@querykitjs/core 1.2.0 → 2.0.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.
- package/README.en.md +36 -0
- package/README.md +36 -0
- package/dist/chunk-NHNDPIPM.js +54 -0
- package/dist/chunk-NHNDPIPM.js.map +1 -0
- package/dist/chunk-VD7XT52J.cjs +72 -0
- package/dist/chunk-VD7XT52J.cjs.map +1 -0
- package/dist/index.cjs +67 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -173
- package/dist/index.d.ts +23 -173
- package/dist/index.js +4 -26
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs +357 -0
- package/dist/internal.cjs.map +1 -0
- package/dist/internal.d.cts +249 -0
- package/dist/internal.d.ts +249 -0
- package/dist/internal.js +327 -0
- package/dist/internal.js.map +1 -0
- package/dist/raw-Bx8c-TrC.d.cts +290 -0
- package/dist/raw-Bx8c-TrC.d.ts +290 -0
- package/package.json +32 -6
- package/skills/querykit-core/SKILL.md +160 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter operatorlari — yagona runtime manba. `FilterOperator` tipi (`types.ts`)
|
|
3
|
+
* shundan chiqadi; `@querykitjs/zod` shu massivdan zod enum quradi.
|
|
4
|
+
*/
|
|
5
|
+
declare const FILTER_OPERATORS: readonly ["=", "!=", ">", ">=", "<", "<=", "eq", "ne", "gt", "gte", "lt", "lte", "like", "ilike", "notLike", "contains", "startsWith", "endsWith", "%_%", "%_", "_%", "in", "notIn", "between", "notBetween", "isNull", "isNotNull"];
|
|
6
|
+
/**
|
|
7
|
+
* Qiymati **text pattern** bo'lgan operatorlar. Backend adapterlari wire qiymatni
|
|
8
|
+
* ustun/path tipiga cast qilishda shularni chetlab o'tadi — aks holda
|
|
9
|
+
* `ilike(dateColumn, "%2026%")` ISO string o'rniga `String(Date)` olardi
|
|
10
|
+
* (`"Mon Jul 28 2026 …"`). Ro'yxat ikki adapterda divergent bo'lmasligi uchun
|
|
11
|
+
* shu yerda — yagona manba.
|
|
12
|
+
*/
|
|
13
|
+
declare const TEXT_FILTER_OPERATORS: readonly ["like", "ilike", "notLike", "contains", "startsWith", "endsWith", "%_%", "%_", "_%"];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* `@querykitjs/core` — ORM-agnostik query DSL tiplari. Backend adapterlar
|
|
17
|
+
* (`@querykitjs/drizzle-pg`) va frontend (`@querykitjs/web`) shu bir xil kontraktga
|
|
18
|
+
* tayanadi. Tiplar ustun-kaliti (`TKey`) bo'yicha generic; adapterlar uni o'z
|
|
19
|
+
* kalit tipiga (Drizzle jadval ustuni yoki entity maydoni) ixtisoslashtiradi.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** Qo'llab-quvvatlanadigan filter operatorlari (token va nom aliaslari). */
|
|
23
|
+
type FilterOperator = (typeof FILTER_OPERATORS)[number];
|
|
24
|
+
/**
|
|
25
|
+
* Tiplangan kalit, lekin har qanday `string` ham qabul qilinadi. Wire (JSON) har
|
|
26
|
+
* doim string-keyed keladi va adapterlar noma'lum kalitni baribir skip qiladi —
|
|
27
|
+
* tip shunchaki haqiqatni aytsin, route'da `as` cast kerak bo'lmasin.
|
|
28
|
+
*
|
|
29
|
+
* `(string & {})` — autocomplete'ni saqlaydigan TS trick'i: IDE `TKey`
|
|
30
|
+
* variantlarini taklif qiladi, boshqa string esa xato bermaydi.
|
|
31
|
+
*/
|
|
32
|
+
type LooseKey<TKey extends string> = TKey | (string & {});
|
|
33
|
+
/**
|
|
34
|
+
* A filter scalar. `Date` is accepted **in-memory** (adapters cast it for local
|
|
35
|
+
* queries); over the JSON wire it serializes to an ISO string, so
|
|
36
|
+
* `@querykitjs/zod` validates scalars **without** `Date` (string/number/boolean/null).
|
|
37
|
+
*/
|
|
38
|
+
type FilterScalar = string | number | boolean | Date | null;
|
|
39
|
+
type FilterValue = FilterScalar | FilterScalar[];
|
|
40
|
+
/** Bitta maydon sharti (`operation` default `"="`). */
|
|
41
|
+
interface FieldCondition<TKey extends string = string> {
|
|
42
|
+
key: TKey;
|
|
43
|
+
operation?: FilterOperator;
|
|
44
|
+
value?: FilterValue;
|
|
45
|
+
}
|
|
46
|
+
interface AndGroup<TKey extends string = string, TRaw = never> {
|
|
47
|
+
and: FilterNode<TKey, TRaw>[];
|
|
48
|
+
}
|
|
49
|
+
interface OrGroup<TKey extends string = string, TRaw = never> {
|
|
50
|
+
or: FilterNode<TKey, TRaw>[];
|
|
51
|
+
}
|
|
52
|
+
interface NotGroup<TKey extends string = string, TRaw = never> {
|
|
53
|
+
not: FilterNode<TKey, TRaw>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Filter daraxti tuguni: maydon sharti, mantiqiy guruh, yoki adapter qo'shadigan
|
|
57
|
+
* raw escape-hatch (`TRaw`, masalan Drizzle `SQL`; default `never`).
|
|
58
|
+
*/
|
|
59
|
+
type FilterNode<TKey extends string = string, TRaw = never> = FieldCondition<TKey> | AndGroup<TKey, TRaw> | OrGroup<TKey, TRaw> | NotGroup<TKey, TRaw> | TRaw;
|
|
60
|
+
/** Public filter: daraxt/tugun yoki flat massiv (implicit AND). */
|
|
61
|
+
type Filter<TKey extends string = string, TRaw = never> = FilterNode<TKey, TRaw> | FieldCondition<TKey>[];
|
|
62
|
+
type SortDirection = "asc" | "desc";
|
|
63
|
+
/** One sort field — `{ key, direction }`. */
|
|
64
|
+
interface SortItem<TKey extends string = string> {
|
|
65
|
+
key: TKey;
|
|
66
|
+
direction?: SortDirection;
|
|
67
|
+
}
|
|
68
|
+
/** Sort is **always an array** of {@link SortItem} (multi-field capable). */
|
|
69
|
+
type Sort<TKey extends string = string> = SortItem<TKey>[];
|
|
70
|
+
/** Scope qiymati ro'yxat bo'yicha (task 014): `{ in: [...] }`; bo'sh ro'yxat — hech qanday qator. */
|
|
71
|
+
interface ScopeIn {
|
|
72
|
+
in: readonly FilterScalar[];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Scoped repository'ning har amaliga qo'llanadigan scope: maydon → tenglik qiymati yoki `{ in: [...] }`.
|
|
76
|
+
* `create` default'lari faqat tenglik scope'laridan olinadi.
|
|
77
|
+
*/
|
|
78
|
+
type Scope<TKey extends string = string> = Partial<Record<TKey, FilterScalar | ScopeIn>>;
|
|
79
|
+
/** Options for upsert / upsertMany — conflict target(s) + optional update set. */
|
|
80
|
+
interface UpsertOptions<TKey extends string = string, TInsert = Record<string, unknown>> {
|
|
81
|
+
/** Unique/conflict key(s) whose match triggers an update instead of an insert. */
|
|
82
|
+
target: TKey | TKey[];
|
|
83
|
+
/** Columns/fields to update on conflict. Defaults to the inserted values minus `target`. */
|
|
84
|
+
set?: Partial<TInsert>;
|
|
85
|
+
}
|
|
86
|
+
/** Aggregate query spec — group + count/sum/avg/min/max, each keyed by field. */
|
|
87
|
+
interface AggregateSpec<TKey extends string = string, TFilter = unknown> {
|
|
88
|
+
filter?: TFilter;
|
|
89
|
+
/** Group rows by these field(s); each appears in the output rows. */
|
|
90
|
+
groupBy?: TKey | TKey[];
|
|
91
|
+
count?: boolean;
|
|
92
|
+
sum?: TKey | TKey[];
|
|
93
|
+
avg?: TKey | TKey[];
|
|
94
|
+
min?: TKey | TKey[];
|
|
95
|
+
max?: TKey | TKey[];
|
|
96
|
+
withDeleted?: boolean;
|
|
97
|
+
}
|
|
98
|
+
/** Paginatsiyasiz umumiy wire params. */
|
|
99
|
+
interface WireBaseParams {
|
|
100
|
+
filter?: Filter;
|
|
101
|
+
sort?: Sort;
|
|
102
|
+
columns?: Record<string, boolean>;
|
|
103
|
+
with?: Record<string, unknown>;
|
|
104
|
+
withDeleted?: boolean;
|
|
105
|
+
}
|
|
106
|
+
/** Offset (sahifali) wire params. */
|
|
107
|
+
interface WireOffsetParams extends WireBaseParams {
|
|
108
|
+
page?: number;
|
|
109
|
+
perPage?: number;
|
|
110
|
+
/**
|
|
111
|
+
* `false` — umumiy son so'ralmaydi (count yo'q): `perPage + 1` qator o'qiladi,
|
|
112
|
+
* `has_next` shundan, `total_items` / `total_pages` = `null`. Default `true`.
|
|
113
|
+
*/
|
|
114
|
+
withTotal?: boolean;
|
|
115
|
+
}
|
|
116
|
+
/** Infinite-scroll wire params. */
|
|
117
|
+
interface WireInfiniteParams extends WireBaseParams {
|
|
118
|
+
limit?: number;
|
|
119
|
+
offset?: number;
|
|
120
|
+
}
|
|
121
|
+
/** Cursor (keyset) wire params — `sort` yo'q, tartib `order` + `direction` bilan. */
|
|
122
|
+
interface WireCursorParams extends Omit<WireBaseParams, "sort"> {
|
|
123
|
+
limit?: number;
|
|
124
|
+
cursor?: string | null;
|
|
125
|
+
cursorKey?: string;
|
|
126
|
+
order?: SortDirection;
|
|
127
|
+
direction?: "forward" | "backward";
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Shart nima uchun tashlab yuborilgani yoki rad etilgani. `forbidden-key`,
|
|
131
|
+
* `forbidden-operator` va `limit-exceeded` — server siyosati (`filterable` /
|
|
132
|
+
* `sortable` / `limits`): ular **hech qachon jim tashlanmaydi**, `strict`dan qat'i nazar
|
|
133
|
+
* `QueryKitError` bo'ladi.
|
|
134
|
+
*/
|
|
135
|
+
type SkipReason = "unknown-key" | "invalid-value" | "forbidden-key" | "forbidden-operator" | "limit-exceeded" | "empty-filter";
|
|
136
|
+
/**
|
|
137
|
+
* Shart qayerda tashlab yuborilgani (`page` — offset chuqurligi, `mutation` — `updateWhere` / `deleteWhere` filtri,
|
|
138
|
+
* `with` — `relations` ro'yxatida yo'q relation, ustun yoki filtr).
|
|
139
|
+
*/
|
|
140
|
+
type SkipSite = "filter" | "sort" | "cursorKey" | "aggregate" | "page" | "mutation" | "with";
|
|
141
|
+
/**
|
|
142
|
+
* Server siyosati: maydon → ruxsat etilgan operatorlar, yoki `"*"` (hammasi — faqat aniq
|
|
143
|
+
* yozilganda). Ro'yxatda yo'q maydon yoki operator `QueryKitError` beradi.
|
|
144
|
+
*/
|
|
145
|
+
type Filterable<TKey extends string = string> = Partial<Record<TKey, readonly FilterOperator[] | "*">>;
|
|
146
|
+
/** Tashlab yuborilgan bitta shart haqida ma'lumot. */
|
|
147
|
+
interface SkippedCondition {
|
|
148
|
+
/** Jadval (drizzle) yoki model (mongoose) nomi. */
|
|
149
|
+
source: string;
|
|
150
|
+
site: SkipSite;
|
|
151
|
+
key: string;
|
|
152
|
+
operation?: FilterOperator;
|
|
153
|
+
reason: SkipReason;
|
|
154
|
+
}
|
|
155
|
+
/** Offset (sahifali) paginatsiya meta'si. */
|
|
156
|
+
interface OffsetMeta {
|
|
157
|
+
/** `withTotal: false` bilan `null` (count so'ralmagan). */
|
|
158
|
+
total_items: number | null;
|
|
159
|
+
/** `withTotal: false` bilan `null`. */
|
|
160
|
+
total_pages: number | null;
|
|
161
|
+
current_page: number;
|
|
162
|
+
per_page: number;
|
|
163
|
+
has_next: boolean;
|
|
164
|
+
has_prev: boolean;
|
|
165
|
+
}
|
|
166
|
+
/** Infinite-scroll paginatsiya meta'si. */
|
|
167
|
+
interface InfiniteMeta {
|
|
168
|
+
limit: number;
|
|
169
|
+
offset: number;
|
|
170
|
+
count: number;
|
|
171
|
+
has_more: boolean;
|
|
172
|
+
next_offset: number | null;
|
|
173
|
+
}
|
|
174
|
+
/** Cursor (keyset) paginatsiya meta'si. */
|
|
175
|
+
interface CursorMeta {
|
|
176
|
+
limit: number;
|
|
177
|
+
has_next: boolean;
|
|
178
|
+
has_prev: boolean;
|
|
179
|
+
next_cursor: string | null;
|
|
180
|
+
prev_cursor: string | null;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* `updateWhere` / `deleteWhere` uchun "hamma qatorlar" — faqat shu aniq ko'rsatilsa filtrsiz
|
|
184
|
+
* mutatsiya bajariladi (scope baribir qo'llanadi). Bo'sh filtr — `QueryKitError` `empty-filter`.
|
|
185
|
+
*/
|
|
186
|
+
interface AllRows {
|
|
187
|
+
all: true;
|
|
188
|
+
}
|
|
189
|
+
/** `updateWhere` / `deleteWhere` opsiyalari: `returning: { limit }` — ta'sirlangan qatorlardan ko'pi bilan `limit` tasi. */
|
|
190
|
+
interface MutationOptions {
|
|
191
|
+
returning?: false | {
|
|
192
|
+
limit: number;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/** Ta'sirlangan qatorlar soni. */
|
|
196
|
+
interface MutationCount {
|
|
197
|
+
count: number;
|
|
198
|
+
}
|
|
199
|
+
/** `returning: { limit }` bilan: soni va ko'pi bilan `limit` ta qator. */
|
|
200
|
+
interface MutationRows<TRow> extends MutationCount {
|
|
201
|
+
rows: TRow[];
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Bitta relation uchun mijoz `with` ruxsati (task 014, R21): `columns` majburiy — ro'yxat yoki aniq `"*"`;
|
|
205
|
+
* `filterable` — relation filtrida (prisma `where`, mongoose `match`) ruxsat etilgan maydonlar;
|
|
206
|
+
* `nested` — shu relation ichidagi `with` uchun xuddi shu shakl (yo'q ⇒ ichki `with` — `forbidden-key`).
|
|
207
|
+
*/
|
|
208
|
+
interface RelationRule {
|
|
209
|
+
columns: readonly string[] | "*";
|
|
210
|
+
filterable?: Filterable;
|
|
211
|
+
nested?: Relations;
|
|
212
|
+
}
|
|
213
|
+
/** Repository `relations`: relation → {@link RelationRule}. Ro'yxatda yo'q relation — `forbidden-key`, `site: "with"`. */
|
|
214
|
+
type Relations = Record<string, RelationRule>;
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Umumiy pagination default'lari — yagona manba. Backend adapter (`createRegistry`
|
|
218
|
+
* options) va frontend (`createQuery` config) shu qiymatlarni fallback sifatida
|
|
219
|
+
* ishlatadi, shuning uchun ular hech qachon bir-biridan farq qilmaydi.
|
|
220
|
+
*/
|
|
221
|
+
/** Offset (list) sahifa o'lchami default'i. */
|
|
222
|
+
declare const DEFAULT_PER_PAGE = 20;
|
|
223
|
+
/** Infinite/cursor `limit` default'i. */
|
|
224
|
+
declare const DEFAULT_LIMIT = 20;
|
|
225
|
+
/**
|
|
226
|
+
* `perPage` uchun yuqori chegara — cap'siz paginatsiya DoS yuzasi. Validatsiya
|
|
227
|
+
* (`@querykitjs/zod` factory'lari), backend repositorylari va frontend `createQuery`
|
|
228
|
+
* shu bitta qiymatga tayanadi, shuning uchun ular hech qachon farq qilmaydi.
|
|
229
|
+
*/
|
|
230
|
+
declare const DEFAULT_MAX_PER_PAGE = 200;
|
|
231
|
+
/** Infinite/cursor `limit` uchun yuqori chegara. Qarang: {@link DEFAULT_MAX_PER_PAGE}. */
|
|
232
|
+
declare const DEFAULT_MAX_LIMIT = 200;
|
|
233
|
+
/** Longest root-to-leaf path of a filter tree, in nodes: the root is level 1, every `and`/`or`/`not` and the condition itself add one. */
|
|
234
|
+
declare const DEFAULT_MAX_FILTER_DEPTH = 5;
|
|
235
|
+
/** Field conditions (leaves) in one filter, across all groups. */
|
|
236
|
+
declare const DEFAULT_MAX_CONDITIONS = 30;
|
|
237
|
+
/** Items in one array filter value (`in`, `notIn`, …). */
|
|
238
|
+
declare const DEFAULT_MAX_IN_ITEMS = 200;
|
|
239
|
+
/** Characters in one string filter value, also inside an array value. */
|
|
240
|
+
declare const DEFAULT_MAX_STRING_LENGTH = 256;
|
|
241
|
+
/** Rows skipped before a page: `(page - 1) × perPage` for offset pagination, `offset` for infinite. Deeper pages need a cursor. */
|
|
242
|
+
declare const DEFAULT_MAX_OFFSET = 10000;
|
|
243
|
+
/** Fields in one `sort` array. */
|
|
244
|
+
declare const DEFAULT_MAX_SORT_FIELDS = 3;
|
|
245
|
+
/**
|
|
246
|
+
* Wildcards (`%`, `_`) in one `like` / `ilike` / `notLike` pattern, after a run
|
|
247
|
+
* of `%` counts as one. Each extra wildcard multiplies the matcher's backtracking
|
|
248
|
+
* (`%a%a%a…%b`), on MongoDB's regex engine and on Postgres alike.
|
|
249
|
+
*/
|
|
250
|
+
declare const DEFAULT_MAX_LIKE_WILDCARDS = 2;
|
|
251
|
+
/** The six request limits, by the option name every package uses. */
|
|
252
|
+
interface QueryLimits {
|
|
253
|
+
maxDepth: number;
|
|
254
|
+
maxConditions: number;
|
|
255
|
+
maxInItems: number;
|
|
256
|
+
maxStringLength: number;
|
|
257
|
+
maxOffset: number;
|
|
258
|
+
maxSortFields: number;
|
|
259
|
+
maxLikeWildcards: number;
|
|
260
|
+
}
|
|
261
|
+
/** The core defaults as one object. */
|
|
262
|
+
declare const DEFAULT_QUERY_LIMITS: Readonly<QueryLimits>;
|
|
263
|
+
/**
|
|
264
|
+
* The defaults with the given limits on top; an `undefined` entry keeps the
|
|
265
|
+
* default. `Infinity` turns a limit off (⚠️ a DoS surface).
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```ts
|
|
269
|
+
* resolveLimits({ maxInItems: 50 }); // { maxDepth: 5, …, maxInItems: 50, … }
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
declare function resolveLimits(limits?: Partial<QueryLimits>): QueryLimits;
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Brand a driver-native filter object so an adapter accepts it as a filter node.
|
|
276
|
+
* The object itself is returned (non-enumerable brand), so the driver receives
|
|
277
|
+
* exactly what you wrote.
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```ts
|
|
281
|
+
* import { raw } from "@querykitjs/core";
|
|
282
|
+
* repo.findAll({ filter: { and: [{ key: "status", value: "active" }, raw({ posts: { some: { published: true } } })] } });
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
declare function raw<T extends object>(value: T): T;
|
|
286
|
+
/** Whether a filter node was branded with {@link raw}. */
|
|
287
|
+
declare const isRaw: (node: unknown) => boolean;
|
|
288
|
+
|
|
289
|
+
export { DEFAULT_LIMIT as D, TEXT_FILTER_OPERATORS as T, raw as X, resolveLimits as Y, isRaw as Z, DEFAULT_MAX_CONDITIONS as f, DEFAULT_MAX_FILTER_DEPTH as g, DEFAULT_MAX_IN_ITEMS as h, DEFAULT_MAX_LIKE_WILDCARDS as i, DEFAULT_MAX_LIMIT as j, DEFAULT_MAX_OFFSET as k, DEFAULT_MAX_PER_PAGE as l, DEFAULT_MAX_SORT_FIELDS as m, DEFAULT_MAX_STRING_LENGTH as n, DEFAULT_PER_PAGE as o, DEFAULT_QUERY_LIMITS as p, FILTER_OPERATORS as q };
|
|
290
|
+
export type { AndGroup as A, SkipReason as B, CursorMeta as C, SkipSite as E, FilterValue as F, Sort as G, SortDirection as H, InfiniteMeta as I, SortItem as J, WireCursorParams as K, LooseKey as L, MutationCount as M, NotGroup as N, OrGroup as O, WireInfiniteParams as P, QueryLimits as Q, RelationRule as R, SkippedCondition as S, UpsertOptions as U, WireOffsetParams as V, WireBaseParams as W, FieldCondition as a, FilterScalar as b, FilterNode as c, AggregateSpec as d, AllRows as e, Filter as r, FilterOperator as s, Filterable as t, MutationOptions as u, MutationRows as v, OffsetMeta as w, Relations as x, Scope as y, ScopeIn as z };
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter operatorlari — yagona runtime manba. `FilterOperator` tipi (`types.ts`)
|
|
3
|
+
* shundan chiqadi; `@querykitjs/zod` shu massivdan zod enum quradi.
|
|
4
|
+
*/
|
|
5
|
+
declare const FILTER_OPERATORS: readonly ["=", "!=", ">", ">=", "<", "<=", "eq", "ne", "gt", "gte", "lt", "lte", "like", "ilike", "notLike", "contains", "startsWith", "endsWith", "%_%", "%_", "_%", "in", "notIn", "between", "notBetween", "isNull", "isNotNull"];
|
|
6
|
+
/**
|
|
7
|
+
* Qiymati **text pattern** bo'lgan operatorlar. Backend adapterlari wire qiymatni
|
|
8
|
+
* ustun/path tipiga cast qilishda shularni chetlab o'tadi — aks holda
|
|
9
|
+
* `ilike(dateColumn, "%2026%")` ISO string o'rniga `String(Date)` olardi
|
|
10
|
+
* (`"Mon Jul 28 2026 …"`). Ro'yxat ikki adapterda divergent bo'lmasligi uchun
|
|
11
|
+
* shu yerda — yagona manba.
|
|
12
|
+
*/
|
|
13
|
+
declare const TEXT_FILTER_OPERATORS: readonly ["like", "ilike", "notLike", "contains", "startsWith", "endsWith", "%_%", "%_", "_%"];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* `@querykitjs/core` — ORM-agnostik query DSL tiplari. Backend adapterlar
|
|
17
|
+
* (`@querykitjs/drizzle-pg`) va frontend (`@querykitjs/web`) shu bir xil kontraktga
|
|
18
|
+
* tayanadi. Tiplar ustun-kaliti (`TKey`) bo'yicha generic; adapterlar uni o'z
|
|
19
|
+
* kalit tipiga (Drizzle jadval ustuni yoki entity maydoni) ixtisoslashtiradi.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** Qo'llab-quvvatlanadigan filter operatorlari (token va nom aliaslari). */
|
|
23
|
+
type FilterOperator = (typeof FILTER_OPERATORS)[number];
|
|
24
|
+
/**
|
|
25
|
+
* Tiplangan kalit, lekin har qanday `string` ham qabul qilinadi. Wire (JSON) har
|
|
26
|
+
* doim string-keyed keladi va adapterlar noma'lum kalitni baribir skip qiladi —
|
|
27
|
+
* tip shunchaki haqiqatni aytsin, route'da `as` cast kerak bo'lmasin.
|
|
28
|
+
*
|
|
29
|
+
* `(string & {})` — autocomplete'ni saqlaydigan TS trick'i: IDE `TKey`
|
|
30
|
+
* variantlarini taklif qiladi, boshqa string esa xato bermaydi.
|
|
31
|
+
*/
|
|
32
|
+
type LooseKey<TKey extends string> = TKey | (string & {});
|
|
33
|
+
/**
|
|
34
|
+
* A filter scalar. `Date` is accepted **in-memory** (adapters cast it for local
|
|
35
|
+
* queries); over the JSON wire it serializes to an ISO string, so
|
|
36
|
+
* `@querykitjs/zod` validates scalars **without** `Date` (string/number/boolean/null).
|
|
37
|
+
*/
|
|
38
|
+
type FilterScalar = string | number | boolean | Date | null;
|
|
39
|
+
type FilterValue = FilterScalar | FilterScalar[];
|
|
40
|
+
/** Bitta maydon sharti (`operation` default `"="`). */
|
|
41
|
+
interface FieldCondition<TKey extends string = string> {
|
|
42
|
+
key: TKey;
|
|
43
|
+
operation?: FilterOperator;
|
|
44
|
+
value?: FilterValue;
|
|
45
|
+
}
|
|
46
|
+
interface AndGroup<TKey extends string = string, TRaw = never> {
|
|
47
|
+
and: FilterNode<TKey, TRaw>[];
|
|
48
|
+
}
|
|
49
|
+
interface OrGroup<TKey extends string = string, TRaw = never> {
|
|
50
|
+
or: FilterNode<TKey, TRaw>[];
|
|
51
|
+
}
|
|
52
|
+
interface NotGroup<TKey extends string = string, TRaw = never> {
|
|
53
|
+
not: FilterNode<TKey, TRaw>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Filter daraxti tuguni: maydon sharti, mantiqiy guruh, yoki adapter qo'shadigan
|
|
57
|
+
* raw escape-hatch (`TRaw`, masalan Drizzle `SQL`; default `never`).
|
|
58
|
+
*/
|
|
59
|
+
type FilterNode<TKey extends string = string, TRaw = never> = FieldCondition<TKey> | AndGroup<TKey, TRaw> | OrGroup<TKey, TRaw> | NotGroup<TKey, TRaw> | TRaw;
|
|
60
|
+
/** Public filter: daraxt/tugun yoki flat massiv (implicit AND). */
|
|
61
|
+
type Filter<TKey extends string = string, TRaw = never> = FilterNode<TKey, TRaw> | FieldCondition<TKey>[];
|
|
62
|
+
type SortDirection = "asc" | "desc";
|
|
63
|
+
/** One sort field — `{ key, direction }`. */
|
|
64
|
+
interface SortItem<TKey extends string = string> {
|
|
65
|
+
key: TKey;
|
|
66
|
+
direction?: SortDirection;
|
|
67
|
+
}
|
|
68
|
+
/** Sort is **always an array** of {@link SortItem} (multi-field capable). */
|
|
69
|
+
type Sort<TKey extends string = string> = SortItem<TKey>[];
|
|
70
|
+
/** Scope qiymati ro'yxat bo'yicha (task 014): `{ in: [...] }`; bo'sh ro'yxat — hech qanday qator. */
|
|
71
|
+
interface ScopeIn {
|
|
72
|
+
in: readonly FilterScalar[];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Scoped repository'ning har amaliga qo'llanadigan scope: maydon → tenglik qiymati yoki `{ in: [...] }`.
|
|
76
|
+
* `create` default'lari faqat tenglik scope'laridan olinadi.
|
|
77
|
+
*/
|
|
78
|
+
type Scope<TKey extends string = string> = Partial<Record<TKey, FilterScalar | ScopeIn>>;
|
|
79
|
+
/** Options for upsert / upsertMany — conflict target(s) + optional update set. */
|
|
80
|
+
interface UpsertOptions<TKey extends string = string, TInsert = Record<string, unknown>> {
|
|
81
|
+
/** Unique/conflict key(s) whose match triggers an update instead of an insert. */
|
|
82
|
+
target: TKey | TKey[];
|
|
83
|
+
/** Columns/fields to update on conflict. Defaults to the inserted values minus `target`. */
|
|
84
|
+
set?: Partial<TInsert>;
|
|
85
|
+
}
|
|
86
|
+
/** Aggregate query spec — group + count/sum/avg/min/max, each keyed by field. */
|
|
87
|
+
interface AggregateSpec<TKey extends string = string, TFilter = unknown> {
|
|
88
|
+
filter?: TFilter;
|
|
89
|
+
/** Group rows by these field(s); each appears in the output rows. */
|
|
90
|
+
groupBy?: TKey | TKey[];
|
|
91
|
+
count?: boolean;
|
|
92
|
+
sum?: TKey | TKey[];
|
|
93
|
+
avg?: TKey | TKey[];
|
|
94
|
+
min?: TKey | TKey[];
|
|
95
|
+
max?: TKey | TKey[];
|
|
96
|
+
withDeleted?: boolean;
|
|
97
|
+
}
|
|
98
|
+
/** Paginatsiyasiz umumiy wire params. */
|
|
99
|
+
interface WireBaseParams {
|
|
100
|
+
filter?: Filter;
|
|
101
|
+
sort?: Sort;
|
|
102
|
+
columns?: Record<string, boolean>;
|
|
103
|
+
with?: Record<string, unknown>;
|
|
104
|
+
withDeleted?: boolean;
|
|
105
|
+
}
|
|
106
|
+
/** Offset (sahifali) wire params. */
|
|
107
|
+
interface WireOffsetParams extends WireBaseParams {
|
|
108
|
+
page?: number;
|
|
109
|
+
perPage?: number;
|
|
110
|
+
/**
|
|
111
|
+
* `false` — umumiy son so'ralmaydi (count yo'q): `perPage + 1` qator o'qiladi,
|
|
112
|
+
* `has_next` shundan, `total_items` / `total_pages` = `null`. Default `true`.
|
|
113
|
+
*/
|
|
114
|
+
withTotal?: boolean;
|
|
115
|
+
}
|
|
116
|
+
/** Infinite-scroll wire params. */
|
|
117
|
+
interface WireInfiniteParams extends WireBaseParams {
|
|
118
|
+
limit?: number;
|
|
119
|
+
offset?: number;
|
|
120
|
+
}
|
|
121
|
+
/** Cursor (keyset) wire params — `sort` yo'q, tartib `order` + `direction` bilan. */
|
|
122
|
+
interface WireCursorParams extends Omit<WireBaseParams, "sort"> {
|
|
123
|
+
limit?: number;
|
|
124
|
+
cursor?: string | null;
|
|
125
|
+
cursorKey?: string;
|
|
126
|
+
order?: SortDirection;
|
|
127
|
+
direction?: "forward" | "backward";
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Shart nima uchun tashlab yuborilgani yoki rad etilgani. `forbidden-key`,
|
|
131
|
+
* `forbidden-operator` va `limit-exceeded` — server siyosati (`filterable` /
|
|
132
|
+
* `sortable` / `limits`): ular **hech qachon jim tashlanmaydi**, `strict`dan qat'i nazar
|
|
133
|
+
* `QueryKitError` bo'ladi.
|
|
134
|
+
*/
|
|
135
|
+
type SkipReason = "unknown-key" | "invalid-value" | "forbidden-key" | "forbidden-operator" | "limit-exceeded" | "empty-filter";
|
|
136
|
+
/**
|
|
137
|
+
* Shart qayerda tashlab yuborilgani (`page` — offset chuqurligi, `mutation` — `updateWhere` / `deleteWhere` filtri,
|
|
138
|
+
* `with` — `relations` ro'yxatida yo'q relation, ustun yoki filtr).
|
|
139
|
+
*/
|
|
140
|
+
type SkipSite = "filter" | "sort" | "cursorKey" | "aggregate" | "page" | "mutation" | "with";
|
|
141
|
+
/**
|
|
142
|
+
* Server siyosati: maydon → ruxsat etilgan operatorlar, yoki `"*"` (hammasi — faqat aniq
|
|
143
|
+
* yozilganda). Ro'yxatda yo'q maydon yoki operator `QueryKitError` beradi.
|
|
144
|
+
*/
|
|
145
|
+
type Filterable<TKey extends string = string> = Partial<Record<TKey, readonly FilterOperator[] | "*">>;
|
|
146
|
+
/** Tashlab yuborilgan bitta shart haqida ma'lumot. */
|
|
147
|
+
interface SkippedCondition {
|
|
148
|
+
/** Jadval (drizzle) yoki model (mongoose) nomi. */
|
|
149
|
+
source: string;
|
|
150
|
+
site: SkipSite;
|
|
151
|
+
key: string;
|
|
152
|
+
operation?: FilterOperator;
|
|
153
|
+
reason: SkipReason;
|
|
154
|
+
}
|
|
155
|
+
/** Offset (sahifali) paginatsiya meta'si. */
|
|
156
|
+
interface OffsetMeta {
|
|
157
|
+
/** `withTotal: false` bilan `null` (count so'ralmagan). */
|
|
158
|
+
total_items: number | null;
|
|
159
|
+
/** `withTotal: false` bilan `null`. */
|
|
160
|
+
total_pages: number | null;
|
|
161
|
+
current_page: number;
|
|
162
|
+
per_page: number;
|
|
163
|
+
has_next: boolean;
|
|
164
|
+
has_prev: boolean;
|
|
165
|
+
}
|
|
166
|
+
/** Infinite-scroll paginatsiya meta'si. */
|
|
167
|
+
interface InfiniteMeta {
|
|
168
|
+
limit: number;
|
|
169
|
+
offset: number;
|
|
170
|
+
count: number;
|
|
171
|
+
has_more: boolean;
|
|
172
|
+
next_offset: number | null;
|
|
173
|
+
}
|
|
174
|
+
/** Cursor (keyset) paginatsiya meta'si. */
|
|
175
|
+
interface CursorMeta {
|
|
176
|
+
limit: number;
|
|
177
|
+
has_next: boolean;
|
|
178
|
+
has_prev: boolean;
|
|
179
|
+
next_cursor: string | null;
|
|
180
|
+
prev_cursor: string | null;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* `updateWhere` / `deleteWhere` uchun "hamma qatorlar" — faqat shu aniq ko'rsatilsa filtrsiz
|
|
184
|
+
* mutatsiya bajariladi (scope baribir qo'llanadi). Bo'sh filtr — `QueryKitError` `empty-filter`.
|
|
185
|
+
*/
|
|
186
|
+
interface AllRows {
|
|
187
|
+
all: true;
|
|
188
|
+
}
|
|
189
|
+
/** `updateWhere` / `deleteWhere` opsiyalari: `returning: { limit }` — ta'sirlangan qatorlardan ko'pi bilan `limit` tasi. */
|
|
190
|
+
interface MutationOptions {
|
|
191
|
+
returning?: false | {
|
|
192
|
+
limit: number;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/** Ta'sirlangan qatorlar soni. */
|
|
196
|
+
interface MutationCount {
|
|
197
|
+
count: number;
|
|
198
|
+
}
|
|
199
|
+
/** `returning: { limit }` bilan: soni va ko'pi bilan `limit` ta qator. */
|
|
200
|
+
interface MutationRows<TRow> extends MutationCount {
|
|
201
|
+
rows: TRow[];
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Bitta relation uchun mijoz `with` ruxsati (task 014, R21): `columns` majburiy — ro'yxat yoki aniq `"*"`;
|
|
205
|
+
* `filterable` — relation filtrida (prisma `where`, mongoose `match`) ruxsat etilgan maydonlar;
|
|
206
|
+
* `nested` — shu relation ichidagi `with` uchun xuddi shu shakl (yo'q ⇒ ichki `with` — `forbidden-key`).
|
|
207
|
+
*/
|
|
208
|
+
interface RelationRule {
|
|
209
|
+
columns: readonly string[] | "*";
|
|
210
|
+
filterable?: Filterable;
|
|
211
|
+
nested?: Relations;
|
|
212
|
+
}
|
|
213
|
+
/** Repository `relations`: relation → {@link RelationRule}. Ro'yxatda yo'q relation — `forbidden-key`, `site: "with"`. */
|
|
214
|
+
type Relations = Record<string, RelationRule>;
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Umumiy pagination default'lari — yagona manba. Backend adapter (`createRegistry`
|
|
218
|
+
* options) va frontend (`createQuery` config) shu qiymatlarni fallback sifatida
|
|
219
|
+
* ishlatadi, shuning uchun ular hech qachon bir-biridan farq qilmaydi.
|
|
220
|
+
*/
|
|
221
|
+
/** Offset (list) sahifa o'lchami default'i. */
|
|
222
|
+
declare const DEFAULT_PER_PAGE = 20;
|
|
223
|
+
/** Infinite/cursor `limit` default'i. */
|
|
224
|
+
declare const DEFAULT_LIMIT = 20;
|
|
225
|
+
/**
|
|
226
|
+
* `perPage` uchun yuqori chegara — cap'siz paginatsiya DoS yuzasi. Validatsiya
|
|
227
|
+
* (`@querykitjs/zod` factory'lari), backend repositorylari va frontend `createQuery`
|
|
228
|
+
* shu bitta qiymatga tayanadi, shuning uchun ular hech qachon farq qilmaydi.
|
|
229
|
+
*/
|
|
230
|
+
declare const DEFAULT_MAX_PER_PAGE = 200;
|
|
231
|
+
/** Infinite/cursor `limit` uchun yuqori chegara. Qarang: {@link DEFAULT_MAX_PER_PAGE}. */
|
|
232
|
+
declare const DEFAULT_MAX_LIMIT = 200;
|
|
233
|
+
/** Longest root-to-leaf path of a filter tree, in nodes: the root is level 1, every `and`/`or`/`not` and the condition itself add one. */
|
|
234
|
+
declare const DEFAULT_MAX_FILTER_DEPTH = 5;
|
|
235
|
+
/** Field conditions (leaves) in one filter, across all groups. */
|
|
236
|
+
declare const DEFAULT_MAX_CONDITIONS = 30;
|
|
237
|
+
/** Items in one array filter value (`in`, `notIn`, …). */
|
|
238
|
+
declare const DEFAULT_MAX_IN_ITEMS = 200;
|
|
239
|
+
/** Characters in one string filter value, also inside an array value. */
|
|
240
|
+
declare const DEFAULT_MAX_STRING_LENGTH = 256;
|
|
241
|
+
/** Rows skipped before a page: `(page - 1) × perPage` for offset pagination, `offset` for infinite. Deeper pages need a cursor. */
|
|
242
|
+
declare const DEFAULT_MAX_OFFSET = 10000;
|
|
243
|
+
/** Fields in one `sort` array. */
|
|
244
|
+
declare const DEFAULT_MAX_SORT_FIELDS = 3;
|
|
245
|
+
/**
|
|
246
|
+
* Wildcards (`%`, `_`) in one `like` / `ilike` / `notLike` pattern, after a run
|
|
247
|
+
* of `%` counts as one. Each extra wildcard multiplies the matcher's backtracking
|
|
248
|
+
* (`%a%a%a…%b`), on MongoDB's regex engine and on Postgres alike.
|
|
249
|
+
*/
|
|
250
|
+
declare const DEFAULT_MAX_LIKE_WILDCARDS = 2;
|
|
251
|
+
/** The six request limits, by the option name every package uses. */
|
|
252
|
+
interface QueryLimits {
|
|
253
|
+
maxDepth: number;
|
|
254
|
+
maxConditions: number;
|
|
255
|
+
maxInItems: number;
|
|
256
|
+
maxStringLength: number;
|
|
257
|
+
maxOffset: number;
|
|
258
|
+
maxSortFields: number;
|
|
259
|
+
maxLikeWildcards: number;
|
|
260
|
+
}
|
|
261
|
+
/** The core defaults as one object. */
|
|
262
|
+
declare const DEFAULT_QUERY_LIMITS: Readonly<QueryLimits>;
|
|
263
|
+
/**
|
|
264
|
+
* The defaults with the given limits on top; an `undefined` entry keeps the
|
|
265
|
+
* default. `Infinity` turns a limit off (⚠️ a DoS surface).
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```ts
|
|
269
|
+
* resolveLimits({ maxInItems: 50 }); // { maxDepth: 5, …, maxInItems: 50, … }
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
declare function resolveLimits(limits?: Partial<QueryLimits>): QueryLimits;
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Brand a driver-native filter object so an adapter accepts it as a filter node.
|
|
276
|
+
* The object itself is returned (non-enumerable brand), so the driver receives
|
|
277
|
+
* exactly what you wrote.
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```ts
|
|
281
|
+
* import { raw } from "@querykitjs/core";
|
|
282
|
+
* repo.findAll({ filter: { and: [{ key: "status", value: "active" }, raw({ posts: { some: { published: true } } })] } });
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
declare function raw<T extends object>(value: T): T;
|
|
286
|
+
/** Whether a filter node was branded with {@link raw}. */
|
|
287
|
+
declare const isRaw: (node: unknown) => boolean;
|
|
288
|
+
|
|
289
|
+
export { DEFAULT_LIMIT as D, TEXT_FILTER_OPERATORS as T, raw as X, resolveLimits as Y, isRaw as Z, DEFAULT_MAX_CONDITIONS as f, DEFAULT_MAX_FILTER_DEPTH as g, DEFAULT_MAX_IN_ITEMS as h, DEFAULT_MAX_LIKE_WILDCARDS as i, DEFAULT_MAX_LIMIT as j, DEFAULT_MAX_OFFSET as k, DEFAULT_MAX_PER_PAGE as l, DEFAULT_MAX_SORT_FIELDS as m, DEFAULT_MAX_STRING_LENGTH as n, DEFAULT_PER_PAGE as o, DEFAULT_QUERY_LIMITS as p, FILTER_OPERATORS as q };
|
|
290
|
+
export type { AndGroup as A, SkipReason as B, CursorMeta as C, SkipSite as E, FilterValue as F, Sort as G, SortDirection as H, InfiniteMeta as I, SortItem as J, WireCursorParams as K, LooseKey as L, MutationCount as M, NotGroup as N, OrGroup as O, WireInfiniteParams as P, QueryLimits as Q, RelationRule as R, SkippedCondition as S, UpsertOptions as U, WireOffsetParams as V, WireBaseParams as W, FieldCondition as a, FilterScalar as b, FilterNode as c, AggregateSpec as d, AllRows as e, Filter as r, FilterOperator as s, Filterable as t, MutationOptions as u, MutationRows as v, OffsetMeta as w, Relations as x, Scope as y, ScopeIn as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@querykitjs/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "ORM-agnostic query DSL shared by querykit packages — filters, operators & wire types.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": {
|
|
@@ -23,26 +23,52 @@
|
|
|
23
23
|
"types": "./dist/index.d.ts",
|
|
24
24
|
"exports": {
|
|
25
25
|
".": {
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
"import": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"default": "./dist/index.js"
|
|
29
|
+
},
|
|
30
|
+
"require": {
|
|
31
|
+
"types": "./dist/index.d.cts",
|
|
32
|
+
"default": "./dist/index.cjs"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"./internal": {
|
|
36
|
+
"import": {
|
|
37
|
+
"types": "./dist/internal.d.ts",
|
|
38
|
+
"default": "./dist/internal.js"
|
|
39
|
+
},
|
|
40
|
+
"require": {
|
|
41
|
+
"types": "./dist/internal.d.cts",
|
|
42
|
+
"default": "./dist/internal.cjs"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"typesVersions": {
|
|
47
|
+
"*": {
|
|
48
|
+
"internal": [
|
|
49
|
+
"./dist/internal.d.ts"
|
|
50
|
+
]
|
|
29
51
|
}
|
|
30
52
|
},
|
|
31
53
|
"files": [
|
|
32
54
|
"dist",
|
|
33
55
|
"README.md",
|
|
34
56
|
"README.en.md",
|
|
35
|
-
"LICENSE"
|
|
57
|
+
"LICENSE",
|
|
58
|
+
"skills"
|
|
36
59
|
],
|
|
37
60
|
"sideEffects": false,
|
|
38
61
|
"publishConfig": {
|
|
39
62
|
"access": "public"
|
|
40
63
|
},
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">=22.12"
|
|
66
|
+
},
|
|
41
67
|
"scripts": {
|
|
42
68
|
"build": "tsup",
|
|
43
69
|
"dev": "tsup --watch",
|
|
44
70
|
"typecheck": "tsc --noEmit",
|
|
45
|
-
"test:smoke": "bun run test/smoke.ts"
|
|
71
|
+
"test:smoke": "bun run test/smoke.ts && bun run test/internal.ts"
|
|
46
72
|
},
|
|
47
73
|
"keywords": [
|
|
48
74
|
"querykit",
|