meadow 2.0.23 → 2.0.27

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 (62) hide show
  1. package/README.md +110 -141
  2. package/docs/README.md +34 -230
  3. package/docs/_cover.md +14 -0
  4. package/docs/_sidebar.md +44 -12
  5. package/docs/_topbar.md +5 -0
  6. package/docs/api/doCount.md +109 -0
  7. package/docs/api/doCreate.md +132 -0
  8. package/docs/api/doDelete.md +101 -0
  9. package/docs/api/doRead.md +122 -0
  10. package/docs/api/doReads.md +136 -0
  11. package/docs/api/doUndelete.md +98 -0
  12. package/docs/api/doUpdate.md +129 -0
  13. package/docs/api/getRoleName.md +84 -0
  14. package/docs/api/loadFromPackage.md +153 -0
  15. package/docs/api/marshalRecordFromSourceToObject.md +92 -0
  16. package/docs/api/query.md +133 -0
  17. package/docs/api/rawQueries.md +197 -0
  18. package/docs/api/reference.md +117 -0
  19. package/docs/api/setAuthorizer.md +103 -0
  20. package/docs/api/setDefault.md +90 -0
  21. package/docs/api/setDefaultIdentifier.md +84 -0
  22. package/docs/api/setDomain.md +56 -0
  23. package/docs/api/setIDUser.md +91 -0
  24. package/docs/api/setJsonSchema.md +92 -0
  25. package/docs/api/setProvider.md +87 -0
  26. package/docs/api/setSchema.md +107 -0
  27. package/docs/api/setScope.md +68 -0
  28. package/docs/api/validateObject.md +119 -0
  29. package/docs/architecture.md +316 -0
  30. package/docs/audit-tracking.md +226 -0
  31. package/docs/configuration.md +317 -0
  32. package/docs/providers/meadow-endpoints.md +306 -0
  33. package/docs/providers/mongodb.md +319 -0
  34. package/docs/providers/postgresql.md +312 -0
  35. package/docs/providers/rocksdb.md +297 -0
  36. package/docs/query-dsl.md +269 -0
  37. package/docs/quick-start.md +384 -0
  38. package/docs/raw-queries.md +193 -0
  39. package/docs/retold-catalog.json +61 -1
  40. package/docs/retold-keyword-index.json +15860 -4839
  41. package/docs/soft-deletes.md +224 -0
  42. package/package.json +44 -13
  43. package/scripts/bookstore-seed-postgresql.sql +135 -0
  44. package/scripts/dgraph-test-db.sh +144 -0
  45. package/scripts/meadow-test-cleanup.sh +5 -1
  46. package/scripts/mongodb-test-db.sh +98 -0
  47. package/scripts/postgresql-test-db.sh +124 -0
  48. package/scripts/solr-test-db.sh +135 -0
  49. package/source/Meadow.js +5 -0
  50. package/source/providers/Meadow-Provider-DGraph.js +679 -0
  51. package/source/providers/Meadow-Provider-MeadowEndpoints.js +1 -1
  52. package/source/providers/Meadow-Provider-MongoDB.js +527 -0
  53. package/source/providers/Meadow-Provider-PostgreSQL.js +361 -0
  54. package/source/providers/Meadow-Provider-RocksDB.js +1300 -0
  55. package/source/providers/Meadow-Provider-Solr.js +726 -0
  56. package/test/Meadow-Provider-DGraph_tests.js +741 -0
  57. package/test/Meadow-Provider-MongoDB_tests.js +661 -0
  58. package/test/Meadow-Provider-PostgreSQL_tests.js +787 -0
  59. package/test/Meadow-Provider-RocksDB_tests.js +887 -0
  60. package/test/Meadow-Provider-SQLiteBrowser-Headless_tests.js +657 -0
  61. package/test/Meadow-Provider-SQLiteBrowser_tests.js +895 -0
  62. package/test/Meadow-Provider-Solr_tests.js +679 -0
@@ -0,0 +1,316 @@
1
+ # Architecture
2
+
3
+ This document describes the internal architecture of Meadow, its component relationships, and how data flows through the system during CRUD operations.
4
+
5
+ ## Module Hierarchy
6
+
7
+ Meadow sits between your application and the database, orchestrating schema management, query generation, behavior execution, and data marshalling.
8
+
9
+ ```mermaid
10
+ graph TB
11
+ Fable["Fable<br/>(Configuration, Logging, DI)"]
12
+ Meadow["Meadow<br/>(Data Broker)"]
13
+ Schema["Schema<br/>(Column Types, JSON Schema,<br/>Default Object, Authorizer)"]
14
+ FoxHound["FoxHound<br/>(Query DSL)"]
15
+ Behaviors["Behaviors<br/>(Create, Read, Reads,<br/>Update, Delete, Undelete, Count)"]
16
+ Provider["Provider<br/>(Database Adapter)"]
17
+ Database["Database<br/>(MySQL, MSSQL, PostgreSQL,<br/>SQLite, MongoDB, RocksDB, etc.)"]
18
+
19
+ Fable --> Meadow
20
+ Meadow --> Schema
21
+ Meadow --> FoxHound
22
+ Meadow --> Behaviors
23
+ Meadow --> Provider
24
+ Provider --> Database
25
+ ```
26
+
27
+ ## CRUD Behavior Flow
28
+
29
+ Every CRUD operation follows the same general flow: a query object enters a behavior module, which orchestrates provider calls, marshals results, and returns data through the callback.
30
+
31
+ ```mermaid
32
+ flowchart TD
33
+ A["Application calls<br/>meadow.doCreate / doRead / doReads /<br/>doUpdate / doDelete / doUndelete / doCount"]
34
+ B["Behavior Module<br/>(async waterfall)"]
35
+ C["Provider.Create / Read /<br/>Update / Delete / Undelete / Count"]
36
+ D["Database Result"]
37
+ E["Marshal Record<br/>(marshalRecordFromSourceToObject)"]
38
+ F["Callback<br/>(pError, pQuery, pRecord)"]
39
+
40
+ A --> B
41
+ B --> C
42
+ C --> D
43
+ D --> E
44
+ E --> F
45
+ ```
46
+
47
+ ## Create Waterfall
48
+
49
+ The create behavior is the most involved operation, performing multiple steps in an async waterfall to ensure GUID uniqueness and return the complete created record.
50
+
51
+ ```mermaid
52
+ flowchart TD
53
+ A["Step 0: GUID Uniqueness Check<br/>If GUID is provided and >= 5 chars,<br/>query for existing record with same GUID"]
54
+ B{"GUID<br/>already exists?"}
55
+ C["Error: Record with GUID already exists"]
56
+ D["Step 1: Insert Record<br/>Merge default object with submitted record,<br/>set IDUser, call Provider.Create"]
57
+ E{"Insert<br/>succeeded?"}
58
+ F["Error: Creation failed"]
59
+ G["Step 2: Read Back<br/>Query by new auto-increment ID,<br/>call Provider.Read"]
60
+ H["Step 3: Marshal<br/>marshalRecordFromSourceToObject<br/>returns plain JavaScript object"]
61
+ I["Callback with<br/>created record"]
62
+
63
+ A --> B
64
+ B -->|Yes| C
65
+ B -->|No| D
66
+ D --> E
67
+ E -->|No| F
68
+ E -->|Yes| G
69
+ G --> H
70
+ H --> I
71
+ ```
72
+
73
+ ## Provider Architecture
74
+
75
+ Every provider implements the same interface. Meadow ships with providers for multiple database engines, plus a `None` provider for testing and a `MeadowEndpoints` provider for proxying to remote REST APIs.
76
+
77
+ ```mermaid
78
+ classDiagram
79
+ class ProviderInterface {
80
+ +Create(pQuery, fCallback)
81
+ +Read(pQuery, fCallback)
82
+ +Update(pQuery, fCallback)
83
+ +Delete(pQuery, fCallback)
84
+ +Undelete(pQuery, fCallback)
85
+ +Count(pQuery, fCallback)
86
+ +marshalRecordFromSourceToObject(pObject, pRecord)
87
+ +setSchema(pScope, pSchema, pDefaultIdentifier, pDefaultGUIdentifier)
88
+ }
89
+
90
+ class MySQL {
91
+ +Create()
92
+ +Read()
93
+ +Update()
94
+ +Delete()
95
+ +Undelete()
96
+ +Count()
97
+ }
98
+
99
+ class MSSQL {
100
+ +Create()
101
+ +Read()
102
+ +Update()
103
+ +Delete()
104
+ +Undelete()
105
+ +Count()
106
+ }
107
+
108
+ class PostgreSQL {
109
+ +Create()
110
+ +Read()
111
+ +Update()
112
+ +Delete()
113
+ +Undelete()
114
+ +Count()
115
+ }
116
+
117
+ class SQLite {
118
+ +Create()
119
+ +Read()
120
+ +Update()
121
+ +Delete()
122
+ +Undelete()
123
+ +Count()
124
+ }
125
+
126
+ class MongoDB {
127
+ +Create()
128
+ +Read()
129
+ +Update()
130
+ +Delete()
131
+ +Undelete()
132
+ +Count()
133
+ }
134
+
135
+ class RocksDB {
136
+ +Create()
137
+ +Read()
138
+ +Update()
139
+ +Delete()
140
+ +Undelete()
141
+ +Count()
142
+ }
143
+
144
+ class ALASQL {
145
+ +Create()
146
+ +Read()
147
+ +Update()
148
+ +Delete()
149
+ +Undelete()
150
+ +Count()
151
+ }
152
+
153
+ class MeadowEndpoints {
154
+ +Create()
155
+ +Read()
156
+ +Update()
157
+ +Delete()
158
+ +Count()
159
+ }
160
+
161
+ class None {
162
+ +Create()
163
+ +Read()
164
+ +Update()
165
+ +Delete()
166
+ +Undelete()
167
+ +Count()
168
+ }
169
+
170
+ ProviderInterface <|-- MySQL
171
+ ProviderInterface <|-- MSSQL
172
+ ProviderInterface <|-- PostgreSQL
173
+ ProviderInterface <|-- SQLite
174
+ ProviderInterface <|-- MongoDB
175
+ ProviderInterface <|-- RocksDB
176
+ ProviderInterface <|-- ALASQL
177
+ ProviderInterface <|-- MeadowEndpoints
178
+ ProviderInterface <|-- None
179
+ ```
180
+
181
+ ## Schema System
182
+
183
+ The schema drives query generation, validation, record initialization, and access control. A single schema definition feeds multiple subsystems.
184
+
185
+ ```mermaid
186
+ graph LR
187
+ Schema["Meadow Schema"]
188
+ ColumnSchema["Column Schema<br/>(Column, Type, Size)"]
189
+ JsonSchema["JSON Schema<br/>(Validation Rules)"]
190
+ DefaultObject["Default Object<br/>(Initial Values)"]
191
+ Authorizer["Authorizer<br/>(Role Permissions)"]
192
+
193
+ QueryGen["Query Generation<br/>(FoxHound builds SQL<br/>from column definitions)"]
194
+ Validation["Validation<br/>(is-my-json-valid<br/>checks objects)"]
195
+ RecordInit["Record Initialization<br/>(merge defaults into<br/>new records)"]
196
+ AccessControl["Access Control<br/>(role-based CRUD<br/>permissions)"]
197
+
198
+ Schema --> ColumnSchema
199
+ Schema --> JsonSchema
200
+ Schema --> DefaultObject
201
+ Schema --> Authorizer
202
+
203
+ ColumnSchema --> QueryGen
204
+ JsonSchema --> Validation
205
+ DefaultObject --> RecordInit
206
+ Authorizer --> AccessControl
207
+ ```
208
+
209
+ ## Query Lifecycle
210
+
211
+ This diagram shows the full sequence of a CRUD operation from the application through to the database and back.
212
+
213
+ ```mermaid
214
+ sequenceDiagram
215
+ participant App as Application
216
+ participant Meadow as Meadow
217
+ participant Behavior as Behavior Module
218
+ participant FH as FoxHound
219
+ participant Provider as Provider
220
+ participant DB as Database
221
+
222
+ App->>Meadow: meadow.query (clone FoxHound)
223
+ Meadow-->>App: Independent query clone
224
+ App->>App: addFilter / addRecord / setCap
225
+ App->>Meadow: meadow.doCreate / doRead / etc.
226
+ Meadow->>Behavior: Invoke behavior (async waterfall)
227
+ Behavior->>FH: setDialect / buildQuery
228
+ FH-->>Behavior: Generated SQL + parameters
229
+ Behavior->>Provider: Provider.Create / Read / etc.
230
+ Provider->>DB: Execute query
231
+ DB-->>Provider: Result rows
232
+ Provider-->>Behavior: Result on query object
233
+ Behavior->>Behavior: Marshal records (source to POJO)
234
+ Behavior-->>App: Callback (pError, pQuery, pRecord)
235
+ ```
236
+
237
+ ## Key Architectural Concepts
238
+
239
+ ### Factory Pattern
240
+
241
+ Meadow uses a factory pattern for instantiation. When you `require('meadow')`, the module returns a constructor object. Calling `.new()` without a Fable instance returns a bare constructor. Calling `.new(pFable, pScope)` with a valid Fable instance returns a fully initialized Meadow DAL:
242
+
243
+ ```javascript
244
+ var libMeadow = require('meadow');
245
+
246
+ // Returns a constructor (no Fable passed)
247
+ var tmpConstructor = libMeadow.new();
248
+
249
+ // Returns a fully initialized Meadow instance
250
+ var tmpBookDAL = libMeadow.new(_Fable, 'Book');
251
+ ```
252
+
253
+ This same pattern is used throughout the Retold ecosystem in providers, schemas, and raw query objects.
254
+
255
+ ### Behavior Modules
256
+
257
+ Each CRUD operation is encapsulated in its own behavior module under `source/behaviors/`. Behaviors use `async/waterfall` to sequence multi-step operations:
258
+
259
+ - **Meadow-Create.js** -- GUID check, insert, read back, marshal (4 steps)
260
+ - **Meadow-Read.js** -- read, marshal (2 steps)
261
+ - **Meadow-Reads.js** -- read, marshal each record, profile timing (2 steps)
262
+ - **Meadow-Update.js** -- validate, update, read back, marshal (4 steps)
263
+ - **Meadow-Delete.js** -- delete or soft-delete (1 step)
264
+ - **Meadow-Undelete.js** -- restore soft-deleted record (1 step)
265
+ - **Meadow-Count.js** -- count, validate result, profile timing (2 steps)
266
+
267
+ Each behavior receives the Meadow instance, a query object, and a callback. Errors at any waterfall step short-circuit to the final callback.
268
+
269
+ ### Provider Interface
270
+
271
+ Every provider must implement six methods plus a marshaller:
272
+
273
+ | Method | Purpose |
274
+ |--------|---------|
275
+ | `Create(pQuery, fCallback)` | Insert a new record |
276
+ | `Read(pQuery, fCallback)` | Read one or more records |
277
+ | `Update(pQuery, fCallback)` | Update an existing record |
278
+ | `Delete(pQuery, fCallback)` | Delete (or soft-delete) a record |
279
+ | `Undelete(pQuery, fCallback)` | Restore a soft-deleted record |
280
+ | `Count(pQuery, fCallback)` | Count matching records |
281
+ | `marshalRecordFromSourceToObject(pObject, pRecord)` | Copy database row data into a JavaScript object |
282
+
283
+ Providers that need schema information also implement `setSchema(pScope, pSchema, pDefaultIdentifier, pDefaultGUIdentifier)`, which Meadow calls automatically when the schema or scope changes.
284
+
285
+ ### Query Cloning
286
+
287
+ Every access to `meadow.query` returns an independent clone of the internal FoxHound query object. This guarantees that configuring one query never leaks state into another:
288
+
289
+ ```javascript
290
+ var tmpQuery1 = tmpBookDAL.query.addFilter('Author', 'Asimov');
291
+ var tmpQuery2 = tmpBookDAL.query.addFilter('Author', 'Herbert');
292
+ // tmpQuery1 and tmpQuery2 are completely independent
293
+ ```
294
+
295
+ The clone copies filters, caps, begin offsets, data elements, and sort configuration. The schema reference is set on each clone so that FoxHound has access to column type information for query generation.
296
+
297
+ ### Auto-Stamping
298
+
299
+ When the schema includes special column types, Meadow automatically populates them during create, update, and delete operations:
300
+
301
+ | Column Type | Stamped During | Value |
302
+ |------------|----------------|-------|
303
+ | `CreateDate` | Create | Current timestamp (`NOW()`) |
304
+ | `CreateIDUser` | Create | Current user ID |
305
+ | `UpdateDate` | Update | Current timestamp (`NOW()`) |
306
+ | `UpdateIDUser` | Update | Current user ID |
307
+ | `DeleteDate` | Delete | Current timestamp (`NOW()`) |
308
+ | `DeleteIDUser` | Delete | Current user ID |
309
+ | `AutoIdentity` | Create | Auto-increment value from database |
310
+ | `AutoGUID` | Create | Generated UUID |
311
+
312
+ User identity comes from `meadow.setIDUser(n)` or from `pQuery.query.IDUser` on a per-query basis. Auto-stamping can be disabled per query with `disableAutoDateStamp` and `disableAutoUserStamp`.
313
+
314
+ ### Soft Delete Filtering
315
+
316
+ When a schema contains a column with type `'Deleted'`, Meadow and FoxHound automatically add `WHERE Deleted = 0` to all read queries. This filters out logically deleted records without any additional code. To see deleted records, set `setDisableDeleteTracking(true)` on the query. See the [Soft Deletes](soft-deletes.md) documentation for details.
@@ -0,0 +1,226 @@
1
+ # Audit Tracking
2
+
3
+ Meadow provides automatic audit tracking through special schema column types. When these columns are present in your schema, Meadow stamps them with timestamps and user identity during create, update, and delete operations -- without any manual intervention.
4
+
5
+ ## Schema Types for Audit Tracking
6
+
7
+ The following schema column types enable automatic audit tracking:
8
+
9
+ | Column Type | Purpose | Stamped During | Value |
10
+ |------------|---------|----------------|-------|
11
+ | `CreateDate` | Records when a row was created | `doCreate` | Current timestamp (`NOW()`) |
12
+ | `CreateIDUser` | Records who created the row | `doCreate` | Current user ID |
13
+ | `UpdateDate` | Records when a row was last modified | `doUpdate` | Current timestamp (`NOW()`) |
14
+ | `UpdateIDUser` | Records who last modified the row | `doUpdate` | Current user ID |
15
+ | `DeleteDate` | Records when a row was soft-deleted | `doDelete` | Current timestamp (`NOW()`) |
16
+ | `DeleteIDUser` | Records who soft-deleted the row | `doDelete` | Current user ID |
17
+
18
+ ### Schema Definition Example
19
+
20
+ A complete schema with all audit columns:
21
+
22
+ ```javascript
23
+ var tmpSchema =
24
+ [
25
+ { Column: 'IDBook', Type: 'AutoIdentity' },
26
+ { Column: 'GUIDBook', Type: 'AutoGUID' },
27
+ { Column: 'Title', Type: 'String', Size: '255' },
28
+ { Column: 'Author', Type: 'String', Size: '128' },
29
+
30
+ // Audit tracking columns
31
+ { Column: 'CreateDate', Type: 'CreateDate' },
32
+ { Column: 'CreatingIDUser', Type: 'CreateIDUser' },
33
+ { Column: 'UpdateDate', Type: 'UpdateDate' },
34
+ { Column: 'UpdatingIDUser', Type: 'UpdateIDUser' },
35
+ { Column: 'DeleteDate', Type: 'DeleteDate' },
36
+ { Column: 'DeletingIDUser', Type: 'DeleteIDUser' },
37
+ { Column: 'Deleted', Type: 'Deleted' }
38
+ ];
39
+ ```
40
+
41
+ You can name the columns whatever you like. The `Type` field determines the behavior, not the `Column` name. For example, `{ Column: 'ModifiedOn', Type: 'UpdateDate' }` works just as well.
42
+
43
+ ## How Each Column Is Populated
44
+
45
+ ### During Create (`doCreate`)
46
+
47
+ When a record is created, Meadow merges the submitted record with the default object and passes it to the provider. The provider (via FoxHound query generation) handles `CreateDate` and `CreateIDUser`:
48
+
49
+ - **CreateDate** -- FoxHound generates `NOW()` (or the database-specific equivalent) in the INSERT statement for this column.
50
+ - **CreateIDUser** -- The current user ID is written into the record before the INSERT. The user ID comes from `meadow.userIdentifier` (set via `setIDUser`) or from `pQuery.query.IDUser` if set on the query.
51
+
52
+ ```javascript
53
+ tmpBookDAL.setIDUser(42);
54
+
55
+ tmpBookDAL.doCreate(tmpBookDAL.query.addRecord({ Title: 'Dune' }),
56
+ function (pError, pCreateQuery, pReadQuery, pRecord)
57
+ {
58
+ // pRecord.CreateDate is set to the current timestamp
59
+ // pRecord.CreatingIDUser is 42
60
+ });
61
+ ```
62
+
63
+ ### During Update (`doUpdate`)
64
+
65
+ The update behavior iterates through the schema looking for `UpdateDate` and `UpdateIDUser` column types. It sets these values to `false` in the record, which signals FoxHound to generate `NOW()` for dates and to use the current user ID:
66
+
67
+ - **UpdateDate** -- Set to `false` in the record before the UPDATE, which FoxHound interprets as "use `NOW()`".
68
+ - **UpdateIDUser** -- Set to `false` in the record, which FoxHound populates with the `IDUser` from the query.
69
+
70
+ ```javascript
71
+ tmpBookDAL.setIDUser(99);
72
+
73
+ tmpBookDAL.doUpdate(tmpBookDAL.query.addRecord({ IDBook: 1, Title: 'Dune (Revised)' }),
74
+ function (pError, pUpdateQuery, pReadQuery, pRecord)
75
+ {
76
+ // pRecord.UpdateDate is set to the current timestamp
77
+ // pRecord.UpdatingIDUser is 99
78
+ });
79
+ ```
80
+
81
+ ### During Delete (`doDelete`)
82
+
83
+ When the schema includes a `Deleted` column (type `'Deleted'`), the delete operation is a soft delete -- an UPDATE that sets `Deleted = 1`. FoxHound also populates the `DeleteDate` and `DeleteIDUser` columns during this operation:
84
+
85
+ - **DeleteDate** -- Set to `NOW()` in the generated UPDATE statement.
86
+ - **DeleteIDUser** -- Set to the current user ID in the generated UPDATE statement.
87
+
88
+ ```javascript
89
+ tmpBookDAL.setIDUser(7);
90
+
91
+ tmpBookDAL.doDelete(tmpBookDAL.query.addFilter('IDBook', 1),
92
+ function (pError, pQuery, pResult)
93
+ {
94
+ // The record now has:
95
+ // Deleted = 1
96
+ // DeleteDate = current timestamp
97
+ // DeletingIDUser = 7
98
+ });
99
+ ```
100
+
101
+ ## Setting User Identity
102
+
103
+ ### DAL-Level Identity with setIDUser
104
+
105
+ Set the user ID on the Meadow DAL instance. This value applies to all subsequent operations on that DAL:
106
+
107
+ ```javascript
108
+ tmpBookDAL.setIDUser(42);
109
+ ```
110
+
111
+ The value is accessible through `meadow.userIdentifier`.
112
+
113
+ ### Per-Query Identity
114
+
115
+ Override the user ID for a single operation by setting `IDUser` on the query object:
116
+
117
+ ```javascript
118
+ var tmpQuery = tmpBookDAL.query
119
+ .addRecord({ Title: 'New Book' });
120
+
121
+ tmpQuery.query.IDUser = 99;
122
+
123
+ tmpBookDAL.doCreate(tmpQuery,
124
+ function (pError, pCreateQuery, pReadQuery, pRecord)
125
+ {
126
+ // CreatingIDUser is 99, not the DAL-level value
127
+ });
128
+ ```
129
+
130
+ The per-query `IDUser` takes precedence. The behavior first checks `pQuery.query.IDUser`, and only falls back to `meadow.userIdentifier` if the query-level value is not set.
131
+
132
+ ### Identity Resolution Order
133
+
134
+ 1. If `pQuery.query.IDUser` is already set (non-falsy), use it as-is.
135
+ 2. If the query has `pQuery.userID` set as a valid non-negative integer, use that.
136
+ 3. Otherwise, use `meadow.userIdentifier` (from `setIDUser`).
137
+
138
+ ## Disabling Auto-Stamps
139
+
140
+ In some cases you may need to prevent Meadow from overwriting date or user columns -- for example, during data migrations or when synchronizing records from an external system.
141
+
142
+ ### disableAutoDateStamp
143
+
144
+ Prevents the update behavior from overwriting `UpdateDate` columns:
145
+
146
+ ```javascript
147
+ var tmpQuery = tmpBookDAL.query
148
+ .addRecord(
149
+ {
150
+ IDBook: 1,
151
+ Title: 'Migrated Record',
152
+ UpdateDate: '2020-01-15 10:30:00'
153
+ });
154
+
155
+ tmpQuery.query.disableAutoDateStamp = true;
156
+
157
+ tmpBookDAL.doUpdate(tmpQuery,
158
+ function (pError, pUpdateQuery, pReadQuery, pRecord)
159
+ {
160
+ // UpdateDate retains the value '2020-01-15 10:30:00'
161
+ // instead of being overwritten with NOW()
162
+ });
163
+ ```
164
+
165
+ ### disableAutoUserStamp
166
+
167
+ Prevents the update behavior from overwriting `UpdateIDUser` columns:
168
+
169
+ ```javascript
170
+ var tmpQuery = tmpBookDAL.query
171
+ .addRecord(
172
+ {
173
+ IDBook: 1,
174
+ Title: 'Imported Record',
175
+ UpdatingIDUser: 500
176
+ });
177
+
178
+ tmpQuery.query.disableAutoUserStamp = true;
179
+
180
+ tmpBookDAL.doUpdate(tmpQuery,
181
+ function (pError, pUpdateQuery, pReadQuery, pRecord)
182
+ {
183
+ // UpdatingIDUser retains the value 500
184
+ // instead of being overwritten with the current user ID
185
+ });
186
+ ```
187
+
188
+ ### Combining Both Flags
189
+
190
+ You can disable both auto-stamps simultaneously:
191
+
192
+ ```javascript
193
+ var tmpQuery = tmpBookDAL.query
194
+ .addRecord(
195
+ {
196
+ IDBook: 1,
197
+ Title: 'Full Migration',
198
+ UpdateDate: '2019-06-01 08:00:00',
199
+ UpdatingIDUser: 200
200
+ });
201
+
202
+ tmpQuery.query.disableAutoDateStamp = true;
203
+ tmpQuery.query.disableAutoUserStamp = true;
204
+ ```
205
+
206
+ ## Use Cases
207
+
208
+ ### Compliance and Audit Trails
209
+
210
+ Including all six audit columns in your schema creates a complete record of who did what and when:
211
+
212
+ - **Who created this record?** Check `CreatingIDUser` and `CreateDate`.
213
+ - **Who last modified it?** Check `UpdatingIDUser` and `UpdateDate`.
214
+ - **Who deleted it and when?** Check `DeletingIDUser` and `DeleteDate`.
215
+
216
+ This information is populated automatically with no additional application code.
217
+
218
+ ### Change History
219
+
220
+ Combine audit columns with soft deletes for a complete change history. Since deleted records are preserved in the database (just flagged with `Deleted = 1`), you always have a trail of when records were removed and by whom.
221
+
222
+ For more granular change tracking, consider logging the full before/after state of records using Meadow behaviors in conjunction with your application logic.
223
+
224
+ ### Data Migration
225
+
226
+ When importing historical data, use `disableAutoDateStamp` and `disableAutoUserStamp` to preserve the original timestamps and user identity from the source system instead of overwriting them with current values.