@tanstack/db
Version:
A reactive client store for building super fast apps on sync
260 lines (259 loc) • 7.45 kB
JavaScript
import { isRefProxy } from "./builder/ref-proxy-identity.js";
const INCLUDES_SCALAR_FIELD = `__includes_scalar__`;
let nextCollectionSourceId = 0;
class BaseExpression {
}
class CollectionRef extends BaseExpression {
constructor(collection, alias) {
super();
this.collection = collection;
this.alias = alias;
this.type = `collectionRef`;
Object.defineProperty(this, `sourceId`, {
value: `source-${++nextCollectionSourceId}`,
enumerable: false
});
}
}
class QueryRef extends BaseExpression {
constructor(query, alias) {
super();
this.query = query;
this.alias = alias;
this.type = `queryRef`;
}
}
class UnionFrom extends BaseExpression {
constructor(sources) {
super();
this.sources = sources;
this.type = `unionFrom`;
}
get alias() {
return this.sources[0]?.alias ?? ``;
}
}
class UnionAll extends BaseExpression {
/**
* Result-level UNION ALL. Downstream query clauses see the union result row
* shape, not the branch source aliases. Optimizers may push safe operations
* into branches, but compiler phases should treat this as a derived relation
* unless they are explicitly handling branch lowering.
*/
constructor(queries) {
super();
this.queries = queries;
this.type = `unionAll`;
}
get alias() {
return ``;
}
}
class PropRef extends BaseExpression {
constructor(path, sourceAlias) {
super();
this.path = path;
this.type = `ref`;
if (sourceAlias !== void 0) {
Object.defineProperty(this, `sourceAlias`, {
value: sourceAlias,
enumerable: true
});
}
}
}
function getPropRefSourceAlias(ref) {
return ref.sourceAlias !== void 0 && ref.path[0] === ref.sourceAlias ? ref.sourceAlias : void 0;
}
function getPropRefPropertyPath(ref) {
return getPropRefSourceAlias(ref) === void 0 ? ref.path : ref.path.slice(1);
}
class Value extends BaseExpression {
constructor(value) {
super();
this.value = value;
this.type = `val`;
}
}
class Func extends BaseExpression {
constructor(name, args) {
super();
this.name = name;
this.args = args;
this.type = `func`;
}
}
class Aggregate extends BaseExpression {
constructor(name, args) {
super();
this.name = name;
this.args = args;
this.type = `agg`;
}
}
class IncludesSubquery extends BaseExpression {
constructor(query, correlationField, childCorrelationField, fieldName, parentFilters, parentProjection, materialization = `collection`, scalarField) {
super();
this.query = query;
this.correlationField = correlationField;
this.childCorrelationField = childCorrelationField;
this.fieldName = fieldName;
this.parentFilters = parentFilters;
this.parentProjection = parentProjection;
this.materialization = materialization;
this.scalarField = scalarField;
this.type = `includesSubquery`;
}
}
class ConditionalSelect extends BaseExpression {
constructor(branches, defaultValue) {
super();
this.branches = branches;
this.defaultValue = defaultValue;
this.type = `conditionalSelect`;
}
}
function isBasicOrAggregateExpression(value) {
return value instanceof Aggregate || value instanceof Func || value instanceof PropRef || value instanceof Value;
}
function isExpressionLike(value) {
return isBasicOrAggregateExpression(value) || value instanceof ConditionalSelect || value instanceof IncludesSubquery;
}
function collectCollectionSources(query) {
const sources = [];
const seen = /* @__PURE__ */ new Set();
const visitSource = (source) => {
if (source.type === `collectionRef`) {
if (!seen.has(source.sourceId)) {
seen.add(source.sourceId);
sources.push(source);
}
} else if (source.type === `queryRef`) {
visitQuery(source.query);
} else if (source.type === `unionFrom`) {
source.sources.forEach(visitSource);
} else {
source.queries.forEach(visitQuery);
}
};
const visitSelectValue = (value) => {
if (value instanceof IncludesSubquery) {
visitQuery(value.query);
} else if (value instanceof ConditionalSelect) {
value.branches.forEach((branch) => visitSelectValue(branch.value));
if (value.defaultValue !== void 0) {
visitSelectValue(value.defaultValue);
}
} else if (value !== null && typeof value === `object` && !Array.isArray(value) && !isExpressionLike(value) && !isRefProxy(value)) {
Object.values(value).forEach(visitSelectValue);
}
};
const visitQuery = (current) => {
visitSource(current.from);
current.join?.forEach(({ from }) => visitSource(from));
if (current.select) Object.values(current.select).forEach(visitSelectValue);
};
visitQuery(query);
return sources;
}
function getWhereExpression(where) {
return typeof where === `object` && `expression` in where ? where.expression : where;
}
function getHavingExpression(having) {
return typeof having === `object` && `expression` in having ? having.expression : having;
}
function isResidualWhere(where) {
return typeof where === `object` && `expression` in where && where.residual === true;
}
function createResidualWhere(expression) {
return { expression, residual: true };
}
function getFromSources(from) {
if (from.type === `unionFrom`) return from.sources;
if (from.type === `unionAll`) return [];
return [from];
}
function getRefFromAlias(query, alias) {
for (const source of getFromSources(query.from)) {
if (source.alias === alias) {
return source;
}
}
for (const join of query.join || []) {
if (join.from.alias === alias) {
return join.from;
}
}
}
function followRef(query, ref, collection) {
const explicitAlias = getPropRefSourceAlias(ref);
if (explicitAlias !== void 0) {
const aliasRef = getRefFromAlias(query, explicitAlias);
if (!aliasRef) return;
const propertyPath = getPropRefPropertyPath(ref);
if (aliasRef.type === `queryRef`) {
return followRef(aliasRef.query, new PropRef(propertyPath), collection);
}
return {
collection: aliasRef.collection,
path: propertyPath,
alias: explicitAlias,
sourceId: aliasRef.sourceId
};
}
if (ref.path.length === 0) {
return;
}
if (ref.path.length === 1) {
const field = ref.path[0];
if (query.select) {
const selectedField = query.select[field];
if (selectedField && selectedField.type === `ref`) {
return followRef(query, selectedField, collection);
}
}
return { collection, path: [field] };
}
if (ref.path.length > 1) {
const [alias, ...rest] = ref.path;
const aliasRef = getRefFromAlias(query, alias);
if (!aliasRef) {
return;
}
if (aliasRef.type === `queryRef`) {
return followRef(aliasRef.query, new PropRef(rest), collection);
} else {
return {
collection: aliasRef.collection,
path: rest,
alias,
sourceId: aliasRef.sourceId
};
}
}
}
export {
Aggregate,
CollectionRef,
ConditionalSelect,
Func,
INCLUDES_SCALAR_FIELD,
IncludesSubquery,
PropRef,
QueryRef,
UnionAll,
UnionFrom,
Value,
collectCollectionSources,
createResidualWhere,
followRef,
getFromSources,
getHavingExpression,
getPropRefPropertyPath,
getPropRefSourceAlias,
getWhereExpression,
isBasicOrAggregateExpression,
isExpressionLike,
isResidualWhere
};
//# sourceMappingURL=ir.js.map