@querykitjs/web 3.1.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/route-query.ts","../../src/url.ts","../../src/list-state.ts","../../src/angular/inject-list-params-base.ts","../../src/angular/inject-list-params.ts"],"names":["searchParamsToQuery","searchParams","query","key","values","URL_DEFAULTS","encodeSort","sort","i","clone","setParam","name","value","url","cfg","next","setPage","page","setSize","size","setSort","encoded","resetParams","keep","createListState","resource","options","schema","withRel","params","injectListParamsBase","setSearchParams","state","read","computed","actions","paramMapToSearchParams","paramMap","injectListParams","route","inject","ActivatedRoute","router","Router","toSignal"],"mappings":"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","file":"index.js","sourcesContent":["/**\n^ * A route query as vue-router gives it: v4 has `string | null | (string | null)[]` per key,\n * v5 always an array. `null` is a key without `=` (`?q`).\n */\nexport type RouteQuery = Record<string, string | null | (string | null)[] | undefined>;\n\n/** Route query → search params: a repeated key keeps every value; `null` becomes an empty value. */\nexport function queryToSearchParams(query: RouteQuery): URLSearchParams {\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n for (const item of Array.isArray(value) ? value : [value]) {\n if (item !== undefined) searchParams.append(key, item ?? \"\");\n }\n }\n return searchParams;\n}\n\n/** Search params → route query for `router.push({ query })`: one value → string, a repeated key → array. */\nexport function searchParamsToQuery(searchParams: URLSearchParams): Record<string, string | string[]> {\n const query: Record<string, string | string[]> = {};\n for (const key of new Set(searchParams.keys())) {\n const values = searchParams.getAll(key);\n query[key] = values.length > 1 ? values : (values[0] ?? \"\");\n }\n return query;\n}\n","import { DEFAULT_MAX_OFFSET, DEFAULT_MAX_PER_PAGE, DEFAULT_MAX_SORT_FIELDS, DEFAULT_PER_PAGE } from \"@querykitjs/core\";\n\nimport { buildListParams, clampInt } from \"./query\";\nimport type { FieldDescriptor, ListSchema } from \"./schema\";\nimport type { FieldCondition, Filter, FilterNode, FilterValue, ListParams, ListPayload, Sort, SortDirection, SortInput } from \"./types\";\n\n/** URL param nomlari (sahifa/o'lcham/sort) — sozlanadigan. */\nexport interface UrlConfig {\n pageParam?: string;\n sizeParam?: string;\n sortParam?: string;\n}\n\nconst URL_DEFAULTS: Required<UrlConfig> = {\n pageParam: \"page\",\n sizeParam: \"size\",\n sortParam: \"sortType\",\n};\n\n/**\n * `\"-createdAt,id,-appNumber\"` → `[{ key, direction }, …]` — comma-separated,\n * order preserved, `-` prefix = `desc` (else `asc`). Empty → `undefined`.\n */\nexport function decodeSort(value: string | null | undefined): Sort | undefined {\n if (!value) return undefined;\n const items = value\n .split(\",\")\n .map(s => s.trim())\n .filter(Boolean)\n .map(tok => {\n const desc = tok.startsWith(\"-\");\n return { key: desc ? tok.slice(1) : tok, direction: (desc ? \"desc\" : \"asc\") as SortDirection };\n })\n .filter(i => i.key); // drop empty keys (e.g. a lone \"-\")\n return items.length ? items : undefined;\n}\n\n/** `[{ key, direction }, …]` (or `\"-field\"` shorthand strings) → `\"-createdAt,id,-appNumber\"` (empty → `\"\"`). */\nexport function encodeSort(sort: SortInput): string {\n return sort\n .map(i => (typeof i === \"string\" ? i.trim() : i && i.key ? (i.direction === \"desc\" ? \"-\" : \"\") + i.key : \"\"))\n .filter(Boolean)\n .join(\",\");\n}\n\n/**\n * Schema + searchParams → filter. Applies `range`/`between`/`search`/`split`/\n * `default`/`trim`; empty/absent params are dropped. Returns a flat\n * `FieldCondition[]` (implicit AND), or a tree when a `search` OR-group is\n * present (`{ and: [orGroup, …conditions] }`).\n */\nexport function schemaToFilter(schema: ListSchema, searchParams: URLSearchParams): Filter {\n const conditions: FieldCondition[] = [];\n const groups: FilterNode[] = [];\n\n for (const [param, d] of Object.entries(schema) as [string, FieldDescriptor][]) {\n const key = d.key ?? param;\n\n // range → two inclusive conditions (>= , <=)\n if (d.range) {\n const from = searchParams.get(d.range[0]);\n const to = searchParams.get(d.range[1]);\n if (from) conditions.push(cond(key, \">=\", from));\n if (to) conditions.push(cond(key, \"<=\", to));\n continue;\n }\n\n // between → one condition with a 2-tuple value\n if (d.between) {\n const from = searchParams.get(d.between[0]);\n const to = searchParams.get(d.between[1]);\n if (from && to) conditions.push(cond(key, \"between\", [from, to]));\n continue;\n }\n\n // read value, falling back to `default` only when the param is ABSENT\n // (an empty `?x=` means the user cleared the filter → prune, don't default).\n const raw = searchParams.get(param);\n let value: FilterValue | undefined = raw !== null ? raw : d.default;\n if (typeof value === \"string\" && d.trim) value = value.trim();\n if (value === undefined || value === null || value === \"\") continue;\n if (Array.isArray(value) && value.length === 0) continue;\n\n // search → OR of `contains` across the listed fields (needs a string)\n if (d.search && typeof value === \"string\") {\n groups.push({ or: d.search.map(field => cond(field, \"%_%\", value as string)) });\n continue;\n }\n\n // split → comma-string → array (for `in`/`notIn`); guarded against empties\n if (d.split && typeof value === \"string\") {\n const delimiter = d.split === true ? \",\" : d.split;\n const parts = value\n .split(delimiter)\n .map(s => s.trim())\n .filter(Boolean);\n if (parts.length === 0) continue;\n value = parts;\n }\n\n conditions.push(cond(key, d.operation ?? \"=\", value));\n }\n\n return groups.length === 0 ? conditions : { and: [...groups, ...conditions] };\n}\n\nfunction cond(key: string, operation: FieldCondition[\"operation\"], value: FilterValue): FieldCondition {\n return { key, operation, value };\n}\n\n/**\n * The bounds the URL readers clamp to — the builder's own (`createRegistry`\n * `defaults`); an absent one is the core default.\n */\nexport interface UrlLimits {\n perPage?: number;\n maxPerPage?: number;\n maxOffset?: number;\n maxSortFields?: number;\n}\n\n/** {@link ListParams} read from a URL. `clamped` — the URL's page or sort was cut to the limits. */\nexport type UrlListParams = ListParams & { clamped: boolean };\n\n/**\n * A list payload built from a URL. `clamped` is non-enumerable: readable in code,\n * never serialized, so the wire payload is unchanged.\n */\nexport type UrlListPayload = ListPayload & { readonly clamped?: boolean };\n\n/** Marks a payload with a non-enumerable `clamped` flag. */\nexport function withClamped(payload: ListPayload, clamped: boolean): UrlListPayload {\n return Object.defineProperty(payload, \"clamped\", { value: clamped, enumerable: false });\n}\n\n/** The last page the builder accepts: `(page - 1) × perPage ≤ maxOffset`. */\nfunction lastPage(perPage: number | undefined, limits: UrlLimits): number {\n const resolved = clampInt(perPage, limits.perPage ?? DEFAULT_PER_PAGE, limits.maxPerPage ?? DEFAULT_MAX_PER_PAGE);\n return Math.floor((limits.maxOffset ?? DEFAULT_MAX_OFFSET) / resolved) + 1;\n}\n\n/**\n * searchParams → normalizatsiyalanmagan {@link ListParams} (filter/sort/page/perPage).\n * The URL is user input: a page past `maxOffset` becomes the last allowed page and a\n * sort past `maxSortFields` keeps its first fields, with `clamped: true` — so a\n * hand-edited `?page=9999` never throws during render. The builders still throw\n * for a direct call.\n */\nexport function readListParams(schema: ListSchema, searchParams: URLSearchParams, url: UrlConfig = {}, limits: UrlLimits = {}): UrlListParams {\n const cfg = { ...URL_DEFAULTS, ...url };\n const size = searchParams.get(cfg.sizeParam);\n const perPage = size ? Number(size) : undefined;\n const page = Math.trunc(Number(searchParams.get(cfg.pageParam))) || 1;\n const sort = decodeSort(searchParams.get(cfg.sortParam));\n const maxPage = lastPage(perPage, limits);\n const maxSortFields = limits.maxSortFields ?? DEFAULT_MAX_SORT_FIELDS;\n const isPageClamped = page > maxPage;\n const isSortClamped = sort !== undefined && sort.length > maxSortFields;\n return {\n filter: schemaToFilter(schema, searchParams),\n sort: isSortClamped ? sort.slice(0, maxSortFields) : sort,\n page: isPageClamped ? maxPage : page,\n perPage,\n clamped: isPageClamped || isSortClamped,\n };\n}\n\n/** searchParams → to'liq, yuborishga tayyor {@link ListPayload} (core default limits; clamped like {@link readListParams}). */\nexport function searchParamsToPayload(schema: ListSchema, searchParams: URLSearchParams, url?: UrlConfig): UrlListPayload {\n const params = readListParams(schema, searchParams, url);\n return withClamped(buildListParams(params), params.clamped);\n}\n\n/* ------------------------- URL yozish (immutable) ------------------------- */\n/* Har biri YANGI URLSearchParams qaytaradi; filter/sort o'zgarsa `page` reset. */\n\nfunction clone(searchParams: URLSearchParams): URLSearchParams {\n return new URLSearchParams(searchParams);\n}\n\n/** Filter param'ini o'rnatadi/o'chiradi va `page`ni reset qiladi. */\nexport function setParam(searchParams: URLSearchParams, name: string, value: string | null | undefined, url: UrlConfig = {}): URLSearchParams {\n const cfg = { ...URL_DEFAULTS, ...url };\n const next = clone(searchParams);\n next.delete(cfg.pageParam);\n if (value === null || value === undefined || value === \"\") next.delete(name);\n else next.set(name, value);\n return next;\n}\n\n/** Sahifani o'rnatadi (`page` reset qilinmaydi). */\nexport function setPage(searchParams: URLSearchParams, page: number, url: UrlConfig = {}): URLSearchParams {\n const cfg = { ...URL_DEFAULTS, ...url };\n const next = clone(searchParams);\n next.set(cfg.pageParam, String(page));\n return next;\n}\n\n/** Sahifa o'lchamini o'rnatadi va `page`ni reset qiladi. */\nexport function setSize(searchParams: URLSearchParams, size: number, url: UrlConfig = {}): URLSearchParams {\n const cfg = { ...URL_DEFAULTS, ...url };\n const next = clone(searchParams);\n next.delete(cfg.pageParam);\n next.set(cfg.sizeParam, String(size));\n return next;\n}\n\n/** Sortni o'rnatadi (`[{ key, direction }, …]`) va `page`ni reset qiladi. */\nexport function setSort(searchParams: URLSearchParams, sort: SortInput, url: UrlConfig = {}): URLSearchParams {\n const cfg = { ...URL_DEFAULTS, ...url };\n const next = clone(searchParams);\n next.delete(cfg.pageParam);\n const encoded = encodeSort(sort);\n if (encoded) next.set(cfg.sortParam, encoded);\n else next.delete(cfg.sortParam);\n return next;\n}\n\n/** Barcha list param'larini tozalaydi (ixtiyoriy saqlanadigan kalitlar bilan). */\nexport function resetParams(searchParams: URLSearchParams, keep: string[] = []): URLSearchParams {\n const next = new URLSearchParams();\n for (const key of keep) {\n const value = searchParams.get(key);\n if (value !== null) next.set(key, value);\n }\n return next;\n}\n","import type { AdapterName, WithFor } from \"./adapter\";\nimport type { Resource } from \"./registry\";\nimport type { ListSchema } from \"./schema\";\nimport type { ListPayload, SortInput } from \"./types\";\nimport type { UrlConfig } from \"./url\";\nimport { resetParams, setPage, setParam, setSize, setSort } from \"./url\";\n\nexport interface ListStateOptions<A extends AdapterName> {\n /** URL↔filter schema ({@link defineListSchema} / `resource.schema`). */\n schema: ListSchema;\n /** URL param names (page/size/sortType) — optional. */\n url?: UrlConfig;\n /** Fixed relations to load on every request (not URL-driven). */\n with?: WithFor<A>;\n}\n\nexport interface ListStateRead {\n /** Ready-to-send list payload (built from the URL via the resource's defaults). */\n params: ListPayload;\n /** The URL's page or sort was past the limits and was clamped (`?page=9999` → the last allowed page). */\n clamped: boolean;\n}\n\n/** URL setters: each returns the NEXT search params and never mutates the given ones. */\nexport interface ListStateActions {\n /** Set/clear a filter param (resets `page`). */\n setParam: (name: string, value: string | null | undefined) => URLSearchParams;\n setPage: (page: number) => URLSearchParams;\n /** Resets `page`. */\n setSize: (size: number) => URLSearchParams;\n /** Resets `page`; an empty sort clears the param. */\n setSort: (sort: SortInput) => URLSearchParams;\n /** Clears every param except `keep`. */\n reset: (keep?: string[]) => URLSearchParams;\n}\n\nexport interface ListState {\n read: (searchParams: URLSearchParams) => ListStateRead;\n actions: (searchParams: URLSearchParams) => ListStateActions;\n}\n\n/**\n * Framework-free list URL state — the logic behind `useListParams` in `@querykitjs/web/react`\n * and `@querykitjs/web/vue`, for any other framework (Svelte, Solid, vanilla). Pure: it reads\n * search params and returns the next ones; navigating is the caller's job.\n *\n * @example\n * ```ts\n * const list = createListState(users, { schema: usersSchema });\n * const { params, clamped } = list.read(new URLSearchParams(location.search));\n * history.pushState(null, \"\", `?${list.actions(new URLSearchParams(location.search)).setPage(2)}`);\n * ```\n */\nexport function createListState<T, A extends AdapterName>(resource: Resource<T, A>, options: ListStateOptions<A>): ListState {\n const { schema, url, with: withRel } = options;\n return {\n read(searchParams) {\n const params = resource.fromSearchParams(searchParams, { schema, url, with: withRel });\n return { params, clamped: params.clamped === true };\n },\n actions(searchParams) {\n return {\n setParam: (name, value) => setParam(searchParams, name, value, url),\n setPage: page => setPage(searchParams, page, url),\n setSize: size => setSize(searchParams, size, url),\n setSort: sort => setSort(searchParams, sort, url),\n reset: keep => resetParams(searchParams, keep),\n };\n },\n };\n}\n","import { computed, type Signal } from \"@angular/core\";\n\nimport type { AdapterName, WithFor } from \"../adapter\";\nimport { createListState } from \"../list-state\";\nimport type { Resource } from \"../registry\";\nimport type { ListSchema } from \"../schema\";\nimport type { ListPayload, SortInput } from \"../types\";\nimport type { UrlConfig } from \"../url\";\n\nexport interface InjectListParamsBaseOptions<A extends AdapterName> {\n /** URL↔filter schema ({@link defineListSchema} / `resource.schema`). */\n schema: ListSchema;\n /** Current URL search params as a signal (from your router). */\n searchParams: Signal<URLSearchParams>;\n /** Apply new search params (`(next) => void`). */\n setSearchParams: (next: URLSearchParams) => void;\n /** URL param names (page/size/sortType) — optional. */\n url?: UrlConfig;\n /** Fixed relations to load on every request (not URL-driven). */\n with?: WithFor<A>;\n}\n\nexport interface InjectListParamsResult {\n /** Ready-to-send list payload (built from the URL via the resource's defaults). */\n params: Signal<ListPayload>;\n /**\n * The URL's page or sort was past the limits and was clamped (`?page=9999` → the last\n * allowed page). The app may rewrite the URL (`setPage(params().page)`).\n */\n clamped: Signal<boolean>;\n searchParams: Signal<URLSearchParams>;\n /** Set/clear a filter param (resets `page`). */\n setParam: (name: string, value: string | null | undefined) => void;\n setPage: (page: number) => void;\n /** Resets `page`. */\n setSize: (size: number) => void;\n /** Resets `page`; an empty sort clears the param. */\n setSort: (sort: SortInput) => void;\n /** Clears every param except `keep`. */\n reset: (keep?: string[]) => void;\n}\n\n/**\n * Router-agnostic list URL state as signals — the Angular twin of the React and Vue\n * `useListParamsBase`: the same reads, clamping and setters. Bring your own\n * `searchParams` signal and `setSearchParams`.\n */\nexport function injectListParamsBase<T, A extends AdapterName>(resource: Resource<T, A>, options: InjectListParamsBaseOptions<A>): InjectListParamsResult {\n const { schema, searchParams, setSearchParams, url, with: withRel } = options;\n const state = createListState(resource, { schema, url, with: withRel });\n const read = computed(() => state.read(searchParams()));\n const actions = () => state.actions(searchParams());\n\n return {\n params: computed(() => read().params),\n clamped: computed(() => read().clamped),\n searchParams,\n setParam: (name, value) => setSearchParams(actions().setParam(name, value)),\n setPage: page => setSearchParams(actions().setPage(page)),\n setSize: size => setSearchParams(actions().setSize(size)),\n setSort: sort => setSearchParams(actions().setSort(sort)),\n reset: keep => setSearchParams(actions().reset(keep)),\n };\n}\n","import { computed, inject } from \"@angular/core\";\nimport { toSignal } from \"@angular/core/rxjs-interop\";\nimport { ActivatedRoute, type ParamMap, Router } from \"@angular/router\";\n\nimport type { AdapterName, WithFor } from \"../adapter\";\nimport type { Resource } from \"../registry\";\nimport { searchParamsToQuery } from \"../route-query\";\nimport type { ListSchema } from \"../schema\";\nimport type { UrlConfig } from \"../url\";\nimport { injectListParamsBase, type InjectListParamsResult } from \"./inject-list-params-base\";\n\nexport interface InjectListParamsOptions<A extends AdapterName> {\n /** URL↔filter schema ({@link defineListSchema} / `resource.schema`). */\n schema: ListSchema;\n /** URL param names (page/size/sortType) — optional. */\n url?: UrlConfig;\n /** Fixed relations to load on every request (not URL-driven). */\n with?: WithFor<A>;\n}\n\nfunction paramMapToSearchParams(paramMap: ParamMap): URLSearchParams {\n return new URLSearchParams(paramMap.keys.flatMap(key => paramMap.getAll(key).map(value => [key, value])));\n}\n\n/**\n * List URL state as signals, with the Angular **Router** (`ActivatedRoute` + `Router`).\n * Reads filters/sort/page from the query params via the schema, builds a ready-to-send\n * payload through the `resource`, and returns URL setters that `router.navigate` (a new\n * history entry; filter/sort/size changes reset `page`). Does **not** fetch. Call it in an\n * injection context (a field initializer or a constructor); elsewhere Angular throws `NG0203`.\n *\n * @example\n * ```ts\n * @Component({ template: `<button (click)=\"list.setPage(2)\">2</button>` })\n * class UsersPage {\n * readonly list = injectListParams(users, { schema: usersSchema });\n * readonly payload = computed(() => this.list.params());\n * }\n * ```\n */\nexport function injectListParams<T, A extends AdapterName>(resource: Resource<T, A>, options: InjectListParamsOptions<A>): InjectListParamsResult {\n const route = inject(ActivatedRoute);\n const router = inject(Router);\n // `queryParamMap` replays its current value on subscribe, so the signal is never empty.\n const paramMap = toSignal(route.queryParamMap, { requireSync: true });\n return injectListParamsBase(resource, {\n ...options,\n searchParams: computed(() => paramMapToSearchParams(paramMap())),\n setSearchParams: next => void router.navigate([], { relativeTo: route, queryParams: searchParamsToQuery(next) }),\n });\n}\n"]}
package/dist/index.cjs CHANGED
@@ -1,361 +1,2 @@
1
- 'use strict';
2
-
3
- var core = require('@querykitjs/core');
4
-
5
- // src/filters.ts
6
- function createFilters() {
7
- return core.createFilters();
8
- }
9
- var DEFAULTS = {
10
- filterField: "filter",
11
- sortField: "sort",
12
- columnsField: "columns",
13
- withField: "with",
14
- withDeletedField: "withDeleted",
15
- pageField: "page",
16
- perPageField: "perPage",
17
- limitField: "limit",
18
- offsetField: "offset",
19
- cursorField: "cursor",
20
- defaultPerPage: core.DEFAULT_PER_PAGE,
21
- defaultLimit: core.DEFAULT_LIMIT,
22
- maxPerPage: core.DEFAULT_MAX_PER_PAGE,
23
- maxLimit: core.DEFAULT_MAX_LIMIT,
24
- defaultSort: [{ key: "createdAt", direction: "desc" }],
25
- pruneEmpty: true
26
- };
27
- function isEmptyValue(value) {
28
- if (value === void 0 || value === null || value === "") return true;
29
- if (Array.isArray(value) && value.length === 0) return true;
30
- return false;
31
- }
32
- function toSortItem(item) {
33
- if (typeof item === "string") {
34
- const desc = item.startsWith("-");
35
- const key = (desc ? item.slice(1) : item).trim();
36
- return key ? { key, direction: desc ? "desc" : "asc" } : void 0;
37
- }
38
- return item && item.key ? { key: item.key, direction: item.direction ?? "asc" } : void 0;
39
- }
40
- function normalizeSort(input, fallback) {
41
- if (!input || input.length === 0) return fallback;
42
- const items = input.map(toSortItem).filter((i) => i !== void 0);
43
- return items.length ? items : fallback;
44
- }
45
- function normalizeCondition(condition, prune) {
46
- const operation = condition.operation ?? "=";
47
- const noValue = operation === "isNull" || operation === "isNotNull";
48
- const value = condition.value;
49
- if (!noValue && prune && isEmptyValue(value)) return void 0;
50
- const out = { key: condition.key, operation };
51
- if (!noValue) out.value = value;
52
- return out;
53
- }
54
- function normalizeNode(node, prune) {
55
- if ("and" in node) {
56
- const kids = node.and.map((n) => normalizeNode(n, prune)).filter((n) => !!n);
57
- return kids.length ? { and: kids } : void 0;
58
- }
59
- if ("or" in node) {
60
- const kids = node.or.map((n) => normalizeNode(n, prune)).filter((n) => !!n);
61
- return kids.length ? { or: kids } : void 0;
62
- }
63
- if ("not" in node) {
64
- const inner = normalizeNode(node.not, prune);
65
- return inner ? { not: inner } : void 0;
66
- }
67
- return normalizeCondition(node, prune);
68
- }
69
- function normalizeFilter(filter, prune) {
70
- if (!filter) return [];
71
- if (Array.isArray(filter)) {
72
- return filter.map((c) => normalizeCondition(c, prune)).filter((c) => !!c);
73
- }
74
- return normalizeNode(filter, prune) ?? [];
75
- }
76
- function buildBase(input, cfg) {
77
- const base = {
78
- [cfg.filterField]: normalizeFilter(input.filter, cfg.pruneEmpty),
79
- [cfg.columnsField]: input.columns ?? {},
80
- [cfg.withField]: input.with ?? {}
81
- };
82
- if (input.withDeleted !== void 0) base[cfg.withDeletedField] = input.withDeleted;
83
- return base;
84
- }
85
- function clampInt(value, fallback, max = Infinity) {
86
- const resolved = value === void 0 || value < 1 || Number.isNaN(value) ? fallback : Math.trunc(value);
87
- return Math.min(max, resolved);
88
- }
89
- function build(input, cfg) {
90
- return { ...buildBase(input, cfg), [cfg.sortField]: normalizeSort(input.sort, cfg.defaultSort) };
91
- }
92
- function buildList(input, cfg) {
93
- return {
94
- ...build(input, cfg),
95
- [cfg.pageField]: clampInt(input.page, 1),
96
- // page >= 1 (kasr/0/manfiy → 1)
97
- [cfg.perPageField]: clampInt(input.perPage, cfg.defaultPerPage, cfg.maxPerPage)
98
- };
99
- }
100
- function buildInfinite(input, cfg) {
101
- return {
102
- ...build(input, cfg),
103
- [cfg.limitField]: clampInt(input.limit, cfg.defaultLimit, cfg.maxLimit),
104
- [cfg.offsetField]: input.offset && input.offset > 0 ? Math.trunc(input.offset) : 0
105
- };
106
- }
107
- function buildCursor(input, cfg) {
108
- const payload = {
109
- ...buildBase(input, cfg),
110
- [cfg.limitField]: clampInt(input.limit, cfg.defaultLimit, cfg.maxLimit),
111
- [cfg.cursorField]: input.cursor ?? null,
112
- order: input.order ?? "asc",
113
- direction: input.direction ?? "forward"
114
- };
115
- if (input.cursorKey !== void 0) payload.cursorKey = input.cursorKey;
116
- return payload;
117
- }
118
- function createQuery(config = {}) {
119
- const cfg = { ...DEFAULTS, ...config };
120
- return {
121
- params: (input = {}) => build(input, cfg),
122
- list: (input = {}) => buildList(input, cfg),
123
- infinite: (input = {}) => buildInfinite(input, cfg),
124
- cursor: (input = {}) => buildCursor(input, cfg)
125
- };
126
- }
127
- function buildParams(input = {}) {
128
- return build(input, DEFAULTS);
129
- }
130
- function buildListParams(input = {}) {
131
- return buildList(input, DEFAULTS);
132
- }
133
- function buildInfiniteParams(input = {}) {
134
- return buildInfinite(input, DEFAULTS);
135
- }
136
- function buildCursorParams(input = {}) {
137
- return buildCursor(input, DEFAULTS);
138
- }
139
-
140
- // src/meta.ts
141
- function mapMeta(raw) {
142
- return {
143
- totalPages: raw?.total_pages ?? 0,
144
- totalCount: raw?.total_items ?? 0,
145
- currentPage: raw?.current_page ?? 0,
146
- perPage: raw?.per_page ?? 0,
147
- hasNext: raw?.has_next ?? false,
148
- hasPrev: raw?.has_prev ?? false
149
- };
150
- }
151
- function mapInfiniteMeta(raw) {
152
- return {
153
- limit: raw?.limit ?? 0,
154
- offset: raw?.offset ?? 0,
155
- count: raw?.count ?? 0,
156
- hasMore: raw?.has_more ?? false,
157
- nextOffset: raw?.next_offset ?? null
158
- };
159
- }
160
- function mapCursorMeta(raw) {
161
- return {
162
- limit: raw?.limit ?? 0,
163
- hasNext: raw?.has_next ?? false,
164
- hasPrev: raw?.has_prev ?? false,
165
- nextCursor: raw?.next_cursor ?? null,
166
- prevCursor: raw?.prev_cursor ?? null
167
- };
168
- }
169
-
170
- // src/schema.ts
171
- function defineListSchema(schema) {
172
- return schema;
173
- }
174
-
175
- // src/url.ts
176
- var URL_DEFAULTS = {
177
- pageParam: "page",
178
- sizeParam: "size",
179
- sortParam: "sortType"
180
- };
181
- function decodeSort(value) {
182
- if (!value) return void 0;
183
- const items = value.split(",").map((s) => s.trim()).filter(Boolean).map((tok) => {
184
- const desc = tok.startsWith("-");
185
- return { key: desc ? tok.slice(1) : tok, direction: desc ? "desc" : "asc" };
186
- }).filter((i) => i.key);
187
- return items.length ? items : void 0;
188
- }
189
- function encodeSort(sort) {
190
- return sort.map((i) => typeof i === "string" ? i.trim() : i && i.key ? (i.direction === "desc" ? "-" : "") + i.key : "").filter(Boolean).join(",");
191
- }
192
- function schemaToFilter(schema, searchParams) {
193
- const conditions = [];
194
- const groups = [];
195
- for (const [param, d] of Object.entries(schema)) {
196
- const key = d.key ?? param;
197
- if (d.range) {
198
- const from = searchParams.get(d.range[0]);
199
- const to = searchParams.get(d.range[1]);
200
- if (from) conditions.push(cond(key, ">=", from));
201
- if (to) conditions.push(cond(key, "<=", to));
202
- continue;
203
- }
204
- if (d.between) {
205
- const from = searchParams.get(d.between[0]);
206
- const to = searchParams.get(d.between[1]);
207
- if (from && to) conditions.push(cond(key, "between", [from, to]));
208
- continue;
209
- }
210
- const raw = searchParams.get(param);
211
- let value = raw !== null ? raw : d.default;
212
- if (typeof value === "string" && d.trim) value = value.trim();
213
- if (value === void 0 || value === null || value === "") continue;
214
- if (Array.isArray(value) && value.length === 0) continue;
215
- if (d.search && typeof value === "string") {
216
- groups.push({ or: d.search.map((field) => cond(field, "%_%", value)) });
217
- continue;
218
- }
219
- if (d.split && typeof value === "string") {
220
- const delimiter = d.split === true ? "," : d.split;
221
- const parts = value.split(delimiter).map((s) => s.trim()).filter(Boolean);
222
- if (parts.length === 0) continue;
223
- value = parts;
224
- }
225
- conditions.push(cond(key, d.operation ?? "=", value));
226
- }
227
- return groups.length === 0 ? conditions : { and: [...groups, ...conditions] };
228
- }
229
- function cond(key, operation, value) {
230
- return { key, operation, value };
231
- }
232
- function readListParams(schema, searchParams, url = {}) {
233
- const cfg = { ...URL_DEFAULTS, ...url };
234
- const size = searchParams.get(cfg.sizeParam);
235
- return {
236
- filter: schemaToFilter(schema, searchParams),
237
- sort: decodeSort(searchParams.get(cfg.sortParam)),
238
- page: Number(searchParams.get(cfg.pageParam)) || 1,
239
- perPage: size ? Number(size) : void 0
240
- };
241
- }
242
- function searchParamsToPayload(schema, searchParams, url) {
243
- return buildListParams(readListParams(schema, searchParams, url));
244
- }
245
- function clone(searchParams) {
246
- return new URLSearchParams(searchParams);
247
- }
248
- function setParam(searchParams, name, value, url = {}) {
249
- const cfg = { ...URL_DEFAULTS, ...url };
250
- const next = clone(searchParams);
251
- next.delete(cfg.pageParam);
252
- if (value === null || value === void 0 || value === "") next.delete(name);
253
- else next.set(name, value);
254
- return next;
255
- }
256
- function setPage(searchParams, page, url = {}) {
257
- const cfg = { ...URL_DEFAULTS, ...url };
258
- const next = clone(searchParams);
259
- next.set(cfg.pageParam, String(page));
260
- return next;
261
- }
262
- function setSize(searchParams, size, url = {}) {
263
- const cfg = { ...URL_DEFAULTS, ...url };
264
- const next = clone(searchParams);
265
- next.delete(cfg.pageParam);
266
- next.set(cfg.sizeParam, String(size));
267
- return next;
268
- }
269
- function setSort(searchParams, sort, url = {}) {
270
- const cfg = { ...URL_DEFAULTS, ...url };
271
- const next = clone(searchParams);
272
- next.delete(cfg.pageParam);
273
- const encoded = encodeSort(sort);
274
- if (encoded) next.set(cfg.sortParam, encoded);
275
- else next.delete(cfg.sortParam);
276
- return next;
277
- }
278
- function resetParams(searchParams, keep = []) {
279
- const next = new URLSearchParams();
280
- for (const key of keep) {
281
- const value = searchParams.get(key);
282
- if (value !== null) next.set(key, value);
283
- }
284
- return next;
285
- }
286
-
287
- // src/registry.ts
288
- function createRegistry(config) {
289
- const defaults = config.defaults ?? {};
290
- const sort = normalizeSort(defaults.sort, []);
291
- const cursorOrder = defaults.cursor?.order ?? "asc";
292
- const qcfg = {};
293
- if (defaults.perPage !== void 0) qcfg.defaultPerPage = defaults.perPage;
294
- if (defaults.limit !== void 0) qcfg.defaultLimit = defaults.limit;
295
- if (defaults.maxPerPage !== void 0) qcfg.maxPerPage = defaults.maxPerPage;
296
- if (defaults.maxLimit !== void 0) qcfg.maxLimit = defaults.maxLimit;
297
- if (sort.length) qcfg.defaultSort = sort;
298
- if (config.pruneEmpty !== void 0) qcfg.pruneEmpty = config.pruneEmpty;
299
- const q = createQuery(qcfg);
300
- const parseList = (raw) => ({ data: raw?.data ?? [], meta: mapMeta(raw?.meta) });
301
- const parseInfinite = (raw) => ({
302
- data: raw?.data ?? [],
303
- meta: mapInfiniteMeta(raw?.meta)
304
- });
305
- const parseCursor = (raw) => ({
306
- data: raw?.data ?? [],
307
- meta: mapCursorMeta(raw?.meta)
308
- });
309
- function resource(name) {
310
- const f2 = createFilters();
311
- const keys = {
312
- all: [name],
313
- list: (p) => [name, "list", p],
314
- infinite: (p) => [name, "infinite", p],
315
- cursor: (p) => [name, "cursor", p],
316
- detail: (id) => [name, "detail", id]
317
- };
318
- return {
319
- list: (input) => q.list(input),
320
- infinite: (input) => q.infinite(input),
321
- cursor: (input) => q.cursor({ ...input, order: input?.order ?? cursorOrder }),
322
- params: (input) => q.params(input),
323
- f: f2,
324
- search: (term, fields) => core.f.or(...fields.map((field) => core.f.contains(field, term))),
325
- schema: (s) => defineListSchema(s),
326
- fromSearchParams: (searchParams, options) => q.list({ ...readListParams(options.schema, searchParams, options.url), with: options.with }),
327
- keys,
328
- parseList: (raw) => parseList(raw),
329
- parseInfinite: (raw) => parseInfinite(raw),
330
- parseCursor: (raw) => parseCursor(raw)
331
- };
332
- }
333
- return { adapter: config.adapter, resource, parseList, parseInfinite, parseCursor };
334
- }
335
-
336
- Object.defineProperty(exports, "f", {
337
- enumerable: true,
338
- get: function () { return core.f; }
339
- });
340
- exports.buildCursorParams = buildCursorParams;
341
- exports.buildInfiniteParams = buildInfiniteParams;
342
- exports.buildListParams = buildListParams;
343
- exports.buildParams = buildParams;
344
- exports.createFilters = createFilters;
345
- exports.createQuery = createQuery;
346
- exports.createRegistry = createRegistry;
347
- exports.decodeSort = decodeSort;
348
- exports.defineListSchema = defineListSchema;
349
- exports.encodeSort = encodeSort;
350
- exports.normalizeFilter = normalizeFilter;
351
- exports.normalizeSort = normalizeSort;
352
- exports.readListParams = readListParams;
353
- exports.resetParams = resetParams;
354
- exports.schemaToFilter = schemaToFilter;
355
- exports.searchParamsToPayload = searchParamsToPayload;
356
- exports.setPage = setPage;
357
- exports.setParam = setParam;
358
- exports.setSize = setSize;
359
- exports.setSort = setSort;
360
- //# sourceMappingURL=index.cjs.map
1
+ 'use strict';var core=require('@querykitjs/core');function k(){return core.createFilters()}var P={filterField:"filter",sortField:"sort",columnsField:"columns",withField:"with",withDeletedField:"withDeleted",withTotalField:"withTotal",pageField:"page",perPageField:"perPage",limitField:"limit",offsetField:"offset",cursorField:"cursor",defaultPerPage:core.DEFAULT_PER_PAGE,defaultLimit:core.DEFAULT_LIMIT,maxPerPage:core.DEFAULT_MAX_PER_PAGE,maxLimit:core.DEFAULT_MAX_LIMIT,maxOffset:core.DEFAULT_MAX_OFFSET,maxSortFields:core.DEFAULT_MAX_SORT_FIELDS,defaultSort:[{key:"createdAt",direction:"desc"}],pruneEmpty:true};function se(e){return !!(e==null||e===""||Array.isArray(e)&&e.length===0)}function le(e){if(typeof e=="string"){let t=e.startsWith("-"),r=(t?e.slice(1):e).trim();return r?{key:r,direction:t?"desc":"asc"}:void 0}return e&&e.key?{key:e.key,direction:e.direction??"asc"}:void 0}function L(e,t){if(!e||e.length===0)return t;let r=e.map(le).filter(n=>n!==void 0);return r.length?r:t}function D(e,t){let r=e.operation??"=",n=r==="isNull"||r==="isNotNull",a=e.value;if(!n&&t&&se(a))return;let i={key:e.key,operation:r};return n||(i.value=a),i}function h(e,t){if("and"in e){let r=e.and.map(n=>h(n,t)).filter(n=>!!n);return r.length?{and:r}:void 0}if("or"in e){let r=e.or.map(n=>h(n,t)).filter(n=>!!n);return r.length?{or:r}:void 0}if("not"in e){let r=h(e.not,t);return r?{not:r}:void 0}return D(e,t)}function _(e,t){return e?Array.isArray(e)?e.map(r=>D(r,t)).filter(r=>!!r):h(e,t)??[]:[]}function Q(e,t){let r={[t.filterField]:_(e.filter,t.pruneEmpty),[t.columnsField]:e.columns??{},[t.withField]:e.with??{}};return e.withDeleted!==void 0&&(r[t.withDeletedField]=e.withDeleted),r}function c(e,t,r=1/0){let n=e===void 0||e<1||Number.isNaN(e)?t:Math.trunc(e);return Math.min(r,n)}function b(e,t,r,n=""){return new Error(`querykit: ${e} exceeds ${t} (${r})${n}`)}function T(e,t){let r=L(e.sort,t.defaultSort);if(r.length>t.maxSortFields)throw b(`sort with ${r.length} fields`,"maxSortFields",t.maxSortFields);return {...Q(e,t),[t.sortField]:r}}var V="; use cursor pagination for deeper pages";function v(e,t){let r=c(e.page,1),n=c(e.perPage,t.defaultPerPage,t.maxPerPage);if((r-1)*n>t.maxOffset)throw b(`page ${r} \xD7 perPage ${n}`,"maxOffset",t.maxOffset,V);let a={...T(e,t),[t.pageField]:r,[t.perPageField]:n};return e.withTotal!==void 0&&(a[t.withTotalField]=e.withTotal),a}function z(e,t){let r=e.offset&&e.offset>0?Math.trunc(e.offset):0;if(r>t.maxOffset)throw b(`offset ${r}`,"maxOffset",t.maxOffset,V);return {...T(e,t),[t.limitField]:c(e.limit,t.defaultLimit,t.maxLimit),[t.offsetField]:r}}function W(e,t){let r={...Q(e,t),[t.limitField]:c(e.limit,t.defaultLimit,t.maxLimit),[t.cursorField]:e.cursor??null,order:e.order??"asc",direction:e.direction??"forward"};return e.cursorKey!==void 0&&(r.cursorKey=e.cursorKey),r}function K(e={}){let t={...P,...e};return {params:(r={})=>T(r,t),list:(r={})=>v(r,t),infinite:(r={})=>z(r,t),cursor:(r={})=>W(r,t)}}function ue(e={}){return T(e,P)}function A(e={}){return v(e,P)}function de(e={}){return z(e,P)}function me(e={}){return W(e,P)}var B=e=>e===null?null:e??0;function q(e){return {totalPages:B(e?.total_pages),totalCount:B(e?.total_items),currentPage:e?.current_page??0,perPage:e?.per_page??0,hasNext:e?.has_next??false,hasPrev:e?.has_prev??false}}function G(e){return {limit:e?.limit??0,offset:e?.offset??0,count:e?.count??0,hasMore:e?.has_more??false,nextOffset:e?.next_offset??null}}function $(e){return {limit:e?.limit??0,hasNext:e?.has_next??false,hasPrev:e?.has_prev??false,nextCursor:e?.next_cursor??null,prevCursor:e?.prev_cursor??null}}function pe(e){return e}var F={pageParam:"page",sizeParam:"size",sortParam:"sortType"};function X(e){if(!e)return;let t=e.split(",").map(r=>r.trim()).filter(Boolean).map(r=>{let n=r.startsWith("-");return {key:n?r.slice(1):r,direction:n?"desc":"asc"}}).filter(r=>r.key);return t.length?t:void 0}function j(e){return e.map(t=>typeof t=="string"?t.trim():t&&t.key?(t.direction==="desc"?"-":"")+t.key:"").filter(Boolean).join(",")}function H(e,t){let r=[],n=[];for(let[a,i]of Object.entries(e)){let o=i.key??a;if(i.range){let u=t.get(i.range[0]),d=t.get(i.range[1]);u&&r.push(g(o,">=",u)),d&&r.push(g(o,"<=",d));continue}if(i.between){let u=t.get(i.between[0]),d=t.get(i.between[1]);u&&d&&r.push(g(o,"between",[u,d]));continue}let p=t.get(a),l=p!==null?p:i.default;if(typeof l=="string"&&i.trim&&(l=l.trim()),!(l==null||l==="")&&!(Array.isArray(l)&&l.length===0)){if(i.search&&typeof l=="string"){n.push({or:i.search.map(u=>g(u,"%_%",l))});continue}if(i.split&&typeof l=="string"){let u=i.split===true?",":i.split,d=l.split(u).map(f=>f.trim()).filter(Boolean);if(d.length===0)continue;l=d;}r.push(g(o,i.operation??"=",l));}}return n.length===0?r:{and:[...n,...r]}}function g(e,t,r){return {key:e,operation:t,value:r}}function U(e,t){return Object.defineProperty(e,"clamped",{value:t,enumerable:false})}function ge(e,t){let r=c(e,t.perPage??core.DEFAULT_PER_PAGE,t.maxPerPage??core.DEFAULT_MAX_PER_PAGE);return Math.floor((t.maxOffset??core.DEFAULT_MAX_OFFSET)/r)+1}function w(e,t,r={},n={}){let a={...F,...r},i=t.get(a.sizeParam),o=i?Number(i):void 0,p=Math.trunc(Number(t.get(a.pageParam)))||1,l=X(t.get(a.sortParam)),u=ge(o,n),d=n.maxSortFields??core.DEFAULT_MAX_SORT_FIELDS,f=p>u,x=l!==void 0&&l.length>d;return {filter:H(e,t),sort:x?l.slice(0,d):l,page:f?u:p,perPage:o,clamped:f||x}}function Fe(e,t,r){let n=w(e,t,r);return U(A(n),n.clamped)}function C(e){return new URLSearchParams(e)}function I(e,t,r,n={}){let a={...F,...n},i=C(e);return i.delete(a.pageParam),r==null||r===""?i.delete(t):i.set(t,r),i}function M(e,t,r={}){let n={...F,...r},a=C(e);return a.set(n.pageParam,String(t)),a}function N(e,t,r={}){let n={...F,...r},a=C(e);return a.delete(n.pageParam),a.set(n.sizeParam,String(t)),a}function E(e,t,r={}){let n={...F,...r},a=C(e);a.delete(n.pageParam);let i=j(t);return i?a.set(n.sortParam,i):a.delete(n.sortParam),a}function O(e,t=[]){let r=new URLSearchParams;for(let n of t){let a=e.get(n);a!==null&&r.set(n,a);}return r}function xe(e){let t=e.defaults??{},r=e.timestamps?.createdAt,n=r?[{key:r,direction:"desc"}]:[],a=L(t.sort,n),i=t.cursor?.order??"asc",o={};t.perPage!==void 0&&(o.defaultPerPage=t.perPage),t.limit!==void 0&&(o.defaultLimit=t.limit),t.maxPerPage!==void 0&&(o.maxPerPage=t.maxPerPage),t.maxLimit!==void 0&&(o.maxLimit=t.maxLimit),t.maxOffset!==void 0&&(o.maxOffset=t.maxOffset),t.maxSortFields!==void 0&&(o.maxSortFields=t.maxSortFields),a.length&&(o.defaultSort=a),e.pruneEmpty!==void 0&&(o.pruneEmpty=e.pruneEmpty);let p=K(o),l={perPage:t.perPage,maxPerPage:t.maxPerPage,maxOffset:t.maxOffset,maxSortFields:t.maxSortFields},u=m=>({data:m?.data??[],meta:q(m?.meta)}),d=m=>({data:m?.data??[],meta:G(m?.meta)}),f=m=>({data:m?.data??[],meta:$(m?.meta)});function x(m){let Y=k();return {list:s=>p.list(s),infinite:s=>p.infinite(s),cursor:s=>p.cursor({...s,order:s?.order??i}),params:s=>p.params(s),f:Y,search:(s,y,S)=>core.f.or(...y.map(Z=>core.f[S?.operation??"contains"](Z,s))),schema:s=>s,fromSearchParams:(s,y)=>{let S=w(y.schema,s,y.url,l);return U(p.list({...S,with:y.with}),S.clamped)},keys:{all:[m],list:s=>[m,"list",s],infinite:s=>[m,"infinite",s],cursor:s=>[m,"cursor",s],detail:s=>[m,"detail",s]},parseList:s=>u(s),parseInfinite:s=>d(s),parseCursor:s=>f(s)}}return {adapter:e.adapter,resource:x,parseList:u,parseInfinite:d,parseCursor:f}}var Se={"unknown-key":true,"invalid-value":true,"forbidden-key":true,"forbidden-operator":true,"limit-exceeded":true,"empty-filter":true},Re={filter:true,sort:true,cursorKey:true,aggregate:true,page:true,mutation:true,with:true},J=(e,t)=>typeof t=="string"&&Object.hasOwn(e,t);function he(e){if(typeof e!="object"||e===null)return false;let t=e;return J(Se,t.reason)&&J(Re,t.site)&&typeof t.key=="string"}function Le(e,t){let{schema:r,url:n,with:a}=t;return {read(i){let o=e.fromSearchParams(i,{schema:r,url:n,with:a});return {params:o,clamped:o.clamped===true}},actions(i){return {setParam:(o,p)=>I(i,o,p,n),setPage:o=>M(i,o,n),setSize:o=>N(i,o,n),setSort:o=>E(i,o,n),reset:o=>O(i,o)}}}}Object.defineProperty(exports,"f",{enumerable:true,get:function(){return core.f}});exports.buildCursorParams=me;exports.buildInfiniteParams=de;exports.buildListParams=A;exports.buildParams=ue;exports.createFilters=k;exports.createListState=Le;exports.createQuery=K;exports.createRegistry=xe;exports.decodeSort=X;exports.defineListSchema=pe;exports.encodeSort=j;exports.isQueryKitError=he;exports.normalizeFilter=_;exports.normalizeSort=L;exports.readListParams=w;exports.resetParams=O;exports.schemaToFilter=H;exports.searchParamsToPayload=Fe;exports.setPage=M;exports.setParam=I;exports.setSize=N;exports.setSort=E;//# sourceMappingURL=index.cjs.map
361
2
  //# sourceMappingURL=index.cjs.map