tina4-nodejs 3.13.131 → 3.13.133
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/CLAUDE.md +3 -2
- package/package.json +1 -1
- package/packages/cli/dist/bin.js +398 -302
- package/packages/core/dist/index.js +399 -302
- package/packages/core/public/js/tina4-dev-admin.min.js +148 -512
- package/packages/core/src/devAdmin.ts +0 -46
- package/packages/core/src/index.ts +1 -1
- package/packages/core/src/server.ts +129 -3
- package/packages/frond/dist/index.js +52 -104
- package/packages/frond/src/engine.ts +52 -100
- package/packages/orm/dist/index.js +399 -302
- package/packages/orm/src/baseModel.ts +64 -55
- package/packages/orm/src/index.ts +2 -0
- package/packages/orm/src/modelCollection.ts +149 -0
- package/packages/swagger/dist/index.js +150 -116
- package/packages/swagger/src/generator.ts +261 -154
- package/types/core/src/index.d.ts +1 -1
- package/types/core/src/server.d.ts +15 -0
- package/types/frond/src/engine.d.ts +11 -0
- package/types/orm/src/baseModel.d.ts +20 -5
- package/types/orm/src/index.d.ts +2 -0
- package/types/orm/src/modelCollection.d.ts +101 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModelCollection — a list of ORM models that also carries the query total.
|
|
3
|
+
*
|
|
4
|
+
* What the ORM read queries (`where` / `select` / `find` filter-form / `all` /
|
|
5
|
+
* `withTrashed`) return. It IS an Array — iterate it, index it, slice it, `.map`
|
|
6
|
+
* it, `.filter` it, read `.length`, `JSON.stringify` it — so every existing
|
|
7
|
+
* caller keeps working unchanged (`Array.isArray(coll) === true`). It adds one
|
|
8
|
+
* thing: the TOTAL number of rows matching the query's filter, independent of
|
|
9
|
+
* `limit` / `offset`.
|
|
10
|
+
*
|
|
11
|
+
* The total is free. Every one of those methods already runs the fetch COUNT
|
|
12
|
+
* probe (`db.fetch` / `probeTotal`) that computes `SELECT COUNT(*)` for the same
|
|
13
|
+
* filter; the ORM used to hydrate the page of models and throw that count away.
|
|
14
|
+
* This class carries it instead, so a caller with 20 models on the page can
|
|
15
|
+
* still learn there are 250 rows in the set. ZERO extra queries.
|
|
16
|
+
*
|
|
17
|
+
* Uniform across all four Tina4 frameworks (ADR-0064). Same concept, language-
|
|
18
|
+
* idiomatic accessor name:
|
|
19
|
+
*
|
|
20
|
+
* Python / Ruby : get_total_records() to_paginate()
|
|
21
|
+
* PHP / Node : getTotalRecords() toPaginate()
|
|
22
|
+
*
|
|
23
|
+
* The accessor is a METHOD, not a `.total` property, on purpose: `Array#count`
|
|
24
|
+
* exists in Ruby and `list.count()` in Python, so a `.count` would shadow a
|
|
25
|
+
* built-in. `DatabaseResult` keeps its `.count` property (it is not a list); both
|
|
26
|
+
* expose the identical seven-key `toPaginate()` envelope.
|
|
27
|
+
*
|
|
28
|
+
* ### Why a real Array subclass with `[Symbol.species] === Array`
|
|
29
|
+
*
|
|
30
|
+
* `class X extends Array` is the parity-faithful backing (the ADR-0064 table
|
|
31
|
+
* says Node is a "subclass of Array"), and it keeps `Array.isArray` true and
|
|
32
|
+
* `instanceof ModelCollection` true (mirroring Python's `isinstance`). BUT a bare
|
|
33
|
+
* Array subclass is a footgun: `map`/`filter`/`slice` build the result via
|
|
34
|
+
* `this.constructor[Symbol.species]`, calling the constructor with a single
|
|
35
|
+
* NUMBER (the length), and `new X(oneNumber)` means "length N", not "one
|
|
36
|
+
* element". Overriding `[Symbol.species]` to return `Array` makes every derived
|
|
37
|
+
* operation build a plain `Array` — so `.map`/`.filter`/`.slice`/spread never
|
|
38
|
+
* touch this constructor and can never explode. The constructor below is also
|
|
39
|
+
* defended against the numeric-length call directly, so even a path that ignores
|
|
40
|
+
* species is safe.
|
|
41
|
+
*/
|
|
42
|
+
/** The canonical pagination envelope — seven snake_case keys (ADR-0043/0064). */
|
|
43
|
+
export interface PaginateEnvelope {
|
|
44
|
+
records: unknown[];
|
|
45
|
+
total: number;
|
|
46
|
+
page: number;
|
|
47
|
+
per_page: number;
|
|
48
|
+
total_pages: number;
|
|
49
|
+
limit: number;
|
|
50
|
+
offset: number;
|
|
51
|
+
}
|
|
52
|
+
export declare class ModelCollection<T = unknown> extends Array<T> {
|
|
53
|
+
/** Total rows matching the query's filter (ignores limit/offset). */
|
|
54
|
+
private _total;
|
|
55
|
+
/** The SQL limit that produced this page. */
|
|
56
|
+
private _limit;
|
|
57
|
+
/** The SQL offset that produced this page. */
|
|
58
|
+
private _offset;
|
|
59
|
+
/**
|
|
60
|
+
* Derived array operations (`map`, `filter`, `slice`, spread, …) build a plain
|
|
61
|
+
* `Array`, never another `ModelCollection`. This is what defuses the Array-
|
|
62
|
+
* subclass constructor/species trap: the engine never calls this constructor
|
|
63
|
+
* with a length during those operations.
|
|
64
|
+
*/
|
|
65
|
+
static get [Symbol.species](): ArrayConstructor;
|
|
66
|
+
/**
|
|
67
|
+
* @param items the page of hydrated model instances (or the length, when the
|
|
68
|
+
* engine constructs a derived array — defended against here).
|
|
69
|
+
* @param total total rows matching the query's filter (ignores limit/offset).
|
|
70
|
+
* @param limit the SQL limit that produced this page.
|
|
71
|
+
* @param offset the SQL offset that produced this page.
|
|
72
|
+
*/
|
|
73
|
+
constructor(items?: readonly T[] | number, total?: number, limit?: number, offset?: number);
|
|
74
|
+
/**
|
|
75
|
+
* Total rows matching the query's filter, ignoring limit/offset.
|
|
76
|
+
*
|
|
77
|
+
* This is the whole point of the collection: the page slice you are iterating
|
|
78
|
+
* is capped by `limit`, but this number is the full count of matching rows —
|
|
79
|
+
* what a pager needs to render "page 3 of 13".
|
|
80
|
+
*/
|
|
81
|
+
getTotalRecords(): number;
|
|
82
|
+
/**
|
|
83
|
+
* The canonical pagination envelope — seven snake_case keys, identical to
|
|
84
|
+
* `DatabaseResult.toPaginate()` (ADR-0043) and to the other three frameworks'
|
|
85
|
+
* `toPaginate()` / `to_paginate()`.
|
|
86
|
+
*
|
|
87
|
+
* records the page's rows as plain objects (never re-sliced)
|
|
88
|
+
* total getTotalRecords() — the true total for the filter
|
|
89
|
+
* page floor(offset / per_page) + 1
|
|
90
|
+
* per_page the query's limit
|
|
91
|
+
* total_pages ceil(total / per_page)
|
|
92
|
+
* limit the SQL limit actually applied
|
|
93
|
+
* offset the SQL offset actually applied
|
|
94
|
+
*
|
|
95
|
+
* `records` are model dicts (via `toDict()`, the same serialisation the
|
|
96
|
+
* framework applies to a model in a JSON response), so the JSON a client sees
|
|
97
|
+
* matches `DatabaseResult` exactly — the result is uniform whether the route
|
|
98
|
+
* returned a raw `db.fetch()` or an ORM query.
|
|
99
|
+
*/
|
|
100
|
+
toPaginate(): PaginateEnvelope;
|
|
101
|
+
}
|