meadow 2.0.17 → 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.
- package/README.md +174 -112
- package/docs/README.md +276 -0
- package/docs/_sidebar.md +38 -0
- package/docs/providers/README.md +253 -0
- package/docs/providers/alasql.md +271 -0
- package/docs/providers/mssql.md +296 -0
- package/docs/providers/mysql.md +260 -0
- package/docs/providers/sqlite.md +173 -0
- package/docs/query/README.md +175 -0
- package/docs/query/count.md +228 -0
- package/docs/query/create.md +226 -0
- package/docs/query/delete.md +264 -0
- package/docs/query/read.md +350 -0
- package/docs/query/update.md +250 -0
- package/docs/schema/README.md +408 -0
- package/package.json +16 -3
- package/scripts/mssql-test-db.sh +111 -0
- package/scripts/mysql-test-db.sh +108 -0
- package/source/Meadow.js +1 -0
- package/source/providers/Meadow-Provider-SQLite.js +235 -155
- package/test/Meadow-Provider-SQLite-AnimalReadQuery.sql +5 -0
- package/test/Meadow-Provider-SQLite_tests.js +931 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Create
|
|
2
|
+
|
|
3
|
+
> Insert new records into the database
|
|
4
|
+
|
|
5
|
+
The `doCreate` method inserts a new record and returns the fully hydrated object, including any auto-generated fields like the primary key, GUID, and creation timestamps.
|
|
6
|
+
|
|
7
|
+
## Method Signature
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
meadow.doCreate(pQuery, fCallBack)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Callback
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
fCallBack(pError, pCreateQuery, pReadQuery, pRecord)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Parameter | Type | Description |
|
|
20
|
+
|-----------|------|-------------|
|
|
21
|
+
| `pError` | object/null | Error object if the operation failed, null on success |
|
|
22
|
+
| `pCreateQuery` | object | The query used for the INSERT operation |
|
|
23
|
+
| `pReadQuery` | object | The query used to read back the created record |
|
|
24
|
+
| `pRecord` | object | The fully hydrated record with all auto-generated fields |
|
|
25
|
+
|
|
26
|
+
## Basic Usage
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
const tmpQuery = meadow.query.addRecord(
|
|
30
|
+
{
|
|
31
|
+
Title: 'Neuromancer',
|
|
32
|
+
Author: 'William Gibson',
|
|
33
|
+
PublishYear: 1984
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
meadow.doCreate(tmpQuery,
|
|
37
|
+
(pError, pCreateQuery, pReadQuery, pRecord) =>
|
|
38
|
+
{
|
|
39
|
+
if (pError)
|
|
40
|
+
{
|
|
41
|
+
return console.log('Create failed:', pError);
|
|
42
|
+
}
|
|
43
|
+
console.log('Created book:', pRecord.IDBook);
|
|
44
|
+
console.log('GUID:', pRecord.GUIDBook);
|
|
45
|
+
console.log('Created at:', pRecord.CreateDate);
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## How It Works
|
|
50
|
+
|
|
51
|
+
The create operation follows a multi-step waterfall:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
1. GUID Uniqueness Check (if GUID provided)
|
|
55
|
+
└── Queries DB to verify no existing record has this GUID
|
|
56
|
+
2. Insert Record
|
|
57
|
+
└── Merges record with schema defaults, executes INSERT
|
|
58
|
+
3. Validate Creation
|
|
59
|
+
└── Confirms the insert succeeded, extracts new ID
|
|
60
|
+
4. Read Back Record
|
|
61
|
+
└── Fetches the complete record using the new ID
|
|
62
|
+
5. Marshal to Object
|
|
63
|
+
└── Converts DB result to a plain JavaScript object
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## GUID Uniqueness
|
|
67
|
+
|
|
68
|
+
If your record includes a GUID value (and the value is at least 5 characters), Meadow automatically checks for uniqueness before inserting:
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
const tmpQuery = meadow.query.addRecord(
|
|
72
|
+
{
|
|
73
|
+
GUIDBook: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
|
|
74
|
+
Title: 'Dune'
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
meadow.doCreate(tmpQuery,
|
|
78
|
+
(pError, pCreateQuery, pReadQuery, pRecord) =>
|
|
79
|
+
{
|
|
80
|
+
// If the GUID already exists, pError will contain:
|
|
81
|
+
// "Record with GUID a1b2c3d4-e5f6-7890-abcd-ef1234567890 already exists!"
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The GUID check searches across all records, including soft-deleted ones (it sets `disableDeleteTracking` to `true` for the uniqueness query). If you do not provide a GUID, the `AutoGUID` schema type generates one automatically.
|
|
86
|
+
|
|
87
|
+
## Auto-Populated Fields
|
|
88
|
+
|
|
89
|
+
When your schema includes these column types, Meadow populates them automatically during creation:
|
|
90
|
+
|
|
91
|
+
| Schema Type | Behavior on Create |
|
|
92
|
+
|-------------|-------------------|
|
|
93
|
+
| `AutoIdentity` | Generated by the database (auto-increment) |
|
|
94
|
+
| `AutoGUID` | Generated if not provided in the record |
|
|
95
|
+
| `CreateDate` | Set to `NOW()` by the database |
|
|
96
|
+
| `CreateIDUser` | Set to the current user ID |
|
|
97
|
+
| `UpdateDate` | Not set on create |
|
|
98
|
+
| `UpdateIDUser` | Not set on create |
|
|
99
|
+
| `Deleted` | Set to `0` (from schema defaults) |
|
|
100
|
+
|
|
101
|
+
## Setting User Identity
|
|
102
|
+
|
|
103
|
+
The creating user ID is determined in this order of precedence:
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
// 1. Set on the query object directly
|
|
107
|
+
const tmpQuery = meadow.query.addRecord({ Title: 'Dune' });
|
|
108
|
+
tmpQuery.query.IDUser = 42;
|
|
109
|
+
|
|
110
|
+
// 2. Set on the Meadow instance
|
|
111
|
+
meadow.setIDUser(42);
|
|
112
|
+
// This applies to all subsequent operations
|
|
113
|
+
|
|
114
|
+
// 3. Set via the userID property on the query parameters
|
|
115
|
+
const tmpQuery = meadow.query.addRecord({ Title: 'Dune' });
|
|
116
|
+
tmpQuery.parameters.userID = 42;
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Creating with Specific Fields
|
|
120
|
+
|
|
121
|
+
Only fields present in your schema are included in the INSERT statement. Extra fields are ignored:
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
const tmpQuery = meadow.query.addRecord(
|
|
125
|
+
{
|
|
126
|
+
Title: 'Foundation',
|
|
127
|
+
Author: 'Isaac Asimov',
|
|
128
|
+
NotASchemaField: 'this will be ignored'
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
meadow.doCreate(tmpQuery,
|
|
132
|
+
(pError, pCreateQuery, pReadQuery, pRecord) =>
|
|
133
|
+
{
|
|
134
|
+
// pRecord will not contain NotASchemaField
|
|
135
|
+
// It WILL contain all schema defaults plus auto-generated fields
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Error Handling
|
|
140
|
+
|
|
141
|
+
Common error conditions:
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
meadow.doCreate(tmpQuery,
|
|
145
|
+
(pError, pCreateQuery, pReadQuery, pRecord) =>
|
|
146
|
+
{
|
|
147
|
+
if (pError)
|
|
148
|
+
{
|
|
149
|
+
// Possible errors:
|
|
150
|
+
// - "No record submitted" (empty or missing addRecord)
|
|
151
|
+
// - "Creation failed" (database insert error)
|
|
152
|
+
// - "Record with GUID ... already exists!" (duplicate GUID)
|
|
153
|
+
// - Provider-specific database errors
|
|
154
|
+
console.log('Error:', pError);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Raw Query Override
|
|
160
|
+
|
|
161
|
+
The Create operation does not support raw query overrides for the INSERT step. However, the read-back step (which fetches the newly created record) does respect the `Read` query override:
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
// This will be used when reading back the created record
|
|
165
|
+
meadow.rawQueries.setQuery('Read',
|
|
166
|
+
'SELECT b.*, a.Name AS AuthorName FROM Book b JOIN Author a ON b.IDAuthor = a.IDAuthor WHERE b.IDBook = :IDBook');
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Full Example
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
const libFable = require('fable').new();
|
|
173
|
+
const libMeadow = require('meadow');
|
|
174
|
+
|
|
175
|
+
const meadow = libMeadow.new(libFable, 'Book')
|
|
176
|
+
.setProvider('MySQL')
|
|
177
|
+
.setDefaultIdentifier('IDBook')
|
|
178
|
+
.setSchema([
|
|
179
|
+
{ Column: 'IDBook', Type: 'AutoIdentity' },
|
|
180
|
+
{ Column: 'GUIDBook', Type: 'AutoGUID' },
|
|
181
|
+
{ Column: 'Title', Type: 'String', Size: '255' },
|
|
182
|
+
{ Column: 'Author', Type: 'String', Size: '128' },
|
|
183
|
+
{ Column: 'Price', Type: 'Decimal', Size: '18,2' },
|
|
184
|
+
{ Column: 'CreateDate', Type: 'CreateDate' },
|
|
185
|
+
{ Column: 'CreatingIDUser', Type: 'CreateIDUser' },
|
|
186
|
+
{ Column: 'UpdateDate', Type: 'UpdateDate' },
|
|
187
|
+
{ Column: 'UpdatingIDUser', Type: 'UpdateIDUser' },
|
|
188
|
+
{ Column: 'Deleted', Type: 'Deleted' }
|
|
189
|
+
]);
|
|
190
|
+
|
|
191
|
+
// Set the user performing the operation
|
|
192
|
+
meadow.setIDUser(1);
|
|
193
|
+
|
|
194
|
+
// Build the create query
|
|
195
|
+
const tmpQuery = meadow.query.addRecord(
|
|
196
|
+
{
|
|
197
|
+
Title: 'Snow Crash',
|
|
198
|
+
Author: 'Neal Stephenson',
|
|
199
|
+
Price: 14.99
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Execute the create
|
|
203
|
+
meadow.doCreate(tmpQuery,
|
|
204
|
+
(pError, pCreateQuery, pReadQuery, pRecord) =>
|
|
205
|
+
{
|
|
206
|
+
if (pError)
|
|
207
|
+
{
|
|
208
|
+
return console.log('Failed to create book:', pError);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// pRecord now contains the full record:
|
|
212
|
+
// {
|
|
213
|
+
// IDBook: 1, (auto-generated)
|
|
214
|
+
// GUIDBook: '0x...', (auto-generated)
|
|
215
|
+
// Title: 'Snow Crash',
|
|
216
|
+
// Author: 'Neal Stephenson',
|
|
217
|
+
// Price: 14.99,
|
|
218
|
+
// CreateDate: '2024-01-15...', (auto-generated)
|
|
219
|
+
// CreatingIDUser: 1, (from setIDUser)
|
|
220
|
+
// UpdateDate: null,
|
|
221
|
+
// UpdatingIDUser: 0,
|
|
222
|
+
// Deleted: 0
|
|
223
|
+
// }
|
|
224
|
+
console.log('Book created:', pRecord.IDBook, '-', pRecord.Title);
|
|
225
|
+
});
|
|
226
|
+
```
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# Delete
|
|
2
|
+
|
|
3
|
+
> Soft delete, hard delete, and undelete records
|
|
4
|
+
|
|
5
|
+
Meadow supports both soft deletes (logical deletion) and hard deletes (physical removal), depending on your schema. When your schema includes a `Deleted` column, delete operations set a flag rather than removing the record. Meadow also provides an undelete operation to restore soft-deleted records.
|
|
6
|
+
|
|
7
|
+
## doDelete
|
|
8
|
+
|
|
9
|
+
### Method Signature
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
meadow.doDelete(pQuery, fCallBack)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Callback
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
fCallBack(pError, pQuery, pCount)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
| Parameter | Type | Description |
|
|
22
|
+
|-----------|------|-------------|
|
|
23
|
+
| `pError` | object/null | Error object if the operation failed, null on success |
|
|
24
|
+
| `pQuery` | object | The query that was executed |
|
|
25
|
+
| `pCount` | number | Number of affected records |
|
|
26
|
+
|
|
27
|
+
### Basic Usage
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
meadow.doDelete(meadow.query.addFilter('IDBook', 42),
|
|
31
|
+
(pError, pQuery, pCount) =>
|
|
32
|
+
{
|
|
33
|
+
if (pError)
|
|
34
|
+
{
|
|
35
|
+
return console.log('Delete failed:', pError);
|
|
36
|
+
}
|
|
37
|
+
console.log('Deleted', pCount, 'record(s)');
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Soft Delete vs Hard Delete
|
|
42
|
+
|
|
43
|
+
The behavior depends on whether your schema includes a `Deleted` column:
|
|
44
|
+
|
|
45
|
+
### Soft Delete (Schema has `Deleted` field)
|
|
46
|
+
|
|
47
|
+
When the schema includes `{ Column: 'Deleted', Type: 'Deleted' }`, the delete operation generates an UPDATE statement instead of a DELETE:
|
|
48
|
+
|
|
49
|
+
```sql
|
|
50
|
+
-- What Meadow generates for soft delete:
|
|
51
|
+
UPDATE Book SET Deleted = 1, DeleteDate = NOW(), DeletingIDUser = :IDUser,
|
|
52
|
+
UpdateDate = NOW() WHERE IDBook = :IDBook
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The record remains in the database but is excluded from normal queries.
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
// Schema includes Deleted column
|
|
59
|
+
const meadow = libMeadow.new(libFable, 'Book')
|
|
60
|
+
.setDefaultIdentifier('IDBook')
|
|
61
|
+
.setSchema([
|
|
62
|
+
{ Column: 'IDBook', Type: 'AutoIdentity' },
|
|
63
|
+
{ Column: 'Title', Type: 'String', Size: '255' },
|
|
64
|
+
{ Column: 'DeleteDate', Type: 'DeleteDate' },
|
|
65
|
+
{ Column: 'DeletingIDUser', Type: 'DeleteIDUser' },
|
|
66
|
+
{ Column: 'UpdateDate', Type: 'UpdateDate' },
|
|
67
|
+
{ Column: 'UpdatingIDUser', Type: 'UpdateIDUser' },
|
|
68
|
+
{ Column: 'Deleted', Type: 'Deleted' }
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
meadow.setIDUser(5);
|
|
72
|
+
|
|
73
|
+
meadow.doDelete(meadow.query.addFilter('IDBook', 42),
|
|
74
|
+
(pError, pQuery, pCount) =>
|
|
75
|
+
{
|
|
76
|
+
// Record 42 now has:
|
|
77
|
+
// Deleted = 1
|
|
78
|
+
// DeleteDate = NOW()
|
|
79
|
+
// DeletingIDUser = 5
|
|
80
|
+
// UpdateDate = NOW()
|
|
81
|
+
// The record is still in the database
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Hard Delete (Schema without `Deleted` field)
|
|
86
|
+
|
|
87
|
+
When there is no `Deleted` column in the schema, the delete operation generates an actual DELETE statement:
|
|
88
|
+
|
|
89
|
+
```sql
|
|
90
|
+
-- What Meadow generates for hard delete:
|
|
91
|
+
DELETE FROM Book WHERE IDBook = :IDBook
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The record is physically removed from the database.
|
|
95
|
+
|
|
96
|
+
### Auto-Populated Fields on Soft Delete
|
|
97
|
+
|
|
98
|
+
| Schema Type | Behavior on Delete |
|
|
99
|
+
|-------------|-------------------|
|
|
100
|
+
| `Deleted` | Set to `1` |
|
|
101
|
+
| `DeleteDate` | Set to `NOW()` |
|
|
102
|
+
| `DeleteIDUser` | Set to the current user ID |
|
|
103
|
+
| `UpdateDate` | Set to `NOW()` (a delete is an update) |
|
|
104
|
+
| `UpdateIDUser` | Set to the current user ID |
|
|
105
|
+
| All others | **Not modified** |
|
|
106
|
+
|
|
107
|
+
## Soft Delete and Read Queries
|
|
108
|
+
|
|
109
|
+
After soft deletion, the record is automatically excluded from normal reads:
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
// This will NOT find the soft-deleted book
|
|
113
|
+
meadow.doRead(meadow.query.addFilter('IDBook', 42),
|
|
114
|
+
(pError, pQuery, pRecord) =>
|
|
115
|
+
{
|
|
116
|
+
// pRecord is undefined -- the book appears "deleted"
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// To find soft-deleted records, disable delete tracking
|
|
120
|
+
meadow.doRead(meadow.query.addFilter('IDBook', 42).setDisableDeleteTracking(true),
|
|
121
|
+
(pError, pQuery, pRecord) =>
|
|
122
|
+
{
|
|
123
|
+
// pRecord is the soft-deleted book with Deleted = 1
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## doUndelete
|
|
130
|
+
|
|
131
|
+
### Method Signature
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
meadow.doUndelete(pQuery, fCallBack)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Callback
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
fCallBack(pError, pQuery, pCount)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
| Parameter | Type | Description |
|
|
144
|
+
|-----------|------|-------------|
|
|
145
|
+
| `pError` | object/null | Error object if the operation failed, null on success |
|
|
146
|
+
| `pQuery` | object | The query that was executed |
|
|
147
|
+
| `pCount` | number | Number of affected records |
|
|
148
|
+
|
|
149
|
+
### Basic Usage
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
meadow.doUndelete(meadow.query.addFilter('IDBook', 42),
|
|
153
|
+
(pError, pQuery, pCount) =>
|
|
154
|
+
{
|
|
155
|
+
if (pError)
|
|
156
|
+
{
|
|
157
|
+
return console.log('Undelete failed:', pError);
|
|
158
|
+
}
|
|
159
|
+
console.log('Restored', pCount, 'record(s)');
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### How Undelete Works
|
|
164
|
+
|
|
165
|
+
The undelete operation generates an UPDATE statement that reverses the soft delete:
|
|
166
|
+
|
|
167
|
+
```sql
|
|
168
|
+
UPDATE Book SET Deleted = 0, UpdateDate = NOW(), UpdatingIDUser = :IDUser
|
|
169
|
+
WHERE IDBook = :IDBook
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Note that `DeleteDate` and `DeletingIDUser` are **not cleared** -- they remain as a historical record of when the record was deleted.
|
|
173
|
+
|
|
174
|
+
### Auto-Populated Fields on Undelete
|
|
175
|
+
|
|
176
|
+
| Schema Type | Behavior on Undelete |
|
|
177
|
+
|-------------|---------------------|
|
|
178
|
+
| `Deleted` | Set to `0` |
|
|
179
|
+
| `UpdateDate` | Set to `NOW()` |
|
|
180
|
+
| `UpdateIDUser` | Set to the current user ID |
|
|
181
|
+
| `DeleteDate` | **Not modified** (preserved as history) |
|
|
182
|
+
| `DeleteIDUser` | **Not modified** (preserved as history) |
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Raw Query Override
|
|
187
|
+
|
|
188
|
+
Both delete and undelete operations respect their respective raw query overrides:
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
// Override the delete query
|
|
192
|
+
meadow.rawQueries.setQuery('Delete',
|
|
193
|
+
'UPDATE Book SET Deleted = 1, DeleteDate = NOW() WHERE IDBook = :IDBook AND IDCustomer = :IDCustomer');
|
|
194
|
+
|
|
195
|
+
// Override the undelete query
|
|
196
|
+
meadow.rawQueries.setQuery('Undelete',
|
|
197
|
+
'UPDATE Book SET Deleted = 0, UpdateDate = NOW() WHERE IDBook = :IDBook AND IDCustomer = :IDCustomer');
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Full Example: Delete and Restore Workflow
|
|
201
|
+
|
|
202
|
+
```javascript
|
|
203
|
+
const libFable = require('fable').new();
|
|
204
|
+
const libMeadow = require('meadow');
|
|
205
|
+
|
|
206
|
+
const meadow = libMeadow.new(libFable, 'Book')
|
|
207
|
+
.setProvider('MySQL')
|
|
208
|
+
.setDefaultIdentifier('IDBook')
|
|
209
|
+
.setSchema([
|
|
210
|
+
{ Column: 'IDBook', Type: 'AutoIdentity' },
|
|
211
|
+
{ Column: 'GUIDBook', Type: 'AutoGUID' },
|
|
212
|
+
{ Column: 'Title', Type: 'String', Size: '255' },
|
|
213
|
+
{ Column: 'CreateDate', Type: 'CreateDate' },
|
|
214
|
+
{ Column: 'CreatingIDUser', Type: 'CreateIDUser' },
|
|
215
|
+
{ Column: 'UpdateDate', Type: 'UpdateDate' },
|
|
216
|
+
{ Column: 'UpdatingIDUser', Type: 'UpdateIDUser' },
|
|
217
|
+
{ Column: 'DeleteDate', Type: 'DeleteDate' },
|
|
218
|
+
{ Column: 'DeletingIDUser', Type: 'DeleteIDUser' },
|
|
219
|
+
{ Column: 'Deleted', Type: 'Deleted' }
|
|
220
|
+
]);
|
|
221
|
+
|
|
222
|
+
meadow.setIDUser(5);
|
|
223
|
+
|
|
224
|
+
// Step 1: Soft delete book 42
|
|
225
|
+
meadow.doDelete(meadow.query.addFilter('IDBook', 42),
|
|
226
|
+
(pError, pQuery, pCount) =>
|
|
227
|
+
{
|
|
228
|
+
console.log('Soft deleted', pCount, 'record(s)');
|
|
229
|
+
|
|
230
|
+
// Step 2: Verify it's gone from normal queries
|
|
231
|
+
meadow.doRead(meadow.query.addFilter('IDBook', 42),
|
|
232
|
+
(pError, pQuery, pRecord) =>
|
|
233
|
+
{
|
|
234
|
+
console.log('Normal read found record:', !!pRecord);
|
|
235
|
+
// false -- record appears deleted
|
|
236
|
+
|
|
237
|
+
// Step 3: It's still there if we look for it
|
|
238
|
+
meadow.doRead(
|
|
239
|
+
meadow.query.addFilter('IDBook', 42).setDisableDeleteTracking(true),
|
|
240
|
+
(pError, pQuery, pRecord) =>
|
|
241
|
+
{
|
|
242
|
+
console.log('With delete tracking disabled:', pRecord.Title);
|
|
243
|
+
console.log('Deleted flag:', pRecord.Deleted);
|
|
244
|
+
// Deleted = 1, record is still in DB
|
|
245
|
+
|
|
246
|
+
// Step 4: Restore it
|
|
247
|
+
meadow.doUndelete(meadow.query.addFilter('IDBook', 42),
|
|
248
|
+
(pError, pQuery, pCount) =>
|
|
249
|
+
{
|
|
250
|
+
console.log('Restored', pCount, 'record(s)');
|
|
251
|
+
|
|
252
|
+
// Step 5: Now it shows up in normal queries again
|
|
253
|
+
meadow.doRead(meadow.query.addFilter('IDBook', 42),
|
|
254
|
+
(pError, pQuery, pRecord) =>
|
|
255
|
+
{
|
|
256
|
+
console.log('Restored:', pRecord.Title);
|
|
257
|
+
console.log('Deleted flag:', pRecord.Deleted);
|
|
258
|
+
// Deleted = 0, record is visible again
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
```
|