@tanstack/optimistic
Version:
Core optimistic updates library
92 lines (91 loc) • 2.81 kB
JavaScript
import { groupBy, map, groupByOperators } from "@electric-sql/d2ts";
import { extractValueFromNestedRow, evaluateOperandOnNestedRow } from "./extractors.js";
import { isAggregateFunctionCall } from "./utils.js";
const { sum, count, avg, min, max, median, mode } = groupByOperators;
function processGroupBy(pipeline, query, mainTableAlias) {
const groupByColumns = Array.isArray(query.groupBy) ? query.groupBy : [query.groupBy];
const keyExtractor = (nestedRow) => {
const key = {};
for (const column of groupByColumns) {
if (typeof column === `string` && column.startsWith(`@`)) {
const columnRef = column.substring(1);
const columnName = columnRef.includes(`.`) ? columnRef.split(`.`)[1] : columnRef;
key[columnName] = extractValueFromNestedRow(
nestedRow,
columnRef,
mainTableAlias
);
}
}
return key;
};
const aggregates = {};
for (const item of query.select) {
if (typeof item === `object`) {
for (const [alias, expr] of Object.entries(item)) {
if (typeof expr === `object` && isAggregateFunctionCall(expr)) {
const functionName = Object.keys(expr)[0];
const columnRef = expr[functionName];
aggregates[alias] = getAggregateFunction(
functionName,
columnRef,
mainTableAlias
);
}
}
}
}
if (Object.keys(aggregates).length > 0) {
pipeline = pipeline.pipe(
groupBy(keyExtractor, aggregates),
// Convert KeyValue<string, ResultType> to Record<string, unknown>
map(([_key, value]) => {
return value;
})
);
}
return pipeline;
}
function getAggregateFunction(functionName, columnRef, mainTableAlias) {
const valueExtractor = (nestedRow) => {
let value;
if (typeof columnRef === `string` && columnRef.startsWith(`@`)) {
value = extractValueFromNestedRow(
nestedRow,
columnRef.substring(1),
mainTableAlias
);
} else {
value = evaluateOperandOnNestedRow(
nestedRow,
columnRef,
mainTableAlias
);
}
return typeof value === `number` ? value : 0;
};
switch (functionName.toUpperCase()) {
case `SUM`:
return sum(valueExtractor);
case `COUNT`:
return count();
// count() doesn't need a value extractor
case `AVG`:
return avg(valueExtractor);
case `MIN`:
return min(valueExtractor);
case `MAX`:
return max(valueExtractor);
case `MEDIAN`:
return median(valueExtractor);
case `MODE`:
return mode(valueExtractor);
default:
throw new Error(`Unsupported aggregate function: ${functionName}`);
}
}
export {
getAggregateFunction,
processGroupBy
};
//# sourceMappingURL=group-by.js.map