es-entity
Version:
ORM framework for Node js based on Ecmascript 6 and Typescript.
220 lines (182 loc) • 6.9 kB
text/typescript
import { Transform } from 'stream';
import Context from '../Context.js';
import { TABLE_COLUMN_KEYS } from '../decorators/Constants.js';
import * as model from '../model/index.js';
import * as types from '../model/types.js';
import * as sql from '../sql/index.js';
import DBSet from './DBSet.js';
import IQuerySet from './IQuerySet.js';
import SelectQuerySet from './SelectQuerySet.js';
/**
* QuerySet
*/
class QuerySet<T extends Object> extends IQuerySet<T> {
protected EntityType: types.IEntityType<T>;
protected dbSet: DBSet;
alias: string;
stat = new sql.Statement();
selectKeys: string[];
constructor(context: Context, EntityType: types.IEntityType<T>, dbSet: DBSet) {
super();
this.context = context;
this.EntityType = EntityType;
this.dbSet = dbSet;
this.alias = this.dbSet.tableName.charAt(0);
this.stat.collection.value = this.dbSet.tableName;
this.stat.collection.alias = this.alias;
this.selectKeys = Reflect.getMetadata(TABLE_COLUMN_KEYS, this.EntityType.prototype);
}
// getEntity() {
// let res = new this.EntityType();
// let keys: string[] = Reflect.getMetadata(TABLE_COLUMN_KEYS, this.EntityType.prototype);
// keys.forEach(key => {
// let field = Reflect.get(res, key);
// if (field instanceof model.LinkObject || field instanceof model.LinkArray) {
// field.bind(this.context, res);
// }
// });
// return res;
// }
// Select Functions
prepareSelectStatement() {
this.stat.command = sql.types.Command.SELECT;
// Get all Columns
let targetKeys: string[] = Reflect.getMetadata(TABLE_COLUMN_KEYS, this.EntityType.prototype);
let fields = this.dbSet.filterFields(targetKeys);
this.stat.columns = this.getColumnExprs(fields, this.alias);
}
async list() {
this.prepareSelectStatement();
let result = await this.context.execute(this.stat);
return result.rows.map(this.transformer);
}
transformer(row: any) {
let obj = new this.EntityType();
this.selectKeys.forEach(key => {
let fieldMapping = this.dbSet.fieldMap.get(key);
if (fieldMapping) {
let colName = fieldMapping.colName;
let val = row[colName];
Reflect.set(obj, key, val);
} else {
let field = Reflect.get(obj, key);
if (field instanceof model.LinkObject || field instanceof model.LinkArray) {
field.bind(this.context, obj);
}
}
});
return obj;
}
async stream() {
this.prepareSelectStatement();
let dataStream = await this.context.stream(this.stat);
let that = this;
return dataStream.pipe(
new Transform({
transform(chunk, encoding, callback) {
callback(null, that.transformer(chunk));
}
})
);
}
async listPlain(keys: (keyof T)[]): Promise<Partial<T>[]> {
this.stat.command = sql.types.Command.SELECT;
let fields = this.dbSet.filterFields(<string[]>keys);
this.stat.columns = this.getColumnExprs(fields, this.alias);
let input = await this.context.execute(this.stat);
let data = input.rows.map(row => {
let obj: Partial<T> = {};
fields.forEach(field => {
let colName = field.colName;
let val = row[colName] ?? row[colName.toLowerCase()] ?? row[colName.toUpperCase()];
Reflect.set(obj, field.fieldName, val);
});
return obj;
});
return data;
}
// Selection Functions
select<U extends Object>(EntityType: types.IEntityType<U>): IQuerySet<U> {
let res = new SelectQuerySet(this.context, EntityType, this.dbSet);
return res;
}
// Conditional Functions
where(param: types.IWhereFunc<model.WhereExprBuilder<T>>, ...args: any[]) {
let fieldMap = new Map(Array.from(this.dbSet.fieldMap));
let eb = new model.WhereExprBuilder<T>(fieldMap);
let res = param(eb, args);
if (res && res instanceof sql.Expression && res.exps.length > 0) {
this.stat.where = this.stat.where.add(res);
}
return this;
}
groupBy(param: types.IArrFieldFunc<model.GroupExprBuilder<T>>) {
let fieldMap = new Map(Array.from(this.dbSet.fieldMap));
let eb = new model.GroupExprBuilder<T>(fieldMap);
let res = param(eb);
if (res && Array.isArray(res)) {
res.forEach(expr => {
if (expr instanceof sql.Expression && expr.exps.length > 0) {
this.stat.groupBy.push(expr);
}
});
}
return this;
}
orderBy(param: types.IArrFieldFunc<model.OrderExprBuilder<T>>) {
let fieldMap = new Map(Array.from(this.dbSet.fieldMap));
let eb = new model.OrderExprBuilder<T>(fieldMap);
let res = param(eb);
if (res && Array.isArray(res)) {
res.forEach(a => {
if (a instanceof sql.Expression && a.exps.length > 0) {
this.stat.orderBy.push(a);
}
});
}
return this;
}
limit(size: number, index?: number) {
this.stat.limit = new sql.Expression(null, sql.types.Operator.Limit);
this.stat.limit.exps.push(new sql.Expression(size.toString()));
if (index) {
this.stat.limit.exps.push(new sql.Expression(index.toString()));
}
return this;
}
async update(entity: T, ...updatedKeys: (keyof T)[]) {
this.stat.command = sql.types.Command.UPDATE;
// Dynamic update
let keys: string[] = Reflect.getMetadata(TABLE_COLUMN_KEYS, entity.constructor.prototype);
let fields = this.dbSet.filterFields(keys).filter(field => (<(string | symbol)[]>updatedKeys).includes(field.fieldName));
if (fields.length == 0) throw new Error('Update Fields Empty');
fields.forEach(field => {
let c1 = new sql.Expression(field.colName);
let c2 = new sql.Expression('?');
let val = Reflect.get(entity, field.fieldName);
c2.args.push(val);
let expr = new sql.Expression(null, sql.types.Operator.Equal, c1, c2);
this.stat.columns.push(expr);
});
let result = await this.context.execute(this.stat);
if (result.error) throw result.error;
}
async delete() {
this.stat.command = sql.types.Command.DELETE;
let result = await this.context.execute(this.stat);
if (result.error) throw result.error;
}
// join<A extends Object>(coll: IQuerySet<A>, param: types.IJoinFunc<model.WhereExprBuilder<T>, model.GroupExprBuilder<A>>, joinType?: sql.types.Join): IQuerySet<T & A> {
// joinType = joinType ?? sql.types.Join.InnerJoin;
// let temp: sql.Expression | null = null;
// if (param && param instanceof Function) {
// let mainObj = new model.WhereExprBuilder<T>(this.dbSet.fieldMap);
// let joinObj = new model.GroupExprBuilder(coll.) coll.getEntity();
// temp = param(mainObj, joinObj);
// }
// if (!(temp && temp instanceof sql.Expression && temp.exps.length > 0))
// throw new Error('Invalid Join');
// return new JoinQuerySet<T, A>(this, coll, joinType, temp);
// }
}
export default QuerySet;