Skip to content

Commit

Permalink
refactor(drivers): introduce platforms, move DriverConfig values there
Browse files Browse the repository at this point in the history
  • Loading branch information
B4nan committed Mar 15, 2019
1 parent 133afaa commit 583edef
Show file tree
Hide file tree
Showing 20 changed files with 97 additions and 67 deletions.
2 changes: 1 addition & 1 deletion lib/EntityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class EntityManager {

createQueryBuilder(entityName: EntityName<IEntity>): QueryBuilder {
entityName = Utils.className(entityName);
return new QueryBuilder(entityName, this.metadata, this.getConnection(), this.driver.getConfig());
return new QueryBuilder(entityName, this.metadata, this.getConnection(), this.driver.getPlatform());
}

async find<T extends IEntityType<T>>(entityName: EntityName<T>, where?: FilterQuery<T>, options?: FindOptions): Promise<T[]>;
Expand Down
4 changes: 2 additions & 2 deletions lib/drivers/AbstractSqlDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export abstract class AbstractSqlDriver<C extends Connection> extends DatabaseDr
const qb = this.createQueryBuilder(entityName);
const res = await qb.count('id', true).where(where).execute('get');

return res.count;
return +res.count;
}

async nativeInsert<T extends IEntityType<T>>(entityName: string, data: EntityData<T>): Promise<number> {
Expand Down Expand Up @@ -83,7 +83,7 @@ export abstract class AbstractSqlDriver<C extends Connection> extends DatabaseDr
}

protected createQueryBuilder(entityName: string): QueryBuilder {
return new QueryBuilder(entityName, this.metadata, this.connection, this.getConfig());
return new QueryBuilder(entityName, this.metadata, this.connection, this.platform);
}

protected extractManyToMany<T extends IEntityType<T>>(entityName: string, data: EntityData<T>): EntityData<T> {
Expand Down
23 changes: 9 additions & 14 deletions lib/drivers/DatabaseDriver.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { DriverConfig, FilterQuery, IDatabaseDriver } from './IDatabaseDriver';
import { FilterQuery, IDatabaseDriver } from './IDatabaseDriver';
import { EntityData, EntityMetadata, EntityProperty, IEntity, IEntityType, IPrimaryKey } from '../decorators';
import { MetadataStorage } from '../metadata';
import { Connection } from '../connections/Connection';
import { Configuration, Utils } from '../utils';
import { QueryOrder } from '../query';
import { UnderscoreNamingStrategy } from '../naming-strategy';
import { Platform } from '../platforms/Platform';

export abstract class DatabaseDriver<C extends Connection> implements IDatabaseDriver<C> {

protected readonly connection: Connection;
protected readonly platform: Platform;
protected readonly metadata = MetadataStorage.getMetadata();
protected readonly logger = this.config.getLogger();
protected transactionLevel = 0;
Expand All @@ -33,7 +34,7 @@ export abstract class DatabaseDriver<C extends Connection> implements IDatabaseD
}

async loadFromPivotTable<T extends IEntity>(prop: EntityProperty, owners: IPrimaryKey[]): Promise<Record<string, T[]>> {
if (!this.getConfig().usesPivotTable) {
if (!this.platform.usesPivotTable()) {
throw new Error(`${this.constructor.name} does not use pivot tables`);
}

Expand Down Expand Up @@ -105,7 +106,7 @@ export abstract class DatabaseDriver<C extends Connection> implements IDatabaseD

if (this.transactionLevel === 1) {
this.transactionRolledBack = false;
} else if (!this.getConfig().supportsSavePoints) {
} else if (!this.platform.supportsSavePoints()) {
this.transactionRolledBack = true;
}

Expand All @@ -129,19 +130,13 @@ export abstract class DatabaseDriver<C extends Connection> implements IDatabaseD
return this.transactionLevel > 0;
}

getConfig(): DriverConfig {
return {
usesPivotTable: true,
supportsTransactions: true,
supportsSavePoints: false,
namingStrategy: UnderscoreNamingStrategy,
identifierQuoteCharacter: '`',
};
getPlatform(): Platform {
return this.platform;
}

private async runTransaction(method: 'beginTransaction' | 'commit' | 'rollback'): Promise<void> {
if (this.transactionLevel === 1 || this.getConfig().supportsSavePoints) {
const useSavepoint = this.transactionLevel !== 1 && this.getConfig().supportsSavePoints;
if (this.transactionLevel === 1 || this.platform.supportsSavePoints()) {
const useSavepoint = this.transactionLevel !== 1 && this.platform.supportsSavePoints();
await this.connection[method](useSavepoint ? this.getSavePointName() : undefined);
}
}
Expand Down
12 changes: 2 additions & 10 deletions lib/drivers/IDatabaseDriver.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EntityData, EntityProperty, IEntity, IPrimaryKey } from '../decorators';
import { Connection } from '../connections/Connection';
import { QueryOrder } from '../query';
import { NamingStrategy } from '../naming-strategy';
import { Platform } from '../platforms/Platform';

export interface IDatabaseDriver<C extends Connection = Connection> {

Expand Down Expand Up @@ -64,16 +64,8 @@ export interface IDatabaseDriver<C extends Connection = Connection> {

isInTransaction(): boolean;

getConfig(): DriverConfig;
getPlatform(): Platform;

}

export type FilterQuery<T> = Partial<T> | Record<string, any>;

export interface DriverConfig {
usesPivotTable: boolean;
supportsTransactions: boolean;
supportsSavePoints: boolean;
namingStrategy: { new(): NamingStrategy };
identifierQuoteCharacter: string,
}
14 changes: 2 additions & 12 deletions lib/drivers/MongoDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { MongoConnection } from '../connections/MongoConnection';
import { EntityData, IEntityType, IPrimaryKey } from '../decorators';
import { QueryOrder } from '../query';
import { Utils } from '../utils';
import { DriverConfig } from './IDatabaseDriver';
import { MongoNamingStrategy } from '../naming-strategy';
import { MongoPlatform } from '../platforms/MongoPlatform';

export class MongoDriver extends DatabaseDriver<MongoConnection> {

protected readonly connection = new MongoConnection(this.config);
protected readonly platform = new MongoPlatform();

async find<T extends IEntityType<T>>(entityName: string, where: FilterQuery<T>, populate: string[], orderBy: Record<string, QueryOrder>, limit: number, offset: number): Promise<T[]> {
where = this.renameFields(entityName, where);
Expand Down Expand Up @@ -80,16 +80,6 @@ export class MongoDriver extends DatabaseDriver<MongoConnection> {
return new ObjectID(data);
}

getConfig(): DriverConfig {
return {
usesPivotTable: false,
supportsTransactions: false,
supportsSavePoints: false,
namingStrategy: MongoNamingStrategy,
identifierQuoteCharacter: '',
};
}

private renameFields(entityName: string, data: any): any {
data = Object.assign({}, data); // copy first
Utils.renameKey(data, 'id', '_id');
Expand Down
2 changes: 2 additions & 0 deletions lib/drivers/MySqlDriver.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { MySqlConnection } from '../connections/MySqlConnection';
import { AbstractSqlDriver } from './AbstractSqlDriver';
import { MySqPlatform } from '../platforms/MySqPlatform';

export class MySqlDriver extends AbstractSqlDriver<MySqlConnection> {

protected readonly connection = new MySqlConnection(this.config);
protected readonly platform = new MySqPlatform();

}
14 changes: 2 additions & 12 deletions lib/drivers/SqliteDriver.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
import { UnderscoreNamingStrategy } from '../naming-strategy';
import { SqliteConnection } from '../connections/SqliteConnection';
import { AbstractSqlDriver } from './AbstractSqlDriver';
import { DriverConfig } from './IDatabaseDriver';
import { SqlitePlatform } from '../platforms/SqlitePlatform';

export class SqliteDriver extends AbstractSqlDriver<SqliteConnection> {

protected readonly connection = new SqliteConnection(this.config);

getConfig(): DriverConfig {
return {
usesPivotTable: true,
supportsTransactions: true,
supportsSavePoints: true,
namingStrategy: UnderscoreNamingStrategy,
identifierQuoteCharacter: '"',
};
}
protected readonly platform = new SqlitePlatform();

}
6 changes: 3 additions & 3 deletions lib/entity/Collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@ export class Collection<T extends IEntityType<T>> extends ArrayCollection<T> {
async init(populate: string[] = []): Promise<this> {
const em = this.owner.__em;

if (!this.initialized && this.property.reference === ReferenceType.MANY_TO_MANY && em.getDriver().getConfig().usesPivotTable) {
if (!this.initialized && this.property.reference === ReferenceType.MANY_TO_MANY && em.getDriver().getPlatform().usesPivotTable()) {
const map = await em.getDriver().loadFromPivotTable<T>(this.property, [this.owner.id]);
this.set(map[this.owner.id].map(item => em.merge<T>(this.property.type, item)), true);

return this;
}

// do not make db call if we know we will get no results
if (this.property.reference === ReferenceType.MANY_TO_MANY && (this.property.owner || em.getDriver().getConfig().usesPivotTable) && this.items.length === 0) {
if (this.property.reference === ReferenceType.MANY_TO_MANY && (this.property.owner || em.getDriver().getPlatform().usesPivotTable()) && this.items.length === 0) {
this.initialized = true;
this.dirty = false;
this.populated();
Expand Down Expand Up @@ -121,7 +121,7 @@ export class Collection<T extends IEntityType<T>> extends ArrayCollection<T> {
}

private createManyToManyCondition(cond: Record<string, any>) {
if (this.property.owner || this.owner.__em.getDriver().getConfig().usesPivotTable) {
if (this.property.owner || this.owner.__em.getDriver().getPlatform().usesPivotTable()) {
cond.id = { $in: this.items.map(item => item.id) };
} else {
cond[this.property.mappedBy] = this.owner.id;
Expand Down
4 changes: 2 additions & 2 deletions lib/entity/EntityLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class EntityLoader {
const prop = this.metadata[entityName].properties[field as string];
const filtered = this.filterCollections<T>(entities, field);

if (prop.reference === ReferenceType.MANY_TO_MANY && this.driver.getConfig().usesPivotTable) {
if (prop.reference === ReferenceType.MANY_TO_MANY && this.driver.getPlatform().usesPivotTable()) {
return this.findChildrenFromPivotTable<T>(filtered, prop, field);
}

Expand All @@ -60,7 +60,7 @@ export class EntityLoader {
this.initializeOneToMany<T>(filtered, children, prop, field);
}

if (prop.reference === ReferenceType.MANY_TO_MANY && !prop.owner && !this.driver.getConfig().usesPivotTable) {
if (prop.reference === ReferenceType.MANY_TO_MANY && !prop.owner && !this.driver.getPlatform().usesPivotTable()) {
this.initializeManyToMany<T>(filtered, children, prop, field);
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/hydration/ObjectHydrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class ObjectHydrator extends Hydrator {
const items = value.map((id: IPrimaryKey) => this.factory.createReference(prop.type, this.driver.normalizePrimaryKey(id)));
entity[prop.name as keyof T] = new Collection<IEntity>(entity, items) as T[keyof T];
} else if (!entity[prop.name as keyof T]) {
const items = this.driver.getConfig().usesPivotTable ? undefined : [];
const items = this.driver.getPlatform().usesPivotTable() ? undefined : [];
entity[prop.name as keyof T] = new Collection<IEntity>(entity, items, false) as T[keyof T];
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/metadata/MetadataDiscovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export class MetadataDiscovery {
this.validator.validateEntityDefinition(this.metadata, meta.name);
EntityHelper.decorate(meta, this.em);

if (this.em.getDriver().getConfig().usesPivotTable) {
if (this.em.getDriver().getPlatform().usesPivotTable()) {
Object.values(meta.properties).forEach(prop => this.definePivotTableEntities(meta, prop));
}
}
Expand Down
18 changes: 18 additions & 0 deletions lib/platforms/MongoPlatform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Platform } from './Platform';
import { MongoNamingStrategy, NamingStrategy } from '../naming-strategy';

export class MongoPlatform extends Platform {

usesPivotTable(): boolean {
return false;
}

supportsTransactions(): boolean {
return false;
}

getNamingStrategy(): { new(): NamingStrategy} {
return MongoNamingStrategy;
}

}
9 changes: 9 additions & 0 deletions lib/platforms/MySqPlatform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Platform } from './Platform';

export class MySqPlatform extends Platform {

getIdentifierQuoteCharacter(): string {
return '`';
}

}
25 changes: 25 additions & 0 deletions lib/platforms/Platform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { NamingStrategy, UnderscoreNamingStrategy } from '../naming-strategy';

export abstract class Platform {

usesPivotTable(): boolean {
return true;
}

supportsTransactions(): boolean {
return true;
}

supportsSavePoints(): boolean {
return false;
}

getNamingStrategy(): { new(): NamingStrategy} {
return UnderscoreNamingStrategy;
}

getIdentifierQuoteCharacter(): string {
return '"';
}

}
9 changes: 9 additions & 0 deletions lib/platforms/SqlitePlatform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Platform } from './Platform';

export class SqlitePlatform extends Platform {

supportsSavePoints(): boolean {
return true;
}

}
6 changes: 3 additions & 3 deletions lib/query/QueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { EntityMetadata, EntityProperty } from '../decorators';
import { Connection } from '../connections/Connection';
import { ReferenceType } from '../entity';
import { QueryFlag, QueryOrder, QueryType } from './enums';
import { DriverConfig } from '..';
import { Platform } from '../platforms/Platform';

/**
* SQL query builder
Expand All @@ -23,12 +23,12 @@ export class QueryBuilder {
private _limit: number;
private _offset: number;
private readonly alias = `e0`;
private readonly helper = new QueryBuilderHelper(this.entityName, this.alias, this.metadata, this.driverConfig);
private readonly helper = new QueryBuilderHelper(this.entityName, this.alias, this.metadata, this.platform);

constructor(private readonly entityName: string,
private readonly metadata: Record<string, EntityMetadata>,
private readonly connection: Connection,
private readonly driverConfig: DriverConfig) { }
private readonly platform: Platform) { }

select(fields: string | string[]): this {
this._fields = Array.isArray(fields) ? fields : [fields];
Expand Down
6 changes: 3 additions & 3 deletions lib/query/QueryBuilderHelper.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Utils } from '../utils';
import { EntityMetadata } from '../decorators';
import { QueryOrder, QueryType } from './enums';
import { DriverConfig } from '..';
import { Platform } from '../platforms/Platform';

export class QueryBuilderHelper {

Expand All @@ -21,12 +21,12 @@ export class QueryBuilderHelper {
$ne: '!=',
};

private readonly quoteChar = this.driverConfig.identifierQuoteCharacter;
private readonly quoteChar = this.platform.getIdentifierQuoteCharacter();

constructor(private readonly entityName: string,
private readonly alias: string,
private readonly metadata: Record<string, EntityMetadata>,
private readonly driverConfig: DriverConfig) { }
private readonly platform: Platform) { }

private getGroupWhereParams(key: string, cond: Record<string, any>): any[] {
if (key === '$and' || key === '$or') {
Expand Down
2 changes: 1 addition & 1 deletion lib/unit-of-work/UnitOfWork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class UnitOfWork {
}

const driver = this.em.getDriver();
const runInTransaction = !driver.isInTransaction() && driver.getConfig().supportsTransactions;
const runInTransaction = !driver.isInTransaction() && driver.getPlatform().supportsTransactions();
const promise = Utils.runSerial(this.changeSets, changeSet => this.commitChangeSet(changeSet));

if (runInTransaction) {
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class Configuration {
}

getNamingStrategy(): NamingStrategy {
return this.cached(this.options.namingStrategy || this.driver.getConfig().namingStrategy);
return this.cached(this.options.namingStrategy || this.driver.getPlatform().getNamingStrategy());
}

getHydrator(factory: EntityFactory): Hydrator {
Expand Down
2 changes: 1 addition & 1 deletion tests/EntityManager.mongo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ describe('EntityManagerMongo', () => {
const driver = orm.em.getDriver<MongoDriver>();
expect(driver instanceof MongoDriver).toBe(true);
expect(await driver.findOne(BookTag.name, { foo: 'bar', books: 123 })).toBeNull();
expect(driver.getConfig().usesPivotTable).toBe(false);
expect(driver.getPlatform().usesPivotTable()).toBe(false);
await expect(driver.loadFromPivotTable({} as EntityProperty, [])).rejects.toThrowError('MongoDriver does not use pivot tables');
await expect(driver.getConnection().execute('')).rejects.toThrowError('MongoConnection does not support generic execute method');
});
Expand Down

0 comments on commit 583edef

Please sign in to comment.