UNPKG

realm

Version:

Realm by MongoDB is an offline-first mobile database: an alternative to SQLite and key-value stores

170 lines 7.82 kB
"use strict"; //////////////////////////////////////////////////////////////////////////// // // Copyright 2023 Realm Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////// Object.defineProperty(exports, "__esModule", { value: true }); exports.validatePropertySchema = exports.validateObjectSchema = exports.validateRealmSchema = void 0; const assert_1 = require("../assert"); const errors_1 = require("../errors"); const indirect_1 = require("../indirect"); // Need to use `CanonicalObjectSchema` rather than `ObjectSchema` due to some // integration tests using `openRealmHook()`. That function sets `this.realm` // to the opened realm whose schema is a `CanonicalObjectSchema[]`. Consequently, // the key `"ctor"` (which doesn't exist on `ObjectSchema`) also needs to be allowed. const OBJECT_SCHEMA_KEYS = new Set([ "name", "primaryKey", "embedded", "asymmetric", "properties", // Not part of `ObjectSchema` "ctor", ]); // Need to use `CanonicalPropertySchema` rather than `PropertySchema` // due to the same reasons as above. const PROPERTY_SCHEMA_KEYS = new Set([ "type", "objectType", "presentation", "property", "default", "optional", "indexed", "mapTo", // Not part of `PropertySchema` "name", ]); /** * Validate the data types of the fields of a user-provided realm schema. */ function validateRealmSchema(realmSchema) { assert_1.assert.array(realmSchema, "realm schema"); for (const objectSchema of realmSchema) { validateObjectSchema(objectSchema); } // TODO: Assert that backlinks point to object schemas that are actually declared } exports.validateRealmSchema = validateRealmSchema; /** * Validate the data types of the fields of a user-provided object schema. */ function validateObjectSchema(objectSchema) { try { // Schema is passed via a class based model (RealmObjectConstructor) if (typeof objectSchema === "function") { const clazz = objectSchema; // We assert this later, but want a custom error message if (!(objectSchema.prototype instanceof indirect_1.indirect.Object)) { const schemaName = clazz.schema && clazz.schema.name; if (typeof schemaName === "string" && schemaName !== objectSchema.name) { throw new TypeError(`Class '${objectSchema.name}' (declaring '${schemaName}' schema) must extend Realm.Object`); } else { throw new TypeError(`Class '${objectSchema.name}' must extend Realm.Object`); } } assert_1.assert.object(clazz.schema, "schema static"); validateObjectSchema(clazz.schema); } // Schema is passed as an object (ObjectSchema) else { assert_1.assert.object(objectSchema, "object schema", { allowArrays: false }); const { name: objectName, properties, primaryKey, asymmetric, embedded } = objectSchema; assert_1.assert.string(objectName, "'name' on object schema"); assert_1.assert.object(properties, `'properties' on '${objectName}'`, { allowArrays: false }); if (primaryKey !== undefined) { assert_1.assert.string(primaryKey, `'primaryKey' on '${objectName}'`); } if (embedded !== undefined) { assert_1.assert.boolean(embedded, `'embedded' on '${objectName}'`); } if (asymmetric !== undefined) { assert_1.assert.boolean(asymmetric, `'asymmetric' on '${objectName}'`); } const invalidKeysUsed = filterInvalidKeys(objectSchema, OBJECT_SCHEMA_KEYS); (0, assert_1.assert)(!invalidKeysUsed.length, `Unexpected field(s) found on the schema for object '${objectName}': '${invalidKeysUsed.join("', '")}'.`); for (const propertyName in properties) { const propertySchema = properties[propertyName]; const isUsingShorthand = typeof propertySchema === "string"; if (!isUsingShorthand) { validatePropertySchema(objectName, propertyName, propertySchema); } } } } catch (err) { // Rethrow as SchemaParseError(s) rather than a mix of Error, TypeError, // TypeAssertionError, or AssertionError. if (err instanceof errors_1.PropertySchemaParseError) { throw err; } else if (err instanceof Error) { // This first line is a workaround to satisfy TS. Runtime check needs to be // `const objectName = objectSchema?.name || ""` where either `objectSchema` // or `objectSchema.name` can be undefined or an incorrect type. const objectName = objectSchema?.name || ""; throw new errors_1.ObjectSchemaParseError(err.message, { objectName }); } throw err; } } exports.validateObjectSchema = validateObjectSchema; /** * Validate the data types of a user-provided property schema that ought to use the * relaxed object notation. */ function validatePropertySchema(objectName, propertyName, propertySchema) { try { assert_1.assert.object(propertySchema, `'${propertyName}' on '${objectName}'`, { allowArrays: false }); const { type, objectType, presentation, optional, property, indexed, mapTo } = propertySchema; assert_1.assert.string(type, `'${propertyName}.type' on '${objectName}'`); if (objectType !== undefined) { assert_1.assert.string(objectType, `'${propertyName}.objectType' on '${objectName}'`); } if (presentation !== undefined) { assert_1.assert.string(presentation, `'${propertyName}.presentation' on '${objectName}'`); } if (optional !== undefined) { assert_1.assert.boolean(optional, `'${propertyName}.optional' on '${objectName}'`); } if (property !== undefined) { assert_1.assert.string(property, `'${propertyName}.property' on '${objectName}'`); } if (indexed !== undefined) { (0, assert_1.assert)(typeof indexed === "boolean" || indexed === "full-text", `Expected '${propertyName}.indexed' on '${objectName}' to be a boolean or 'full-text'.`); } if (mapTo !== undefined) { assert_1.assert.string(mapTo, `'${propertyName}.mapTo' on '${objectName}'`); } const invalidKeysUsed = filterInvalidKeys(propertySchema, PROPERTY_SCHEMA_KEYS); (0, assert_1.assert)(!invalidKeysUsed.length, `Unexpected field(s) found on the schema for property '${propertyName}' on '${objectName}': '${invalidKeysUsed.join("', '")}'.`); } catch (err) { if (err instanceof Error) { throw new errors_1.PropertySchemaParseError(err.message, { objectName, propertyName }); } throw err; } } exports.validatePropertySchema = validatePropertySchema; /** * Get the keys of an object that are not part of the provided valid keys. */ function filterInvalidKeys(object, validKeys) { return Object.keys(object).filter((key) => !validKeys.has(key)); } //# sourceMappingURL=validate.js.map