@solidxai/core 0.1.11-beta.0 → 0.1.11-beta.1
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/repository/scheduled-job.repository.d.ts +3 -0
- package/dist/repository/scheduled-job.repository.d.ts.map +1 -1
- package/dist/repository/scheduled-job.repository.js +60 -0
- package/dist/repository/scheduled-job.repository.js.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts +32 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +1011 -230
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/services/action-metadata.service.d.ts +7 -0
- package/dist/services/action-metadata.service.d.ts.map +1 -1
- package/dist/services/action-metadata.service.js +76 -3
- package/dist/services/action-metadata.service.js.map +1 -1
- package/dist/services/role-metadata.service.d.ts +4 -0
- package/dist/services/role-metadata.service.d.ts.map +1 -1
- package/dist/services/role-metadata.service.js +72 -31
- package/dist/services/role-metadata.service.js.map +1 -1
- package/dist/services/view-metadata.service.d.ts +6 -0
- package/dist/services/view-metadata.service.d.ts.map +1 -1
- package/dist/services/view-metadata.service.js +66 -1
- package/dist/services/view-metadata.service.js.map +1 -1
- package/dist-tests/api/authenticate.spec.js +119 -0
- package/dist-tests/api/authenticate.spec.js.map +1 -0
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +97 -0
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +1 -0
- package/dist-tests/api/ping.spec.js +21 -0
- package/dist-tests/api/ping.spec.js.map +1 -0
- package/dist-tests/helpers/auth.js +41 -0
- package/dist-tests/helpers/auth.js.map +1 -0
- package/dist-tests/helpers/env.js +11 -0
- package/dist-tests/helpers/env.js.map +1 -0
- package/docs/agent-hub-grooming.md +301 -0
- package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +438 -0
- package/docs/dashboards/dashboard-curl-smoke-tests.txt +146 -0
- package/docs/dashboards/delete-legacy-dashboard-metadata.sql +172 -0
- package/docs/datasource-introspection-ddl-analysis.md +326 -0
- package/docs/datasource-introspection-implementation-plan.md +306 -0
- package/docs/grouping-enhancements.md +89 -0
- package/docs/java-spring/README.md +3 -0
- package/docs/java-spring/solid-core-module-deep-dive-report.md +1317 -0
- package/docs/module-package-import-handoff.md +691 -0
- package/docs/seed-changes.md +65 -0
- package/docs/test-data-workflow.md +200 -0
- package/docs/type-declaration-import-issue.md +24 -0
- package/package.json +1 -1
- package/src/repository/scheduled-job.repository.ts +73 -0
- package/src/seeders/module-metadata-seeder.service.ts +1223 -262
- package/src/services/action-metadata.service.ts +87 -2
- package/src/services/role-metadata.service.ts +86 -47
- package/src/services/view-metadata.service.ts +79 -1
- package/.claude/settings.local.json +0 -15
- package/src/services/1.js +0 -6
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# Datasource Introspection Implementation Plan
|
|
2
|
+
|
|
3
|
+
## Current Status
|
|
4
|
+
- [x] Review the handwritten UX note for datasource introspection.
|
|
5
|
+
- [x] Inspect how SolidX currently represents models in metadata JSON.
|
|
6
|
+
- [x] Inspect the three superclass patterns used by generated entities.
|
|
7
|
+
- [x] Inspect migration placement conventions via `solidctl`.
|
|
8
|
+
- [x] Compare DDL SQL files against generated entities and metadata JSON.
|
|
9
|
+
- Detailed findings are captured in [datasource-introspection-ddl-analysis.md](/Users/harishpatel/Code/javascript/solid-core-module/docs/datasource-introspection-ddl-analysis.md).
|
|
10
|
+
- The only blocked subset is the missing `MOB3PO_*` amextxn DDL coverage.
|
|
11
|
+
|
|
12
|
+
## Scope We Are Planning For
|
|
13
|
+
- [x] Given a datasource and a target module, inspect legacy database tables and generate SolidX model metadata JSON.
|
|
14
|
+
- [x] Keep per-session mapping options in frontend React state and send them to dedicated backend endpoints.
|
|
15
|
+
- [x] Treat the generated metadata JSON as the primary output of introspection.
|
|
16
|
+
- [x] Leave the rest of the code asset generation to existing SolidX flows such as `refresh model`.
|
|
17
|
+
- [x] Force introspection-created legacy mappings onto `synchronize = false`.
|
|
18
|
+
- [x] Add a migration generation path that is template-based rather than TypeORM diff-based.
|
|
19
|
+
|
|
20
|
+
## Findings From The Current Analysis
|
|
21
|
+
|
|
22
|
+
### 1. `legacyTableType` is already the right switch
|
|
23
|
+
- [x] `ModelMetadata` already persists `legacyTableType` and supports `none`, `existing_id`, and `generated_id`.
|
|
24
|
+
- [x] `CreateModelMetadataDto` already accepts `legacyTableType`.
|
|
25
|
+
- [x] `ModelMetadataHelperService.getSystemFieldsMetadata()` already derives system fields from `legacyTableType`.
|
|
26
|
+
- [x] This means the new introspection flow should emit the correct `legacyTableType` instead of inventing a parallel concept.
|
|
27
|
+
|
|
28
|
+
### 2. The three superclass rules are now clear
|
|
29
|
+
- [x] `CommonEntity` is the Solid-native case.
|
|
30
|
+
- Use when the table follows standard SolidX system columns like `id`, `created_at`, `updated_at`, `deleted_at`, `published_at`, `created_by_id`, and `updated_by_id`.
|
|
31
|
+
- Metadata should use `legacyTableType = none`.
|
|
32
|
+
- [x] `LegacyCommonEntityWithExistingId` is the legacy-table-with-existing-key case.
|
|
33
|
+
- Use when the legacy table already has a stable key strategy and SolidX should not add a generated `ss_id`.
|
|
34
|
+
- SolidX system fields are expected with the `ss_` prefix.
|
|
35
|
+
- Metadata should use `legacyTableType = existing_id`.
|
|
36
|
+
- [x] `LegacyCommonEntityWithGeneratedId` is the legacy-table-needing-surrogate-id case.
|
|
37
|
+
- Use when the legacy table does not have the SolidX-style surrogate key we want for framework operations.
|
|
38
|
+
- SolidX adds generated `ss_id` plus the other `ss_` system fields.
|
|
39
|
+
- Metadata should use `legacyTableType = generated_id`.
|
|
40
|
+
|
|
41
|
+
### 3. System fields are not guessed, they are already encoded
|
|
42
|
+
- [x] For `none`, SolidX expects system fields such as `id`, `createdAt`, `updatedAt`, `deletedAt`, `deletedTracker`, `publishedAt`, `localeName`, `defaultEntityLocaleId`, `createdBy`, and `updatedBy`.
|
|
43
|
+
- [x] For legacy tables, the same logical system fields are mapped to `ss_*` column names.
|
|
44
|
+
- [x] For `generated_id`, `id` is included and maps to `ss_id`.
|
|
45
|
+
- [x] For `existing_id`, the generated `id` system field is omitted.
|
|
46
|
+
- [x] The introspection implementation should reuse these existing rules instead of hardcoding them a second time.
|
|
47
|
+
|
|
48
|
+
### 4. Entity-vs-metadata audit shows existing inconsistencies
|
|
49
|
+
- [x] I compared entity superclass usage against model metadata entries in `mswipe-erp-solidx`.
|
|
50
|
+
- [x] Sample audit result:
|
|
51
|
+
- Total models checked: `114`
|
|
52
|
+
- Matches between entity superclass and metadata `legacyTableType`: `81`
|
|
53
|
+
- Mismatches: `33`
|
|
54
|
+
- [x] The mismatches are mostly cases where the entity clearly extends a legacy superclass but metadata still falls back to implicit `none`.
|
|
55
|
+
- [x] Example mismatches observed:
|
|
56
|
+
- `peoples/employee` extends `LegacyCommonEntityWithExistingId`, but metadata does not stamp `existing_id`.
|
|
57
|
+
- `mswipe-masters/itemMaster` extends `LegacyCommonEntityWithGeneratedId`, but metadata does not stamp `generated_id`.
|
|
58
|
+
- `frms/frmsLead` extends `LegacyCommonEntityWithGeneratedId`, but metadata does not stamp `generated_id`.
|
|
59
|
+
- [x] Conclusion:
|
|
60
|
+
- Existing metadata JSON is directionally useful, but not always fully normalized.
|
|
61
|
+
- The introspection feature should treat superclass/legacy strategy rules as explicit logic, not as something to infer from historical metadata files alone.
|
|
62
|
+
|
|
63
|
+
### 5. What current metadata JSON tells us about the target output
|
|
64
|
+
- [x] A model metadata entry minimally needs:
|
|
65
|
+
- `singularName`
|
|
66
|
+
- `pluralName`
|
|
67
|
+
- `displayName`
|
|
68
|
+
- `description`
|
|
69
|
+
- `dataSource`
|
|
70
|
+
- `dataSourceType`
|
|
71
|
+
- `tableName`
|
|
72
|
+
- `enableAuditTracking`
|
|
73
|
+
- `enableSoftDelete`
|
|
74
|
+
- `draftPublishWorkflow`
|
|
75
|
+
- `internationalisation`
|
|
76
|
+
- `isChild`
|
|
77
|
+
- `fields`
|
|
78
|
+
- optional `userKeyFieldUserKey`
|
|
79
|
+
- optional `legacyTableType`
|
|
80
|
+
- [x] A field metadata entry minimally needs:
|
|
81
|
+
- `name`
|
|
82
|
+
- `displayName`
|
|
83
|
+
- `type`
|
|
84
|
+
- `ormType`
|
|
85
|
+
- `required`
|
|
86
|
+
- `unique`
|
|
87
|
+
- `index`
|
|
88
|
+
- `private`
|
|
89
|
+
- `columnName`
|
|
90
|
+
- optional `max`
|
|
91
|
+
- optional `defaultValue`
|
|
92
|
+
- optional `isPrimaryKey`
|
|
93
|
+
- optional `isUserKey`
|
|
94
|
+
- [x] This aligns well with a backend introspection service that produces normalized DTO-shaped JSON rather than source files directly.
|
|
95
|
+
|
|
96
|
+
### 6. DDL-to-JSON comparison status
|
|
97
|
+
- [x] The DDL-vs-entity-vs-metadata comparison has now been completed for the available exports.
|
|
98
|
+
- [ ] We still need to validate the missing `MOB3PO_*` amextxn tables once their DDL is available.
|
|
99
|
+
- [x] The completed comparison covered:
|
|
100
|
+
- column name preservation
|
|
101
|
+
- nullable to `required` mapping
|
|
102
|
+
- key/index mapping
|
|
103
|
+
- `varchar` length mapping
|
|
104
|
+
- numeric precision/scale mapping
|
|
105
|
+
- date/time type mapping
|
|
106
|
+
- defaults
|
|
107
|
+
- foreign-key relation opportunities
|
|
108
|
+
- whether a table should be `none`, `existing_id`, or `generated_id`
|
|
109
|
+
|
|
110
|
+
## Proposed Backend Design
|
|
111
|
+
|
|
112
|
+
### Controller Layer
|
|
113
|
+
- [ ] Add a dedicated controller for datasource introspection endpoints inside `solid-core-module`.
|
|
114
|
+
- [ ] Keep it separate from generic CRUD metadata endpoints because this workflow is file-backed, session-driven, and safety-sensitive.
|
|
115
|
+
|
|
116
|
+
### Service Layer
|
|
117
|
+
- [ ] Add an orchestration service, for example `DatasourceIntrospectionService`, responsible for:
|
|
118
|
+
- loading datasource configuration
|
|
119
|
+
- validating `synchronize = false`
|
|
120
|
+
- selecting the correct database-engine implementation
|
|
121
|
+
- normalizing introspection results into SolidX model metadata DTOs
|
|
122
|
+
- writing metadata JSON updates
|
|
123
|
+
- optionally generating template migrations
|
|
124
|
+
|
|
125
|
+
### Engine Interface
|
|
126
|
+
- [ ] Define a shared interface for engine-specific implementations, for example:
|
|
127
|
+
- `listTables()`
|
|
128
|
+
- `describeTable(tableName)`
|
|
129
|
+
- `listColumns(tableName)`
|
|
130
|
+
- `listPrimaryKeys(tableName)`
|
|
131
|
+
- `listIndexes(tableName)`
|
|
132
|
+
- `listForeignKeys(tableName)`
|
|
133
|
+
- `inferLegacyTableType(tableDescriptor, options)`
|
|
134
|
+
- [ ] Implement providers for:
|
|
135
|
+
- `MssqlDatasourceIntrospectionProvider`
|
|
136
|
+
- `MysqlDatasourceIntrospectionProvider`
|
|
137
|
+
- `PostgresDatasourceIntrospectionProvider`
|
|
138
|
+
- [ ] Keep database-specific SQL isolated to these providers.
|
|
139
|
+
|
|
140
|
+
### Metadata Mapping Layer
|
|
141
|
+
- [ ] Add a mapper layer that converts engine-neutral table/column descriptors into `CreateModelMetadataDto`-shaped objects.
|
|
142
|
+
- [ ] This mapper should own:
|
|
143
|
+
- table-name to model-name conversion
|
|
144
|
+
- column-name to field-name conversion
|
|
145
|
+
- `ormType` mapping
|
|
146
|
+
- Solid field type mapping
|
|
147
|
+
- `required`, `unique`, `index`, `defaultValue`, and `max` derivation
|
|
148
|
+
- `userKeyFieldUserKey` selection
|
|
149
|
+
- `legacyTableType` resolution
|
|
150
|
+
|
|
151
|
+
### File Writer Layer
|
|
152
|
+
- [ ] Add a file writer that updates the module metadata JSON file on disk.
|
|
153
|
+
- [ ] This should support:
|
|
154
|
+
- append new model metadata into an existing module JSON
|
|
155
|
+
- optionally create a new module JSON if the user chose “new module”
|
|
156
|
+
- stable formatting and ordering so diffs stay readable
|
|
157
|
+
|
|
158
|
+
### Migration Template Layer
|
|
159
|
+
- [ ] Add a template-based migration generator for introspected models.
|
|
160
|
+
- [ ] This generator should not rely on TypeORM schema diffing.
|
|
161
|
+
- [ ] It should instead emit migrations that add only the SolidX superclass columns implied by:
|
|
162
|
+
- `legacyTableType = existing_id`
|
|
163
|
+
- `legacyTableType = generated_id`
|
|
164
|
+
- possibly `legacyTableType = none` if we ever support generating Solid-native tables from this flow
|
|
165
|
+
- [ ] Generated files must land under the same folder convention used by `solidctl`:
|
|
166
|
+
- `solid-api/src/<module>/migrations/<datasource>/`
|
|
167
|
+
|
|
168
|
+
## Proposed Frontend Design
|
|
169
|
+
|
|
170
|
+
### Primary UX Direction
|
|
171
|
+
- [ ] Add datasource introspection as a focused workflow rather than a generic list view.
|
|
172
|
+
- [ ] Entry point should sit close to module creation/editing because the user is mapping tables into a module.
|
|
173
|
+
- [ ] Follow the note’s flow:
|
|
174
|
+
- choose new module or existing module
|
|
175
|
+
- choose datasource
|
|
176
|
+
- list tables in datasource
|
|
177
|
+
- indicate whether each table is already mapped
|
|
178
|
+
- if mapped, route into the model form view
|
|
179
|
+
- if not mapped, open a mapping UI for columns and settings
|
|
180
|
+
|
|
181
|
+
### Session Settings
|
|
182
|
+
- [ ] Keep mapping-session options in React state and send them with each introspection request.
|
|
183
|
+
- [ ] Likely session options:
|
|
184
|
+
- target module
|
|
185
|
+
- datasource
|
|
186
|
+
- naming conventions override
|
|
187
|
+
- audit tracking default
|
|
188
|
+
- default user key strategy
|
|
189
|
+
- relation inference toggle
|
|
190
|
+
- include/exclude tables
|
|
191
|
+
- preferred `legacyTableType` override
|
|
192
|
+
- migration generation toggle
|
|
193
|
+
|
|
194
|
+
### Sync Safety Guard
|
|
195
|
+
- [ ] Before allowing table mapping, fetch datasource details and validate that synchronize is disabled.
|
|
196
|
+
- [ ] If synchronize is `true`, block the flow with a clear validation message.
|
|
197
|
+
- [ ] This validation should be enforced in both UI and backend.
|
|
198
|
+
|
|
199
|
+
## Legacy Table Strategy Rules For Introspection
|
|
200
|
+
|
|
201
|
+
### `legacyTableType = none`
|
|
202
|
+
- [ ] Use only when the datasource/table is intended to behave like a Solid-native table.
|
|
203
|
+
- [ ] For the legacy-database mapping flow, this should probably be rare.
|
|
204
|
+
|
|
205
|
+
### `legacyTableType = existing_id`
|
|
206
|
+
- [ ] Use when the table already has a stable business or primary key that SolidX can rely on.
|
|
207
|
+
- [ ] Typical indicators:
|
|
208
|
+
- a meaningful single-column key already exists
|
|
209
|
+
- the table already has a durable row identity that should remain authoritative
|
|
210
|
+
- we do not want to add `ss_id`
|
|
211
|
+
|
|
212
|
+
### `legacyTableType = generated_id`
|
|
213
|
+
- [ ] Use when the table does not offer a suitable SolidX-compatible surrogate key.
|
|
214
|
+
- [ ] Typical indicators:
|
|
215
|
+
- composite or awkward primary keys
|
|
216
|
+
- no stable numeric surrogate key
|
|
217
|
+
- we still need a generated SolidX framework identity via `ss_id`
|
|
218
|
+
|
|
219
|
+
### Important Note
|
|
220
|
+
- [ ] The final decision logic should be explicit and reviewable.
|
|
221
|
+
- [ ] Do not quietly infer superclass choice from incomplete historical metadata JSON.
|
|
222
|
+
|
|
223
|
+
## Type Mapping Rules To Confirm Once DDL Arrives
|
|
224
|
+
- [ ] MSSQL:
|
|
225
|
+
- `varchar` / `nvarchar` -> `shortText` or `longText` depending on length
|
|
226
|
+
- `text` -> `longText`
|
|
227
|
+
- `bit` -> `boolean`
|
|
228
|
+
- `int` / `bigint` / `numeric` / `decimal` -> numeric Solid field types
|
|
229
|
+
- `date` / `datetime` / `datetime2` / `time` -> date/time Solid field types
|
|
230
|
+
- [ ] MySQL:
|
|
231
|
+
- confirm handling of `tinyint(1)` for boolean-like columns
|
|
232
|
+
- confirm `text` family mapping thresholds
|
|
233
|
+
- [ ] PostgreSQL:
|
|
234
|
+
- confirm `text`, `json`, `jsonb`, `timestamp`, `timestamptz`, `uuid`
|
|
235
|
+
- [ ] Cross-engine:
|
|
236
|
+
- precision/scale preservation in `ormType`-driven fields
|
|
237
|
+
- default value normalization
|
|
238
|
+
- nullability to `required`
|
|
239
|
+
|
|
240
|
+
## Proposed API Shape
|
|
241
|
+
|
|
242
|
+
### Discovery Endpoints
|
|
243
|
+
- [ ] `GET /datasource-introspection/datasources`
|
|
244
|
+
- [ ] `GET /datasource-introspection/datasources/:name/tables`
|
|
245
|
+
- [ ] `GET /datasource-introspection/datasources/:name/tables/:tableName`
|
|
246
|
+
|
|
247
|
+
### Mapping Endpoints
|
|
248
|
+
- [ ] `POST /datasource-introspection/preview-model`
|
|
249
|
+
- returns the normalized model metadata JSON payload before writing
|
|
250
|
+
- [ ] `POST /datasource-introspection/apply-model`
|
|
251
|
+
- writes model metadata JSON into the chosen module
|
|
252
|
+
- [ ] `POST /datasource-introspection/generate-migration`
|
|
253
|
+
- creates the template migration for superclass/system columns
|
|
254
|
+
|
|
255
|
+
### Safety / Validation
|
|
256
|
+
- [ ] Every write endpoint should verify:
|
|
257
|
+
- datasource exists
|
|
258
|
+
- module exists or can be created
|
|
259
|
+
- `synchronize` is `false`
|
|
260
|
+
- target table is not already mapped unless overwrite is explicitly requested
|
|
261
|
+
|
|
262
|
+
## Proposed Execution Phases
|
|
263
|
+
|
|
264
|
+
### Phase 1: Audit And Foundations
|
|
265
|
+
- [ ] Finalize DDL-vs-JSON comparison once SQL files are added.
|
|
266
|
+
- [ ] Write down exact superclass decision rules with examples.
|
|
267
|
+
- [ ] Decide the canonical naming-conversion rules for model and field names.
|
|
268
|
+
- [ ] Decide how to pick `userKeyFieldUserKey`.
|
|
269
|
+
|
|
270
|
+
### Phase 2: Backend Read Path
|
|
271
|
+
- [ ] Implement datasource introspection controller and orchestration service.
|
|
272
|
+
- [ ] Implement engine interface and MSSQL provider first.
|
|
273
|
+
- [ ] Add table and column discovery endpoints.
|
|
274
|
+
- [ ] Add normalize-to-metadata preview endpoint.
|
|
275
|
+
|
|
276
|
+
### Phase 3: Frontend Flow
|
|
277
|
+
- [ ] Add the new introspection entry point in the module workflow.
|
|
278
|
+
- [ ] Build datasource selector and table browser.
|
|
279
|
+
- [ ] Show mapped vs unmapped tables.
|
|
280
|
+
- [ ] Add preview/mapping canvas for a selected table.
|
|
281
|
+
- [ ] Add synchronize guardrail messaging.
|
|
282
|
+
|
|
283
|
+
### Phase 4: Write Path
|
|
284
|
+
- [ ] Persist generated model metadata JSON into the module metadata file.
|
|
285
|
+
- [ ] Support “add to existing module”.
|
|
286
|
+
- [ ] Support “create new module”.
|
|
287
|
+
- [ ] Prevent duplicate model/table mappings.
|
|
288
|
+
|
|
289
|
+
### Phase 5: Migration Templates
|
|
290
|
+
- [ ] Generate migration stubs for superclass/system columns.
|
|
291
|
+
- [ ] Place migrations under the datasource-specific module folder.
|
|
292
|
+
- [ ] Ensure generation works cleanly with the existing `solidctl migration` conventions.
|
|
293
|
+
|
|
294
|
+
### Phase 6: Validation And Hardening
|
|
295
|
+
- [ ] Validate generated metadata by running the downstream SolidX refresh flow.
|
|
296
|
+
- [ ] Test against at least one MSSQL datasource first.
|
|
297
|
+
- [ ] Then add MySQL and PostgreSQL coverage.
|
|
298
|
+
- [ ] Add regression checks for relation inference, key detection, and field-type mapping.
|
|
299
|
+
|
|
300
|
+
## Immediate Next Steps
|
|
301
|
+
- [ ] Wait for the DDL SQL files to be added under `mswipe-erp-solidx`.
|
|
302
|
+
- [ ] Once ready, perform a table-by-table comparison between:
|
|
303
|
+
- DDL SQL
|
|
304
|
+
- generated TypeORM entity
|
|
305
|
+
- module metadata JSON
|
|
306
|
+
- [ ] Use that comparison to lock the exact mapping rules before implementation begins.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Grouping & Aggregation Enhancements (Code Review Summary)
|
|
2
|
+
|
|
3
|
+
This document explains the recent changes to grouping/aggregation in the CRUD helper/service, why they were made, and how to use them (with examples on `PincodeMaster`).
|
|
4
|
+
|
|
5
|
+
## What Changed and Why
|
|
6
|
+
- **Dedicated grouping pipeline**: Grouping no longer reuses the record-level query (which had `SELECT entity.*`, pagination, and default order). A separate path builds clean group queries to avoid SQL errors and ensure correct counts.
|
|
7
|
+
- **Multiple group-by fields**: The one-field limit was removed. You can now group on multiple fields (including relations) in the requested order.
|
|
8
|
+
- **Relation-safe grouping**: Group-by fields can traverse many-to-one relations (e.g., `state.name`, `city.name`). The helper reuses existing joins (from filters) or adds the necessary joins and aliases.
|
|
9
|
+
- **Date granularity**: Grouping supports `day`, `week`, `month`, `year` granularities in a DB-aware way (Postgres, MySQL/MariaDB, SQL Server).
|
|
10
|
+
- **Aggregates**: Supports a core, DB-agnostic set: `count`, `count_distinct`, `sum`, `avg`, `min`, `max`. If `aggregates` is omitted, it defaults to `count(*)`.
|
|
11
|
+
- **Group sorting/pagination**: Sorting and pagination are applied to group rows (not entity rows). Record pagination is kept separate for non-grouped queries.
|
|
12
|
+
- **Ordered group names**: Group names follow the order of `groupBy` fields. Relation values and date/grouped values are included in sequence.
|
|
13
|
+
- **Formatted date group labels**: You can add an optional format specifier to a date groupBy field: `field:granularity:format`. Supported formats: `MMM`, `MMMM`, `YYYY`, `YYYY-MM`, `YYYY-MM-DD` (defaults to the raw value if omitted).
|
|
14
|
+
- **Count of groups**: Group counts are computed without pagination interference, so `meta.totalRecords` reflects total groups.
|
|
15
|
+
- **DTO update**: `BasicFilterDto` now includes optional `aggregates?: string[]`.
|
|
16
|
+
|
|
17
|
+
## Caveats
|
|
18
|
+
- `populateGroup` is **not** supported when grouping on relation fields (e.g., `state.name`, `city.name`). Use it for scalar group-by fields only; otherwise fetch group metadata and then retrieve records in a separate call with the group key.
|
|
19
|
+
- Sorting works for group keys without extra colons (e.g., `state.name`) and for aggregate aliases (e.g., `id_max`). For date bucket group keys with granularity/format (`createdAt:month:YYYY`), the sort parser treats the last segment as the order; results may vary by driver and may not sort as expected in all cases.
|
|
20
|
+
|
|
21
|
+
## Usage Examples (PincodeMaster)
|
|
22
|
+
Assume `PincodeMaster` has many-to-one `state` and `city` relations and a `createdAt` timestamp.
|
|
23
|
+
|
|
24
|
+
### 1) Group by State and City
|
|
25
|
+
```
|
|
26
|
+
GET /api/pincode-master?offset=0&limit=200&groupBy[0]=state.name&groupBy[1]=city.name
|
|
27
|
+
```
|
|
28
|
+
Returns groups for every state/city combination with default `count(*)` aggregate.
|
|
29
|
+
|
|
30
|
+
### 2) Group by Relation + Filter on Relation
|
|
31
|
+
```
|
|
32
|
+
GET /api/pincode-master?offset=0&limit=200&groupBy[0]=state.name&filters[state][name][$eq]=Maharashtra
|
|
33
|
+
```
|
|
34
|
+
Groups by state name but only for rows where state is Maharashtra.
|
|
35
|
+
|
|
36
|
+
### 3) Multiple Group Fields (Relation + Scalar)
|
|
37
|
+
```
|
|
38
|
+
GET /api/pincode-master?offset=0&limit=200&groupBy[0]=state.name&groupBy[1]=city.name&groupBy[2]=pincode
|
|
39
|
+
```
|
|
40
|
+
Group names are ordered: state → city → pincode.
|
|
41
|
+
|
|
42
|
+
### 4) Group by Date with Granularity (Month)
|
|
43
|
+
```
|
|
44
|
+
GET /api/pincode-master?offset=0&limit=200&groupBy[0]=createdAt:month
|
|
45
|
+
```
|
|
46
|
+
Groups by month (driver-aware), default group labels are raw date buckets.
|
|
47
|
+
|
|
48
|
+
### 5) Date Granularity with Formatting
|
|
49
|
+
```
|
|
50
|
+
GET /api/pincode-master?offset=0&limit=200&groupBy[0]=createdAt:month:MMM
|
|
51
|
+
```
|
|
52
|
+
Group labels use short month names (Jan, Feb, …). For full names: `createdAt:month:MMMM`. Other formats: `YYYY`, `YYYY-MM`, `YYYY-MM-DD`.
|
|
53
|
+
|
|
54
|
+
### 6) Aggregates (Count Distinct)
|
|
55
|
+
```
|
|
56
|
+
GET /api/pincode-master?offset=0&limit=200&groupBy[0]=state.name&aggregates[0]=pincode:count_distinct
|
|
57
|
+
```
|
|
58
|
+
Shows distinct pincodes per state.
|
|
59
|
+
|
|
60
|
+
### 7) Aggregates (Multiple)
|
|
61
|
+
```
|
|
62
|
+
GET /api/pincode-master?offset=0&limit=200&groupBy[0]=state.name&groupBy[1]=city.name&aggregates[0]=id:count&aggregates[1]=id:count_distinct
|
|
63
|
+
```
|
|
64
|
+
Returns both total rows and distinct IDs per state/city group.
|
|
65
|
+
|
|
66
|
+
### 8) Date Granularity + Relations + Aggregates
|
|
67
|
+
```
|
|
68
|
+
GET /api/pincode-master?offset=0&limit=200&groupBy[0]=createdAt:year&groupBy[1]=state.name&aggregates[0]=pincode:count_distinct
|
|
69
|
+
```
|
|
70
|
+
Distinct pincodes per state, per year.
|
|
71
|
+
|
|
72
|
+
### 9) Filters with Grouping (Many-to-One)
|
|
73
|
+
```
|
|
74
|
+
GET /api/pincode-master?offset=0&limit=200&groupBy[0]=state.name&groupBy[1]=city.name&filters[state][name][$eq]=Nagaland
|
|
75
|
+
```
|
|
76
|
+
Groups only rows where state.name = Nagaland.
|
|
77
|
+
|
|
78
|
+
### 10) Group Sorting and Pagination
|
|
79
|
+
- Sorting applies to the group rows. Example:
|
|
80
|
+
```
|
|
81
|
+
GET /api/pincode-master?offset=0&limit=50&groupBy[0]=state.name&sort[0]=state.name:ASC
|
|
82
|
+
```
|
|
83
|
+
- Pagination (`offset/limit`) limits the number of groups returned; total group count remains in `meta.totalRecords`.
|
|
84
|
+
|
|
85
|
+
## Notes and Behavior
|
|
86
|
+
- If `aggregates` is omitted, `COUNT(*)` is added automatically.
|
|
87
|
+
- Group names reflect `groupBy` order and apply formatting when specified.
|
|
88
|
+
- Group queries reuse joins from filters when possible; otherwise, they create necessary joins for relation paths.
|
|
89
|
+
- Non-grouped find behavior remains unchanged.
|