Persistence

Persisting data is one of the most common functions in backend services. There are many good persistence frameworks available on the market and the Pip.Services toolkit doesn’t intend to compete with them. Using the Component Model the toolkit integrates selected best of breed persistence technologies to enable consistent configuration, management and the use of the symmetric programming model across different databases and languages.

Out of the box, the Pip.Services toolkit offers support for a number of persistence technologies and popular relational and NoSQL databases (implementations for different languages may vary). They are:

  • In-memory persistence
  • File persistence
  • SQL Server
  • MySQL
  • Postresql
  • SQLite
  • MongoDB
  • Couchbase
  • Cassandra

Connection Management

The XyzConnection component encapsulates database connections and configures them like on the example config file below:

# Database connection
descriptor: pip-services:connection:mongodb:default:3.0
connection:
  host: ${{MONGO_HOST}}{$unless MONGO_HOST}localhost{$unless}
  port: ${{MONGO_PORT}}{$unless MONGO_PORT}27017{$unless}
credentials:
  host: ${{MONGO_USER}}{$unless MONGO_USER}mongo{$unless}
  port: ${{MONGO_PASS}}{$unless MONGO_PASS}pwd123{$unless}
options:
  max_pool_size: 10
  keep_alive: true

Using the connection.discovery_key parameter, the connection component can retrieve connection parameters from Discovery Services and, using the credentials.store_key parameter, it can retrieve credential parameters from Credential Stores.

By default, persistence components will try to retrieve the first available connection from the references. By specifying the references.connection parameter, a persistence component can be linked with a specific connection. If there are no connections available, each persistence component will try to create its own connection. See the sample config below:

# Persistence with default connection
descriptor: myservice:mypersistence:mongodb:persist1:1.0

# Persistence linked to specific connection
descriptor: myservice:mypersistence:mongodb:persist2:1.0
references:
  connection: pip-services:connection:mongodb:conn1:3.0

Most XyzConnection components have the getConnection() method (Connection property) to get a reference to a shared database connection.

Generic Persistence

For persistence operations against a single table (collection) the toolkit offers XyzPersistence components. They act as abstract classes for specific implementations that enable the component lifecycle and share database connections. Persistence operations can be implemented using custom code or a number of out-of-the-box methods like GetListByFilter(), Create() or DeleteByFilter().

import { MongoDbPersistence } from 'pip-services3-mongodb-nodex';

class MyObject {
  key: string;
  name: string;
}

class MyMongoDbPersistence extends MongoDbPersistence<MyObject> {

  public constructor() {
    super("mycollection");
  }

  public async getByName(correlationId: string, name: string): Promise<MyObject> {
    let criteria= { name: name };
    let res = await super.getListByFilter(correlationId, criteria, null, null);
    return res.length > 0 ? res[0] : null;
  }

  public async createDefault(correlationId: string, name: string): Promise<MyObject> {
    name = name ?? "unknown";
    let key = name.toLowerCase().replace(" #$%^&", "_");
    let item: MyObject = { key: key, name: name };

      let result = await new Promise<any>((resolve, reject) => {
      this._collection.insertOne(item, (err, result) => {
        if (err = null) resolve(result);
        else reject(err);
      });
    });

    this._logger.trace(correlationId, "Created item in %s with key = %s", this._collectionName, key);

   let newItem = result != null ? result.ops[0] : null;
   return newItem;
  }

  public async deleteByName(correlationId: string, name: string): Promise<void> {
    let criteria= { name: name };
    await super.deleteByFilter(correlationId, criteria);
  }
}
using PipServices3.MongoDb.Persistence;
using MongoDB.Bson.Serialization.Attributes;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using MongoDB.Driver;

class MyObject
{
    [BsonElement("key")]
    [DataMember(Name = "key")]
    public string Key { get; set; }
    [BsonElement("name")]
    [DataMember(Name = "name")]
    public string Name { get; set; }
}

class MyMongoDbPersistence : MongoDbPersistence<MyObject>
{
    public MyMongoDbPersistence():base("mycollection") { }

    public async Task<MyObject> GetByNameAsync(string correlationId, string name)
    {
        var builder = Builders<MyObject>.Filter;
        var filter = builder.Empty;

        
        filter &= builder.Eq("name", name); ;
        var res = await GetListByFilterAsync(correlationId, filter);

        return res.Count > 0 ? res[0] : null;
    }

    public async Task<MyObject> CreateDefault(string correlationId, string name)
    {
        name ??= "unknown";
        var key = name.ToLower().Replace(" #$%^&", "_");
        var item = new MyObject { Key = key, Name = name };

        await _collection.InsertOneAsync(item, null);

        _logger.Trace(correlationId, "Created item in %s with key = %s", _collectionName, key);

        return item;
    }

    public async Task DeleteByName(string correlationId, string name)
    {
        var builder = Builders<MyObject>.Filter;
        var filter = builder.Empty;


        filter &= builder.Eq("name", name); ;
        await DeleteByFilterAsync(correlationId, filter);
    }
}

import (
	"context"
	"strings"

	persist "github.com/pip-services3-gox/pip-services3-mongodb-gox/persistence"
	"go.mongodb.org/mongo-driver/bson"
)

type MyObject struct {
	Key  string `bson:"key" json:"key"`
	Name string `bson:"name" json:"name"`
}

type MyMongoDbPersistence struct {
	*persist.MongoDbPersistence[MyObject]
}

func NewMyMongoDbPersistence() *MyMongoDbPersistence {
	c := &MyMongoDbPersistence{}
	c.MongoDbPersistence = persist.InheritMongoDbPersistence[MyObject](c, "mycollection")
	return c
}

func (c *MyMongoDbPersistence) GetByName(ctx context.Context, correlationId string,
	name string) (result MyObject, err error) {

	filterObj := bson.M{"name": name}

	items, err := c.MongoDbPersistence.GetListByFilter(ctx, correlationId, filterObj, nil, nil)
	if err != nil {
		return result, err
	}

	if len(items) > 0 {
		return items[0], nil
	} else {
		return result, nil
	}
}

func (c *MyMongoDbPersistence) CreateDefault(ctx context.Context, correlationId string,
	name string) (result MyObject, err error) {

	if name == "" {
		name = "unknown"
	}

	key := strings.ReplaceAll(strings.ToLower(name), " #$%^&", "_")
	item := MyObject{Key: key, Name: name}

	newItem, err := c.Overrides.ConvertFromPublic(item)
	if err != nil {
		return result, err
	}
	insRes, err := c.Collection.InsertOne(ctx, newItem)
	if err != nil {
		return result, err
	}

	result, err = c.Overrides.ConvertToPublic(newItem)
	if err != nil {
		return result, err
	}
	c.Logger.Trace(ctx, correlationId, "Created in %s with id = %s", c.Collection, insRes.InsertedID)
	return result, nil
}

func (c *MyMongoDbPersistence) DeleteByName(ctx context.Context, correlationId string,
	name string) error {
	filterObj := bson.M{"name": name}
	return c.DeleteByFilter(ctx, correlationId, filterObj)
}
import 'package:pip_services3_mongodb/pip_services3_mongodb.dart';

class MyObject {
  String key;
  String name;

  MyObject.from(this.key, this.name);

  Map<String, dynamic> toJson() {
    return <String, dynamic>{'key': key, 'name': name};
  }

  void fromJson(Map<String, dynamic> json) {
    key = json['key'];
    name = json['name'];
  }

  MyObject clone() {
    return MyObject.from(key, name);
  }
}

class MyMongoDbPersistence extends MongoDbPersistence<MyObject> {
  MyMongoDbPersistence() : super('mycollection');

  Future<MyObject?> getByName(String correlationId, String name) async {
    var criteria = {name: name};
    var res = await super.getListByFilterEx(correlationId, criteria, null);
    return res.isNotEmpty ? res[0] : null;
  }

  Future<MyObject?> createDefault(String correlationId, String name) async {
    name = name ?? 'unknown';
    var key = name.toLowerCase().replaceAll(' #\$%^&', '_');
    var item = MyObject.from(key, name);

    var jsonMap = convertFromPublic(item, createUid: false);
    var result = await collection!.insertOne(jsonMap!);

    logger.trace(correlationId, 'Created in %s with id = %s',
        [collectionName, result.id]);

    return convertToPublic(jsonMap);
  }

  Future<void> deleteByName(String correlationId, String name) async {
    var criteria = {name: name};
    await super.deleteByFilterEx(correlationId, criteria);
  }
}
from pip_services3_mongodb.persistence import MongoDbPersistence


class MyObject:
    def __init__(self, key: str = None, name: str = None):
        self.name = key
        self.content = name


class MyMongoDbPersistence(MongoDbPersistence):

    def __init__(self):
        super(MyMongoDbPersistence, self).__init__('mycollection')

    def get_by_name(self, correlation_id: str, name: str) -> MyObject:
        criteria = {'name': name}
        res = self.get_list_by_filter(correlation_id, criteria, None, None)
        return None if len(res) < 0 else res[0]

    def create_default(self, correlation_id: str, name: str) -> MyObject:
        name = name or 'unknown'
        key = name.lower().replace(" #$%^&", "_")
        item = MyObject(key, name)

        result = self._collection.insert_one(item)
        item = self._collection.find_one({'_id': result.inserted_id})

        item = self._convert_to_public(item)
        return item

    def delete_by_name(self, correlation_id: str, name: str):
        criteria = {'name': name}
        self.delete_by_filter(correlation_id, criteria)
Not available

To implement custom persistence operations, protected properties should be used to get access to database connection, transaction and table (collection) object references encapsulated by the component (check the component documentation for details).

Identifiable Persistence

The most common persistence scenario is when data objects are identified by a unique Id field and stored in a single table (collection). This allows to implement persistence that can work against any relational or NoSQL persistence store available now or in the future (see concept Long-Living Code). To support this scenario the Pip.Services toolkit has the XyzIdentifiablePersistence components that offer a full set of CRUD operations for objects that have the Id property and implement the IIdentifiable interface.

import { IIdentifiable } from 'pip-services3-commons-nodex';

class MyIdentifiableObject implements IIdentifiable <string> {
    public id: string;
    public name: string;
    public value: string;
}

using PipServices3.Commons.Data;

class MyIdentifiableObject: IIdentifiable<string>
{
    [BsonElement("id")]
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [BsonElement("key")]
    [DataMember(Name = "key")]
    public string Key { get; set; }
    
    [BsonElement("name")]
    [DataMember(Name = "name")]
    public string Name { get; set; }
}

type MyIdentifiableObject struct {
	Id    string `bson:"id" json:"id"`
	Name  string `bson:"name" json:"name"`
	Value string `bson:"value" json:"value"`
}

func (c *MyIdentifiableObject) GetId() string {
	return c.Id
}

import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyIdentifiableObject implements IIdentifiable<String> {
  @override
  String? id;
  String key;
  String name;

  MyIdentifiableObject.from(this.id, this.key, this.name);

  Map<String, dynamic> toJson() {
    return <String, dynamic>{'id': id, 'key': key, 'name': name};
  }

  void fromJson(Map<String, dynamic> json) {
    key = json['key'];
    name = json['name'];
  }

  MyIdentifiableObject clone() {
    return MyIdentifiableObject.from(id, key, name);
  }
}

from pip_services3_commons.data import IIdentifiable

class MyIdentifiableObject(IIdentifiable):
    def __init__(self, id: str = None, name: str = None, value: str = None):
        self.id = id
        self.name = name
        self.value = value
Not available

Unique ids can be natural or generated by a special key generator. However, to make it simpler and portable, the toolkit has the IdGenerator class that can generate globally unique Ids as string GUIDs. Those ids are quite long (32 characters) but they work well for collections of moderate size.

The example below requires only a few lines of code, but implements a persistence with a full set of CRUD operations:

import { IIdentifiable } from 'pip-services3-commons-nodex';
import { DataPage, FilterParams, PagingParams } from 'pip-services3-commons-nodex';
import { IdentifiablePostgresPersistence } from 'pip-services3-postgres-nodex';

class MyIdentifiableObject implements IIdentifiable <string> {
    public id: string;
    public name: string;
    public value: string;
}

interface MyIdentifiablePersistence {
    getPageByFilter(correlationId: string, filter: FilterParams, paging: PagingParams): Promise<DataPage<MyIdentifiableObject>>;
    create(correlationId: string, item: MyIdentifiableObject): Promise<MyIdentifiableObject>;
    getOneById(correlationId: string, id: string): Promise<MyIdentifiableObject>;
    deleteById(correlationId: string, id: string): Promise<MyIdentifiableObject>;
}

class MyIdentifiablePostgreSqlPersistence extends IdentifiablePostgresPersistence<MyIdentifiableObject, string> implements MyIdentifiablePersistence {

    public constructor() {
        super("mycollection");
    }

    public composeFilter(filter: FilterParams): string {
        filter = filter ?? new FilterParams();
        let criteria = [];

        let id = filter.getAsString("id");
        if (id != null) {
            criteria.push("id='" + id + "'");
        }

        let name = filter.getAsString("name");
        if (name != null) {
            criteria.push("name='" + name + "'");
        }

        return criteria.length > 0 ? criteria.join(" AND ") : null;
    }

    public async getPageByFilter(correlationId: string, filter: FilterParams, paging: PagingParams): Promise<DataPage<MyIdentifiableObject>> {
        let criteria = this.composeFilter(filter);
        return await super.getPageByFilter(correlationId, criteria, paging, null, null);
    }
}

using MongoDB.Bson.Serialization.Attributes;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using PipServices3.Commons.Data;
using PipServices3.Postgres.Persistence;
using System.Collections.Generic;

class MyIdentifiableObject : IIdentifiable<string>
{
    [BsonElement("id")]
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [BsonElement("key")]
    [DataMember(Name = "key")]
    public string Key { get; set; }
    [BsonElement("name")]
    [DataMember(Name = "name")]
    public string Name { get; set; }
}

interface MyIdentifiablePersistence
{
    Task<DataPage<MyIdentifiableObject>> GetPageByFilterAsync(string correlationId, FilterParams filter, PagingParams paging);
    Task<MyIdentifiableObject> CreateAsync(string correlationId, MyIdentifiableObject item);
    Task<MyIdentifiableObject> GetOneByIdAsync(string correlationId, string id);
    Task<MyIdentifiableObject> DeleteByIdAsync(string correlationId, string id);
}

class MyMongoDbPersistence : IdentifiablePostgresPersistence<MyIdentifiableObject, string>, MyIdentifiablePersistence
{
    public MyMongoDbPersistence() : base("mycollection") { }

    private string composeFilter(FilterParams filter)
    {
        filter = filter ?? new FilterParams();
        var criteria = new List<string>();

        var id = filter.GetAsString("id");
        if (id != null)
            criteria.Add("id='" + id + "'");
        

        var name = filter.GetAsString("name");
        if (name != null)
            criteria.Add("name='" + name + "'");
        

        return criteria.Count > 0 ? string.Join(" AND ", criteria) : null;
    }

    public async Task<DataPage<MyIdentifiableObject>> GetPageByFilterAsync(string correlationId, FilterParams filter, PagingParams paging)
    {
        return await base.GetPageByFilterAsync(correlationId, composeFilter(filter), paging);
    }
}


import (
	"context"
	"strings"

	"github.com/pip-services3-gox/pip-services3-commons-gox/data"
	"github.com/pip-services3-gox/pip-services3-postgres-gox/persistence"
)

type MyIdentifiableObject struct {
	Id    string `bson:"id" json:"id"`
	Name  string `bson:"name" json:"name"`
	Value string `bson:"value" json:"value"`
}

func (c *MyIdentifiableObject) GetId() string {
	return c.Id
}

type MyIdentifiablePersistence interface {
	GetPageByFilter(correlationId string, filter data.FilterParams, paging data.PagingParams) (data.DataPage[MyIdentifiableObject], error)
	Create(correlationId string, item MyIdentifiableObject) (MyIdentifiableObject, error)
	GetOneById(correlationId string, id string) (MyIdentifiableObject, error)
	DeleteById(correlationId string, id string) (MyIdentifiableObject, error)
}

type MyIdentifiablePostgreSqlPersistence struct {
	*persistence.IdentifiablePostgresPersistence[MyIdentifiableObject, string]
}

func NewMyIdentifiablePostgreSqlPersistence() *MyIdentifiablePostgreSqlPersistence {
	c := &MyIdentifiablePostgreSqlPersistence{}
	c.IdentifiablePostgresPersistence = persistence.InheritIdentifiablePostgresPersistence[MyIdentifiableObject, string](c, "mycollection")
	return c
}

func (c *MyIdentifiablePostgreSqlPersistence) composeFilter(filter data.FilterParams) string {
	criteria := make([]string, 0)

	if id, ok := filter.GetAsNullableString("id"); ok && id != "" {
		criteria = append(criteria, "id='"+id+"'")
	}

	if name, ok := filter.GetAsNullableString("name"); ok && name != "" {
		criteria = append(criteria, "name='"+name+"'")
	}

	if len(criteria) > 0 {
		return strings.Join(criteria, " AND ")
	} else {
		return ""
	}
}

func (c *MyIdentifiablePostgreSqlPersistence) GetPageByFilter(ctx context.Context, correlationId string,
	filter data.FilterParams, paging data.PagingParams) (page data.DataPage[MyIdentifiableObject], err error) {

	return c.IdentifiablePostgresPersistence.GetPageByFilter(ctx, correlationId,
		c.composeFilter(filter), paging,
		"", "",
	)
}

import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_postgres/pip_services3_postgres.dart';

class MyIdentifiableObject implements IIdentifiable<String> {
  @override
  String? id;
  String key;
  String name;

  MyIdentifiableObject.from(this.id, this.key, this.name);

  Map<String, dynamic> toJson() {
    return <String, dynamic>{'id': id, 'key': key, 'name': name};
  }

  void fromJson(Map<String, dynamic> json) {
    key = json['key'];
    name = json['name'];
  }

  MyIdentifiableObject clone() {
    return MyIdentifiableObject.from(id, key, name);
  }
}

abstract class MyIdentifiablePersistence {
  Future<DataPage<MyIdentifiableObject>> GetPageByFilter(
      String? correlationId, FilterParams? filter, PagingParams? paging);
  Future<MyIdentifiableObject?> create(
      String? correlationId, MyIdentifiableObject? item);
  Future<MyIdentifiableObject?> getOneById(String? correlationId, String id);
  Future<MyIdentifiableObject?> deleteById(String? correlationId, String? id);
}

class MyIdentifiablePostgreSqlPersistence
    extends IdentifiablePostgresPersistence<MyIdentifiableObject, String>
    implements MyIdentifiablePersistence {
  MyIdentifiablePostgreSqlPersistence() : super('mycollection', null);

  String? composeFilter(FilterParams? filter) {
    filter = filter ?? FilterParams();
    var criteria = [];

    var id = filter.getAsString('id');
    if (id.isNotEmpty) {
      criteria.add("id='" + id + "'");
    }

    var name = filter.getAsString('name');
    if (name.isNotEmpty) {
      criteria.add("name='" + name + "'");
    }

    return criteria.isNotEmpty ? criteria.join(' AND ') : null;
  }

  @override
  Future<DataPage<MyIdentifiableObject>> GetPageByFilter(
      String? correlationId, FilterParams? filter, PagingParams? paging) async {
    return await super.getPageByFilter_(
        correlationId, composeFilter(filter), paging, null, null);
  }
}

from abc import ABC

from pip_services3_commons.data import IIdentifiable, FilterParams, PagingParams, DataPage
from pip_services3_postgres.persistence import IdentifiablePostgresPersistence


class MyIdentifiableObject(IIdentifiable):
    def __init__(self, id: str = None, name: str = None, value: str = None):
        self.id = id
        self.name = name
        self.value = value


class MyIdentifiablePersistence(ABC):
    def get_page_by_filter(self, correlation_id: str, filter: FilterParams, paging: PagingParams) -> DataPage:
        pass

    def create(self, correlation_id: str, item: MyIdentifiableObject) -> MyIdentifiableObject:
        pass

    def get_one_by_id(self, correlation_id: str, id: str) -> MyIdentifiableObject:
        pass

    def delete_by_id(self, correlation_id: str, id: str) -> MyIdentifiableObject:
        pass


class MyIdentifiablePostgreSqlPersistence(IdentifiablePostgresPersistence, MyIdentifiablePersistence):
    def __init__(self):
        super(MyIdentifiablePostgreSqlPersistence, self).__init__('mycollection')

    def _compose_filter(self, filter_params: FilterParams):
        filter_params = filter_params or FilterParams()
        criteria = []

        id = filter_params.get_as_string("id")
        if id is not None and id != "":
            criteria.append("id='" + id + "'")

        name = filter_params.get_as_string("name")
        if name is not None and name != "":
            criteria.append("name='" + name + "'")

        return None if len(criteria) < 0 else " AND ".join(criteria)

    def get_page_by_filter(self, correlation_id: str, filter: FilterParams, paging: PagingParams) -> DataPage:
        criteria = self._compose_filter(filter)
        return super(MyIdentifiablePostgreSqlPersistence, self).get_page_by_filter(correlation_id, criteria, paging, None, None)

Not available

Most relational XyzIdentifiablePersistence components have variations called XyzJsonIdentifiablePersistence that store objects in JSON format. In this case, tables have only 2 fields: id and data. The id field contains the unique object Id and the data field contains the entire object data serialized as JSON:

CREATE TABLE MyIdentifiableJsonObject (
  id VARCHAR(32) PRIMARY KEY,
  data JSON
);

For more information, please, refer to the component documentation.

Custom Persistence

There are situations, when persistence has a complex data model, or there is already an existing implementation that does the work. In those cases, it is only necessary to use that implementation written in a chosen persistence framework and wrap it into a Pip.Services component to enable configuration and life-cycle management in order to place that persistence into a container and connect to other components in a data service. Here is a simple example of how it can be done.

import { ConfigParams, IConfigurable, IOpenable, IReferenceable, IReferences } from "pip-services3-commons-nodex";

class MyCustomPersistence {
    // Custom implementation using any persistence framework
}

class MyCustomPersistenceWrapper implements IConfigurable, IReferenceable, IOpenable {
    public _config: ConfigParams = new ConfigParams();
    public _persistence: MyCustomPersistence;

    public configure(config: ConfigParams): void {
        // Store config parameters
        this._config = config ?? this._config;
    }

    public setReferences(references: IReferences): void {
        // Retrieve whatever references you may need
    }

    public isOpen(): boolean {
        return this._persistence != null;
    }

    public async open(correlationId: string): Promise<void> {
        if (this._persistence != null) return;

        // Create custom persistence
        this._persistence = new MyCustomPersistence();

        // Configure custom persistence
        ...

        // Open and connect to the database
        await this._persistence.connect();
    }

    public async close(correlationId: string): Promise<void> {
        if (this._persistence == null) return;

        // Disconnect from the database and close
        await this._persistence.disconnect();
        this._persistence = null;
    }

    public customMethod(...) {
        // Delegate operations to custom persistence
        return await this._persistence.customMethod(...);
    }
}

using System.Threading.Tasks;
using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Commons.Run;

class MyCustomPersistence
{
    // Custom implementation using any persistence framework
}

class MyCustomPersistenceWrapper : IConfigurable, IReferenceable, IOpenable
{
    public ConfigParams _config = new ConfigParams();
    public MyCustomPersistence _persistence;

    public void Configure(ConfigParams config)
    {
        // Store config parameters
        this._config = config ?? this._config;
    }

    public void SetReferences(IReferences references)
    {
        // Retrieve whatever references you may need
    }

    public bool IsOpen()
    {
        return this._persistence != null;
    }

    public Task OpenAsync(string correlationId)
    {
        if (this._persistence != null) return;

        // Create custom persistence
        this._persistence = new MyCustomPersistence();

        // Configure custom persistence
        ...

        // Open and connect to the database
        await this._persistence.connect();
    }

    public Task CloseAsync(string correlationId)
    {
        if (this._persistence == null) return;

        // Disconnect from the database and close
        await this._persistence.disconnect();
        this._persistence = null;
    }

    public void CustomMethod(...)
    {
        // Delegate operations to custom persistence
        return await this._persistence.customMethod(...);
    }
}


import (
	"context"

	"github.com/pip-services3-go/pip-services3-commons-go/refer"
	"github.com/pip-services3-gox/pip-services3-commons-gox/config"
)

type MyCustomPersistence struct {
	// Custom implementation using any persistence framework
}

func NewMyCustomPersistence() *MyCustomPersistence {
	return &MyCustomPersistence{}
}

type MyCustomPersistenceWrapper struct {
	config      *config.ConfigParams
	persistence *MyCustomPersistence
}

func NewMyCustomPersistenceWrapper() *MyCustomPersistenceWrapper {
	return &MyCustomPersistenceWrapper{
		config: config.NewConfigParams(),
	}
}

func (c *MyCustomPersistenceWrapper) Configure(ctx context.Context, config *config.ConfigParams) {
	// Store config parameters
	if config != nil {
		c.config = config
	}
}

func (c *MyCustomPersistenceWrapper) SetReferences(ctx context.Context, references refer.IReferences) {
	// Retrieve whatever references you may need
}

func (c *MyCustomPersistenceWrapper) IsOpen() bool {
	return c.persistence != nil
}

func (c *MyCustomPersistenceWrapper) Open(ctx context.Context, correlationId string) (err error) {
	if c.persistence != nil {
		return nil
	}

	// Create custom persistence
	c.persistence = NewMyCustomPersistence()

	// Configure custom persistence
	// ...

	// Open and connect to the database
	c.persistence.Connect()
}

func (c *MyCustomPersistenceWrapper) Close(ctx context.Context, correlationId string) (err error) {
	if c.persistence == nil {
		return
	}

	// Disconnect from the database and close
	c.persistence.Disconnect()
	c.persistence = nil
}

import 'package:pip_services3_commons/pip_services3_commons.dart';

class MyCustomPersistence {
  // Custom implementation using any persistence framework
}

class MyCustomPersistenceWrapper
    implements IConfigurable, IReferenceable, IOpenable {
  ConfigParams _config = ConfigParams();
  MyCustomPersistence? _persistence;

  @override
  void configure(ConfigParams config) {
    // Store config parameters
        _config = config;
  }

  @override
  void setReferences(IReferences references) {
    // Retrieve whatever references you may need
  }

   @override
  bool isOpen() {
    return _persistence != null;
  }

  @override
  Future open(String? correlationId) {
    if (_persistence != null) {
      return;
    }

    // Create custom persistence
    _persistence = new MyCustomPersistence();

    // Configure custom persistence
    ...

    // Open and connect to the database
    await _persistence.connect();
  }

  @override
  Future close(String? correlationId) {
    if (_persistence == null) {
      return;
    }

    // Disconnect from the database and close
    await _persistence.disconnect();
    _persistence = null;
  }

  Future customMethod(...) async {
    // Delegate operations to custom persistence
    return await _persistence.customMethod(...);
  }
  
}

from typing import Optional

from pip_services3_commons.config import IConfigurable, ConfigParams
from pip_services3_commons.refer import IReferenceable, IReferences
from pip_services3_commons.run import IOpenable


class MyCustomPersistence:
    # Custom implementation using any persistence framework
    pass

class MyCustomPersistenceWrapper(IConfigurable, IReferenceable, IOpenable):

    def __init__(self):
        self._config = ConfigParams()
        self._persistence: MyCustomPersistence = None

    def configure(self, config: ConfigParams):
        # Store config parameters
        self._config = config or self._config

    def set_references(self, references: IReferences):
        # Retrieve whatever references you may need
        pass

    def is_open(self) -> bool:
        return self._persistence is not None

    def open(self, correlation_id: Optional[str]):
        if self._persistence is not None:
            return

        # Create custom persistence
        self._persistence = MyCustomPersistence()

        # Configure custom persistence
        # ...

        # Open and connect to the database
        self._persistence.connect()

    def close(self, correlation_id: Optional[str]):
        if self._persistence is None:
            return

        # Disconnect from the database and close
        self._persistence.disconnect()
        self._persistence = None

    def custom_method(self, ...):
        # Delegate operations to custom persistence
        return self._persistence.custom_method(...)

Not available

References

For more information about configurations see: