From 43fe69649e8e222668c0e5ee9973aaa6e733453e Mon Sep 17 00:00:00 2001 From: Aaron Aichlmayr Date: Thu, 4 Aug 2016 16:53:53 -0500 Subject: [PATCH 01/14] Working on adding relationships --- angular2/DataContract.ts | 3 ++ node/DataConnection.spec.ts | 7 ++++ node/DataContract.spec.class.ts | 14 +++++++ node/DataContract.spec.ts | 9 +++++ node/DataContract.ts | 11 +++++ node/http.spec.ts | 6 +++ node/index.ts | 2 +- node/relationships/OneToOne.ts | 28 +++++++++++++ node/relationships/RelationshipCache.ts | 40 ++++++++++++++++++ node/relationships/index.ts | 2 + node/relationships/relatedField.ts | 54 +++++++++++++++++++++++++ package.json | 4 +- shared/DataObject.ts | 12 ++++-- shared/Types.ts | 3 +- shared/field.ts | 2 +- 15 files changed, 188 insertions(+), 9 deletions(-) create mode 100644 node/relationships/OneToOne.ts create mode 100644 node/relationships/RelationshipCache.ts create mode 100644 node/relationships/index.ts create mode 100644 node/relationships/relatedField.ts diff --git a/angular2/DataContract.ts b/angular2/DataContract.ts index b73c488..4456e70 100644 --- a/angular2/DataContract.ts +++ b/angular2/DataContract.ts @@ -12,6 +12,9 @@ import 'rxjs/add/operator/toPromise'; import { Observable } from 'rxjs/Observable'; export abstract class DataContract implements IDataContract { + // tslint:disable-next-line:no-unused-variable + private static contract = true; + @field() public id: number; @field(Types.dateTimeTz) diff --git a/node/DataConnection.spec.ts b/node/DataConnection.spec.ts index 5b88a92..a1e0e89 100644 --- a/node/DataConnection.spec.ts +++ b/node/DataConnection.spec.ts @@ -15,6 +15,7 @@ describe('node/DataConnection', function() { mockery.registerMock('sequelize', Sequelize); mockery.registerAllowables([ './connect', + '../connect', './DataContract', './DataConnection', './DataContract.spec.class', @@ -23,7 +24,13 @@ describe('node/DataConnection', function() { './field', '../shared/field', '../shared/Types', + '../../shared/field', + '../../shared/Types', './Types', + './relationships', + './relatedField', + './OneToOne', + './RelationshipCache', 'moment', 'lodash', 'bunyan', diff --git a/node/DataContract.spec.class.ts b/node/DataContract.spec.class.ts index 02db96f..383c929 100644 --- a/node/DataContract.spec.class.ts +++ b/node/DataContract.spec.class.ts @@ -1,6 +1,8 @@ import {DataContract} from './DataContract'; +import {OneToOne, relatedField} from './relationships'; import {field} from './field'; import {Types} from '../shared/Types'; +import {register} from '../shared/DataObject'; import * as moment from 'moment'; @@ -35,3 +37,15 @@ export class BadProp extends DataContract { @field( 'a') public dateThing: moment.Moment; } + +@register('test') +export class OneToOneA extends DataContract { + @relatedField(() => OneToOneB) + public b: OneToOne; +} + +@register('test') +export class OneToOneB extends DataContract { + @relatedField(() => OneToOneA) + public a: OneToOne; +} diff --git a/node/DataContract.spec.ts b/node/DataContract.spec.ts index 3348cbf..268dc2d 100644 --- a/node/DataContract.spec.ts +++ b/node/DataContract.spec.ts @@ -3,6 +3,7 @@ import * as chai from 'chai'; import * as classTypes from './DataContract.spec.class'; import * as moment from 'moment'; import * as sinon from 'sinon'; +import * as mockConnect from '../mocks/connect'; import {Sequelize, Model} from '../mocks/Sequelize'; @@ -21,6 +22,8 @@ describe('node/DataContract', function() { '../shared/field', '../shared/Types', './Types', + './relationships', + './OneToOne', 'moment', 'lodash', 'debug' @@ -30,6 +33,12 @@ describe('node/DataContract', function() { connect.connect('a', 'b', 'c'); classes = require('./DataContract.spec.class'); + + mockConnect.reset(connect); + var a = (new classes.OneToOneA()); + a.b.fetch(); + var b = (new classes.OneToOneB()); + b.a.fetch(); }); describe('existing', function() { diff --git a/node/DataContract.ts b/node/DataContract.ts index c62d6b4..29137ab 100644 --- a/node/DataContract.ts +++ b/node/DataContract.ts @@ -10,7 +10,18 @@ import { Types } from '../shared/Types'; import { IDataContract } from '../shared/DataObject'; import { logger } from './connect'; +export interface IDataContractConstruct { + new ( + instance: any, + model: sequelize.Model + ): T; + name?: string; +} + export abstract class DataContract implements IDataContract { + // tslint:disable-next-line:no-unused-variable + private static contract = true; + private get fields(): string[] { return Reflect.getMetadata('ORM:fields', this); } diff --git a/node/http.spec.ts b/node/http.spec.ts index 088ecbe..74eb492 100644 --- a/node/http.spec.ts +++ b/node/http.spec.ts @@ -19,8 +19,14 @@ describe('node/http', function() { './DataConnection', './DataConnection.spec.class', './DataContract.spec.class', + './DataContract', + './field', + './relationships', + './OneToOne', '../shared/DataObject', + '../shared/Types', './connect', + 'moment', 'debug' ]); diff --git a/node/index.ts b/node/index.ts index 86b0b4d..bd17a77 100644 --- a/node/index.ts +++ b/node/index.ts @@ -4,4 +4,4 @@ export {DataContract} from './DataContract'; export {DataConnection} from './DataConnection'; export {register} from '../shared/DataObject'; export {HTTP} from './http'; -export {ILogger} from './ILogger'; +export {ILogger} from './ILogger'; \ No newline at end of file diff --git a/node/relationships/OneToOne.ts b/node/relationships/OneToOne.ts new file mode 100644 index 0000000..a97421a --- /dev/null +++ b/node/relationships/OneToOne.ts @@ -0,0 +1,28 @@ +import { DataContract, IDataContractConstruct } from '../DataContract'; +import { RelationshipCache } from './RelationshipCache'; + +export class OneToOne { + public static fetch(from: DataContract, target: IDataContractConstruct): Promise { + const model = RelationshipCache.get( from.constructor, target); + const dbId = Reflect.getMetadata('ORM:dbId', from); + + const where: any = {}; + where[dbId] = from.id; + + return model.findOne({ + where: where + }).then((data) => { + console.log(data); + }); + } + + public constructor(private parent: DataContract, private target: () => IDataContractConstruct) {} + + public fetch(): Promise { + return OneToOne.fetch(this.parent, this.target()); + } + + public set(obj: T): Promise { + return null; + } +} diff --git a/node/relationships/RelationshipCache.ts b/node/relationships/RelationshipCache.ts new file mode 100644 index 0000000..716c29b --- /dev/null +++ b/node/relationships/RelationshipCache.ts @@ -0,0 +1,40 @@ +import * as sequelize from 'sequelize'; + +import {DataContract, IDataContractConstruct} from '../DataContract'; +import {connection} from '../connect'; + +export class RelationshipCache { + private static cache: sequelize.Model[] = []; + + public static get< + T extends DataContract, + U extends DataContract + >( + obj1: IDataContractConstruct, + obj2: IDataContractConstruct + ): sequelize.Model { + const names = []; + + names[0] = Reflect.getMetadata('ORM:dbId', obj1); + names[1] = Reflect.getMetadata('ORM:dbId', obj2); + + names.sort(); + + const modelName = names[0] + '-' + names[1]; + + if (!RelationshipCache.cache[modelName]) { + const model = {}; + model[names[0]] = { + type: sequelize.INTEGER + }; + model[names[1]] = { + type: sequelize.INTEGER + }; + + RelationshipCache.cache[modelName] = connection.define(names[0] + '-' + names[1], model); + RelationshipCache.cache[modelName].sync(); + } + + return RelationshipCache.cache[modelName]; + } +} diff --git a/node/relationships/index.ts b/node/relationships/index.ts new file mode 100644 index 0000000..38963be --- /dev/null +++ b/node/relationships/index.ts @@ -0,0 +1,2 @@ +export { relatedField } from './relatedField'; +export { OneToOne } from './OneToOne'; \ No newline at end of file diff --git a/node/relationships/relatedField.ts b/node/relationships/relatedField.ts new file mode 100644 index 0000000..3bcdc95 --- /dev/null +++ b/node/relationships/relatedField.ts @@ -0,0 +1,54 @@ +// DO NOT REMOVE THIS IMPORT it is required for this file to function +// tslint:disable-next-line:no-unused-variable +import * as reflectMetadata from 'reflect-metadata'; +import * as moment from 'moment'; + +import {field as sharedField} from '../../shared/field'; +import {Types} from '../../shared/Types'; +import {OneToOne} from './OneToOne'; +import {DataContract, IDataContractConstruct} from '../DataContract'; + +export function relatedField( + RelatedType: () => IDataContractConstruct, + hidden: boolean = false +): (target: any, key: string) => any { + return function relatedField(target: any, key: string) { + const JsType: any = Reflect.getMetadata('design:type', target, key); + + let type: Types = undefined; + + switch (JsType) { + case(OneToOne): + type = Types.relationshipOneToOne; + break; + /* istanbul ignore next */ + default: + throw new TypeError('Unknown js type found! ' + JsType.name); + } + + const getter = function () { + if (!this['_' + key]) { + this['_' + key] = new JsType(this, RelatedType); + } + return this['_' + key]; + }; + const setter = () => { /* */ }; + + sharedField( + target, + key, + { + getter: getter, + setter: setter + }, + type + ); + + Reflect.defineMetadata('ORM:hidden', hidden, target, key); + + return { + getter: getter, + setter: setter + }; + }; +} diff --git a/package.json b/package.json index 05a2ac8..0176ddc 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,8 @@ "chai-as-promised": "^5.3.0", "coveralls": "^2.11.9", "istanbul": "^1.1.0-alpha.1", - "livereload": "^0.4.1", - "mocha": "^2.5.3", + "livereload": "^0.5.0", + "mocha": "^3.0.1", "mockery": "^1.7.0", "nodemon": "^1.9.2", "rxjs": "^5.0.0-beta.6", diff --git a/shared/DataObject.ts b/shared/DataObject.ts index 7c35a46..0864b5c 100644 --- a/shared/DataObject.ts +++ b/shared/DataObject.ts @@ -24,10 +24,14 @@ export const registeredClasses: registeredClassMap = * This registers the class with the API ORM system */ export function register(moduleId: string, apiHidden: boolean = false) { - return (target: new (...args: any[]) => IDataConnection): any => { + return (target: new (...args: any[]) => IDataConnection | IDataContract): any => { const idx = moduleId + '.' + ( target).name; - registeredClasses[idx] = target; - Reflect.defineMetadata('ORM:registeredIndex', idx, target); - Reflect.defineMetadata('ORM:apiHidden', apiHidden, target); + if (( target).contract === true) { + Reflect.defineMetadata('ORM:dbId', idx, target); + } else { + registeredClasses[idx] = target; + Reflect.defineMetadata('ORM:registeredIndex', idx, target); + Reflect.defineMetadata('ORM:apiHidden', apiHidden, target); + } }; } diff --git a/shared/Types.ts b/shared/Types.ts index a1af37d..ce90b44 100644 --- a/shared/Types.ts +++ b/shared/Types.ts @@ -3,5 +3,6 @@ export enum Types { integer, bigInt, float, - dateTimeTz + dateTimeTz, + relationshipOneToOne } diff --git a/shared/field.ts b/shared/field.ts index 0c88a95..6182edb 100644 --- a/shared/field.ts +++ b/shared/field.ts @@ -25,7 +25,7 @@ export function field(target: any, key: string, actions: IActions, type?: Types) }); if (!type) { - const jsType: any = Reflect.getMetadata("design:type", target, key); + const jsType: any = Reflect.getMetadata('design:type', target, key); switch (jsType.name) { case 'String': type = Types.string; From 5bc0d8e449ccba0e891f6fda4246c75ab44c2e19 Mon Sep 17 00:00:00 2001 From: Aaron Aichlmayr Date: Thu, 11 Aug 2016 11:56:11 -0500 Subject: [PATCH 02/14] Moved the model to the connection objects --- node/DataConnection.spec.ts | 12 ++--- node/DataConnection.ts | 84 +++++---------------------------- node/DataContract.spec.class.ts | 27 ++++++----- node/DataContract.spec.ts | 8 ++-- node/DataContract.ts | 73 ++++++++++++++++++++++++++-- shared/DataObject.ts | 13 +++++ 6 files changed, 118 insertions(+), 99 deletions(-) diff --git a/node/DataConnection.spec.ts b/node/DataConnection.spec.ts index a1e0e89..6dd819b 100644 --- a/node/DataConnection.spec.ts +++ b/node/DataConnection.spec.ts @@ -90,7 +90,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "NoProp", + "test.NoProp", {}, { "freezeTableName": true @@ -111,7 +111,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "StringProp", + "test.StringProp", { "stringy": { type: sequelize.STRING @@ -136,7 +136,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "FloatProp", + "test.FloatProp", { "floaty": { type: sequelize.FLOAT @@ -161,7 +161,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "IntProp", + "test.IntProp", { "inty": { type: sequelize.INTEGER @@ -186,7 +186,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "BigIntProp", + "test.BigIntProp", { "inty": { type: sequelize.BIGINT @@ -211,7 +211,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "DateProp", + "test.DateProp", { "dateThing": { type: sequelize.DATE diff --git a/node/DataConnection.ts b/node/DataConnection.ts index 6870455..9ad83d9 100644 --- a/node/DataConnection.ts +++ b/node/DataConnection.ts @@ -4,17 +4,11 @@ import * as reflectMetadata from 'reflect-metadata'; import * as sequelize from 'sequelize'; import * as _ from 'lodash'; -import { Types } from '../shared/Types'; import { IDataConnection } from '../shared/DataObject'; -import { connection } from './connect'; import {DataContract} from './DataContract'; export abstract class DataConnection implements IDataConnection { - private static syncedModels: { - [modelName: string]: sequelize.Model; - } = {}; - private _dummyContract: T = null; private get dummyContract(): T { if (!this._dummyContract) { @@ -31,74 +25,18 @@ export abstract class DataConnection implements IDataCon return this._fields; } + private get model(): sequelize.Model { + return this.getContract().getSequelizeModel(); + } + // This is used in some of the decorators // tslint:disable-next-line:no-unused-variable private instance: any = null; - private get model(): sequelize.Model { - return DataConnection.syncedModels[( this.constructor).name]; - } - private set model(val: sequelize.Model) { - DataConnection.syncedModels[( this.constructor).name] = val; - // TODO make updates more graceful - val.sync(); - } - constructor(injector?: any) { - let className = ( this.constructor).name; - - if (!this.model) { - const model: any = {}; - const fields: string[] = this.fields; - _.forEach(fields, (fieldName) => { - const type: Types = Reflect.getMetadata( - "ORM:type", - this.dummyContract, - fieldName - ); - - switch (type) { - case Types.string: - model[fieldName] = { - type: sequelize.STRING - }; - break; - case Types.float: - model[fieldName] = { - type: sequelize.FLOAT - }; - break; - case Types.integer: - model[fieldName] = { - type: sequelize.INTEGER - }; - break; - case Types.bigInt: - model[fieldName] = { - type: sequelize.BIGINT - }; - break; - case Types.dateTimeTz: - model[fieldName] = { - type: sequelize.DATE - }; - break; - default: - throw new TypeError( - 'Field of unknown type found! ' + - 'Field Name:' + fieldName + ' ' + - 'Field Type: ' + type - ); - } - }); - this.model = connection.define( - className, - model, - { - freezeTableName: true // Model tableName will be the same as the model name - } - ); - } + // Load the model once to make sure it gets created at initialization + // instead of when it's first acted upon + this.getContract().getSequelizeModel(); } public fetch(id: number): Promise { @@ -136,8 +74,8 @@ export abstract class DataConnection implements IDataCon /** * This feeds the data contract into the system */ - protected abstract getContract(): new( - instance: any, - model: sequelize.Model - ) => T; + protected abstract getContract(): { + new(instance: any, model: sequelize.Model): T; + getSequelizeModel(): sequelize.Model; + }; } diff --git a/node/DataContract.spec.class.ts b/node/DataContract.spec.class.ts index 383c929..0df9714 100644 --- a/node/DataContract.spec.class.ts +++ b/node/DataContract.spec.class.ts @@ -2,50 +2,51 @@ import {DataContract} from './DataContract'; import {OneToOne, relatedField} from './relationships'; import {field} from './field'; import {Types} from '../shared/Types'; -import {register} from '../shared/DataObject'; import * as moment from 'moment'; -export class NoProp extends DataContract {} -export class StringProp extends DataContract { +class BaseContract extends DataContract { + public static moduleName = 'test'; +} + +export class NoProp extends BaseContract {} +export class StringProp extends BaseContract { @field() public stringy: string; } -export class HiddenProp extends DataContract { +export class HiddenProp extends BaseContract { @field() public stringy: string; @field(Types.string, true) public hideMe: string; } -export class FloatProp extends DataContract { +export class FloatProp extends BaseContract { @field() public floaty: number; } -export class IntProp extends DataContract { +export class IntProp extends BaseContract { @field(Types.integer) public inty: number; } -export class BigIntProp extends DataContract { +export class BigIntProp extends BaseContract { @field(Types.bigInt) public inty: number; } -export class DateProp extends DataContract { +export class DateProp extends BaseContract { @field(Types.dateTimeTz) public dateThing: moment.Moment; } -export class BadProp extends DataContract { +export class BadProp extends BaseContract { @field( 'a') public dateThing: moment.Moment; } -@register('test') -export class OneToOneA extends DataContract { +export class OneToOneA extends BaseContract { @relatedField(() => OneToOneB) public b: OneToOne; } -@register('test') -export class OneToOneB extends DataContract { +export class OneToOneB extends BaseContract { @relatedField(() => OneToOneA) public a: OneToOne; } diff --git a/node/DataContract.spec.ts b/node/DataContract.spec.ts index 268dc2d..5b3b9ce 100644 --- a/node/DataContract.spec.ts +++ b/node/DataContract.spec.ts @@ -35,10 +35,10 @@ describe('node/DataContract', function() { classes = require('./DataContract.spec.class'); mockConnect.reset(connect); - var a = (new classes.OneToOneA()); - a.b.fetch(); - var b = (new classes.OneToOneB()); - b.a.fetch(); + // var a = (new classes.OneToOneA()); + // a.b.fetch(); + // var b = (new classes.OneToOneB()); + // b.a.fetch(); }); describe('existing', function() { diff --git a/node/DataContract.ts b/node/DataContract.ts index 29137ab..35d8314 100644 --- a/node/DataContract.ts +++ b/node/DataContract.ts @@ -8,7 +8,7 @@ import * as _ from 'lodash'; import { field } from './field'; import { Types } from '../shared/Types'; import { IDataContract } from '../shared/DataObject'; -import { logger } from './connect'; +import { logger, connection } from './connect'; export interface IDataContractConstruct { new ( @@ -19,8 +19,75 @@ export interface IDataContractConstruct { } export abstract class DataContract implements IDataContract { - // tslint:disable-next-line:no-unused-variable - private static contract = true; + public static moduleName: string; + public static name: string; + + public static getSequelizeModel(): sequelize.Model { + if (DataContract.models[this.moduleName] === undefined) { + DataContract.models[this.moduleName] = {}; + } + if (DataContract.models[this.moduleName][this.name] === undefined) { + const constructor: any = this; + const instance: DataContract = (new constructor(null, null)); + const fields = instance.fields; + const model: any = {}; + _.forEach(fields, (fieldName) => { + const type: Types = Reflect.getMetadata( + "ORM:type", + instance, + fieldName + ); + + switch (type) { + case Types.string: + model[fieldName] = { + type: sequelize.STRING + }; + break; + case Types.float: + model[fieldName] = { + type: sequelize.FLOAT + }; + break; + case Types.integer: + model[fieldName] = { + type: sequelize.INTEGER + }; + break; + case Types.bigInt: + model[fieldName] = { + type: sequelize.BIGINT + }; + break; + case Types.dateTimeTz: + model[fieldName] = { + type: sequelize.DATE + }; + break; + default: + throw new TypeError( + 'Field of unknown type found! ' + + 'Field Name:' + fieldName + ' ' + + 'Field Type: ' + type + ); + } + }); + DataContract.models[this.moduleName][this.name] = connection.define( + this.moduleName + '.' + this.name, + model, + { + freezeTableName: true // Model tableName will be the same as the model name + } + ); + } + return DataContract.models[this.moduleName][this.name]; + } + + private static models: { + [moduleName: string]: { + [contractName: string]: sequelize.Model; + } + } = {}; private get fields(): string[] { return Reflect.getMetadata('ORM:fields', this); diff --git a/shared/DataObject.ts b/shared/DataObject.ts index 0864b5c..c0728a1 100644 --- a/shared/DataObject.ts +++ b/shared/DataObject.ts @@ -35,3 +35,16 @@ export function register(moduleId: string, apiHidden: boolean = false) { } }; } + +export function contract(moduleId: string) { + return (target: new (...args: any[]) => IDataConnection | IDataContract): any => { + const idx = moduleId + '.' + ( target).name; + if (( target).contract === true) { + Reflect.defineMetadata('ORM:dbId', idx, target); + } else { + registeredClasses[idx] = target; + Reflect.defineMetadata('ORM:registeredIndex', idx, target); + Reflect.defineMetadata('ORM:apiHidden', apiHidden, target); + } + }; +} From 6673e8b3fb13b62439573efd4ebf960f78931330 Mon Sep 17 00:00:00 2001 From: Aaron Aichlmayr Date: Thu, 11 Aug 2016 17:23:05 -0500 Subject: [PATCH 03/14] More refactoring, one to one relationships are created in the tables and load properly (without tests) --- mocks/connect.ts | 20 +-- node/DataConnection.spec.class.ts | 12 ++ node/DataConnection.spec.ts | 19 +- node/DataConnection.ts | 23 ++- node/DataContract.spec.ts | 13 +- node/DataContract.ts | 229 ++++++++++++++++++------ node/relationships/OneToOne.spec.ts | 71 ++++++++ node/relationships/OneToOne.ts | 70 ++++++-- node/relationships/RelationshipCache.ts | 40 ----- node/relationships/relatedField.ts | 5 +- shared/DataObject.ts | 2 +- 11 files changed, 350 insertions(+), 154 deletions(-) create mode 100644 node/relationships/OneToOne.spec.ts delete mode 100644 node/relationships/RelationshipCache.ts diff --git a/mocks/connect.ts b/mocks/connect.ts index a6b3dbc..7691d66 100644 --- a/mocks/connect.ts +++ b/mocks/connect.ts @@ -1,22 +1,20 @@ import * as sinon from 'sinon'; +import * as sequelize from './Sequelize'; -export const model = { - create: sinon.stub(), - findAll: sinon.stub(), - findById: sinon.stub(), - sync: sinon.stub() -}; +const pristineModel = new sequelize.Model(''); + +export const model = new sequelize.Model(''); export function reset(connect: any) { - model.create = sinon.stub(); + for (const prop in pristineModel) { + if (pristineModel[prop].name === 'proxy') { + model[prop] = sinon.stub(); + } + } - model.findById = sinon.stub(); model.findById.returns(Promise.resolve(null)); - model.findAll = sinon.stub(); model.findAll.returns(Promise.resolve([])); - model.sync = sinon.stub(); - connect.connection.define.returns(model); } diff --git a/node/DataConnection.spec.class.ts b/node/DataConnection.spec.class.ts index 2a3ab2e..9b79572 100644 --- a/node/DataConnection.spec.class.ts +++ b/node/DataConnection.spec.class.ts @@ -59,3 +59,15 @@ export class BadProp extends DataConnection { return Contracts.BadProp; } } + +export class OneToOneA extends DataConnection { + protected getContract() { + return Contracts.OneToOneA; + } +} + +export class OneToOneB extends DataConnection { + protected getContract() { + return Contracts.OneToOneB; + } +} diff --git a/node/DataConnection.spec.ts b/node/DataConnection.spec.ts index 6dd819b..c25305f 100644 --- a/node/DataConnection.spec.ts +++ b/node/DataConnection.spec.ts @@ -29,6 +29,7 @@ describe('node/DataConnection', function() { './Types', './relationships', './relatedField', + './relationships/OneToOne', './OneToOne', './RelationshipCache', 'moment', @@ -90,7 +91,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "test.NoProp", + "testNoProp", {}, { "freezeTableName": true @@ -111,7 +112,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "test.StringProp", + "testStringProp", { "stringy": { type: sequelize.STRING @@ -136,7 +137,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "test.FloatProp", + "testFloatProp", { "floaty": { type: sequelize.FLOAT @@ -161,7 +162,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "test.IntProp", + "testIntProp", { "inty": { type: sequelize.INTEGER @@ -186,7 +187,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "test.BigIntProp", + "testBigIntProp", { "inty": { type: sequelize.BIGINT @@ -211,7 +212,7 @@ describe('node/DataConnection', function() { chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([ - "test.DateProp", + "testDateProp", { "dateThing": { type: sequelize.DATE @@ -227,10 +228,8 @@ describe('node/DataConnection', function() { describe('badProp', function () { it('throws an error', function () { - chai.expect(() => { - const a = new classes.BadProp(); - a.create(); - }).to.throw(TypeError); + const a = new classes.BadProp(); + return chai.expect(a.fetch(5)).to.eventually.be.rejectedWith(TypeError); }); }); }); diff --git a/node/DataConnection.ts b/node/DataConnection.ts index 9ad83d9..00c7baf 100644 --- a/node/DataConnection.ts +++ b/node/DataConnection.ts @@ -5,14 +5,14 @@ import * as sequelize from 'sequelize'; import * as _ from 'lodash'; import { IDataConnection } from '../shared/DataObject'; -import {DataContract} from './DataContract'; +import { DataContract, IDataContractConstruct } from './DataContract'; export abstract class DataConnection implements IDataConnection { private _dummyContract: T = null; private get dummyContract(): T { if (!this._dummyContract) { - this._dummyContract = new (this.getContract())(null, null); + this._dummyContract = new (this.getContract())(null); } return this._dummyContract; } @@ -25,7 +25,7 @@ export abstract class DataConnection implements IDataCon return this._fields; } - private get model(): sequelize.Model { + private get model(): Promise> { return this.getContract().getSequelizeModel(); } @@ -40,32 +40,32 @@ export abstract class DataConnection implements IDataCon } public fetch(id: number): Promise { - return this.model.findById(id) + return this.model.then((model) => model.findById(id)) .then((sqlData: any): Promise | T => { if ( sqlData === null ) { return Promise.reject('Not Found'); } else { - return new (this.getContract())(sqlData, this.model); + return new (this.getContract())(sqlData); } }); } public create(): T { - return new (this.getContract())(null, this.model); + return new (this.getContract())(null); } public search( criteria: sequelize.WhereOptions | Array ): Promise { return this.model - .findAll({ + .then((model) => model.findAll({ include: [{ all: true }], where: criteria - }) + })) .then((data: any[]) => { let ret: T[] = []; _.forEach(data, (value: any) => { - ret.push(new (this.getContract())(value, this.model)); + ret.push(new (this.getContract())(value)); }); return ret; }); @@ -74,8 +74,5 @@ export abstract class DataConnection implements IDataCon /** * This feeds the data contract into the system */ - protected abstract getContract(): { - new(instance: any, model: sequelize.Model): T; - getSequelizeModel(): sequelize.Model; - }; + protected abstract getContract(): IDataContractConstruct; } diff --git a/node/DataContract.spec.ts b/node/DataContract.spec.ts index 5b3b9ce..f8383bb 100644 --- a/node/DataContract.spec.ts +++ b/node/DataContract.spec.ts @@ -35,10 +35,6 @@ describe('node/DataContract', function() { classes = require('./DataContract.spec.class'); mockConnect.reset(connect); - // var a = (new classes.OneToOneA()); - // a.b.fetch(); - // var b = (new classes.OneToOneB()); - // b.a.fetch(); }); describe('existing', function() { @@ -172,11 +168,12 @@ describe('node/DataContract', function() { describe('save', function () { it('creates an object', function () { model.create.returns(Promise.resolve({})); - current.save(); - const calls = model.create.getCalls(); - chai.expect(calls.length).to.equal(1); - chai.expect(calls[0].args).to.deep.equal([{}]); + current.save().then(() => { + const calls = model.create.getCalls(); + chai.expect(calls.length).to.equal(1); + chai.expect(calls[0].args).to.deep.equal([{}]); + }) }); }); diff --git a/node/DataContract.ts b/node/DataContract.ts index 35d8314..e431b87 100644 --- a/node/DataContract.ts +++ b/node/DataContract.ts @@ -9,85 +9,194 @@ import { field } from './field'; import { Types } from '../shared/Types'; import { IDataContract } from '../shared/DataObject'; import { logger, connection } from './connect'; +import {OneToOne} from "./relationships/OneToOne"; export interface IDataContractConstruct { new ( - instance: any, - model: sequelize.Model + instance: any ): T; - name?: string; + getContractName(): string; + getSequelizeModel(relationships?: boolean): Promise>; + isFirst(dest: IDataContractConstruct): boolean; } +type DataContractType = typeof DataContract; + export abstract class DataContract implements IDataContract { public static moduleName: string; public static name: string; + public static relationshipsSetup: boolean = false; + public static relationshipsSetupList: any[] = []; + + public static getContractName(): string { + return this.moduleName + this.name; + } - public static getSequelizeModel(): sequelize.Model { + public static getSequelizeModel(): Promise> { if (DataContract.models[this.moduleName] === undefined) { DataContract.models[this.moduleName] = {}; } if (DataContract.models[this.moduleName][this.name] === undefined) { - const constructor: any = this; - const instance: DataContract = (new constructor(null, null)); - const fields = instance.fields; - const model: any = {}; + DataContract.models[this.moduleName][this.name] = this + .getBaseModel() + .then(this.setupRelationships.bind(this)) + .then((model: sequelize.Model) => { + if (DataContract.needsSync.indexOf(model) === -1) { + DataContract.needsSync.push(model); + } + return model; + }); + } + return DataContract.models[this.moduleName][this.name] + .then((contract) => DataContract.syncAll() + .then(() => contract) + ); + } + + public static isFirst(dest: IDataContractConstruct) { + return this.getContractName().localeCompare(dest.getContractName()) > 0; + } + + private static models: { + [moduleName: string]: { + [contractName: string]: Promise>; + } + } = {}; + + private static needsSync: sequelize.Model[] = []; + + private static getBaseModel(): Promise> { + return new Promise((resolve, reject) => { + try { + const constructor: any = this; + const instance: DataContract = (new constructor(null, null)); + const fields = instance.fields; + const model: any = {}; + _.forEach(fields, (fieldName) => { + const type: Types = Reflect.getMetadata( + "ORM:type", + instance, + fieldName + ); + + switch (type) { + case Types.string: + model[fieldName] = { + type: sequelize.STRING + }; + break; + case Types.float: + model[fieldName] = { + type: sequelize.FLOAT + }; + break; + case Types.integer: + model[fieldName] = { + type: sequelize.INTEGER + }; + break; + case Types.bigInt: + model[fieldName] = { + type: sequelize.BIGINT + }; + break; + case Types.dateTimeTz: + model[fieldName] = { + type: sequelize.DATE + }; + break; + case Types.relationshipOneToOne: + break; + default: + throw new TypeError( + 'Field of unknown type found! ' + + 'Field Name:' + fieldName + ' ' + + 'Field Type: ' + type + ); + } + }); + const contract = connection.define( + this.getContractName(), + model, + { + freezeTableName: true // Model tableName will be the same as the model name + } + ); + resolve(contract); + } catch (e) { + reject(e); + } + }); + } + + private static setupRelationships(thisModel): Promise> { + const constructor: any = this; + const instance: DataContract = (new constructor(null, null)); + const fields = instance.fields; + const relationships: Promise[] = []; + + this.relationshipsSetup = true; + + try { + _.forEach(fields, (fieldName) => { const type: Types = Reflect.getMetadata( "ORM:type", instance, fieldName ); + const relatedTypeFn:() => IDataContractConstruct = + Reflect.getMetadata( + "ORM:relatedType", + instance, + fieldName + ); + // This can get called before everything is setup properly so we need to skip those that haven't fully + // loaded yet + if (relatedTypeFn && this.relationshipsSetupList.indexOf(relatedTypeFn) === -1) { + this.relationshipsSetupList.push(relatedTypeFn); - switch (type) { - case Types.string: - model[fieldName] = { - type: sequelize.STRING - }; - break; - case Types.float: - model[fieldName] = { - type: sequelize.FLOAT - }; - break; - case Types.integer: - model[fieldName] = { - type: sequelize.INTEGER - }; - break; - case Types.bigInt: - model[fieldName] = { - type: sequelize.BIGINT - }; - break; - case Types.dateTimeTz: - model[fieldName] = { - type: sequelize.DATE - }; - break; - default: - throw new TypeError( - 'Field of unknown type found! ' + - 'Field Name:' + fieldName + ' ' + - 'Field Type: ' + type - ); + const relatedType: IDataContractConstruct = relatedTypeFn(); + + relationships.push(( relatedType).getBaseModel().then((relatedModel) => { + switch (type) { + case Types.relationshipOneToOne: + OneToOne.addRelationship( + this, + thisModel, + relatedType, + relatedModel + ); + break; + default: + break; + } + + if (DataContract.needsSync.indexOf(relatedModel) === -1) { + DataContract.needsSync.push(relatedModel); + } + })); + } else { + this.relationshipsSetup = false; } }); - DataContract.models[this.moduleName][this.name] = connection.define( - this.moduleName + '.' + this.name, - model, - { - freezeTableName: true // Model tableName will be the same as the model name - } - ); + + return Promise.all(relationships).then(() => thisModel); + } catch (e) { + return Promise.reject(e); } - return DataContract.models[this.moduleName][this.name]; } - private static models: { - [moduleName: string]: { - [contractName: string]: sequelize.Model; + private static syncAll(): Promise { + const syncList = DataContract.needsSync; + DataContract.needsSync = []; + const syncs: Promise[] = [] + // tslint:disable-next-line:forin + for (const i in syncList) { + syncs.push(syncList[i].sync()); } - } = {}; + return Promise.all(syncs).then(() => { /* */ }); + } private get fields(): string[] { return Reflect.getMetadata('ORM:fields', this); @@ -101,8 +210,7 @@ export abstract class DataContract implements IDataContract { public updatedAt: moment.Moment; constructor( - private instance: any, - private model: sequelize.Model + private instance: any ) {} public loadData(data: any): void { @@ -143,10 +251,15 @@ export abstract class DataContract implements IDataContract { if (this.instance) { return this.instance.save().then(() => this); } else { - return this.model.create(this.getFields()).then((sqlData: any) => { - this.instance = sqlData; - return this; - }); + return ( this.constructor) + .getSequelizeModel() + .then((model) => { + return model.create(this.getFields()); + }) + .then((sqlData: any) => { + this.instance = sqlData; + return this; + }); } } diff --git a/node/relationships/OneToOne.spec.ts b/node/relationships/OneToOne.spec.ts new file mode 100644 index 0000000..7710d2c --- /dev/null +++ b/node/relationships/OneToOne.spec.ts @@ -0,0 +1,71 @@ +import * as mockery from 'mockery'; +import * as chai from 'chai'; +import * as classTypes from '../DataContract.spec.class'; +import * as moment from 'moment'; +import * as sinon from 'sinon'; +import * as mockConnect from '../../mocks/connect'; + +import {Sequelize, Model} from '../../mocks/Sequelize'; + +describe('node/DataContract', function() { + let connect: any; + let classes: any; + + before(function(){ + mockery.enable(); + mockery.registerMock('sequelize', Sequelize); + mockery.registerAllowables([ + '../connect', + './DataContract', + '../DataContract.spec.class', + './field', + '../shared/field', + '../shared/Types', + './Types', + './relationships', + './OneToOne', + 'moment', + 'lodash', + 'debug' + ]); + + connect = require('../connect'); + connect.connect('a', 'b', 'c'); + + classes = require('../DataContract.spec.class'); + classes = require('../DataContract.spec.class'); + }); + + beforeEach(function () { + mockConnect.reset(connect); + }); + + it('Creates the Relationships', function () { + return Promise.all([ + classes.OneToOneA.getSequelizeModel(), + classes.OneToOneB.getSequelizeModel() + ]).then((models) => { + const modelA = models[0]; + const modelB = models[1]; + const hasCalls = mockConnect.model.hasOne.getCalls(); + const belongsCalls = mockConnect.model.belongsTo.getCalls(); + + chai.expect(hasCalls.length).to.equal(2); + chai.expect(hasCalls[0].args[0]).to.equal(modelB); + chai.expect(hasCalls[1].args[0]).to.equal(modelB); + chai.expect(belongsCalls.length).to.equal(2); + chai.expect(belongsCalls[0].args[0]).to.equal(modelA); + chai.expect(belongsCalls[1].args[0]).to.equal(modelA); + }); + }); + + it('Fetches data from the A side', function () { + const a: classTypes.OneToOneA = new classes.OneToOneA(mockConnect.model); + a.b.fetch(); + }); + + after(function() { + mockery.deregisterAll(); + mockery.disable(); + }); +}); diff --git a/node/relationships/OneToOne.ts b/node/relationships/OneToOne.ts index a97421a..c96c859 100644 --- a/node/relationships/OneToOne.ts +++ b/node/relationships/OneToOne.ts @@ -1,24 +1,72 @@ +import * as sequelize from 'sequelize'; + import { DataContract, IDataContractConstruct } from '../DataContract'; -import { RelationshipCache } from './RelationshipCache'; export class OneToOne { - public static fetch(from: DataContract, target: IDataContractConstruct): Promise { - const model = RelationshipCache.get( from.constructor, target); - const dbId = Reflect.getMetadata('ORM:dbId', from); - const where: any = {}; - where[dbId] = from.id; + public static fetch( + from: DataContract, + target: IDataContractConstruct + ): Promise { + return Promise.all([ + target.getSequelizeModel(), + ( from.constructor).getSequelizeModel() + ]).then((models: sequelize.Model[]) => { + const targetModel: sequelize.Model = models[0]; + const fromModel: sequelize.Model = models[1]; + if ((> from.constructor).isFirst(target)) { + const idName: string = ( targetModel).name + 'Id'; + const id: number = ( from).instance.get(idName); - return model.findOne({ - where: where - }).then((data) => { - console.log(data); + if (id) { + return targetModel.findById(id).then((data) => { + return new target(data); + }); + } + return null; + } else { + const idName: string = ( fromModel).name + 'Id'; + const condition = {where: {}}; + condition.where[idName] = from.id; + return targetModel.findOne( condition).then((data) => { + if (!data) { + return null; + } + return new target(data); + }); + } }); } - public constructor(private parent: DataContract, private target: () => IDataContractConstruct) {} + public static addRelationship( + src: IDataContractConstruct, + srcModel: sequelize.Model, + dest: IDataContractConstruct, + destModel: sequelize.Model + ): void { + if (src.isFirst(dest)) { + srcModel.belongsTo(destModel); + destModel.hasOne(srcModel); + } else { + destModel.belongsTo(destModel); + srcModel.hasOne(destModel); + } + } + + private currentValue: T = null; + private belongsTo: boolean = false; + + public constructor( + private parent: DataContract, + private target: () => IDataContractConstruct + ) { + this.belongsTo = ( parent.constructor).getContractName().localeCompare(target().getContractName()) > 0; + } public fetch(): Promise { + if (this.currentValue) { + return Promise.resolve(this.currentValue); + } return OneToOne.fetch(this.parent, this.target()); } diff --git a/node/relationships/RelationshipCache.ts b/node/relationships/RelationshipCache.ts deleted file mode 100644 index 716c29b..0000000 --- a/node/relationships/RelationshipCache.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as sequelize from 'sequelize'; - -import {DataContract, IDataContractConstruct} from '../DataContract'; -import {connection} from '../connect'; - -export class RelationshipCache { - private static cache: sequelize.Model[] = []; - - public static get< - T extends DataContract, - U extends DataContract - >( - obj1: IDataContractConstruct, - obj2: IDataContractConstruct - ): sequelize.Model { - const names = []; - - names[0] = Reflect.getMetadata('ORM:dbId', obj1); - names[1] = Reflect.getMetadata('ORM:dbId', obj2); - - names.sort(); - - const modelName = names[0] + '-' + names[1]; - - if (!RelationshipCache.cache[modelName]) { - const model = {}; - model[names[0]] = { - type: sequelize.INTEGER - }; - model[names[1]] = { - type: sequelize.INTEGER - }; - - RelationshipCache.cache[modelName] = connection.define(names[0] + '-' + names[1], model); - RelationshipCache.cache[modelName].sync(); - } - - return RelationshipCache.cache[modelName]; - } -} diff --git a/node/relationships/relatedField.ts b/node/relationships/relatedField.ts index 3bcdc95..82b91c6 100644 --- a/node/relationships/relatedField.ts +++ b/node/relationships/relatedField.ts @@ -1,7 +1,7 @@ // DO NOT REMOVE THIS IMPORT it is required for this file to function // tslint:disable-next-line:no-unused-variable import * as reflectMetadata from 'reflect-metadata'; -import * as moment from 'moment'; +import * as sequelize from 'sequelize'; import {field as sharedField} from '../../shared/field'; import {Types} from '../../shared/Types'; @@ -45,10 +45,11 @@ export function relatedField( ); Reflect.defineMetadata('ORM:hidden', hidden, target, key); + Reflect.defineMetadata('ORM:relatedType', RelatedType, target, key); return { getter: getter, setter: setter }; }; -} +} \ No newline at end of file diff --git a/shared/DataObject.ts b/shared/DataObject.ts index c0728a1..a9b42c7 100644 --- a/shared/DataObject.ts +++ b/shared/DataObject.ts @@ -36,7 +36,7 @@ export function register(moduleId: string, apiHidden: boolean = false) { }; } -export function contract(moduleId: string) { +export function contract(moduleId: string, apiHidden: boolean = false) { return (target: new (...args: any[]) => IDataConnection | IDataContract): any => { const idx = moduleId + '.' + ( target).name; if (( target).contract === true) { From c4a5a5e57335dbecec25dc4b116631b384348798 Mon Sep 17 00:00:00 2001 From: Aaron Aichlmayr Date: Thu, 11 Aug 2016 17:32:29 -0500 Subject: [PATCH 04/14] Fixing compile issue --- node/DataContract.spec.class.ts | 2 +- node/DataContract.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/node/DataContract.spec.class.ts b/node/DataContract.spec.class.ts index 0df9714..be7d2a5 100644 --- a/node/DataContract.spec.class.ts +++ b/node/DataContract.spec.class.ts @@ -5,7 +5,7 @@ import {Types} from '../shared/Types'; import * as moment from 'moment'; -class BaseContract extends DataContract { +export class BaseContract extends DataContract { public static moduleName = 'test'; } diff --git a/node/DataContract.spec.ts b/node/DataContract.spec.ts index f8383bb..ca6789a 100644 --- a/node/DataContract.spec.ts +++ b/node/DataContract.spec.ts @@ -173,7 +173,7 @@ describe('node/DataContract', function() { const calls = model.create.getCalls(); chai.expect(calls.length).to.equal(1); chai.expect(calls[0].args).to.deep.equal([{}]); - }) + }); }); }); From e77a4e82f4a877766dfd9ccc5dd2f93800e7b12f Mon Sep 17 00:00:00 2001 From: Aaron Aichlmayr Date: Thu, 11 Aug 2016 17:38:24 -0500 Subject: [PATCH 05/14] lint fixes --- angular2/DataContract.ts | 2 +- node/DataContract.ts | 8 ++++---- node/index.ts | 2 +- node/relationships/OneToOne.spec.ts | 4 +--- node/relationships/index.ts | 2 +- node/relationships/relatedField.ts | 3 +-- 6 files changed, 9 insertions(+), 12 deletions(-) diff --git a/angular2/DataContract.ts b/angular2/DataContract.ts index 4456e70..019be52 100644 --- a/angular2/DataContract.ts +++ b/angular2/DataContract.ts @@ -14,7 +14,7 @@ import { Observable } from 'rxjs/Observable'; export abstract class DataContract implements IDataContract { // tslint:disable-next-line:no-unused-variable private static contract = true; - + @field() public id: number; @field(Types.dateTimeTz) diff --git a/node/DataContract.ts b/node/DataContract.ts index e431b87..66608d3 100644 --- a/node/DataContract.ts +++ b/node/DataContract.ts @@ -141,13 +141,13 @@ export abstract class DataContract implements IDataContract { _.forEach(fields, (fieldName) => { const type: Types = Reflect.getMetadata( - "ORM:type", + 'ORM:type', instance, fieldName ); - const relatedTypeFn:() => IDataContractConstruct = + const relatedTypeFn: () => IDataContractConstruct = Reflect.getMetadata( - "ORM:relatedType", + 'ORM:relatedType', instance, fieldName ); @@ -190,7 +190,7 @@ export abstract class DataContract implements IDataContract { private static syncAll(): Promise { const syncList = DataContract.needsSync; DataContract.needsSync = []; - const syncs: Promise[] = [] + const syncs: Promise[] = []; // tslint:disable-next-line:forin for (const i in syncList) { syncs.push(syncList[i].sync()); diff --git a/node/index.ts b/node/index.ts index bd17a77..86b0b4d 100644 --- a/node/index.ts +++ b/node/index.ts @@ -4,4 +4,4 @@ export {DataContract} from './DataContract'; export {DataConnection} from './DataConnection'; export {register} from '../shared/DataObject'; export {HTTP} from './http'; -export {ILogger} from './ILogger'; \ No newline at end of file +export {ILogger} from './ILogger'; diff --git a/node/relationships/OneToOne.spec.ts b/node/relationships/OneToOne.spec.ts index 7710d2c..2b12dad 100644 --- a/node/relationships/OneToOne.spec.ts +++ b/node/relationships/OneToOne.spec.ts @@ -1,11 +1,9 @@ import * as mockery from 'mockery'; import * as chai from 'chai'; import * as classTypes from '../DataContract.spec.class'; -import * as moment from 'moment'; -import * as sinon from 'sinon'; import * as mockConnect from '../../mocks/connect'; -import {Sequelize, Model} from '../../mocks/Sequelize'; +import {Sequelize} from '../../mocks/Sequelize'; describe('node/DataContract', function() { let connect: any; diff --git a/node/relationships/index.ts b/node/relationships/index.ts index 38963be..f252825 100644 --- a/node/relationships/index.ts +++ b/node/relationships/index.ts @@ -1,2 +1,2 @@ export { relatedField } from './relatedField'; -export { OneToOne } from './OneToOne'; \ No newline at end of file +export { OneToOne } from './OneToOne'; diff --git a/node/relationships/relatedField.ts b/node/relationships/relatedField.ts index 82b91c6..85e2bdf 100644 --- a/node/relationships/relatedField.ts +++ b/node/relationships/relatedField.ts @@ -1,7 +1,6 @@ // DO NOT REMOVE THIS IMPORT it is required for this file to function // tslint:disable-next-line:no-unused-variable import * as reflectMetadata from 'reflect-metadata'; -import * as sequelize from 'sequelize'; import {field as sharedField} from '../../shared/field'; import {Types} from '../../shared/Types'; @@ -52,4 +51,4 @@ export function relatedField( setter: setter }; }; -} \ No newline at end of file +} From ebba643b17ac51ce0e7e1c48c9c6c0dbb4a3f5fa Mon Sep 17 00:00:00 2001 From: Aaron Aichlmayr Date: Thu, 11 Aug 2016 17:40:19 -0500 Subject: [PATCH 06/14] Removing some extra code --- angular2/DataContract.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/angular2/DataContract.ts b/angular2/DataContract.ts index 019be52..b73c488 100644 --- a/angular2/DataContract.ts +++ b/angular2/DataContract.ts @@ -12,9 +12,6 @@ import 'rxjs/add/operator/toPromise'; import { Observable } from 'rxjs/Observable'; export abstract class DataContract implements IDataContract { - // tslint:disable-next-line:no-unused-variable - private static contract = true; - @field() public id: number; @field(Types.dateTimeTz) From 25fceca58c37f054196ed5f5cadcecc59b11e819 Mon Sep 17 00:00:00 2001 From: Aaron Aichlmayr Date: Thu, 11 Aug 2016 17:42:27 -0500 Subject: [PATCH 07/14] Removing some extra code --- node/DataConnection.ts | 16 ---------------- shared/DataObject.ts | 10 +++------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/node/DataConnection.ts b/node/DataConnection.ts index 00c7baf..fa7e859 100644 --- a/node/DataConnection.ts +++ b/node/DataConnection.ts @@ -9,22 +9,6 @@ import { DataContract, IDataContractConstruct } from './DataContract'; export abstract class DataConnection implements IDataConnection { - private _dummyContract: T = null; - private get dummyContract(): T { - if (!this._dummyContract) { - this._dummyContract = new (this.getContract())(null); - } - return this._dummyContract; - } - - private _fields: string[] = []; - private get fields(): string[] { - if (!this._fields.length) { - this._fields = Reflect.getMetadata('ORM:fields', this.dummyContract); - } - return this._fields; - } - private get model(): Promise> { return this.getContract().getSequelizeModel(); } diff --git a/shared/DataObject.ts b/shared/DataObject.ts index a9b42c7..0e6c486 100644 --- a/shared/DataObject.ts +++ b/shared/DataObject.ts @@ -26,13 +26,9 @@ export const registeredClasses: registeredClassMap = export function register(moduleId: string, apiHidden: boolean = false) { return (target: new (...args: any[]) => IDataConnection | IDataContract): any => { const idx = moduleId + '.' + ( target).name; - if (( target).contract === true) { - Reflect.defineMetadata('ORM:dbId', idx, target); - } else { - registeredClasses[idx] = target; - Reflect.defineMetadata('ORM:registeredIndex', idx, target); - Reflect.defineMetadata('ORM:apiHidden', apiHidden, target); - } + registeredClasses[idx] = target; + Reflect.defineMetadata('ORM:registeredIndex', idx, target); + Reflect.defineMetadata('ORM:apiHidden', apiHidden, target); }; } From 3865dbae9eee6df1937b4ac7229bcf8fbaf9a5f7 Mon Sep 17 00:00:00 2001 From: Aaron Aichlmayr Date: Thu, 11 Aug 2016 17:49:42 -0500 Subject: [PATCH 08/14] Removing coverage from travis, coveralls can have this set more effectively --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0176ddc..11cbf97 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "coverage": "istanbul check-coverage", "coveralls": "cat coverage/lcov.info | ./node_modules/.bin/coveralls", "prepublish": "typings install && tsc", - "test": "npm run lint && npm run mocha && npm run coveralls && npm run coverage" + "test": "npm run lint && npm run mocha && npm run coveralls" }, "repository": { "type": "git", From eba52b4065715b3eb2d71ad49699fae7b0b9f955 Mon Sep 17 00:00:00 2001 From: Aaron Aichlmayr Date: Fri, 12 Aug 2016 07:46:52 -0500 Subject: [PATCH 09/14] Added setting the relationships --- .idea/codeStyleSettings.xml | 9 +++ node/relationships/OneToOne.ts | 134 ++++++++++++++++++++++----------- 2 files changed, 99 insertions(+), 44 deletions(-) diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml index d3bbb2f..3860dc4 100644 --- a/.idea/codeStyleSettings.xml +++ b/.idea/codeStyleSettings.xml @@ -3,6 +3,12 @@