foxhound 2.0.23 → 2.0.24
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 +2 -0
- package/docs/_sidebar.md +1 -0
- package/docs/filters.md +28 -0
- package/docs/json-columns.md +145 -0
- package/docs/schema.md +53 -0
- package/package.json +2 -2
- package/source/dialects/ALASQL/FoxHound-Dialect-ALASQL.js +63 -0
- package/source/dialects/MicrosoftSQL/FoxHound-Dialect-MSSQL.js +73 -2
- package/source/dialects/MySQL/FoxHound-Dialect-MySQL.js +78 -2
- package/source/dialects/PostgreSQL/FoxHound-Dialect-PostgreSQL.js +81 -1
- package/source/dialects/SQLite/FoxHound-Dialect-SQLite.js +73 -2
package/README.md
CHANGED
|
@@ -89,6 +89,8 @@ When a schema is attached, FoxHound automatically manages special columns:
|
|
|
89
89
|
| `UpdateDate` / `UpdateIDUser` | Auto-populated on insert and update |
|
|
90
90
|
| `DeleteDate` / `DeleteIDUser` | Auto-populated on soft delete |
|
|
91
91
|
| `Deleted` | Soft-delete flag — auto-filtered in reads |
|
|
92
|
+
| `JSON` | Structured JSON data — serialized to `TEXT` on write, parsed on read |
|
|
93
|
+
| `JSONProxy` | JSON stored in a different SQL column — uses `StorageColumn` for SQL, virtual name for objects |
|
|
92
94
|
|
|
93
95
|
## Filter Operators
|
|
94
96
|
|
package/docs/_sidebar.md
CHANGED
package/docs/filters.md
CHANGED
|
@@ -166,6 +166,34 @@ The operator codes are:
|
|
|
166
166
|
| `LE` | `<=` |
|
|
167
167
|
| `LK` | `LIKE` |
|
|
168
168
|
|
|
169
|
+
## JSON Path Filtering
|
|
170
|
+
|
|
171
|
+
When a schema is attached and contains `JSON` or `JSONProxy` columns, you can filter on nested JSON properties using dot notation:
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
// Filter where Metadata.habitat equals 'forest'
|
|
175
|
+
tmpQuery.addFilter('Metadata.habitat', 'forest');
|
|
176
|
+
|
|
177
|
+
// Filter where Metadata.weight is greater than 100
|
|
178
|
+
tmpQuery.addFilter('Metadata.weight', 100, '>');
|
|
179
|
+
|
|
180
|
+
// Nested paths work too
|
|
181
|
+
tmpQuery.addFilter('Metadata.dimensions.height', 50, '>=');
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
FoxHound detects the dot notation, resolves the base column against the schema, and generates the appropriate JSON path expression for the active dialect:
|
|
185
|
+
|
|
186
|
+
| Dialect | Single-Level | Nested |
|
|
187
|
+
|---------|-------------|--------|
|
|
188
|
+
| MySQL | `JSON_EXTRACT(col, '$.key')` | `JSON_EXTRACT(col, '$.key1.key2')` |
|
|
189
|
+
| PostgreSQL | `col->>'key'` | `col#>>'{key1,key2}'` |
|
|
190
|
+
| SQLite | `json_extract(col, '$.key')` | `json_extract(col, '$.key1.key2')` |
|
|
191
|
+
| MSSQL | `JSON_VALUE(col, '$.key')` | `JSON_VALUE(col, '$.key1.key2')` |
|
|
192
|
+
|
|
193
|
+
For `JSONProxy` columns, the storage column name is used in the SQL expression automatically. For example, if `Preferences` is a `JSONProxy` with `StorageColumn: 'PreferencesJSON'`, filtering on `Preferences.theme` produces `json_extract(PreferencesJSON, '$.theme')` in SQLite.
|
|
194
|
+
|
|
195
|
+
All standard comparison operators (`=`, `!=`, `>`, `>=`, `<`, `<=`, `LIKE`) work with JSON path filters.
|
|
196
|
+
|
|
169
197
|
## Soft-Delete Auto-Filter
|
|
170
198
|
|
|
171
199
|
When a schema with a `Deleted` column type is present and delete tracking is not disabled, FoxHound automatically appends a `WHERE Deleted = 0` filter to all Read and Count queries. If you explicitly add a filter on the `Deleted` column, the automatic filter is suppressed.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# JSON Column Support
|
|
2
|
+
|
|
3
|
+
> Automatic serialization and JSON path filtering for structured data columns
|
|
4
|
+
|
|
5
|
+
FoxHound provides schema-aware handling of JSON data types. When a schema with `JSON` or `JSONProxy` columns is attached, FoxHound automatically serializes object values on write and generates dialect-specific JSON path expressions for filtering.
|
|
6
|
+
|
|
7
|
+
## Schema Types
|
|
8
|
+
|
|
9
|
+
### JSON
|
|
10
|
+
|
|
11
|
+
The SQL column and JavaScript property share the same name.
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
{ Column: 'Metadata', Type: 'JSON' }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### JSONProxy
|
|
18
|
+
|
|
19
|
+
The SQL column differs from the JavaScript property. The `StorageColumn` specifies the actual SQL column.
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
{ Column: 'Preferences', Type: 'JSONProxy', StorageColumn: 'PreferencesJSON' }
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Write Operations (Create / Update)
|
|
26
|
+
|
|
27
|
+
On CREATE and UPDATE, FoxHound automatically calls `JSON.stringify` on JSON column values:
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
tmpQuery.query.schema = [
|
|
31
|
+
{ Column: 'IDProduct', Type: 'AutoIdentity' },
|
|
32
|
+
{ Column: 'Name', Type: 'String' },
|
|
33
|
+
{ Column: 'Metadata', Type: 'JSON' },
|
|
34
|
+
{ Column: 'Preferences', Type: 'JSONProxy', StorageColumn: 'PreferencesJSON' }
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
tmpQuery.addRecord({
|
|
38
|
+
Name: 'Widget',
|
|
39
|
+
Metadata: { color: 'blue' },
|
|
40
|
+
Preferences: { theme: 'dark' }
|
|
41
|
+
});
|
|
42
|
+
tmpQuery.setDialect('MySQL').buildCreateQuery();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Generated SQL:
|
|
46
|
+
|
|
47
|
+
```sql
|
|
48
|
+
INSERT INTO Product (Name, Metadata, PreferencesJSON)
|
|
49
|
+
VALUES (:Name_0, :Metadata_1, :Preferences_2);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Parameters:
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
{
|
|
56
|
+
Name_0: 'Widget',
|
|
57
|
+
Metadata_1: '{"color":"blue"}', // JSON.stringify'd
|
|
58
|
+
Preferences_2: '{"theme":"dark"}' // JSON.stringify'd, stored in PreferencesJSON
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Key behaviors:
|
|
63
|
+
- **JSON**: Column name in SQL matches the property name. Value is serialized.
|
|
64
|
+
- **JSONProxy**: `StorageColumn` is used as the SQL column name. Value is serialized from the virtual property.
|
|
65
|
+
- If a value is already a string, it is passed through without double-serialization.
|
|
66
|
+
|
|
67
|
+
## JSON Path Filtering
|
|
68
|
+
|
|
69
|
+
FoxHound supports filtering on nested JSON properties using dot notation in column names. When a filter column contains a dot and the base name matches a JSON or JSONProxy schema entry, FoxHound generates a JSON path expression.
|
|
70
|
+
|
|
71
|
+
### Usage
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
tmpQuery
|
|
75
|
+
.addFilter('Metadata.color', 'blue')
|
|
76
|
+
.addFilter('Metadata.weight', 100, '>')
|
|
77
|
+
.addFilter('Metadata.dimensions.height', 50, '>=');
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Dialect Output
|
|
81
|
+
|
|
82
|
+
#### MySQL
|
|
83
|
+
|
|
84
|
+
```sql
|
|
85
|
+
WHERE JSON_EXTRACT(`Metadata`, '$.color') = :Metadata_color_w0
|
|
86
|
+
AND JSON_EXTRACT(`Metadata`, '$.weight') > :Metadata_weight_w1
|
|
87
|
+
AND JSON_EXTRACT(`Metadata`, '$.dimensions.height') >= :Metadata_dimensions_height_w2
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### PostgreSQL
|
|
91
|
+
|
|
92
|
+
Single-level paths use the `->>` operator; nested paths use `#>>`:
|
|
93
|
+
|
|
94
|
+
```sql
|
|
95
|
+
WHERE "Metadata"->>'color' = :Metadata_color_w0
|
|
96
|
+
AND "Metadata"->>'weight' > :Metadata_weight_w1
|
|
97
|
+
AND "Metadata"#>>'{dimensions,height}' >= :Metadata_dimensions_height_w2
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### SQLite
|
|
101
|
+
|
|
102
|
+
```sql
|
|
103
|
+
WHERE json_extract(`Metadata`, '$.color') = :Metadata_color_w0
|
|
104
|
+
AND json_extract(`Metadata`, '$.weight') > :Metadata_weight_w1
|
|
105
|
+
AND json_extract(`Metadata`, '$.dimensions.height') >= :Metadata_dimensions_height_w2
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### MSSQL
|
|
109
|
+
|
|
110
|
+
```sql
|
|
111
|
+
WHERE JSON_VALUE([Metadata], '$.color') = @Metadata_color_w0
|
|
112
|
+
AND JSON_VALUE([Metadata], '$.weight') > @Metadata_weight_w1
|
|
113
|
+
AND JSON_VALUE([Metadata], '$.dimensions.height') >= @Metadata_dimensions_height_w2
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### JSONProxy Resolution
|
|
117
|
+
|
|
118
|
+
For `JSONProxy` columns, the storage column name is automatically used in the generated SQL. Filtering on `Preferences.theme` when `Preferences` has `StorageColumn: 'PreferencesJSON'`:
|
|
119
|
+
|
|
120
|
+
```sql
|
|
121
|
+
-- MySQL
|
|
122
|
+
WHERE JSON_EXTRACT(`PreferencesJSON`, '$.theme') = :Preferences_theme_w0
|
|
123
|
+
|
|
124
|
+
-- PostgreSQL
|
|
125
|
+
WHERE "PreferencesJSON"->>'theme' = :Preferences_theme_w0
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Supported Operators
|
|
129
|
+
|
|
130
|
+
All standard filter operators work with JSON path expressions: `=`, `!=`, `>`, `>=`, `<`, `<=`, `LIKE`.
|
|
131
|
+
|
|
132
|
+
### ALASQL Limitation
|
|
133
|
+
|
|
134
|
+
ALASQL does not support JSON path functions. JSON columns work for basic CRUD (values are serialized/deserialized), but JSON path filtering is not available.
|
|
135
|
+
|
|
136
|
+
## Database Requirements
|
|
137
|
+
|
|
138
|
+
JSON path filtering requires these minimum database versions:
|
|
139
|
+
|
|
140
|
+
| Database | Minimum Version | Function Used |
|
|
141
|
+
|----------|----------------|---------------|
|
|
142
|
+
| MySQL | 5.7 | `JSON_EXTRACT` |
|
|
143
|
+
| PostgreSQL | 9.3 | `->>` / `#>>` |
|
|
144
|
+
| SQLite | 3.38 | `json_extract` |
|
|
145
|
+
| SQL Server | 2016 | `JSON_VALUE` |
|
package/docs/schema.md
CHANGED
|
@@ -13,6 +13,8 @@ tmpQuery.query.schema = [
|
|
|
13
13
|
{Column: 'Title', Type: 'String'},
|
|
14
14
|
{Column: 'Author', Type: 'String'},
|
|
15
15
|
{Column: 'PublishedYear', Type: 'Integer'},
|
|
16
|
+
{Column: 'Metadata', Type: 'JSON'},
|
|
17
|
+
{Column: 'Extras', Type: 'JSONProxy', StorageColumn: 'ExtrasJSON'},
|
|
16
18
|
{Column: 'CreateDate', Type: 'CreateDate'},
|
|
17
19
|
{Column: 'CreatingIDUser', Type: 'CreateIDUser'},
|
|
18
20
|
{Column: 'UpdateDate', Type: 'UpdateDate'},
|
|
@@ -41,6 +43,57 @@ tmpQuery.query.schema = [
|
|
|
41
43
|
| `Decimal` | Decimal data | parameterized | included | parameterized | — | — |
|
|
42
44
|
| `Boolean` | Boolean data | parameterized | included | parameterized | — | — |
|
|
43
45
|
| `DateTime` | Date/time data | parameterized | included | parameterized | — | — |
|
|
46
|
+
| `JSON` | Structured JSON data | `JSON.stringify` | included | `JSON.stringify` | — | — |
|
|
47
|
+
| `JSONProxy` | JSON with different SQL column name | `JSON.stringify` to `StorageColumn` | included | `JSON.stringify` to `StorageColumn` | — | — |
|
|
48
|
+
|
|
49
|
+
## JSON and JSON Proxy Types
|
|
50
|
+
|
|
51
|
+
FoxHound supports two schema types for structured JSON data stored as `TEXT` in SQL databases.
|
|
52
|
+
|
|
53
|
+
### JSON
|
|
54
|
+
|
|
55
|
+
The `JSON` type marks a column whose value should be serialized with `JSON.stringify` on write and deserialized with `JSON.parse` on read. The SQL column name matches the object property name.
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
{ Column: 'Metadata', Type: 'JSON' }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
On CREATE and UPDATE, FoxHound automatically calls `JSON.stringify` on the value. If the value is already a string, it is passed through as-is.
|
|
62
|
+
|
|
63
|
+
### JSON Proxy
|
|
64
|
+
|
|
65
|
+
The `JSONProxy` type stores JSON in a SQL column with a different name than the JavaScript property. The `StorageColumn` property specifies the actual SQL column name.
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
{ Column: 'Preferences', Type: 'JSONProxy', StorageColumn: 'PreferencesJSON' }
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
On CREATE and UPDATE, FoxHound:
|
|
72
|
+
- Uses `StorageColumn` (`PreferencesJSON`) as the column name in the SQL statement
|
|
73
|
+
- Calls `JSON.stringify` on the value from the `Column` property (`Preferences`)
|
|
74
|
+
|
|
75
|
+
On READ, the Meadow provider layer handles deserialization: the raw `PreferencesJSON` text column is parsed and mapped to the `Preferences` property, and the storage column is hidden from the result object.
|
|
76
|
+
|
|
77
|
+
### JSON Path Filtering
|
|
78
|
+
|
|
79
|
+
You can filter on nested JSON properties using dot notation in `addFilter`:
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
tmpQuery
|
|
83
|
+
.addFilter('Metadata.habitat', 'forest')
|
|
84
|
+
.addFilter('Metadata.weight', 100, '>');
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
FoxHound generates dialect-specific JSON path expressions:
|
|
88
|
+
|
|
89
|
+
| Dialect | Generated SQL |
|
|
90
|
+
|---------|---------------|
|
|
91
|
+
| MySQL | `JSON_EXTRACT(Metadata, '$.habitat') = :Metadata_habitat_w0` |
|
|
92
|
+
| PostgreSQL | `Metadata->>'habitat' = :Metadata_habitat_w0` |
|
|
93
|
+
| SQLite | `json_extract(Metadata, '$.habitat') = :Metadata_habitat_w0` |
|
|
94
|
+
| MSSQL | `JSON_VALUE(Metadata, '$.habitat') = :Metadata_habitat_w0` |
|
|
95
|
+
|
|
96
|
+
Nested paths are supported (e.g., `Metadata.dimensions.width`). JSON Proxy columns are automatically resolved to their storage column in the SQL expression.
|
|
44
97
|
|
|
45
98
|
## How Schema Affects Each Operation
|
|
46
99
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "foxhound",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.24",
|
|
4
4
|
"description": "A Database Query generation library.",
|
|
5
5
|
"main": "source/FoxHound.js",
|
|
6
6
|
"scripts": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
"homepage": "https://github.com/stevenvelozo/foxhound",
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"quackage": "^1.0.
|
|
51
|
+
"quackage": "^1.0.62"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"fable": "^3.1.63",
|
|
@@ -112,6 +112,27 @@ var FoxHoundDialectALASQL = function(pFable)
|
|
|
112
112
|
return tmpFieldList;
|
|
113
113
|
};
|
|
114
114
|
|
|
115
|
+
var resolveJsonColumnPath = function(pColumnName, pSchema)
|
|
116
|
+
{
|
|
117
|
+
if (!Array.isArray(pSchema) || pSchema.length < 1) return null;
|
|
118
|
+
var tmpParts = pColumnName.replace(/`/g, '').replace(/"/g, '').split('.');
|
|
119
|
+
for (var tmpStartIdx = 0; tmpStartIdx < Math.min(tmpParts.length - 1, 2); tmpStartIdx++)
|
|
120
|
+
{
|
|
121
|
+
var tmpBaseColumn = tmpParts[tmpStartIdx];
|
|
122
|
+
for (var s = 0; s < pSchema.length; s++)
|
|
123
|
+
{
|
|
124
|
+
if (pSchema[s].Column === tmpBaseColumn &&
|
|
125
|
+
(pSchema[s].Type === 'JSON' || pSchema[s].Type === 'JSONProxy'))
|
|
126
|
+
{
|
|
127
|
+
var tmpActualColumn = (pSchema[s].Type === 'JSONProxy') ? pSchema[s].StorageColumn : tmpBaseColumn;
|
|
128
|
+
var tmpJsonPath = '$.' + tmpParts.slice(tmpStartIdx + 1).join('.');
|
|
129
|
+
return { column: tmpActualColumn, path: tmpJsonPath };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
};
|
|
135
|
+
|
|
115
136
|
/**
|
|
116
137
|
* Generate a query from the array of where clauses
|
|
117
138
|
*
|
|
@@ -372,6 +393,20 @@ var FoxHoundDialectALASQL = function(pFable)
|
|
|
372
393
|
// Set the query parameter
|
|
373
394
|
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
374
395
|
break;
|
|
396
|
+
case 'JSON':
|
|
397
|
+
var tmpJSONUpdateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
398
|
+
tmpUpdate += ' '+tmpColumn+' = :'+tmpJSONUpdateParam;
|
|
399
|
+
pParameters.query.parameters[tmpJSONUpdateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
400
|
+
? tmpRecords[0][tmpColumn]
|
|
401
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
402
|
+
break;
|
|
403
|
+
case 'JSONProxy':
|
|
404
|
+
var tmpProxyUpdateParam = tmpSchemaEntry.StorageColumn+'_'+tmpCurrentColumn;
|
|
405
|
+
tmpUpdate += ' '+tmpSchemaEntry.StorageColumn+' = :'+tmpProxyUpdateParam;
|
|
406
|
+
pParameters.query.parameters[tmpProxyUpdateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
407
|
+
? tmpRecords[0][tmpColumn]
|
|
408
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
409
|
+
break;
|
|
375
410
|
default:
|
|
376
411
|
var tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;
|
|
377
412
|
tmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = :'+tmpColumnDefaultParameter;
|
|
@@ -667,6 +702,20 @@ var FoxHoundDialectALASQL = function(pFable)
|
|
|
667
702
|
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
668
703
|
}
|
|
669
704
|
break;
|
|
705
|
+
case 'JSON':
|
|
706
|
+
var tmpJSONCreateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
707
|
+
tmpCreateSet += ' :'+tmpJSONCreateParam;
|
|
708
|
+
pParameters.query.parameters[tmpJSONCreateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
709
|
+
? tmpRecords[0][tmpColumn]
|
|
710
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
711
|
+
break;
|
|
712
|
+
case 'JSONProxy':
|
|
713
|
+
var tmpProxyCreateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
714
|
+
tmpCreateSet += ' :'+tmpProxyCreateParam;
|
|
715
|
+
pParameters.query.parameters[tmpProxyCreateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
716
|
+
? tmpRecords[0][tmpColumn]
|
|
717
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
718
|
+
break;
|
|
670
719
|
default:
|
|
671
720
|
buildDefaultDefinition();
|
|
672
721
|
break;
|
|
@@ -727,6 +776,20 @@ var FoxHoundDialectALASQL = function(pFable)
|
|
|
727
776
|
}
|
|
728
777
|
switch (tmpSchemaEntry.Type)
|
|
729
778
|
{
|
|
779
|
+
case 'JSON':
|
|
780
|
+
if (tmpCreateSet != '')
|
|
781
|
+
{
|
|
782
|
+
tmpCreateSet += ',';
|
|
783
|
+
}
|
|
784
|
+
tmpCreateSet += ' '+tmpColumn;
|
|
785
|
+
break;
|
|
786
|
+
case 'JSONProxy':
|
|
787
|
+
if (tmpCreateSet != '')
|
|
788
|
+
{
|
|
789
|
+
tmpCreateSet += ',';
|
|
790
|
+
}
|
|
791
|
+
tmpCreateSet += ' '+tmpSchemaEntry.StorageColumn;
|
|
792
|
+
break;
|
|
730
793
|
default:
|
|
731
794
|
if (tmpCreateSet != '')
|
|
732
795
|
{
|
|
@@ -195,6 +195,27 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
+
var resolveJsonColumnPath = function(pColumnName, pSchema)
|
|
199
|
+
{
|
|
200
|
+
if (!Array.isArray(pSchema) || pSchema.length < 1) return null;
|
|
201
|
+
var tmpParts = pColumnName.replace(/`/g, '').replace(/"/g, '').split('.');
|
|
202
|
+
for (var tmpStartIdx = 0; tmpStartIdx < Math.min(tmpParts.length - 1, 2); tmpStartIdx++)
|
|
203
|
+
{
|
|
204
|
+
var tmpBaseColumn = tmpParts[tmpStartIdx];
|
|
205
|
+
for (var s = 0; s < pSchema.length; s++)
|
|
206
|
+
{
|
|
207
|
+
if (pSchema[s].Column === tmpBaseColumn &&
|
|
208
|
+
(pSchema[s].Type === 'JSON' || pSchema[s].Type === 'JSONProxy'))
|
|
209
|
+
{
|
|
210
|
+
var tmpActualColumn = (pSchema[s].Type === 'JSONProxy') ? pSchema[s].StorageColumn : tmpBaseColumn;
|
|
211
|
+
var tmpJsonPath = '$.' + tmpParts.slice(tmpStartIdx + 1).join('.');
|
|
212
|
+
return { column: tmpActualColumn, path: tmpJsonPath };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
};
|
|
218
|
+
|
|
198
219
|
/**
|
|
199
220
|
* Generate a query from the array of where clauses
|
|
200
221
|
*
|
|
@@ -313,8 +334,16 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
313
334
|
else
|
|
314
335
|
{
|
|
315
336
|
tmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;
|
|
316
|
-
|
|
317
|
-
|
|
337
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
338
|
+
var tmpJsonRef = resolveJsonColumnPath(tmpFilter[i].Column, tmpSchema);
|
|
339
|
+
if (tmpJsonRef)
|
|
340
|
+
{
|
|
341
|
+
tmpWhere += ' JSON_VALUE(['+tmpJsonRef.column+"], '"+tmpJsonRef.path+"') "+tmpFilter[i].Operator+' :'+tmpColumnParameter;
|
|
342
|
+
}
|
|
343
|
+
else
|
|
344
|
+
{
|
|
345
|
+
tmpWhere += ' ['+tmpFilter[i].Column+'] '+tmpFilter[i].Operator+' @'+tmpColumnParameter;
|
|
346
|
+
}
|
|
318
347
|
pParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;
|
|
319
348
|
generateMSSQLParameterTypeEntry(pParameters, tmpColumnParameter, tmpFilter[i].Parameter)
|
|
320
349
|
}
|
|
@@ -523,6 +552,20 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
523
552
|
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
524
553
|
generateMSSQLParameterTypeEntry(pParameters, tmpColumnParameter, tmpColumn)
|
|
525
554
|
break;
|
|
555
|
+
case 'JSON':
|
|
556
|
+
var tmpJSONUpdateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
557
|
+
tmpUpdate += ' '+tmpColumn+' = :'+tmpJSONUpdateParam;
|
|
558
|
+
pParameters.query.parameters[tmpJSONUpdateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
559
|
+
? tmpRecords[0][tmpColumn]
|
|
560
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
561
|
+
break;
|
|
562
|
+
case 'JSONProxy':
|
|
563
|
+
var tmpProxyUpdateParam = tmpSchemaEntry.StorageColumn+'_'+tmpCurrentColumn;
|
|
564
|
+
tmpUpdate += ' '+tmpSchemaEntry.StorageColumn+' = :'+tmpProxyUpdateParam;
|
|
565
|
+
pParameters.query.parameters[tmpProxyUpdateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
566
|
+
? tmpRecords[0][tmpColumn]
|
|
567
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
568
|
+
break;
|
|
526
569
|
default:
|
|
527
570
|
var tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;
|
|
528
571
|
tmpUpdate += ' ['+tmpColumn+'] = @'+tmpColumnDefaultParameter;
|
|
@@ -822,6 +865,20 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
822
865
|
generateMSSQLParameterTypeEntry(pParameters, tmpColumnParameter, tmpSchemaEntry)
|
|
823
866
|
}
|
|
824
867
|
break;
|
|
868
|
+
case 'JSON':
|
|
869
|
+
var tmpJSONCreateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
870
|
+
tmpCreateSet += ' :'+tmpJSONCreateParam;
|
|
871
|
+
pParameters.query.parameters[tmpJSONCreateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
872
|
+
? tmpRecords[0][tmpColumn]
|
|
873
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
874
|
+
break;
|
|
875
|
+
case 'JSONProxy':
|
|
876
|
+
var tmpProxyCreateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
877
|
+
tmpCreateSet += ' :'+tmpProxyCreateParam;
|
|
878
|
+
pParameters.query.parameters[tmpProxyCreateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
879
|
+
? tmpRecords[0][tmpColumn]
|
|
880
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
881
|
+
break;
|
|
825
882
|
default:
|
|
826
883
|
buildDefaultDefinition();
|
|
827
884
|
break;
|
|
@@ -893,6 +950,20 @@ var FoxHoundDialectMSSQL = function(pFable)
|
|
|
893
950
|
tmpCreateSet += ' ['+tmpColumn+']';
|
|
894
951
|
}
|
|
895
952
|
continue;
|
|
953
|
+
case 'JSON':
|
|
954
|
+
if (tmpCreateSet != '')
|
|
955
|
+
{
|
|
956
|
+
tmpCreateSet += ',';
|
|
957
|
+
}
|
|
958
|
+
tmpCreateSet += ' '+tmpColumn;
|
|
959
|
+
break;
|
|
960
|
+
case 'JSONProxy':
|
|
961
|
+
if (tmpCreateSet != '')
|
|
962
|
+
{
|
|
963
|
+
tmpCreateSet += ',';
|
|
964
|
+
}
|
|
965
|
+
tmpCreateSet += ' '+tmpSchemaEntry.StorageColumn;
|
|
966
|
+
break;
|
|
896
967
|
default:
|
|
897
968
|
if (tmpCreateSet != '')
|
|
898
969
|
{
|
|
@@ -131,6 +131,30 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
131
131
|
return "`" + cleanseQuoting(pFieldNames[0]) + "`";
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
var resolveJsonColumnPath = function(pColumnName, pSchema)
|
|
135
|
+
{
|
|
136
|
+
if (!Array.isArray(pSchema) || pSchema.length < 1) return null;
|
|
137
|
+
|
|
138
|
+
// Check for dot notation indicating JSON path: e.g. "Metadata.key" or "FableTest.Metadata.key"
|
|
139
|
+
var tmpParts = pColumnName.replace(/`/g, '').split('.');
|
|
140
|
+
|
|
141
|
+
for (var tmpStartIdx = 0; tmpStartIdx < Math.min(tmpParts.length - 1, 2); tmpStartIdx++)
|
|
142
|
+
{
|
|
143
|
+
var tmpBaseColumn = tmpParts[tmpStartIdx];
|
|
144
|
+
for (var s = 0; s < pSchema.length; s++)
|
|
145
|
+
{
|
|
146
|
+
if (pSchema[s].Column === tmpBaseColumn &&
|
|
147
|
+
(pSchema[s].Type === 'JSON' || pSchema[s].Type === 'JSONProxy'))
|
|
148
|
+
{
|
|
149
|
+
var tmpActualColumn = (pSchema[s].Type === 'JSONProxy') ? pSchema[s].StorageColumn : tmpBaseColumn;
|
|
150
|
+
var tmpJsonPath = '$.' + tmpParts.slice(tmpStartIdx + 1).join('.');
|
|
151
|
+
return { column: tmpActualColumn, path: tmpJsonPath };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
};
|
|
157
|
+
|
|
134
158
|
/**
|
|
135
159
|
* Generate a query from the array of where clauses
|
|
136
160
|
*
|
|
@@ -247,8 +271,18 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
247
271
|
else
|
|
248
272
|
{
|
|
249
273
|
tmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;
|
|
250
|
-
//
|
|
251
|
-
|
|
274
|
+
// Check for JSON path references (e.g. Metadata.habitat)
|
|
275
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
276
|
+
var tmpJsonRef = resolveJsonColumnPath(tmpFilter[i].Column, tmpSchema);
|
|
277
|
+
if (tmpJsonRef)
|
|
278
|
+
{
|
|
279
|
+
tmpWhere += ' JSON_EXTRACT(`'+tmpJsonRef.column+"`, '"+tmpJsonRef.path+"') "+tmpFilter[i].Operator+' :'+tmpColumnParameter;
|
|
280
|
+
}
|
|
281
|
+
else
|
|
282
|
+
{
|
|
283
|
+
// Add the column name, operator and parameter name to the list of where value parenthetical
|
|
284
|
+
tmpWhere += ' '+tmpFilter[i].Column+' '+tmpFilter[i].Operator+' :'+tmpColumnParameter;
|
|
285
|
+
}
|
|
252
286
|
pParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;
|
|
253
287
|
}
|
|
254
288
|
}
|
|
@@ -441,6 +475,20 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
441
475
|
// Set the query parameter
|
|
442
476
|
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
443
477
|
break;
|
|
478
|
+
case 'JSON':
|
|
479
|
+
var tmpJSONUpdateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
480
|
+
tmpUpdate += ' '+tmpColumn+' = :'+tmpJSONUpdateParam;
|
|
481
|
+
pParameters.query.parameters[tmpJSONUpdateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
482
|
+
? tmpRecords[0][tmpColumn]
|
|
483
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
484
|
+
break;
|
|
485
|
+
case 'JSONProxy':
|
|
486
|
+
var tmpProxyUpdateParam = tmpSchemaEntry.StorageColumn+'_'+tmpCurrentColumn;
|
|
487
|
+
tmpUpdate += ' '+tmpSchemaEntry.StorageColumn+' = :'+tmpProxyUpdateParam;
|
|
488
|
+
pParameters.query.parameters[tmpProxyUpdateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
489
|
+
? tmpRecords[0][tmpColumn]
|
|
490
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
491
|
+
break;
|
|
444
492
|
default:
|
|
445
493
|
var tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;
|
|
446
494
|
tmpUpdate += ' '+tmpColumn+' = :'+tmpColumnDefaultParameter;
|
|
@@ -733,6 +781,20 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
733
781
|
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
734
782
|
}
|
|
735
783
|
break;
|
|
784
|
+
case 'JSON':
|
|
785
|
+
var tmpJSONCreateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
786
|
+
tmpCreateSet += ' :'+tmpJSONCreateParam;
|
|
787
|
+
pParameters.query.parameters[tmpJSONCreateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
788
|
+
? tmpRecords[0][tmpColumn]
|
|
789
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
790
|
+
break;
|
|
791
|
+
case 'JSONProxy':
|
|
792
|
+
var tmpProxyCreateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
793
|
+
tmpCreateSet += ' :'+tmpProxyCreateParam;
|
|
794
|
+
pParameters.query.parameters[tmpProxyCreateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
795
|
+
? tmpRecords[0][tmpColumn]
|
|
796
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
797
|
+
break;
|
|
736
798
|
default:
|
|
737
799
|
buildDefaultDefinition();
|
|
738
800
|
break;
|
|
@@ -793,6 +855,20 @@ var FoxHoundDialectMySQL = function(pFable)
|
|
|
793
855
|
}
|
|
794
856
|
switch (tmpSchemaEntry.Type)
|
|
795
857
|
{
|
|
858
|
+
case 'JSON':
|
|
859
|
+
if (tmpCreateSet != '')
|
|
860
|
+
{
|
|
861
|
+
tmpCreateSet += ',';
|
|
862
|
+
}
|
|
863
|
+
tmpCreateSet += ' '+tmpColumn;
|
|
864
|
+
break;
|
|
865
|
+
case 'JSONProxy':
|
|
866
|
+
if (tmpCreateSet != '')
|
|
867
|
+
{
|
|
868
|
+
tmpCreateSet += ',';
|
|
869
|
+
}
|
|
870
|
+
tmpCreateSet += ' '+tmpSchemaEntry.StorageColumn;
|
|
871
|
+
break;
|
|
796
872
|
default:
|
|
797
873
|
if (tmpCreateSet != '')
|
|
798
874
|
{
|
|
@@ -128,6 +128,27 @@ var FoxHoundDialectPostgreSQL = function(pFable)
|
|
|
128
128
|
return '"' + cleanseQuoting(pFieldNames[0]) + '"';
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
var resolveJsonColumnPath = function(pColumnName, pSchema)
|
|
132
|
+
{
|
|
133
|
+
if (!Array.isArray(pSchema) || pSchema.length < 1) return null;
|
|
134
|
+
var tmpParts = pColumnName.replace(/`/g, '').replace(/"/g, '').split('.');
|
|
135
|
+
for (var tmpStartIdx = 0; tmpStartIdx < Math.min(tmpParts.length - 1, 2); tmpStartIdx++)
|
|
136
|
+
{
|
|
137
|
+
var tmpBaseColumn = tmpParts[tmpStartIdx];
|
|
138
|
+
for (var s = 0; s < pSchema.length; s++)
|
|
139
|
+
{
|
|
140
|
+
if (pSchema[s].Column === tmpBaseColumn &&
|
|
141
|
+
(pSchema[s].Type === 'JSON' || pSchema[s].Type === 'JSONProxy'))
|
|
142
|
+
{
|
|
143
|
+
var tmpActualColumn = (pSchema[s].Type === 'JSONProxy') ? pSchema[s].StorageColumn : tmpBaseColumn;
|
|
144
|
+
var tmpJsonPath = '$.' + tmpParts.slice(tmpStartIdx + 1).join('.');
|
|
145
|
+
return { column: tmpActualColumn, path: tmpJsonPath };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
};
|
|
151
|
+
|
|
131
152
|
/**
|
|
132
153
|
* Generate a query from the array of where clauses
|
|
133
154
|
*
|
|
@@ -234,7 +255,24 @@ var FoxHoundDialectPostgreSQL = function(pFable)
|
|
|
234
255
|
else
|
|
235
256
|
{
|
|
236
257
|
tmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;
|
|
237
|
-
|
|
258
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
259
|
+
var tmpJsonRef = resolveJsonColumnPath(tmpFilter[i].Column, tmpSchema);
|
|
260
|
+
if (tmpJsonRef)
|
|
261
|
+
{
|
|
262
|
+
var tmpPathParts = tmpJsonRef.path.replace('$.', '').split('.');
|
|
263
|
+
if (tmpPathParts.length === 1)
|
|
264
|
+
{
|
|
265
|
+
tmpWhere += ' "'+tmpJsonRef.column+'"'+"->>'"+tmpPathParts[0]+"' "+tmpFilter[i].Operator+' :'+tmpColumnParameter;
|
|
266
|
+
}
|
|
267
|
+
else
|
|
268
|
+
{
|
|
269
|
+
tmpWhere += ' "'+tmpJsonRef.column+'"'+"#>>'{"+tmpPathParts.join(',')+"}' "+tmpFilter[i].Operator+' :'+tmpColumnParameter;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
else
|
|
273
|
+
{
|
|
274
|
+
tmpWhere += ' '+generateSafeFieldName(tmpFilter[i].Column)+' '+tmpFilter[i].Operator+' :'+tmpColumnParameter;
|
|
275
|
+
}
|
|
238
276
|
pParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;
|
|
239
277
|
}
|
|
240
278
|
}
|
|
@@ -394,6 +432,20 @@ var FoxHoundDialectPostgreSQL = function(pFable)
|
|
|
394
432
|
tmpUpdate += ' '+generateSafeFieldName(tmpColumn)+' = :'+tmpColumnParameter;
|
|
395
433
|
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
396
434
|
break;
|
|
435
|
+
case 'JSON':
|
|
436
|
+
var tmpJSONUpdateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
437
|
+
tmpUpdate += ' '+tmpColumn+' = :'+tmpJSONUpdateParam;
|
|
438
|
+
pParameters.query.parameters[tmpJSONUpdateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
439
|
+
? tmpRecords[0][tmpColumn]
|
|
440
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
441
|
+
break;
|
|
442
|
+
case 'JSONProxy':
|
|
443
|
+
var tmpProxyUpdateParam = tmpSchemaEntry.StorageColumn+'_'+tmpCurrentColumn;
|
|
444
|
+
tmpUpdate += ' '+tmpSchemaEntry.StorageColumn+' = :'+tmpProxyUpdateParam;
|
|
445
|
+
pParameters.query.parameters[tmpProxyUpdateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
446
|
+
? tmpRecords[0][tmpColumn]
|
|
447
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
448
|
+
break;
|
|
397
449
|
default:
|
|
398
450
|
var tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;
|
|
399
451
|
tmpUpdate += ' '+generateSafeFieldName(tmpColumn)+' = :'+tmpColumnDefaultParameter;
|
|
@@ -646,6 +698,20 @@ var FoxHoundDialectPostgreSQL = function(pFable)
|
|
|
646
698
|
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
647
699
|
}
|
|
648
700
|
break;
|
|
701
|
+
case 'JSON':
|
|
702
|
+
var tmpJSONCreateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
703
|
+
tmpCreateSet += ' :'+tmpJSONCreateParam;
|
|
704
|
+
pParameters.query.parameters[tmpJSONCreateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
705
|
+
? tmpRecords[0][tmpColumn]
|
|
706
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
707
|
+
break;
|
|
708
|
+
case 'JSONProxy':
|
|
709
|
+
var tmpProxyCreateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
710
|
+
tmpCreateSet += ' :'+tmpProxyCreateParam;
|
|
711
|
+
pParameters.query.parameters[tmpProxyCreateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
712
|
+
? tmpRecords[0][tmpColumn]
|
|
713
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
714
|
+
break;
|
|
649
715
|
default:
|
|
650
716
|
buildDefaultDefinition();
|
|
651
717
|
break;
|
|
@@ -697,6 +763,20 @@ var FoxHoundDialectPostgreSQL = function(pFable)
|
|
|
697
763
|
}
|
|
698
764
|
switch (tmpSchemaEntry.Type)
|
|
699
765
|
{
|
|
766
|
+
case 'JSON':
|
|
767
|
+
if (tmpCreateSet != '')
|
|
768
|
+
{
|
|
769
|
+
tmpCreateSet += ',';
|
|
770
|
+
}
|
|
771
|
+
tmpCreateSet += ' '+tmpColumn;
|
|
772
|
+
break;
|
|
773
|
+
case 'JSONProxy':
|
|
774
|
+
if (tmpCreateSet != '')
|
|
775
|
+
{
|
|
776
|
+
tmpCreateSet += ',';
|
|
777
|
+
}
|
|
778
|
+
tmpCreateSet += ' '+tmpSchemaEntry.StorageColumn;
|
|
779
|
+
break;
|
|
700
780
|
default:
|
|
701
781
|
if (tmpCreateSet != '')
|
|
702
782
|
{
|
|
@@ -115,6 +115,27 @@ var FoxHoundDialectSQLite = function(pFable)
|
|
|
115
115
|
return tmpFieldList;
|
|
116
116
|
};
|
|
117
117
|
|
|
118
|
+
var resolveJsonColumnPath = function(pColumnName, pSchema)
|
|
119
|
+
{
|
|
120
|
+
if (!Array.isArray(pSchema) || pSchema.length < 1) return null;
|
|
121
|
+
var tmpParts = pColumnName.replace(/`/g, '').replace(/"/g, '').split('.');
|
|
122
|
+
for (var tmpStartIdx = 0; tmpStartIdx < Math.min(tmpParts.length - 1, 2); tmpStartIdx++)
|
|
123
|
+
{
|
|
124
|
+
var tmpBaseColumn = tmpParts[tmpStartIdx];
|
|
125
|
+
for (var s = 0; s < pSchema.length; s++)
|
|
126
|
+
{
|
|
127
|
+
if (pSchema[s].Column === tmpBaseColumn &&
|
|
128
|
+
(pSchema[s].Type === 'JSON' || pSchema[s].Type === 'JSONProxy'))
|
|
129
|
+
{
|
|
130
|
+
var tmpActualColumn = (pSchema[s].Type === 'JSONProxy') ? pSchema[s].StorageColumn : tmpBaseColumn;
|
|
131
|
+
var tmpJsonPath = '$.' + tmpParts.slice(tmpStartIdx + 1).join('.');
|
|
132
|
+
return { column: tmpActualColumn, path: tmpJsonPath };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
};
|
|
138
|
+
|
|
118
139
|
/**
|
|
119
140
|
* Generate a query from the array of where clauses
|
|
120
141
|
*
|
|
@@ -243,8 +264,16 @@ var FoxHoundDialectSQLite = function(pFable)
|
|
|
243
264
|
else
|
|
244
265
|
{
|
|
245
266
|
tmpColumnParameter = tmpFilter[i].Parameter+'_w'+i;
|
|
246
|
-
|
|
247
|
-
|
|
267
|
+
var tmpSchema = Array.isArray(pParameters.query.schema) ? pParameters.query.schema : [];
|
|
268
|
+
var tmpJsonRef = resolveJsonColumnPath(tmpFilter[i].Column, tmpSchema);
|
|
269
|
+
if (tmpJsonRef)
|
|
270
|
+
{
|
|
271
|
+
tmpWhere += ' json_extract(`'+tmpJsonRef.column+"`, '"+tmpJsonRef.path+"') "+tmpFilter[i].Operator+' :'+tmpColumnParameter;
|
|
272
|
+
}
|
|
273
|
+
else
|
|
274
|
+
{
|
|
275
|
+
tmpWhere += ' '+escapeColumn(tmpFilter[i].Column, pParameters)+' '+tmpFilter[i].Operator+' :'+tmpColumnParameter;
|
|
276
|
+
}
|
|
248
277
|
pParameters.query.parameters[tmpColumnParameter] = tmpFilter[i].Value;
|
|
249
278
|
}
|
|
250
279
|
}
|
|
@@ -392,6 +421,20 @@ var FoxHoundDialectSQLite = function(pFable)
|
|
|
392
421
|
// Set the query parameter
|
|
393
422
|
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
394
423
|
break;
|
|
424
|
+
case 'JSON':
|
|
425
|
+
var tmpJSONUpdateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
426
|
+
tmpUpdate += ' '+tmpColumn+' = :'+tmpJSONUpdateParam;
|
|
427
|
+
pParameters.query.parameters[tmpJSONUpdateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
428
|
+
? tmpRecords[0][tmpColumn]
|
|
429
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
430
|
+
break;
|
|
431
|
+
case 'JSONProxy':
|
|
432
|
+
var tmpProxyUpdateParam = tmpSchemaEntry.StorageColumn+'_'+tmpCurrentColumn;
|
|
433
|
+
tmpUpdate += ' '+tmpSchemaEntry.StorageColumn+' = :'+tmpProxyUpdateParam;
|
|
434
|
+
pParameters.query.parameters[tmpProxyUpdateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
435
|
+
? tmpRecords[0][tmpColumn]
|
|
436
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
437
|
+
break;
|
|
395
438
|
default:
|
|
396
439
|
var tmpColumnDefaultParameter = tmpColumn+'_'+tmpCurrentColumn;
|
|
397
440
|
tmpUpdate += ' '+escapeColumn(tmpColumn, pParameters)+' = :'+tmpColumnDefaultParameter;
|
|
@@ -687,6 +730,20 @@ var FoxHoundDialectSQLite = function(pFable)
|
|
|
687
730
|
pParameters.query.parameters[tmpColumnParameter] = pParameters.query.IDUser;
|
|
688
731
|
}
|
|
689
732
|
break;
|
|
733
|
+
case 'JSON':
|
|
734
|
+
var tmpJSONCreateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
735
|
+
tmpCreateSet += ' :'+tmpJSONCreateParam;
|
|
736
|
+
pParameters.query.parameters[tmpJSONCreateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
737
|
+
? tmpRecords[0][tmpColumn]
|
|
738
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
739
|
+
break;
|
|
740
|
+
case 'JSONProxy':
|
|
741
|
+
var tmpProxyCreateParam = tmpColumn+'_'+tmpCurrentColumn;
|
|
742
|
+
tmpCreateSet += ' :'+tmpProxyCreateParam;
|
|
743
|
+
pParameters.query.parameters[tmpProxyCreateParam] = (typeof tmpRecords[0][tmpColumn] === 'string')
|
|
744
|
+
? tmpRecords[0][tmpColumn]
|
|
745
|
+
: JSON.stringify(tmpRecords[0][tmpColumn] || {});
|
|
746
|
+
break;
|
|
690
747
|
default:
|
|
691
748
|
buildDefaultDefinition();
|
|
692
749
|
break;
|
|
@@ -747,6 +804,20 @@ var FoxHoundDialectSQLite = function(pFable)
|
|
|
747
804
|
}
|
|
748
805
|
switch (tmpSchemaEntry.Type)
|
|
749
806
|
{
|
|
807
|
+
case 'JSON':
|
|
808
|
+
if (tmpCreateSet != '')
|
|
809
|
+
{
|
|
810
|
+
tmpCreateSet += ',';
|
|
811
|
+
}
|
|
812
|
+
tmpCreateSet += ' '+tmpColumn;
|
|
813
|
+
break;
|
|
814
|
+
case 'JSONProxy':
|
|
815
|
+
if (tmpCreateSet != '')
|
|
816
|
+
{
|
|
817
|
+
tmpCreateSet += ',';
|
|
818
|
+
}
|
|
819
|
+
tmpCreateSet += ' '+tmpSchemaEntry.StorageColumn;
|
|
820
|
+
break;
|
|
750
821
|
default:
|
|
751
822
|
if (tmpCreateSet != '')
|
|
752
823
|
{
|