foxhound 2.0.19 → 2.0.21
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 +3 -2
- package/docs/README.md +32 -11
- package/docs/_cover.md +3 -2
- package/docs/_sidebar.md +21 -1
- package/docs/_topbar.md +7 -0
- package/docs/api/README.md +73 -0
- package/docs/api/addFilter.md +170 -0
- package/docs/api/addJoin.md +128 -0
- package/docs/api/addRecord.md +108 -0
- package/docs/api/addSort.md +109 -0
- package/docs/api/behaviorFlags.md +123 -0
- package/docs/api/buildQuery.md +146 -0
- package/docs/api/clone.md +115 -0
- package/docs/api/queryOverrides.md +82 -0
- package/docs/api/setCap.md +115 -0
- package/docs/api/setDataElements.md +95 -0
- package/docs/api/setDialect.md +78 -0
- package/docs/api/setDistinct.md +76 -0
- package/docs/api/setIDUser.md +80 -0
- package/docs/api/setScope.md +70 -0
- package/docs/architecture.md +134 -42
- package/docs/dialects/README.md +2 -0
- package/docs/dialects/postgresql.md +126 -0
- package/docs/quickstart.md +196 -0
- package/docs/retold-catalog.json +40 -1
- package/docs/retold-keyword-index.json +7996 -2630
- package/package.json +2 -2
- package/source/Foxhound-Dialects.js +1 -1
- package/source/dialects/PostgreSQL/FoxHound-Dialect-PostgreSQL.js +17 -17
- package/test/FoxHound-Dialect-PostgreSQL_tests.js +11 -11
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# addSort / setSort
|
|
2
|
+
|
|
3
|
+
Add or replace sort expressions for the ORDER BY clause.
|
|
4
|
+
|
|
5
|
+
## addSort
|
|
6
|
+
|
|
7
|
+
Add a single sort expression to the existing sort array.
|
|
8
|
+
|
|
9
|
+
### Signature
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
tmpQuery.addSort(pSort)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Parameters
|
|
16
|
+
|
|
17
|
+
| Parameter | Type | Description |
|
|
18
|
+
|-----------|------|-------------|
|
|
19
|
+
| `pSort` | String or Object | Column name (ascending by default) or sort object |
|
|
20
|
+
|
|
21
|
+
### Returns
|
|
22
|
+
|
|
23
|
+
Returns `this` for chaining.
|
|
24
|
+
|
|
25
|
+
### Examples
|
|
26
|
+
|
|
27
|
+
#### Sort ascending by column name
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
tmpQuery.addSort('PublishedYear');
|
|
31
|
+
// ORDER BY PublishedYear
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
#### Sort descending
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
tmpQuery.addSort({Column: 'PublishedYear', Direction: 'Descending'});
|
|
38
|
+
// ORDER BY PublishedYear DESC
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
#### Multiple sort columns
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
tmpQuery
|
|
45
|
+
.addSort({Column: 'Genre', Direction: 'Ascending'})
|
|
46
|
+
.addSort({Column: 'PublishedYear', Direction: 'Descending'});
|
|
47
|
+
// ORDER BY Genre, PublishedYear DESC
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## setSort
|
|
51
|
+
|
|
52
|
+
Replace the entire sort array.
|
|
53
|
+
|
|
54
|
+
### Signature
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
tmpQuery.setSort(pSort)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Parameters
|
|
61
|
+
|
|
62
|
+
| Parameter | Type | Description |
|
|
63
|
+
|-----------|------|-------------|
|
|
64
|
+
| `pSort` | String, Object, or Array | Sort expression(s) |
|
|
65
|
+
|
|
66
|
+
### Examples
|
|
67
|
+
|
|
68
|
+
#### Single string
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
tmpQuery.setSort('Title');
|
|
72
|
+
// ORDER BY Title
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Single object
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
tmpQuery.setSort({Column: 'Title', Direction: 'Descending'});
|
|
79
|
+
// ORDER BY Title DESC
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### Array of sort expressions
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
tmpQuery.setSort([
|
|
86
|
+
{Column: 'Genre', Direction: 'Ascending'},
|
|
87
|
+
{Column: 'Title', Direction: 'Ascending'}
|
|
88
|
+
]);
|
|
89
|
+
// ORDER BY Genre, Title
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Sort Object Structure
|
|
93
|
+
|
|
94
|
+
| Property | Type | Values | Description |
|
|
95
|
+
|----------|------|--------|-------------|
|
|
96
|
+
| `Column` | String | Any column name | Column to sort by |
|
|
97
|
+
| `Direction` | String | `'Ascending'` or `'Descending'` | Sort direction (default: Ascending) |
|
|
98
|
+
|
|
99
|
+
## Dialect Quoting
|
|
100
|
+
|
|
101
|
+
Each dialect quotes the column name in ORDER BY according to its conventions:
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
tmpQuery.addSort('PublishedYear');
|
|
105
|
+
|
|
106
|
+
// MySQL: ORDER BY PublishedYear
|
|
107
|
+
// PostgreSQL: ORDER BY "PublishedYear"
|
|
108
|
+
// MSSQL: ORDER BY [PublishedYear]
|
|
109
|
+
```
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Behavior Flags
|
|
2
|
+
|
|
3
|
+
Control how FoxHound handles automatic column management.
|
|
4
|
+
|
|
5
|
+
## Methods
|
|
6
|
+
|
|
7
|
+
All behavior flag methods accept a boolean and return `this` for chaining.
|
|
8
|
+
|
|
9
|
+
### setDisableAutoIdentity(pFlag)
|
|
10
|
+
|
|
11
|
+
Disable automatic identity column handling on INSERT.
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
tmpQuery.setDisableAutoIdentity(true);
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
When **false** (default): AutoIdentity columns insert `NULL` (MySQL/SQLite), `DEFAULT` (PostgreSQL), or are omitted (MSSQL), letting the database assign the ID.
|
|
18
|
+
|
|
19
|
+
When **true**: The identity column value from the record is used as-is.
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
// Force a specific ID value
|
|
23
|
+
tmpQuery
|
|
24
|
+
.setDisableAutoIdentity(true)
|
|
25
|
+
.addRecord({IDBook: 999, Title: 'Custom ID Book'});
|
|
26
|
+
|
|
27
|
+
tmpQuery.query.schema = [{Column: 'IDBook', Type: 'AutoIdentity'}, ...];
|
|
28
|
+
tmpQuery.setDialect('MySQL').buildCreateQuery();
|
|
29
|
+
|
|
30
|
+
// IDBook uses the provided value 999 instead of NULL
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### setDisableAutoDateStamp(pFlag)
|
|
34
|
+
|
|
35
|
+
Disable automatic timestamp generation.
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
tmpQuery.setDisableAutoDateStamp(true);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
When **false** (default): `CreateDate`, `UpdateDate`, and `DeleteDate` columns are automatically set to the current timestamp.
|
|
42
|
+
|
|
43
|
+
When **true**: These columns use the value from the record object instead.
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
// Set a custom date
|
|
47
|
+
tmpQuery
|
|
48
|
+
.setDisableAutoDateStamp(true)
|
|
49
|
+
.addRecord({Title: 'Imported Book', CreateDate: '2020-01-15'});
|
|
50
|
+
|
|
51
|
+
// CreateDate uses '2020-01-15' instead of NOW()
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### setDisableAutoUserStamp(pFlag)
|
|
55
|
+
|
|
56
|
+
Disable automatic user ID stamping.
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
tmpQuery.setDisableAutoUserStamp(true);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
When **false** (default): `CreateIDUser`, `UpdateIDUser`, and `DeleteIDUser` columns are set to the value from `setIDUser()`.
|
|
63
|
+
|
|
64
|
+
When **true**: These columns use the value from the record object instead.
|
|
65
|
+
|
|
66
|
+
### setDisableDeleteTracking(pFlag)
|
|
67
|
+
|
|
68
|
+
Disable soft-delete behavior.
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
tmpQuery.setDisableDeleteTracking(true);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
When **false** (default):
|
|
75
|
+
- `DELETE` generates an UPDATE that sets `Deleted = 1`
|
|
76
|
+
- `DeleteDate` and `DeleteIDUser` columns are excluded from INSERT
|
|
77
|
+
- Read and Count queries automatically add `WHERE Deleted = 0`
|
|
78
|
+
|
|
79
|
+
When **true**:
|
|
80
|
+
- `DELETE` generates a true `DELETE FROM` statement
|
|
81
|
+
- `DeleteDate` and `DeleteIDUser` columns are included in INSERT
|
|
82
|
+
- No automatic `Deleted` filter on Read/Count queries
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
// Hard delete instead of soft delete
|
|
86
|
+
tmpQuery
|
|
87
|
+
.setScope('TempRecords')
|
|
88
|
+
.addFilter('IDTemp', 99)
|
|
89
|
+
.setDisableDeleteTracking(true)
|
|
90
|
+
.setDialect('MySQL')
|
|
91
|
+
.buildDeleteQuery();
|
|
92
|
+
|
|
93
|
+
// => DELETE FROM `TempRecords` WHERE IDTemp = :IDTemp_w0;
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### setLogLevel(pLogLevel)
|
|
97
|
+
|
|
98
|
+
Set query logging verbosity.
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
tmpQuery.setLogLevel(3);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
| Level | Behavior |
|
|
105
|
+
|-------|----------|
|
|
106
|
+
| `0` | No logging (default) |
|
|
107
|
+
| `1` | Log generated queries |
|
|
108
|
+
| `2` | Log queries and non-parameterized versions |
|
|
109
|
+
| `3+` | Log everything including configuration steps |
|
|
110
|
+
|
|
111
|
+
## Combining Flags
|
|
112
|
+
|
|
113
|
+
Flags can be combined as needed:
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
tmpQuery
|
|
117
|
+
.setDisableAutoIdentity(true)
|
|
118
|
+
.setDisableAutoDateStamp(true)
|
|
119
|
+
.setDisableAutoUserStamp(true)
|
|
120
|
+
.setDisableDeleteTracking(true);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
This gives you full manual control over all column values — useful for data migration or import scenarios.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Build Methods
|
|
2
|
+
|
|
3
|
+
Generate SQL from the current query configuration.
|
|
4
|
+
|
|
5
|
+
## Methods
|
|
6
|
+
|
|
7
|
+
| Method | Operation | SQL Pattern |
|
|
8
|
+
|--------|-----------|-------------|
|
|
9
|
+
| `buildCreateQuery()` | Insert a record | `INSERT INTO ... VALUES (...)` |
|
|
10
|
+
| `buildReadQuery()` | Select records | `SELECT ... FROM ... WHERE ...` |
|
|
11
|
+
| `buildUpdateQuery()` | Modify a record | `UPDATE ... SET ... WHERE ...` |
|
|
12
|
+
| `buildDeleteQuery()` | Soft- or hard-delete | `UPDATE ... SET Deleted=1` or `DELETE FROM ...` |
|
|
13
|
+
| `buildUndeleteQuery()` | Restore soft-deleted | `UPDATE ... SET Deleted=0` |
|
|
14
|
+
| `buildCountQuery()` | Count matching rows | `SELECT COUNT(*) AS RowCount FROM ...` |
|
|
15
|
+
|
|
16
|
+
All build methods return `this` for chaining.
|
|
17
|
+
|
|
18
|
+
## Accessing Results
|
|
19
|
+
|
|
20
|
+
After calling a build method, the generated SQL and bound parameters are available on the `query` property:
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
tmpQuery.buildReadQuery();
|
|
24
|
+
|
|
25
|
+
console.log(tmpQuery.query.body); // SQL string
|
|
26
|
+
console.log(tmpQuery.query.parameters); // Bound parameter values
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## buildCreateQuery
|
|
30
|
+
|
|
31
|
+
Generate an INSERT statement. Requires at least one record via `addRecord()`.
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
var tmpQuery = libFoxHound.new(_Fable)
|
|
35
|
+
.setDialect('PostgreSQL')
|
|
36
|
+
.setScope('Books')
|
|
37
|
+
.addRecord({Title: 'Dune', Author: 'Frank Herbert'})
|
|
38
|
+
.buildCreateQuery();
|
|
39
|
+
|
|
40
|
+
console.log(tmpQuery.query.body);
|
|
41
|
+
// => INSERT INTO "Books" ( "Title", "Author")
|
|
42
|
+
// VALUES ( :Title_0, :Author_1) RETURNING *;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Returns `false` for `query.body` if no records are provided or the record is empty.
|
|
46
|
+
|
|
47
|
+
## buildReadQuery
|
|
48
|
+
|
|
49
|
+
Generate a SELECT statement. Uses all configured filters, sorts, joins, and pagination.
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
var tmpQuery = libFoxHound.new(_Fable)
|
|
53
|
+
.setDialect('MySQL')
|
|
54
|
+
.setScope('Books')
|
|
55
|
+
.setDataElements(['Title', 'Author'])
|
|
56
|
+
.addFilter('Genre', 'Fantasy')
|
|
57
|
+
.addSort('Title')
|
|
58
|
+
.setCap(25)
|
|
59
|
+
.buildReadQuery();
|
|
60
|
+
|
|
61
|
+
console.log(tmpQuery.query.body);
|
|
62
|
+
// => SELECT `Title`, `Author` FROM `Books`
|
|
63
|
+
// WHERE `Books`.`Genre` = :Genre_w0
|
|
64
|
+
// ORDER BY Title LIMIT 25;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## buildUpdateQuery
|
|
68
|
+
|
|
69
|
+
Generate an UPDATE ... SET statement. Requires at least one record and typically a filter for the WHERE clause.
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
var tmpQuery = libFoxHound.new(_Fable)
|
|
73
|
+
.setDialect('MySQL')
|
|
74
|
+
.setScope('Books')
|
|
75
|
+
.addFilter('IDBook', 42)
|
|
76
|
+
.addRecord({Title: 'Dune Messiah'})
|
|
77
|
+
.buildUpdateQuery();
|
|
78
|
+
|
|
79
|
+
console.log(tmpQuery.query.body);
|
|
80
|
+
// => UPDATE `Books` SET Title = :Title_0 WHERE IDBook = :IDBook_w0;
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Returns `false` for `query.body` if no records are provided.
|
|
84
|
+
|
|
85
|
+
## buildDeleteQuery
|
|
86
|
+
|
|
87
|
+
Generate a soft-delete UPDATE or a hard DELETE.
|
|
88
|
+
|
|
89
|
+
When a schema has a `Deleted` column type and delete tracking is enabled:
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
// Soft delete — generates an UPDATE
|
|
93
|
+
tmpQuery.buildDeleteQuery();
|
|
94
|
+
// => UPDATE `Books` SET Deleted = 1, DeleteDate = NOW(3), ...
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
When no schema or delete tracking is disabled:
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
// Hard delete — generates a DELETE
|
|
101
|
+
tmpQuery.setDisableDeleteTracking(true).buildDeleteQuery();
|
|
102
|
+
// => DELETE FROM `Books` WHERE IDBook = :IDBook_w0;
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## buildUndeleteQuery
|
|
106
|
+
|
|
107
|
+
Restore soft-deleted records by setting `Deleted = 0`.
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
var tmpQuery = libFoxHound.new(_Fable)
|
|
111
|
+
.setDialect('MySQL')
|
|
112
|
+
.setScope('Books')
|
|
113
|
+
.addFilter('IDBook', 42)
|
|
114
|
+
.setIDUser(5);
|
|
115
|
+
|
|
116
|
+
tmpQuery.query.schema = _BookSchema;
|
|
117
|
+
tmpQuery.buildUndeleteQuery();
|
|
118
|
+
|
|
119
|
+
// => UPDATE `Books` SET Deleted = 0, UpdateDate = NOW(3),
|
|
120
|
+
// UpdateIDUser = :UpdateIDUser_1 WHERE IDBook = :IDBook_w0;
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Returns `SELECT NULL;` if no Deleted column exists in the schema.
|
|
124
|
+
|
|
125
|
+
## buildCountQuery
|
|
126
|
+
|
|
127
|
+
Generate a SELECT COUNT(*) statement.
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
var tmpQuery = libFoxHound.new(_Fable)
|
|
131
|
+
.setDialect('MySQL')
|
|
132
|
+
.setScope('Books')
|
|
133
|
+
.addFilter('Genre', 'Fantasy')
|
|
134
|
+
.buildCountQuery();
|
|
135
|
+
|
|
136
|
+
console.log(tmpQuery.query.body);
|
|
137
|
+
// => SELECT COUNT(*) AS RowCount FROM `Books`
|
|
138
|
+
// WHERE `Books`.`Genre` = :Genre_w0;
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
With DISTINCT:
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
tmpQuery.setDistinct(true).setDataElements(['Author']).buildCountQuery();
|
|
145
|
+
// => SELECT COUNT(DISTINCT `Author`) AS RowCount FROM `Books` ...;
|
|
146
|
+
```
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# clone / resetParameters / mergeParameters
|
|
2
|
+
|
|
3
|
+
Utility methods for managing query state.
|
|
4
|
+
|
|
5
|
+
## clone
|
|
6
|
+
|
|
7
|
+
Create an independent copy of the current query.
|
|
8
|
+
|
|
9
|
+
### Signature
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
var tmpClone = tmpQuery.clone();
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Returns
|
|
16
|
+
|
|
17
|
+
Returns a new FoxHound query instance with copies of the current scope, begin, cap, schema, dataElements, sorts, and filters.
|
|
18
|
+
|
|
19
|
+
### Description
|
|
20
|
+
|
|
21
|
+
Cloning is useful when you need to build multiple similar queries from the same base configuration. The cloned query has its own independent state — changes to the clone do not affect the original.
|
|
22
|
+
|
|
23
|
+
### Example
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
var tmpBase = libFoxHound.new(_Fable)
|
|
27
|
+
.setDialect('MySQL')
|
|
28
|
+
.setScope('Books')
|
|
29
|
+
.addFilter('Genre', 'Fantasy');
|
|
30
|
+
|
|
31
|
+
// Clone and customize for a read
|
|
32
|
+
var tmpRead = tmpBase.clone();
|
|
33
|
+
tmpRead.setCap(10).buildReadQuery();
|
|
34
|
+
|
|
35
|
+
// Clone and customize for a count
|
|
36
|
+
var tmpCount = tmpBase.clone();
|
|
37
|
+
tmpCount.buildCountQuery();
|
|
38
|
+
|
|
39
|
+
console.log(tmpRead.query.body);
|
|
40
|
+
// => SELECT `Books`.* FROM `Books` WHERE ... LIMIT 10;
|
|
41
|
+
|
|
42
|
+
console.log(tmpCount.query.body);
|
|
43
|
+
// => SELECT COUNT(*) AS RowCount FROM `Books` WHERE ...;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## resetParameters
|
|
47
|
+
|
|
48
|
+
Reset the query to its default state.
|
|
49
|
+
|
|
50
|
+
### Signature
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
tmpQuery.resetParameters()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Returns
|
|
57
|
+
|
|
58
|
+
Returns `this` for chaining.
|
|
59
|
+
|
|
60
|
+
### Description
|
|
61
|
+
|
|
62
|
+
Re-initializes all parameters (scope, filters, sorts, joins, cap, begin, records, etc.) to their default values. This is useful for reusing a query object for a new query.
|
|
63
|
+
|
|
64
|
+
### Example
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
tmpQuery
|
|
68
|
+
.setScope('Books')
|
|
69
|
+
.addFilter('Genre', 'Fantasy')
|
|
70
|
+
.buildReadQuery();
|
|
71
|
+
|
|
72
|
+
// Reset and build a new query
|
|
73
|
+
tmpQuery.resetParameters();
|
|
74
|
+
tmpQuery
|
|
75
|
+
.setScope('Authors')
|
|
76
|
+
.setDialect('MySQL')
|
|
77
|
+
.buildReadQuery();
|
|
78
|
+
|
|
79
|
+
console.log(tmpQuery.query.body);
|
|
80
|
+
// => SELECT `Authors`.* FROM `Authors`;
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## mergeParameters
|
|
84
|
+
|
|
85
|
+
Merge an object of parameters into the current state.
|
|
86
|
+
|
|
87
|
+
### Signature
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
tmpQuery.mergeParameters(pFromParameters)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Parameters
|
|
94
|
+
|
|
95
|
+
| Parameter | Type | Description |
|
|
96
|
+
|-----------|------|-------------|
|
|
97
|
+
| `pFromParameters` | Object | Object with parameter values to merge |
|
|
98
|
+
|
|
99
|
+
### Returns
|
|
100
|
+
|
|
101
|
+
Returns `this` for chaining.
|
|
102
|
+
|
|
103
|
+
### Description
|
|
104
|
+
|
|
105
|
+
Performs a shallow merge of the provided object into the current parameters. This is useful for applying a set of parameter overrides at once.
|
|
106
|
+
|
|
107
|
+
### Example
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
tmpQuery.mergeParameters({
|
|
111
|
+
cap: 50,
|
|
112
|
+
begin: 0,
|
|
113
|
+
scope: 'Books'
|
|
114
|
+
});
|
|
115
|
+
```
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Query Overrides
|
|
2
|
+
|
|
3
|
+
Supply custom SQL templates for Read and Count queries while retaining automatic parameter binding.
|
|
4
|
+
|
|
5
|
+
## Setting a Query Override
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
tmpQuery.parameters.queryOverride =
|
|
9
|
+
'SELECT <%= FieldList %> FROM <%= TableName %> <%= Where %> GROUP BY Genre <%= OrderBy %> <%= Limit %>';
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Or via Meadow's raw query system:
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
myMeadow.rawQueries.setQuery('Read',
|
|
16
|
+
'SELECT <%= FieldList %> FROM <%= TableName %> <%= Join %> <%= Where %> GROUP BY Genre <%= OrderBy %> <%= Limit %>');
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## How It Works
|
|
20
|
+
|
|
21
|
+
A query override is an underscore-style template string. FoxHound generates the individual clauses (field list, WHERE, JOINs, etc.) and then passes them into your template as variables.
|
|
22
|
+
|
|
23
|
+
## Template Variables
|
|
24
|
+
|
|
25
|
+
| Variable | Type | Description |
|
|
26
|
+
|----------|------|-------------|
|
|
27
|
+
| `<%= FieldList %>` | String | Comma-separated field list (with dialect-specific quoting) |
|
|
28
|
+
| `<%= TableName %>` | String | Quoted table name |
|
|
29
|
+
| `<%= Where %>` | String | Full WHERE clause including the keyword, or empty string |
|
|
30
|
+
| `<%= Join %>` | String | All JOIN clauses, or empty string |
|
|
31
|
+
| `<%= OrderBy %>` | String | ORDER BY clause including the keyword, or empty string |
|
|
32
|
+
| `<%= Limit %>` | String | Pagination clause (dialect-specific), or empty string |
|
|
33
|
+
| `<%= IndexHints %>` | String | Index hint clause (MySQL/MSSQL), or empty string |
|
|
34
|
+
| `<%= Distinct %>` | String | The `DISTINCT` keyword if set, or empty string |
|
|
35
|
+
| `<%= _Params %>` | Object | The full Parameters object for advanced access |
|
|
36
|
+
|
|
37
|
+
## Examples
|
|
38
|
+
|
|
39
|
+
### GROUP BY
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
tmpQuery.parameters.queryOverride =
|
|
43
|
+
'SELECT Genre, COUNT(*) as BookCount FROM <%= TableName %> <%= Where %> GROUP BY Genre <%= OrderBy %>';
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Subquery
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
tmpQuery.parameters.queryOverride =
|
|
50
|
+
'SELECT <%= FieldList %> FROM <%= TableName %> <%= Where %> AND PublishedYear = (SELECT MAX(PublishedYear) FROM <%= TableName %>)';
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Custom aggregation
|
|
54
|
+
|
|
55
|
+
```javascript
|
|
56
|
+
tmpQuery.parameters.queryOverride =
|
|
57
|
+
'SELECT Author, AVG(Rating) as AvgRating FROM <%= TableName %> <%= Where %> GROUP BY Author HAVING AVG(Rating) > 4.0 <%= OrderBy %>';
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Accessing the full parameters object
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
tmpQuery.parameters.queryOverride =
|
|
64
|
+
'SELECT * FROM <%= TableName %> WHERE IDBook > <%= _Params.begin %>';
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Scope
|
|
68
|
+
|
|
69
|
+
Query overrides apply to **Read** and **Count** operations only. Create, Update, Delete, and Undelete always use the standard generation path.
|
|
70
|
+
|
|
71
|
+
## Error Handling
|
|
72
|
+
|
|
73
|
+
If a query override template fails to compile or execute, FoxHound catches the error, logs it, and returns `false` for the query body.
|
|
74
|
+
|
|
75
|
+
## When to Use
|
|
76
|
+
|
|
77
|
+
- `GROUP BY` clauses
|
|
78
|
+
- Subqueries
|
|
79
|
+
- Custom aggregations (`SUM`, `AVG`, `MAX`, `MIN`)
|
|
80
|
+
- `HAVING` clauses
|
|
81
|
+
- `UNION` queries
|
|
82
|
+
- Any SQL feature not directly supported by the fluent API
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# setCap / setBegin
|
|
2
|
+
|
|
3
|
+
Set pagination limits and offsets.
|
|
4
|
+
|
|
5
|
+
## setCap
|
|
6
|
+
|
|
7
|
+
Set the maximum number of rows to return (LIMIT).
|
|
8
|
+
|
|
9
|
+
### Signature
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
tmpQuery.setCap(pCapAmount)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Parameters
|
|
16
|
+
|
|
17
|
+
| Parameter | Type | Description |
|
|
18
|
+
|-----------|------|-------------|
|
|
19
|
+
| `pCapAmount` | Integer or false | Maximum row count (must be >= 0), or `false` to remove |
|
|
20
|
+
|
|
21
|
+
### Returns
|
|
22
|
+
|
|
23
|
+
Returns `this` for chaining.
|
|
24
|
+
|
|
25
|
+
### Examples
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
// Return at most 50 rows
|
|
29
|
+
tmpQuery.setCap(50);
|
|
30
|
+
|
|
31
|
+
// Remove the cap (return all rows)
|
|
32
|
+
tmpQuery.setCap(false);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## setBegin
|
|
36
|
+
|
|
37
|
+
Set the zero-based starting offset (OFFSET / SKIP).
|
|
38
|
+
|
|
39
|
+
### Signature
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
tmpQuery.setBegin(pBeginAmount)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Parameters
|
|
46
|
+
|
|
47
|
+
| Parameter | Type | Description |
|
|
48
|
+
|-----------|------|-------------|
|
|
49
|
+
| `pBeginAmount` | Integer or false | Zero-based row offset (must be >= 0), or `false` to remove |
|
|
50
|
+
|
|
51
|
+
### Returns
|
|
52
|
+
|
|
53
|
+
Returns `this` for chaining.
|
|
54
|
+
|
|
55
|
+
### Examples
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
// Start at the 101st record
|
|
59
|
+
tmpQuery.setBegin(100);
|
|
60
|
+
|
|
61
|
+
// Remove the offset
|
|
62
|
+
tmpQuery.setBegin(false);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Pagination Examples
|
|
66
|
+
|
|
67
|
+
### First page
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
tmpQuery
|
|
71
|
+
.setScope('Books')
|
|
72
|
+
.setCap(20)
|
|
73
|
+
.setDialect('MySQL')
|
|
74
|
+
.buildReadQuery();
|
|
75
|
+
|
|
76
|
+
// MySQL: SELECT ... LIMIT 20;
|
|
77
|
+
// PostgreSQL: SELECT ... LIMIT 20;
|
|
78
|
+
// MSSQL: SELECT ... OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Second page
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
tmpQuery
|
|
85
|
+
.setScope('Books')
|
|
86
|
+
.setBegin(20)
|
|
87
|
+
.setCap(20)
|
|
88
|
+
.setDialect('MySQL')
|
|
89
|
+
.buildReadQuery();
|
|
90
|
+
|
|
91
|
+
// MySQL: SELECT ... LIMIT 20, 20;
|
|
92
|
+
// PostgreSQL: SELECT ... LIMIT 20 OFFSET 20;
|
|
93
|
+
// MSSQL: SELECT ... OFFSET 20 ROWS FETCH NEXT 20 ROWS ONLY;
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Page-based helper
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
var tmpPageSize = 20;
|
|
100
|
+
var tmpPageNumber = 3; // zero-based
|
|
101
|
+
|
|
102
|
+
tmpQuery
|
|
103
|
+
.setBegin(tmpPageNumber * tmpPageSize)
|
|
104
|
+
.setCap(tmpPageSize);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Dialect Syntax
|
|
108
|
+
|
|
109
|
+
| Dialect | Cap Only | Cap + Offset |
|
|
110
|
+
|---------|----------|--------------|
|
|
111
|
+
| MySQL | `LIMIT 20` | `LIMIT 40, 20` |
|
|
112
|
+
| PostgreSQL | `LIMIT 20` | `LIMIT 20 OFFSET 40` |
|
|
113
|
+
| MSSQL | `OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY` | `OFFSET 40 ROWS FETCH NEXT 20 ROWS ONLY` |
|
|
114
|
+
| SQLite | `LIMIT 20` | `LIMIT 20 OFFSET 40` |
|
|
115
|
+
| ALASQL | `LIMIT 20` | `LIMIT 20 FETCH 40` |
|