@atscript/db-client 0.1.43 → 0.1.45

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/dist/index.d.mts CHANGED
@@ -1,371 +1,104 @@
1
- //#region ../../node_modules/.pnpm/@uniqu+core@0.1.2/node_modules/@uniqu/core/dist/index.d.ts
2
- /** All comparison operators supported by the filter format. */
3
- type ComparisonOp = '$eq' | '$ne' | '$gt' | '$gte' | '$lt' | '$lte' | '$in' | '$nin' | '$regex' | '$exists';
4
- /**
5
- * Per-field typed operator map. When `V` is the field's value type, operators
6
- * are constrained accordingly:
7
- * - `$regex` is only available when `V` extends `string`
8
- * - `$gt/$gte/$lt/$lte` are only available when `V` extends `number | string | Date`
9
- */
10
- type FieldOpsFor<V> = {
11
- $eq?: V;
12
- $ne?: V;
13
- $in?: V[];
14
- $nin?: V[];
15
- $exists?: boolean;
16
- } & (V extends string ? {
17
- $regex?: RegExp | string;
18
- } : {}) & (V extends number | string | Date ? {
19
- $gt?: V;
20
- $gte?: V;
21
- $lt?: V;
22
- $lte?: V;
23
- } : {});
24
- /** Untyped operator map. */
25
- /**
26
- * A filter expression is either a comparison leaf or a logical branch.
27
- * `T` is the entity shape — provides type-safe field names and value types.
28
- * Defaults to `Record<string, unknown>` (untyped).
29
- */
30
- type FilterExpr<T = Record<string, unknown>> = ComparisonNode<T> | LogicalNode<T>;
31
- /**
32
- * Leaf node: one or more field comparisons.
33
- * When `T` is typed, only known keys are allowed.
34
- * When untyped (default), any string key is accepted.
35
- */
36
- type ComparisonNode<T = Record<string, unknown>> = { [K in keyof T & string]?: T[K] | FieldOpsFor<T[K]> };
37
- /**
38
- * Branch node: logical combination of child expressions.
39
- * Each variant forbids the other logical keys via `never` to prevent
40
- * mixing comparison fields with logical operators at the type level.
41
- */
42
- type LogicalNode<T = Record<string, unknown>> = {
43
- $and: FilterExpr<T>[];
44
- $or?: never;
45
- $not?: never;
46
- } | {
47
- $or: FilterExpr<T>[];
48
- $and?: never;
49
- $not?: never;
50
- } | {
51
- $not: FilterExpr<T>;
52
- $and?: never;
53
- $or?: never;
54
- };
55
- /** Known aggregate function names. Consumers may support additional functions via the (string & {}) escape hatch. */
56
- type AggregateFn = 'sum' | 'count' | 'avg' | 'min' | 'max';
57
- /** A single aggregate function call within $select. Generic params preserve literal types for result inference. */
58
- interface AggregateExpr<Fn extends string = AggregateFn | (string & {}), Field extends string = string, Alias extends string = string> {
59
- /** Function name (sum, count, avg, min, max, or custom). */
60
- $fn: Fn;
61
- /** Field to aggregate. '*' for count(*). */
62
- $field: Field;
63
- /** Alias for the result. Auto-generated by URL parser if omitted. */
64
- $as?: Alias;
65
- }
66
- /**
67
- * Projection definition.
68
- * - Array form: inclusion list with optional aggregates.
69
- * Plain strings select fields; AggregateExpr objects define computed columns.
70
- * - Object form: inclusion/exclusion map (0 or 1 per field). No aggregates in this form.
71
- */
72
- type SelectExpr<T = Record<string, unknown>> = ((keyof T & string) | AggregateExpr)[] | Partial<Record<keyof T & string, 0 | 1>>;
73
- /** Query controls (pagination, projection, sorting, grouping). Generic `T` constrains field names. */
74
- interface UniqueryControls<T = Record<string, unknown>, Nav extends Record<string, unknown> = Record<string, unknown>> {
75
- $sort?: Partial<Record<keyof T & string, 1 | -1>>;
76
- $skip?: number;
77
- $limit?: number;
78
- $count?: boolean;
79
- $select?: SelectExpr<T>;
80
- /** Fields to group by for aggregate queries. */
81
- $groupBy?: (keyof T & string)[];
82
- /** Post-aggregation filter. Operates on aggregate aliases and dimension fields. */
83
- $having?: FilterExpr;
84
- /** Relations to populate alongside the query. */
85
- $with?: TypedWithRelation<Nav>[];
86
- /** Pass-through for unknown $-prefixed keywords. */
87
- [key: `$${string}`]: unknown;
88
- }
89
- /**
90
- * Canonical query representation.
91
- * When `name` is present this is a nested relation (sub-query inside `$with`).
92
- * When absent it is the root query.
93
- */
94
- interface Uniquery<T = Record<string, unknown>, Nav extends Record<string, unknown> = Record<string, unknown>> {
95
- /** Relation name. Present only for nested `$with` sub-queries. */
96
- name?: string;
97
- filter?: FilterExpr<T>;
98
- controls?: UniqueryControls<T, Nav>;
99
- /** Pre-computed insights. */
100
- insights?: UniqueryInsights;
101
- }
102
- /** Unwrap array types to get the element type for nav props. */
103
- type NavTarget<T> = T extends Array<infer U> ? U : T;
104
- /**
105
- * A typed $with relation entry.
106
- * When Nav is typed (from __navProps), name is constrained to known nav prop keys.
107
- * Each entry gets its own filter/controls typed to the target entity.
108
- * Falls back to untyped WithRelation when Nav has no known keys.
109
- */
110
- type TypedWithRelation<Nav extends Record<string, unknown>> = [keyof Nav & string] extends [never] ? WithRelation | string : { [K in keyof Nav & string]: {
111
- name: K;
112
- filter?: FilterExpr<NavTarget<Nav[K]> extends {
113
- __ownProps: infer F;
114
- } ? F : Record<string, unknown>>;
115
- controls?: UniqueryControls<NavTarget<Nav[K]> extends {
116
- __ownProps: infer F;
117
- } ? F : Record<string, unknown>, NavTarget<Nav[K]> extends {
118
- __navProps: infer N extends Record<string, unknown>;
119
- } ? N : Record<string, unknown>>;
120
- insights?: UniqueryInsights;
121
- } }[keyof Nav & string] | (keyof Nav & string);
122
- /** Untyped $with relation — used when Nav generic is not provided. */
123
- type WithRelation = {
124
- name: string;
125
- filter?: FilterExpr;
126
- controls?: UniqueryControls;
127
- insights?: UniqueryInsights;
128
- };
129
- /**
130
- * Insight operator includes comparison ops, control ops ($-prefixed),
131
- * and aggregate function names (bare, e.g. 'sum', 'avg').
132
- */
133
- type InsightOp = ComparisonOp | '$select' | '$order' | '$with' | '$groupBy' | '$having' | AggregateFn | (string & {});
134
- /** Map of field names to the set of operators used on that field. */
135
- type UniqueryInsights = Map<string, Set<InsightOp>>;
136
- /** Aggregate query controls. Separate from UniqueryControls: $groupBy is required, $with is forbidden. */
137
- interface AggregateControls<T = Record<string, unknown>, D extends keyof T & string = keyof T & string, M extends keyof T & string = keyof T & string> {
138
- $groupBy: D[];
139
- $select?: (D | AggregateExpr<AggregateFn, M | '*'>)[];
140
- $having?: FilterExpr;
141
- $sort?: Record<string, 1 | -1>;
142
- $skip?: number;
143
- $limit?: number;
144
- $count?: boolean;
145
- [key: `$${string}`]: unknown;
146
- }
147
- /** Aggregate query — no name (can't nest), no Nav (no $with). */
148
- interface AggregateQuery<T = Record<string, unknown>, D extends keyof T & string = keyof T & string, M extends keyof T & string = keyof T & string> {
149
- filter?: FilterExpr<T>;
150
- controls: AggregateControls<T, D, M>;
151
- insights?: UniqueryInsights;
152
- }
153
- /** Resolve the output alias of an AggregateExpr. Uses $as if provided, otherwise generates {fn}_{field}. */
154
- //#endregion
155
- //#region ../../node_modules/.pnpm/@atscript+typescript@0.1.41_@atscript+core@0.1.41_@atscript+db@packages+db_@prostojs+lo_041ff52083ad05a1dfbd1c9f541c1d21/node_modules/@atscript/typescript/dist/utils.d.ts
156
- /** Top-level serialized annotated type. JSON-safe representation of a {@link TAtscriptAnnotatedType}. */
157
- interface TSerializedAnnotatedType extends TSerializedAnnotatedTypeInner {
158
- /** Format version for forward compatibility */
159
- $v: number;
160
- }
161
- /** Serialized annotated type node (used for nested types within the top-level). */
162
- interface TSerializedAnnotatedTypeInner {
163
- type: TSerializedTypeDef;
164
- metadata: Record<string, unknown>;
165
- optional?: boolean;
166
- id?: string;
167
- }
168
- interface TSerializedTypeFinal {
169
- kind: '';
170
- designType: string;
171
- value?: string | number | boolean;
172
- tags: string[];
173
- }
174
- interface TSerializedTypeObject {
175
- kind: 'object';
176
- props: Record<string, TSerializedAnnotatedTypeInner>;
177
- propsPatterns: Array<{
178
- pattern: {
179
- source: string;
180
- flags: string;
181
- };
182
- def: TSerializedAnnotatedTypeInner;
183
- }>;
184
- tags: string[];
185
- }
186
- interface TSerializedTypeArray {
187
- kind: 'array';
188
- of: TSerializedAnnotatedTypeInner;
189
- tags: string[];
190
- }
191
- interface TSerializedTypeComplex {
192
- kind: 'union' | 'intersection' | 'tuple';
193
- items: TSerializedAnnotatedTypeInner[];
194
- tags: string[];
195
- }
196
- interface TSerializedTypeRef {
197
- kind: '$ref';
198
- id: string;
199
- }
200
- type TSerializedTypeDef = TSerializedTypeFinal | TSerializedTypeObject | TSerializedTypeArray | TSerializedTypeComplex | TSerializedTypeRef;
201
- /** Context passed to {@link TSerializeOptions.processAnnotation} for each annotation entry. */
202
- //#endregion
203
- //#region src/types.d.ts
204
- /** Options for creating a Client instance. */
205
- interface ClientOptions {
206
- /**
207
- * Custom fetch implementation. Defaults to `globalThis.fetch`.
208
- * Use this to inject auth headers, interceptors, or a custom HTTP client.
209
- */
210
- fetch?: typeof globalThis.fetch;
211
- /**
212
- * Default headers to include with every request.
213
- * Can be a static object or an async factory (e.g. for refreshing auth tokens).
214
- */
215
- headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
216
- /**
217
- * Base URL prefix. Prepended to the client path for full URL construction.
218
- * @example "https://api.example.com"
219
- */
220
- baseUrl?: string;
221
- }
222
- /** Search index metadata from the server. */
223
- interface SearchIndexInfo {
224
- name: string;
225
- description?: string;
226
- type?: "text" | "vector";
227
- }
228
- /** Relation summary in meta response. */
229
- interface RelationInfo {
230
- name: string;
231
- direction: "to" | "from" | "via";
232
- isArray: boolean;
233
- }
234
- /** Per-field capability flags. */
235
- interface FieldMeta {
236
- sortable: boolean;
237
- filterable: boolean;
238
- }
239
- /** Enhanced meta response from the server. */
240
- interface MetaResponse {
241
- searchable: boolean;
242
- vectorSearchable: boolean;
243
- searchIndexes: SearchIndexInfo[];
244
- primaryKeys: string[];
245
- readOnly: boolean;
246
- relations: RelationInfo[];
247
- fields: Record<string, FieldMeta>;
248
- type: TSerializedAnnotatedType;
249
- }
250
- interface InsertResult {
251
- insertedId: unknown;
252
- }
253
- interface InsertManyResult {
254
- insertedCount: number;
255
- insertedIds: unknown[];
256
- }
257
- interface UpdateResult {
258
- matchedCount: number;
259
- modifiedCount: number;
260
- }
261
- interface DeleteResult {
262
- deletedCount: number;
263
- }
264
- /** Paginated response shape (matches moost-db /pages response). */
265
- interface PagesResponse<T> {
266
- data: T[];
267
- page: number;
268
- itemsPerPage: number;
269
- pages: number;
270
- count: number;
271
- }
272
- /** Server error response shape (matches moost-db error transform). */
273
- interface ServerError {
274
- message: string;
275
- statusCode: number;
276
- errors?: Array<{
277
- path: string;
278
- message: string;
279
- details?: unknown[];
280
- }>;
281
- }
282
- /** Extract the data type from an Atscript annotated type `T`. */
283
- type DataOf<T> = T extends {
284
- type: {
285
- __dataType?: infer D;
286
- };
287
- } ? unknown extends D ? T extends (new (...a: any[]) => infer I) ? I : Record<string, unknown> : D & Record<string, unknown> : Record<string, unknown>;
288
- /** Extract own (non-nav) properties from an Atscript annotated type. */
289
- type OwnOf<T> = T extends {
290
- __ownProps: infer O;
291
- } ? O : DataOf<T>;
292
- /** Extract nav properties from an Atscript annotated type. */
293
- type NavOf<T> = T extends {
294
- __navProps: infer N extends Record<string, unknown>;
295
- } ? N : Record<string, never>;
296
- /** Extract primary key type from an Atscript annotated type. */
297
- type IdOf<T> = T extends {
298
- __pk: infer PK;
299
- } ? PK : unknown;
300
- /**
301
- * Shared interface for both server-side `AtscriptDbTable` and client-side `Client`.
302
- * Enables SSR isomorphism: same code runs on server (direct DB) and browser (HTTP).
303
- *
304
- * ```typescript
305
- * const users: DbInterface<typeof User> = isServer ? serverTable : httpClient
306
- * await users.findMany({ filter: { active: true } })
307
- * ```
308
- */
309
- interface DbInterface<T = Record<string, unknown>> {
310
- findOne(query: Uniquery<OwnOf<T>, NavOf<T>>): Promise<DataOf<T> | null>;
311
- findMany(query?: Uniquery<OwnOf<T>, NavOf<T>>): Promise<DataOf<T>[]>;
312
- findById(id: IdOf<T>, query?: {
313
- controls?: UniqueryControls<OwnOf<T>, NavOf<T>>;
314
- }): Promise<DataOf<T> | null>;
315
- count(query?: Uniquery<OwnOf<T>, NavOf<T>>): Promise<number>;
316
- search(text: string, query?: Uniquery<OwnOf<T>, NavOf<T>>, indexName?: string): Promise<DataOf<T>[]>;
317
- aggregate(query: AggregateQuery): Promise<Record<string, unknown>[]>;
318
- insertOne(data: Partial<DataOf<T>>): Promise<InsertResult>;
319
- insertMany(data: Partial<DataOf<T>>[]): Promise<InsertManyResult>;
320
- updateOne(data: Partial<DataOf<T>>): Promise<UpdateResult>;
321
- bulkUpdate(data: Partial<DataOf<T>>[]): Promise<UpdateResult>;
322
- replaceOne(data: DataOf<T>): Promise<UpdateResult>;
323
- bulkReplace(data: DataOf<T>[]): Promise<UpdateResult>;
324
- deleteOne(id: IdOf<T>): Promise<DeleteResult>;
325
- }
326
- //#endregion
1
+ import { C as TDbUpdateResult, E as UniqueryControls, S as TDbInsertResult, T as Uniquery, _ as RelationInfo, b as TDbDeleteResult, c as ClientOptions, d as FilterExpr, f as IdOf, g as PageResult, h as OwnOf, i as ValidatorMode, l as DataOf, m as NavOf, n as ClientValidator, o as AggregateQuery, p as MetaResponse, s as AggregateResult, t as ClientValidationError, u as FieldMeta, v as SearchIndexInfo, w as TypedWithRelation, x as TDbInsertManyResult, y as ServerError } from "./validator-D0lqruKm.mjs";
2
+ import { TSerializedAnnotatedType } from "@atscript/typescript/utils";
3
+ import { AggregateQuery as AggregateQuery$1, AggregateResult as AggregateResult$1, Uniquery as Uniquery$1, UniqueryControls as UniqueryControls$1 } from "@uniqu/core";
4
+ import { TDbDeleteResult as TDbDeleteResult$1, TDbInsertManyResult as TDbInsertManyResult$1, TDbInsertResult as TDbInsertResult$1, TDbUpdateResult as TDbUpdateResult$1 } from "@atscript/db";
5
+
327
6
  //#region src/client.d.ts
7
+ type Own<T> = OwnOf<T>;
8
+ type Nav<T> = NavOf<T>;
9
+ type Data<T> = DataOf<T>;
10
+ type Id<T> = IdOf<T>;
328
11
  /**
329
- * Browser-compatible HTTP client for moost-db REST endpoints.
12
+ * HTTP client for moost-db REST endpoints.
330
13
  *
331
- * Two usage modes (same class, different generic):
332
- * ```typescript
333
- * // Untyped broad Record<string, unknown> typing
334
- * const users = new Client('/db/tables/users')
14
+ * Each method maps 1:1 to a controller endpoint:
15
+ * - `query()` → `GET /query`
16
+ * - `count()` `GET /query` with `$count`
17
+ * - `aggregate()` `GET /query` with `$groupBy`
18
+ * - `pages()` → `GET /pages`
19
+ * - `one()` → `GET /one/:id` or `GET /one?compositeKeys`
20
+ * - `insert()` → `POST /`
21
+ * - `update()` → `PATCH /`
22
+ * - `replace()` → `PUT /`
23
+ * - `remove()` → `DELETE /:id` or `DELETE /?compositeKeys`
24
+ * - `meta()` → `GET /meta`
335
25
  *
336
- * // Type-safe — Atscript type as generic parameter
337
- * const users = new Client<typeof User>('/db/tables/users')
26
+ * ```typescript
27
+ * const users = new Client<typeof User>('/api/users')
28
+ * const all = await users.query()
29
+ * const page = await users.pages({ filter: { active: true } }, 1, 20)
338
30
  * ```
339
31
  */
340
- declare class Client<T = Record<string, unknown>> implements DbInterface<T> {
32
+ declare class Client<T = Record<string, unknown>> {
341
33
  private readonly _path;
342
34
  private readonly _baseUrl;
343
35
  private readonly _fetch;
344
36
  private readonly _headers?;
345
37
  private _metaPromise?;
38
+ private _validatorPromise?;
346
39
  constructor(path: string, opts?: ClientOptions);
347
- findOne(query: Uniquery<OwnOf<T>, NavOf<T>>): Promise<DataOf<T> | null>;
348
- findMany(query?: Uniquery<OwnOf<T>, NavOf<T>>): Promise<DataOf<T>[]>;
349
- findById(id: IdOf<T>, query?: {
350
- controls?: UniqueryControls<OwnOf<T>, NavOf<T>>;
351
- }): Promise<DataOf<T> | null>;
352
- count(query?: Uniquery<OwnOf<T>, NavOf<T>>): Promise<number>;
353
- findManyWithCount(query: Uniquery<OwnOf<T>, NavOf<T>>): Promise<{
354
- data: DataOf<T>[];
355
- count: number;
356
- }>;
357
- pages(query?: Uniquery<OwnOf<T>, NavOf<T>>): Promise<PagesResponse<DataOf<T>>>;
358
- search(text: string, query?: Uniquery<OwnOf<T>, NavOf<T>>, indexName?: string): Promise<DataOf<T>[]>;
359
- aggregate(query: AggregateQuery): Promise<Record<string, unknown>[]>;
360
- insertOne(data: Partial<DataOf<T>>): Promise<InsertResult>;
361
- insertMany(data: Partial<DataOf<T>>[]): Promise<InsertManyResult>;
362
- updateOne(data: Partial<DataOf<T>>): Promise<UpdateResult>;
363
- bulkUpdate(data: Partial<DataOf<T>>[]): Promise<UpdateResult>;
364
- replaceOne(data: DataOf<T>): Promise<UpdateResult>;
365
- bulkReplace(data: DataOf<T>[]): Promise<UpdateResult>;
366
- deleteOne(id: IdOf<T>): Promise<DeleteResult>;
40
+ /**
41
+ * `GET /query` query records with typed filter, sort, select, and relations.
42
+ */
43
+ query(query?: Uniquery$1<Own<T>, Nav<T>>): Promise<Data<T>[]>;
44
+ /**
45
+ * `GET /query` with `$count: true` — returns record count.
46
+ */
47
+ count(query?: {
48
+ filter?: Uniquery$1<Own<T>, Nav<T>>["filter"];
49
+ }): Promise<number>;
50
+ /**
51
+ * `GET /query` with `$groupBy` aggregate query with typed dimension/measure fields.
52
+ */
53
+ aggregate<Q extends AggregateQuery$1<Own<T>>>(query: Q): Promise<Q["controls"]["$select"] extends readonly (string | {
54
+ $fn: string;
55
+ $field: string;
56
+ })[] ? AggregateResult$1<Own<T>, Q["controls"]["$select"]>[] : Record<string, unknown>[]>;
57
+ /**
58
+ * `GET /pages` — paginated query with typed filter and relations.
59
+ */
60
+ pages(query?: Uniquery$1<Own<T>, Nav<T>>, page?: number, size?: number): Promise<PageResult<Data<T>>>;
61
+ /**
62
+ * `GET /one/:id` or `GET /one?k1=v1&k2=v2` — single record by primary key.
63
+ *
64
+ * Returns `null` on 404.
65
+ */
66
+ one(id: Id<T>, query?: {
67
+ controls?: UniqueryControls$1<Own<T>, Nav<T>>;
68
+ }): Promise<Data<T> | null>;
69
+ /**
70
+ * `POST /` — insert one record.
71
+ */
72
+ insert(data: Partial<Data<T>>): Promise<TDbInsertResult$1>;
73
+ /**
74
+ * `POST /` — insert many records.
75
+ */
76
+ insert(data: Partial<Data<T>>[]): Promise<TDbInsertManyResult$1>;
77
+ /**
78
+ * `PATCH /` — partial update one or many records by primary key.
79
+ */
80
+ update(data: Partial<Data<T>> | Partial<Data<T>>[]): Promise<TDbUpdateResult$1>;
81
+ /**
82
+ * `PUT /` — full replace one or many records by primary key.
83
+ */
84
+ replace(data: Data<T> | Data<T>[]): Promise<TDbUpdateResult$1>;
85
+ /**
86
+ * `DELETE /:id` or `DELETE /?k1=v1&k2=v2` — remove a record by primary key.
87
+ */
88
+ remove(id: Id<T>): Promise<TDbDeleteResult$1>;
89
+ /**
90
+ * `GET /meta` — table/view metadata (cached after first call).
91
+ */
367
92
  meta(): Promise<MetaResponse>;
93
+ /**
94
+ * Returns a lazily-initialized {@link ClientValidator} backed by the `/meta` type.
95
+ * Useful for accessing `flatMap` and `navFields` (e.g. for form generation).
96
+ */
97
+ getValidator(): Promise<ClientValidator>;
98
+ private _validateData;
99
+ private _getValidator;
368
100
  private _idToParams;
101
+ private _getOrNull;
369
102
  private _get;
370
103
  private _resolveHeaders;
371
104
  private _request;
@@ -395,4 +128,4 @@ declare class ClientError extends Error {
395
128
  }[];
396
129
  }
397
130
  //#endregion
398
- export { type AggregateQuery, Client, ClientError, type ClientOptions, type DataOf, type DbInterface, type DeleteResult, type FieldMeta, type FilterExpr, type IdOf, type InsertManyResult, type InsertResult, type MetaResponse, type NavOf, type OwnOf, type PagesResponse, type RelationInfo, type SearchIndexInfo, type ServerError, type TSerializedAnnotatedType, type TypedWithRelation, type Uniquery, type UniqueryControls, type UpdateResult };
131
+ export { type AggregateQuery, type AggregateResult, Client, ClientError, type ClientOptions, type ClientValidationError, type ClientValidator, type DataOf, type FieldMeta, type FilterExpr, type IdOf, type MetaResponse, type NavOf, type OwnOf, type PageResult, type RelationInfo, type SearchIndexInfo, type ServerError, type TDbDeleteResult, type TDbInsertManyResult, type TDbInsertResult, type TDbUpdateResult, type TSerializedAnnotatedType, type TypedWithRelation, type Uniquery, type UniqueryControls, type ValidatorMode };