@tanstack/db
Version:
A reactive client store for building super fast apps on sync
117 lines (116 loc) • 4.45 kB
JavaScript
;
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const dbIvm = require("@tanstack/db-ivm");
const errors = require("../../errors.cjs");
const expressions = require("../compiler/expressions.cjs");
const index = require("../builder/index.cjs");
const ir = require("../ir.cjs");
const queryIr = require("../builder/query-ir.cjs");
function extractCollectionsFromQuery(query) {
const collections = {};
for (const source of ir.collectCollectionSources(query)) {
collections[source.collection.id] = source.collection;
}
return collections;
}
function extractCollectionFromSource(query) {
const from = query.from;
if (from.type === `collectionRef`) {
return from.collection;
} else if (from.type === `queryRef`) {
return extractCollectionFromSource(from.query);
} else if (from.type === `unionFrom`) {
return extractCollectionFromSource({ from: from.sources[0] });
} else if (from.type === `unionAll`) {
return extractCollectionFromSource(from.queries[0]);
}
throw new Error(
`Failed to extract collection. Invalid FROM clause: ${JSON.stringify(query)}`
);
}
function isNestedSelectObject(obj) {
if (obj === null || typeof obj !== `object`) return false;
if (ir.isExpressionLike(obj)) return false;
if (obj.__refProxy) return false;
return true;
}
function buildQueryFromConfig(config) {
const query = typeof config.query === `function` ? index.buildQuery(config.query) : queryIr.getQueryIR(config.query);
if (config.requireObjectResult && query.select && !isNestedSelectObject(query.select)) {
throw new errors.UnsupportedRootScalarSelectError();
}
return query;
}
function sendChangesToInput(input, changes) {
const multiSetArray = [];
for (const change of changes) {
const key = change.key;
if (change.type === `insert`) {
multiSetArray.push([[key, change.value], 1]);
} else if (change.type === `update`) {
multiSetArray.push([[key, change.previousValue], -1]);
multiSetArray.push([[key, change.value], 1]);
} else {
multiSetArray.push([[key, change.value], -1]);
}
}
if (multiSetArray.length !== 0) {
input.sendData(new dbIvm.MultiSet(multiSetArray));
}
return multiSetArray.length;
}
function* splitUpdates(changes) {
for (const change of changes) {
if (change.type === `update`) {
yield { type: `delete`, key: change.key, value: change.previousValue };
yield { type: `insert`, key: change.key, value: change.value };
} else {
yield change;
}
}
}
function reconcileChangesForD2(changes, sentRows) {
const reconciled = [];
for (const change of changes) {
const previousValue = sentRows.get(change.key);
if (change.type === `insert`) {
if (previousValue !== void 0) continue;
sentRows.set(change.key, change.value);
reconciled.push(change);
} else if (change.type === `delete`) {
if (previousValue === void 0) continue;
sentRows.delete(change.key);
reconciled.push({ ...change, value: previousValue });
} else {
sentRows.set(change.key, change.value);
reconciled.push(
previousValue === void 0 ? { type: `insert`, key: change.key, value: change.value } : { ...change, previousValue }
);
}
}
return reconciled;
}
function computeSubscriptionOrderByHints(query, alias) {
const { orderBy, limit, offset } = query;
const effectiveLimit = limit !== void 0 && offset !== void 0 ? limit + offset : limit;
const normalizedOrderBy = orderBy ? expressions.normalizeOrderByPaths(orderBy, alias) : void 0;
const canPassOrderBy = normalizedOrderBy?.every((clause) => {
const exp = clause.expression;
if (exp.type !== `ref`) return false;
const path = exp.path;
return Array.isArray(path) && path.length === 1;
}) ?? false;
return {
orderBy: canPassOrderBy ? normalizedOrderBy : void 0,
limit: canPassOrderBy ? effectiveLimit : void 0
};
}
exports.extractCollectionSources = ir.collectCollectionSources;
exports.buildQueryFromConfig = buildQueryFromConfig;
exports.computeSubscriptionOrderByHints = computeSubscriptionOrderByHints;
exports.extractCollectionFromSource = extractCollectionFromSource;
exports.extractCollectionsFromQuery = extractCollectionsFromQuery;
exports.reconcileChangesForD2 = reconcileChangesForD2;
exports.sendChangesToInput = sendChangesToInput;
exports.splitUpdates = splitUpdates;
//# sourceMappingURL=utils.cjs.map