@magnetarjs/core
Version:
Magnetar core library.
132 lines (131 loc) • 5.51 kB
JavaScript
import { MODULE_IDENTIFIER_SPLIT, getPathFilterIdentifier, getPathWhereOrderByIdentifier, } from '@magnetarjs/types';
import { mapGetOrSet } from 'getorset-anything';
import { isString } from 'is-what';
import { createCollectionWithContext } from './Collection.js';
import { createDocWithContext } from './Doc.js';
import { defaultsGlobalConfig } from './helpers/configHelpers.js';
import { getCollectionPathDocIdEntry } from './helpers/pathHelpers.js';
import { throwIfInvalidModulePath } from './helpers/throwFns.js';
/**
* Creates a magnetar instance.
* @see {@link GlobalConfig}
* @see {@link MagnetarInstance}
*/
export function Magnetar(magnetarConfig) {
/**
* the passed GlobalConfig is merged onto defaults
*/
const globalConfig = defaultsGlobalConfig(magnetarConfig);
/**
* All collections visited so far, kept to be able to clear all data
*/
const collectionNames = new Set();
/**
* the global storage for WriteLock objects
* @see {@link WriteLock}
*/
const writeLockMap = new Map(); // apply type upon get/set
/**
* the global storage for closeStream functions
*/
const closeStreamFnMap = new Map(); // apply type upon get/set
/**
* the global storage for open stream promises
*/
const streamingPromiseMap = new Map(); // apply type upon get/set
/**
* the global storage for fetch promises
*/
const fetchPromiseMap = new Map(); // apply type upon get/set
/**
* the global storage for FetchMetaDataCollection
*/
const fetchMetaMap = new Map(); // apply type upon get/set
async function clearAllData(options) {
for (const collectionName of collectionNames) {
if (options?.exclude?.includes(collectionName))
continue;
collection(collectionName).data?.clear();
}
}
/** _ to prevent name clash */
async function _closeAllStreams(options) {
for (const collectionName of collectionNames) {
if (options?.exclude?.includes(collectionName))
continue;
collection(collectionName).closeAllStreams();
}
}
function getModuleInstance(modulePath, moduleConfig = {}, moduleType, docFn, collectionFn) {
throwIfInvalidModulePath(modulePath, moduleType);
const [collectionPath, docId] = getCollectionPathDocIdEntry(modulePath);
collectionNames.add(collectionPath);
const pathFilterIdentifier = getPathFilterIdentifier(modulePath, moduleConfig);
// grab (and set) the FetchPromises for this module
const fetchPromises = mapGetOrSet(fetchPromiseMap, pathFilterIdentifier, () => ({
fetch: new Map(),
fetchCount: new Map(),
fetchSum: new Map(),
fetchAverage: new Map(),
}));
// Create the FetchMeta helpers for this module
const pathWhereOrderByIdentifier = getPathWhereOrderByIdentifier(modulePath, moduleConfig);
const fetchMeta = {
get: () => fetchMetaMap.get(pathWhereOrderByIdentifier) || { reachedEnd: false, cursor: undefined },
set: (payload) => fetchMetaMap.set(pathWhereOrderByIdentifier, payload),
};
// grab the stream related functions
function cacheStream(closeStreamFn, streamingPromise) {
closeStreamFnMap.set(pathFilterIdentifier, closeStreamFn);
streamingPromiseMap.set(pathFilterIdentifier, streamingPromise);
}
function streaming() {
return streamingPromiseMap.get(pathFilterIdentifier) || null;
}
function closeStream() {
const closeStreamFn = closeStreamFnMap.get(pathFilterIdentifier);
if (closeStreamFn) {
closeStreamFn();
setTimeout(() => {
streamingPromiseMap.delete(pathFilterIdentifier);
closeStreamFnMap.delete(pathFilterIdentifier);
});
}
}
function closeAllStreams() {
for (const [identifier, closeStreamFn] of closeStreamFnMap) {
const openStreamPath = identifier.split(MODULE_IDENTIFIER_SPLIT)[0];
if (openStreamPath === modulePath || openStreamPath?.startsWith(modulePath + '/')) {
closeStreamFn();
}
}
}
const streamAndFetchPromises = {
writeLockMap,
fetchPromises,
cacheStream,
streaming,
closeStream,
closeAllStreams,
};
// then create the module instance
if (moduleType === 'doc' && isString(docId)) {
return createDocWithContext([collectionPath, docId], moduleConfig, globalConfig, docFn, collectionFn, streamAndFetchPromises);
}
return createCollectionWithContext(collectionPath, moduleConfig, globalConfig, docFn, collectionFn, streamAndFetchPromises, fetchMeta);
}
function collection(modulePath, moduleConfig = {}) {
return getModuleInstance(modulePath, moduleConfig, 'collection', doc, collection); // prettier-ignore
}
function doc(modulePath, moduleConfig = {}) {
return getModuleInstance(modulePath, moduleConfig, 'doc', doc, collection); // prettier-ignore
}
const instance = {
globalConfig,
collection: collection,
doc: doc,
clearAllData,
closeAllStreams: _closeAllStreams,
};
return instance;
}