Skip to content

Commit

Permalink
Relation type definitions and .load() for Eloquent
Browse files Browse the repository at this point in the history
  • Loading branch information
nhat-phan committed May 26, 2018
1 parent 6588767 commit 15eb6d8
Show file tree
Hide file tree
Showing 16 changed files with 113 additions and 62 deletions.
1 change: 0 additions & 1 deletion dist/lib/model/components/ModelRelation.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@ export declare class ModelRelation implements Najs.Contracts.Eloquent.Component
static getRelationByName: NajsEloquent.Model.ModelMethod<any>;
static callMappedRelationByName(model: NajsEloquent.Model.IModel<any>, name: string): any;
static defineRelationProperty: NajsEloquent.Model.ModelMethod<any>;
static warningNotAvailableUntilVersion4(): void;
}
17 changes: 5 additions & 12 deletions dist/lib/model/components/ModelRelation.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const Relation_1 = require("./../../relations/Relation");
const RelationFactory_1 = require("../../relations/RelationFactory");
const Eloquent_1 = require("../Eloquent");
const functions_1 = require("../../util/functions");
// // import { flatten } from 'lodash'
const lodash_1 = require("lodash");
function get_value_and_type_of_property(descriptor, instance) {
// perform getter or function for sample, the sample will contains "relationName"
const sample = instance['getClassSetting']().getSample();
Expand Down Expand Up @@ -103,32 +103,25 @@ class ModelRelation {
}
return model[mapping.mapTo].call(model);
}
static warningNotAvailableUntilVersion4() {
// console.warn('Relation feature is not available until v0.4.0')
}
}
ModelRelation.className = constants_1.NajsEloquent.Model.Component.ModelRelation;
ModelRelation.getRelationDataBucket = function () {
return this['relationDataBucket'];
};
ModelRelation.load = async function () {
ModelRelation.warningNotAvailableUntilVersion4();
// const relations: string[] = flatten(arguments)
// for (const relationName of relations) {
// this.getRelationByName(relationName).lazyLoad(this)
// }
// return this
const relations = lodash_1.flatten(arguments);
for (const relationName of relations) {
await this.getRelationByName(relationName).load();
}
};
ModelRelation.getRelationByName = function (name) {
ModelRelation.warningNotAvailableUntilVersion4();
// const relationNames = name.split('.')
// for (const relationName of relationNames) {
// return this[relationName]
// }
return ModelRelation.callMappedRelationByName(this, name);
};
ModelRelation.defineRelationProperty = function (name) {
ModelRelation.warningNotAvailableUntilVersion4();
if (this['__sample']) {
this['relationName'] = name;
return new RelationFactory_1.RelationFactory(this, name, true);
Expand Down
6 changes: 6 additions & 0 deletions dist/lib/relations/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// <reference path="interfaces/IHasOne.d.ts" />
/// <reference path="../model/interfaces/IModel.d.ts" />
export declare type HasOne<T> = (NajsEloquent.Model.IModel<T> & T) | undefined | null;
export declare type BelongsTo<T> = (NajsEloquent.Model.IModel<T> & T) | undefined | null;
export declare type HasOneRelation<T> = NajsEloquent.Relation.IHasOne<T>;
export declare type BelongsToRelation<T> = NajsEloquent.Relation.IHasOne<T>;
4 changes: 4 additions & 0 deletions dist/lib/relations/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
/// <reference path="./interfaces/IHasOne.ts" />
/// <reference path="../model/interfaces/IModel.ts" />
Object.defineProperty(exports, "__esModule", { value: true });
2 changes: 0 additions & 2 deletions dist/lib/relations/types/BelongsTo.d.ts

This file was deleted.

3 changes: 0 additions & 3 deletions dist/lib/relations/types/BelongsTo.js

This file was deleted.

2 changes: 0 additions & 2 deletions dist/lib/relations/types/HasOne.d.ts

This file was deleted.

3 changes: 0 additions & 3 deletions dist/lib/relations/types/HasOne.js

This file was deleted.

27 changes: 25 additions & 2 deletions dist/test/model/components/ModelRelation.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
require("jest");
const Sinon = require("sinon");
const ClassSetting_1 = require("../../../lib/util/ClassSetting");
const Eloquent_1 = require("../../../lib/model/Eloquent");
const ModelRelation_1 = require("../../../lib/model/components/ModelRelation");
Expand Down Expand Up @@ -43,9 +44,31 @@ describe('ModelRelation', function () {
Test.className = 'Test';
najs_binding_1.register(Test);
describe('.load()', function () {
it('does nothing for now', function () {
it('flattens arguments, then loops all relations and calls .getRelationByName().load()', async function () {
const user = new User();
user.load();
const relation = {
load() { }
};
const loadSpy = Sinon.spy(relation, 'load');
const getRelationByNameStub = Sinon.stub(user, 'getRelationByName');
getRelationByNameStub.returns(relation);
await user.load('test');
expect(getRelationByNameStub.calledWith('test')).toBe(true);
expect(loadSpy.called).toBe(true);
getRelationByNameStub.resetHistory();
loadSpy.resetHistory();
await user.load('a', 'b', 'c');
expect(getRelationByNameStub.firstCall.calledWith('a')).toBe(true);
expect(getRelationByNameStub.secondCall.calledWith('b')).toBe(true);
expect(getRelationByNameStub.thirdCall.calledWith('c')).toBe(true);
expect(loadSpy.callCount).toBe(3);
getRelationByNameStub.resetHistory();
loadSpy.resetHistory();
await user.load('a', ['b', 'c']);
expect(getRelationByNameStub.firstCall.calledWith('a')).toBe(true);
expect(getRelationByNameStub.secondCall.calledWith('b')).toBe(true);
expect(getRelationByNameStub.thirdCall.calledWith('c')).toBe(true);
expect(loadSpy.callCount).toBe(3);
});
});
describe('.getRelationDataBucket()', function () {
Expand Down
5 changes: 2 additions & 3 deletions dist/test/relations/HasOneOrMany.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,8 @@ describe('HasOneOrMany - Integration - MongooseDriver', function () {
// console.log(first.getRelationDataBucket() === last.getRelationDataBucket())
// console.log('result', result)
// console.log('data bucket', userModel.getRelationDataBucket())
const first = result.first();
await first.getPhoneRelation().eagerLoad();
console.log(first.phone['toJson']());
await result.first().load('phone');
console.log(result.first().phone.toJson());
const last = result.last();
console.log(last.phone);
const newUser = await FactoryFacade_1.Factory.create(User);
Expand Down
18 changes: 5 additions & 13 deletions lib/model/components/ModelRelation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Relation } from './../../relations/Relation'
import { RelationFactory } from '../../relations/RelationFactory'
import { Eloquent } from '../Eloquent'
import { find_base_prototypes } from '../../util/functions'
// // import { flatten } from 'lodash'
import { flatten } from 'lodash'

function get_value_and_type_of_property(descriptor: PropertyDescriptor, instance: Object) {
// perform getter or function for sample, the sample will contains "relationName"
Expand Down Expand Up @@ -110,16 +110,13 @@ export class ModelRelation implements Najs.Contracts.Eloquent.Component {
}

static load: NajsEloquent.Model.ModelMethod<any> = async function() {
ModelRelation.warningNotAvailableUntilVersion4()
// const relations: string[] = flatten(arguments)
// for (const relationName of relations) {
// this.getRelationByName(relationName).lazyLoad(this)
// }
// return this
const relations: string[] = flatten(arguments)
for (const relationName of relations) {
await this.getRelationByName(relationName).load()
}
}

static getRelationByName: NajsEloquent.Model.ModelMethod<any> = function(name: string) {
ModelRelation.warningNotAvailableUntilVersion4()
// const relationNames = name.split('.')
// for (const relationName of relationNames) {
// return this[relationName]
Expand All @@ -139,7 +136,6 @@ export class ModelRelation implements Najs.Contracts.Eloquent.Component {
}

static defineRelationProperty: NajsEloquent.Model.ModelMethod<any> = function(name: string) {
ModelRelation.warningNotAvailableUntilVersion4()
if (this['__sample']) {
this['relationName'] = name
return new RelationFactory(this, name, true)
Expand All @@ -153,9 +149,5 @@ export class ModelRelation implements Najs.Contracts.Eloquent.Component {
}
return this['relations'][name].factory
}

static warningNotAvailableUntilVersion4() {
// console.warn('Relation feature is not available until v0.4.0')
}
}
register(ModelRelation)
8 changes: 8 additions & 0 deletions lib/relations/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/// <reference path="./interfaces/IHasOne.ts" />
/// <reference path="../model/interfaces/IModel.ts" />

export type HasOne<T> = (NajsEloquent.Model.IModel<T> & T) | undefined | null
export type BelongsTo<T> = (NajsEloquent.Model.IModel<T> & T) | undefined | null

export type HasOneRelation<T> = NajsEloquent.Relation.IHasOne<T>
export type BelongsToRelation<T> = NajsEloquent.Relation.IHasOne<T>
3 changes: 0 additions & 3 deletions lib/relations/types/BelongsTo.ts

This file was deleted.

3 changes: 0 additions & 3 deletions lib/relations/types/HasOne.ts

This file was deleted.

32 changes: 30 additions & 2 deletions test/model/components/ModelRelation.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'jest'
import * as Sinon from 'sinon'
import { ClassSetting } from '../../../lib/util/ClassSetting'
import { Eloquent } from '../../../lib/model/Eloquent'
import { ModelRelation } from '../../../lib/model/components/ModelRelation'
Expand Down Expand Up @@ -47,9 +48,36 @@ describe('ModelRelation', function() {
register(Test)

describe('.load()', function() {
it('does nothing for now', function() {
it('flattens arguments, then loops all relations and calls .getRelationByName().load()', async function() {
const user = new User()
user.load()
const relation = {
load() {}
}
const loadSpy = Sinon.spy(relation, 'load')
const getRelationByNameStub = Sinon.stub(user, 'getRelationByName')
getRelationByNameStub.returns(relation)

await user.load('test')
expect(getRelationByNameStub.calledWith('test')).toBe(true)
expect(loadSpy.called).toBe(true)

getRelationByNameStub.resetHistory()
loadSpy.resetHistory()

await user.load('a', 'b', 'c')
expect(getRelationByNameStub.firstCall.calledWith('a')).toBe(true)
expect(getRelationByNameStub.secondCall.calledWith('b')).toBe(true)
expect(getRelationByNameStub.thirdCall.calledWith('c')).toBe(true)
expect(loadSpy.callCount).toBe(3)

getRelationByNameStub.resetHistory()
loadSpy.resetHistory()

await user.load('a', ['b', 'c'])
expect(getRelationByNameStub.firstCall.calledWith('a')).toBe(true)
expect(getRelationByNameStub.secondCall.calledWith('b')).toBe(true)
expect(getRelationByNameStub.thirdCall.calledWith('c')).toBe(true)
expect(loadSpy.callCount).toBe(3)
})
})

Expand Down
41 changes: 28 additions & 13 deletions test/relations/HasOneOrMany.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { MongooseProvider } from '../../lib/facades/global/MongooseProviderFacad
import { EloquentDriverProviderFacade } from '../../lib/facades/global/EloquentDriverProviderFacade'
import { init_mongoose, delete_collection } from '../util'
import { Eloquent } from '../../lib/model/Eloquent'
import { HasOne } from '../../lib/relations/types/HasOne'
import { HasOne, BelongsTo, HasOneRelation, BelongsToRelation } from '../../lib/relations/types'
import { Factory, factory } from './../../lib/facades/global/FactoryFacade'

EloquentDriverProviderFacade.register(MongooseDriver, 'mongoose', true)
Expand Down Expand Up @@ -95,34 +95,50 @@ describe('HasOneOrMany - Integration - MongooseDriver', function() {
await delete_collection(MongooseProvider.getMongooseInstance(), 'posts')
})

class Phone extends Eloquent {
interface IPhone {
number: string
user_id: string
}

interface IPhoneRelations {
user: BelongsTo<IUser>

getUserRelation(): BelongsToRelation<IUser>
}

interface Phone extends IPhone, IPhoneRelations {}
class Phone extends Eloquent<IPhone & IPhoneRelations> {
static className: string = 'Phone'
static schema = {
user_id: { type: String, required: true },
number: { type: String, required: true }
}
static fillable = ['number']

user?: HasOne<Phone>
user_id: string
number: string

getUserRelation() {
return this.defineRelationProperty('user').belongsTo('User')
}
}
Eloquent.register(Phone)

class User extends Eloquent {
interface IUser {
name: string
}

interface IUserRelations {
phone: HasOne<IPhone>

getPhoneRelation(): HasOneRelation<IPhone>
}

interface User extends IUser, IUserRelations {}
class User extends Eloquent<IUser & IUserRelations> {
static className: string = 'User'
static schema = {
name: { type: String, required: true }
}
static fillable = ['name']

phone?: HasOne<Phone>
name: string

getPhoneRelation() {
return this.defineRelationProperty('phone').hasOne('Phone')
}
Expand Down Expand Up @@ -195,9 +211,8 @@ describe('HasOneOrMany - Integration - MongooseDriver', function() {
// console.log('result', result)
// console.log('data bucket', userModel.getRelationDataBucket())

const first: User = <any>result.first()
await first.getPhoneRelation().eagerLoad()
console.log(first.phone!['toJson']())
await result.first().load('phone')
console.log(result.first().phone!.toJson())

const last: User = <any>result.last()
console.log(last.phone)
Expand Down

0 comments on commit 15eb6d8

Please sign in to comment.