UNPKG

@react-native-ohos/realm

Version:

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

255 lines 11 kB
"use strict"; //////////////////////////////////////////////////////////////////////////// // // Copyright 2022 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.Dictionary = void 0; const assert_1 = require("./assert"); const binding_1 = require("./binding"); const indirect_1 = require("./indirect"); const Collection_1 = require("./Collection"); const errors_1 = require("./errors"); const JSONCacheMap_1 = require("./JSONCacheMap"); const TypeHelpers_1 = require("./TypeHelpers"); const Object_1 = require("./Object"); const Results_1 = require("./collection-accessors/Results"); /* eslint-disable jsdoc/multiline-blocks -- We need this to have @ts-expect-error located correctly in the .d.ts bundle */ const REALM = Symbol("Dictionary#realm"); const INTERNAL = Symbol("Dictionary#internal"); const DEFAULT_PROPERTY_DESCRIPTOR = { configurable: true, enumerable: true }; const PROXY_HANDLER = { get(target, prop, receiver) { const value = Reflect.get(target, prop, receiver); if (typeof value === "undefined" && typeof prop === "string") { return target[Collection_1.COLLECTION_ACCESSOR].get(target[INTERNAL], prop); } else { return value; } }, set(target, prop, value) { if (typeof prop === "string") { target[Collection_1.COLLECTION_ACCESSOR].set(target[INTERNAL], prop, value); return true; } else { (0, assert_1.assert)(typeof prop !== "symbol", "Symbols cannot be used as keys of a dictionary"); return false; } }, deleteProperty(target, prop) { // We're intentionally not checking !Reflect.has(target, prop) below to allow deletes to propagate for any key if (typeof prop === "string") { const internal = target[INTERNAL]; internal.tryErase(prop); // We consider any key without a value as "deletable", the same way `const foo = {}; delete foo.bar;` returns true return true; } else { return false; } }, ownKeys(target) { const internal = target[INTERNAL]; const result = Reflect.ownKeys(target); const keys = internal.keys.snapshot(); for (let i = 0; i < keys.size(); i++) { const key = keys.getAny(i); assert_1.assert.string(key, "dictionary key"); result.push(key); } return result; }, getOwnPropertyDescriptor(target, prop) { const internal = target[INTERNAL]; if (typeof prop === "string" && internal.contains(prop)) { return { ...DEFAULT_PROPERTY_DESCRIPTOR, get: PROXY_HANDLER.get?.bind(null, target, prop, null), set: PROXY_HANDLER.set?.bind(null, target, prop, null), }; } else { return Reflect.getOwnPropertyDescriptor(target, prop); } }, }; /** * Instances of this class are returned when accessing object properties whose type is `"Dictionary"` * * Dictionaries behave mostly like a JavaScript object i.e., as a key/value pair * where the key is a string. */ class Dictionary extends Collection_1.Collection { /** * The representation in the binding. * @internal */ [INTERNAL]; /** * Create a `Results` wrapping a set of query `Results` from the binding. * @internal */ constructor(realm, internal, accessor, typeHelpers) { if (arguments.length === 0 || !(internal instanceof binding_1.binding.Dictionary)) { throw new errors_1.IllegalConstructorError("Dictionary"); } super(accessor, typeHelpers, (listener, keyPaths) => { return this[INTERNAL].addKeyBasedNotificationCallback(({ deletions, insertions, modifications }) => { try { listener(proxied, { deletions: deletions.map((value) => { assert_1.assert.string(value); return value; }), insertions: insertions.map((value) => { assert_1.assert.string(value); return value; }), modifications: modifications.map((value) => { assert_1.assert.string(value); return value; }), }); } catch (err) { // Scheduling a throw on the event loop, // since throwing synchronously here would result in an abort in the calling C++ setImmediate(() => { throw err; }); } }, keyPaths ? realm.internal.createKeyPathArray(internal.objectSchema.name, keyPaths) : keyPaths); }); const proxied = new Proxy(this, PROXY_HANDLER); Object.defineProperty(this, REALM, { enumerable: false, configurable: false, writable: false, value: realm, }); this[INTERNAL] = internal; return proxied; } /** * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries Array.prototype.entries} * @returns An iterator with all entries in the dictionary. */ *[Symbol.iterator]() { yield* this.entries(); } /** * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys Array.prototype.keys} * @returns An iterator with all values in the dictionary. * @since 10.5.0 * @ts-expect-error We're exposing methods in the end-users namespace of keys */ *keys() { const snapshot = this[INTERNAL].keys.snapshot(); const size = snapshot.size(); for (let i = 0; i < size; i++) { const key = snapshot.getAny(i); assert_1.assert.string(key); yield key; } } /** * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values Array.prototype.values} * @returns An iterator with all values in the dictionary. * @since 10.5.0 * @ts-expect-error We're exposing methods in the end-users namespace of values */ *values() { const realm = this[REALM]; const values = this[INTERNAL].values; const itemType = (0, TypeHelpers_1.toItemType)(values.type); const typeHelpers = this[Collection_1.COLLECTION_TYPE_HELPERS]; const accessor = (0, Results_1.createResultsAccessor)({ realm, typeHelpers, itemType }); const results = new indirect_1.indirect.Results(realm, values, accessor, typeHelpers); for (const value of results.values()) { yield value; } } /** * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries Array.prototype.entries} * @returns An iterator with all key/value pairs in the dictionary. * @since 10.5.0 * @ts-expect-error We're exposing methods in the end-users namespace of entries */ *entries() { const keys = this[INTERNAL].keys.snapshot(); const snapshot = this[INTERNAL].values.snapshot(); const size = keys.size(); (0, assert_1.assert)(size === snapshot.size(), "Expected keys and values to equal in size"); const realm = this[REALM]; const itemType = (0, TypeHelpers_1.toItemType)(snapshot.type); const typeHelpers = this[Collection_1.COLLECTION_TYPE_HELPERS]; const accessor = (0, Results_1.createResultsAccessor)({ realm, typeHelpers, itemType }); const results = new indirect_1.indirect.Results(realm, snapshot, accessor, typeHelpers); for (let i = 0; i < size; i++) { const key = keys.getAny(i); const value = results[i]; yield [key, value]; } } /** * Checks if this dictionary has not been deleted and is part of a valid Realm. * @returns `true` if the dictionary can be safely accessed. * @since 0.14.0 * @ts-expect-error We're exposing methods in the end-users namespace of keys */ isValid() { return this[INTERNAL].isValid; } /** * Adds one or more elements with the specified key and value to the dictionary or updates value if key exists. * @param elementsOrKey - The element to add or the key of the element to add. * @param value - The value of the element to add. * @throws An {@link AssertionError} if not inside a write transaction, if using symbol as keys, or if any value violates type constraints. * @returns The dictionary. * @since 10.6.0 */ set(elementsOrKey, value) { assert_1.assert.inTransaction(this[REALM]); const elements = typeof elementsOrKey === "object" ? elementsOrKey : { [elementsOrKey]: value }; (0, assert_1.assert)(Object.getOwnPropertySymbols(elements).length === 0, "Symbols cannot be used as keys of a dictionary"); for (const [key, value] of Object.entries(elements)) { this[key] = value; } return this; } /** * Removes elements from the dictionary, with the keys provided. * This does not throw if the keys are already missing from the dictionary. * @param key - The key to be removed. * @throws An {@link AssertionError} if not inside a write transaction. * @returns The dictionary * @since 10.6.0 * @ts-expect-error We're exposing methods in the end-users namespace of keys */ remove(key) { assert_1.assert.inTransaction(this[REALM]); const internal = this[INTERNAL]; const keys = typeof key === "string" ? [key] : key; for (const k of keys) { internal.tryErase(k); } return this; } /** @internal */ toJSON(_, cache = new JSONCacheMap_1.JSONCacheMap()) { return Object.fromEntries(Object.entries(this).map(([k, v]) => [k, v instanceof Object_1.RealmObject ? v.toJSON(k, cache) : v])); } } exports.Dictionary = Dictionary; (0, indirect_1.injectIndirect)("Dictionary", Dictionary); //# sourceMappingURL=Dictionary.js.map