UNPKG

@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
"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