UNPKG

@themost/data

Version:

MOST Web Framework Codename Blueshift - Data module

200 lines (188 loc) 6.87 kB
// MOST Web Framework 2.0 Codename Blueshift BSD-3-Clause license Copyright (c) 2017-2022, THEMOST LP All rights reserved /*eslint no-var: "off"*/ // noinspection ES6ConvertVarToLetConst var {LangUtils} = require('@themost/common'); var _ = require('lodash'); var {QueryExpression} = require('@themost/query'); var {QueryField} = require('@themost/query'); var {DataAssociationMapping} = require('./types'); var {DataQueryable} = require('./data-queryable'); var {hasOwnProperty} = require('./has-own-property'); /** * @classdesc Represents a foreign key association between two models. <p> This association may be defined in a field of a data model as follows: </p> <pre class="prettyprint"><code> { "name": "Order", "id": 449, "title": "Order", "hidden": false, "sealed": false, "abstract": false, "version": "1.0", "fields": [ ... { "name": "customer", "title": "Customer", "description": "Party placing the order.", "type": "Party" } ... ] } </code></pre> <p> where model Order has a foreign key association with model Party (Person or Organization). HasOneAssociation class inherits DataQueryable class for selecting the associated item. </p> <pre class="prettyprint"><code> var orders = context.model('Order'); orders.where('id').equal(145).first().then(function(result) { var order = orders.convert(result); order.property('customer') .first().then(function(result) { done(null, result); }).catch(function(err) { done(err); }); }).catch(function(err) { done(err); }); </code></pre> * @class * @constructor * @augments DataQueryable * @param {DataObject} obj - An instance of DataObject class that represents the parent data object * @param {string|*} association A string that represents the name of the field which holds association mapping or the association mapping itself. * @property {DataObject} parent Gets or sets the parent data object */ function HasOneAssociation(obj, association) { /** * @property super_ * @memberof HasOneAssociation * @static */ /** * @type {DataObject} * @private */ var parent = obj; /** * Gets or sets the parent data object * @type DataObject */ Object.defineProperty(this, 'parent', { get: function () { return parent; }, set: function (value) { parent = value; }, configurable: false, enumerable: false}); var self = this; /** * @type {DataAssociationMapping} */ this.mapping = undefined; if (typeof association === 'string') { //infer mapping from field name //set relation mapping if (self.parent!==null) { var model = self.parent.getModel(); if (model!==null) self.mapping = model.inferMapping(association); } } else if (typeof association === 'object' && association !==null) { //get the specified mapping if (association instanceof DataAssociationMapping) self.mapping = association; else self.mapping = _.assign(new DataAssociationMapping(), association); } /** * @type QueryExpression */ var _query; //override query property Object.defineProperty(this, 'query', { get:function() { //if query is already defined if (_query != null) { return _query; } if (typeof self.mapping === 'undefined' || self.mapping===null) throw new Error('Data association mapping cannot be empty at this context.'); //get parent object var associatedValue = null; if (hasOwnProperty(self.parent, self.mapping.childField)) { // get associated object var associatedObject = self.parent[self.mapping.childField]; // if parent object has a property for mapping child field if (associatedObject && hasOwnProperty(associatedObject, self.mapping.parentField)) { // get associated value associatedValue = associatedObject[self.mapping.parentField]; } else if (associatedObject != null ) { associatedValue = associatedObject; } // return query _query = self.model.where(self.mapping.parentField).equal(associatedValue).prepare().query; return _query; } else { var childModel = self.parent.getModel(); var parentModel = self.model; /** * get empty query expression * @type QueryExpression */ _query = self.model.asQueryable().cache(false).select().query; // get random alias var alias = self.model.name + '0'; // get join left operand var left = new QueryExpression().select(self.mapping.parentField).from(parentModel.viewAdapter).$select; // get join right operand var right = new QueryExpression().select(self.mapping.childField).from(alias).$select; // create join _query.join(childModel.viewAdapter, [], alias).with([left, right]); // inject where _query.injectWhere(new QueryExpression().where(new QueryField(self.model.primaryKey).from(alias)).equal(self.parent.getId()).$where); // return query return _query.prepare(); } }, configurable:false, enumerable:false }); /** * @type DataModel */ var _model; Object.defineProperty(this, 'model', { get: function() { if (_model) { return _model; } if (self.parent && self.mapping) { _model = this.parent.context.model(self.mapping.parentModel); return _model; } return null; }, enumerable: false }); } LangUtils.inherits(HasOneAssociation, DataQueryable); HasOneAssociation.prototype.getItems = function() { throw new Error('Unsupported method call:getItems()') }; HasOneAssociation.prototype.getList = function() { throw new Error('Unsupported method call:getList()') }; HasOneAssociation.prototype.getItem = function() { // noinspection JSPotentiallyInvalidConstructorUsage return HasOneAssociation.super_.prototype.getItem.bind(this)(); }; HasOneAssociation.prototype.getAllItems = function() { throw new Error('Unsupported method call:getAllItems()') }; module.exports = { HasOneAssociation };