jsonbadger 0.5.0 → 0.6.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.
Files changed (123) hide show
  1. package/README.md +36 -18
  2. package/docs/api/connection.md +144 -0
  3. package/docs/api/delta-tracker.md +106 -0
  4. package/docs/api/document.md +77 -0
  5. package/docs/api/field-types.md +329 -0
  6. package/docs/api/index.md +35 -0
  7. package/docs/api/model.md +392 -0
  8. package/docs/api/query-builder.md +81 -0
  9. package/docs/api/schema.md +204 -0
  10. package/docs/architecture-flow.md +397 -0
  11. package/docs/examples.md +495 -218
  12. package/docs/jsonb-ops.md +171 -0
  13. package/docs/lifecycle/model-compilation.md +111 -0
  14. package/docs/lifecycle.md +146 -0
  15. package/docs/query-translation.md +11 -10
  16. package/package.json +10 -3
  17. package/src/connection/connect.js +12 -17
  18. package/src/connection/connection.js +128 -0
  19. package/src/connection/server-capabilities.js +60 -59
  20. package/src/constants/defaults.js +32 -19
  21. package/src/constants/{id-strategies.js → id-strategy.js} +28 -29
  22. package/src/constants/intake-mode.js +8 -0
  23. package/src/debug/debug-logger.js +17 -15
  24. package/src/errors/model-overwrite-error.js +25 -0
  25. package/src/errors/query-error.js +25 -23
  26. package/src/errors/validation-error.js +25 -23
  27. package/src/field-types/base-field-type.js +137 -140
  28. package/src/field-types/builtins/advanced.js +365 -365
  29. package/src/field-types/builtins/index.js +579 -585
  30. package/src/field-types/field-type-namespace.js +9 -0
  31. package/src/field-types/registry.js +149 -122
  32. package/src/index.js +26 -36
  33. package/src/migration/ensure-index.js +157 -154
  34. package/src/migration/ensure-schema.js +27 -15
  35. package/src/migration/ensure-table.js +44 -31
  36. package/src/migration/schema-indexes-resolver.js +8 -6
  37. package/src/model/document-instance.js +29 -540
  38. package/src/model/document.js +60 -0
  39. package/src/model/factory/constants.js +36 -0
  40. package/src/model/factory/index.js +58 -0
  41. package/src/model/model.js +875 -0
  42. package/src/model/operations/delete-one.js +39 -0
  43. package/src/model/operations/insert-one.js +35 -0
  44. package/src/model/operations/query-builder.js +132 -0
  45. package/src/model/operations/update-one.js +333 -0
  46. package/src/model/state.js +34 -0
  47. package/src/schema/field-definition-parser.js +213 -218
  48. package/src/schema/path-introspection.js +87 -82
  49. package/src/schema/schema-compiler.js +126 -212
  50. package/src/schema/schema.js +621 -138
  51. package/src/sql/index.js +17 -0
  52. package/src/sql/jsonb/ops.js +153 -0
  53. package/src/{query → sql/jsonb}/path-parser.js +54 -43
  54. package/src/sql/jsonb/read/elem-match.js +133 -0
  55. package/src/{query → sql/jsonb/read}/operators/contains.js +13 -7
  56. package/src/sql/jsonb/read/operators/elem-match.js +9 -0
  57. package/src/{query → sql/jsonb/read}/operators/has-all-keys.js +17 -11
  58. package/src/{query → sql/jsonb/read}/operators/has-any-keys.js +18 -11
  59. package/src/sql/jsonb/read/operators/has-key.js +12 -0
  60. package/src/{query → sql/jsonb/read}/operators/jsonpath-exists.js +22 -15
  61. package/src/{query → sql/jsonb/read}/operators/jsonpath-match.js +22 -15
  62. package/src/{query → sql/jsonb/read}/operators/size.js +23 -16
  63. package/src/sql/parameter-binder.js +18 -13
  64. package/src/sql/read/build-count-query.js +12 -0
  65. package/src/sql/read/build-find-query.js +25 -0
  66. package/src/sql/read/limit-skip.js +21 -0
  67. package/src/sql/read/sort.js +85 -0
  68. package/src/sql/read/where/base-fields.js +310 -0
  69. package/src/sql/read/where/casting.js +90 -0
  70. package/src/sql/read/where/context.js +79 -0
  71. package/src/sql/read/where/field-clause.js +58 -0
  72. package/src/sql/read/where/index.js +38 -0
  73. package/src/sql/read/where/operator-entries.js +29 -0
  74. package/src/{query → sql/read/where}/operators/all.js +16 -10
  75. package/src/sql/read/where/operators/eq.js +12 -0
  76. package/src/{query → sql/read/where}/operators/gt.js +23 -16
  77. package/src/{query → sql/read/where}/operators/gte.js +23 -16
  78. package/src/{query → sql/read/where}/operators/in.js +18 -12
  79. package/src/sql/read/where/operators/index.js +40 -0
  80. package/src/{query → sql/read/where}/operators/lt.js +23 -16
  81. package/src/{query → sql/read/where}/operators/lte.js +23 -16
  82. package/src/sql/read/where/operators/ne.js +12 -0
  83. package/src/{query → sql/read/where}/operators/nin.js +18 -12
  84. package/src/{query → sql/read/where}/operators/regex.js +14 -8
  85. package/src/sql/read/where/operators.js +126 -0
  86. package/src/sql/read/where/text-operators.js +83 -0
  87. package/src/sql/run.js +46 -0
  88. package/src/sql/write/build-delete-query.js +33 -0
  89. package/src/sql/write/build-insert-query.js +42 -0
  90. package/src/sql/write/build-update-query.js +65 -0
  91. package/src/utils/assert.js +34 -27
  92. package/src/utils/delta-tracker/.archive/1 tracker-redesign-codex-v2.md +250 -0
  93. package/src/utils/delta-tracker/.archive/1 tracker-redesign-gemini.md +101 -0
  94. package/src/utils/delta-tracker/.archive/2 evaluation by gemini.txt +65 -0
  95. package/src/utils/delta-tracker/.archive/2 evaluation by grok.txt +39 -0
  96. package/src/utils/delta-tracker/.archive/3 gemini evaluate grok.txt +37 -0
  97. package/src/utils/delta-tracker/.archive/3 grok evaluate gemini.txt +63 -0
  98. package/src/utils/delta-tracker/.archive/4 gemini veredict.txt +16 -0
  99. package/src/utils/delta-tracker/.archive/index.1.js +587 -0
  100. package/src/utils/delta-tracker/.archive/index.2.js +612 -0
  101. package/src/utils/delta-tracker/index.js +592 -0
  102. package/src/utils/dirty-tracker/inline.js +335 -0
  103. package/src/utils/dirty-tracker/instance.js +414 -0
  104. package/src/utils/dirty-tracker/static.js +343 -0
  105. package/src/utils/json-safe.js +13 -9
  106. package/src/utils/object-path.js +227 -33
  107. package/src/utils/object.js +408 -168
  108. package/src/utils/string.js +55 -0
  109. package/src/utils/value.js +169 -30
  110. package/docs/api.md +0 -152
  111. package/src/connection/disconnect.js +0 -16
  112. package/src/connection/pool-store.js +0 -46
  113. package/src/model/model-factory.js +0 -555
  114. package/src/query/limit-skip-compiler.js +0 -31
  115. package/src/query/operators/elem-match.js +0 -3
  116. package/src/query/operators/eq.js +0 -6
  117. package/src/query/operators/has-key.js +0 -6
  118. package/src/query/operators/index.js +0 -60
  119. package/src/query/operators/ne.js +0 -6
  120. package/src/query/query-builder.js +0 -93
  121. package/src/query/sort-compiler.js +0 -30
  122. package/src/query/where-compiler.js +0 -477
  123. package/src/sql/sql-runner.js +0 -31
@@ -0,0 +1,397 @@
1
+ # Architecture Flow
2
+
3
+ This page shows the current JsonBadger runtime flow as ASCII diagrams.
4
+
5
+ ## 1. Bootstrap
6
+
7
+ ```text
8
+ User code
9
+ |
10
+ v
11
+ public API entry
12
+ |
13
+ +--> connect()
14
+ +--> Schema
15
+ +--> field_type
16
+ +--> field_types
17
+ ```
18
+
19
+ Important:
20
+
21
+ - there is no root `disconnect()`
22
+ - there is no root `model()`
23
+ - the public API is Connection-first
24
+
25
+ ## 2. Connection Flow
26
+
27
+ ```text
28
+ User
29
+ |
30
+ v
31
+ JsonBadger.connect(uri, options)
32
+ |
33
+ v
34
+ connection bootstrap
35
+ |
36
+ +--> validate options
37
+ +--> create pg.Pool
38
+ +--> SELECT 1
39
+ +--> scan server capabilities
40
+ +--> create Connection(pool_instance, options, server_capabilities)
41
+ +--> on bootstrap failure:
42
+ - close_pool_quietly(pool_instance)
43
+ - rethrow original error
44
+ |
45
+ v
46
+ returns Connection
47
+ ```
48
+
49
+ Important:
50
+
51
+ - each `connect(...)` call creates a new `Connection`
52
+ - there is no process-global current connection
53
+ - if you want reuse, cache the returned `Connection` explicitly
54
+
55
+ ## 3. Connection Ownership
56
+
57
+ ```text
58
+ Connection
59
+ |
60
+ +--> owns pool_instance
61
+ +--> owns normalized options
62
+ +--> owns server_capabilities
63
+ +--> owns model registry
64
+ +--> exposes:
65
+ - model(model_definition)
66
+ - disconnect()
67
+ ```
68
+
69
+ ## 4. Schema Flow
70
+
71
+ ```text
72
+ User
73
+ |
74
+ v
75
+ new Schema(schema_definition, options)
76
+ |
77
+ v
78
+ Schema
79
+ |
80
+ +--> inject base fields: id / created_at / updated_at
81
+ +--> compile schema definition
82
+ +--> build introspection paths
83
+ +--> normalize inline index declarations
84
+ +--> normalize slug options
85
+ +--> build aliases
86
+ +--> build conform tree
87
+ +--> configure validators:
88
+ - base field validator
89
+ - slug-slice validators
90
+ +--> register field-defined indexes
91
+ +--> register schema instance methods via Schema.add_method(...)
92
+ +--> store:
93
+ - paths
94
+ - indexes
95
+ - options
96
+ - id_strategy
97
+ - auto_index
98
+ - methods
99
+ - aliases
100
+ - validators
101
+ - $conform_tree
102
+ ```
103
+
104
+ Important:
105
+
106
+ - slug ownership belongs to `Schema`
107
+ - `Schema` owns the final runtime `id_strategy`
108
+ - schema methods are later installed on compiled model constructors
109
+
110
+ ## 5. Model Registration Flow
111
+
112
+ ```text
113
+ User
114
+ |
115
+ v
116
+ connection.model({name, schema, table_name, ...})
117
+ |
118
+ v
119
+ Connection.model(...)
120
+ |
121
+ +--> validate model_definition.name
122
+ +--> build model options from model_definition
123
+ +--> derive table_name from name when omitted
124
+ +--> return existing model when schema/options match
125
+ +--> throw ModelOverwriteError on conflicting redefinition
126
+ +--> require schema instanceof Schema
127
+ +--> build compiled model constructor/runtime
128
+ ```
129
+
130
+ Compiled model owns:
131
+
132
+ - `$name`
133
+ - `schema`
134
+ - `options`
135
+ - `connection`
136
+ - `state`
137
+
138
+ Document runtime exposes:
139
+
140
+ - built-in instance methods like `get`, `set`, `save`, `insert`, and `update`
141
+ - schema-defined instance methods copied from `schema.methods`
142
+
143
+ ## 6. Construction Flow
144
+
145
+ New payload intake:
146
+
147
+ ```text
148
+ External payload
149
+ |
150
+ v
151
+ Model.from(...)
152
+ |
153
+ v
154
+ extract_from_document_fields(...)
155
+ |
156
+ +--> serialize non-plain input
157
+ +--> expand dotted payload keys
158
+ +--> route base fields / default slug / extra slugs
159
+ |
160
+ v
161
+ new Model(document)
162
+ |
163
+ v
164
+ instance.$normalize({mode: 'from'})
165
+ |
166
+ +--> instance.$conform_document(...)
167
+ +--> instance.$apply_defaults(...)
168
+ +--> instance.$cast(...)
169
+ +--> instance.$validate(...)
170
+ |
171
+ v
172
+ instance.document.$rebase_changes()
173
+ |
174
+ v
175
+ new document instance
176
+ ```
177
+
178
+ Persisted row intake:
179
+
180
+ ```text
181
+ Raw row from SQL
182
+ |
183
+ v
184
+ Model.hydrate(...)
185
+ |
186
+ v
187
+ extract_hydrated_document_fields(...)
188
+ |
189
+ +--> serialize non-plain row input
190
+ +--> copy base fields from row root
191
+ +--> read schema.get_slugs() from row roots
192
+ |
193
+ v
194
+ new Model(document)
195
+ |
196
+ v
197
+ instance.$normalize({mode: 'hydrate'})
198
+ |
199
+ +--> instance.$conform_document(...)
200
+ +--> instance.$apply_defaults(...)
201
+ +--> instance.$cast(...)
202
+ +--> instance.$validate(...)
203
+ |
204
+ v
205
+ instance.document.$rebase_changes()
206
+ |
207
+ v
208
+ instance.is_new = false
209
+ |
210
+ v
211
+ rebased persisted model instance
212
+ ```
213
+
214
+ Manual low-level path:
215
+
216
+ ```text
217
+ const instance = new UserModel(document)
218
+ |
219
+ +--> raw tracked document state only
220
+ +--> no conform / defaults / cast / validate yet
221
+ |
222
+ +--> instance.$conform_document(...)
223
+ +--> instance.$apply_defaults(...)
224
+ +--> instance.$cast(...)
225
+ +--> instance.$validate(...)
226
+ +--> or instance.$normalize(...)
227
+ +--> optionally instance.document.$rebase_changes()
228
+ ```
229
+
230
+ ## 7. Read Query Flow
231
+
232
+ ```text
233
+ User
234
+ |
235
+ v
236
+ model constructor read methods
237
+ |
238
+ +--> Model.find(...)
239
+ +--> Model.find_one(...)
240
+ +--> Model.count_documents(...)
241
+ |
242
+ v
243
+ query builder
244
+ |
245
+ +--> where_compiler(..., {schema, data_column, id_strategy})
246
+ +--> sort_compiler(...)
247
+ +--> limit_skip_compiler(...)
248
+ +--> sql_runner(sql_text, params, Model.connection)
249
+ |
250
+ v
251
+ Connection.pool_instance.query(...)
252
+ |
253
+ v
254
+ PostgreSQL
255
+ ```
256
+
257
+ Hydration path for document-returning reads:
258
+
259
+ ```text
260
+ query row
261
+ |
262
+ +--> row_to_document(...)
263
+ | - id -> string|null
264
+ | - data -> object fallback
265
+ | - created_at / updated_at -> ISO timestamp
266
+ |
267
+ v
268
+ Model.hydrate(...)
269
+ |
270
+ v
271
+ document instance
272
+ ```
273
+
274
+ ## 8. Write Flow
275
+
276
+ ```text
277
+ User
278
+ |
279
+ +--> Model.insert_one(plain_input)
280
+ | |
281
+ | +--> Model.from(...)
282
+ | +--> doc.insert()
283
+ | +--> schema.validate(document)
284
+ | +--> apply_timestamps(document)
285
+ | +--> exec_insert_one(...)
286
+ | +--> sql_runner(..., Model.connection)
287
+ | +--> raw inserted row
288
+ | +--> rebase same instance
289
+ |
290
+ +--> Model.from(...).save()
291
+ | |
292
+ | +--> doc.insert()
293
+ | +--> schema.validate(document)
294
+ | +--> apply_timestamps(document)
295
+ | +--> exec_insert_one(...)
296
+ | +--> sql_runner(..., Model.connection)
297
+ | +--> raw inserted row
298
+ | +--> rebase same instance
299
+ |
300
+ +--> hydrated_doc.save()
301
+ | |
302
+ | +--> schema.validate(document)
303
+ | +--> set updated_at
304
+ | +--> require id for persisted update
305
+ | +--> build tracker delta
306
+ | +--> exec_update_one(...)
307
+ | +--> sql_runner(..., Model.connection)
308
+ | +--> raw updated row
309
+ | +--> rebase current document
310
+ |
311
+ +--> Model.update_one(filter, update_definition)
312
+ | |
313
+ | +--> normalize update gateway
314
+ | +--> normalize update definition
315
+ | +--> JsonbOps.from(...)
316
+ | +--> where_compiler(..., {schema, data_column, id_strategy})
317
+ | +--> exec_update_one(...)
318
+ | +--> sql_runner(..., Model.connection)
319
+ | +--> raw updated row
320
+ | +--> Model.hydrate(row)
321
+ |
322
+ +--> Model.delete_one(...)
323
+ |
324
+ +--> where_compiler(..., {schema, data_column, id_strategy})
325
+ +--> sql_runner(..., Model.connection)
326
+ +--> raw deleted row
327
+ +--> Model.hydrate(row)
328
+ ```
329
+
330
+ ## 9. Migration And Index Flow
331
+
332
+ ```text
333
+ App startup / bootstrap
334
+ |
335
+ v
336
+ Model.ensure_table()
337
+ |
338
+ +--> read model.schema.id_strategy
339
+ +--> if uuidv7: assert server capability snapshot
340
+ +--> table migration helper
341
+ +--> execute through explicit Connection
342
+
343
+ Model.ensure_indexes()
344
+ |
345
+ +--> resolve schema indexes
346
+ +--> index migration helper
347
+ +--> execute through explicit Connection
348
+
349
+ Model.ensure_model()
350
+ |
351
+ +--> ensure table
352
+ +--> ensure schema indexes when schema.auto_index is enabled
353
+ +--> execute through explicit Connection
354
+ ```
355
+
356
+ Important:
357
+
358
+ - run `ensure_*` helpers during startup/bootstrap
359
+ - `uuidv7` capability is enforced at `Model.ensure_table()`, not at `connect(...)`
360
+ - normal runtime read/write operations do not provision tables or indexes implicitly
361
+
362
+ ## Ownership Summary
363
+
364
+ ```text
365
+ Connection
366
+ |
367
+ +--> owns one pool
368
+ +--> owns normalized connection options
369
+ +--> owns one capability snapshot
370
+ +--> owns one model registry
371
+ |
372
+ Schema
373
+ |
374
+ +--> owns paths, indexes, slug ownership, aliases, and validators
375
+ +--> owns id_strategy and auto_index
376
+ +--> owns the document conform tree
377
+ |
378
+ Model
379
+ |
380
+ +--> is compiled through Connection.model(...)
381
+ +--> owns schema/options/connection bindings
382
+ +--> reads model.schema.id_strategy as final runtime truth
383
+ +--> executes through its owning Connection
384
+ |
385
+ Document instances
386
+ |
387
+ +--> receive built-in runtime methods plus schema-defined methods
388
+ |
389
+ SQL execution
390
+ |
391
+ +--> stays bound to explicit Connection context
392
+ ```
393
+
394
+ Important:
395
+
396
+ - there is no architectural singleton underneath the public API
397
+ - any future root-level convenience must be layered on top, not treated as core runtime state