pims
Version:
An ORM for document-oriented database systems, written in and for TypeScript.
143 lines • 7.47 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const index_1 = require("./index");
const model_1 = require("../model");
const relationships_1 = require("../relationships");
const column_1 = require("../column");
function getHasAndBelongsName(leftName, rightName) {
if (leftName < rightName) {
return `${leftName}_${rightName}`;
}
return `${rightName}_${leftName}`;
}
class AdapterBase {
constructor(opts) {
this.models = opts.models;
const tableNames = new Map();
opts.models.forEach(model => {
model[index_1.adapterKey] = this;
const modelInfo = model_1.Model.getInfo(model);
const relations = modelInfo.relationships.filter(relation => relation.kind === relationships_1.Relationship.HasAndBelongsToMany);
relations.forEach(relation => {
const relatedModel = model_1.Model.getInfo(relation.model(model));
let tableName = getHasAndBelongsName(modelInfo.table, relatedModel.table);
tableNames.set(tableName, {
leftModel: modelInfo,
rightModel: relatedModel,
});
});
});
Array.from(tableNames.entries()).forEach(([tableName, { leftModel, rightModel }]) => {
let LinkedModel = class LinkedModel {
};
LinkedModel = __decorate([
model_1.Model({
database: leftModel.database,
table: tableName,
})
], LinkedModel);
column_1.Column({ primary: true })(LinkedModel.prototype, 'id');
column_1.Column({ secondary: true })(LinkedModel.prototype, `${leftModel.table}_id`);
column_1.Column({ secondary: true })(LinkedModel.prototype, `${rightModel.table}_id`);
this.models.push(LinkedModel);
});
}
/**
* Ensures all tables exist, and waits for them to be ready.
*/
ensure() {
return Promise.all(this.models.map(this.ensureTable, this)).then(() => undefined);
}
/**
* Save the model to the Database.
*
* If replace is set to true, the entire model will be **replaced**. Otherwise
* default action would be to update the document.
*/
save(model, replace = false) {
return __awaiter(this, void 0, void 0, function* () {
const ctor = model.constructor;
const modelInfo = model_1.Model.getInfo(ctor);
model_1.Model.notify(model, 'beforeSave');
// todo(birtles): Actually figure out what changed.
const changed = modelInfo.columns.filter(col => !col.computed).reduce((doc, col) => (Object.assign({}, doc, { [col.key]: model[col.modelKey] })), {});
yield this.updateStore(model, changed, replace);
model_1.Model.notify(model, 'afterSave');
return model;
});
}
delete(model) {
return __awaiter(this, void 0, void 0, function* () {
const ctor = model.constructor;
const modelInfo = model_1.Model.getInfo(ctor);
model_1.Model.notify(model, 'beforeDelete');
if (!model[modelInfo.primaryKey]) {
throw new Error('Cannot delete model without a populated primary key.');
}
yield this.deleteFromStore(model);
model_1.Model.notify(model, 'afterDelete');
});
}
join(model, relationshipKey, opts = {}) {
return __awaiter(this, void 0, void 0, function* () {
const ctor = model.constructor;
const modelInfo = model_1.Model.getInfo(ctor);
const relationship = modelInfo.relationships.find(relationship => relationship.key === relationshipKey);
if (!relationship) {
throw new Error(`No relationship found for ${relationshipKey}`);
}
model_1.Model.notify(model, 'beforeJoin', relationship);
let joinData;
const relationshipModel = relationship.model(model);
const relationshipModelInfo = model_1.Model.getInfo(relationshipModel);
switch (relationship.kind) {
case relationships_1.Relationship.HasMany:
joinData = yield this.get(relationshipModel, model[modelInfo.primaryKey], { index: relationship.foreignKey });
if (opts.predicate) {
yield Promise.all(joinData.map(opts.predicate));
}
break;
case relationships_1.Relationship.BelongsTo:
joinData = yield this.getOne(relationshipModel, model[relationship.foreignKey]);
if (opts.predicate) {
yield opts.predicate(joinData);
}
break;
case relationships_1.Relationship.HasOne:
joinData = yield this.getOne(relationshipModel, model[modelInfo.primaryKey], { index: relationship.foreignKey });
if (opts.predicate) {
yield opts.predicate(joinData);
}
break;
case relationships_1.Relationship.HasAndBelongsToMany:
const linkedModels = yield this.get(this.getModelByName(getHasAndBelongsName(modelInfo.table, relationshipModelInfo.table)), model[modelInfo.primaryKey], { index: `${modelInfo.table}_id` });
joinData = yield Promise.all(linkedModels.map(model => this.getOne(relationshipModel, model[`${relationshipModelInfo.table}_id`])));
break;
default:
throw new Error(`Unhandled relationship type ${relationship.kind}`);
}
model[relationship.key] = joinData;
model_1.Model.notify(model, 'afterJoin', relationship);
return model;
});
}
getModelByName(name) {
return this.models.find(model => model_1.Model.getInfo(model).table === name);
}
}
exports.AdapterBase = AdapterBase;
//# sourceMappingURL=base.js.map