@aws-amplify/datastore
Version:
AppSyncLocal support for aws-amplify
344 lines • 12.8 kB
JavaScript
"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