blow-data
Version:
Data access layer for Blow.
147 lines (124 loc) • 4.54 kB
text/typescript
'use strict';
import {isUndefined, isFunction, isNull} from 'util';
import {Observable} from 'rxjs';
import {IQueryWhere, IQuery, Query, IQueryObject} from 'blow-query';
import * as _ from './helpers';
import {manager} from './manager';
import {
IModelRelationMetadataOptions,
IModelRelationMetadata,
IPersistedModelConstructor
} from './interfaces';
export class ModelRelationMetadata implements IModelRelationMetadata {
protected _name: string;
protected _type: string;
protected _model: IPersistedModelConstructor | string;
protected _foreignKey: string;
protected _hidden: boolean;
constructor(options: IModelRelationMetadataOptions) {
this._name = options.name;
this._type = options.type;
this._model = options.model;
this._foreignKey = options.foreignKey;
this._hidden = isUndefined(options.hidden) ? false : options.hidden;
}
get name(): string {
return this._name;
}
get type(): string {
return this._type;
}
get model(): IPersistedModelConstructor | string {
return this._model;
}
get foreignKey(): string {
return this._foreignKey;
}
get hidden(): boolean {
return this._hidden;
}
apply(model: IPersistedModelConstructor): void {
switch(this.type) {
case 'belongsTo': {
const relationName = this.name;
const targetModel = <IPersistedModelConstructor>(_.getModel(this.model));
const targetKey = _.getModel(this.model).metadata.idProperty;
if(!model.metadata.hasProperty(this.foreignKey)) {
model.metadata.defineProperty({
name: this.foreignKey,
type: targetKey.type
});
}
const rootModel = model;
const rootKey = model.metadata.getProperty(this.foreignKey);
Object.defineProperty(model.prototype, relationName, {
enumerable: false,
configurable: false,
get: function() {
const inst = this;
return function(data) {
if(arguments.length > 0) {
inst[rootKey.name] = data[targetKey.name];
}
else {
if(inst[rootKey.name]) {
return targetModel.findById(inst[rootKey.name]);
} else {
return Observable.of(undefined);
}
}
}
}
});
} break;
case 'hasMany': {
const relationName = this.name;
const rootModel = model;
const rootKey = model.metadata.idProperty;
const targetMetadata = _.getModel(this.model).metadata;
if(!targetMetadata.hasProperty(this.foreignKey)) {
targetMetadata.defineProperty({
name: this.foreignKey,
type: rootKey.type
});
}
const targetModel = <IPersistedModelConstructor>(_.getModel(this.model));
const targetKey = targetMetadata.getProperty(this.foreignKey);
Object.defineProperty(model.prototype, relationName, {
enumerable: false,
configurable: false,
get: function() {
const inst = this;
return {
create(data: {[key: string]: any}) {
data[targetKey.name] = inst[rootKey.name];
return targetModel.create(data);
},
find(query?: IQuery | IQueryObject) {
const q: IQuery = new Query(query);
q.equal(targetKey.name, inst[rootKey.name]);
return targetModel.find(q);
},
findById(id: any) {
const q: IQuery = new Query();
q.equal(targetKey.name, inst[rootKey.name]);
q.equal(targetModel.metadata.idProperty.name, id);
return targetModel.findOne(q);
},
destroy(query?: IQueryWhere) {
const q: IQuery = new Query({where: query});
q.equal(targetKey.name, inst[rootKey.name]);
return targetModel.destroy(q.toJSON().where);
},
destroyById(id: any) {
const q: IQuery = new Query();
q.equal(targetModel.metadata.idProperty.name, id);
return this.destroy(q.toJSON().where);
}
}
}
});
} break;
}
}
}