# Implementation using a pattern strategy

**Strategy Pattern** is a behavioral design pattern that allows choosing the behavior of an algorithm at runtime. In the context of an ORM (Object-Relational Mapping) system, this pattern is particularly useful for supporting multiple database systems, such as PostgreSQL and MySQL, without binding the `DatabaseManager` class to a specific database implementation.

**Concept Overview**

In my ORM system, the Strategy pattern is implemented using classes that encapsulate logic specific to each database. The `DatabaseManager` class acts as the context and dynamically selects the appropriate strategy depending on the database type. The strategy is a representation of various database operations adapted to a specific database (e.g., PostgreSQL or MySQL).

**Code Implementation**

Here’s how the Strategy pattern is applied in my system:

1. `DatabaseManager` Class: The context class that holds a reference to the strategy object.

```typescript
class DatabaseManager<DT extends DatabasesTypes> implements DatabaseManagerInterface<DT> {
    private _connectionData: ConnectionData;
    private _dataSource: DataSourceContextInterface<DT>;

    constructor(connectionData: ConnectionData, dataSource: DataSourceContextInterface<DT>) {
        this._dataSource = dataSource;
        this._dataSource.connectionData = this._connectionData;
        
        if (connectionData.type === DatabasesTypes.POSTGRES) {
            this._dataSource.database = new DataSourcePostgres() as unknown as DataSourceInterface<DT>;
        }

        if (this._connectionData.type === DatabasesTypes.MYSQL) {
            this._dataSource.database = new DataSourceMySql() as unknown as DataSourceInterface<DT>;
        }
    }
}
```

* The `DatabaseManager` class initializes the corresponding `DataSource` based on the `connectionData.type`.
* This class is the entry point that sets up the correct strategy.

2. `DataSourceContext` class: A context for storing the strategy.

```typescript
class DataSourceContext<DT extends DatabasesTypes> implements DataSourceContextInterface<DT> {
    set database(dataSource: DataSourceInterface<DT>) {
        this._dataSource = dataSource;
    }
}
```

* The `DataSourceContext` class allows you to dynamically set the strategy (database) using the `database` method.

3. **Specific Strategy (PostgreSQL)**: Implements operations specific to PostgreSQL.

```typescript
export class DataSourcePostgres extends BaseQueries implements DataSourceInterface<DatabasesTypes.POSTGRES> {
    client: PoolClient;
    private _tableBuilder: TableBuilderInterface;
    private _tableAlterer: TableAltererInterface;
    private _migrationService: MigrationServiceInterface;
    private _selectQueries: SelectQueriesInterface;
    private _insertQueries: InsertQueriesInterface;
    private _updateQueries: UpdateQueriesInterface;
    private _deleteQueries: DeleteQueriesInterface;
    private _aggregateQueries: AggregateQueriesInterface;
    private _structureQueries: StructureQueriesInterface;
    private _viewQueries: ViewQueriesInterface;
    private _triggerAlterer: TriggerAltererInterface;
    private _indexAlterer: IndexAltererInterface;
    private _transaction: TransactionInterface;
    private _monitoring: MonitoringInterface<DatabasesTypes.POSTGRES>;

    constructor() {
        super();
        this._migrationService = new MigrationService();
        this._tableBuilder = new TableBuilder();
        this._tableAlterer = new TableAlterer();
        this._selectQueries = new SelectQueries();
        this._insertQueries = new InsertQueries();
        this._updateQueries = new UpdateQueries();
        this._deleteQueries = new DeleteQueries();
        this._aggregateQueries = new AggregateQueries();
        this._structureQueries = new StructureQueries();
        this._viewQueries = new ViewQueries();
        this._triggerAlterer = new TriggerAlterer();
        this._indexAlterer = новий IndexAlterer();
        this._transaction = new Transaction();
        this._monitoring = new Monitoring();
    }

    async connect(dataToConnect: ConnectionData): Promise<void> {
        const pool = new Pool(dataToConnect);
        this.client = await pool.connect();
    }

    createTable(options: CreateTableOptionsInterface<DatabasesTypes.POSTGRES>): string {
        return this._tableBuilder.createTable(
            options?.table,
            options?.columns,
            options?.computedColumns,
            options?.foreignKeys,
            options?.primaryColumn,
            options?.oneToOne,
            options?.oneToMany
        );
    }
}
```

* `DataSourcePostgres` Class encapsulates all PostgreSQL-specific operations, such as table creation, migration management, and query handling.
* By adhering to the `DataSourceInterface`, it ensures seamless switching between different database strategies in `DatabaseManager`.

**Why the Strategy Pattern is Useful:**

1. **Flexibility**: The Strategy Pattern allows easy switching between different types of databases by simply selecting the appropriate strategy. This is particularly useful in systems that need to support multiple databases.
2. **Ease of Maintenance**: By encapsulating database-specific logic in separate classes, I can manage and update each strategy independently. If PostgreSQL changes its API, I only need to update the `DataSourcePostgres` class without affecting other parts of the system.
3. **Scalability**: As my ORM system grows and starts supporting more databases, I can add new strategies without needing to modify existing code. Simply implement a new `DataSource` class and connect it to `DatabaseManager`.

This approach provides adaptability to different database environments and ease of maintenance over time, making it a robust solution for handling complex database operations.
