tina4-nodejs 3.13.95 → 3.13.96

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.
@@ -31,53 +31,43 @@ export declare class DatabaseResult implements Iterable<Record<string, unknown>>
31
31
  toCsv(): string;
32
32
  /** Same as records — plain array of row objects. */
33
33
  toArray(): Record<string, unknown>[];
34
- /** Pagination envelope — accepts either (page, perPage) or (offset, limit) style.
34
+ /**
35
+ * Describe the page this result IS — the canonical pagination envelope.
35
36
  *
36
- * When called with two arguments both >= 0 and the first >= the second
37
- * (i.e. offset-style), pass `{ offset, limit }` as the first argument.
38
- * The simplest way is to always use the default (page, perPage) form and
39
- * let the autoCRUD layer supply offset/limit from the query string.
37
+ * Takes NO arguments and derives every field from the query that produced this
38
+ * result (ADR-0043). Passing ANY argument RAISES: a DatabaseResult holds no
39
+ * connection, so an argument could only re-slice the rows already in memory and
40
+ * then report total_pages for pages it can never reach. To read page N, FETCH
41
+ * page N (limit + offset) and call this with no arguments.
40
42
  *
41
- * Returns a superset of keys for backwards-compatibility across all clients.
42
- */
43
- /**
44
- * Describe the page this result actually IS. Takes no arguments.
43
+ * The envelope is EXACTLY seven snake_case keys, identical across all four
44
+ * frameworks: `records, total, page, per_page, total_pages, limit, offset`.
45
45
  *
46
- * MEASURED 2026-08-05 on a real 250-row table read with limit=20 offset=40
47
- * (page 3 of 13): this reported page 1 of 2 and returned 10 of the 20 rows.
48
- * It ignored the query entirely - defaulting page to 1 and perPage to 10 -
49
- * then re-sliced the rows it was handed, which were already just that page.
50
- * So a caller who paginated correctly at the SQL level had the answer
51
- * silently re-paginated underneath them, with a page number that was simply
52
- * wrong.
46
+ * per_page = the query's limit
47
+ * page = floor(offset / limit) + 1
48
+ * total = the TRUE total for the filter Database.fetch (and
49
+ * QueryBuilder.get) run a COUNT probe whenever a limit was
50
+ * applied NEVER the number of rows returned
51
+ * total_pages = ceil(total / per_page)
52
+ * records = the rows the query returned, VERBATIM (never re-sliced)
53
+ * limit = the SQL limit actually applied
54
+ * offset = the SQL offset actually applied
53
55
  *
54
- * WITH page/perPage it slices this result in memory, the behaviour GitHub
55
- * issue #106 asked for. Valid ONLY when the result holds the WHOLE set
56
- * (records.length >= count). A PARTIAL result cannot be sliced by page number
57
- * without lying: MEASURED on 100,000 rows read under the default cap of 100,
58
- * pages 1-5 of 20 were right and every page from 6 onward came back EMPTY
59
- * while totalPages reported 5,000.
56
+ * The JSON payload is snake_case even though the method name is camelCase — a
57
+ * JSON key is data, not a language surface (ADR-0043). The old duplicate and
58
+ * camelCase keys (`data`, `count`, `perPage`, `totalPages`, `has_next`,
59
+ * `has_prev`) are removed: Node emitted 13 keys, the worst offender of the four.
60
60
  *
61
- * `total` is `count`, and `count` is now the TRUE total for the filter in
62
- * all four frameworks - Database.fetch runs a COUNT probe whenever it applied
63
- * a limit. It used to be ROWS RETURNED here and in Ruby while Python and PHP
64
- * probed, so one query answered 20 in two frameworks and 250 in the other
65
- * two.
61
+ * @throws {TypeError} if called with any argument.
66
62
  */
67
- toPaginate(page?: number, perPage?: number): {
63
+ toPaginate(): {
68
64
  records: Record<string, unknown>[];
69
- data: Record<string, unknown>[];
70
- count: number;
71
65
  total: number;
72
- limit: number;
73
- offset: number;
74
66
  page: number;
75
67
  per_page: number;
76
- perPage: number;
77
- totalPages: number;
78
68
  total_pages: number;
79
- has_next: boolean;
80
- has_prev: boolean;
69
+ limit: number;
70
+ offset: number;
81
71
  };
82
72
  /** Iterable — for (const row of result) */
83
73
  [Symbol.iterator](): Iterator<Record<string, unknown>>;
@@ -1,5 +1,4 @@
1
- export type { FieldType, FieldDefinition, ModelDefinition, DatabaseAdapter, DatabaseResult as DatabaseWriteResult, ColumnInfo, QueryOptions, RelationshipDefinition, PaginatedResult, } from "./types.js";
2
- export { FetchResult } from "./types.js";
1
+ export type { FieldType, FieldDefinition, ModelDefinition, DatabaseAdapter, DatabaseResult as DatabaseWriteResult, ColumnInfo, QueryOptions, RelationshipDefinition, } from "./types.js";
3
2
  export { DatabaseResult } from "./databaseResult.js";
4
3
  export type { ColumnInfoResult } from "./databaseResult.js";
5
4
  export { Database, initDatabase, getAdapter, setAdapter, bindDatabase, createAdapterFromUrl, closeDatabase, parseDatabaseUrl, setNamedAdapter, getNamedAdapter, resolveDbPool, stripTrailingSemicolons, wrapWithCache, resetRequestCaches } from "./database.js";
@@ -206,7 +206,7 @@ export declare function status(adapter?: DatabaseAdapter, options?: {
206
206
  */
207
207
  export declare function createMigration(description: string, options?: {
208
208
  migrationsDir?: string;
209
- kind?: "sql" | "class";
209
+ kind?: "sql" | "code" | "class";
210
210
  }): Promise<string | {
211
211
  upPath: string;
212
212
  downPath: string;
@@ -258,11 +258,12 @@ export declare class Migration {
258
258
  * Scaffold a new migration file.
259
259
  *
260
260
  * kind="sql" — creates {timestamp}_{description}.sql + .down.sql (default)
261
- * kind="class" — creates {timestamp}_{description}.ts with a TypeScript class template
261
+ * kind="code" — creates {timestamp}_{description}.ts with a TypeScript class
262
+ * template. "class" is accepted as a legacy alias.
262
263
  *
263
264
  * Returns the path to the created up file (or class file).
264
265
  */
265
- create(description: string, kind?: "sql" | "class"): Promise<string | {
266
+ create(description: string, kind?: "sql" | "code" | "class"): Promise<string | {
266
267
  upPath: string;
267
268
  downPath: string;
268
269
  }>;
@@ -28,6 +28,13 @@ export interface RelationshipDefinition {
28
28
  }
29
29
  export interface ModelDefinition {
30
30
  tableName: string;
31
+ /**
32
+ * The model CLASS name (e.g. `Item` for tableName `items`), carried from
33
+ * `ModelClass.name` at discovery. Swagger keys `components.schemas` by this —
34
+ * the type name a generated client wants — falling back to a singular
35
+ * PascalCase derivation of tableName when a raw definition carries none.
36
+ */
37
+ className?: string;
31
38
  fields: Record<string, FieldDefinition>;
32
39
  fieldMapping?: Record<string, string>;
33
40
  softDelete?: boolean;
@@ -106,40 +113,6 @@ export interface DatabaseAdapter {
106
113
  */
107
114
  cacheIdentity?: string;
108
115
  }
109
- export interface PaginatedResult<T = Record<string, unknown>> {
110
- data: T[];
111
- page: number;
112
- perPage: number;
113
- total: number;
114
- totalPages: number;
115
- hasNext: boolean;
116
- hasPrev: boolean;
117
- }
118
- /**
119
- * Wraps an array of fetched rows with convenience methods.
120
- *
121
- * Mirrors Python's `DatabaseResult` and Ruby's `Tina4::DatabaseResult`.
122
- */
123
- export declare class FetchResult<T = Record<string, unknown>> {
124
- readonly records: T[];
125
- readonly count: number;
126
- readonly sql: string;
127
- constructor(records: T[], sql?: string);
128
- /** Paginate the in-memory result set. */
129
- toPaginate(page?: number, perPage?: number): PaginatedResult<T>;
130
- /** Return the first record or null. */
131
- first(): T | null;
132
- /** Return the last record or null. */
133
- last(): T | null;
134
- /** Check if result is empty. */
135
- isEmpty(): boolean;
136
- /** Convert to plain array. */
137
- toArray(): T[];
138
- /** Convert to JSON string. */
139
- toJSON(): string;
140
- /** Iterate over records. */
141
- [Symbol.iterator](): Iterator<T>;
142
- }
143
116
  export interface QueryOptions {
144
117
  filter?: Record<string, unknown>;
145
118
  sort?: string;