@aws-amplify/datastore
Version:
AppSyncLocal support for aws-amplify
146 lines (143 loc) • 6.37 kB
JavaScript
import { OpType, QueryOne } from '../../types.mjs';
import { getIndexKeys, traverseModel, keysEqual, getStorename, DEFAULT_PRIMARY_KEY_VALUE_SEPARATOR, validatePredicate, inMemoryPagination } from '../../util.mjs';
import AsyncStorageDatabase from './AsyncStorageDatabase.mjs';
import { StorageAdapterBase } from './StorageAdapterBase.mjs';
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
class AsyncStorageAdapter extends StorageAdapterBase {
async preSetUpChecks() {
// no-ops for AsyncStorageAdapter
}
async preOpCheck() {
// no-ops for AsyncStorageAdapter
}
/**
* Open AsyncStorage database
* Create new DB if one doesn't exist
*
* Called by `StorageAdapterBase.setUp()`
*
* @returns AsyncStorageDatabase instance
*/
async initDb() {
const db = new AsyncStorageDatabase();
await db.init();
return db;
}
async clear() {
await this.db.clear();
this.db = undefined;
this.initPromise = undefined;
}
async batchSave(modelConstructor, items) {
if (items.length === 0) {
return [];
}
const modelName = modelConstructor.name;
const namespaceName = this.namespaceResolver(modelConstructor);
const storeName = getStorename(namespaceName, modelName);
const keys = getIndexKeys(this.schema.namespaces[namespaceName], modelName);
const batch = [];
for (const item of items) {
const model = this.modelInstanceCreator(modelConstructor, item);
const connectedModels = traverseModel(modelName, model, this.schema.namespaces[namespaceName], this.modelInstanceCreator, this.getModelConstructorByModelName);
const keyValuesPath = this.getIndexKeyValuesPath(model);
const { instance } = connectedModels.find(({ instance: connectedModelInstance }) => {
const instanceKeyValuesPath = this.getIndexKeyValuesPath(connectedModelInstance);
return keysEqual([instanceKeyValuesPath], [keyValuesPath]);
});
batch.push(instance);
}
return this.db.batchSave(storeName, batch, keys);
}
async _get(storeName, keyArr) {
const itemKeyValuesPath = keyArr.join(DEFAULT_PRIMARY_KEY_VALUE_SEPARATOR);
return (await this.db.get(itemKeyValuesPath, storeName));
}
async save(model, condition) {
const { storeName, connectionStoreNames, modelKeyValues } = this.saveMetadata(model);
const fromDB = await this._get(storeName, modelKeyValues);
this.validateSaveCondition(condition, fromDB);
const result = [];
for await (const resItem of connectionStoreNames) {
const { storeName: storeNameForRestItem, item, instance, keys } = resItem;
const itemKeyValues = keys.map(key => item[key]);
const fromDBForRestItem = (await this._get(storeNameForRestItem, itemKeyValues));
const opType = fromDBForRestItem ? OpType.UPDATE : OpType.INSERT;
if (keysEqual(itemKeyValues, modelKeyValues) ||
opType === OpType.INSERT) {
await this.db.save(item, storeNameForRestItem, keys, itemKeyValues.join(DEFAULT_PRIMARY_KEY_VALUE_SEPARATOR));
result.push([instance, opType]);
}
}
return result;
}
async query(modelConstructor, predicate, pagination) {
const { storeName, namespaceName, queryByKey, predicates, hasSort, hasPagination, } = this.queryMetadata(modelConstructor, predicate, pagination);
const records = (await (async () => {
if (queryByKey) {
const keyValues = queryByKey.join(DEFAULT_PRIMARY_KEY_VALUE_SEPARATOR);
const record = await this.getByKey(storeName, keyValues);
return record ? [record] : [];
}
if (predicates) {
const filtered = await this.filterOnPredicate(storeName, predicates);
return this.inMemoryPagination(filtered, pagination);
}
if (hasSort || hasPagination) {
const all = await this.getAll(storeName);
return this.inMemoryPagination(all, pagination);
}
return this.getAll(storeName);
})());
return this.load(namespaceName, modelConstructor.name, records);
}
async getByKey(storeName, keyValuePath) {
return (await this.db.get(keyValuePath, storeName));
}
async getAll(storeName) {
return this.db.getAll(storeName);
}
async filterOnPredicate(storeName, predicates) {
const { predicates: predicateObjs, type } = predicates;
const all = (await this.getAll(storeName));
const filtered = predicateObjs
? all.filter(m => validatePredicate(m, type, predicateObjs))
: all;
return filtered;
}
inMemoryPagination(records, pagination) {
return inMemoryPagination(records, pagination);
}
async queryOne(modelConstructor, firstOrLast = QueryOne.FIRST) {
const storeName = this.getStorenameForModel(modelConstructor);
const result = (await this.db.getOne(firstOrLast, storeName));
return result && this.modelInstanceCreator(modelConstructor, result);
}
async deleteItem(deleteQueue) {
for await (const deleteItem of deleteQueue) {
const { storeName, items } = deleteItem;
for await (const item of items) {
if (item) {
if (typeof item === 'object') {
const keyValuesPath = this.getIndexKeyValuesPath(item);
await this.db.delete(keyValuesPath, storeName);
}
}
}
}
}
// #region platform-specific helper methods
/**
* Retrieves concatenated primary key values from a model
*
* @param model
* @returns
*/
getIndexKeyValuesPath(model) {
return this.getIndexKeyValuesFromModel(model).join(DEFAULT_PRIMARY_KEY_VALUE_SEPARATOR);
}
}
var AsyncStorageAdapter$1 = new AsyncStorageAdapter();
export { AsyncStorageAdapter, AsyncStorageAdapter$1 as default };
//# sourceMappingURL=AsyncStorageAdapter.mjs.map