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.
@@ -0,0 +1,95 @@
1
+ # setDataElements
2
+
3
+ Set which columns to include in the SELECT clause.
4
+
5
+ ## Signature
6
+
7
+ ```javascript
8
+ tmpQuery.setDataElements(pDataElements)
9
+ ```
10
+
11
+ ## Parameters
12
+
13
+ | Parameter | Type | Required | Description |
14
+ |-----------|------|----------|-------------|
15
+ | `pDataElements` | Array or String | Yes | Column name(s) to select |
16
+
17
+ ## Returns
18
+
19
+ Returns `this` for chaining.
20
+
21
+ ## Description
22
+
23
+ Sets the list of columns to include in the SELECT field list. When not set (or set to `false`), the query selects all columns using `*`.
24
+
25
+ If a string is passed, it is automatically wrapped in an array.
26
+
27
+ ## Examples
28
+
29
+ ### Select all columns (default)
30
+
31
+ ```javascript
32
+ tmpQuery.setScope('Books').setDialect('MySQL').buildReadQuery();
33
+ // => SELECT `Books`.* FROM `Books`;
34
+ ```
35
+
36
+ ### Select specific columns
37
+
38
+ ```javascript
39
+ tmpQuery
40
+ .setScope('Books')
41
+ .setDataElements(['Title', 'Author', 'PublishedYear'])
42
+ .setDialect('MySQL')
43
+ .buildReadQuery();
44
+
45
+ // => SELECT `Title`, `Author`, `PublishedYear` FROM `Books`;
46
+ ```
47
+
48
+ ### Single column as string
49
+
50
+ ```javascript
51
+ tmpQuery.setDataElements('Title');
52
+ // Automatically converted to ['Title']
53
+ ```
54
+
55
+ ### Column aliases
56
+
57
+ Pass an array pair `[column, alias]` to create a column alias:
58
+
59
+ ```javascript
60
+ tmpQuery
61
+ .setScope('Books')
62
+ .setDataElements([
63
+ ['Books.Title', 'BookTitle'],
64
+ ['Books.Author', 'AuthorName']
65
+ ])
66
+ .setDialect('MySQL')
67
+ .buildReadQuery();
68
+
69
+ // => SELECT `Books`.`Title` AS `BookTitle`, `Books`.`Author` AS `AuthorName`
70
+ // FROM `Books`;
71
+ ```
72
+
73
+ ### Wildcard with specific columns
74
+
75
+ ```javascript
76
+ tmpQuery
77
+ .setScope('Books')
78
+ .setDataElements(['*', 'Authors.Name'])
79
+ .setDialect('PostgreSQL')
80
+ .buildReadQuery();
81
+
82
+ // => SELECT *, "Authors"."Name" FROM "Books";
83
+ ```
84
+
85
+ ### Table-qualified wildcard
86
+
87
+ ```javascript
88
+ tmpQuery
89
+ .setScope('Books')
90
+ .setDataElements(['Books.*', 'Authors.Name'])
91
+ .setDialect('PostgreSQL')
92
+ .buildReadQuery();
93
+
94
+ // => SELECT "Books".*, "Authors"."Name" FROM "Books";
95
+ ```
@@ -0,0 +1,78 @@
1
+ # setDialect
2
+
3
+ Set the SQL dialect used for query generation.
4
+
5
+ ## Signature
6
+
7
+ ```javascript
8
+ tmpQuery.setDialect(pDialectName)
9
+ ```
10
+
11
+ ## Parameters
12
+
13
+ | Parameter | Type | Required | Description |
14
+ |-----------|------|----------|-------------|
15
+ | `pDialectName` | String | Yes | Name of the dialect |
16
+
17
+ ## Returns
18
+
19
+ Returns `this` for chaining.
20
+
21
+ ## Available Dialects
22
+
23
+ | Name | Target Database |
24
+ |------|----------------|
25
+ | `'MySQL'` | MySQL / MariaDB |
26
+ | `'PostgreSQL'` | PostgreSQL 9.5+ |
27
+ | `'MSSQL'` | Microsoft SQL Server |
28
+ | `'SQLite'` | SQLite 3 |
29
+ | `'ALASQL'` | ALASQL (in-memory JavaScript) |
30
+ | `'English'` | Human-readable text (default) |
31
+ | `'MeadowEndpoints'` | REST URL generation |
32
+ | `'MongoDB'` | MongoDB query objects |
33
+ | `'DGraph'` | DGraph graph queries |
34
+ | `'Solr'` | Apache Solr search |
35
+
36
+ ## Description
37
+
38
+ The dialect determines how FoxHound translates the internal query parameters into database-specific syntax. This includes identifier quoting, parameter prefixes, pagination syntax, timestamp functions, and auto-identity handling.
39
+
40
+ If an invalid dialect name is passed, FoxHound logs an error and falls back to the `English` dialect.
41
+
42
+ ## Examples
43
+
44
+ ### Basic usage
45
+
46
+ ```javascript
47
+ tmpQuery.setDialect('MySQL');
48
+ ```
49
+
50
+ ### Same query, different dialects
51
+
52
+ ```javascript
53
+ var tmpQuery = libFoxHound.new(_Fable)
54
+ .setScope('Books')
55
+ .addFilter('Genre', 'Fantasy')
56
+ .setCap(10);
57
+
58
+ tmpQuery.setDialect('MySQL').buildReadQuery();
59
+ console.log(tmpQuery.query.body);
60
+ // => SELECT `Books`.* FROM `Books` WHERE `Books`.`Genre` = :Genre_w0 LIMIT 10;
61
+
62
+ tmpQuery.setDialect('PostgreSQL').buildReadQuery();
63
+ console.log(tmpQuery.query.body);
64
+ // => SELECT "Books".* FROM "Books" WHERE "Genre" = :Genre_w0 LIMIT 10;
65
+
66
+ tmpQuery.setDialect('MSSQL').buildReadQuery();
67
+ console.log(tmpQuery.query.body);
68
+ // => SELECT [Books].* FROM [Books] WHERE Genre = @Genre_w0
69
+ // OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;
70
+ ```
71
+
72
+ ### Checking the active dialect
73
+
74
+ ```javascript
75
+ tmpQuery.setDialect('PostgreSQL');
76
+ console.log(tmpQuery.dialect.name);
77
+ // => 'PostgreSQL'
78
+ ```
@@ -0,0 +1,76 @@
1
+ # setDistinct
2
+
3
+ Enable or disable DISTINCT result filtering.
4
+
5
+ ## Signature
6
+
7
+ ```javascript
8
+ tmpQuery.setDistinct(pDistinct)
9
+ ```
10
+
11
+ ## Parameters
12
+
13
+ | Parameter | Type | Required | Description |
14
+ |-----------|------|----------|-------------|
15
+ | `pDistinct` | Boolean | Yes | `true` to enable DISTINCT |
16
+
17
+ ## Returns
18
+
19
+ Returns `this` for chaining.
20
+
21
+ ## Description
22
+
23
+ When enabled, the generated SELECT statement includes the `DISTINCT` keyword to return only unique rows.
24
+
25
+ For Count queries with DISTINCT, FoxHound counts distinct values of the selected field list (or the AutoIdentity column from the schema if no specific fields are set).
26
+
27
+ ## Examples
28
+
29
+ ### DISTINCT select
30
+
31
+ ```javascript
32
+ tmpQuery
33
+ .setScope('Books')
34
+ .setDataElements(['Genre'])
35
+ .setDistinct(true)
36
+ .setDialect('MySQL')
37
+ .buildReadQuery();
38
+
39
+ // => SELECT DISTINCT `Genre` FROM `Books`;
40
+ ```
41
+
42
+ ### DISTINCT count
43
+
44
+ ```javascript
45
+ tmpQuery
46
+ .setScope('Books')
47
+ .setDataElements(['Author'])
48
+ .setDistinct(true)
49
+ .setDialect('MySQL')
50
+ .buildCountQuery();
51
+
52
+ // => SELECT COUNT(DISTINCT `Author`) AS RowCount FROM `Books`;
53
+ ```
54
+
55
+ ### DISTINCT count with schema (no explicit fields)
56
+
57
+ ```javascript
58
+ tmpQuery
59
+ .setScope('Books')
60
+ .setDistinct(true);
61
+
62
+ tmpQuery.query.schema = [
63
+ {Column: 'IDBook', Type: 'AutoIdentity'},
64
+ {Column: 'Title', Type: 'String'}
65
+ ];
66
+
67
+ tmpQuery.setDialect('MySQL').buildCountQuery();
68
+
69
+ // => SELECT COUNT(DISTINCT `Books`.`IDBook`) AS RowCount FROM `Books`;
70
+ ```
71
+
72
+ ### Disable DISTINCT
73
+
74
+ ```javascript
75
+ tmpQuery.setDistinct(false);
76
+ ```
@@ -0,0 +1,80 @@
1
+ # setIDUser
2
+
3
+ Set the user ID for automatic audit column stamping.
4
+
5
+ ## Signature
6
+
7
+ ```javascript
8
+ tmpQuery.setIDUser(pIDUser)
9
+ ```
10
+
11
+ ## Parameters
12
+
13
+ | Parameter | Type | Required | Description |
14
+ |-----------|------|----------|-------------|
15
+ | `pIDUser` | Integer | Yes | User ID (must be >= 0) |
16
+
17
+ ## Returns
18
+
19
+ Returns `this` for chaining.
20
+
21
+ ## Description
22
+
23
+ Sets the user ID that FoxHound uses when auto-populating audit columns in schema-aware queries. This value is applied to:
24
+
25
+ - `CreateIDUser` columns on INSERT
26
+ - `UpdateIDUser` columns on INSERT and UPDATE
27
+ - `DeleteIDUser` columns on soft DELETE
28
+
29
+ The value defaults to `0` if not set.
30
+
31
+ ## Examples
32
+
33
+ ### Basic usage
34
+
35
+ ```javascript
36
+ tmpQuery
37
+ .setScope('Books')
38
+ .addRecord({Title: 'Dune', Author: 'Frank Herbert'})
39
+ .setIDUser(42);
40
+
41
+ tmpQuery.query.schema = [
42
+ {Column: 'IDBook', Type: 'AutoIdentity'},
43
+ {Column: 'Title', Type: 'String'},
44
+ {Column: 'Author', Type: 'String'},
45
+ {Column: 'CreatingIDUser', Type: 'CreateIDUser'},
46
+ {Column: 'UpdatingIDUser', Type: 'UpdateIDUser'}
47
+ ];
48
+
49
+ tmpQuery.setDialect('MySQL').buildCreateQuery();
50
+
51
+ // CreatingIDUser => 42
52
+ // UpdatingIDUser => 42
53
+ ```
54
+
55
+ ### With soft delete
56
+
57
+ ```javascript
58
+ tmpQuery
59
+ .setScope('Books')
60
+ .addFilter('IDBook', 99)
61
+ .setIDUser(5);
62
+
63
+ tmpQuery.query.schema = [
64
+ {Column: 'IDBook', Type: 'AutoIdentity'},
65
+ {Column: 'Deleted', Type: 'Deleted'},
66
+ {Column: 'DeleteDate', Type: 'DeleteDate'},
67
+ {Column: 'DeletingIDUser', Type: 'DeleteIDUser'},
68
+ {Column: 'UpdateDate', Type: 'UpdateDate'}
69
+ ];
70
+
71
+ tmpQuery.setDialect('MySQL').buildDeleteQuery();
72
+
73
+ // DeletingIDUser => 5
74
+ ```
75
+
76
+ ### Alternative: direct property access
77
+
78
+ ```javascript
79
+ tmpQuery.query.IDUser = 42;
80
+ ```
@@ -0,0 +1,70 @@
1
+ # setScope
2
+
3
+ Set the primary table or collection for the query.
4
+
5
+ ## Signature
6
+
7
+ ```javascript
8
+ tmpQuery.setScope(pScope)
9
+ ```
10
+
11
+ ## Parameters
12
+
13
+ | Parameter | Type | Required | Description |
14
+ |-----------|------|----------|-------------|
15
+ | `pScope` | String | Yes | Table or collection name |
16
+
17
+ ## Returns
18
+
19
+ Returns `this` for chaining.
20
+
21
+ ## Description
22
+
23
+ The scope defines which table (or collection, in NoSQL dialects) the query targets. This is required for all query types — it appears as the `FROM` clause in SELECT, `INSERT INTO` in CREATE, `UPDATE` in UPDATE, and `DELETE FROM` in DELETE.
24
+
25
+ FoxHound validates that the input is a string. Non-string values are ignored and an error is logged.
26
+
27
+ ## Examples
28
+
29
+ ### Basic usage
30
+
31
+ ```javascript
32
+ tmpQuery.setScope('Books');
33
+ ```
34
+
35
+ ### With dialect quoting
36
+
37
+ Each dialect quotes the scope name according to its conventions:
38
+
39
+ ```javascript
40
+ // MySQL
41
+ tmpQuery.setScope('Books').setDialect('MySQL').buildReadQuery();
42
+ // => SELECT `Books`.* FROM `Books`;
43
+
44
+ // PostgreSQL
45
+ tmpQuery.setScope('Books').setDialect('PostgreSQL').buildReadQuery();
46
+ // => SELECT "Books".* FROM "Books";
47
+
48
+ // MSSQL
49
+ tmpQuery.setScope('Books').setDialect('MSSQL').buildReadQuery();
50
+ // => SELECT [Books].* FROM [Books];
51
+ ```
52
+
53
+ ### Pre-quoted scope
54
+
55
+ If the scope is already quoted for your dialect, FoxHound preserves it:
56
+
57
+ ```javascript
58
+ tmpQuery.setScope('"MySchema"."Books"');
59
+ // PostgreSQL will use: "MySchema"."Books"
60
+ ```
61
+
62
+ ### Chaining
63
+
64
+ ```javascript
65
+ tmpQuery
66
+ .setScope('Books')
67
+ .setDataElements(['Title', 'Author'])
68
+ .setDialect('MySQL')
69
+ .buildReadQuery();
70
+ ```
@@ -4,36 +4,76 @@ FoxHound follows a clean separation between query configuration, dialect-specifi
4
4
 
5
5
  ## Overview
6
6
 
7
+ ```mermaid
8
+ graph TD
9
+ A[Application Code] -->|configure| B[FoxHound Core]
10
+ B -->|setDialect| C{Dialect Engine}
11
+ C -->|MySQL| D[MySQL Generator]
12
+ C -->|PostgreSQL| E[PostgreSQL Generator]
13
+ C -->|MSSQL| F[MSSQL Generator]
14
+ C -->|SQLite| G[SQLite Generator]
15
+ C -->|ALASQL| H[ALASQL Generator]
16
+ C -->|English| I[English Generator]
17
+ D --> J[Query Output]
18
+ E --> J
19
+ F --> J
20
+ G --> J
21
+ H --> J
22
+ I --> J
23
+ J -->|query.body| K[SQL String]
24
+ J -->|query.parameters| L[Bound Values]
7
25
  ```
8
- ┌─────────────────────────────────────┐
9
- │ Application Code │
10
- │ query.setScope('Books') │
11
- │ .addFilter('Genre','Sci-Fi') │
12
- │ .setDialect('MySQL') │
13
- │ .buildReadQuery() │
14
- └──────────────┬──────────────────────┘
15
-
16
- ┌──────────────▼──────────────────────┐
17
- │ FoxHound Core │
18
- │ - Parameters object (state)
19
- │ - Chainable configuration API │
20
- │ - Dialect selection & delegation │
21
- └──────────────┬──────────────────────┘
22
-
23
- ┌──────────────▼──────────────────────┐
24
- │ Dialect Engine │
25
- │ MySQL │ MSSQL │ SQLite │ ALASQL │
26
- │ - Generates SQL string │
27
- │ - Populates named parameters │
28
- │ - Applies schema-aware logic │
29
- └──────────────┬──────────────────────┘
30
-
31
- ┌──────────────▼──────────────────────┐
32
- │ Query Output │
33
- │ query.body → SQL string │
34
- │ query.parameters → bound values │
35
- │ query.schema → column metadata │
36
- └─────────────────────────────────────┘
26
+
27
+ ## Query Lifecycle
28
+
29
+ ```mermaid
30
+ sequenceDiagram
31
+ participant App as Application
32
+ participant FH as FoxHound
33
+ participant D as Dialect
34
+ participant P as Parameters
35
+
36
+ App->>FH: libFoxHound.new(_Fable)
37
+ FH->>P: Initialize Parameters
38
+ App->>FH: setScope('Books')
39
+ App->>FH: addFilter('Genre', 'Sci-Fi')
40
+ App->>FH: setDialect('MySQL')
41
+ App->>FH: buildReadQuery()
42
+ FH->>D: Read(parameters)
43
+ D->>D: generateFieldList()
44
+ D->>D: generateWhere()
45
+ D->>D: generateOrderBy()
46
+ D->>D: generateLimit()
47
+ D-->>FH: SQL string
48
+ FH->>P: Store in query.body
49
+ App->>FH: query.body
50
+ FH-->>App: SELECT `Books`.* FROM `Books` WHERE ...
51
+ ```
52
+
53
+ ## Component Architecture
54
+
55
+ ```mermaid
56
+ graph LR
57
+ subgraph FoxHound Core
58
+ A[FoxHound.js] --> B[Parameters.js]
59
+ A --> C[Foxhound-Dialects.js]
60
+ end
61
+
62
+ subgraph Dialect Modules
63
+ C --> D[MySQL]
64
+ C --> E[PostgreSQL]
65
+ C --> F[MSSQL]
66
+ C --> G[SQLite]
67
+ C --> H[ALASQL]
68
+ C --> I[English]
69
+ C --> J[MeadowEndpoints]
70
+ end
71
+
72
+ subgraph External
73
+ K[Fable] --> A
74
+ L[Meadow] --> A
75
+ M[Stricture] --> B
76
+ end
37
77
  ```
38
78
 
39
79
  ## Factory Pattern
@@ -70,12 +110,42 @@ All query state lives in a single `Parameters` object:
70
110
 
71
111
  Each dialect is a module that exports a factory function accepting a Fable instance. The returned object exposes six methods that each accept a Parameters object and return a SQL string:
72
112
 
73
- - `Create(pParameters)` — INSERT statement
74
- - `Read(pParameters)` — SELECT statement
75
- - `Update(pParameters)` — UPDATE statement
76
- - `Delete(pParameters)` — UPDATE (soft) or DELETE (hard)
77
- - `Undelete(pParameters)` — UPDATE to restore soft-deleted rows
78
- - `Count(pParameters)` — SELECT COUNT statement
113
+ ```mermaid
114
+ classDiagram
115
+ class Dialect {
116
+ +Create(pParameters) String
117
+ +Read(pParameters) String
118
+ +Update(pParameters) String
119
+ +Delete(pParameters) String
120
+ +Undelete(pParameters) String
121
+ +Count(pParameters) String
122
+ +name String
123
+ }
124
+
125
+ class MySQL {
126
+ +backtick quoting
127
+ +colon parameters
128
+ +NOW 3 timestamps
129
+ }
130
+
131
+ class PostgreSQL {
132
+ +double-quote quoting
133
+ +colon parameters
134
+ +NOW timestamps
135
+ +RETURNING clause
136
+ }
137
+
138
+ class MSSQL {
139
+ +bracket quoting
140
+ +at-sign parameters
141
+ +GETUTCDATE timestamps
142
+ +OFFSET FETCH pagination
143
+ }
144
+
145
+ Dialect <|-- MySQL
146
+ Dialect <|-- PostgreSQL
147
+ Dialect <|-- MSSQL
148
+ ```
79
149
 
80
150
  The dialect handles all syntax differences: quoting identifiers, parameter prefixes, pagination syntax, date functions, and identity column handling.
81
151
 
@@ -85,13 +155,13 @@ Every setter method returns `this`, enabling fluent composition:
85
155
 
86
156
  ```javascript
87
157
  tmpQuery
88
- .setScope('Orders')
89
- .setDataElements(['OrderID', 'Total', 'Status'])
90
- .addFilter('Status', 'Pending')
91
- .addSort({Column: 'Total', Direction: 'Descending'})
92
- .setCap(50)
93
- .setDialect('MySQL')
94
- .buildReadQuery();
158
+ .setScope('Orders')
159
+ .setDataElements(['OrderID', 'Total', 'Status'])
160
+ .addFilter('Status', 'Pending')
161
+ .addSort({Column: 'Total', Direction: 'Descending'})
162
+ .setCap(50)
163
+ .setDialect('MySQL')
164
+ .buildReadQuery();
95
165
  ```
96
166
 
97
167
  ## Fable Integration
@@ -102,3 +172,25 @@ FoxHound depends on Fable for:
102
172
  - **Logging** — filter, scope, and query errors are logged through `_Fable.log`
103
173
  - **Utility Functions** — `_Fable.Utility.extend()` for parameter merging and `_Fable.Utility.template()` for query overrides
104
174
  - **Configuration** — inherits any relevant settings from the Fable config
175
+
176
+ ## Schema-Aware Generation
177
+
178
+ ```mermaid
179
+ flowchart TD
180
+ A[Record Object] --> B{Schema Attached?}
181
+ B -->|No| C[All columns parameterized]
182
+ B -->|Yes| D[Check each column type]
183
+ D --> E{AutoIdentity?}
184
+ E -->|Yes| F[NULL / DEFAULT / Skip]
185
+ D --> G{CreateDate?}
186
+ G -->|Yes| H[NOW timestamp]
187
+ D --> I{Deleted?}
188
+ I -->|Yes| J[Auto-filter on Read]
189
+ D --> K{Default?}
190
+ K -->|Yes| L[Parameterized value]
191
+ C --> M[Generate SQL]
192
+ F --> M
193
+ H --> M
194
+ J --> M
195
+ L --> M
196
+ ```
@@ -7,6 +7,7 @@ FoxHound uses a dialect strategy pattern to generate database-specific SQL from
7
7
  | Dialect | Target | Identifier Quoting | Parameter Prefix | Pagination |
8
8
  |---------|--------|-------------------|-----------------|------------|
9
9
  | [MySQL](dialects/mysql.md) | MySQL / MariaDB | `` `backticks` `` | `:name` | `LIMIT offset, count` |
10
+ | [PostgreSQL](dialects/postgresql.md) | PostgreSQL 9.5+ | `"double quotes"` | `:name` | `LIMIT count OFFSET offset` |
10
11
  | [MSSQL](dialects/mssql.md) | Microsoft SQL Server | `[brackets]` | `@name` | `OFFSET n ROWS FETCH NEXT m ROWS ONLY` |
11
12
  | [SQLite](dialects/sqlite.md) | SQLite 3 | `` `backticks` `` | `:name` | `LIMIT count OFFSET offset` |
12
13
  | [ALASQL](dialects/alasql.md) | ALASQL (in-memory) | `` `backticks` `` | `:name` | `LIMIT count FETCH offset` |
@@ -54,6 +55,7 @@ All SQL dialects share these behaviors:
54
55
  | Use Case | Recommended Dialect |
55
56
  |----------|-------------------|
56
57
  | Production MySQL/MariaDB | `MySQL` |
58
+ | Production PostgreSQL | `PostgreSQL` |
57
59
  | Production SQL Server | `MSSQL` |
58
60
  | Embedded/file-based database | `SQLite` |
59
61
  | Browser-side or in-memory queries | `ALASQL` |