ravendb
Version:
RavenDB client for Node.js
248 lines • 10.8 kB
JavaScript
import { TypeUtil } from "../../Utility/TypeUtil.js";
import { CONSTANTS } from "../../Constants.js";
import { throwError } from "../../Exceptions/index.js";
import { SetupDocumentBase } from "../SetupDocumentBase.js";
export class EntityToJson {
_session;
/**
* All the listeners for this session
*/
constructor(session) {
this._session = session;
}
_missingDictionary = new Map();
get missingDictionary() {
return this._missingDictionary;
}
convertEntityToJson(entity, documentInfo) {
if (documentInfo) {
this._session.onBeforeConversionToDocumentInvoke(documentInfo.id, entity);
}
let document = EntityToJson._convertEntityToJsonInternal(entity, this._session.conventions, documentInfo);
if (documentInfo) {
const documentReference = {
value: document
};
this._session.onAfterConversionToDocumentInvoke(documentInfo.id, entity, documentReference);
document = documentReference.value;
}
return document;
}
static _convertEntityToJsonInternal(entity, conventions, documentInfo, removeIdentityProperty = true) {
const entityMapper = conventions.objectMapper;
let typeInfo;
let jsonNode = entityMapper.toObjectLiteral(entity, (_typeInfo) => {
typeInfo = _typeInfo;
}, conventions.knownEntityTypesByName);
if (entity instanceof SetupDocumentBase) {
jsonNode = entity.toRemoteFieldNames();
}
else {
jsonNode = conventions.transformObjectKeysToRemoteFieldNameConvention(jsonNode);
}
EntityToJson._writeMetadata(jsonNode, typeInfo, documentInfo);
if (removeIdentityProperty) {
const type = TypeUtil.findType(entity, conventions.knownEntityTypes);
EntityToJson._tryRemoveIdentityProperty(jsonNode, type, conventions);
}
return jsonNode;
}
static convertEntityToJson(entity, conventions, documentInfo, removeIdentityProperty = true) {
let typeInfo;
const jsonNode = conventions.objectMapper.toObjectLiteral(entity, (_typeInfo) => {
typeInfo = _typeInfo;
});
EntityToJson._writeMetadata(jsonNode, typeInfo, documentInfo);
if (removeIdentityProperty) {
EntityToJson._tryRemoveIdentityProperty(jsonNode, typeInfo.typeName, conventions);
}
return jsonNode;
}
static nestedTypes = CONSTANTS.Documents.Metadata.NESTED_OBJECT_TYPES;
static ravenJsType = CONSTANTS.Documents.Metadata.RAVEN_JS_TYPE;
static _writeMetadata(jsonNode, typeInfo, documentInfo) {
if (!documentInfo) {
return;
}
if (documentInfo.metadata) {
documentInfo.metadata[EntityToJson.nestedTypes] = typeInfo.nestedTypes;
documentInfo.metadata[EntityToJson.ravenJsType] ??= typeInfo.typeName;
}
function differentNestedTypes() {
const existing = documentInfo.metadataInstance[EntityToJson.nestedTypes];
if (!existing) {
return true;
}
if (Object.keys(existing).length !== Object.keys(typeInfo.nestedTypes).length) {
return true;
}
for (const key in typeInfo.nestedTypes) {
if (typeInfo.nestedTypes[key] !== existing[key]) {
return true;
}
}
return false;
}
if (documentInfo.metadataInstance) {
if (differentNestedTypes()) {
documentInfo.metadataInstance[EntityToJson.nestedTypes] = typeInfo.nestedTypes;
}
documentInfo.metadataInstance[EntityToJson.ravenJsType] ??= typeInfo.typeName;
}
let setMetadata = false;
const metadataNode = {};
if (documentInfo.metadata && Object.keys(documentInfo.metadata).length > 0) {
setMetadata = true;
Object.assign(metadataNode, documentInfo.metadata);
// Add the document @metadata fields (for RDBC-213)
const entityMeta = documentInfo.entity[CONSTANTS.Documents.Metadata.KEY];
for (const metadataItem in entityMeta) {
// eslint-disable-next-line no-prototype-builtins
if (entityMeta.hasOwnProperty(metadataItem)) {
setMetadata = true;
metadataNode[metadataItem] = entityMeta[metadataItem];
}
}
}
else if (documentInfo.metadataInstance) {
setMetadata = true;
Object.assign(metadataNode, documentInfo.metadataInstance);
}
if (documentInfo.collection) {
setMetadata = true;
metadataNode["@collection"] = documentInfo.collection;
}
if (setMetadata) {
jsonNode[CONSTANTS.Documents.Metadata.KEY] = metadataNode;
}
}
/**
* Converts a json object to an entity.
*/
convertToEntity(targetEntityType, id, document, trackEntity) {
const conventions = this._session.conventions;
const entityType = conventions.getJsTypeByDocumentType(targetEntityType);
try {
if (TypeUtil.isType(document, targetEntityType)) {
return document;
}
const documentRef = {
value: document
};
this._session.onBeforeConversionToEntityInvoke(id, entityType, documentRef);
document = documentRef.value;
let entity;
//TODO: if track! -> RegisterMissingProperties
const documentTypeFromConventions = conventions.getJsType(id, document);
const entityTypeInfoFromMetadata = EntityToJson._getEntityTypeInfoFromMetadata(document);
if (documentTypeFromConventions) {
const passedEntityTypeIsAssignableFromConventionsDocType = entityType
&& ((entityType.name === documentTypeFromConventions.name)
|| TypeUtil.isInstanceOf(entityType, documentTypeFromConventions));
if (passedEntityTypeIsAssignableFromConventionsDocType) {
const mapper = conventions.objectMapper;
entity = mapper.fromObjectLiteral(document, entityTypeInfoFromMetadata);
}
}
if (!entity) {
const mapper = conventions.objectMapper;
let passedTypeInfo = entityTypeInfoFromMetadata;
if (entityType) {
passedTypeInfo =
Object.assign(passedTypeInfo, { typeName: entityType.name });
}
entity = mapper.fromObjectLiteral(document, passedTypeInfo);
}
const isProjection = !!document[CONSTANTS.Documents.Metadata.PROJECTION];
if (id) {
this._session.generateEntityIdOnTheClient.trySetIdentity(entity, id, isProjection);
}
return entity;
}
catch (err) {
throwError("InvalidOperationException", `Could not convert document ${id} to entity of type `
+ `${entityType ? entityType.name : entityType}: ${err.stack}`, err);
}
}
static _getEntityTypeInfoFromMetadata(document) {
const metadata = document[CONSTANTS.Documents.Metadata.KEY];
if (!metadata) {
return {};
}
return {
typeName: metadata[CONSTANTS.Documents.Metadata.RAVEN_JS_TYPE],
nestedTypes: metadata[CONSTANTS.Documents.Metadata.NESTED_OBJECT_TYPES]
};
}
populateEntity(entity, id, document) {
if (!id) {
throwError("InvalidArgumentException", "Id cannot be null.");
}
EntityToJson.populateEntity(entity, document, this._session.conventions.objectMapper);
this._session.generateEntityIdOnTheClient.trySetIdentity(entity, id);
}
static populateEntity(entity, document, objectMapper) {
if (!entity) {
throwError("InvalidArgumentException", "Entity cannot be null");
}
if (!document) {
throwError("InvalidArgumentException", "Document cannot be null");
}
if (!objectMapper) {
throwError("InvalidArgumentException", "ObjectMapper cannot be null");
}
try {
const entityValue = objectMapper.fromObjectLiteral(document);
Object.assign(entity, entityValue);
}
catch (e) {
throwError("InvalidOperationException", "Could not populate entity.", e);
}
}
static _tryRemoveIdentityProperty(document, entityType, conventions) {
const identityProperty = conventions.getIdentityProperty(entityType);
if (!identityProperty) {
return false;
}
delete document[identityProperty];
return true;
}
static convertToEntity(entityClass, id, document, conventions) {
const entityType = conventions.getJsTypeByDocumentType(entityClass);
try {
let entity;
const documentTypeFromConventions = conventions.getJsType(id, document);
const entityTypeInfoFromMetadata = EntityToJson._getEntityTypeInfoFromMetadata(document);
if (documentTypeFromConventions) {
const passedEntityTypeIsAssignableFromConventionsDocType = entityType
&& ((entityType.name === documentTypeFromConventions.name)
|| TypeUtil.isInstanceOf(entityType, documentTypeFromConventions));
if (passedEntityTypeIsAssignableFromConventionsDocType) {
const mapper = conventions.objectMapper;
entity = mapper.fromObjectLiteral(document, entityTypeInfoFromMetadata);
}
}
if (!entity) {
const mapper = conventions.objectMapper;
let passedTypeInfo = entityTypeInfoFromMetadata;
if (entityType) {
passedTypeInfo =
Object.assign(passedTypeInfo, { typeName: entityType.name });
}
entity = mapper.fromObjectLiteral(document, passedTypeInfo);
}
return entity;
}
catch (err) {
throwError("InvalidOperationException", `Could not convert document ${id} to entity of type `
+ `${entityType ? entityType.name : entityType}: ${err.stack}`, err);
}
}
removeFromMissing(entity) {
this._missingDictionary.delete(entity);
}
clear() {
this._missingDictionary.clear();
}
}
//# sourceMappingURL=EntityToJson.js.map