@supabase-cache-helpers/postgrest-core
Version:
A collection of cache utilities for working with the Supabase REST API. It is not meant to be used standalone.
1,451 lines (1,402 loc) • 70.7 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
target[prop] = source[prop];
}
return target;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/index.ts
var index_exports = {};
__export(index_exports, {
PostgrestFilter: () => PostgrestFilter,
PostgrestParser: () => PostgrestParser,
PostgrestQueryParser: () => PostgrestQueryParser,
SUPPORTED_OPERATORS: () => SUPPORTED_OPERATORS,
buildDeleteFetcher: () => buildDeleteFetcher,
buildInsertFetcher: () => buildInsertFetcher,
buildMutationFetcherResponse: () => buildMutationFetcherResponse,
buildNormalizedQuery: () => buildNormalizedQuery,
buildUpdateFetcher: () => buildUpdateFetcher,
buildUpsertFetcher: () => buildUpsertFetcher,
createCursorPaginationFetcher: () => createCursorPaginationFetcher,
createOffsetPaginationFetcher: () => createOffsetPaginationFetcher,
createOffsetPaginationHasMoreFetcher: () => createOffsetPaginationHasMoreFetcher,
decodeObject: () => decodeObject,
deleteItem: () => deleteItem,
encodeObject: () => encodeObject,
fetcher: () => fetcher,
findFilters: () => findFilters,
get: () => get,
getTable: () => getTable,
isAndFilter: () => isAndFilter,
isAnyPostgrestResponse: () => isAnyPostgrestResponse,
isFilterDefinition: () => isFilterDefinition,
isOrFilter: () => isOrFilter,
isPlainObject: () => isPlainObject,
isPostgrestBuilder: () => isPostgrestBuilder,
isPostgrestHasMorePaginationCacheData: () => isPostgrestHasMorePaginationCacheData,
isPostgrestHasMorePaginationResponse: () => isPostgrestHasMorePaginationResponse,
isPostgrestPaginationCacheData: () => isPostgrestPaginationCacheData,
isPostgrestPaginationResponse: () => isPostgrestPaginationResponse,
isPostgrestTransformBuilder: () => isPostgrestTransformBuilder,
mutateItem: () => mutateItem,
mutateOperation: () => mutateOperation,
normalizeResponse: () => normalizeResponse,
offsetPaginationFetcher: () => offsetPaginationFetcher,
offsetPaginationHasMoreFetcher: () => offsetPaginationHasMoreFetcher,
parseOrderBy: () => parseOrderBy,
parseOrderByKey: () => parseOrderByKey,
parseValue: () => parseValue,
revalidateTables: () => revalidateTables,
rpcOffsetPaginationFetcher: () => rpcOffsetPaginationFetcher,
rpcOffsetPaginationHasMoreFetcher: () => rpcOffsetPaginationHasMoreFetcher,
setFilterValue: () => setFilterValue,
upsert: () => upsert,
upsertItem: () => upsertItem
});
module.exports = __toCommonJS(index_exports);
// src/lib/query-types.ts
var isAndFilter = (f) => Array.isArray(f.and);
var isOrFilter = (f) => Array.isArray(f.or);
var isFilterDefinition = (f) => !isAndFilter(f) && !isOrFilter(f);
// src/lib/extract-paths-from-filter.ts
var extractPathsFromFilters = (f, p) => {
return f.reduce((prev, filter) => {
var _a;
if (isAndFilter(filter)) {
prev.push(...extractPathsFromFilters(filter.and, p));
} else if (isOrFilter(filter)) {
prev.push(...extractPathsFromFilters(filter.or, p));
} else if (isFilterDefinition(filter)) {
const relatedPath = p.find((p2) => p2.path === filter.path);
const pathElements = filter.path.split(".");
const aliasElements = (_a = filter.alias) == null ? void 0 : _a.split(".");
const declaration = pathElements.map(
(el, idx) => `${aliasElements && aliasElements[idx] !== el ? `${aliasElements[idx]}:` : ""}${el}`
).join(".");
prev.push({
path: filter.path,
alias: filter.alias,
declaration: relatedPath ? relatedPath.declaration : declaration
});
}
return prev;
}, []);
};
// src/lib/remove-first-path-element.ts
var removeFirstPathElement = (p) => {
const aliasWithoutFirstElement = p.alias ? p.alias.split(".").slice(1).join(".") : void 0;
const pathWithoutFirstEelment = p.path.split(".").slice(1).join(".");
return {
declaration: p.declaration.split(".").slice(1).join("."),
path: pathWithoutFirstEelment,
alias: aliasWithoutFirstElement && (aliasWithoutFirstElement.split(".").length > 1 || aliasWithoutFirstElement !== pathWithoutFirstEelment) ? aliasWithoutFirstElement : void 0
};
};
// src/lib/group-paths-recursive.ts
var isNestedPath = (p) => Array.isArray(p.paths);
var groupPathsRecursive = (paths) => {
const grouped = paths.reduce((prev, curr) => {
const levels = curr.path.split(".").length;
if (levels === 1) {
prev.push(curr);
return prev;
}
const firstLevelDeclaration = curr.declaration.split(".")[0];
const indexOfNested = prev.findIndex(
(p) => isNestedPath(p) && p.declaration === firstLevelDeclaration
);
const pathWithoutCurrentLevel = removeFirstPathElement(curr);
if (indexOfNested !== -1) {
prev[indexOfNested].paths.push(pathWithoutCurrentLevel);
return prev;
}
prev.push(__spreadValues({
declaration: firstLevelDeclaration,
path: curr.path.split(".")[0],
paths: [pathWithoutCurrentLevel]
}, curr.alias ? { alias: curr.alias.split(".")[0] } : {}));
return prev;
}, []);
return grouped.map(
(p) => isNestedPath(p) ? __spreadProps(__spreadValues({}, p), { paths: groupPathsRecursive(p.paths) }) : p
);
};
// src/lib/parse-select-param.ts
var import_xregexp = __toESM(require("xregexp"), 1);
var parseSelectParam = (s, currentPath) => {
s = s.replace(/\s/g, "");
let result;
try {
result = import_xregexp.default.matchRecursive(`,${s}`, "([^,\\(]+)\\(", "\\)", "g", {
valueNames: {
"0": null,
"1": "tableName",
"2": "selectedColumns",
"3": null
}
}).map((item) => {
if (item.name === "tableName" && item.value && !item.value.startsWith(",")) {
item.value = "," + item.value;
}
return item;
});
} catch (e) {
const path = (currentPath == null ? void 0 : currentPath.path) ? `${currentPath == null ? void 0 : currentPath.declaration} with alias ${currentPath == null ? void 0 : currentPath.alias} at path ${currentPath == null ? void 0 : currentPath.path}` : "root";
throw new Error(`Unable to parse ${s} at ${path}`, {
cause: e
});
}
const foreignTables = result.reduce((prev, curr, idx, matches) => {
if (curr.name === "selectedColumns" && curr.value.length > 0) {
const name = matches[idx - 1].value.slice(1, -1);
prev = __spreadProps(__spreadValues({}, prev), { [name]: curr.value });
}
return prev;
}, {});
const columns = s.replace(
new RegExp(
`${Object.entries(foreignTables).map(
([table, selectedColumns]) => `${table}(${selectedColumns})`.replace(/\(/g, "\\(").replace(/\)/g, "\\)").replace(/\*/g, "\\*")
).join("|")}`,
"g"
),
""
).replace(/(,)\1+/g, ",").split(",").filter((c) => c.length > 0).map((c) => {
var _a;
const split = c.split(":");
const hasAlias = split.length > 1;
const aggregateSplit = split[hasAlias ? 1 : 0].split(".");
const hasAggregate = aggregateSplit.length > 1 && aggregateSplit[1].endsWith("()");
return __spreadValues({
declaration: [currentPath == null ? void 0 : currentPath.declaration, c].filter(Boolean).join("."),
alias: hasAlias || (currentPath == null ? void 0 : currentPath.alias) ? [(_a = currentPath == null ? void 0 : currentPath.alias) != null ? _a : currentPath == null ? void 0 : currentPath.path, split[0]].filter(Boolean).join(".") : void 0,
path: [
currentPath == null ? void 0 : currentPath.path,
hasAggregate ? aggregateSplit[0] : split[hasAlias ? 1 : 0]
].filter(Boolean).join(".")
}, hasAggregate ? { aggregate: aggregateSplit[1].slice(0, -2) } : {});
});
return [
...columns,
...Object.entries(foreignTables).flatMap(
([currentDeclaration, selectedColumns]) => {
var _a;
const aliasSplit = currentDeclaration.split(":");
const currentAliasElem = aliasSplit.length > 1 ? aliasSplit[0] : void 0;
const currentPathDeclaration = aliasSplit[aliasSplit.length - 1];
const currentPathElem = currentPathDeclaration.split("!")[0];
const path = [currentPath == null ? void 0 : currentPath.path, currentPathElem].filter(Boolean).join(".");
const alias = [
(_a = currentPath == null ? void 0 : currentPath.alias) != null ? _a : currentPath == null ? void 0 : currentPath.path,
currentAliasElem != null ? currentAliasElem : currentPathElem
].filter(Boolean).join(".");
const declaration = [currentPath == null ? void 0 : currentPath.declaration, currentDeclaration].filter(Boolean).join(".");
return parseSelectParam(`${selectedColumns}`, {
path,
alias: (currentPath == null ? void 0 : currentPath.alias) || currentAliasElem ? alias : void 0,
declaration
});
}
)
];
};
// src/lib/remove-alias-from-declaration.ts
var removeAliasFromDeclaration = (d) => d.split(".").map((el) => el.split(":").pop()).join(".");
// src/fetch/build-select-statement.ts
var buildSelectStatement = (paths) => {
return buildSelectStatementFromGroupedPaths(groupPathsRecursive(paths));
};
var buildSelectStatementFromGroupedPaths = (paths) => paths.map((i) => {
if (isNestedPath(i)) {
return `${i.declaration}(${buildSelectStatement(i.paths)})`;
}
return `${i.alias ? `${i.alias}:` : ""}${i.path}`;
}).join(",");
// src/fetch/dedupe.ts
var DEDUPE_ALIAS_PREFIX = "d";
var dedupeGroupedPathsRecursive = (grouped) => {
const dedupeCounters = /* @__PURE__ */ new Map();
return grouped.map((p, idx, a) => {
if (!isNestedPath(p)) return p;
if (a.some((i, itemIdx) => i.path === p.path && idx !== itemIdx)) {
const counter = dedupeCounters.get(p.path) || 0;
dedupeCounters.set(p.path, counter + 1);
const alias = [DEDUPE_ALIAS_PREFIX, counter, p.path].join("_");
return __spreadProps(__spreadValues({}, p), {
alias,
declaration: `${alias}:${p.declaration}`,
paths: dedupeGroupedPathsRecursive(p.paths)
});
}
return __spreadProps(__spreadValues({}, p), {
paths: dedupeGroupedPathsRecursive(p.paths)
});
});
};
// src/fetch/build-normalized-query.ts
var buildNormalizedQuery = ({
query,
disabled,
queriesForTable
}) => {
var _a;
const userQueryPaths = query ? parseSelectParam(query) : null;
const paths = userQueryPaths ? userQueryPaths.map((q) => ({
declaration: removeAliasFromDeclaration(q.declaration),
path: q.path
})) : [];
if (!disabled) {
for (const tableQuery of queriesForTable()) {
for (const filterPath of extractPathsFromFilters(
tableQuery.filters,
tableQuery.paths
)) {
const path = (_a = tableQuery.paths.find(
(p) => p.path === filterPath.path && p.alias === filterPath.alias
)) != null ? _a : {
path: filterPath.path,
declaration: filterPath.path
};
if (paths.every(
(p) => removeAliasFromDeclaration(p.declaration) !== removeAliasFromDeclaration(path.declaration)
)) {
paths.push({
path: path.path,
declaration: removeAliasFromDeclaration(path.declaration)
});
}
}
for (const path of tableQuery.paths) {
if (paths.every(
(p) => removeAliasFromDeclaration(p.declaration) !== removeAliasFromDeclaration(path.declaration)
) && // do not add agg functions
!path.declaration.endsWith(".count") && // do not add wildcard queries
!path.declaration.endsWith("*")) {
paths.push({
path: path.path,
declaration: removeAliasFromDeclaration(path.declaration)
});
}
}
}
}
const groupedPaths = groupPathsRecursive(paths);
const groupedDedupedPaths = dedupeGroupedPathsRecursive(groupedPaths);
const selectQuery = buildSelectStatementFromGroupedPaths(groupedDedupedPaths);
if (selectQuery.length === 0) return null;
return {
selectQuery,
groupedUserQueryPaths: userQueryPaths ? groupPathsRecursive(userQueryPaths) : null,
groupedPaths: groupedDedupedPaths
};
};
// src/fetch/build-mutation-fetcher-response.ts
var import_flat = require("flat");
// src/lib/get.ts
var get = (obj, path, defaultValue = void 0) => {
const split = path.split(/((?:\.|,|\[|\]|->>|->)+)/g);
let result = obj;
for (let i = -1; i < split.length; i += 2) {
const separator = split[i];
let key = split[i + 1];
if (!key) {
continue;
}
if ((separator == null ? void 0 : separator.endsWith("->")) || (separator == null ? void 0 : separator.endsWith("->>"))) {
if (/^\d+$/.test(key)) {
key = Number.parseInt(key, 10);
}
}
if (separator == null ? void 0 : separator.endsWith("->>")) {
result = `${result ? result[key] : result}`;
} else {
result = result ? result[key] : result;
}
}
return result === void 0 || result === obj ? defaultValue : result;
};
// src/lib/is-plain-object.ts
function isPlainObject(value) {
return Object.prototype.toString.call(value) === "[object Object]";
}
// src/fetch/build-mutation-fetcher-response.ts
var buildMutationFetcherResponse = (input, {
groupedPaths,
groupedUserQueryPaths
}) => {
return {
normalizedData: normalizeResponse(groupedPaths, input),
userQueryData: groupedUserQueryPaths ? buildUserQueryData(groupedUserQueryPaths, groupedPaths, input) : void 0
};
};
var normalizeResponse = (groups, obj) => {
if (groups.some((p) => p.path === "*")) {
Object.entries(obj).forEach(([k, v]) => {
if (typeof v === "object" || Array.isArray(v)) {
if (!groups.some((g) => isNestedPath(g) && g.path === k)) {
groups.push({
path: k,
declaration: k
});
}
} else if (!groups.some((g) => g.path === k)) {
groups.push({
path: k,
declaration: k
});
}
});
}
return groups.reduce((prev, curr) => {
var _a, _b;
const value = get(obj, curr.alias || curr.path);
if (typeof value === "undefined") return prev;
if (value === null) {
return __spreadProps(__spreadValues({}, prev), {
// add hint to path if it has dedupe alias
// can happen if the same relation is queried multiple times via different fkeys
[`${curr.path}${((_a = curr.alias) == null ? void 0 : _a.startsWith("d_")) && curr.declaration.split("!").length > 1 ? `!${curr.declaration.split("!")[1]}` : ""}`]: value
});
}
if (!isNestedPath(curr)) {
return __spreadValues(__spreadValues({}, prev), (0, import_flat.flatten)({
[curr.path]: value !== null && (isPlainObject(value) || Array.isArray(value) && value.length > 0) ? (0, import_flat.flatten)(value) : value
}));
}
if (Array.isArray(value)) {
return __spreadValues(__spreadValues({}, prev), (0, import_flat.flatten)({
[curr.path]: value.map((v) => normalizeResponse(curr.paths, v))
}));
}
return __spreadValues(__spreadValues({}, prev), (0, import_flat.flatten)({
// add hint to path if it has dedupe alias
// can happen if the same relation is queried multiple times via different fkeys
[`${curr.path}${((_b = curr.alias) == null ? void 0 : _b.startsWith("d_")) && curr.declaration.split("!").length > 1 ? `!${curr.declaration.split("!")[1]}` : ""}`]: normalizeResponse(curr.paths, value)
}));
}, {});
};
var buildUserQueryData = (userQueryGroups, pathGroups, obj) => {
if (pathGroups.some((p) => p.path === "*")) {
Object.entries(obj).forEach(([k, v]) => {
if (typeof v === "object" || Array.isArray(v)) {
if (!pathGroups.some((g) => isNestedPath(g) && g.path === k)) {
pathGroups.push({
path: k,
declaration: k
});
}
} else if (!pathGroups.some((g) => g.path === k)) {
pathGroups.push({
path: k,
declaration: k
});
}
});
}
if (userQueryGroups.some((p) => p.path === "*")) {
Object.entries(obj).forEach(([k, v]) => {
if (typeof v === "object" || Array.isArray(v)) {
if (!pathGroups.some((g) => isNestedPath(g) && g.path === k)) {
userQueryGroups.push({
path: k,
declaration: k
});
}
} else if (!userQueryGroups.some((g) => g.path === k)) {
userQueryGroups.push({
path: k,
declaration: k
});
}
});
}
return userQueryGroups.reduce((prev, curr) => {
if (curr.path === "*") return prev;
const inputPath = pathGroups.find(
(p) => p.path === curr.path && isNestedPath(p) === isNestedPath(curr)
);
if (!inputPath) {
throw new Error(`Path ${curr.path} not found in response paths`);
}
const value = get(obj, inputPath.alias || inputPath.path);
if (typeof value === "undefined") return prev;
if (value === null || !isNestedPath(curr) || !isNestedPath(inputPath)) {
prev[curr.alias ? curr.alias : curr.path] = value;
} else if (Array.isArray(value)) {
prev[curr.alias ? curr.alias : curr.path] = value.map((v) => buildUserQueryData(curr.paths, inputPath.paths, v));
} else {
prev[curr.alias ? curr.alias : curr.path] = buildUserQueryData(
curr.paths,
inputPath.paths,
value
);
}
return prev;
}, {});
};
// src/lib/get-table-from-url.ts
var getTableFromUrl = (url) => {
var _a;
const split = url.toString().split("/");
const table = (_a = split.pop()) == null ? void 0 : _a.split("?").shift();
const maybeRpc = split.pop();
return [maybeRpc === "rpc" ? maybeRpc : null, table].filter(Boolean).join("/");
};
// src/lib/like-query-builder.ts
var isLikeQueryBuilder = (v) => {
if (typeof v !== "object" || v === null) return false;
const obj = v;
return typeof obj["url"] === "object";
};
// src/lib/get-table.ts
var getTable = (query) => {
if (!isLikeQueryBuilder(query)) {
throw new Error("Invalid PostgrestBuilder");
}
return getTableFromUrl(query["url"].pathname);
};
// src/lib/cache-data-types.ts
var isPostgrestPaginationCacheData = (q) => {
if (!Array.isArray(q)) return false;
return q.length === 0 || Array.isArray(q[0]);
};
var isPostgrestHasMorePaginationCacheData = (q) => {
if (!Array.isArray(q)) return false;
if (q.length === 0) return true;
const firstPage = q[0];
return Array.isArray(
firstPage.data
) && typeof firstPage.hasMore === "boolean";
};
// src/lib/response-types.ts
var isAnyPostgrestResponse = (q) => {
if (!q) return false;
return typeof q.data === "object" || Array.isArray(q.data);
};
var isPostgrestPaginationResponse = (q) => {
return Array.isArray(q);
};
var isPostgrestHasMorePaginationResponse = (q) => {
if (!q) return false;
return Array.isArray(q.data) && typeof q.hasMore === "boolean";
};
// src/lib/encode-object.ts
var import_flat2 = require("flat");
// src/lib/sort-search-param.ts
var sortSearchParams = (params) => new URLSearchParams(
Array.from(params.entries()).sort((a, b) => {
const x = `${a[0]}${a[1]}`;
const y = `${b[0]}${b[1]}`;
return x > y ? 1 : -1;
})
);
// src/lib/encode-object.ts
var encodeObject = (obj) => {
const sortedEntries = Object.entries(
(0, import_flat2.flatten)(obj)
).sort(([a], [b]) => a.length - b.length);
const bodyParams = new URLSearchParams();
sortedEntries.forEach(([key, value]) => {
bodyParams.append(key, String(value));
});
return sortSearchParams(bodyParams).toString();
};
var decodeObject = (encodedString) => {
const params = new URLSearchParams(encodedString);
const flatObject = {};
params.forEach((value, key) => {
let parsedValue = value;
if (/^-?\d+$/.test(value)) {
parsedValue = parseInt(value, 10);
} else if (/^-?\d+\.\d+$/.test(value)) {
parsedValue = parseFloat(value);
} else if (value === "true") {
parsedValue = true;
} else if (value === "false") {
parsedValue = false;
} else if (value === "null") {
parsedValue = null;
}
flatObject[key] = parsedValue;
});
return (0, import_flat2.unflatten)(flatObject);
};
// src/lib/is-postgrest-builder.ts
var isPostgrestBuilder = (q) => {
return typeof q.throwOnError === "function";
};
// src/lib/is-postgrest-transform-builder.ts
var isPostgrestTransformBuilder = (q) => {
return typeof q.abortSignal === "function";
};
// src/lib/set-filter-value.ts
var setFilterValue = (searchParams, path, op, value) => {
const filters = searchParams.getAll(path);
searchParams.delete(path);
for (const f of filters) {
if (f.startsWith(`${op}.`)) {
continue;
}
searchParams.append(path, f);
}
searchParams.append(path, `${op}.${value}`);
};
// src/lib/is-iso-date-string.ts
var isISODateString = (v) => typeof v === "string" && /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/.test(
v
);
// src/lib/parse-value.ts
var parseValue = (v) => {
if (isISODateString(v)) return new Date(v);
try {
return JSON.parse(v);
} catch (e) {
return v;
}
};
// src/lib/parse-order-by-key.ts
var parseOrderByKey = (v) => {
return v.split("|").map((orderBy) => {
const [tableDef, orderDef] = orderBy.split(":");
const [foreignTableOrCol, maybeCol] = tableDef.split(".");
const [dir, nulls] = orderDef.split(".");
return {
ascending: dir === "asc",
nullsFirst: nulls === "nullsFirst",
foreignTable: maybeCol ? foreignTableOrCol : void 0,
column: maybeCol ? maybeCol : foreignTableOrCol
};
});
};
// src/lib/parse-order-by.ts
var parseOrderBy = (searchParams) => {
const orderBy = [];
searchParams.forEach((value, key) => {
const split = key.split(".");
if (split[split.length === 2 ? 1 : 0] === "order") {
const orderByDefs = value.split(",");
orderByDefs.forEach((def) => {
const [column, ascending, nullsFirst] = def.split(".");
orderBy.push({
ascending: ascending === "asc",
column,
nullsFirst: nullsFirst === "nullsfirst",
foreignTable: split.length === 2 ? split[0] : void 0
});
});
}
});
return orderBy;
};
// src/lib/find-filters.ts
var findFilters = (f, by) => {
const filters = [];
f.forEach((filter) => {
if (isAndFilter(filter)) {
filters.push(...findFilters(filter.and, by));
}
if (isOrFilter(filter)) {
filters.push(...findFilters(filter.or, by));
}
if (isFilterDefinition(filter)) {
if ((typeof by.path === "undefined" || filter.path === by.path) && (typeof by.alias === "undefined" || filter.alias === by.alias) && (typeof by.value === "undefined" || filter.value === by.value) && (typeof by.negate === "undefined" || filter.negate === by.negate) && (typeof by.operator === "undefined" || filter.operator === by.operator)) {
filters.push(filter);
}
}
});
return filters;
};
// src/cursor-pagination-fetcher.ts
var createCursorPaginationFetcher = (queryFactory, config) => {
if (!queryFactory) return null;
return (args) => __async(void 0, null, function* () {
const cursor = config.decode(args);
const query = queryFactory();
if (config.rpcArgs) {
query["body"] = __spreadValues(__spreadProps(__spreadValues({}, isPlainObject(query["body"]) ? query["body"] : {}), {
[config.rpcArgs.orderBy]: cursor.orderBy
}), cursor.uqOrderBy && config.rpcArgs.uqOrderBy ? { [config.rpcArgs.uqOrderBy]: cursor.uqOrderBy } : {});
const { data: data2 } = yield query.throwOnError();
return data2;
}
const orderByDef = parseOrderBy(query["url"].searchParams);
const orderBy = orderByDef.find((o) => o.column === config.orderBy);
if (!orderBy) {
throw new Error(`No ordering key found for path ${config.orderBy}`);
}
const uqOrderBy = config.uqOrderBy ? orderByDef.find((o) => o.column === config.uqOrderBy) : null;
if (cursor.orderBy && config.uqOrderBy && cursor.uqOrderBy && uqOrderBy) {
const operator = orderBy.ascending ? "gt" : "lt";
const uqOperator = uqOrderBy.ascending ? "gt" : "lt";
query["url"].searchParams.append(
"or",
`(${config.orderBy}.${operator}."${cursor.orderBy}",and(${config.orderBy}.eq."${cursor.orderBy}",${config.uqOrderBy}.${uqOperator}."${cursor.uqOrderBy}"))`
);
} else if (cursor.orderBy) {
const operator = orderBy.ascending ? "gt" : "lt";
query["url"].searchParams.append(
config.orderBy,
`${operator}.${cursor.orderBy}`
);
}
const { data, error } = yield query;
if (error) throw error;
return data;
});
};
// src/delete-fetcher.ts
var buildDeleteFetcher = (qb, primaryKeys, opts) => (input) => __async(void 0, null, function* () {
let filterBuilder = qb.delete(opts);
if (primaryKeys.length === 1) {
const primaryKey = primaryKeys[0];
filterBuilder.in(
primaryKey,
input.map((i) => {
const v = i[primaryKey];
if (!v) {
throw new Error(
`Missing value for primary key ${primaryKey}`
);
}
return v;
})
);
} else {
filterBuilder = filterBuilder.or(
input.map(
(i) => `and(${primaryKeys.map((c) => {
const v = i[c];
if (!v) {
throw new Error(
`Missing value for primary key ${c}`
);
}
return `${c}.eq.${v}`;
})})`
).join(",")
);
}
const primaryKeysData = input.map(
(i) => primaryKeys.reduce((prev, key) => {
return __spreadProps(__spreadValues({}, prev), {
[key]: i[key]
});
}, {})
);
const query = buildNormalizedQuery(opts);
if (query) {
const { selectQuery, groupedUserQueryPaths, groupedPaths } = query;
const groupedPathsWithPrimaryKeys = groupedPaths;
const addKeys = [];
primaryKeys.forEach((key) => {
if (!groupedPathsWithPrimaryKeys.find((p) => p.path === key)) {
groupedPathsWithPrimaryKeys.push({
declaration: key,
path: key
});
addKeys.push(key);
}
});
const { data } = yield filterBuilder.select([selectQuery, ...addKeys].join(",")).throwOnError();
return data.map(
(d) => buildMutationFetcherResponse(d, {
groupedPaths: groupedPathsWithPrimaryKeys,
groupedUserQueryPaths
})
);
}
yield filterBuilder.throwOnError();
if (opts.queriesForTable().length > 0) {
return primaryKeysData.map((pk) => ({ normalizedData: pk }));
}
return null;
});
// src/mutate/should-revalidate-relation.ts
var shouldRevalidateRelation = (relations, {
input,
getPostgrestFilter,
decodedKey: { schema, table, queryKey }
}) => Boolean(
relations.find(
(r) => (!r.schema || r.schema === schema) && r.relation === table && typeof input[r.fKeyColumn] !== "undefined" && getPostgrestFilter(queryKey, {
exclusivePaths: [r.relationIdColumn]
}).applyFilters({
[r.relationIdColumn]: input[r.fKeyColumn]
})
)
);
// src/mutate/should-revalidate-table.ts
var shouldRevalidateTable = (tables, { decodedKey: { schema, table } }) => Boolean(
tables.find((t) => (!t.schema || t.schema === schema) && t.table === table)
);
// src/mutate/transformers.ts
var toHasMorePaginationCacheData = (a, currentData, chunkSize) => {
const hasMoreCache = currentData.map((p) => p.hasMore);
return a.reduce(
(resultArray, item, index) => {
var _a, _b;
const chunkIndex = Math.floor(index / chunkSize);
if (!resultArray[chunkIndex]) {
let hasMore = hasMoreCache[chunkIndex];
if (!hasMore) {
hasMore = hasMoreCache[hasMoreCache.length - 1];
}
if (chunkIndex > 0) {
resultArray[chunkIndex - 1].hasMore = true;
}
resultArray[chunkIndex] = {
data: [],
hasMore: (_b = (_a = hasMoreCache[chunkIndex]) != null ? _a : hasMoreCache[hasMoreCache.length - 1]) != null ? _b : false
};
}
resultArray[chunkIndex].data.push(item);
return resultArray;
},
[]
);
};
var toPaginationCacheData = (a, chunkSize) => {
return a.reduce(
(resultArray, item, index) => {
const chunkIndex = Math.floor(index / chunkSize);
if (!resultArray[chunkIndex]) {
resultArray[chunkIndex] = [];
}
resultArray[chunkIndex].push(item);
return resultArray;
},
[]
);
};
// src/delete-item.ts
var filterByPks = (input, currentData, primaryKeys) => {
return currentData.filter(
(i) => primaryKeys.some((pk) => i[pk] !== input[pk])
);
};
var deleteItem = (op, cache) => __async(void 0, null, function* () {
var _a;
const {
revalidateRelations: revalidateRelationsOpt,
revalidateTables: revalidateTablesOpt,
schema,
table
} = op;
const { cacheKeys, decode, getPostgrestFilter, mutate, revalidate } = cache;
const mutations = [];
for (const k of cacheKeys) {
const key = decode(k);
if (!key) continue;
const filter = getPostgrestFilter(key.queryKey);
if (key.schema === schema && key.table === table) {
if (key.isHead === true) {
mutations.push(revalidate(k));
} else {
const transformedInput = filter.denormalize(op.input);
if (
// For delete, the input has to have a value for all primary keys
op.primaryKeys.every(
(pk) => typeof transformedInput[pk] !== "undefined"
)
) {
const limit = (_a = key.limit) != null ? _a : 1e3;
mutations.push(
mutate(k, (currentData) => {
if (!currentData) return currentData;
if (isPostgrestHasMorePaginationCacheData(currentData)) {
return toHasMorePaginationCacheData(
filterByPks(
transformedInput,
currentData.flatMap((p) => p.data),
op.primaryKeys
),
currentData,
limit
);
} else if (isPostgrestPaginationCacheData(currentData)) {
return toPaginationCacheData(
filterByPks(
transformedInput,
currentData.flat(),
op.primaryKeys
),
limit
);
} else if (isAnyPostgrestResponse(currentData)) {
const { data } = currentData;
if (!Array.isArray(data)) {
if (data && op.primaryKeys.some(
(pk) => transformedInput[pk] !== data[pk]
)) {
return currentData;
} else {
return { data: null };
}
}
const newData = filterByPks(
transformedInput,
data,
op.primaryKeys
);
return {
data: newData,
count: newData.length
};
}
})
);
}
}
}
if (revalidateTablesOpt && shouldRevalidateTable(revalidateTablesOpt, { decodedKey: key })) {
mutations.push(revalidate(k));
}
if (revalidateRelationsOpt && shouldRevalidateRelation(revalidateRelationsOpt, {
input: op.input,
getPostgrestFilter,
decodedKey: key
})) {
mutations.push(revalidate(k));
}
}
yield Promise.all(mutations);
});
// src/fetcher.ts
var fetcher = (q) => __async(void 0, null, function* () {
if (isPostgrestBuilder(q)) {
q = q.throwOnError();
}
return yield q;
});
// src/insert-fetcher.ts
function buildInsertFetcher(qb, opts) {
return (input) => __async(this, null, function* () {
const query = buildNormalizedQuery(opts);
if (query) {
const { selectQuery, groupedUserQueryPaths, groupedPaths } = query;
const { data } = yield qb.insert(input, opts).select(selectQuery).throwOnError();
return data.map(
(d) => buildMutationFetcherResponse(d, {
groupedUserQueryPaths,
groupedPaths
})
);
}
yield qb.insert(input).throwOnError();
return input.map((d) => ({ normalizedData: d }));
});
}
// src/lib/binary-search.ts
function binarySearch(arr, el, compare) {
let m = 0;
let n = arr.length - 1;
while (m <= n) {
const k = n + m >> 1;
const cmp = compare(el, arr[k]);
if (cmp > 0) {
m = k + 1;
} else if (cmp < 0) {
n = k - 1;
} else {
return k;
}
}
return m;
}
// src/lib/if-date-get-time.ts
var ifDateGetTime = (v) => {
if (v instanceof Date) return v.getTime();
if (typeof v === "string") {
const t = new Date(v).getTime();
if (!isNaN(t)) return t;
}
return v;
};
// src/lib/sorted-comparator.ts
var buildSortedComparator = (orderBy) => {
return (a, b) => {
for (const { column, ascending, nullsFirst, foreignTable } of orderBy) {
const aValue = ifDateGetTime(
get(
a,
`${foreignTable ? `${foreignTable}.` : ""}${column}`,
null
)
);
const bValue = ifDateGetTime(
get(
b,
`${foreignTable ? `${foreignTable}.` : ""}${column}`,
null
)
);
if (aValue === bValue) continue;
if (aValue === null || aValue === void 0) {
return nullsFirst ? -1 : 1;
}
if (bValue === null || bValue === void 0) {
return nullsFirst ? 1 : -1;
}
if (ascending) {
return aValue < bValue ? -1 : 1;
}
return aValue < bValue ? 1 : -1;
}
return 0;
};
};
// src/lib/find-index-ordered.ts
var findIndexOrdered = (input, currentData, orderBy) => binarySearch(currentData, input, buildSortedComparator(orderBy));
// src/mutate-item.ts
var mutateOperation = (input, mutate, currentData, primaryKeys, filter, orderBy) => {
const itemIdx = currentData.findIndex(
(oldItem) => primaryKeys.every((pk) => oldItem[pk] === input[pk])
);
if (itemIdx === -1) {
return currentData;
}
let newItemIdx = itemIdx;
const newItem = mutate(currentData[newItemIdx]);
currentData.splice(itemIdx, 1);
if (orderBy && Array.isArray(orderBy) && orderBy.length > 0) {
newItemIdx = findIndexOrdered(newItem, currentData, orderBy);
}
if (newItemIdx === -1) {
newItemIdx = 0;
}
if (filter.apply(newItem)) {
currentData.splice(newItemIdx, 0, newItem);
}
return currentData;
};
var mutateItem = (op, cache) => __async(void 0, null, function* () {
var _a;
const {
mutate: mutateInput,
revalidateRelations: revalidateRelationsOpt,
revalidateTables: revalidateTablesOpt,
schema,
table,
primaryKeys
} = op;
const { cacheKeys, decode, getPostgrestFilter, mutate, revalidate } = cache;
const mutations = [];
for (const k of cacheKeys) {
const key = decode(k);
if (!key) continue;
const filter = getPostgrestFilter(key.queryKey);
if (key.schema === schema && key.table === table) {
const transformedInput = filter.denormalize(op.input);
if (
// For mutate, the input has to have a value for all primary keys
op.primaryKeys.every(
(pk) => typeof transformedInput[pk] !== "undefined"
) && // allow mutate if either the filter does not apply eq filters on any pk
(!filter.hasFiltersOnPaths(op.primaryKeys) || // or input matches all pk filters
filter.applyFiltersOnPaths(
transformedInput,
op.primaryKeys
))
) {
const limit = (_a = key.limit) != null ? _a : 1e3;
const orderBy = key.orderByKey ? parseOrderByKey(key.orderByKey) : void 0;
if (key.isHead === true || filter.hasWildcardPath || filter.hasAggregatePath) {
mutations.push(revalidate(k));
} else {
mutations.push(
mutate(k, (currentData) => {
if (!currentData) return currentData;
if (isPostgrestHasMorePaginationCacheData(currentData)) {
return toHasMorePaginationCacheData(
mutateOperation(
transformedInput,
mutateInput,
currentData.flatMap((p) => p.data),
primaryKeys,
filter,
orderBy
),
currentData,
limit
);
} else if (isPostgrestPaginationCacheData(currentData)) {
return toPaginationCacheData(
mutateOperation(
transformedInput,
mutateInput,
currentData.flat(),
primaryKeys,
filter,
orderBy
),
limit
);
} else if (isAnyPostgrestResponse(currentData)) {
const { data } = currentData;
if (!Array.isArray(data)) {
if (data === null) {
return {
data,
count: currentData.count
};
}
const newData2 = mutateInput(data);
return {
// Check if the new data is still valid given the key
data: filter.apply(newData2) ? newData2 : null,
count: currentData.count
};
}
const newData = mutateOperation(
transformedInput,
mutateInput,
// deep copy data to avoid mutating the original
JSON.parse(JSON.stringify(data)),
primaryKeys,
filter,
orderBy
);
return {
data: newData,
count: newData.length
};
}
return currentData;
})
);
}
}
}
if (revalidateTablesOpt && shouldRevalidateTable(revalidateTablesOpt, { decodedKey: key })) {
mutations.push(revalidate(k));
}
if (revalidateRelationsOpt && shouldRevalidateRelation(revalidateRelationsOpt, {
input: op.input,
getPostgrestFilter,
decodedKey: key
})) {
mutations.push(revalidate(k));
}
}
yield Promise.all(mutations);
});
// src/offset-pagination-fetcher.ts
var createOffsetPaginationFetcher = (queryFactory, {
decode,
pageSize,
rpcArgs
}) => {
if (!queryFactory) return null;
return (args) => __async(void 0, null, function* () {
var _a;
const decodedKey = decode(args);
const limit = decodedKey.limit ? decodedKey.limit : pageSize;
const offset = (_a = decodedKey.offset) != null ? _a : 0;
const query = queryFactory();
return rpcArgs ? yield rpcOffsetPaginationFetcher(query, { limit, offset, rpcArgs }) : yield offsetPaginationFetcher(query, { limit, offset });
});
};
var offsetPaginationFetcher = (_0, _1) => __async(void 0, [_0, _1], function* (query, { limit, offset }) {
const { data } = yield query.range(offset, offset + limit - 1).throwOnError();
return data;
});
var rpcOffsetPaginationFetcher = (_0, _1) => __async(void 0, [_0, _1], function* (query, {
limit,
offset,
rpcArgs
}) {
query["body"] = __spreadProps(__spreadValues({}, isPlainObject(query["body"]) ? query["body"] : {}), {
[rpcArgs.limit]: limit,
[rpcArgs.offset]: offset
});
const { data } = yield query.throwOnError();
return data;
});
var createOffsetPaginationHasMoreFetcher = (queryFactory, {
decode,
pageSize,
rpcArgs
}) => {
if (!queryFactory) return null;
return (args) => __async(void 0, null, function* () {
var _a;
const decodedKey = decode(args);
const limit = decodedKey.limit ? decodedKey.limit : pageSize;
const offset = (_a = decodedKey.offset) != null ? _a : 0;
const query = queryFactory();
return rpcArgs ? yield rpcOffsetPaginationHasMoreFetcher(query, {
limit,
offset,
pageSize,
rpcArgs
}) : yield offsetPaginationHasMoreFetcher(query, {
limit,
offset,
pageSize
});
});
};
var offsetPaginationHasMoreFetcher = (_0, _1) => __async(void 0, [_0, _1], function* (query, {
limit,
offset,
pageSize
}) {
const { data } = yield query.range(offset, offset + limit).throwOnError();
let hasMore = false;
if (data && data.length === pageSize + 1) {
hasMore = true;
data.pop();
}
return {
// cannot be null because of .throwOnError()
data,
hasMore
};
});
var rpcOffsetPaginationHasMoreFetcher = (_0, _1) => __async(void 0, [_0, _1], function* (query, {
limit,
offset,
pageSize,
rpcArgs
}) {
query["body"] = __spreadProps(__spreadValues({}, isPlainObject(query["body"]) ? query["body"] : {}), {
[rpcArgs.limit]: limit + 1,
[rpcArgs.offset]: offset
});
const { data } = yield query.throwOnError();
let hasMore = false;
if (data && data.length === pageSize + 1) {
hasMore = true;
data.pop();
}
return {
// cannot be null because of .throwOnError()
data,
hasMore
};
});
// src/filter/denormalize.ts
var import_flat3 = require("flat");
var denormalize = (paths, obj) => {
const groups = groupPathsRecursive(paths);
if (groups.some((g) => g.path === "*")) {
Object.keys(obj).forEach((k) => {
const keyParts = k.split(".");
if (keyParts.length > 1 && groups.some((g) => isNestedPath(g) && g.path === keyParts[0])) {
return;
}
if (groups.some((g) => g.path === keyParts[0])) {
return;
}
groups.push({
declaration: keyParts[0],
path: keyParts[0]
});
});
}
return groups.reduce((prev, curr) => {
if (curr.path === "*") return prev;
let value = obj[curr.path];
if (!isNestedPath(curr)) {
if (typeof value === "undefined") {
const array = Object.entries(obj).reduce((prev2, [k, v]) => {
if (new RegExp(`^${curr.path}.\\d+$`).test(k)) {
prev2.push(v);
}
return prev2;
}, []);
if (array.length > 0) {
value = array;
}
}
if (typeof value === "undefined") {
let isArray2 = false;
const jsonValue = Object.entries(obj).reduce(
(prev2, [k, v]) => {
if (k.startsWith(`${curr.path}.`)) {
const key = k.slice(curr.path.length + 1);
const maybeIdx = key.match(/^\b\d+\b/);
if (maybeIdx && isFlatNestedArray(prev2)) {
isArray2 = true;
prev2 = __spreadProps(__spreadValues({}, prev2), {
[maybeIdx[0]]: __spreadProps(__spreadValues({}, prev2[maybeIdx[0]] ? prev2[maybeIdx[0]] : {}), {
[key.slice(maybeIdx[0].length + 1)]: v
})
});
} else {
prev2[maybeIdx ? maybeIdx[0] : key] = v;
}
}
return prev2;
},
{}
);
if (Object.keys(jsonValue).length > 0) {
if (isArray2) {
value = Object.values(jsonValue).map((v) => (0, import_flat3.unflatten)(v));
} else {
value = (0, import_flat3.unflatten)(jsonValue);
}
}
}
if (typeof value === "undefined") {
return prev;
}
return __spreadProps(__spreadValues({}, prev), {
[curr.alias || curr.path]: value
});
}
if (value === null || Array.isArray(value) && value.length === 0) {
return __spreadProps(__spreadValues({}, prev), {
[curr.alias || curr.path]: value
});
}
let isArray = false;
const flatNestedObjectOrArray = Object.entries(obj).reduce((prev2, [k, v]) => {
const isNested = k.startsWith(`${curr.path}.`) || k.includes("!") && k.startsWith(`${removeFirstAlias(curr.declaration)}.`);
if (!isNested) return prev2;
const flatKey = k.slice(
(k.includes("!") ? removeFirstAlias(curr.declaration) : curr.path).length + 1
);
const maybeIdx = flatKey.match(/^\b\d+\b/);
if (maybeIdx && isFlatNestedArray(prev2)) {
isArray = true;
const key = flatKey.slice(maybeIdx[0].length + 1);
return __spreadProps(__spreadValues({}, prev2), {
[maybeIdx[0]]: __spreadProps(__spreadValues({}, prev2[maybeIdx[0]] ? prev2[maybeIdx[0]] : {}), {
[key]: v
})
});
}
return __spreadProps(__spreadValues({}, prev2), {
[flatKey]: v
});
}, {});
if (Object.keys(flatNestedObjectOrArray).length === 0) return prev;
if (isArray && isFlatNestedArray(flatNestedObjectOrArray)) {
return __spreadProps(__spreadValues({}, prev), {
[curr.alias || curr.path]: Object.values(flatNestedObjectOrArray).map(
(v) => denormalize(curr.paths, v)
)
});
}
return __spreadProps(__spreadValues({}, prev), {
[curr.alias || curr.path]: denormalize(
curr.paths,
flatNestedObjectOrArray
)
});
}, {});
};
var isFlatNestedArray = (obj) => true;
var removeFirstAlias = (key) => {
const split = key.split(":");
if (split.length === 1) return key;
split.shift();
return split.join(":");
};
// src/lib/filter-filter-definitions-by-paths.ts
var filterFilterDefinitionsByPaths = (f, paths) => {
return f.reduce((prev, filter) => {
if (isAndFilter(filter)) {
const filters = filterFilterDefinitionsByPaths(filter.and, paths);
if (filters.length > 0) {
prev.push({ and: filters });
}
} else if (isOrFilter(filter)) {
const filters = filterFilterDefinitionsByPaths(filter.or, paths);
if (filters.length > 0) {
prev.push({ or: filters });
}
} else if (isFilterDefinition(filter) && paths.includes(filter.path)) {
prev.push(filter);
}
return prev;
}, []);
};
// src/lib/is-object.ts
var isObject = (v) => typeof v === "object" && !Array.isArray(v) && v !== null;
// src/lib/like-postgrest-builder.ts
var isLikePostgrestBuilder = (v) => {
if (typeof v !== "object" || v === null) return false;
const obj = v;
return typeof obj["url"] === "object" && typeof obj["headers"] === "object" && typeof obj["method"] === "string";
};
// src/lib/operators.ts
var import_fast_equals = require("fast-equals");
var buildLikeRegex = (search) => new RegExp(`^${search.replace(/%/g, ".*")}$`);
var textSearch = (c, v) => {
const regExp = `^${v.split("&").map((v2) => v2.trim().toLowerCase()).join("|").replace(/:\*/g, ".*")}$`;
const tokens = c.match(/'(.*?)'/g).map((t) => t.replace(/'/g, "").toLowerCase());
return tokens.some((t) => new RegExp(regExp