meadow 2.0.16 → 2.0.18

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.
@@ -0,0 +1,38 @@
1
+ - Getting Started
2
+
3
+ - [Introduction](/)
4
+ - [Architecture](architecture.md)
5
+
6
+ - Core Concepts
7
+
8
+ - [Schema](schema/README.md)
9
+ - [CRUD Operations](crud-operations.md)
10
+ - [Query DSL](query-dsl.md)
11
+ - [Raw Queries](raw-queries.md)
12
+
13
+ - Schema
14
+
15
+ - [Schema Overview](schema/README.md)
16
+
17
+ - Query Operations
18
+
19
+ - [Query Overview](query/README.md)
20
+ - [Create](query/create.md)
21
+ - [Read](query/read.md)
22
+ - [Update](query/update.md)
23
+ - [Delete](query/delete.md)
24
+ - [Count](query/count.md)
25
+
26
+ - Providers
27
+
28
+ - [Providers Overview](providers/README.md)
29
+ - [MySQL](providers/mysql.md)
30
+ - [MSSQL](providers/mssql.md)
31
+ - [SQLite](providers/sqlite.md)
32
+ - [ALASQL](providers/alasql.md)
33
+
34
+ - Advanced
35
+
36
+ - [Audit Tracking](audit-tracking.md)
37
+ - [Soft Deletes](soft-deletes.md)
38
+ - [Configuration Reference](configuration.md)
@@ -0,0 +1,253 @@
1
+ # Providers
2
+
3
+ > Pluggable database backends through a consistent interface
4
+
5
+ Meadow's provider system abstracts database communication behind a unified CRUD interface. You write your data access code once, then swap providers to target MySQL, MSSQL, SQLite, an in-browser IndexedDB store, or even a remote REST API — all without changing your application logic.
6
+
7
+ ## Overview
8
+
9
+ ```
10
+ Meadow (Data Access Layer)
11
+ └── Provider Interface
12
+ ├── MySQL → mysql2 connection pool, named placeholders
13
+ ├── MSSQL → mssql prepared statements, SCOPE_IDENTITY()
14
+ ├── SQLite → Lightweight embedded SQL
15
+ ├── ALASQL → In-memory JavaScript SQL engine (browser/Node)
16
+ ├── MeadowEndpoints → HTTP proxy to remote Meadow REST API
17
+ └── None → No-op stub for testing
18
+ ```
19
+
20
+ Every provider implements the same operation set:
21
+
22
+ | Operation | Description |
23
+ |-----------|-------------|
24
+ | `Create` | Insert a new record, return the identity value |
25
+ | `Read` | Execute a SELECT query, return result rows |
26
+ | `Update` | Execute an UPDATE query |
27
+ | `Delete` | Execute a DELETE query (soft delete), return affected rows |
28
+ | `Undelete` | Reverse a soft delete, return affected rows |
29
+ | `Count` | Execute a COUNT query, return the row count |
30
+
31
+ ## Choosing a Provider
32
+
33
+ | Provider | Best For | Connection Module |
34
+ |----------|----------|-------------------|
35
+ | [MySQL](providers/mysql.md) | Production web applications, MySQL/MariaDB | [meadow-connection-mysql](https://github.com/stevenvelozo/meadow-connection-mysql) |
36
+ | [MSSQL](providers/mssql.md) | Enterprise environments, SQL Server | [meadow-connection-mssql](https://github.com/stevenvelozo/meadow-connection-mssql) |
37
+ | [SQLite](providers/sqlite.md) | Embedded applications, local development | [meadow-connection-sqlite](https://github.com/stevenvelozo/meadow-connection-sqlite) |
38
+ | [ALASQL](providers/alasql.md) | Browser applications, unit testing, prototyping | Built-in (no external connection) |
39
+ | MeadowEndpoints | Client-side proxy to remote Meadow APIs | Built-in (HTTP via simple-get) |
40
+ | None | Unit testing stubs, development scaffolding | None required |
41
+
42
+ ## Setting a Provider
43
+
44
+ ```javascript
45
+ const libFable = require('fable').new();
46
+ const libMeadow = require('meadow');
47
+
48
+ const meadow = libMeadow.new(libFable, 'Book')
49
+ .setProvider('MySQL')
50
+ .setDefaultIdentifier('IDBook')
51
+ .setSchema([
52
+ { Column: 'IDBook', Type: 'AutoIdentity' },
53
+ { Column: 'Title', Type: 'String', Size: '255' }
54
+ ]);
55
+ ```
56
+
57
+ The provider name is a string matching one of: `'MySQL'`, `'MSSQL'`, `'SQLite'`, `'ALASQL'`, `'MeadowEndpoints'`, or `'None'`.
58
+
59
+ ## How Providers Work
60
+
61
+ ### Query Flow
62
+
63
+ Every CRUD operation follows the same flow through the provider:
64
+
65
+ ```
66
+ Application Code
67
+
68
+
69
+ Meadow Behavior (e.g., doCreate)
70
+ │ 1. Build query object via FoxHound
71
+ │ 2. Apply auto-stamps and GUID generation
72
+ │ 3. Merge default object with submitted record
73
+
74
+
75
+ FoxHound Query DSL
76
+ │ 4. Set dialect for target database
77
+ │ 5. Generate dialect-specific SQL
78
+ │ 6. Bind parameters
79
+
80
+
81
+ Provider
82
+ │ 7. Get database connection
83
+ │ 8. Execute generated SQL
84
+ │ 9. Marshal results into result object
85
+
86
+
87
+ Callback
88
+ 10. Return (pError, pQuery, pRecord/pRecords)
89
+ ```
90
+
91
+ ### FoxHound Dialect Integration
92
+
93
+ Each provider sets the appropriate FoxHound dialect before building queries:
94
+
95
+ ```javascript
96
+ // MySQL provider internally calls:
97
+ pQuery.setDialect('MySQL').buildReadQuery();
98
+
99
+ // MSSQL provider internally calls:
100
+ pQuery.setDialect('MSSQL').buildReadQuery();
101
+
102
+ // ALASQL provider internally calls:
103
+ pQuery.setDialect('ALASQL').buildReadQuery();
104
+ ```
105
+
106
+ This ensures the generated SQL matches the target database's syntax.
107
+
108
+ ### Result Object
109
+
110
+ All providers store their results in a consistent structure on the query object:
111
+
112
+ ```javascript
113
+ pQuery.parameters.result =
114
+ {
115
+ error: null, // Error object if operation failed, null on success
116
+ value: false, // Result value (varies by operation — see below)
117
+ executed: true // Whether the provider attempted execution
118
+ };
119
+ ```
120
+
121
+ | Operation | `result.value` |
122
+ |-----------|----------------|
123
+ | Create | Identity value of the new record (e.g., `42`) |
124
+ | Read | Array of record objects |
125
+ | Update | Query result object |
126
+ | Delete | Number of affected rows |
127
+ | Undelete | Number of affected rows |
128
+ | Count | Integer count of matching records |
129
+
130
+ ### Record Marshalling
131
+
132
+ All providers implement `marshalRecordFromSourceToObject(pObject, pRecord)` to copy database field values onto a result object:
133
+
134
+ ```javascript
135
+ // Provider copies each column from the database result to the output object
136
+ for (var tmpColumn in pRecord)
137
+ {
138
+ pObject[tmpColumn] = pRecord[tmpColumn];
139
+ }
140
+ ```
141
+
142
+ Meadow's `marshalRecordFromSourceToObject` method combines this with default object merging:
143
+
144
+ ```javascript
145
+ // Internally:
146
+ // 1. Create object from default template
147
+ // 2. Provider copies database values over defaults
148
+ const tmpRecord = fable.Utility.extend({}, schema.defaultObject, pRecord);
149
+ ```
150
+
151
+ ### Schema Synchronization
152
+
153
+ When you call `setSchema()` on Meadow, it automatically updates the provider:
154
+
155
+ ```javascript
156
+ // Meadow internally calls:
157
+ provider.setSchema(scope, schema, defaultIdentifier, defaultGUIdentifier);
158
+ ```
159
+
160
+ This is critical for providers like ALASQL that dynamically create tables from schema definitions.
161
+
162
+ ## Connection Management
163
+
164
+ Each SQL provider requires a connection module registered as a Fable service. The connection modules handle pooling, configuration, and lifecycle management.
165
+
166
+ ### MySQL Connection
167
+
168
+ ```javascript
169
+ const libMeadowConnectionMySQL = require('meadow-connection-mysql');
170
+
171
+ // Register the connection service
172
+ libFable.serviceManager.addServiceType('MeadowMySQLProvider', libMeadowConnectionMySQL);
173
+ libFable.serviceManager.instantiateServiceProvider('MeadowMySQLProvider');
174
+
175
+ // Or auto-connect on init:
176
+ libFable.serviceManager.instantiateServiceProvider('MeadowMySQLProvider',
177
+ { MeadowConnectionMySQLAutoConnect: true });
178
+ ```
179
+
180
+ ### MSSQL Connection
181
+
182
+ ```javascript
183
+ const libMeadowConnectionMSSQL = require('meadow-connection-mssql');
184
+
185
+ // Register and connect asynchronously
186
+ libFable.serviceManager.addServiceType('MeadowMSSQLProvider', libMeadowConnectionMSSQL);
187
+ const tmpConnection = libFable.serviceManager.instantiateServiceProvider('MeadowMSSQLProvider');
188
+ tmpConnection.connectAsync(
189
+ (pError) =>
190
+ {
191
+ if (pError)
192
+ {
193
+ return console.error('Connection failed:', pError);
194
+ }
195
+ // Ready for CRUD operations
196
+ });
197
+ ```
198
+
199
+ ## MeadowEndpoints Provider
200
+
201
+ The MeadowEndpoints provider is unique — it doesn't connect to a database directly. Instead, it acts as an HTTP proxy to a remote Meadow REST API. This enables client-side code to use the same Meadow interface while the actual data operations happen on a server.
202
+
203
+ ```javascript
204
+ meadow.setProvider('MeadowEndpoints');
205
+ ```
206
+
207
+ Configuration is read from Fable settings:
208
+
209
+ ```json
210
+ {
211
+ "MeadowEndpoints": {
212
+ "ServerProtocol": "http",
213
+ "ServerAddress": "127.0.0.1",
214
+ "ServerPort": 8086,
215
+ "ServerEndpointPrefix": "1.0/"
216
+ }
217
+ }
218
+ ```
219
+
220
+ | HTTP Method | CRUD Operation |
221
+ |-------------|----------------|
222
+ | `POST` | Create |
223
+ | `GET` | Read / Reads / Count |
224
+ | `PUT` | Update |
225
+ | `DELETE` | Delete |
226
+
227
+ ## None Provider
228
+
229
+ The None provider is a no-op stub that marks every operation as executed without doing anything. Useful for testing application logic without a database connection.
230
+
231
+ ```javascript
232
+ meadow.setProvider('None');
233
+
234
+ // All operations succeed immediately with empty results
235
+ meadow.doRead(meadow.query.addFilter('IDBook', 1),
236
+ (pError, pQuery, pRecord) =>
237
+ {
238
+ // pRecord will be minimal/empty — no actual data
239
+ });
240
+ ```
241
+
242
+ ## Provider-Specific Documentation
243
+
244
+ - [MySQL](providers/mysql.md) — Connection pooling, named placeholders, configuration
245
+ - [MSSQL](providers/mssql.md) — Prepared statements, type mapping, identity handling
246
+ - [SQLite](providers/sqlite.md) — Embedded database, lightweight deployment
247
+ - [ALASQL](providers/alasql.md) — In-memory SQL, dynamic table creation, browser support
248
+
249
+ ## Related Documentation
250
+
251
+ - [Schema](schema/README.md) — How schema definitions drive provider behavior
252
+ - [Query Overview](query/README.md) — FoxHound query DSL and dialect generation
253
+ - [Meadow-Endpoints](https://github.com/stevenvelozo/meadow-endpoints) — REST API generation on top of Meadow providers
@@ -0,0 +1,271 @@
1
+ # ALASQL Provider
2
+
3
+ > In-memory JavaScript SQL engine for browser applications, unit testing, and rapid prototyping
4
+
5
+ The ALASQL provider connects Meadow to [AlaSQL](https://github.com/AlaSQL/alasql), a JavaScript SQL database that runs entirely in memory. It requires no external database server, supports dynamic table creation from Meadow schemas, and works in both Node.js and browser environments. This makes it ideal for unit tests, browser-based applications, and prototyping.
6
+
7
+ ## Setup
8
+
9
+ ### Install Dependencies
10
+
11
+ ```bash
12
+ npm install meadow alasql
13
+ ```
14
+
15
+ ### Initialize ALASQL on Fable
16
+
17
+ ```javascript
18
+ const libFable = require('fable').new();
19
+ const libALASQL = require('alasql');
20
+
21
+ // Attach ALASQL to the Fable instance
22
+ libFable.ALASQL = libALASQL;
23
+ ```
24
+
25
+ ### Create a Meadow DAL
26
+
27
+ ```javascript
28
+ const libMeadow = require('meadow');
29
+
30
+ const meadow = libMeadow.new(libFable, 'Book')
31
+ .setProvider('ALASQL')
32
+ .setDefaultIdentifier('IDBook')
33
+ .setSchema([
34
+ { Column: 'IDBook', Type: 'AutoIdentity' },
35
+ { Column: 'GUIDBook', Type: 'AutoGUID' },
36
+ { Column: 'Title', Type: 'String', Size: '255' },
37
+ { Column: 'Author', Type: 'String', Size: '128' },
38
+ { Column: 'PageCount', Type: 'Numeric' },
39
+ { Column: 'InPrint', Type: 'Boolean' },
40
+ { Column: 'CreateDate', Type: 'CreateDate' },
41
+ { Column: 'CreatingIDUser', Type: 'CreateIDUser' },
42
+ { Column: 'UpdateDate', Type: 'UpdateDate' },
43
+ { Column: 'UpdatingIDUser', Type: 'UpdateIDUser' },
44
+ { Column: 'DeleteDate', Type: 'DeleteDate' },
45
+ { Column: 'DeletingIDUser', Type: 'DeleteIDUser' },
46
+ { Column: 'Deleted', Type: 'Deleted' }
47
+ ]);
48
+ ```
49
+
50
+ ## Dynamic Table Creation
51
+
52
+ Unlike SQL-server-based providers, ALASQL dynamically creates tables from your Meadow schema. When the first CRUD operation is executed, the provider checks whether the table exists and creates it if needed.
53
+
54
+ ### Schema-to-SQL Type Mapping
55
+
56
+ | Meadow Type | ALASQL Column Definition |
57
+ |-------------|--------------------------|
58
+ | `AutoIdentity` | `INT AUTOINCREMENT` |
59
+ | `AutoGUID` | `STRING` |
60
+ | `Boolean` | `BOOLEAN` |
61
+ | `Numeric` | `INT` |
62
+ | `Integer` | `INT` |
63
+ | `Decimal` | `DECIMAL` |
64
+ | `String` | `STRING` |
65
+ | `Text` | `STRING` |
66
+ | `DateTime` | `STRING` |
67
+ | `CreateDate` | `STRING` |
68
+ | `CreateIDUser` | `INT` |
69
+ | `UpdateDate` | `STRING` |
70
+ | `UpdateIDUser` | `INT` |
71
+ | `DeleteDate` | `STRING` |
72
+ | `DeleteIDUser` | `INT` |
73
+ | `Deleted` | `BOOLEAN` |
74
+
75
+ ### Automatic Table Check
76
+
77
+ Before each CRUD operation, the provider calls `checkDataExists(pParameters)` to verify the table exists. If not, it generates and executes a `CREATE TABLE` statement based on the schema:
78
+
79
+ ```sql
80
+ -- Generated automatically from schema:
81
+ CREATE TABLE Book (
82
+ IDBook INT AUTOINCREMENT,
83
+ GUIDBook STRING,
84
+ Title STRING,
85
+ Author STRING,
86
+ PageCount INT,
87
+ InPrint BOOLEAN,
88
+ CreateDate STRING,
89
+ CreatingIDUser INT,
90
+ UpdateDate STRING,
91
+ UpdatingIDUser INT,
92
+ DeleteDate STRING,
93
+ DeletingIDUser INT,
94
+ Deleted BOOLEAN
95
+ )
96
+ ```
97
+
98
+ ## CRUD Operations
99
+
100
+ All ALASQL operations are **synchronous** internally (wrapped in callbacks for API consistency). Queries are compiled via `libALASQL.compile()` for efficient execution.
101
+
102
+ ### Create
103
+
104
+ ```javascript
105
+ meadow.doCreate(
106
+ meadow.query.addRecord({ Title: 'Dune', Author: 'Frank Herbert' }),
107
+ (pError, pCreateQuery, pReadQuery, pRecord) =>
108
+ {
109
+ console.log('New ID:', pRecord.IDBook);
110
+ });
111
+ ```
112
+
113
+ **Internally:**
114
+ - Builds query: `pQuery.setDialect('ALASQL').buildCreateQuery()`
115
+ - Compiles: `libALASQL.compile(queryBody)`
116
+ - Extracts identity: `libALASQL.autoval(scope, defaultIdentifier)`
117
+
118
+ ### Read
119
+
120
+ ```javascript
121
+ meadow.doRead(
122
+ meadow.query.addFilter('IDBook', 1),
123
+ (pError, pQuery, pRecord) =>
124
+ {
125
+ console.log('Title:', pRecord.Title);
126
+ });
127
+
128
+ meadow.doReads(
129
+ meadow.query.setCap(10),
130
+ (pError, pQuery, pRecords) =>
131
+ {
132
+ pRecords.forEach((pBook) => console.log(pBook.Title));
133
+ });
134
+ ```
135
+
136
+ ### Update
137
+
138
+ ```javascript
139
+ meadow.doUpdate(
140
+ meadow.query
141
+ .addFilter('IDBook', 1)
142
+ .addRecord({ Title: 'Updated Title' }),
143
+ (pError, pUpdateQuery, pReadQuery, pRecord) =>
144
+ {
145
+ console.log('Updated:', pRecord.Title);
146
+ });
147
+ ```
148
+
149
+ ### Delete
150
+
151
+ ```javascript
152
+ meadow.doDelete(
153
+ meadow.query.addFilter('IDBook', 1),
154
+ (pError, pQuery, pResult) =>
155
+ {
156
+ console.log('Deleted rows:', pResult);
157
+ });
158
+ ```
159
+
160
+ ### Count
161
+
162
+ ```javascript
163
+ meadow.doCount(
164
+ meadow.query,
165
+ (pError, pQuery, pCount) =>
166
+ {
167
+ console.log('Total books:', pCount);
168
+ });
169
+ ```
170
+
171
+ ## Data Binding
172
+
173
+ The ALASQL provider offers special methods for directly binding JavaScript data to tables, which is useful for initializing state or importing datasets.
174
+
175
+ ### Bind an Array to a Table
176
+
177
+ ```javascript
178
+ // Directly assign an array as the table's data
179
+ meadow.provider.bindObject(
180
+ [
181
+ { IDBook: 1, Title: 'Dune', Author: 'Frank Herbert' },
182
+ { IDBook: 2, Title: 'Foundation', Author: 'Isaac Asimov' },
183
+ { IDBook: 3, Title: 'Neuromancer', Author: 'William Gibson' }
184
+ ]);
185
+ // ALASQL.tables['Book'].data now contains these records
186
+ ```
187
+
188
+ ### Construct from Object
189
+
190
+ The `constructFromObject` method builds a complete Meadow entity from a JavaScript object prototype, optionally including audit columns and importing data:
191
+
192
+ ```javascript
193
+ meadow.provider.constructFromObject(
194
+ {
195
+ Meadow: meadow,
196
+ Scope: 'Book',
197
+ ObjectPrototype:
198
+ {
199
+ Title: 'String',
200
+ Author: 'String',
201
+ PageCount: 'Numeric'
202
+ },
203
+ AuditData: true, // Auto-generate audit columns
204
+ Import: true, // Import the Data array via doCreate
205
+ Data:
206
+ [
207
+ { Title: 'Dune', Author: 'Frank Herbert', PageCount: 412 },
208
+ { Title: 'Foundation', Author: 'Isaac Asimov', PageCount: 244 }
209
+ ]
210
+ });
211
+ ```
212
+
213
+ | Parameter | Type | Description |
214
+ |-----------|------|-------------|
215
+ | `Meadow` | object | The Meadow instance to configure |
216
+ | `Scope` | string | Entity name for the table |
217
+ | `ObjectPrototype` | object | Column name to type mapping |
218
+ | `AuditData` | boolean | Add Create/Update/Delete audit columns |
219
+ | `Import` | boolean | Import Data array via `doCreate` operations |
220
+ | `Data` | array | Records to import (when `Import` is `true`) |
221
+
222
+ ## Browser Usage
223
+
224
+ ALASQL is the recommended provider for browser-based Meadow applications. When bundled with Browserify or another bundler, Meadow with ALASQL provides a full SQL database in the browser.
225
+
226
+ ```javascript
227
+ // In a browser bundle:
228
+ const libFable = require('fable').new();
229
+ const libALASQL = require('alasql');
230
+ const libMeadow = require('meadow');
231
+
232
+ libFable.ALASQL = libALASQL;
233
+
234
+ const meadow = libMeadow.new(libFable, 'Task')
235
+ .setProvider('ALASQL')
236
+ .setDefaultIdentifier('IDTask')
237
+ .setSchema([
238
+ { Column: 'IDTask', Type: 'AutoIdentity' },
239
+ { Column: 'Description', Type: 'String', Size: '255' },
240
+ { Column: 'Complete', Type: 'Boolean' }
241
+ ]);
242
+
243
+ // Full CRUD operations in the browser
244
+ meadow.doCreate(
245
+ meadow.query.addRecord({ Description: 'Buy groceries', Complete: false }),
246
+ (pError, pCreateQuery, pReadQuery, pRecord) =>
247
+ {
248
+ console.log('Created task:', pRecord.IDTask);
249
+ });
250
+ ```
251
+
252
+ ## When to Use ALASQL
253
+
254
+ | Use Case | Recommendation |
255
+ |----------|---------------|
256
+ | Unit testing | Excellent — no database setup, fast, deterministic |
257
+ | Browser applications | Excellent — full SQL in the browser |
258
+ | Rapid prototyping | Excellent — start coding immediately |
259
+ | Production server | Consider MySQL or MSSQL instead |
260
+ | Data persistence | Data is in-memory only (lost on refresh/restart) |
261
+
262
+ ## Error Handling
263
+
264
+ All operations are wrapped in try-catch blocks. Errors are stored in `pQuery.parameters.result.error` and the `executed` flag is always set to `true`.
265
+
266
+ ## Related Documentation
267
+
268
+ - [Providers Overview](providers/README.md) — Comparison of all providers
269
+ - [MySQL Provider](providers/mysql.md) — Production MySQL alternative
270
+ - [SQLite Provider](providers/sqlite.md) — Lightweight embedded alternative
271
+ - [Schema](schema/README.md) — Schema definitions that drive table creation