rxdb
Version:
A local-first realtime NoSQL Database for JavaScript applications - https://rxdb.info/
823 lines (793 loc) • 28.6 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.RxCollectionBase = exports.OPEN_COLLECTIONS = void 0;
exports.createRxCollection = createRxCollection;
exports.isRxCollection = isRxCollection;
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _rxjs = require("rxjs");
var _index = require("./plugins/utils/index.js");
var _rxCollectionHelper = require("./rx-collection-helper.js");
var _rxQuery = require("./rx-query.js");
var _rxError = require("./rx-error.js");
var _docCache = require("./doc-cache.js");
var _queryCache = require("./query-cache.js");
var _changeEventBuffer = require("./change-event-buffer.js");
var _hooks = require("./hooks.js");
var _rxDocumentPrototypeMerge = require("./rx-document-prototype-merge.js");
var _rxStorageHelper = require("./rx-storage-helper.js");
var _incrementalWrite = require("./incremental-write.js");
var _rxDocument = require("./rx-document.js");
var _overwritable = require("./overwritable.js");
var _defaultConflictHandler = require("./replication-protocol/default-conflict-handler.js");
var _rxChangeEvent = require("./rx-change-event.js");
var HOOKS_WHEN = ['pre', 'post'];
var HOOKS_KEYS = ['insert', 'save', 'remove', 'create'];
var hooksApplied = false;
var OPEN_COLLECTIONS = exports.OPEN_COLLECTIONS = new Set();
var RxCollectionBase = exports.RxCollectionBase = /*#__PURE__*/function () {
/**
* Stores all 'normal' documents
*/
/**
* Before reads, all these methods are awaited. Used to "block" reads
* depending on other processes, like when the RxPipeline is running.
*/
function RxCollectionBase(database, name, schema, internalStorageInstance, instanceCreationOptions = {}, migrationStrategies = {}, methods = {}, attachments = {}, options = {}, cacheReplacementPolicy = _queryCache.defaultCacheReplacementPolicy, statics = {}, conflictHandler = _defaultConflictHandler.defaultConflictHandler) {
this.storageInstance = {};
this.timeouts = new Set();
this.incrementalWriteQueue = {};
this.awaitBeforeReads = new Set();
this._incrementalUpsertQueues = new Map();
this.synced = false;
this.hooks = {};
this._subs = [];
this._docCache = {};
this._queryCache = (0, _queryCache.createQueryCache)();
this.$ = {};
this.checkpoint$ = {};
this._changeEventBuffer = {};
this.eventBulks$ = {};
this.onClose = [];
this.closed = false;
this.onRemove = [];
this.database = database;
this.name = name;
this.schema = schema;
this.internalStorageInstance = internalStorageInstance;
this.instanceCreationOptions = instanceCreationOptions;
this.migrationStrategies = migrationStrategies;
this.methods = methods;
this.attachments = attachments;
this.options = options;
this.cacheReplacementPolicy = cacheReplacementPolicy;
this.statics = statics;
this.conflictHandler = conflictHandler;
_applyHookFunctions(this.asRxCollection);
if (database) {
// might be falsy on pseudoInstance
this.eventBulks$ = database.eventBulks$.pipe((0, _rxjs.filter)(changeEventBulk => changeEventBulk.collectionName === this.name));
} else {}
/**
* Must be last because the hooks might throw on dev-mode
* checks and we do not want to have broken collections here.
* RxCollection instances created for testings do not have a database
* so we do not add these to the list.
*/
if (this.database) {
OPEN_COLLECTIONS.add(this);
}
}
var _proto = RxCollectionBase.prototype;
_proto.prepare = async function prepare() {
if (!(await (0, _index.hasPremiumFlag)())) {
/**
* When used in a test suite, we often open and close many databases with collections
* while not awaiting the database.close() call to improve the test times.
* So when reopening collections and the OPEN_COLLECTIONS size is full,
* we retry after some times to account for this.
*/
var count = 0;
while (count < 10 && OPEN_COLLECTIONS.size > _index.NON_PREMIUM_COLLECTION_LIMIT) {
count++;
await this.promiseWait(30);
}
if (OPEN_COLLECTIONS.size > _index.NON_PREMIUM_COLLECTION_LIMIT) {
throw (0, _rxError.newRxError)('COL23', {
database: this.database.name,
collection: this.name,
args: {
existing: Array.from(OPEN_COLLECTIONS.values()).map(c => ({
db: c.database ? c.database.name : '',
c: c.name
}))
}
});
}
}
this.storageInstance = (0, _rxStorageHelper.getWrappedStorageInstance)(this.database, this.internalStorageInstance, this.schema.jsonSchema);
this.incrementalWriteQueue = new _incrementalWrite.IncrementalWriteQueue(this.storageInstance, this.schema.primaryPath, (newData, oldData) => (0, _rxDocument.beforeDocumentUpdateWrite)(this, newData, oldData), result => this._runHooks('post', 'save', result));
this.$ = this.eventBulks$.pipe((0, _rxjs.mergeMap)(changeEventBulk => (0, _rxChangeEvent.rxChangeEventBulkToRxChangeEvents)(changeEventBulk)));
this.checkpoint$ = this.eventBulks$.pipe((0, _rxjs.map)(changeEventBulk => changeEventBulk.checkpoint));
this._changeEventBuffer = (0, _changeEventBuffer.createChangeEventBuffer)(this.asRxCollection);
var documentConstructor;
this._docCache = new _docCache.DocumentCache(this.schema.primaryPath, this.eventBulks$.pipe((0, _rxjs.filter)(bulk => !bulk.isLocal), (0, _rxjs.map)(bulk => bulk.events)), docData => {
if (!documentConstructor) {
documentConstructor = (0, _rxDocumentPrototypeMerge.getRxDocumentConstructor)(this.asRxCollection);
}
return (0, _rxDocumentPrototypeMerge.createNewRxDocument)(this.asRxCollection, documentConstructor, docData);
});
var listenToRemoveSub = this.database.internalStore.changeStream().pipe((0, _rxjs.filter)(bulk => {
var key = this.name + '-' + this.schema.version;
var found = bulk.events.find(event => {
return event.documentData.context === 'collection' && event.documentData.key === key && event.operation === 'DELETE';
});
return !!found;
})).subscribe(async () => {
await this.close();
await Promise.all(this.onRemove.map(fn => fn()));
});
this._subs.push(listenToRemoveSub);
var databaseStorageToken = await this.database.storageToken;
var subDocs = this.storageInstance.changeStream().subscribe(eventBulk => {
var changeEventBulk = {
id: eventBulk.id,
isLocal: false,
internal: false,
collectionName: this.name,
storageToken: databaseStorageToken,
events: eventBulk.events,
databaseToken: this.database.token,
checkpoint: eventBulk.checkpoint,
context: eventBulk.context
};
this.database.$emit(changeEventBulk);
});
this._subs.push(subDocs);
return _index.PROMISE_RESOLVE_VOID;
}
/**
* Manually call the cleanup function of the storage.
* @link https://rxdb.info/cleanup.html
*/;
_proto.cleanup = function cleanup(_minimumDeletedTime) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
throw (0, _index.pluginMissing)('cleanup');
}
// overwritten by migration-plugin
;
_proto.migrationNeeded = function migrationNeeded() {
throw (0, _index.pluginMissing)('migration-schema');
};
_proto.getMigrationState = function getMigrationState() {
throw (0, _index.pluginMissing)('migration-schema');
};
_proto.startMigration = function startMigration(batchSize = 10) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
return this.getMigrationState().startMigration(batchSize);
};
_proto.migratePromise = function migratePromise(batchSize = 10) {
return this.getMigrationState().migratePromise(batchSize);
};
_proto.insert = async function insert(json) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
var writeResult = await this.bulkInsert([json]);
var isError = writeResult.error[0];
(0, _rxStorageHelper.throwIfIsStorageWriteError)(this, json[this.schema.primaryPath], json, isError);
var insertResult = (0, _index.ensureNotFalsy)(writeResult.success[0]);
return insertResult;
};
_proto.bulkInsert = async function bulkInsert(docsData) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
/**
* Optimization shortcut,
* do nothing when called with an empty array
*/
if (docsData.length === 0) {
return {
success: [],
error: []
};
}
var primaryPath = this.schema.primaryPath;
var ids = new Set();
/**
* This code is a bit redundant for better performance.
* Instead of iterating multiple times,
* we directly transform the input to a write-row array.
*/
var insertRows;
if (this.hasHooks('pre', 'insert')) {
insertRows = await Promise.all(docsData.map(docData => {
var useDocData = (0, _rxCollectionHelper.fillObjectDataBeforeInsert)(this.schema, docData);
return this._runHooks('pre', 'insert', useDocData).then(() => {
ids.add(useDocData[primaryPath]);
return {
document: useDocData
};
});
}));
} else {
insertRows = new Array(docsData.length);
var _schema = this.schema;
for (var index = 0; index < docsData.length; index++) {
var docData = docsData[index];
var useDocData = (0, _rxCollectionHelper.fillObjectDataBeforeInsert)(_schema, docData);
ids.add(useDocData[primaryPath]);
insertRows[index] = {
document: useDocData
};
}
}
if (ids.size !== docsData.length) {
throw (0, _rxError.newRxError)('COL22', {
collection: this.name,
args: {
documents: docsData
}
});
}
var results = await this.storageInstance.bulkWrite(insertRows, 'rx-collection-bulk-insert');
/**
* Often the user does not need to access the RxDocuments of the bulkInsert() call.
* So we transform the data to RxDocuments only if needed to use less CPU performance.
*/
var rxDocuments;
var collection = this;
var ret = {
get success() {
if (!rxDocuments) {
var success = (0, _rxStorageHelper.getWrittenDocumentsFromBulkWriteResponse)(collection.schema.primaryPath, insertRows, results);
rxDocuments = (0, _docCache.mapDocumentsDataToCacheDocs)(collection._docCache, success);
}
return rxDocuments;
},
error: results.error
};
if (this.hasHooks('post', 'insert')) {
var docsMap = new Map();
insertRows.forEach(row => {
var doc = row.document;
docsMap.set(doc[primaryPath], doc);
});
await Promise.all(ret.success.map(doc => {
return this._runHooks('post', 'insert', docsMap.get(doc.primary), doc);
}));
}
return ret;
};
_proto.bulkRemove = async function bulkRemove(
/**
* You can either remove the documents by their ids
* or by directly providing the RxDocument instances
* if you have them already. This improves performance a bit.
*/
idsOrDocs) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
var primaryPath = this.schema.primaryPath;
/**
* Optimization shortcut,
* do nothing when called with an empty array
*/
if (idsOrDocs.length === 0) {
return {
success: [],
error: []
};
}
var rxDocumentMap;
if (typeof idsOrDocs[0] === 'string') {
rxDocumentMap = await this.findByIds(idsOrDocs).exec();
} else {
rxDocumentMap = new Map();
idsOrDocs.forEach(d => rxDocumentMap.set(d.primary, d));
}
var docsData = [];
var docsMap = new Map();
Array.from(rxDocumentMap.values()).forEach(rxDocument => {
var data = rxDocument.toMutableJSON(true);
docsData.push(data);
docsMap.set(rxDocument.primary, data);
});
await Promise.all(docsData.map(doc => {
var primary = doc[this.schema.primaryPath];
return this._runHooks('pre', 'remove', doc, rxDocumentMap.get(primary));
}));
var removeDocs = docsData.map(doc => {
var writeDoc = (0, _index.flatClone)(doc);
writeDoc._deleted = true;
return {
previous: doc,
document: writeDoc
};
});
var results = await this.storageInstance.bulkWrite(removeDocs, 'rx-collection-bulk-remove');
var success = (0, _rxStorageHelper.getWrittenDocumentsFromBulkWriteResponse)(this.schema.primaryPath, removeDocs, results);
var deletedRxDocuments = [];
var successIds = success.map(d => {
var id = d[primaryPath];
var doc = this._docCache.getCachedRxDocument(d);
deletedRxDocuments.push(doc);
return id;
});
// run hooks
await Promise.all(successIds.map(id => {
return this._runHooks('post', 'remove', docsMap.get(id), rxDocumentMap.get(id));
}));
return {
success: deletedRxDocuments,
error: results.error
};
}
/**
* same as bulkInsert but overwrites existing document with same primary
*/;
_proto.bulkUpsert = async function bulkUpsert(docsData) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
var insertData = [];
var useJsonByDocId = new Map();
docsData.forEach(docData => {
var useJson = (0, _rxCollectionHelper.fillObjectDataBeforeInsert)(this.schema, docData);
var primary = useJson[this.schema.primaryPath];
if (!primary) {
throw (0, _rxError.newRxError)('COL3', {
primaryPath: this.schema.primaryPath,
data: useJson,
schema: this.schema.jsonSchema
});
}
useJsonByDocId.set(primary, useJson);
insertData.push(useJson);
});
var insertResult = await this.bulkInsert(insertData);
var success = insertResult.success.slice(0);
var error = [];
// update the ones that existed already
await Promise.all(insertResult.error.map(async err => {
if (err.status !== 409) {
error.push(err);
} else {
var id = err.documentId;
var writeData = (0, _index.getFromMapOrThrow)(useJsonByDocId, id);
var docDataInDb = (0, _index.ensureNotFalsy)(err.documentInDb);
var doc = this._docCache.getCachedRxDocuments([docDataInDb])[0];
var newDoc = await doc.incrementalModify(() => writeData);
success.push(newDoc);
}
}));
return {
error,
success
};
}
/**
* same as insert but overwrites existing document with same primary
*/;
_proto.upsert = async function upsert(json) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
var bulkResult = await this.bulkUpsert([json]);
(0, _rxStorageHelper.throwIfIsStorageWriteError)(this.asRxCollection, json[this.schema.primaryPath], json, bulkResult.error[0]);
return bulkResult.success[0];
}
/**
* upserts to a RxDocument, uses incrementalModify if document already exists
*/;
_proto.incrementalUpsert = function incrementalUpsert(json) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
var useJson = (0, _rxCollectionHelper.fillObjectDataBeforeInsert)(this.schema, json);
var primary = useJson[this.schema.primaryPath];
if (!primary) {
throw (0, _rxError.newRxError)('COL4', {
data: json
});
}
// ensure that it won't try 2 parallel runs
var queue = this._incrementalUpsertQueues.get(primary);
if (!queue) {
queue = _index.PROMISE_RESOLVE_VOID;
}
queue = queue.then(() => _incrementalUpsertEnsureRxDocumentExists(this, primary, useJson)).then(wasInserted => {
if (!wasInserted.inserted) {
return _incrementalUpsertUpdate(wasInserted.doc, useJson);
} else {
return wasInserted.doc;
}
});
this._incrementalUpsertQueues.set(primary, queue);
return queue;
};
_proto.find = function find(queryObj) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
(0, _hooks.runPluginHooks)('prePrepareRxQuery', {
op: 'find',
queryObj,
collection: this
});
if (!queryObj) {
queryObj = (0, _rxQuery._getDefaultQuery)();
}
var query = (0, _rxQuery.createRxQuery)('find', queryObj, this);
return query;
};
_proto.findOne = function findOne(queryObj) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
(0, _hooks.runPluginHooks)('prePrepareRxQuery', {
op: 'findOne',
queryObj,
collection: this
});
var query;
if (typeof queryObj === 'string') {
query = (0, _rxQuery.createRxQuery)('findOne', {
selector: {
[this.schema.primaryPath]: queryObj
},
limit: 1
}, this);
} else {
if (!queryObj) {
queryObj = (0, _rxQuery._getDefaultQuery)();
}
// cannot have limit on findOne queries because it will be overwritten
if (queryObj.limit) {
throw (0, _rxError.newRxError)('QU6');
}
queryObj = (0, _index.flatClone)(queryObj);
queryObj.limit = 1;
query = (0, _rxQuery.createRxQuery)('findOne', queryObj, this);
}
return query;
};
_proto.count = function count(queryObj) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
if (!queryObj) {
queryObj = (0, _rxQuery._getDefaultQuery)();
}
var query = (0, _rxQuery.createRxQuery)('count', queryObj, this);
return query;
}
/**
* find a list documents by their primary key
* has way better performance then running multiple findOne() or a find() with a complex $or-selected
*/;
_proto.findByIds = function findByIds(ids) {
(0, _rxCollectionHelper.ensureRxCollectionIsNotClosed)(this);
var mangoQuery = {
selector: {
[this.schema.primaryPath]: {
$in: ids.slice(0)
}
}
};
var query = (0, _rxQuery.createRxQuery)('findByIds', mangoQuery, this);
return query;
}
/**
* Export collection to a JSON friendly format.
*/;
_proto.exportJSON = function exportJSON() {
throw (0, _index.pluginMissing)('json-dump');
}
/**
* Import the parsed JSON export into the collection.
* @param _exportedJSON The previously exported data from the `<collection>.exportJSON()` method.
*/;
_proto.importJSON = function importJSON(_exportedJSON) {
throw (0, _index.pluginMissing)('json-dump');
};
_proto.insertCRDT = function insertCRDT(_updateObj) {
throw (0, _index.pluginMissing)('crdt');
};
_proto.addPipeline = function addPipeline(_options) {
throw (0, _index.pluginMissing)('pipeline');
}
/**
* HOOKS
*/;
_proto.addHook = function addHook(when, key, fun, parallel = false) {
if (typeof fun !== 'function') {
throw (0, _rxError.newRxTypeError)('COL7', {
key,
when
});
}
if (!HOOKS_WHEN.includes(when)) {
throw (0, _rxError.newRxTypeError)('COL8', {
key,
when
});
}
if (!HOOKS_KEYS.includes(key)) {
throw (0, _rxError.newRxError)('COL9', {
key
});
}
if (when === 'post' && key === 'create' && parallel === true) {
throw (0, _rxError.newRxError)('COL10', {
when,
key,
parallel
});
}
// bind this-scope to hook-function
var boundFun = fun.bind(this);
var runName = parallel ? 'parallel' : 'series';
this.hooks[key] = this.hooks[key] || {};
this.hooks[key][when] = this.hooks[key][when] || {
series: [],
parallel: []
};
this.hooks[key][when][runName].push(boundFun);
};
_proto.getHooks = function getHooks(when, key) {
if (!this.hooks[key] || !this.hooks[key][when]) {
return {
series: [],
parallel: []
};
}
return this.hooks[key][when];
};
_proto.hasHooks = function hasHooks(when, key) {
/**
* Performance shortcut
* so that we not have to build the empty object.
*/
if (!this.hooks[key] || !this.hooks[key][when]) {
return false;
}
var hooks = this.getHooks(when, key);
if (!hooks) {
return false;
}
return hooks.series.length > 0 || hooks.parallel.length > 0;
};
_proto._runHooks = function _runHooks(when, key, data, instance) {
var hooks = this.getHooks(when, key);
if (!hooks) {
return _index.PROMISE_RESOLVE_VOID;
}
// run parallel: false
var tasks = hooks.series.map(hook => () => hook(data, instance));
return (0, _index.promiseSeries)(tasks)
// run parallel: true
.then(() => Promise.all(hooks.parallel.map(hook => hook(data, instance))));
}
/**
* does the same as ._runHooks() but with non-async-functions
*/;
_proto._runHooksSync = function _runHooksSync(when, key, data, instance) {
if (!this.hasHooks(when, key)) {
return;
}
var hooks = this.getHooks(when, key);
if (!hooks) return;
hooks.series.forEach(hook => hook(data, instance));
}
/**
* Returns a promise that resolves after the given time.
* Ensures that is properly cleans up when the collection is closed
* so that no running timeouts prevent the exit of the JavaScript process.
*/;
_proto.promiseWait = function promiseWait(time) {
var ret = new Promise(res => {
var timeout = setTimeout(() => {
this.timeouts.delete(timeout);
res();
}, time);
this.timeouts.add(timeout);
});
return ret;
};
_proto.close = async function close() {
if (this.closed) {
return _index.PROMISE_RESOLVE_FALSE;
}
OPEN_COLLECTIONS.delete(this);
await Promise.all(this.onClose.map(fn => fn()));
/**
* Settings closed = true
* must be the first thing to do,
* so for example the replication can directly stop
* instead of sending requests to a closed storage.
*/
this.closed = true;
Array.from(this.timeouts).forEach(timeout => clearTimeout(timeout));
if (this._changeEventBuffer) {
this._changeEventBuffer.close();
}
/**
* First wait until the whole database is idle.
* This ensures that the storage does not get closed
* while some operation is running.
* It is important that we do not intercept a running call
* because it might lead to undefined behavior like when a doc is written
* but the change is not added to the changes collection.
*/
return this.database.requestIdlePromise().then(() => this.storageInstance.close()).then(() => {
/**
* Unsubscribing must be done AFTER the storageInstance.close()
* Because the conflict handling is part of the subscriptions and
* otherwise there might be open conflicts to be resolved which
* will then stuck and never resolve.
*/
this._subs.forEach(sub => sub.unsubscribe());
delete this.database.collections[this.name];
return (0, _hooks.runAsyncPluginHooks)('postCloseRxCollection', this).then(() => true);
});
}
/**
* remove all data of the collection
*/;
_proto.remove = async function remove() {
await this.close();
await Promise.all(this.onRemove.map(fn => fn()));
/**
* TODO here we should pass the already existing
* storage instances instead of creating new ones.
*/
await (0, _rxCollectionHelper.removeCollectionStorages)(this.database.storage, this.database.internalStore, this.database.token, this.database.name, this.name, this.database.multiInstance, this.database.password, this.database.hashFunction);
};
return (0, _createClass2.default)(RxCollectionBase, [{
key: "insert$",
get: function () {
return this.$.pipe((0, _rxjs.filter)(cE => cE.operation === 'INSERT'));
}
}, {
key: "update$",
get: function () {
return this.$.pipe((0, _rxjs.filter)(cE => cE.operation === 'UPDATE'));
}
}, {
key: "remove$",
get: function () {
return this.$.pipe((0, _rxjs.filter)(cE => cE.operation === 'DELETE'));
}
// defaults
/**
* Internally only use eventBulks$
* Do not use .$ or .observable$ because that has to transform
* the events which decreases performance.
*/
/**
* When the collection is closed,
* these functions will be called an awaited.
* Used to automatically clean up stuff that
* belongs to this collection.
*/
}, {
key: "asRxCollection",
get: function () {
return this;
}
}]);
}();
/**
* adds the hook-functions to the collections prototype
* this runs only once
*/
function _applyHookFunctions(collection) {
if (hooksApplied) return; // already run
hooksApplied = true;
var colProto = Object.getPrototypeOf(collection);
HOOKS_KEYS.forEach(key => {
HOOKS_WHEN.map(when => {
var fnName = when + (0, _index.ucfirst)(key);
colProto[fnName] = function (fun, parallel) {
return this.addHook(when, key, fun, parallel);
};
});
});
}
function _incrementalUpsertUpdate(doc, json) {
return doc.incrementalModify(_innerDoc => {
return json;
});
}
/**
* ensures that the given document exists
* @return promise that resolves with new doc and flag if inserted
*/
function _incrementalUpsertEnsureRxDocumentExists(rxCollection, primary, json) {
/**
* Optimisation shortcut,
* first try to find the document in the doc-cache
*/
var docDataFromCache = rxCollection._docCache.getLatestDocumentDataIfExists(primary);
if (docDataFromCache) {
return Promise.resolve({
doc: rxCollection._docCache.getCachedRxDocuments([docDataFromCache])[0],
inserted: false
});
}
return rxCollection.findOne(primary).exec().then(doc => {
if (!doc) {
return rxCollection.insert(json).then(newDoc => ({
doc: newDoc,
inserted: true
}));
} else {
return {
doc,
inserted: false
};
}
});
}
/**
* creates and prepares a new collection
*/
function createRxCollection({
database,
name,
schema,
instanceCreationOptions = {},
migrationStrategies = {},
autoMigrate = true,
statics = {},
methods = {},
attachments = {},
options = {},
localDocuments = false,
cacheReplacementPolicy = _queryCache.defaultCacheReplacementPolicy,
conflictHandler = _defaultConflictHandler.defaultConflictHandler
}) {
var storageInstanceCreationParams = {
databaseInstanceToken: database.token,
databaseName: database.name,
collectionName: name,
schema: schema.jsonSchema,
options: instanceCreationOptions,
multiInstance: database.multiInstance,
password: database.password,
devMode: _overwritable.overwritable.isDevMode()
};
(0, _hooks.runPluginHooks)('preCreateRxStorageInstance', storageInstanceCreationParams);
return (0, _rxCollectionHelper.createRxCollectionStorageInstance)(database, storageInstanceCreationParams).then(storageInstance => {
var collection = new RxCollectionBase(database, name, schema, storageInstance, instanceCreationOptions, migrationStrategies, methods, attachments, options, cacheReplacementPolicy, statics, conflictHandler);
return collection.prepare().then(() => {
// ORM add statics
Object.entries(statics).forEach(([funName, fun]) => {
Object.defineProperty(collection, funName, {
get: () => fun.bind(collection)
});
});
var ret = _index.PROMISE_RESOLVE_VOID;
if (autoMigrate && collection.schema.version !== 0) {
ret = collection.migratePromise();
}
return ret;
}).then(() => {
(0, _hooks.runPluginHooks)('createRxCollection', {
collection,
creator: {
name,
schema,
storageInstance,
instanceCreationOptions,
migrationStrategies,
methods,
attachments,
options,
cacheReplacementPolicy,
localDocuments,
statics
}
});
return collection;
})
/**
* If the collection creation fails,
* we yet have to close the storage instances.
*/.catch(err => {
OPEN_COLLECTIONS.delete(collection);
return storageInstance.close().then(() => Promise.reject(err));
});
});
}
function isRxCollection(obj) {
return obj instanceof RxCollectionBase;
}
//# sourceMappingURL=rx-collection.js.map