meadow 2.0.22 → 2.0.26

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 (59) 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 -27
  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-MongoDB.js +527 -0
  52. package/source/providers/Meadow-Provider-PostgreSQL.js +361 -0
  53. package/source/providers/Meadow-Provider-RocksDB.js +1300 -0
  54. package/source/providers/Meadow-Provider-Solr.js +726 -0
  55. package/test/Meadow-Provider-DGraph_tests.js +741 -0
  56. package/test/Meadow-Provider-MongoDB_tests.js +661 -0
  57. package/test/Meadow-Provider-PostgreSQL_tests.js +787 -0
  58. package/test/Meadow-Provider-RocksDB_tests.js +887 -0
  59. package/test/Meadow-Provider-Solr_tests.js +679 -0
@@ -0,0 +1,319 @@
1
+ # MongoDB Provider
2
+
3
+ > Document-based storage with automatic counter management and sentinel value support
4
+
5
+ The MongoDB provider connects Meadow to MongoDB databases via the [meadow-connection-mongodb](https://github.com/stevenvelozo/meadow-connection-mongodb) module. It uses the FoxHound MongoDB dialect for query generation, providing document-based storage without schema migration. Auto-increment counters, GUID generation, and timestamp sentinels are handled automatically.
6
+
7
+ ## Setup
8
+
9
+ ### Install Dependencies
10
+
11
+ ```bash
12
+ npm install meadow meadow-connection-mongodb
13
+ ```
14
+
15
+ ### Register the Connection
16
+
17
+ ```javascript
18
+ const libFable = require('fable').new(
19
+ {
20
+ MongoDB:
21
+ {
22
+ URL: 'mongodb://localhost:27017',
23
+ Database: 'myapp'
24
+ }
25
+ });
26
+
27
+ const libMeadowConnectionMongoDB = require('meadow-connection-mongodb');
28
+
29
+ // Register the connection service
30
+ libFable.serviceManager.addServiceType('MeadowMongoDBProvider', libMeadowConnectionMongoDB);
31
+ libFable.serviceManager.instantiateServiceProvider('MeadowMongoDBProvider');
32
+ ```
33
+
34
+ ### Create a Meadow DAL
35
+
36
+ ```javascript
37
+ const libMeadow = require('meadow');
38
+
39
+ const meadow = libMeadow.new(libFable, 'Book')
40
+ .setProvider('MongoDB')
41
+ .setDefaultIdentifier('IDBook')
42
+ .setSchema([
43
+ { Column: 'IDBook', Type: 'AutoIdentity' },
44
+ { Column: 'GUIDBook', Type: 'AutoGUID' },
45
+ { Column: 'Title', Type: 'String', Size: '255' },
46
+ { Column: 'Author', Type: 'String', Size: '128' },
47
+ { Column: 'PageCount', Type: 'Numeric' },
48
+ { Column: 'CreateDate', Type: 'CreateDate' },
49
+ { Column: 'CreatingIDUser', Type: 'CreateIDUser' },
50
+ { Column: 'UpdateDate', Type: 'UpdateDate' },
51
+ { Column: 'UpdatingIDUser', Type: 'UpdateIDUser' },
52
+ { Column: 'DeleteDate', Type: 'DeleteDate' },
53
+ { Column: 'DeletingIDUser', Type: 'DeleteIDUser' },
54
+ { Column: 'Deleted', Type: 'Deleted' }
55
+ ]);
56
+ ```
57
+
58
+ ## Connection Management
59
+
60
+ ### Connection Configuration
61
+
62
+ | Setting | Type | Default | Description |
63
+ |---------|------|---------|-------------|
64
+ | `MongoDB.URL` | string | -- | MongoDB connection URL |
65
+ | `MongoDB.Database` | string | -- | Database name |
66
+
67
+ ### No Schema Migration
68
+
69
+ Unlike SQL-based providers, MongoDB does not require table creation or schema migration. Collections are created automatically when the first document is inserted. This makes MongoDB well-suited for rapid development and evolving data models.
70
+
71
+ ## Document Storage
72
+
73
+ ### The `_id` Field
74
+
75
+ MongoDB automatically assigns an `_id` field to every document. The Meadow MongoDB provider works alongside this native identifier while maintaining Meadow's own identity system (`IDBook`, `GUIDBook`, etc.). Your application code interacts with Meadow's identity columns as usual; the underlying `_id` is managed transparently.
76
+
77
+ ### Auto-Increment Counters
78
+
79
+ MongoDB does not natively support auto-increment integer identifiers. The Meadow MongoDB provider implements auto-increment behavior using a dedicated `_meadow_counters` collection. When a record is created with an `AutoIdentity` column:
80
+
81
+ 1. The provider queries the `_meadow_counters` collection for the current counter value
82
+ 2. The counter is atomically incremented
83
+ 3. The new value is assigned to the identity column on the inserted document
84
+
85
+ This ensures unique, sequential integer IDs across concurrent inserts.
86
+
87
+ ### Sentinel Values
88
+
89
+ The MongoDB provider supports sentinel values that are resolved at write time:
90
+
91
+ | Sentinel | Resolved To | Description |
92
+ |----------|-------------|-------------|
93
+ | `$$NOW` | Current timestamp | Sets the field to the current date and time |
94
+ | `$$AUTOINCREMENT` | Next counter value | Assigns the next auto-increment integer from `_meadow_counters` |
95
+ | `$$AUTOGUID` | New GUID | Generates a new globally unique identifier |
96
+
97
+ Sentinels are placed in record fields and expanded by the provider before the document is written to MongoDB:
98
+
99
+ ```javascript
100
+ meadow.doCreate(
101
+ meadow.query.addRecord(
102
+ {
103
+ Title: 'Dune',
104
+ Author: 'Frank Herbert',
105
+ CreateDate: '$$NOW',
106
+ GUIDBook: '$$AUTOGUID'
107
+ }),
108
+ (pError, pCreateQuery, pReadQuery, pRecord) =>
109
+ {
110
+ console.log('Created at:', pRecord.CreateDate);
111
+ console.log('GUID:', pRecord.GUIDBook);
112
+ });
113
+ ```
114
+
115
+ ## CRUD Operations
116
+
117
+ ### Create
118
+
119
+ Inserts a new document into the collection and returns the auto-generated identity value.
120
+
121
+ ```javascript
122
+ meadow.doCreate(
123
+ meadow.query.addRecord({ Title: 'Dune', Author: 'Frank Herbert' }),
124
+ (pError, pCreateQuery, pReadQuery, pRecord) =>
125
+ {
126
+ console.log('New ID:', pRecord.IDBook);
127
+ });
128
+ ```
129
+
130
+ **Internally:**
131
+ - Builds query: `pQuery.setDialect('MongoDB').buildCreateQuery()`
132
+ - Resolves sentinel values ($$NOW, $$AUTOINCREMENT, $$AUTOGUID)
133
+ - Increments the counter in `_meadow_counters`
134
+ - Inserts the document into the collection
135
+
136
+ ### Read
137
+
138
+ Queries the collection and returns matching documents.
139
+
140
+ ```javascript
141
+ // Single record
142
+ meadow.doRead(
143
+ meadow.query.addFilter('IDBook', 42),
144
+ (pError, pQuery, pRecord) =>
145
+ {
146
+ console.log('Title:', pRecord.Title);
147
+ });
148
+
149
+ // Multiple records
150
+ meadow.doReads(
151
+ meadow.query.setCap(25).setBegin(0).addSort({ Column: 'Title', Direction: 'ASC' }),
152
+ (pError, pQuery, pRecords) =>
153
+ {
154
+ pRecords.forEach((pBook) => console.log(pBook.Title));
155
+ });
156
+ ```
157
+
158
+ **Internally:**
159
+ - Builds query: `pQuery.setDialect('MongoDB').buildReadQuery()`
160
+ - Translates filters to MongoDB query objects
161
+ - Applies sort, skip, and limit from the query parameters
162
+
163
+ ### Update
164
+
165
+ Updates matching documents in the collection.
166
+
167
+ ```javascript
168
+ meadow.doUpdate(
169
+ meadow.query
170
+ .addFilter('IDBook', 42)
171
+ .addRecord({ Title: 'Updated Title' }),
172
+ (pError, pUpdateQuery, pReadQuery, pRecord) =>
173
+ {
174
+ console.log('Updated:', pRecord.Title);
175
+ });
176
+ ```
177
+
178
+ **Internally:**
179
+ - Builds query: `pQuery.setDialect('MongoDB').buildUpdateQuery()`
180
+ - Resolves sentinel values before applying the update
181
+
182
+ ### Delete
183
+
184
+ Executes a soft delete (sets the Deleted flag) and returns the affected document count.
185
+
186
+ ```javascript
187
+ meadow.doDelete(
188
+ meadow.query.addFilter('IDBook', 42),
189
+ (pError, pQuery, pResult) =>
190
+ {
191
+ console.log('Deleted documents:', pResult);
192
+ });
193
+ ```
194
+
195
+ **Internally:**
196
+ - Builds query: `pQuery.setDialect('MongoDB').buildDeleteQuery()`
197
+ - Updates the Deleted field rather than removing the document
198
+
199
+ ### Undelete
200
+
201
+ Reverses a soft delete.
202
+
203
+ ```javascript
204
+ meadow.doUndelete(
205
+ meadow.query.addFilter('IDBook', 42),
206
+ (pError, pQuery, pResult) =>
207
+ {
208
+ console.log('Restored documents:', pResult);
209
+ });
210
+ ```
211
+
212
+ ### Count
213
+
214
+ Returns the count of matching documents.
215
+
216
+ ```javascript
217
+ meadow.doCount(
218
+ meadow.query.addFilter('Author', 'Frank Herbert', '='),
219
+ (pError, pQuery, pCount) =>
220
+ {
221
+ console.log('Books by Herbert:', pCount);
222
+ });
223
+ ```
224
+
225
+ **Internally:**
226
+ - Builds query: `pQuery.setDialect('MongoDB').buildCountQuery()`
227
+ - Returns the integer count of matching documents
228
+
229
+ ## Full Setup Example
230
+
231
+ A complete working example connecting to MongoDB and performing CRUD operations:
232
+
233
+ ```javascript
234
+ const libFable = require('fable').new(
235
+ {
236
+ MongoDB:
237
+ {
238
+ URL: 'mongodb://localhost:27017',
239
+ Database: 'bookstore'
240
+ }
241
+ });
242
+
243
+ const libMeadow = require('meadow');
244
+ const libMeadowConnectionMongoDB = require('meadow-connection-mongodb');
245
+
246
+ // Register the connection service
247
+ libFable.serviceManager.addServiceType('MeadowMongoDBProvider', libMeadowConnectionMongoDB);
248
+ libFable.serviceManager.instantiateServiceProvider('MeadowMongoDBProvider');
249
+
250
+ // Create the DAL
251
+ const meadow = libMeadow.new(libFable, 'Book')
252
+ .setProvider('MongoDB')
253
+ .setDefaultIdentifier('IDBook')
254
+ .setSchema([
255
+ { Column: 'IDBook', Type: 'AutoIdentity' },
256
+ { Column: 'GUIDBook', Type: 'AutoGUID' },
257
+ { Column: 'Title', Type: 'String', Size: '255' },
258
+ { Column: 'Author', Type: 'String', Size: '128' },
259
+ { Column: 'PageCount', Type: 'Numeric' },
260
+ { Column: 'CreateDate', Type: 'CreateDate' },
261
+ { Column: 'CreatingIDUser', Type: 'CreateIDUser' },
262
+ { Column: 'UpdateDate', Type: 'UpdateDate' },
263
+ { Column: 'UpdatingIDUser', Type: 'UpdateIDUser' },
264
+ { Column: 'DeleteDate', Type: 'DeleteDate' },
265
+ { Column: 'DeletingIDUser', Type: 'DeleteIDUser' },
266
+ { Column: 'Deleted', Type: 'Deleted' }
267
+ ]);
268
+
269
+ // Insert a record
270
+ meadow.doCreate(
271
+ meadow.query.addRecord({ Title: 'Dune', Author: 'Frank Herbert', PageCount: 412 }),
272
+ (pError, pCreateQuery, pReadQuery, pRecord) =>
273
+ {
274
+ console.log('Created book with ID:', pRecord.IDBook);
275
+ console.log('GUID:', pRecord.GUIDBook);
276
+
277
+ // Read it back
278
+ meadow.doRead(
279
+ meadow.query.addFilter('IDBook', pRecord.IDBook),
280
+ (pError, pQuery, pRecord) =>
281
+ {
282
+ console.log('Read back:', pRecord.Title, 'by', pRecord.Author);
283
+
284
+ // Count all books
285
+ meadow.doCount(
286
+ meadow.query,
287
+ (pError, pQuery, pCount) =>
288
+ {
289
+ console.log('Total books in collection:', pCount);
290
+ });
291
+ });
292
+ });
293
+ ```
294
+
295
+ ## Error Handling
296
+
297
+ All operations follow the same error handling pattern:
298
+
299
+ - Database errors are stored in `pQuery.parameters.result.error`
300
+ - Connection errors bubble up through the callback as `pError`
301
+ - Counter increment failures are logged and reported through the error callback
302
+
303
+ ## Docker Development
304
+
305
+ For local MongoDB development:
306
+
307
+ ```bash
308
+ docker run -d \
309
+ --name meadow-mongodb \
310
+ -p 27017:27017 \
311
+ mongo:7
312
+ ```
313
+
314
+ ## Related Documentation
315
+
316
+ - [Providers Overview](providers/README.md) -- Comparison of all providers
317
+ - [MySQL Provider](providers/mysql.md) -- Relational database alternative
318
+ - [ALASQL Provider](providers/alasql.md) -- In-memory alternative
319
+ - [meadow-connection-mongodb](https://github.com/stevenvelozo/meadow-connection-mongodb) -- Connection module source
@@ -0,0 +1,312 @@
1
+ # PostgreSQL Provider
2
+
3
+ > Production-ready PostgreSQL integration with connection pooling and named parameter binding
4
+
5
+ The PostgreSQL provider connects Meadow to PostgreSQL databases via the [meadow-connection-postgresql](https://github.com/stevenvelozo/meadow-connection-postgresql) module. It uses the FoxHound PostgreSQL dialect for query generation and supports named parameter binding with positional placeholders ($1, $2, etc.).
6
+
7
+ ## Setup
8
+
9
+ ### Install Dependencies
10
+
11
+ ```bash
12
+ npm install meadow meadow-connection-postgresql
13
+ ```
14
+
15
+ ### Register the Connection
16
+
17
+ ```javascript
18
+ const libFable = require('fable').new(
19
+ {
20
+ PostgreSQL:
21
+ {
22
+ Host: 'localhost',
23
+ Port: 5432,
24
+ User: 'postgres',
25
+ Password: '',
26
+ Database: 'myapp',
27
+ ConnectionPoolLimit: 20
28
+ }
29
+ });
30
+
31
+ const libMeadowConnectionPostgreSQL = require('meadow-connection-postgresql');
32
+
33
+ // Register the connection service
34
+ libFable.serviceManager.addServiceType('MeadowPostgreSQLProvider', libMeadowConnectionPostgreSQL);
35
+ const tmpConnection = libFable.serviceManager.instantiateServiceProvider('MeadowPostgreSQLProvider');
36
+
37
+ // Connect asynchronously
38
+ tmpConnection.connectAsync(
39
+ (pError) =>
40
+ {
41
+ if (pError)
42
+ {
43
+ return console.error('PostgreSQL connection failed:', pError);
44
+ }
45
+ console.log('Connected to PostgreSQL');
46
+ });
47
+ ```
48
+
49
+ ### Create a Meadow DAL
50
+
51
+ ```javascript
52
+ const libMeadow = require('meadow');
53
+
54
+ const meadow = libMeadow.new(libFable, 'Book')
55
+ .setProvider('PostgreSQL')
56
+ .setDefaultIdentifier('IDBook')
57
+ .setSchema([
58
+ { Column: 'IDBook', Type: 'AutoIdentity' },
59
+ { Column: 'GUIDBook', Type: 'AutoGUID' },
60
+ { Column: 'Title', Type: 'String', Size: '255' },
61
+ { Column: 'Author', Type: 'String', Size: '128' },
62
+ { Column: 'Price', Type: 'Decimal', Size: '12,2' },
63
+ { Column: 'CreateDate', Type: 'CreateDate' },
64
+ { Column: 'CreatingIDUser', Type: 'CreateIDUser' },
65
+ { Column: 'UpdateDate', Type: 'UpdateDate' },
66
+ { Column: 'UpdatingIDUser', Type: 'UpdateIDUser' },
67
+ { Column: 'DeleteDate', Type: 'DeleteDate' },
68
+ { Column: 'DeletingIDUser', Type: 'DeleteIDUser' },
69
+ { Column: 'Deleted', Type: 'Deleted' }
70
+ ]);
71
+ ```
72
+
73
+ ## Connection Management
74
+
75
+ ### Async Connection Model
76
+
77
+ The PostgreSQL provider uses an asynchronous connection model. The connection module provides:
78
+
79
+ | Method | Description |
80
+ |--------|-------------|
81
+ | `connectAsync(fCallback)` | Async connection with callback on completion |
82
+
83
+ ### Connection Pool Settings
84
+
85
+ | Setting | Type | Default | Description |
86
+ |---------|------|---------|-------------|
87
+ | `PostgreSQL.Host` | string | -- | Database server hostname |
88
+ | `PostgreSQL.Port` | number | `5432` | Database server port |
89
+ | `PostgreSQL.User` | string | -- | Database user |
90
+ | `PostgreSQL.Password` | string | -- | Database password |
91
+ | `PostgreSQL.Database` | string | -- | Database name |
92
+ | `PostgreSQL.ConnectionPoolLimit` | number | `20` | Maximum pool connections |
93
+
94
+ ### Named Parameter Binding
95
+
96
+ The PostgreSQL provider uses positional parameter placeholders ($1, $2, etc.) as required by the PostgreSQL wire protocol. FoxHound's PostgreSQL dialect generates queries with these positional bindings:
97
+
98
+ ```sql
99
+ -- Generated by FoxHound with positional placeholders:
100
+ SELECT "IDBook", "Title", "Author" FROM "Book" WHERE "IDBook" = $1 AND "Deleted" = 0
101
+ ```
102
+
103
+ ## CRUD Operations
104
+
105
+ ### Create
106
+
107
+ Executes an INSERT statement with a RETURNING clause to capture the generated identity.
108
+
109
+ ```javascript
110
+ meadow.doCreate(
111
+ meadow.query.addRecord({ Title: 'Dune', Author: 'Frank Herbert' }),
112
+ (pError, pCreateQuery, pReadQuery, pRecord) =>
113
+ {
114
+ console.log('New ID:', pRecord.IDBook);
115
+ });
116
+ ```
117
+
118
+ **Internally:**
119
+ - Builds query: `pQuery.setDialect('PostgreSQL').buildCreateQuery()`
120
+ - Extracts identity from the RETURNING clause result
121
+
122
+ ### Read
123
+
124
+ Executes a SELECT statement and returns result rows.
125
+
126
+ ```javascript
127
+ // Single record
128
+ meadow.doRead(
129
+ meadow.query.addFilter('IDBook', 42),
130
+ (pError, pQuery, pRecord) =>
131
+ {
132
+ console.log('Title:', pRecord.Title);
133
+ });
134
+
135
+ // Multiple records
136
+ meadow.doReads(
137
+ meadow.query.setCap(25).setBegin(0).addSort({ Column: 'Title', Direction: 'ASC' }),
138
+ (pError, pQuery, pRecords) =>
139
+ {
140
+ pRecords.forEach((pBook) => console.log(pBook.Title));
141
+ });
142
+ ```
143
+
144
+ **Internally:**
145
+ - Builds query: `pQuery.setDialect('PostgreSQL').buildReadQuery()`
146
+ - Returns full result rows array
147
+
148
+ ### Update
149
+
150
+ Executes an UPDATE statement.
151
+
152
+ ```javascript
153
+ meadow.doUpdate(
154
+ meadow.query
155
+ .addFilter('IDBook', 42)
156
+ .addRecord({ Title: 'Updated Title' }),
157
+ (pError, pUpdateQuery, pReadQuery, pRecord) =>
158
+ {
159
+ console.log('Updated:', pRecord.Title);
160
+ });
161
+ ```
162
+
163
+ **Internally:**
164
+ - Builds query: `pQuery.setDialect('PostgreSQL').buildUpdateQuery()`
165
+
166
+ ### Delete
167
+
168
+ Executes a soft delete (UPDATE setting Deleted flag) and returns the affected row count.
169
+
170
+ ```javascript
171
+ meadow.doDelete(
172
+ meadow.query.addFilter('IDBook', 42),
173
+ (pError, pQuery, pResult) =>
174
+ {
175
+ console.log('Deleted rows:', pResult);
176
+ });
177
+ ```
178
+
179
+ **Internally:**
180
+ - Builds query: `pQuery.setDialect('PostgreSQL').buildDeleteQuery()`
181
+ - Extracts affected rows from the result
182
+
183
+ ### Undelete
184
+
185
+ Reverses a soft delete and returns the affected row count.
186
+
187
+ ```javascript
188
+ meadow.doUndelete(
189
+ meadow.query.addFilter('IDBook', 42),
190
+ (pError, pQuery, pResult) =>
191
+ {
192
+ console.log('Restored rows:', pResult);
193
+ });
194
+ ```
195
+
196
+ **Internally:**
197
+ - Builds query: `pQuery.setDialect('PostgreSQL').buildUndeleteQuery()`
198
+ - Extracts affected rows from the result
199
+
200
+ ### Count
201
+
202
+ Executes a COUNT query and returns the integer count.
203
+
204
+ ```javascript
205
+ meadow.doCount(
206
+ meadow.query.addFilter('Author', 'Frank Herbert', '='),
207
+ (pError, pQuery, pCount) =>
208
+ {
209
+ console.log('Books by Herbert:', pCount);
210
+ });
211
+ ```
212
+
213
+ **Internally:**
214
+ - Builds query: `pQuery.setDialect('PostgreSQL').buildCountQuery()`
215
+ - Extracts count from the result
216
+
217
+ ## Full Setup Example
218
+
219
+ A complete working example connecting to PostgreSQL and performing CRUD operations:
220
+
221
+ ```javascript
222
+ const libFable = require('fable').new(
223
+ {
224
+ PostgreSQL:
225
+ {
226
+ Host: 'localhost',
227
+ Port: 5432,
228
+ User: 'postgres',
229
+ Password: 'secret',
230
+ Database: 'bookstore',
231
+ ConnectionPoolLimit: 10
232
+ }
233
+ });
234
+
235
+ const libMeadow = require('meadow');
236
+ const libMeadowConnectionPostgreSQL = require('meadow-connection-postgresql');
237
+
238
+ // Register and connect
239
+ libFable.serviceManager.addServiceType('MeadowPostgreSQLProvider', libMeadowConnectionPostgreSQL);
240
+ const tmpConnection = libFable.serviceManager.instantiateServiceProvider('MeadowPostgreSQLProvider');
241
+
242
+ tmpConnection.connectAsync(
243
+ (pError) =>
244
+ {
245
+ if (pError)
246
+ {
247
+ return console.error('Connection failed:', pError);
248
+ }
249
+
250
+ // Create the DAL
251
+ const meadow = libMeadow.new(libFable, 'Book')
252
+ .setProvider('PostgreSQL')
253
+ .setDefaultIdentifier('IDBook')
254
+ .setSchema([
255
+ { Column: 'IDBook', Type: 'AutoIdentity' },
256
+ { Column: 'GUIDBook', Type: 'AutoGUID' },
257
+ { Column: 'Title', Type: 'String', Size: '255' },
258
+ { Column: 'Author', Type: 'String', Size: '128' },
259
+ { Column: 'CreateDate', Type: 'CreateDate' },
260
+ { Column: 'CreatingIDUser', Type: 'CreateIDUser' },
261
+ { Column: 'UpdateDate', Type: 'UpdateDate' },
262
+ { Column: 'UpdatingIDUser', Type: 'UpdateIDUser' },
263
+ { Column: 'DeleteDate', Type: 'DeleteDate' },
264
+ { Column: 'DeletingIDUser', Type: 'DeleteIDUser' },
265
+ { Column: 'Deleted', Type: 'Deleted' }
266
+ ]);
267
+
268
+ // Insert a record
269
+ meadow.doCreate(
270
+ meadow.query.addRecord({ Title: 'Dune', Author: 'Frank Herbert' }),
271
+ (pError, pCreateQuery, pReadQuery, pRecord) =>
272
+ {
273
+ console.log('Created book with ID:', pRecord.IDBook);
274
+
275
+ // Read it back
276
+ meadow.doRead(
277
+ meadow.query.addFilter('IDBook', pRecord.IDBook),
278
+ (pError, pQuery, pRecord) =>
279
+ {
280
+ console.log('Read back:', pRecord.Title, 'by', pRecord.Author);
281
+ });
282
+ });
283
+ });
284
+ ```
285
+
286
+ ## Error Handling
287
+
288
+ All operations follow the same error handling pattern:
289
+
290
+ - Database errors are stored in `pQuery.parameters.result.error`
291
+ - Identity/rowcount extraction failures are logged as warnings
292
+ - Connection errors bubble up through the callback as `pError`
293
+
294
+ ## Docker Development
295
+
296
+ For local PostgreSQL development:
297
+
298
+ ```bash
299
+ docker run -d \
300
+ --name meadow-postgresql \
301
+ -e POSTGRES_PASSWORD=secret \
302
+ -e POSTGRES_DB=myapp \
303
+ -p 5432:5432 \
304
+ postgres:16
305
+ ```
306
+
307
+ ## Related Documentation
308
+
309
+ - [Providers Overview](providers/README.md) -- Comparison of all providers
310
+ - [MySQL Provider](providers/mysql.md) -- MySQL/MariaDB alternative
311
+ - [MSSQL Provider](providers/mssql.md) -- Microsoft SQL Server alternative
312
+ - [meadow-connection-postgresql](https://github.com/stevenvelozo/meadow-connection-postgresql) -- Connection module source