@tanstack/db
Version:
A reactive client store for building super fast apps on sync
307 lines (306 loc) • 10.9 kB
JavaScript
;
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const dbIvm = require("@tanstack/db-ivm");
const routeMetadata = require("../compiler/route-metadata.cjs");
const errorMessage = require("../../error-message.cjs");
const publicKeyReduction = require("./public-key-reduction.cjs");
const BUCKET_FACADE_REF = /* @__PURE__ */ Symbol(`bucketFacadeRef`);
let nextBucketFacadeEdgeId = 0;
function materializeCompilation(compilation, getRootKey) {
if (!compilation.includes?.length) {
return { pipeline: compilation.pipeline, facades: void 0 };
}
const built = /* @__PURE__ */ new WeakMap();
const materialized = materializeRelation(
compilation,
getRootKey,
built,
`root`
);
return {
...materialized,
facades: dedupeFacades(materialized.facades)
};
}
function materializeRelation(compilation, getKey, built, scope) {
const cached = built.get(compilation)?.[scope];
if (cached) return cached;
let pipeline = publicKeyReduction.canonicalizeByPublicKey(
publicKeyReduction.exposeRouting(compilation.pipeline),
getKey,
scope,
compilation.valueIdentity
);
const facades = [];
for (const include of compilation.includes ?? []) {
const child = materializeRelation(
include.childCompilationResult,
void 0,
built,
`child`
);
facades.push(...child.facades);
const bucketRows = createBucketRows(
child.pipeline,
include.childCompilationResult.valueIdentity
);
if (include.materialization === `collection`) {
const edgeId = `bucket-facade-${++nextBucketFacadeEdgeId}`;
const activeBuckets = createActiveBuckets(
pipeline,
include,
compilation.valueIdentity
);
const activeBucketRows = activeBuckets.pipe(
dbIvm.join(bucketRows),
dbIvm.map(([bucketKey, [, row]]) => [bucketKey, row])
);
facades.push({
edgeId,
rows: activeBucketRows,
activeBuckets,
hasOrderBy: include.hasOrderBy,
resolve: child.resolve
});
pipeline = attachCollectionInclude(
pipeline,
include,
edgeId,
scope,
compilation.valueIdentity
);
} else {
pipeline = attachInlineInclude(
pipeline,
bucketRows,
include,
scope,
compilation.valueIdentity
);
}
}
const result = {
pipeline,
facades,
resolve: compileValueResolver(compilation.includes ?? [])
};
built.set(compilation, { ...built.get(compilation), [scope]: result });
return result;
}
function dedupeFacades(facades) {
return [...new Map(facades.map((facade) => [facade.edgeId, facade])).values()];
}
function attachInlineInclude(parentPipeline, bucketRows, include, scope, valueIdentity) {
const bucketValues = bucketRows.pipe(
dbIvm.reduce((values) => {
const rows = [];
for (const [row, multiplicity] of values) {
if (multiplicity < 0) {
throw new Error(
errorMessage.devBuild() && process.env.NODE_ENV !== `production` ? `Materialization bucket row has negative multiplicity` : errorMessage.codedMessage(157)
);
}
for (let index = 0; index < multiplicity; index++) rows.push(row);
}
if (rows.length === 0) return [];
rows.sort(compareBucketRows);
return [[{ value: materializeRows(rows, include) }, 1]];
})
);
const routedParents = parentPipeline.pipe(
dbIvm.map(([parentKey, rawTuple]) => {
const tuple = rawTuple;
const routing = getIncludeRoute(tuple, include.fieldName);
return [
routing?.active !== true ? `inactive:${dbIvm.serializeValue(parentKey)}` : publicKeyReduction.routeKey(
routing.correlationKey,
routing.parentContext,
valueIdentity
),
[parentKey, tuple]
];
}),
dbIvm.join(bucketValues, `left`),
dbIvm.map(([_bucketKey, [parent, bucketValue]]) => {
const [parentKey, tuple] = parent;
const [value, order, correlationKey, parentContext, routing, publicKey] = tuple;
const edgeRouting = routing?.[include.fieldName];
if (edgeRouting?.active !== true) {
return [
parentKey,
[value, order, correlationKey, parentContext, routing, publicKey]
];
}
const materialized = bucketValue === null ? emptyMaterializedValue(include.materialization) : bucketValue.value;
return [
parentKey,
[
setNestedValue(value, include.resultPath, materialized),
order,
correlationKey,
parentContext,
routing,
publicKey
]
];
})
);
return publicKeyReduction.canonicalizeByPublicKey(
routedParents,
void 0,
scope,
valueIdentity
);
}
function createBucketRows(childPipeline, valueIdentity) {
return childPipeline.pipe(
dbIvm.map(([internalKey, rawTuple]) => {
const [value, order, correlationKey, parentContext, , publicKey] = rawTuple;
return [
publicKeyReduction.routeKey(correlationKey, parentContext, valueIdentity),
[publicKey ?? internalKey, value, order]
];
})
);
}
function attachCollectionInclude(parentPipeline, include, edgeId, scope, valueIdentity) {
const routedParents = parentPipeline.pipe(
dbIvm.map(([parentKey, rawTuple]) => {
const tuple = rawTuple;
const routing = getIncludeRoute(tuple, include.fieldName);
if (routing?.active !== true) return [parentKey, tuple];
const facade = createBucketFacadeRef(
edgeId,
publicKeyReduction.routeKey(routing.correlationKey, routing.parentContext, valueIdentity)
);
return [
parentKey,
[
setNestedValue(tuple[0], include.resultPath, facade),
tuple[1],
tuple[2],
tuple[3],
tuple[4],
tuple[5]
]
];
})
);
return publicKeyReduction.canonicalizeByPublicKey(
routedParents,
void 0,
scope,
valueIdentity
);
}
function createActiveBuckets(parentPipeline, include, valueIdentity) {
return parentPipeline.pipe(
dbIvm.map(([parentKey, rawTuple]) => {
const tuple = rawTuple;
const routing = getIncludeRoute(tuple, include.fieldName);
const bucketKey = routing?.active === true ? publicKeyReduction.routeKey(
routing.correlationKey,
routing.parentContext,
valueIdentity
) : void 0;
return [parentKey, bucketKey];
}),
dbIvm.filter(([, bucketKey]) => bucketKey !== void 0),
dbIvm.distinct(([, bucketKey]) => bucketKey),
dbIvm.map(([, bucketKey]) => [bucketKey, true])
);
}
function createBucketFacadeRef(edgeId, bucketKey) {
return { [BUCKET_FACADE_REF]: { edgeId, bucketKey } };
}
function getIncludeRoute(tuple, fieldName) {
return tuple[4]?.[fieldName];
}
function compareBucketRows(left, right) {
const [leftPublicKey, , leftOrder] = left;
const [rightPublicKey, , rightOrder] = right;
if (leftOrder !== rightOrder) {
if (leftOrder === void 0) return 1;
if (rightOrder === void 0) return -1;
return leftOrder < rightOrder ? -1 : 1;
}
if ((typeof leftPublicKey === `string` || typeof leftPublicKey === `number`) && (typeof rightPublicKey === `string` || typeof rightPublicKey === `number`)) {
return dbIvm.compareKeys(leftPublicKey, rightPublicKey);
}
const leftKey = dbIvm.serializeValue(leftPublicKey);
const rightKey = dbIvm.serializeValue(rightPublicKey);
return leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0;
}
function materializeRows(rows, include) {
const scalarField = include.scalarField;
const values = scalarField ? rows.map(([, value]) => value[scalarField]) : rows.map(([, value]) => value);
if (include.materialization === `array`) return values;
if (include.materialization === `singleton`) return values[0];
return values.map((value) => String(value ?? ``)).join(``);
}
function emptyMaterializedValue(materialization) {
if (materialization === `array`) return [];
if (materialization === `concat`) return ``;
if (materialization === `singleton`) return void 0;
throw new Error(
errorMessage.devBuild() && process.env.NODE_ENV !== `production` ? `Collection includes require a bucket facade` : errorMessage.codedMessage(158)
);
}
function setNestedValue(source, path, value) {
const root = { ...source };
let target = root;
let current = source;
for (let index = 0; index < path.length - 1; index++) {
const part = path[index];
const currentChild = current?.[part];
const next = Array.isArray(currentChild) ? [...currentChild] : { ...currentChild ?? {} };
target[part] = next;
target = next;
current = currentChild;
}
target[path[path.length - 1]] = value;
return root;
}
function compileValueResolver(includes, scalarField) {
const fields = includes.flatMap((include) => {
if (scalarField !== void 0 && include.resultPath[0] !== scalarField)
return [];
const path = scalarField === void 0 ? include.resultPath : include.resultPath.slice(1);
const child = compileValueResolver(
include.childCompilationResult.includes ?? [],
include.scalarField
);
return [{ path, include, child }];
});
return (value, resolveFacade) => {
let result = routeMetadata.stripInternalCallbackMetadata(value);
for (const { path, include, child } of fields) {
result = replaceIncludePath(result, path, 0, (included) => {
if (include.materialization === `collection`)
return resolveFacade(included);
if (include.materialization === `concat`) return included;
if (include.materialization === `singleton`)
return child(included, resolveFacade);
if (!Array.isArray(included)) return included;
const values = included.map((row) => child(row, resolveFacade));
return values.some((row, index) => row !== included[index]) ? values : included;
});
}
return result;
};
}
function replaceIncludePath(value, path, index, replace) {
if (index === path.length) return replace(value);
if (value === null || typeof value !== `object`) return value;
const key = path[index];
const descriptor = Object.getOwnPropertyDescriptor(value, key);
if (!descriptor || !(`value` in descriptor)) return value;
const next = replaceIncludePath(descriptor.value, path, index + 1, replace);
if (Object.is(next, descriptor.value)) return value;
const descriptors = Object.getOwnPropertyDescriptors(value);
descriptors[key] = { ...descriptor, value: next };
return Object.defineProperties(routeMetadata.createPublicContainerShell(value), descriptors);
}
exports.BUCKET_FACADE_REF = BUCKET_FACADE_REF;
exports.materializeCompilation = materializeCompilation;
//# sourceMappingURL=materialized-pipeline.cjs.map