UNPKG

ravendb

Version:
764 lines 28.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DocumentConventions = void 0; const ObjectMapper_js_1 = require("../../Mapping/ObjectMapper.js"); const index_js_1 = require("../../Exceptions/index.js"); const Constants_js_1 = require("../../Constants.js"); const TypeUtil_js_1 = require("../../Utility/TypeUtil.js"); const DateUtil_js_1 = require("../../Utility/DateUtil.js"); const ObjectUtil_js_1 = require("../../Utility/ObjectUtil.js"); const BulkInsertConventions_js_1 = require("./BulkInsertConventions.js"); const ShardingConventions_js_1 = require("./ShardingConventions.js"); const pluralize_js_1 = require("../../ext/pluralize/pluralize.js"); function createServerDefaults() { const conventions = new DocumentConventions(); conventions.sendApplicationIdentifier = false; conventions.freeze(); return conventions; } class DocumentConventions { static _defaults = new DocumentConventions(); static defaultForServerConventions; static get defaultConventions() { return this._defaults; } static _cachedDefaultTypeCollectionNames = new Map(); _listOfQueryValueToObjectConverters = []; _registeredIdConventions = new Map(); _registeredIdPropertyNames = new Map(); _frozen; _originalConfiguration; _identityPartsSeparator; _disableTopologyUpdates; _disableAtomicDocumentWritesInClusterWideTransaction; _disableTcpCompression = true; // not yet supported _shouldIgnoreEntityChanges; _transformClassCollectionNameToDocumentIdPrefix; _documentIdGenerator; _loadBalancerPerSessionContextSelector; _findCollectionName; _identityProperty; _findJsTypeName; _findJsType; _useOptimisticConcurrency; _maxNumberOfRequestsPerSession; _requestTimeout; _firstBroadcastAttemptTimeout; _secondBroadcastAttemptTimeout; _waitForIndexesAfterSaveChangesTimeout; _waitForReplicationAfterSaveChangesTimeout; _waitForNonStaleResultsTimeout; _loadBalancerContextSeed; _loadBalanceBehavior; _readBalanceBehavior; _maxHttpCacheSize; _knownEntityTypes; _localToServerFieldNameConverter; _serverToLocalFieldNameConverter; _objectMapper; _customFetch; _dateUtil; _useHttpDecompression = null; _httpCompressionAlgorithm = "Gzip"; _sendApplicationIdentifier; _bulkInsert; get bulkInsert() { return this._bulkInsert; } _sharding; get sharding() { return this._sharding; } _returnPlainJsObjects = false; /** * Gets whether all values returned from API will be plain objects (not class instances). * This is useful for environments like Next.js that require serializable results. */ get returnPlainJsObjects() { return this._returnPlainJsObjects; } /** * Sets whether all values returned from API will be plain objects (not class instances). * This is useful for environments like Next.js that require serializable results. */ set returnPlainJsObjects(value) { this._assertNotFrozen(); this._returnPlainJsObjects = value; } constructor() { this._readBalanceBehavior = "None"; this._identityPartsSeparator = "/"; this._identityProperty = Constants_js_1.CONSTANTS.Documents.Metadata.ID_PROPERTY; this._findJsType = (id, doc) => { const metadata = doc[Constants_js_1.CONSTANTS.Documents.Metadata.KEY]; if (metadata) { const jsType = metadata[Constants_js_1.CONSTANTS.Documents.Metadata.RAVEN_JS_TYPE]; return this.getJsTypeByDocumentType(jsType); } return null; }; this._findJsTypeName = (ctorOrTypeChecker) => { if (!ctorOrTypeChecker) { return null; } const name = ctorOrTypeChecker.name; if (name === "Object") { return null; } return name; }; this._transformClassCollectionNameToDocumentIdPrefix = collectionName => DocumentConventions.defaultTransformCollectionNameToDocumentIdPrefix(collectionName); this._findCollectionName = type => DocumentConventions.defaultGetCollectionName(type); this._maxNumberOfRequestsPerSession = 30; this._bulkInsert = new BulkInsertConventions_js_1.BulkInsertConventions(() => this._assertNotFrozen()); this._sharding = new ShardingConventions_js_1.ShardingConventions(this); this._maxHttpCacheSize = 128 * 1024 * 1024; this._knownEntityTypes = new Map(); this._objectMapper = new ObjectMapper_js_1.TypesAwareObjectMapper({ documentConventions: this }); this._dateUtilOpts = {}; this._dateUtil = new DateUtil_js_1.DateUtil(this._dateUtilOpts); this._firstBroadcastAttemptTimeout = 5_000; this._secondBroadcastAttemptTimeout = 30_000; this._waitForIndexesAfterSaveChangesTimeout = 15_000; this._waitForReplicationAfterSaveChangesTimeout = 15_000; this._waitForNonStaleResultsTimeout = 15_000; this._sendApplicationIdentifier = true; } get requestTimeout() { return this._requestTimeout; } set requestTimeout(requestTimeout) { this._assertNotFrozen(); this._requestTimeout = requestTimeout; } /** * Enables sending a unique application identifier to the RavenDB Server that is used for Client API usage tracking. * It allows RavenDB Server to issue performance hint notifications e.g. during robust topology update requests which could indicate Client API misuse impacting the overall performance * @return if option is enabled */ get sendApplicationIdentifier() { return this._sendApplicationIdentifier; } /** * Enables sending a unique application identifier to the RavenDB Server that is used for Client API usage tracking. * It allows RavenDB Server to issue performance hint notifications e.g. during robust topology update requests which could indicate Client API misuse impacting the overall performance * @param sendApplicationIdentifier if option should be enabled */ set sendApplicationIdentifier(sendApplicationIdentifier) { this._assertNotFrozen(); this._sendApplicationIdentifier = sendApplicationIdentifier; } /** * Get the timeout for the second broadcast attempt. * Default: 30 seconds * * Upon failure of the first attempt the request executor will resend the command to all nodes simultaneously. * @return broadcast timeout */ get secondBroadcastAttemptTimeout() { return this._secondBroadcastAttemptTimeout; } /** * Set the timeout for the second broadcast attempt. * Default: 30 seconds * * Upon failure of the first attempt the request executor will resend the command to all nodes simultaneously. * * @param secondBroadcastAttemptTimeout broadcast timeout */ set secondBroadcastAttemptTimeout(secondBroadcastAttemptTimeout) { this._assertNotFrozen(); this._secondBroadcastAttemptTimeout = secondBroadcastAttemptTimeout; } /** * Get the timeout for the first broadcast attempt. * Default: 5 seconds * * First attempt will send a single request to a selected node. * @return broadcast timeout */ get firstBroadcastAttemptTimeout() { return this._firstBroadcastAttemptTimeout; } /** * Set the timeout for the first broadcast attempt. * Default: 5 seconds * * First attempt will send a single request to a selected node. * * @param firstBroadcastAttemptTimeout broadcast timeout */ set firstBroadcastAttemptTimeout(firstBroadcastAttemptTimeout) { this._assertNotFrozen(); this._firstBroadcastAttemptTimeout = firstBroadcastAttemptTimeout; } get objectMapper() { return this._objectMapper; } set objectMapper(value) { this._assertNotFrozen(); this._objectMapper = value; } get customFetch() { return this._customFetch; } /** * Allows to override default fetch method * * This method is useful to enable RavenDB node.js client * on CloudFlare Workers * * You should pass object bound to worker with type: mtls_certificate * * @param customFetch */ set customFetch(customFetch) { this._assertNotFrozen(); this._customFetch = customFetch; } get dateUtil() { return this._dateUtil; } set dateUtil(value) { this._assertNotFrozen(); this._dateUtil = value; } get readBalanceBehavior() { return this._readBalanceBehavior; } set readBalanceBehavior(value) { this._assertNotFrozen(); this._readBalanceBehavior = value; } get loadBalancerContextSeed() { return this._loadBalancerContextSeed; } set loadBalancerContextSeed(seed) { this._assertNotFrozen(); this._loadBalancerContextSeed = seed; } get isDisableTcpCompression() { return this._disableTcpCompression; } /** * We have to make this check so if admin activated this, but client code did not provide the selector, * it is still disabled. Relevant if we have multiple clients / versions at once. */ get loadBalanceBehavior() { return this._loadBalanceBehavior; } set loadBalanceBehavior(loadBalanceBehavior) { this._assertNotFrozen(); this._loadBalanceBehavior = loadBalanceBehavior; } /** * Gets the function that allow to specialize the topology * selection for a particular session. Used in load balancing * scenarios */ get loadBalancerPerSessionContextSelector() { return this._loadBalancerPerSessionContextSelector; } /** * Sets the function that allow to specialize the topology * selection for a particular session. Used in load balancing * scenarios * @param selector selector to use */ set loadBalancerPerSessionContextSelector(selector) { this._loadBalancerPerSessionContextSelector = selector; } /** * Optional field name casing converter * This one is applied on local object before sending request to server */ get localToServerFieldNameConverter() { return this._localToServerFieldNameConverter; } /** * Optional field name casing converter * This one is applied on local object before sending request to server */ set localToServerFieldNameConverter(converter) { this._assertNotFrozen(); this._localToServerFieldNameConverter = converter; } /** * Optional field name casing converter * This one is applied on server object before returning result to the user */ get serverToLocalFieldNameConverter() { return this._serverToLocalFieldNameConverter; } /** * Optional field name casing converter * This one is applied on server object before returning result to the user */ set serverToLocalFieldNameConverter(converter) { this._assertNotFrozen(); this._serverToLocalFieldNameConverter = converter; } set useOptimisticConcurrency(val) { this._assertNotFrozen(); this._useOptimisticConcurrency = val; } get useOptimisticConcurrency() { return this._useOptimisticConcurrency; } deserializeEntityFromJson(documentType, document) { try { const typeName = documentType ? documentType.name : null; return this.objectMapper.fromObjectLiteral(document, { typeName }); } catch (err) { (0, index_js_1.throwError)("RavenException", "Cannot deserialize entity", err); } } get maxNumberOfRequestsPerSession() { return this._maxNumberOfRequestsPerSession; } set maxNumberOfRequestsPerSession(value) { this._maxNumberOfRequestsPerSession = value; } get maxHttpCacheSize() { return this._maxHttpCacheSize; } set maxHttpCacheSize(value) { this._assertNotFrozen(); this._maxHttpCacheSize = value; } get waitForIndexesAfterSaveChangesTimeout() { return this._waitForIndexesAfterSaveChangesTimeout; } set waitForIndexesAfterSaveChangesTimeout(value) { this._assertNotFrozen(); this._waitForIndexesAfterSaveChangesTimeout = value; } get waitForNonStaleResultsTimeout() { return this._waitForNonStaleResultsTimeout; } set waitForNonStaleResultsTimeout(value) { this._assertNotFrozen(); this._waitForNonStaleResultsTimeout = value; } get waitForReplicationAfterSaveChangesTimeout() { return this._waitForReplicationAfterSaveChangesTimeout; } set waitForReplicationAfterSaveChangesTimeout(value) { this._assertNotFrozen(); this._waitForReplicationAfterSaveChangesTimeout = value; } /** * Can accept compressed HTTP response content and will use decompression methods */ get useHttpDecompression() { if (this._useHttpDecompression === null) { return true; } return this._useHttpDecompression; } /** * Can accept compressed HTTP response content and will use decompression methods */ set useHttpDecompression(value) { this._assertNotFrozen(); this._useHttpDecompression = value; } get httpCompressionAlgorithm() { return this._httpCompressionAlgorithm; } _dateUtilOpts; get storeDatesInUtc() { return this._dateUtilOpts.useUtcDates; } set storeDatesInUtc(value) { this._assertNotFrozen(); this._dateUtilOpts.useUtcDates = value; } get storeDatesWithTimezoneInfo() { return this._dateUtilOpts.withTimezone; } set storeDatesWithTimezoneInfo(value) { this._assertNotFrozen(); this._dateUtilOpts.withTimezone = true; } /** * Whether UseOptimisticConcurrency is set to true by default for all opened sessions */ isUseOptimisticConcurrency() { return this._useOptimisticConcurrency; } /** * Whether UseOptimisticConcurrency is set to true by default for all opened sessions */ setUseOptimisticConcurrency(useOptimisticConcurrency) { this._assertNotFrozen(); this._useOptimisticConcurrency = useOptimisticConcurrency; } get identityProperty() { return this._identityProperty; } set identityProperty(val) { this._assertNotFrozen(); this._identityProperty = val; } get findJsType() { return this._findJsType; } set findJsType(value) { this._assertNotFrozen(); this._findJsType = value; } get findJsTypeName() { return this._findJsTypeName; } set findJsTypeName(value) { this._assertNotFrozen(); this._findJsTypeName = value; } get findCollectionName() { return this._findCollectionName; } set findCollectionName(value) { this._assertNotFrozen(); this._findCollectionName = value; } get documentIdGenerator() { return this._documentIdGenerator; } set documentIdGenerator(value) { this._assertNotFrozen(); this._documentIdGenerator = value; } get identityPartsSeparator() { return this._identityPartsSeparator; } set identityPartsSeparator(value) { this._assertNotFrozen(); if (this.identityPartsSeparator === "|") { (0, index_js_1.throwError)("InvalidArgumentException", "Cannot set identity parts separator to '|'"); } this._identityPartsSeparator = value; } get shouldIgnoreEntityChanges() { return this._shouldIgnoreEntityChanges; } set shouldIgnoreEntityChanges(shouldIgnoreEntityChanges) { this._assertNotFrozen(); this._shouldIgnoreEntityChanges = shouldIgnoreEntityChanges; } get disableTopologyUpdates() { return this._disableTopologyUpdates; } set disableTopologyUpdates(value) { this._assertNotFrozen(); this._disableTopologyUpdates = value; } get transformClassCollectionNameToDocumentIdPrefix() { return this._transformClassCollectionNameToDocumentIdPrefix; } set transformClassCollectionNameToDocumentIdPrefix(value) { this._assertNotFrozen(); this._transformClassCollectionNameToDocumentIdPrefix = value; } /** * Default method used when finding a collection name for a type */ static defaultGetCollectionName(ctorOrTypeChecker) { if (!ctorOrTypeChecker) { return null; } if (!TypeUtil_js_1.TypeUtil.isObjectTypeDescriptor(ctorOrTypeChecker)) { (0, index_js_1.throwError)("InvalidArgumentException", "Invalid class argument."); } if (!ctorOrTypeChecker.name) { (0, index_js_1.throwError)("InvalidArgumentException", "Type name cannot be null or undefined."); } let result = this._cachedDefaultTypeCollectionNames.get(ctorOrTypeChecker); if (result) { return result; } if (typeof (ctorOrTypeChecker) === "string") { result = (0, pluralize_js_1.plural)(ctorOrTypeChecker); } else { result = (0, pluralize_js_1.plural)(ctorOrTypeChecker.name); } this._cachedDefaultTypeCollectionNames.set(ctorOrTypeChecker, result); return result; } /** * Gets the collection name for a given type. */ getCollectionNameForType(ctorOrTypeChecker) { const collectionName = this._findCollectionName(ctorOrTypeChecker); return collectionName || DocumentConventions.defaultGetCollectionName(ctorOrTypeChecker); } /** * Gets the collection name for a given type. */ getCollectionNameForEntity(entity) { if (!entity) { return null; } const typeDescriptor = this.getEntityTypeDescriptor(entity); if (typeDescriptor) { return this.getCollectionNameForType(typeDescriptor); } if (this._findCollectionNameForObjectLiteral && entity.constructor === Object) { return this._findCollectionNameForObjectLiteral(entity); } return null; } _findCollectionNameForObjectLiteral; get findCollectionNameForObjectLiteral() { return this._findCollectionNameForObjectLiteral; } set findCollectionNameForObjectLiteral(value) { this._findCollectionNameForObjectLiteral = value; } getTypeDescriptorByEntity(entity) { return this.getEntityTypeDescriptor(entity); } getEntityTypeDescriptor(entity) { if (TypeUtil_js_1.TypeUtil.isClass(entity.constructor)) { return entity.constructor; } for (const entityType of this._knownEntityTypes.values()) { if (!TypeUtil_js_1.TypeUtil.isObjectLiteralTypeDescriptor(entityType)) { continue; } if (entityType.isType(entity)) { return entityType; } } return null; } /** * Generates the document id. */ generateDocumentId(database, entity) { for (const [typeDescriptor, idConvention] of this._registeredIdConventions) { if (TypeUtil_js_1.TypeUtil.isType(entity, typeDescriptor)) { return Promise.resolve(idConvention(database, entity)); } } return this._documentIdGenerator(database, entity); } /** * Register an id convention for a single type. * Note that you can still fall back to the DocumentIdGenerator if you want. */ registerIdConvention(ctorOrTypeChecker, idConvention) { this._assertNotFrozen(); this._registeredIdConventions.set(ctorOrTypeChecker, idConvention); return this; } registerEntityIdPropertyName(ctorOrTypeChecker, idProperty) { this._registeredIdPropertyNames.set(ctorOrTypeChecker, idProperty); } /** * Get the java class (if exists) from the document */ getJsType(id, document) { return this._findJsType(id, document); } /** * Get the Java class name to be stored in the entity metadata */ getJsTypeName(entityType) { return this._findJsTypeName(entityType); } /** * EXPERT: Disable automatic atomic writes with cluster write transactions. If set to 'true', will only consider explicitly * added compare exchange values to validate cluster wide transactions. */ get disableAtomicDocumentWritesInClusterWideTransaction() { return this._disableAtomicDocumentWritesInClusterWideTransaction; } /** * EXPERT: Disable automatic atomic writes with cluster write transactions. If set to 'true', will only consider explicitly * added compare exchange values to validate cluster wide transactions. */ set disableAtomicDocumentWritesInClusterWideTransaction(disableAtomicDocumentWritesInClusterWideTransaction) { this._assertNotFrozen(); this._disableAtomicDocumentWritesInClusterWideTransaction = disableAtomicDocumentWritesInClusterWideTransaction; } clone() { const cloned = new DocumentConventions(); return Object.assign(cloned, this); } /** * Gets the identity property. */ getIdentityProperty(documentType) { const typeDescriptor = this.getJsTypeByDocumentType(documentType); return this._registeredIdPropertyNames.get(typeDescriptor) || this._identityProperty; } updateFrom(configuration) { if (!configuration) { return; } const orig = this._originalConfiguration; if (configuration.disabled && !orig) { // nothing to do return; } if (configuration.disabled && orig) { // need to revert to original values this._maxNumberOfRequestsPerSession = orig.maxNumberOfRequestsPerSession ?? this.maxNumberOfRequestsPerSession; this._readBalanceBehavior = orig.readBalanceBehavior ?? this._readBalanceBehavior; this._identityPartsSeparator = orig.identityPartsSeparator ?? this._identityPartsSeparator; this._loadBalanceBehavior = orig.loadBalanceBehavior ?? this._loadBalanceBehavior; this._loadBalancerContextSeed = orig.loadBalancerContextSeed ?? this._loadBalancerContextSeed; this._originalConfiguration = null; return; } if (!this._originalConfiguration) { this._originalConfiguration = { etag: -1, maxNumberOfRequestsPerSession: this._maxNumberOfRequestsPerSession, readBalanceBehavior: this._readBalanceBehavior, identityPartsSeparator: this._identityPartsSeparator, loadBalanceBehavior: this._loadBalanceBehavior, loadBalancerContextSeed: this._loadBalancerContextSeed, disabled: false }; } this._maxNumberOfRequestsPerSession = configuration.maxNumberOfRequestsPerSession ?? this._originalConfiguration.maxNumberOfRequestsPerSession ?? this._maxNumberOfRequestsPerSession; this._readBalanceBehavior = configuration.readBalanceBehavior ?? this._originalConfiguration.readBalanceBehavior ?? this._readBalanceBehavior; this._loadBalanceBehavior = configuration.loadBalanceBehavior ?? this._originalConfiguration.loadBalanceBehavior ?? this._loadBalanceBehavior; this._loadBalancerContextSeed = configuration.loadBalancerContextSeed ?? this._originalConfiguration.loadBalancerContextSeed ?? this._loadBalancerContextSeed; this._identityPartsSeparator = configuration.identityPartsSeparator ?? this._originalConfiguration.identityPartsSeparator ?? this._identityPartsSeparator; } static defaultTransformCollectionNameToDocumentIdPrefix(collectionName) { const upperCaseRegex = /[A-Z]/g; const m = collectionName.match(upperCaseRegex); const upperCount = m ? m.length : 0; if (upperCount <= 1) { return collectionName.toLowerCase(); } // multiple capital letters, so probably something that we want to preserve caps on. return collectionName; } registerQueryValueConverter(type, converter) { this._assertNotFrozen(); let index; for (let index = 0; index < this._listOfQueryValueToObjectConverters.length; index++) { const entry = this._listOfQueryValueToObjectConverters[index]; if (type instanceof entry.Type) { break; } } this._listOfQueryValueToObjectConverters.splice(index, 0, { Type: type, Converter: (fieldName, value, forRange, stringValue) => { if (value instanceof type) { return converter(fieldName, value, forRange, stringValue); } stringValue(null); return false; } }); } tryConvertValueToObjectForQuery(fieldName, value, forRange, strValue) { for (const queryValueConverter of this._listOfQueryValueToObjectConverters) { if (!(value instanceof queryValueConverter.Type)) { continue; } return queryValueConverter.Converter(fieldName, value, forRange, strValue); } strValue(null); return false; } freeze() { this._frozen = true; } _assertNotFrozen() { if (this._frozen) { (0, index_js_1.throwError)("RavenException", "Conventions has been frozen after documentStore.initialize() and no changes can be applied to them"); } } get knownEntityTypesByName() { return this._knownEntityTypes; } get knownEntityTypes() { return Array.from(this._knownEntityTypes.values()); } registerJsType(entityType, name) { return this.registerEntityType(entityType, name); } registerEntityType(entityType, name) { if (!TypeUtil_js_1.TypeUtil.isObjectTypeDescriptor(entityType)) { (0, index_js_1.throwError)("InvalidArgumentException", "Entity type must be a constructor or an object literal descriptor."); } if (name) { this._knownEntityTypes.set(name, entityType); } this._knownEntityTypes.set(entityType.name, entityType); return this; } tryRegisterJsType(docType) { return this.tryRegisterEntityType(docType); } tryRegisterEntityType(docType) { if (TypeUtil_js_1.TypeUtil.isObjectTypeDescriptor(docType)) { this.registerJsType(docType); } return this; } getJsTypeByDocumentType(docTypeOrTypeName) { if (!docTypeOrTypeName) { return null; } if (typeof (docTypeOrTypeName) === "string") { return this._knownEntityTypes.get(docTypeOrTypeName) || null; } if (docTypeOrTypeName.name === "Object") { return null; } return docTypeOrTypeName; } transformObjectKeysToRemoteFieldNameConvention(obj) { if (!this._localToServerFieldNameConverter) { return obj; } const options = { recursive: true, arrayRecursive: true, defaultTransform: this._localToServerFieldNameConverter, ignorePaths: [ Constants_js_1.CONSTANTS.Documents.Metadata.IGNORE_CASE_TRANSFORM_REGEX, ] }; return ObjectUtil_js_1.ObjectUtil.transformObjectKeys(obj, options); } validate() { if ((this._localToServerFieldNameConverter && !this._serverToLocalFieldNameConverter) || (!this._localToServerFieldNameConverter && this._serverToLocalFieldNameConverter)) { (0, index_js_1.throwError)("ConfigurationException", "When configuring field name conventions, " + "one has to configure both localToServer and serverToLocal field name converters."); } } } exports.DocumentConventions = DocumentConventions; DocumentConventions.defaultForServerConventions = createServerDefaults(); DocumentConventions.defaultConventions.freeze(); //# sourceMappingURL=DocumentConventions.js.map