UNPKG

@aws-amplify/datastore

Version:

AppSyncLocal support for aws-amplify

344 lines • 12.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var types_1 = require("../types"); /** * Defines a relationship from a LOCAL model.field to a REMOTE model.field and helps * navigate the relationship, providing a simplified peek at the relationship details * pertinent to setting FK's and constructing join conditions. * * Because I mean, relationships are tough. * */ var ModelRelationship = /** @class */ (function () { /** * @param modelDefinition The "local" model. * @param field The "local" model field. */ function ModelRelationship(model, field) { if (!types_1.isFieldAssociation(model.schema, field)) { throw new Error(model.schema.name + "." + field + " is not a relationship."); } this.localModel = model; this._field = field; } /** * Returns a ModelRelationship for the the given model and field if the pair * indicates a relationship to another model. Else, returns `null`. * * @param model The model the relationship field exists in. * @param field The field that may relates the local model to the remote model. */ ModelRelationship.from = function (model, field) { if (types_1.isFieldAssociation(model.schema, field)) { return new this(model, field); } else { return null; } }; /** * Enumerates all valid `ModelRelationship`'s on the given model. * * @param model The model definition to enumerate relationships of. */ ModelRelationship.allFrom = function (model) { var e_1, _a; var relationships = []; try { for (var _b = tslib_1.__values(Object.keys(model.schema.fields)), _c = _b.next(); !_c.done; _c = _b.next()) { var field = _c.value; var relationship = ModelRelationship.from(model, field); relationship && relationships.push(relationship); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } return relationships; }; Object.defineProperty(ModelRelationship.prototype, "localDefinition", { get: function () { return this.localModel.schema; }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "field", { /** * The virtual/computed field on the local model that should contain * the related model. */ get: function () { return this._field; }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "localConstructor", { /** * The constructor that can be used to query DataStore or create instance for * the local model. */ get: function () { return this.localModel.builder; }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "type", { /** * The name/type of the relationship the local model has with the remote model * via the defined local model field. */ get: function () { return this.localAssocation.connectionType; }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "localAssocation", { /** * Raw details about the local FK as-is from the local model's field definition in * the schema. This field requires interpretation. * * @see localJoinFields * @see localAssociatedWith */ get: function () { return this.localDefinition.fields[this.field].association; }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "localJoinFields", { /** * The field names on the local model that can be used to query or queried to match * with instances of the remote model. * * Fields are returned in-order to match the order of `this.remoteKeyFields`. */ get: function () { /** * This is relatively straightforward, actually. * * If we have explicitly stated targetNames, codegen is telling us authoritatively * to use those fields for this relationship. The local model "points to" fields * in the remote one. * * In other cases, the remote model points to this one's */ if (this.localAssocation.targetName) { // This case is theoretically unnecessary going forward. return [this.localAssocation.targetName]; } else if (this.localAssocation.targetNames) { return this.localAssocation.targetNames; } else { return this.localPKFields; } }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "localPKFields", { /** * The field names on the local model that uniquely identify it. * * These fields may or may not be relevant to the join fields. */ get: function () { return this.localModel.pkField; }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "remoteDefinition", { get: function () { var _a; return (_a = this.remoteModelType.modelConstructor) === null || _a === void 0 ? void 0 : _a.schema; }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "remoteModelType", { get: function () { return this.localDefinition.fields[this.field].type; }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "remoteModelConstructor", { /** * Constructor that can be used to query DataStore or create instances for * the remote model. */ get: function () { return this.remoteModelType.modelConstructor.builder; }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "remotePKFields", { /** * The field names on the remote model that uniquely identify it. * * These fields may or may not be relevant to the join fields. */ get: function () { var _a; return ((_a = this.remoteModelType.modelConstructor) === null || _a === void 0 ? void 0 : _a.pkField) || ['id']; }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "localAssociatedWith", { /** * The `associatedWith` fields from the local perspective. * * When present, these fields indicate which fields on the remote model to use * when looking for a remote association and/or determining the final remote * key fields. */ get: function () { if (this.localAssocation.connectionType === 'HAS_MANY' || this.localAssocation.connectionType === 'HAS_ONE') { // This de-arraying is theoretically unnecessary going forward. return Array.isArray(this.localAssocation.associatedWith) ? this.localAssocation.associatedWith : [this.localAssocation.associatedWith]; } else { return undefined; } }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "explicitRemoteAssociation", { /** * The `remote` model's associated field's `assocation` metadata, if * present. * * This is used when determining if the remote model's associated field * specifies which FK fields to use. If this value is `undefined`, the * name of the remote field (`this.localAssociatedWith`) *is* the remote * key field. */ get: function () { var _a; if (this.localAssociatedWith) { if (this.localAssociatedWith.length === 1) { return (_a = this.remoteDefinition.fields[this.localAssociatedWith[0]]) === null || _a === void 0 ? void 0 : _a.association; } else { return undefined; } } }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "remoteJoinFields", { /** * The field names on the remote model that can used to query or queried to match * with instances of the local model. * * Fields are returned in-order to match the order of `this.localKeyFields`. */ get: function () { /** * If the local relationship explicitly names "associated with" fields, we * need to see if this points direction to a reciprocating assocation. If it * does, the remote assocation indicates what fields to use. */ var _a, _b, _c; if ((_a = this.explicitRemoteAssociation) === null || _a === void 0 ? void 0 : _a.targetName) { // This case is theoretically unnecessary going forward. return [this.explicitRemoteAssociation.targetName]; } else if ((_b = this.explicitRemoteAssociation) === null || _b === void 0 ? void 0 : _b.targetNames) { return (_c = this.explicitRemoteAssociation) === null || _c === void 0 ? void 0 : _c.targetNames; } else if (this.localAssociatedWith) { return this.localAssociatedWith; } else { return this.remotePKFields; } }, enumerable: true, configurable: true }); Object.defineProperty(ModelRelationship.prototype, "isComplete", { /** * Whether this relationship everything necessary to get, set, and query from * the perspective of the local model provided at instantiation. */ get: function () { return this.localJoinFields.length > 0 && this.remoteJoinFields.length > 0; }, enumerable: true, configurable: true }); /** * Creates an FK mapper object with respect to the given related instance. * * E.g., if the local FK fields are `[parentId, parentName]` and point to * `[customId, name]` on the remote model, `createLocalFKObject(remote)` * will return: * * ``` * { * parentId: remote.customId, * parentName: remote.name * } * ``` * * @param remote The remote related instance. */ ModelRelationship.prototype.createLocalFKObject = function (remote) { var fk = {}; for (var i = 0; i < this.localJoinFields.length; i++) { fk[this.localJoinFields[i]] = remote[this.remoteJoinFields[i]]; } return fk; }; /** * Creates an query mapper object to help fetch the remote instance(s) or * `null` if any of the necessary local fields are `null` or `undefined`. * * E.g., if the local FK fields are `[parentId, parentName]` and point to * `[customId, name]` on the remote model, `createLocalFKObject(remote)` * will return: * * ``` * { * customId: local.parentId * name: local.parentName * } * ``` * * If the local fields are not populated, returns * * @param local The local instance. */ ModelRelationship.prototype.createRemoteQueryObject = function (local) { var query = {}; for (var i = 0; i < this.remoteJoinFields.length; i++) { var localValue = local[this.localJoinFields[i]]; if (localValue === null || localValue === undefined) return null; query[this.remoteJoinFields[i]] = local[this.localJoinFields[i]]; } return query; }; return ModelRelationship; }()); exports.ModelRelationship = ModelRelationship; //# sourceMappingURL=relationship.js.map