meadow 2.0.28 → 2.0.30
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/.quackage.json +9 -0
- package/README.md +3 -0
- package/docs/_sidebar.md +1 -0
- package/docs/schema/README.md +36 -0
- package/docs/schema/json-columns.md +188 -0
- package/package.json +9 -8
- package/source/providers/Meadow-Provider-ALASQL.js +61 -6
- package/source/providers/Meadow-Provider-MSSQL.js +54 -5
- package/source/providers/Meadow-Provider-MySQL.js +144 -11
- package/source/providers/Meadow-Provider-PostgreSQL.js +54 -4
- package/source/providers/Meadow-Provider-SQLite.js +54 -4
- package/test/Animal.json +14 -2
- package/test/Meadow-Provider-ALASQL.js +7 -2
- package/test/Meadow-Provider-MSSQL_tests.js +45 -9
- package/test/Meadow-Provider-MongoDB_tests.js +39 -5
- package/test/Meadow-Provider-MySQL_tests.js +45 -9
- package/test/Meadow-Provider-PostgreSQL_tests.js +44 -8
- package/test/Meadow-Provider-RocksDB_tests.js +65 -30
- package/test/Meadow-Provider-SQLiteBrowser-Headless_tests.js +8 -3
- package/test/Meadow-Provider-SQLiteBrowser_tests.js +43 -5
- package/test/Meadow-Provider-SQLite_tests.js +43 -5
|
@@ -104,13 +104,63 @@ var MeadowProvider = function ()
|
|
|
104
104
|
return false;
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
-
// The Meadow marshaller
|
|
108
|
-
var marshalRecordFromSourceToObject = function (pObject, pRecord)
|
|
107
|
+
// The Meadow marshaller passes in the Schema as the third parameter for JSON/JSONProxy deserialization.
|
|
108
|
+
var marshalRecordFromSourceToObject = function (pObject, pRecord, pSchema)
|
|
109
109
|
{
|
|
110
|
-
//
|
|
110
|
+
// Build lookups for JSON columns (only if schema is provided)
|
|
111
|
+
var tmpJsonColumns = {};
|
|
112
|
+
var tmpProxyColumns = {};
|
|
113
|
+
if (Array.isArray(pSchema))
|
|
114
|
+
{
|
|
115
|
+
for (var s = 0; s < pSchema.length; s++)
|
|
116
|
+
{
|
|
117
|
+
if (pSchema[s].Type === 'JSON')
|
|
118
|
+
{
|
|
119
|
+
tmpJsonColumns[pSchema[s].Column] = true;
|
|
120
|
+
}
|
|
121
|
+
else if (pSchema[s].Type === 'JSONProxy' && pSchema[s].StorageColumn)
|
|
122
|
+
{
|
|
123
|
+
tmpProxyColumns[pSchema[s].StorageColumn] = pSchema[s].Column;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
111
128
|
for (var tmpColumn in pRecord)
|
|
112
129
|
{
|
|
113
|
-
|
|
130
|
+
if (tmpJsonColumns[tmpColumn])
|
|
131
|
+
{
|
|
132
|
+
// JSON type: parse string from DB into object on the same column name
|
|
133
|
+
try
|
|
134
|
+
{
|
|
135
|
+
pObject[tmpColumn] = (typeof pRecord[tmpColumn] === 'string')
|
|
136
|
+
? JSON.parse(pRecord[tmpColumn])
|
|
137
|
+
: (pRecord[tmpColumn] || {});
|
|
138
|
+
}
|
|
139
|
+
catch (pParseError)
|
|
140
|
+
{
|
|
141
|
+
pObject[tmpColumn] = {};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else if (tmpProxyColumns.hasOwnProperty(tmpColumn))
|
|
145
|
+
{
|
|
146
|
+
// JSONProxy: storage column -> parse and assign to virtual column name
|
|
147
|
+
var tmpVirtualColumn = tmpProxyColumns[tmpColumn];
|
|
148
|
+
try
|
|
149
|
+
{
|
|
150
|
+
pObject[tmpVirtualColumn] = (typeof pRecord[tmpColumn] === 'string')
|
|
151
|
+
? JSON.parse(pRecord[tmpColumn])
|
|
152
|
+
: (pRecord[tmpColumn] || {});
|
|
153
|
+
}
|
|
154
|
+
catch (pParseError)
|
|
155
|
+
{
|
|
156
|
+
pObject[tmpVirtualColumn] = {};
|
|
157
|
+
}
|
|
158
|
+
// Do NOT copy the storage column to the output object
|
|
159
|
+
}
|
|
160
|
+
else
|
|
161
|
+
{
|
|
162
|
+
pObject[tmpColumn] = pRecord[tmpColumn];
|
|
163
|
+
}
|
|
114
164
|
}
|
|
115
165
|
};
|
|
116
166
|
|
|
@@ -105,13 +105,63 @@ var MeadowProvider = function ()
|
|
|
105
105
|
return pParams;
|
|
106
106
|
};
|
|
107
107
|
|
|
108
|
-
// The Meadow marshaller
|
|
109
|
-
var marshalRecordFromSourceToObject = function (pObject, pRecord)
|
|
108
|
+
// The Meadow marshaller passes in the Schema as the third parameter for JSON/JSONProxy deserialization.
|
|
109
|
+
var marshalRecordFromSourceToObject = function (pObject, pRecord, pSchema)
|
|
110
110
|
{
|
|
111
|
-
//
|
|
111
|
+
// Build lookups for JSON columns (only if schema is provided)
|
|
112
|
+
var tmpJsonColumns = {};
|
|
113
|
+
var tmpProxyColumns = {};
|
|
114
|
+
if (Array.isArray(pSchema))
|
|
115
|
+
{
|
|
116
|
+
for (var s = 0; s < pSchema.length; s++)
|
|
117
|
+
{
|
|
118
|
+
if (pSchema[s].Type === 'JSON')
|
|
119
|
+
{
|
|
120
|
+
tmpJsonColumns[pSchema[s].Column] = true;
|
|
121
|
+
}
|
|
122
|
+
else if (pSchema[s].Type === 'JSONProxy' && pSchema[s].StorageColumn)
|
|
123
|
+
{
|
|
124
|
+
tmpProxyColumns[pSchema[s].StorageColumn] = pSchema[s].Column;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
112
129
|
for (var tmpColumn in pRecord)
|
|
113
130
|
{
|
|
114
|
-
|
|
131
|
+
if (tmpJsonColumns[tmpColumn])
|
|
132
|
+
{
|
|
133
|
+
// JSON type: parse string from DB into object on the same column name
|
|
134
|
+
try
|
|
135
|
+
{
|
|
136
|
+
pObject[tmpColumn] = (typeof pRecord[tmpColumn] === 'string')
|
|
137
|
+
? JSON.parse(pRecord[tmpColumn])
|
|
138
|
+
: (pRecord[tmpColumn] || {});
|
|
139
|
+
}
|
|
140
|
+
catch (pParseError)
|
|
141
|
+
{
|
|
142
|
+
pObject[tmpColumn] = {};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else if (tmpProxyColumns.hasOwnProperty(tmpColumn))
|
|
146
|
+
{
|
|
147
|
+
// JSONProxy: storage column -> parse and assign to virtual column name
|
|
148
|
+
var tmpVirtualColumn = tmpProxyColumns[tmpColumn];
|
|
149
|
+
try
|
|
150
|
+
{
|
|
151
|
+
pObject[tmpVirtualColumn] = (typeof pRecord[tmpColumn] === 'string')
|
|
152
|
+
? JSON.parse(pRecord[tmpColumn])
|
|
153
|
+
: (pRecord[tmpColumn] || {});
|
|
154
|
+
}
|
|
155
|
+
catch (pParseError)
|
|
156
|
+
{
|
|
157
|
+
pObject[tmpVirtualColumn] = {};
|
|
158
|
+
}
|
|
159
|
+
// Do NOT copy the storage column to the output object
|
|
160
|
+
}
|
|
161
|
+
else
|
|
162
|
+
{
|
|
163
|
+
pObject[tmpColumn] = pRecord[tmpColumn];
|
|
164
|
+
}
|
|
115
165
|
}
|
|
116
166
|
};
|
|
117
167
|
|
package/test/Animal.json
CHANGED
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
{ "Column": "DeletingIDUser", "Type":"DeleteIDUser" },
|
|
15
15
|
{ "Column": "DeleteDate", "Type":"DeleteDate" },
|
|
16
16
|
{ "Column": "Name", "Type":"String" },
|
|
17
|
-
{ "Column": "Type", "Type":"String" }
|
|
17
|
+
{ "Column": "Type", "Type":"String" },
|
|
18
|
+
{ "Column": "Metadata", "Type":"JSON" },
|
|
19
|
+
{ "Column": "ExtraData", "Type":"JSONProxy", "StorageColumn":"ExtraDataJSON" }
|
|
18
20
|
],
|
|
19
21
|
|
|
20
22
|
"DefaultObject": {
|
|
@@ -30,7 +32,9 @@
|
|
|
30
32
|
"DeletingIDUser": 0,
|
|
31
33
|
|
|
32
34
|
"Name": "Unknown",
|
|
33
|
-
"Type": "Unclassified"
|
|
35
|
+
"Type": "Unclassified",
|
|
36
|
+
"Metadata": {},
|
|
37
|
+
"ExtraData": {}
|
|
34
38
|
},
|
|
35
39
|
|
|
36
40
|
"JsonSchema": {
|
|
@@ -49,6 +53,14 @@
|
|
|
49
53
|
"Type": {
|
|
50
54
|
"description": "The type of the animal",
|
|
51
55
|
"type": "string"
|
|
56
|
+
},
|
|
57
|
+
"Metadata": {
|
|
58
|
+
"description": "JSON metadata about the animal",
|
|
59
|
+
"type": "object"
|
|
60
|
+
},
|
|
61
|
+
"ExtraData": {
|
|
62
|
+
"description": "Extra JSON data (proxied storage)",
|
|
63
|
+
"type": "object"
|
|
52
64
|
}
|
|
53
65
|
},
|
|
54
66
|
"required": ["IDAnimal", "Name", "CreatingIDUser"]
|
|
@@ -64,7 +64,9 @@ var _AnimalSchema = (
|
|
|
64
64
|
{ Column: "DeletingIDUser", Type:"DeleteIDUser" },
|
|
65
65
|
{ Column: "DeleteDate", Type:"DeleteDate" },
|
|
66
66
|
{ "Column": "Name", "Type":"String" },
|
|
67
|
-
{ "Column": "Type", "Type":"String" }
|
|
67
|
+
{ "Column": "Type", "Type":"String" },
|
|
68
|
+
{ Column: "Metadata", Type:"JSON" },
|
|
69
|
+
{ Column: "ExtraData", Type:"JSONProxy", StorageColumn:"ExtraDataJSON" }
|
|
68
70
|
]);
|
|
69
71
|
var _AnimalDefault = (
|
|
70
72
|
{
|
|
@@ -80,7 +82,10 @@ var _AnimalDefault = (
|
|
|
80
82
|
DeletingIDUser: 0,
|
|
81
83
|
|
|
82
84
|
Name: 'Unknown',
|
|
83
|
-
Type: 'Unclassified'
|
|
85
|
+
Type: 'Unclassified',
|
|
86
|
+
|
|
87
|
+
Metadata: {},
|
|
88
|
+
ExtraData: {}
|
|
84
89
|
});
|
|
85
90
|
|
|
86
91
|
suite
|
|
@@ -80,7 +80,9 @@ var _AnimalSchema = (
|
|
|
80
80
|
{ Column: "DeleteDate", Type: "DeleteDate" },
|
|
81
81
|
{ Column: "Name", Type: "String" },
|
|
82
82
|
{ Column: "Type", Type: "String" },
|
|
83
|
-
{ Column: "Age", Type: "Integer" }
|
|
83
|
+
{ Column: "Age", Type: "Integer" },
|
|
84
|
+
{ Column: "Metadata", Type:"JSON" },
|
|
85
|
+
{ Column: "ExtraData", Type:"JSONProxy", StorageColumn:"ExtraDataJSON" }
|
|
84
86
|
]);
|
|
85
87
|
var _AnimalDefault = (
|
|
86
88
|
{
|
|
@@ -96,7 +98,10 @@ var _AnimalDefault = (
|
|
|
96
98
|
DeletingIDUser: 0,
|
|
97
99
|
|
|
98
100
|
Name: 'Unknown',
|
|
99
|
-
Type: 'Unclassified'
|
|
101
|
+
Type: 'Unclassified',
|
|
102
|
+
|
|
103
|
+
Metadata: {},
|
|
104
|
+
ExtraData: {}
|
|
100
105
|
});
|
|
101
106
|
|
|
102
107
|
suite
|
|
@@ -108,7 +113,7 @@ suite
|
|
|
108
113
|
|
|
109
114
|
var getAnimalInsert = function (pName, pType)
|
|
110
115
|
{
|
|
111
|
-
return "INSERT INTO FableTest (GUIDAnimal, CreateDate, CreatingIDUser, UpdateDate, UpdatingIDUser, Deleted, DeleteDate, DeletingIDUser, Name, Type) VALUES ('00000000-0000-0000-0000-000000000000', GETUTCDATE(), 1, GETUTCDATE(), 1, 0, NULL, 0, '" + pName + "', '" + pType + "'); ";
|
|
116
|
+
return "INSERT INTO FableTest (GUIDAnimal, CreateDate, CreatingIDUser, UpdateDate, UpdatingIDUser, Deleted, DeleteDate, DeletingIDUser, Name, Type, Metadata, ExtraDataJSON) VALUES ('00000000-0000-0000-0000-000000000000', GETUTCDATE(), 1, GETUTCDATE(), 1, 0, NULL, 0, '" + pName + "', '" + pType + "', '{}', '{}'); ";
|
|
112
117
|
};
|
|
113
118
|
|
|
114
119
|
var newMeadow = function ()
|
|
@@ -163,7 +168,7 @@ END
|
|
|
163
168
|
},
|
|
164
169
|
function (fStageComplete)
|
|
165
170
|
{
|
|
166
|
-
libFable.MeadowMSSQLProvider.pool.query("CREATE TABLE FableTest (IDAnimal INT IDENTITY(1,1) NOT NULL, GUIDAnimal VARCHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', CreateDate DATETIME, CreatingIDUser INT NOT NULL DEFAULT '0', UpdateDate DATETIME, UpdatingIDUser INT NOT NULL DEFAULT '0', Deleted TINYINT NOT NULL DEFAULT '0', DeleteDate DATETIME, DeletingIDUser INT NOT NULL DEFAULT '0', Name VARCHAR(128) NOT NULL DEFAULT '', Type VARCHAR(128) NOT NULL DEFAULT '' );").then(()=>{ return fStageComplete(); }).catch(fStageComplete);
|
|
171
|
+
libFable.MeadowMSSQLProvider.pool.query("CREATE TABLE FableTest (IDAnimal INT IDENTITY(1,1) NOT NULL, GUIDAnimal VARCHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', CreateDate DATETIME, CreatingIDUser INT NOT NULL DEFAULT '0', UpdateDate DATETIME, UpdatingIDUser INT NOT NULL DEFAULT '0', Deleted TINYINT NOT NULL DEFAULT '0', DeleteDate DATETIME, DeletingIDUser INT NOT NULL DEFAULT '0', Name VARCHAR(128) NOT NULL DEFAULT '', Type VARCHAR(128) NOT NULL DEFAULT '', Metadata TEXT, ExtraDataJSON TEXT );").then(()=>{ return fStageComplete(); }).catch(fStageComplete);
|
|
167
172
|
},
|
|
168
173
|
function (fStageComplete)
|
|
169
174
|
{
|
|
@@ -255,6 +260,37 @@ END
|
|
|
255
260
|
)
|
|
256
261
|
}
|
|
257
262
|
);
|
|
263
|
+
test
|
|
264
|
+
(
|
|
265
|
+
'Create a record with JSON data',
|
|
266
|
+
function(fDone)
|
|
267
|
+
{
|
|
268
|
+
var testMeadow = newMeadow().setIDUser(90210);
|
|
269
|
+
|
|
270
|
+
var tmpQuery = testMeadow.query.clone().setLogLevel(5)
|
|
271
|
+
.addRecord({Name:'Moose', Type:'Mammal', Metadata: { habitat: 'forest', weight: 500 }, ExtraData: { endangered: false, population: 'stable' }});
|
|
272
|
+
|
|
273
|
+
testMeadow.doCreate(tmpQuery,
|
|
274
|
+
function(pError, pQuery, pQueryRead, pRecord)
|
|
275
|
+
{
|
|
276
|
+
// We should have a record with JSON data ....
|
|
277
|
+
Expect(pRecord.Name)
|
|
278
|
+
.to.equal('Moose');
|
|
279
|
+
Expect(pRecord.Metadata)
|
|
280
|
+
.to.be.an('object');
|
|
281
|
+
Expect(pRecord.Metadata.habitat)
|
|
282
|
+
.to.equal('forest');
|
|
283
|
+
Expect(pRecord.ExtraData)
|
|
284
|
+
.to.be.an('object');
|
|
285
|
+
Expect(pRecord.ExtraData.endangered)
|
|
286
|
+
.to.equal(false);
|
|
287
|
+
// The storage column should not be exposed on the marshaled record
|
|
288
|
+
Expect(pRecord).to.not.have.property('ExtraDataJSON');
|
|
289
|
+
fDone();
|
|
290
|
+
}
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
);
|
|
258
294
|
test
|
|
259
295
|
(
|
|
260
296
|
'Create a record in the database with Deleted bit already set',
|
|
@@ -425,9 +461,9 @@ END
|
|
|
425
461
|
testMeadow.doCount(testMeadow.query,
|
|
426
462
|
function (pError, pQuery, pRecord)
|
|
427
463
|
{
|
|
428
|
-
// There should be
|
|
464
|
+
// There should be 6 records
|
|
429
465
|
Expect(pRecord)
|
|
430
|
-
.to.equal(
|
|
466
|
+
.to.equal(6);
|
|
431
467
|
Expect(pQuery.parameters.result.executed)
|
|
432
468
|
.to.equal(true);
|
|
433
469
|
testMeadow.fable.settings.QueryThresholdWarnTime = 1000;
|
|
@@ -640,9 +676,9 @@ END
|
|
|
640
676
|
testMeadow.doCount(testMeadow.query.setLogLevel(5),
|
|
641
677
|
function (pError, pQuery, pRecord)
|
|
642
678
|
{
|
|
643
|
-
// There should be
|
|
679
|
+
// There should be 8 records
|
|
644
680
|
Expect(pRecord)
|
|
645
|
-
.to.equal(
|
|
681
|
+
.to.equal(8);
|
|
646
682
|
fDone();
|
|
647
683
|
}
|
|
648
684
|
)
|
|
@@ -663,7 +699,7 @@ END
|
|
|
663
699
|
{
|
|
664
700
|
// We should have a record ....
|
|
665
701
|
Expect(pRecord.IDAnimal)
|
|
666
|
-
.to.equal(
|
|
702
|
+
.to.equal(11);
|
|
667
703
|
Expect(pRecord.Name)
|
|
668
704
|
.to.equal('MewThree');
|
|
669
705
|
fDone();
|
|
@@ -77,7 +77,9 @@ var _AnimalSchema = (
|
|
|
77
77
|
{ Column: "DeletingIDUser", Type: "DeleteIDUser" },
|
|
78
78
|
{ Column: "DeleteDate", Type: "DeleteDate" },
|
|
79
79
|
{ Column: "Name", Type: "String" },
|
|
80
|
-
{ Column: "Type", Type: "String" }
|
|
80
|
+
{ Column: "Type", Type: "String" },
|
|
81
|
+
{ Column: "Metadata", Type:"JSON" },
|
|
82
|
+
{ Column: "ExtraData", Type:"JSONProxy", StorageColumn:"ExtraDataJSON" }
|
|
81
83
|
]);
|
|
82
84
|
var _AnimalDefault = (
|
|
83
85
|
{
|
|
@@ -93,7 +95,10 @@ var _AnimalDefault = (
|
|
|
93
95
|
DeletingIDUser: 0,
|
|
94
96
|
|
|
95
97
|
Name: 'Unknown',
|
|
96
|
-
Type: 'Unclassified'
|
|
98
|
+
Type: 'Unclassified',
|
|
99
|
+
|
|
100
|
+
Metadata: {},
|
|
101
|
+
ExtraData: {}
|
|
97
102
|
});
|
|
98
103
|
|
|
99
104
|
suite
|
|
@@ -236,6 +241,35 @@ suite
|
|
|
236
241
|
)
|
|
237
242
|
}
|
|
238
243
|
);
|
|
244
|
+
test
|
|
245
|
+
(
|
|
246
|
+
'Create a record with JSON data',
|
|
247
|
+
function(fDone)
|
|
248
|
+
{
|
|
249
|
+
var testMeadow = newMeadow().setIDUser(90210);
|
|
250
|
+
|
|
251
|
+
var tmpQuery = testMeadow.query.clone().setLogLevel(5)
|
|
252
|
+
.addRecord({Name:'Moose', Type:'Mammal', Metadata: { habitat: 'forest', weight: 500 }, ExtraData: { endangered: false, population: 'stable' }});
|
|
253
|
+
|
|
254
|
+
testMeadow.doCreate(tmpQuery,
|
|
255
|
+
function(pError, pQuery, pQueryRead, pRecord)
|
|
256
|
+
{
|
|
257
|
+
// We should have a record with JSON data ....
|
|
258
|
+
Expect(pRecord.Name)
|
|
259
|
+
.to.equal('Moose');
|
|
260
|
+
Expect(pRecord.Metadata)
|
|
261
|
+
.to.be.an('object');
|
|
262
|
+
Expect(pRecord.Metadata.habitat)
|
|
263
|
+
.to.equal('forest');
|
|
264
|
+
Expect(pRecord.ExtraData)
|
|
265
|
+
.to.be.an('object');
|
|
266
|
+
Expect(pRecord.ExtraData.endangered)
|
|
267
|
+
.to.equal(false);
|
|
268
|
+
fDone();
|
|
269
|
+
}
|
|
270
|
+
)
|
|
271
|
+
}
|
|
272
|
+
);
|
|
239
273
|
test
|
|
240
274
|
(
|
|
241
275
|
'Read a record from the database',
|
|
@@ -361,9 +395,9 @@ suite
|
|
|
361
395
|
testMeadow.doCount(testMeadow.query,
|
|
362
396
|
function (pError, pQuery, pRecord)
|
|
363
397
|
{
|
|
364
|
-
// There should be
|
|
398
|
+
// There should be 6 records (5 seeded + 1 created + 1 Moose - 1 deleted = 6 non-deleted)
|
|
365
399
|
Expect(pRecord)
|
|
366
|
-
.to.equal(
|
|
400
|
+
.to.equal(6);
|
|
367
401
|
Expect(pQuery.parameters.result.executed)
|
|
368
402
|
.to.equal(true);
|
|
369
403
|
fDone();
|
|
@@ -506,7 +540,7 @@ suite
|
|
|
506
540
|
{
|
|
507
541
|
// MongoDB auto-filters Deleted=0, so count is non-deleted records only
|
|
508
542
|
Expect(pRecord)
|
|
509
|
-
.to.equal(
|
|
543
|
+
.to.equal(6);
|
|
510
544
|
fDone();
|
|
511
545
|
}
|
|
512
546
|
)
|
|
@@ -89,7 +89,9 @@ var _AnimalSchema = (
|
|
|
89
89
|
{ Column: "UpdatingIDUser", Type:"UpdateIDUser" },
|
|
90
90
|
{ Column: "Deleted", Type:"Deleted" },
|
|
91
91
|
{ Column: "DeletingIDUser", Type:"DeleteIDUser" },
|
|
92
|
-
{ Column: "DeleteDate", Type:"DeleteDate" }
|
|
92
|
+
{ Column: "DeleteDate", Type:"DeleteDate" },
|
|
93
|
+
{ Column: "Metadata", Type:"JSON" },
|
|
94
|
+
{ Column: "ExtraData", Type:"JSONProxy", StorageColumn:"ExtraDataJSON" }
|
|
93
95
|
]);
|
|
94
96
|
var _AnimalDefault = (
|
|
95
97
|
{
|
|
@@ -105,7 +107,10 @@ var _AnimalDefault = (
|
|
|
105
107
|
DeletingIDUser: 0,
|
|
106
108
|
|
|
107
109
|
Name: 'Unknown',
|
|
108
|
-
Type: 'Unclassified'
|
|
110
|
+
Type: 'Unclassified',
|
|
111
|
+
|
|
112
|
+
Metadata: {},
|
|
113
|
+
ExtraData: {}
|
|
109
114
|
});
|
|
110
115
|
|
|
111
116
|
suite
|
|
@@ -117,7 +122,7 @@ suite
|
|
|
117
122
|
|
|
118
123
|
var getAnimalInsert = function(pName, pType)
|
|
119
124
|
{
|
|
120
|
-
return "INSERT INTO `FableTest` (`IDAnimal`, `GUIDAnimal`, `CreateDate`, `CreatingIDUser`, `UpdateDate`, `UpdatingIDUser`, `Deleted`, `DeleteDate`, `DeletingIDUser`, `Name`, `Type`) VALUES (NULL, '00000000-0000-0000-0000-000000000000', NOW(), 1, NOW(), 1, 0, NULL, 0, '"+pName+"', '"+pType+"'); ";
|
|
125
|
+
return "INSERT INTO `FableTest` (`IDAnimal`, `GUIDAnimal`, `CreateDate`, `CreatingIDUser`, `UpdateDate`, `UpdatingIDUser`, `Deleted`, `DeleteDate`, `DeletingIDUser`, `Name`, `Type`, `Metadata`, `ExtraDataJSON`) VALUES (NULL, '00000000-0000-0000-0000-000000000000', NOW(), 1, NOW(), 1, 0, NULL, 0, '"+pName+"', '"+pType+"', '{}', '{}'); ";
|
|
121
126
|
};
|
|
122
127
|
|
|
123
128
|
var newMeadow = function()
|
|
@@ -160,7 +165,7 @@ suite
|
|
|
160
165
|
},
|
|
161
166
|
function(fCallBack)
|
|
162
167
|
{
|
|
163
|
-
_SQLConnectionPool.query("CREATE TABLE IF NOT EXISTS FableTest (IDAnimal INT UNSIGNED NOT NULL AUTO_INCREMENT, GUIDAnimal CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', CreateDate DATETIME, CreatingIDUser INT NOT NULL DEFAULT '0', UpdateDate DATETIME, UpdatingIDUser INT NOT NULL DEFAULT '0', Deleted TINYINT NOT NULL DEFAULT '0', DeleteDate DATETIME, DeletingIDUser INT NOT NULL DEFAULT '0', Name CHAR(128) NOT NULL DEFAULT '', Type CHAR(128) NOT NULL DEFAULT '', PRIMARY KEY (IDAnimal) );",
|
|
168
|
+
_SQLConnectionPool.query("CREATE TABLE IF NOT EXISTS FableTest (IDAnimal INT UNSIGNED NOT NULL AUTO_INCREMENT, GUIDAnimal CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', CreateDate DATETIME, CreatingIDUser INT NOT NULL DEFAULT '0', UpdateDate DATETIME, UpdatingIDUser INT NOT NULL DEFAULT '0', Deleted TINYINT NOT NULL DEFAULT '0', DeleteDate DATETIME, DeletingIDUser INT NOT NULL DEFAULT '0', Name CHAR(128) NOT NULL DEFAULT '', Type CHAR(128) NOT NULL DEFAULT '', Metadata LONGTEXT, ExtraDataJSON LONGTEXT, PRIMARY KEY (IDAnimal) );",
|
|
164
169
|
function(pErrorUpdate, pResponse) { fCallBack(null); });
|
|
165
170
|
},
|
|
166
171
|
function(fCallBack)
|
|
@@ -258,6 +263,37 @@ suite
|
|
|
258
263
|
}
|
|
259
264
|
);
|
|
260
265
|
test
|
|
266
|
+
(
|
|
267
|
+
'Create a record with JSON data',
|
|
268
|
+
function(fDone)
|
|
269
|
+
{
|
|
270
|
+
var testMeadow = newMeadow().setIDUser(90210);
|
|
271
|
+
|
|
272
|
+
var tmpQuery = testMeadow.query.clone().setLogLevel(5)
|
|
273
|
+
.addRecord({Name:'Moose', Type:'Mammal', Metadata: { habitat: 'forest', weight: 500 }, ExtraData: { endangered: false, population: 'stable' }});
|
|
274
|
+
|
|
275
|
+
testMeadow.doCreate(tmpQuery,
|
|
276
|
+
function(pError, pQuery, pQueryRead, pRecord)
|
|
277
|
+
{
|
|
278
|
+
// We should have a record with JSON data ....
|
|
279
|
+
Expect(pRecord.Name)
|
|
280
|
+
.to.equal('Moose');
|
|
281
|
+
Expect(pRecord.Metadata)
|
|
282
|
+
.to.be.an('object');
|
|
283
|
+
Expect(pRecord.Metadata.habitat)
|
|
284
|
+
.to.equal('forest');
|
|
285
|
+
Expect(pRecord.ExtraData)
|
|
286
|
+
.to.be.an('object');
|
|
287
|
+
Expect(pRecord.ExtraData.endangered)
|
|
288
|
+
.to.equal(false);
|
|
289
|
+
// The storage column should not be exposed on the marshaled record
|
|
290
|
+
Expect(pRecord).to.not.have.property('ExtraDataJSON');
|
|
291
|
+
fDone();
|
|
292
|
+
}
|
|
293
|
+
)
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
test
|
|
261
297
|
(
|
|
262
298
|
'New provider format',
|
|
263
299
|
function(fDone)
|
|
@@ -476,9 +512,9 @@ suite
|
|
|
476
512
|
testMeadow.doCount(testMeadow.query,
|
|
477
513
|
function(pError, pQuery, pRecord)
|
|
478
514
|
{
|
|
479
|
-
// There should be
|
|
515
|
+
// There should be 6 records
|
|
480
516
|
Expect(pRecord)
|
|
481
|
-
.to.equal(
|
|
517
|
+
.to.equal(6);
|
|
482
518
|
Expect(pQuery.parameters.result.executed)
|
|
483
519
|
.to.equal(true);
|
|
484
520
|
testMeadow.fable.settings.QueryThresholdWarnTime = 1000;
|
|
@@ -691,9 +727,9 @@ suite
|
|
|
691
727
|
testMeadow.doCount(testMeadow.query.setLogLevel(5),
|
|
692
728
|
function(pError, pQuery, pRecord)
|
|
693
729
|
{
|
|
694
|
-
// There should be
|
|
730
|
+
// There should be 8 records
|
|
695
731
|
Expect(pRecord)
|
|
696
|
-
.to.equal(
|
|
732
|
+
.to.equal(8);
|
|
697
733
|
fDone();
|
|
698
734
|
}
|
|
699
735
|
)
|
|
@@ -714,7 +750,7 @@ suite
|
|
|
714
750
|
{
|
|
715
751
|
// We should have a record ....
|
|
716
752
|
Expect(pRecord.IDAnimal)
|
|
717
|
-
.to.equal(
|
|
753
|
+
.to.equal(11);
|
|
718
754
|
Expect(pRecord.Name)
|
|
719
755
|
.to.equal('MewThree');
|
|
720
756
|
fDone();
|
|
@@ -79,7 +79,9 @@ var _AnimalSchema = (
|
|
|
79
79
|
{ Column: "DeletingIDUser", Type: "DeleteIDUser" },
|
|
80
80
|
{ Column: "DeleteDate", Type: "DeleteDate" },
|
|
81
81
|
{ Column: "Name", Type: "String" },
|
|
82
|
-
{ Column: "Type", Type: "String" }
|
|
82
|
+
{ Column: "Type", Type: "String" },
|
|
83
|
+
{ Column: "Metadata", Type:"JSON" },
|
|
84
|
+
{ Column: "ExtraData", Type:"JSONProxy", StorageColumn:"ExtraDataJSON" }
|
|
83
85
|
]);
|
|
84
86
|
var _AnimalDefault = (
|
|
85
87
|
{
|
|
@@ -95,7 +97,10 @@ var _AnimalDefault = (
|
|
|
95
97
|
DeletingIDUser: 0,
|
|
96
98
|
|
|
97
99
|
Name: 'Unknown',
|
|
98
|
-
Type: 'Unclassified'
|
|
100
|
+
Type: 'Unclassified',
|
|
101
|
+
|
|
102
|
+
Metadata: {},
|
|
103
|
+
ExtraData: {}
|
|
99
104
|
});
|
|
100
105
|
|
|
101
106
|
suite
|
|
@@ -107,7 +112,7 @@ suite
|
|
|
107
112
|
|
|
108
113
|
var getAnimalInsert = function (pName, pType)
|
|
109
114
|
{
|
|
110
|
-
return 'INSERT INTO "FableTest" ("GUIDAnimal", "CreateDate", "CreatingIDUser", "UpdateDate", "UpdatingIDUser", "Deleted", "DeleteDate", "DeletingIDUser", "Name", "Type") VALUES (\'00000000-0000-0000-0000-000000000000\', NOW(), 1, NOW(), 1, 0, NULL, 0, \'' + pName + '\', \'' + pType + '\'); ';
|
|
115
|
+
return 'INSERT INTO "FableTest" ("GUIDAnimal", "CreateDate", "CreatingIDUser", "UpdateDate", "UpdatingIDUser", "Deleted", "DeleteDate", "DeletingIDUser", "Name", "Type", "Metadata", "ExtraDataJSON") VALUES (\'00000000-0000-0000-0000-000000000000\', NOW(), 1, NOW(), 1, 0, NULL, 0, \'' + pName + '\', \'' + pType + '\', \'{}\', \'{}\'); ';
|
|
111
116
|
};
|
|
112
117
|
|
|
113
118
|
var newMeadow = function ()
|
|
@@ -153,7 +158,7 @@ suite
|
|
|
153
158
|
},
|
|
154
159
|
function (fStageComplete)
|
|
155
160
|
{
|
|
156
|
-
libFable.MeadowPostgreSQLProvider.pool.query('CREATE TABLE IF NOT EXISTS "FableTest" ("IDAnimal" SERIAL PRIMARY KEY, "GUIDAnimal" VARCHAR(36) NOT NULL DEFAULT \'00000000-0000-0000-0000-000000000000\', "CreateDate" TIMESTAMP, "CreatingIDUser" INT NOT NULL DEFAULT 0, "UpdateDate" TIMESTAMP, "UpdatingIDUser" INT NOT NULL DEFAULT 0, "Deleted" SMALLINT NOT NULL DEFAULT 0, "DeleteDate" TIMESTAMP, "DeletingIDUser" INT NOT NULL DEFAULT 0, "Name" VARCHAR(128) NOT NULL DEFAULT \'\', "Type" VARCHAR(128) NOT NULL DEFAULT \'\');').then(() => { return fStageComplete(); }).catch(fStageComplete);
|
|
161
|
+
libFable.MeadowPostgreSQLProvider.pool.query('CREATE TABLE IF NOT EXISTS "FableTest" ("IDAnimal" SERIAL PRIMARY KEY, "GUIDAnimal" VARCHAR(36) NOT NULL DEFAULT \'00000000-0000-0000-0000-000000000000\', "CreateDate" TIMESTAMP, "CreatingIDUser" INT NOT NULL DEFAULT 0, "UpdateDate" TIMESTAMP, "UpdatingIDUser" INT NOT NULL DEFAULT 0, "Deleted" SMALLINT NOT NULL DEFAULT 0, "DeleteDate" TIMESTAMP, "DeletingIDUser" INT NOT NULL DEFAULT 0, "Name" VARCHAR(128) NOT NULL DEFAULT \'\', "Type" VARCHAR(128) NOT NULL DEFAULT \'\', "Metadata" TEXT, "ExtraDataJSON" TEXT);').then(() => { return fStageComplete(); }).catch(fStageComplete);
|
|
157
162
|
},
|
|
158
163
|
function (fStageComplete)
|
|
159
164
|
{
|
|
@@ -247,6 +252,37 @@ suite
|
|
|
247
252
|
)
|
|
248
253
|
}
|
|
249
254
|
);
|
|
255
|
+
test
|
|
256
|
+
(
|
|
257
|
+
'Create a record with JSON data',
|
|
258
|
+
function (fDone)
|
|
259
|
+
{
|
|
260
|
+
var testMeadow = newMeadow().setIDUser(90210);
|
|
261
|
+
|
|
262
|
+
var tmpQuery = testMeadow.query.clone().setLogLevel(5)
|
|
263
|
+
.addRecord({ Name: 'Moose', Type: 'Mammal', Metadata: { habitat: 'forest', weight: 500 }, ExtraData: { endangered: false, population: 'stable' } });
|
|
264
|
+
|
|
265
|
+
testMeadow.doCreate(tmpQuery,
|
|
266
|
+
function (pError, pQuery, pQueryRead, pRecord)
|
|
267
|
+
{
|
|
268
|
+
// We should have a record with JSON data ....
|
|
269
|
+
Expect(pRecord.Name)
|
|
270
|
+
.to.equal('Moose');
|
|
271
|
+
Expect(pRecord.Metadata)
|
|
272
|
+
.to.be.an('object');
|
|
273
|
+
Expect(pRecord.Metadata.habitat)
|
|
274
|
+
.to.equal('forest');
|
|
275
|
+
Expect(pRecord.ExtraData)
|
|
276
|
+
.to.be.an('object');
|
|
277
|
+
Expect(pRecord.ExtraData.endangered)
|
|
278
|
+
.to.equal(false);
|
|
279
|
+
// The storage column should not be exposed on the marshaled record
|
|
280
|
+
Expect(pRecord).to.not.have.property('ExtraDataJSON');
|
|
281
|
+
fDone();
|
|
282
|
+
}
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
);
|
|
250
286
|
test
|
|
251
287
|
(
|
|
252
288
|
'Read a record from the database',
|
|
@@ -374,9 +410,9 @@ suite
|
|
|
374
410
|
testMeadow.doCount(testMeadow.query,
|
|
375
411
|
function (pError, pQuery, pRecord)
|
|
376
412
|
{
|
|
377
|
-
// There should be
|
|
413
|
+
// There should be 6 records
|
|
378
414
|
Expect(pRecord)
|
|
379
|
-
.to.equal(
|
|
415
|
+
.to.equal(6);
|
|
380
416
|
Expect(pQuery.parameters.result.executed)
|
|
381
417
|
.to.equal(true);
|
|
382
418
|
fDone();
|
|
@@ -588,9 +624,9 @@ suite
|
|
|
588
624
|
testMeadow.doCount(testMeadow.query.setLogLevel(5),
|
|
589
625
|
function (pError, pQuery, pRecord)
|
|
590
626
|
{
|
|
591
|
-
// There should be
|
|
627
|
+
// There should be 8 records
|
|
592
628
|
Expect(pRecord)
|
|
593
|
-
.to.equal(
|
|
629
|
+
.to.equal(8);
|
|
594
630
|
fDone();
|
|
595
631
|
}
|
|
596
632
|
)
|