@tanstack/optimistic
Version:
Core optimistic updates library
217 lines (216 loc) • 6.38 kB
JavaScript
import { orderByWithIndex, map, topKWithIndex, orderByWithFractionalIndex, topKWithFractionalIndex, orderBy, topK } from "@electric-sql/d2ts";
import { evaluateOperandOnNestedRow } from "./extractors.js";
import { isOrderIndexFunctionCall } from "./utils.js";
function processOrderBy(resultPipeline, query, mainTableAlias) {
let hasOrderIndexColumn = false;
let orderIndexType = `numeric`;
let orderIndexAlias = ``;
for (const item of query.select) {
if (typeof item === `object`) {
for (const [alias, expr] of Object.entries(item)) {
if (typeof expr === `object` && isOrderIndexFunctionCall(expr)) {
hasOrderIndexColumn = true;
orderIndexAlias = alias;
orderIndexType = getOrderIndexType(expr);
break;
}
}
}
if (hasOrderIndexColumn) break;
}
const orderByItems = [];
if (typeof query.orderBy === `string`) {
orderByItems.push({
operand: query.orderBy,
direction: `asc`
});
} else if (Array.isArray(query.orderBy)) {
for (const item of query.orderBy) {
if (typeof item === `string`) {
orderByItems.push({
operand: item,
direction: `asc`
});
} else if (typeof item === `object`) {
for (const [column, direction] of Object.entries(item)) {
orderByItems.push({
operand: column,
direction
});
}
}
}
} else if (typeof query.orderBy === `object`) {
for (const [column, direction] of Object.entries(query.orderBy)) {
orderByItems.push({
operand: column,
direction
});
}
}
const valueExtractor = (value) => {
const row = value;
const nestedRow = { [mainTableAlias]: row };
if (orderByItems.length > 1) {
return orderByItems.map((item) => {
const val = evaluateOperandOnNestedRow(
nestedRow,
item.operand,
mainTableAlias
);
return item.direction === `desc` && typeof val === `number` ? -val : item.direction === `desc` && typeof val === `string` ? String.fromCharCode(
...[...val].map((c) => 65535 - c.charCodeAt(0))
) : val;
});
} else if (orderByItems.length === 1) {
const item = orderByItems[0];
const val = evaluateOperandOnNestedRow(
nestedRow,
item.operand,
mainTableAlias
);
return item.direction === `desc` && typeof val === `number` ? -val : item.direction === `desc` && typeof val === `string` ? String.fromCharCode(
...[...val].map((c) => 65535 - c.charCodeAt(0))
) : val;
}
return null;
};
const comparator = (a, b) => {
if (typeof a === `number` && typeof b === `number`) {
return a - b;
}
if (typeof a === `string` && typeof b === `string`) {
return a.localeCompare(b);
}
if (typeof a === `boolean` && typeof b === `boolean`) {
return a ? 1 : -1;
}
if (a instanceof Date && b instanceof Date) {
return a.getTime() - b.getTime();
}
if (a === null && b === null) {
return 0;
}
if (Array.isArray(a) && Array.isArray(b)) {
for (let i = 0; i < a.length; i++) {
const result = comparator(a[i], b[i]);
if (result !== 0) return result;
}
return 0;
}
if ((a === null || a === void 0) && (b === null || b === void 0)) {
return 0;
}
return a.toString().localeCompare(b.toString());
};
let topKComparator;
if (!query.keyBy) {
topKComparator = (a, b) => {
const aValue = valueExtractor(a);
const bValue = valueExtractor(b);
return comparator(aValue, bValue);
};
}
if (hasOrderIndexColumn) {
if (orderIndexType === `numeric`) {
if (query.keyBy) {
resultPipeline = resultPipeline.pipe(
orderByWithIndex(valueExtractor, {
limit: query.limit,
offset: query.offset,
comparator
}),
map(([key, [value, index]]) => {
const result = {
...value,
[orderIndexAlias]: index
};
return [key, result];
})
);
} else {
resultPipeline = resultPipeline.pipe(
map((value) => [null, value]),
topKWithIndex(topKComparator, {
limit: query.limit,
offset: query.offset
}),
map(([_, [value, index]]) => {
return {
...value,
[orderIndexAlias]: index
};
})
);
}
} else {
if (query.keyBy) {
resultPipeline = resultPipeline.pipe(
orderByWithFractionalIndex(valueExtractor, {
limit: query.limit,
offset: query.offset,
comparator
}),
map(([key, [value, index]]) => {
const result = {
...value,
[orderIndexAlias]: index
};
return [key, result];
})
);
} else {
resultPipeline = resultPipeline.pipe(
map((value) => [null, value]),
topKWithFractionalIndex(topKComparator, {
limit: query.limit,
offset: query.offset
}),
map(([_, [value, index]]) => {
return {
...value,
[orderIndexAlias]: index
};
})
);
}
}
} else {
if (query.keyBy) {
resultPipeline = resultPipeline.pipe(
orderBy(valueExtractor, {
limit: query.limit,
offset: query.offset,
comparator
})
);
} else {
resultPipeline = resultPipeline.pipe(
map((value) => [null, value]),
topK(topKComparator, {
limit: query.limit,
offset: query.offset
}),
map(([_, value]) => value)
);
}
}
return resultPipeline;
}
function getOrderIndexType(obj) {
if (!isOrderIndexFunctionCall(obj)) {
throw new Error(`Not an ORDER_INDEX function call`);
}
const arg = obj[`ORDER_INDEX`];
if (arg === `numeric` || arg === true || arg === `default`) {
return `numeric`;
} else if (arg === `fractional`) {
return `fractional`;
} else {
throw new Error(`Invalid ORDER_INDEX type: ` + arg);
}
}
export {
processOrderBy
};
//# sourceMappingURL=order-by.js.map