Skip to content

Commit

Permalink
refactor(postgre): support returning default values from database
Browse files Browse the repository at this point in the history
  • Loading branch information
B4nan committed Mar 20, 2019
1 parent 71e0220 commit 6b435d1
Show file tree
Hide file tree
Showing 17 changed files with 103 additions and 69 deletions.
17 changes: 11 additions & 6 deletions lib/EntityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,22 +126,28 @@ export class EntityManager {
async nativeInsert<T extends IEntityType<T>>(entityName: EntityName<T>, data: EntityData<T>): Promise<IPrimaryKey> {
entityName = Utils.className(entityName);
this.validator.validateParams(data, 'insert data');
return this.driver.nativeInsert(entityName, data);
const res = await this.driver.nativeInsert(entityName, data);

return res.insertId;
}

async nativeUpdate<T extends IEntityType<T>>(entityName: EntityName<T>, where: FilterQuery<T>, data: EntityData<T>): Promise<number> {
entityName = Utils.className(entityName);
where = SmartQueryHelper.processWhere(where as FilterQuery<T>);
this.validator.validateParams(data, 'update data');
this.validator.validateParams(where, 'update condition');
return this.driver.nativeUpdate(entityName, where, data);
const res = await this.driver.nativeUpdate(entityName, where, data);

return res.affectedRows;
}

async nativeDelete<T extends IEntityType<T>>(entityName: EntityName<T>, where: FilterQuery<T> | string | any): Promise<number> {
entityName = Utils.className(entityName);
where = SmartQueryHelper.processWhere(where as FilterQuery<T>);
this.validator.validateParams(where, 'delete condition');
return this.driver.nativeDelete(entityName, where);
const res = await this.driver.nativeDelete(entityName, where);

return res.affectedRows;
}

/**
Expand All @@ -160,7 +166,7 @@ export class EntityManager {
throw new Error('You cannot merge entity without identifier!');
}

const entity = Utils.isEntity<T>(data) ? data : this.getEntityFactory().create<T>(entityName, data, true);
const entity = Utils.isEntity<T>(data) ? data : this.getEntityFactory().create<T>(entityName, data);
EntityAssigner.assign(entity, data, true);
this.getUnitOfWork().addToIdentityMap(entity);

Expand All @@ -171,8 +177,7 @@ export class EntityManager {
* Creates new instance of given entity and populates it with given data
*/
create<T extends IEntityType<T>>(entityName: EntityName<T>, data: EntityData<T>): T {
entityName = Utils.className(entityName);
return this.getEntityFactory().create<T>(entityName, data, false);
return this.getEntityFactory().create<T>(entityName, data, false, false);
}

/**
Expand Down
1 change: 1 addition & 0 deletions lib/connections/Connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export abstract class Connection {
export interface QueryResult {
affectedRows: number;
insertId: number;
row?: Record<string, any>,
}

export interface ConnectionConfig {
Expand Down
23 changes: 15 additions & 8 deletions lib/connections/MongoConnection.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Collection, Db, DeleteWriteOpResultObject, InsertOneWriteOpResult, MongoClient, ObjectID, UpdateWriteOpResult } from 'mongodb';
import { Connection } from './Connection';
import { Collection, Db, MongoClient, ObjectID } from 'mongodb';
import { Connection, QueryResult } from './Connection';
import { Utils } from '../utils';
import { QueryOrder } from '../query';
import { FilterQuery } from '..';
Expand Down Expand Up @@ -63,35 +63,35 @@ export class MongoConnection extends Connection {
return res;
}

async insertOne<T>(collection: string, data: Partial<T>): Promise<InsertOneWriteOpResult> {
async insertOne<T>(collection: string, data: Partial<T>): Promise<QueryResult> {
data = this.convertObjectIds(data);
const now = Date.now();
const res = await this.getCollection(collection).insertOne(data);
const query = `db.getCollection("${collection}").insertOne(${JSON.stringify(data)});`;
this.logQuery(`${query} [took ${Date.now() - now} ms]`);

return res;
return this.transformResult(res);
}

async updateMany<T>(collection: string, where: FilterQuery<T>, data: Partial<T>): Promise<UpdateWriteOpResult> {
async updateMany<T>(collection: string, where: FilterQuery<T>, data: Partial<T>): Promise<QueryResult> {
where = this.convertObjectIds(where);
data = this.convertObjectIds(data);
const now = Date.now();
const res = await this.getCollection(collection).updateMany(where, { $set: data });
const query = `db.getCollection("${collection}").updateMany(${JSON.stringify(where)}, { $set: ${JSON.stringify(data)} });`;
this.logQuery(`${query} [took ${Date.now() - now} ms]`);

return res;
return this.transformResult(res);
}

async deleteMany<T>(collection: string, where: FilterQuery<T>): Promise<DeleteWriteOpResultObject> {
async deleteMany<T>(collection: string, where: FilterQuery<T>): Promise<QueryResult> {
where = this.convertObjectIds(where);
const res = await this.getCollection(collection).deleteMany(where);
const query = `db.getCollection("${collection}").deleteMany()`;
const now = Date.now();
this.logQuery(`${query} [took ${Date.now() - now} ms]`);

return res;
return this.transformResult(res);
}

async aggregate(collection: string, pipeline: any[]): Promise<any[]> {
Expand Down Expand Up @@ -135,4 +135,11 @@ export class MongoConnection extends Connection {
return payload;
}

private transformResult(res: any): QueryResult {
return {
affectedRows: res.modifiedCount || res.deletedCount || 0,
insertId: res.insertedId,
};
}

}
3 changes: 2 additions & 1 deletion lib/connections/PostgreSqlConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ export class PostgreSqlConnection extends Connection {

if (method === 'run') {
return {
affectedRows: res.rowCount,
affectedRows: res.rowCount || 0,
insertId: res.rows[0] ? res.rows[0].id : 0,
row: res.rows[0],
};
}

Expand Down
1 change: 1 addition & 0 deletions lib/decorators/Entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export interface EntityProperty {
primary: boolean;
reference: ReferenceType;
fieldName: string;
default?: string;
cascade: Cascade[];
onUpdate?: () => any;
owner: boolean;
Expand Down
1 change: 1 addition & 0 deletions lib/decorators/Property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ export type PropertyOptions = {
referenceColumnName?: string;
type?: any;
onUpdate?: () => any;
default?: string;
}
27 changes: 10 additions & 17 deletions lib/drivers/AbstractSqlDriver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EntityData, IEntityType, IPrimaryKey } from '../decorators';
import { DatabaseDriver } from './DatabaseDriver';
import { Connection } from '../connections/Connection';
import { Connection, QueryResult } from '../connections/Connection';
import { ReferenceType } from '../entity';
import { FilterQuery } from './IDatabaseDriver';
import { QueryBuilder, QueryOrder } from '../query';
Expand Down Expand Up @@ -41,7 +41,7 @@ export abstract class AbstractSqlDriver<C extends Connection> extends DatabaseDr
return +res.count;
}

async nativeInsert<T extends IEntityType<T>>(entityName: string, data: EntityData<T>): Promise<number> {
async nativeInsert<T extends IEntityType<T>>(entityName: string, data: EntityData<T>): Promise<QueryResult> {
const collections = this.extractManyToMany(entityName, data);
const pk = this.getPrimaryKeyField(entityName);

Expand All @@ -51,21 +51,21 @@ export abstract class AbstractSqlDriver<C extends Connection> extends DatabaseDr

const qb = this.createQueryBuilder(entityName);
const res = await qb.insert(data).execute('run');
const id = res.insertId || data[pk];
await this.processManyToMany(entityName, id, collections);
res.insertId = res.insertId || data[pk];
await this.processManyToMany(entityName, res.insertId, collections);

return id;
return res;
}

async nativeUpdate<T extends IEntityType<T>>(entityName: string, where: FilterQuery<T>, data: EntityData<T>): Promise<number> {
async nativeUpdate<T extends IEntityType<T>>(entityName: string, where: FilterQuery<T>, data: EntityData<T>): Promise<QueryResult> {
const pk = this.metadata[entityName] ? this.metadata[entityName].primaryKey : this.config.getNamingStrategy().referenceColumnName();

if (Utils.isPrimaryKey(where)) {
where = { [pk]: where };
}

const collections = this.extractManyToMany(entityName, data);
let res: any;
let res: QueryResult = { affectedRows: 0, insertId: 0 };

if (Object.keys(data).length) {
const qb = this.createQueryBuilder(entityName);
Expand All @@ -74,19 +74,16 @@ export abstract class AbstractSqlDriver<C extends Connection> extends DatabaseDr

await this.processManyToMany(entityName, Utils.extractPK(data[pk] || where, this.metadata[entityName])!, collections);

return res ? res.affectedRows : 0;
return res;
}

async nativeDelete<T extends IEntityType<T>>(entityName: string, where: FilterQuery<T> | string | any): Promise<number> {
async nativeDelete<T extends IEntityType<T>>(entityName: string, where: FilterQuery<T> | string | any): Promise<QueryResult> {
if (Utils.isPrimaryKey(where)) {
const pk = this.metadata[entityName] ? this.metadata[entityName].primaryKey : this.config.getNamingStrategy().referenceColumnName();
where = { [pk]: where };
}

const qb = this.createQueryBuilder(entityName);
const res = await qb.delete(where).execute('run');

return res.affectedRows;
return this.createQueryBuilder(entityName).delete(where).execute('run');
}

protected createQueryBuilder(entityName: string): QueryBuilder {
Expand Down Expand Up @@ -135,8 +132,4 @@ export abstract class AbstractSqlDriver<C extends Connection> extends DatabaseDr
}
}

protected getPrimaryKeyField(entityName: string): string {
return this.metadata[entityName] ? this.metadata[entityName].primaryKey : this.config.getNamingStrategy().referenceColumnName();
}

}
12 changes: 8 additions & 4 deletions lib/drivers/DatabaseDriver.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FilterQuery, IDatabaseDriver } from './IDatabaseDriver';
import { EntityData, EntityMetadata, EntityProperty, IEntity, IEntityType, IPrimaryKey } from '../decorators';
import { MetadataStorage } from '../metadata';
import { Connection } from '../connections/Connection';
import { Connection, QueryResult } from '../connections/Connection';
import { Configuration, Utils } from '../utils';
import { QueryOrder } from '../query';
import { Platform } from '../platforms/Platform';
Expand All @@ -21,11 +21,11 @@ export abstract class DatabaseDriver<C extends Connection> implements IDatabaseD

abstract async findOne<T extends IEntity>(entityName: string, where: FilterQuery<T> | string, populate: string[]): Promise<T | null>;

abstract async nativeInsert<T extends IEntity>(entityName: string, data: EntityData<T>): Promise<IPrimaryKey>;
abstract async nativeInsert<T extends IEntityType<T>>(entityName: string, data: EntityData<T>): Promise<QueryResult>;

abstract async nativeUpdate<T extends IEntity>(entityName: string, where: FilterQuery<IEntity> | IPrimaryKey, data: EntityData<T>): Promise<number>;
abstract async nativeUpdate<T extends IEntity>(entityName: string, where: FilterQuery<IEntity> | IPrimaryKey, data: EntityData<T>): Promise<QueryResult>;

abstract async nativeDelete<T extends IEntity>(entityName: string, where: FilterQuery<IEntity> | IPrimaryKey): Promise<number>;
abstract async nativeDelete<T extends IEntity>(entityName: string, where: FilterQuery<IEntity> | IPrimaryKey): Promise<QueryResult>;

abstract async count<T extends IEntity>(entityName: string, where: FilterQuery<T>): Promise<number>;

Expand Down Expand Up @@ -126,6 +126,10 @@ export abstract class DatabaseDriver<C extends Connection> implements IDatabaseD
return this.platform;
}

protected getPrimaryKeyField(entityName: string): string {
return this.metadata[entityName] ? this.metadata[entityName].primaryKey : this.config.getNamingStrategy().referenceColumnName();
}

private async runTransaction(method: 'beginTransaction' | 'commit' | 'rollback'): Promise<void> {
if (this.transactionLevel === 1 || this.platform.supportsSavePoints()) {
const useSavepoint = this.transactionLevel !== 1 && this.platform.supportsSavePoints();
Expand Down
8 changes: 4 additions & 4 deletions lib/drivers/IDatabaseDriver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { EntityData, EntityProperty, IEntity, IPrimaryKey } from '../decorators';
import { Connection } from '../connections/Connection';
import { Connection, QueryResult } from '../connections/Connection';
import { QueryOrder } from '../query';
import { Platform } from '../platforms/Platform';

Expand All @@ -17,11 +17,11 @@ export interface IDatabaseDriver<C extends Connection = Connection> {
*/
findOne<T extends IEntity>(entityName: string, where: FilterQuery<T> | IPrimaryKey, populate?: string[]): Promise<T | null>;

nativeInsert<T extends IEntity>(entityName: string, data: EntityData<T>): Promise<IPrimaryKey>;
nativeInsert<T extends IEntity>(entityName: string, data: EntityData<T>): Promise<QueryResult>;

nativeUpdate<T extends IEntity>(entityName: string, where: FilterQuery<T> | IPrimaryKey, data: EntityData<T>): Promise<number>;
nativeUpdate<T extends IEntity>(entityName: string, where: FilterQuery<T> | IPrimaryKey, data: EntityData<T>): Promise<QueryResult>;

nativeDelete<T extends IEntity>(entityName: string, where: FilterQuery<T> | IPrimaryKey): Promise<number>;
nativeDelete<T extends IEntity>(entityName: string, where: FilterQuery<T> | IPrimaryKey): Promise<QueryResult>;

count<T extends IEntity>(entityName: string, where: FilterQuery<T>): Promise<number>;

Expand Down
17 changes: 7 additions & 10 deletions lib/drivers/MongoDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { EntityData, IEntityType, IPrimaryKey } from '../decorators';
import { QueryOrder } from '../query';
import { Utils } from '../utils';
import { MongoPlatform } from '../platforms/MongoPlatform';
import { QueryResult } from '../connections/Connection';

export class MongoDriver extends DatabaseDriver<MongoConnection> {

Expand Down Expand Up @@ -34,34 +35,30 @@ export class MongoDriver extends DatabaseDriver<MongoConnection> {
return this.connection.countDocuments<T>(this.getCollectionName(entityName), where);
}

async nativeInsert<T extends IEntityType<T>>(entityName: string, data: EntityData<T>): Promise<ObjectID> {
async nativeInsert<T extends IEntityType<T>>(entityName: string, data: EntityData<T>): Promise<QueryResult> {
data = this.renameFields(entityName, data);
const res = await this.connection.insertOne<EntityData<T>>(this.getCollectionName(entityName), data);

return res.insertedId;
return this.connection.insertOne<EntityData<T>>(this.getCollectionName(entityName), data);
}

async nativeUpdate<T extends IEntityType<T>>(entityName: string, where: FilterQuery<T> | IPrimaryKey, data: EntityData<T>): Promise<number> {
async nativeUpdate<T extends IEntityType<T>>(entityName: string, where: FilterQuery<T> | IPrimaryKey, data: EntityData<T>): Promise<QueryResult> {
if (Utils.isPrimaryKey(where)) {
where = { _id: new ObjectID(where as string) };
}

where = this.renameFields(entityName, where) as FilterQuery<T>;
data = this.renameFields(entityName, data);
const res = await this.connection.updateMany<T>(this.getCollectionName(entityName), where, data);

return res.modifiedCount;
return this.connection.updateMany<T>(this.getCollectionName(entityName), where, data);
}

async nativeDelete<T extends IEntityType<T>>(entityName: string, where: FilterQuery<T> | IPrimaryKey): Promise<number> {
async nativeDelete<T extends IEntityType<T>>(entityName: string, where: FilterQuery<T> | IPrimaryKey): Promise<QueryResult> {
if (Utils.isPrimaryKey(where)) {
where = { _id: new ObjectID(where as string) };
}

where = this.renameFields(entityName, where) as FilterQuery<T>;
const res = await this.connection.deleteMany<T>(this.getCollectionName(entityName), where);

return res.deletedCount || 0;
return this.connection.deleteMany<T>(this.getCollectionName(entityName), where);
}

async aggregate(entityName: string, pipeline: any[]): Promise<any[]> {
Expand Down
9 changes: 5 additions & 4 deletions lib/drivers/PostgreSqlDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import { AbstractSqlDriver } from './AbstractSqlDriver';
import { EntityData, IEntityType } from '../decorators';
import { QueryType } from '../query';
import { PostgreSqlPlatform } from '../platforms/PostgreSqlPlatform';
import { QueryResult } from '../connections/Connection';

export class PostgreSqlDriver extends AbstractSqlDriver<PostgreSqlConnection> {

protected readonly connection = new PostgreSqlConnection(this.config);
protected readonly platform = new PostgreSqlPlatform();

async nativeInsert<T extends IEntityType<T>>(entityName: string, data: EntityData<T>): Promise<number> {
async nativeInsert<T extends IEntityType<T>>(entityName: string, data: EntityData<T>): Promise<QueryResult> {
const collections = this.extractManyToMany(entityName, data);
const qb = this.createQueryBuilder(entityName).insert(data);
const params = qb.getParams();
Expand All @@ -23,10 +24,10 @@ export class PostgreSqlDriver extends AbstractSqlDriver<PostgreSqlConnection> {

const res = await this.connection.execute(sql, params, 'run');
const pk = this.getPrimaryKeyField(entityName);
const id = res.insertId || data[pk];
await this.processManyToMany(entityName, id, collections);
res.insertId = res.insertId || data[pk];
await this.processManyToMany(entityName, res.insertId, collections);

return id;
return res;
}

}
11 changes: 7 additions & 4 deletions lib/entity/EntityFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class EntityFactory {
private readonly driver: IDatabaseDriver,
private readonly config: Configuration) { }

create<T extends IEntityType<T>>(entityName: EntityName<T>, data: EntityData<T>, initialized = true): T {
create<T extends IEntityType<T>>(entityName: EntityName<T>, data: EntityData<T>, initialized = true, merge = true): T {
entityName = Utils.className(entityName);
data = Object.assign({}, data);
const meta = this.metadata[entityName];
Expand All @@ -30,7 +30,7 @@ export class EntityFactory {
data[meta.primaryKey] = id;
}

const entity = this.createEntity(data, meta);
const entity = this.createEntity(data, meta, merge);
this.hydrator.hydrate(entity, meta, data);

if (initialized) {
Expand All @@ -42,7 +42,7 @@ export class EntityFactory {
return entity;
}

private createEntity<T extends IEntityType<T>>(data: EntityData<T>, meta: EntityMetadata<T>): T {
private createEntity<T extends IEntityType<T>>(data: EntityData<T>, meta: EntityMetadata<T>, merge: boolean): T {
const Entity = require(meta.path)[meta.name];

if (!data[meta.primaryKey]) {
Expand All @@ -58,7 +58,10 @@ export class EntityFactory {
// creates new entity instance, with possibility to bypass constructor call when instancing already persisted entity
const entity = Object.create(Entity.prototype);
entity[meta.primaryKey] = data[meta.primaryKey];
this.unitOfWork.addToIdentityMap(entity);

if (merge) {
this.unitOfWork.addToIdentityMap(entity);
}

return entity;
}
Expand Down

0 comments on commit 6b435d1

Please sign in to comment.