@adonisjs/lucid
Version:
SQL ORM built on top of Active Record pattern
251 lines (250 loc) • 8.18 kB
JavaScript
"use strict";
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.FactoryModel = void 0;
const hooks_1 = require("@poppinss/hooks");
const HasOne_1 = require("./Relations/HasOne");
const HasMany_1 = require("./Relations/HasMany");
const FactoryBuilder_1 = require("./FactoryBuilder");
const BelongsTo_1 = require("./Relations/BelongsTo");
const ManyToMany_1 = require("./Relations/ManyToMany");
/**
* Factory model exposes the API to define a model factory with custom
* states and relationships
*/
class FactoryModel {
constructor(model, define, manager) {
Object.defineProperty(this, "model", {
enumerable: true,
configurable: true,
writable: true,
value: model
});
Object.defineProperty(this, "define", {
enumerable: true,
configurable: true,
writable: true,
value: define
});
Object.defineProperty(this, "manager", {
enumerable: true,
configurable: true,
writable: true,
value: manager
});
/**
* Method to instantiate a new model instance. This method can be
* overridden using the `newUp` public method.
*/
Object.defineProperty(this, "newUpModelInstance", {
enumerable: true,
configurable: true,
writable: true,
value: function (attributes) {
const ModelConstructor = this.model;
/**
* Handling case, where someone returns model instance directly
*/
if (attributes instanceof ModelConstructor) {
return attributes;
}
const modelInstance = new ModelConstructor();
modelInstance.merge(attributes);
return modelInstance;
}.bind(this)
});
/**
* Method to merge runtime attributes with the model instance. This method
* can be overridden using the `merge` method.
*/
Object.defineProperty(this, "mergeAttributes", {
enumerable: true,
configurable: true,
writable: true,
value: function (model, attributes) {
model.merge(attributes);
}.bind(this)
});
/**
* A collection of factory states
*/
Object.defineProperty(this, "states", {
enumerable: true,
configurable: true,
writable: true,
value: {}
});
/**
* A collection of factory relations
*/
Object.defineProperty(this, "relations", {
enumerable: true,
configurable: true,
writable: true,
value: {}
});
/**
* A set of registered hooks
*/
Object.defineProperty(this, "hooks", {
enumerable: true,
configurable: true,
writable: true,
value: new hooks_1.Hooks()
});
}
/**
* Register a before event hook
*/
before(event, handler) {
this.hooks.add('before', event, handler);
return this;
}
/**
* Register an after event hook
*/
after(event, handler) {
this.hooks.add('after', event, handler);
return this;
}
/**
* Returns state callback defined on the model factory. Raises an
* exception, when state is not registered
*/
getState(state) {
const stateCallback = this.states[state];
if (!stateCallback) {
throw new Error(`Cannot apply undefined state "${state}". Double check the model factory`);
}
return stateCallback;
}
/**
* Returns the pre-registered relationship factory function, along with
* the original model relation.
*/
getRelation(relation) {
const relationship = this.relations[relation];
if (!relationship) {
throw new Error(`Cannot setup undefined relationship "${relation}". Double check the model factory`);
}
return relationship;
}
/**
* Define custom state for the factory. When executing the factory,
* you can apply the pre-defined states
*/
state(state, callback) {
this.states[state] = callback;
return this;
}
/**
* Define a relationship on another factory
*/
relation(relation, callback) {
const modelRelation = this.model.$getRelation(relation);
/**
* Only whitelisted relationships are allowed on the factory
*/
if (!modelRelation) {
throw new Error([
`Cannot define "${relation}" relationship.`,
`The relationship must exist on the "${this.model.name}" model first`,
].join(' '));
}
switch (modelRelation.type) {
case 'belongsTo':
this.relations[relation] = new BelongsTo_1.BelongsTo(modelRelation, callback);
break;
case 'hasOne':
this.relations[relation] = new HasOne_1.HasOne(modelRelation, callback);
break;
case 'hasMany':
this.relations[relation] = new HasMany_1.HasMany(modelRelation, callback);
break;
case 'manyToMany':
this.relations[relation] = new ManyToMany_1.ManyToMany(modelRelation, callback);
break;
case 'hasManyThrough':
throw new Error([
`Cannot define "${relation}" relationship.`,
'"hasManyThrough" relationship does not have any persistance API',
].join(' '));
}
return this;
}
/**
* Define a custom `newUp` method
*/
newUp(callback) {
this.newUpModelInstance = callback;
return this;
}
/**
* Define a custom `merge` method
*/
merge(callback) {
this.mergeAttributes = callback;
return this;
}
/**
* Build factory model and return factory builder. The builder is then
* used to make/create model instances
*/
build() {
/**
* Return a build object, which proxies all of the factory builder
* method and invokes them with a fresh instance.
*/
const builder = {
model: this,
query(options) {
return new FactoryBuilder_1.FactoryBuilder(this.model, options);
},
client(...args) {
return this.query().client(...args);
},
connection(...args) {
return this.query().connection(...args);
},
apply(...args) {
return this.query().apply(...args);
},
with(relation, ...args) {
return this.query().with(relation, ...args);
},
merge(attributes) {
return this.query().merge(attributes);
},
useCtx(ctx) {
return this.query().useCtx(ctx);
},
make(callback) {
return this.query().make(callback);
},
makeStubbed(callback) {
return this.query().makeStubbed(callback);
},
create(callback) {
return this.query().create(callback);
},
makeMany(count, callback) {
return this.query().makeMany(count, callback);
},
makeStubbedMany(count, callback) {
return this.query().makeStubbedMany(count, callback);
},
createMany(count, callback) {
return this.query().createMany(count, callback);
},
};
return builder;
}
}
exports.FactoryModel = FactoryModel;