@react-native-ohos/realm
Version:
Realm by MongoDB is an offline-first mobile database: an alternative to SQLite and key-value stores
245 lines • 11 kB
JavaScript
"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.List = 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 OrderedCollection_1 = require("./OrderedCollection");
const TypeHelpers_1 = require("./TypeHelpers");
/**
* Instances of this class will be returned when accessing object properties whose type is `"list"`.
*
* Lists mostly behave like normal Javascript Arrays, except for that they can
* only store values of a single type (indicated by the `type` and `optional`
* properties of the List), and can only be modified inside a {@link Realm.write | write} transaction.
*/
class List extends OrderedCollection_1.OrderedCollection {
/** @internal */
constructor(realm, internal, accessor, typeHelpers) {
if (arguments.length === 0 || !(internal instanceof binding_1.binding.List)) {
throw new errors_1.IllegalConstructorError("List");
}
const results = internal.asResults();
super(realm, results, accessor, typeHelpers);
// Getting the `objectSchema` off the internal will throw if base type isn't object
const isEmbedded = (0, TypeHelpers_1.toItemType)(results.type) === 7 /* binding.PropertyType.Object */ &&
internal.objectSchema.tableType === 1 /* binding.TableType.Embedded */;
Object.defineProperty(this, "internal", {
enumerable: false,
configurable: false,
writable: false,
value: internal,
});
Object.defineProperty(this, "isEmbedded", {
enumerable: false,
configurable: false,
writable: false,
value: isEmbedded,
});
}
/** @internal */
get(index) {
return this[Collection_1.COLLECTION_ACCESSOR].get(this.internal, index);
}
/** @internal */
set(index, value) {
this[Collection_1.COLLECTION_ACCESSOR].set(this.internal, index, value);
}
/**
* Checks if this collection has not been deleted and is part of a valid Realm.
* @returns `true` if the collection can be safely accessed.
*/
isValid() {
return this.internal.isValid;
}
/**
* @returns The number of values in the list.
*/
get length() {
return this.internal.size;
}
/**
* @throws An {@link Error} as the length property cannot be assigned.
*/
set length(value) {
throw new Error("Cannot assign to read only property 'length'");
}
/**
* Remove the **last** value from the list and return it.
* @throws an {@link AssertionError} If not inside a write transaction.
* @returns The last value or undefined if the list is empty.
*/
pop() {
assert_1.assert.inTransaction(this.realm);
const { internal } = this;
const lastIndex = internal.size - 1;
if (lastIndex >= 0) {
const result = this.get(lastIndex);
internal.remove(lastIndex);
return result;
}
}
/**
* Add one or more values to the _end_ of the list.
* @param items - Values to add to the list.
* @throws A {TypeError} if a value is not of a type which can be stored in
* the list, or if an object being added to the list does not match the {@link ObjectSchema} for the list.
* @throws An {@link AssertionError} if not inside a write transaction.
* @returns The new length of the list after adding the values.
*/
push(...items) {
assert_1.assert.inTransaction(this.realm);
const { internal } = this;
const start = internal.size;
for (const [offset, item] of items.entries()) {
const index = start + offset;
this[Collection_1.COLLECTION_ACCESSOR].insert(internal, index, item);
}
return internal.size;
}
/**
* Remove the **first** value from the list and return it.
* @throws An {@link AssertionError} if not inside a write transaction.
* @returns The first value or `undefined` if the list is empty.
*/
shift() {
assert_1.assert.inTransaction(this.realm);
const { internal } = this;
if (internal.size > 0) {
const result = this.get(0);
internal.remove(0);
return result;
}
}
/**
* Add one or more values to the _beginning_ of the list.
* @param items - Values to add to the list.
* @throws A {TypeError} if a value is not of a type which can be stored in
* the list, or if an object being added to the list does not match the {@link ObjectSchema} for the list.
* @throws An {@link AssertionError} if not inside a write transaction.
* @returns The new length of the list after adding the values.
*/
unshift(...items) {
assert_1.assert.inTransaction(this.realm);
const { internal } = this;
const { insert } = this[Collection_1.COLLECTION_ACCESSOR];
for (const [index, item] of items.entries()) {
insert(internal, index, item);
}
return internal.size;
}
/**
* Changes the contents of the list by removing value and/or inserting new value.
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice Array.prototype.splice}
* @param start - The start index. If greater than the length of the list,
* the start index will be set to the length instead. If negative, then the start index
* will be counted from the end of the list (e.g. `list.length - index`).
* @param deleteCount - The number of values to remove from the list.
* If not provided, then all values from the start index through the end of
* the list will be removed.
* @param items - Values to insert into the list starting at `index`.
* @returns An array containing the value that were removed from the list. The
* array is empty if no value were removed.
*/
splice(start, deleteCount, ...items) {
// Comments in the code below is copied from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
assert_1.assert.inTransaction(this.realm);
assert_1.assert.number(start, "start");
const { internal } = this;
// If negative, it will begin that many elements from the end of the array.
if (start < 0) {
start = internal.size + start;
}
// If greater than the length of the array, start will be set to the length of the array.
if (start > internal.size) {
start = internal.size;
}
// If deleteCount is omitted, or if its value is equal to or larger than array.length - start
// (that is, if it is equal to or greater than the number of elements left in the array, starting at start),
// then all the elements from start to the end of the array will be deleted.
const end = typeof deleteCount === "number" ? Math.min(start + deleteCount, internal.size) : internal.size;
// Get the elements that are about to be deleted
const result = [];
for (let i = start; i < end; i++) {
result.push(this.get(i));
}
// Remove the elements from the list (backwards to avoid skipping elements as they're being deleted)
for (let i = end - 1; i >= start; i--) {
internal.remove(i);
}
// Insert any new elements
const { insert } = this[Collection_1.COLLECTION_ACCESSOR];
for (const [offset, item] of items.entries()) {
const index = start + offset;
insert(internal, index, item);
}
return result;
}
/**
* Removes the element of the list at the specified index.
* @param index - The index of the element to remove.
* @throws An {@link AssertionError} if not inside a write transaction or the input index is less than 0
* or greater than or equal to the size of the list.
*/
remove(index) {
assert_1.assert.inTransaction(this.realm);
assert_1.assert.number(index, "index");
(0, assert_1.assert)(index >= 0, "Index cannot be smaller than 0");
(0, assert_1.assert)(index < this.internal.size, "Index cannot be greater than the size of the list");
this.internal.remove(index);
}
/**
* Moves one element of the list from one index to another.
* @param from - The index of the element to move.
* @param to - The destination index of the element.
* @throws An {@link AssertionError} if not inside a write transaction or if any of the input indexes
* is less than 0 or greater than or equal to the size of the list.
*/
move(from, to) {
assert_1.assert.inTransaction(this.realm);
assert_1.assert.number(from, "from");
assert_1.assert.number(to, "to");
const size = this.internal.size;
(0, assert_1.assert)(from >= 0 && to >= 0, "Indexes cannot be smaller than 0");
(0, assert_1.assert)(from < size && to < size, "Indexes cannot be greater than the size of the list");
this.internal.move(from, to);
}
/**
* Swaps the positions of the elements of the list at two indexes.
* @param index1 - The index of the first element.
* @param index2 - The index of the second element.
* @throws An {@link AssertionError} if not inside a write transaction or if any of the input indexes
* is less than 0 or greater than or equal to the size of the list.
*/
swap(index1, index2) {
assert_1.assert.inTransaction(this.realm);
assert_1.assert.number(index1, "index1");
assert_1.assert.number(index2, "index2");
const size = this.internal.size;
(0, assert_1.assert)(index1 >= 0 && index2 >= 0, "Indexes cannot be smaller than 0");
(0, assert_1.assert)(index1 < size && index2 < size, "Indexes cannot be greater than the size of the list");
this.internal.swap(index1, index2);
}
}
exports.List = List;
(0, indirect_1.injectIndirect)("List", List);
//# sourceMappingURL=List.js.map