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,126 @@
1
+ # PostgreSQL Dialect
2
+
3
+ The PostgreSQL dialect generates SQL compatible with PostgreSQL 9.5 and later.
4
+
5
+ ## Identifier Quoting
6
+
7
+ PostgreSQL uses double-quote quoting for identifiers, which preserves case sensitivity. Without double quotes, PostgreSQL folds all identifiers to lowercase. FoxHound quotes all column and table names to ensure case-sensitive operation:
8
+
9
+ ```sql
10
+ SELECT "Title", "Author" FROM "Books" WHERE "Genre" = :Genre_w0;
11
+ ```
12
+
13
+ Table-qualified field names are quoted on each segment:
14
+
15
+ ```sql
16
+ "Books"."Title"
17
+ ```
18
+
19
+ ## Named Parameters
20
+
21
+ The PostgreSQL dialect uses `:name` syntax for named parameters:
22
+
23
+ ```sql
24
+ INSERT INTO "Books" ( "Title", "Author") VALUES ( :Title_0, :Author_1);
25
+ ```
26
+
27
+ The bound values are stored in `query.parameters` as a plain object:
28
+
29
+ ```javascript
30
+ { Title_0: 'Dune', Author_1: 'Frank Herbert' }
31
+ ```
32
+
33
+ ## Timestamp Function
34
+
35
+ PostgreSQL uses `NOW()` for timestamp generation. Unlike MySQL's `NOW(3)`, PostgreSQL's `NOW()` natively provides microsecond precision.
36
+
37
+ ## Pagination
38
+
39
+ PostgreSQL uses `LIMIT ... OFFSET` syntax:
40
+
41
+ ```sql
42
+ -- Cap only
43
+ SELECT "Books".* FROM "Books" LIMIT 20;
44
+
45
+ -- Cap with offset
46
+ SELECT "Books".* FROM "Books" LIMIT 20 OFFSET 40;
47
+ ```
48
+
49
+ ## AutoIdentity on INSERT
50
+
51
+ The PostgreSQL dialect uses `DEFAULT` for AutoIdentity columns on INSERT, allowing PostgreSQL `SERIAL` or `IDENTITY` columns to auto-assign values:
52
+
53
+ ```sql
54
+ INSERT INTO "Books" ( "IDBook", "Title") VALUES ( DEFAULT, :Title_1) RETURNING *;
55
+ ```
56
+
57
+ ## RETURNING Clause
58
+
59
+ All INSERT statements include `RETURNING *`, which returns the full inserted row — including any auto-generated values like serial IDs and default timestamps.
60
+
61
+ ## Joins
62
+
63
+ ```sql
64
+ INNER JOIN Authors ON Authors.IDAuthor = Books.IDAuthor
65
+ LEFT JOIN Publishers ON Publishers.IDPublisher = Books.IDPublisher
66
+ ```
67
+
68
+ ## DISTINCT
69
+
70
+ ```sql
71
+ SELECT DISTINCT "Genre" FROM "Books";
72
+ SELECT COUNT(DISTINCT "Books"."IDBook") AS RowCount FROM "Books";
73
+ ```
74
+
75
+ ## Case Sensitivity
76
+
77
+ PostgreSQL treats unquoted identifiers as case-insensitive (folded to lowercase). The FoxHound PostgreSQL dialect wraps all column and table names in double quotes to preserve the exact case of your schema definitions. This is important when your schema uses mixed-case column names like `IDBook`, `CreateDate`, or `UpdatingIDUser`.
78
+
79
+ If your PostgreSQL tables were created with quoted identifiers:
80
+
81
+ ```sql
82
+ CREATE TABLE "Books" (
83
+ "IDBook" SERIAL PRIMARY KEY,
84
+ "Title" VARCHAR(255),
85
+ "PublishedYear" INTEGER
86
+ );
87
+ ```
88
+
89
+ Then FoxHound's quoted queries will match these column names correctly.
90
+
91
+ ## Soft Delete
92
+
93
+ When a schema has a `Deleted` column type, the Delete operation generates an UPDATE:
94
+
95
+ ```sql
96
+ UPDATE "Books" SET "Deleted" = 1, "DeleteDate" = NOW(),
97
+ "UpdateDate" = NOW(), "DeleteIDUser" = :DeleteIDUser_3
98
+ WHERE "IDBook" = :IDBook_w0;
99
+ ```
100
+
101
+ ## Query Overrides
102
+
103
+ The PostgreSQL dialect supports underscore-style templates for Read and Count queries:
104
+
105
+ | Variable | Description |
106
+ |----------|-------------|
107
+ | `<%= FieldList %>` | Generated column list with double-quote quoting |
108
+ | `<%= TableName %>` | Table name with double-quote quoting |
109
+ | `<%= Where %>` | WHERE clause (including the keyword) |
110
+ | `<%= Join %>` | JOIN clauses |
111
+ | `<%= OrderBy %>` | ORDER BY clause |
112
+ | `<%= Limit %>` | LIMIT/OFFSET clause |
113
+ | `<%= Distinct %>` | DISTINCT keyword (if set) |
114
+ | `<%= _Params %>` | Full parameters object |
115
+
116
+ ## Comparison with Other Dialects
117
+
118
+ | Feature | PostgreSQL | MySQL | MSSQL |
119
+ |---------|-----------|-------|-------|
120
+ | Identifier quoting | `"double quotes"` | `` `backticks` `` | `[brackets]` |
121
+ | Parameter prefix | `:name` | `:name` | `@name` |
122
+ | Timestamp function | `NOW()` | `NOW(3)` | `GETUTCDATE()` |
123
+ | AutoIdentity INSERT | `DEFAULT` | `NULL` | column omitted |
124
+ | INSERT return | `RETURNING *` | none | none |
125
+ | Pagination | `LIMIT n OFFSET m` | `LIMIT m, n` | `OFFSET m ROWS FETCH NEXT n ROWS ONLY` |
126
+ | Case sensitivity | case-sensitive (quoted) | case-insensitive | case-insensitive |
@@ -0,0 +1,196 @@
1
+ # Quickstart
2
+
3
+ Get up and running with FoxHound in under five minutes.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install foxhound fable
9
+ ```
10
+
11
+ FoxHound requires [Fable](https://github.com/stevenvelozo/fable) as a peer dependency for logging, UUID generation, and utility functions.
12
+
13
+ ## Your First Query
14
+
15
+ ```javascript
16
+ var libFable = require('fable');
17
+ var libFoxHound = require('foxhound');
18
+
19
+ // Create a Fable instance (provides logging, UUIDs, and utilities)
20
+ var _Fable = new libFable({Product: 'MyApp'});
21
+
22
+ // Create a new FoxHound query
23
+ var tmpQuery = libFoxHound.new(_Fable);
24
+
25
+ // Build a simple SELECT
26
+ tmpQuery
27
+ .setScope('Books')
28
+ .setDialect('MySQL')
29
+ .buildReadQuery();
30
+
31
+ console.log(tmpQuery.query.body);
32
+ // => SELECT `Books`.* FROM `Books`;
33
+ ```
34
+
35
+ ## Selecting Specific Columns
36
+
37
+ ```javascript
38
+ var tmpQuery = libFoxHound.new(_Fable)
39
+ .setDialect('MySQL')
40
+ .setScope('Books')
41
+ .setDataElements(['Title', 'Author', 'PublishedYear'])
42
+ .buildReadQuery();
43
+
44
+ console.log(tmpQuery.query.body);
45
+ // => SELECT `Title`, `Author`, `PublishedYear` FROM `Books`;
46
+ ```
47
+
48
+ ## Adding Filters
49
+
50
+ ```javascript
51
+ var tmpQuery = libFoxHound.new(_Fable)
52
+ .setDialect('MySQL')
53
+ .setScope('Books')
54
+ .setDataElements(['Title', 'Author'])
55
+ .addFilter('Genre', 'Science Fiction')
56
+ .addFilter('PublishedYear', 2000, '>')
57
+ .buildReadQuery();
58
+
59
+ console.log(tmpQuery.query.body);
60
+ // => SELECT `Title`, `Author` FROM `Books`
61
+ // WHERE `Books`.`Genre` = :Genre_w0
62
+ // AND `Books`.`PublishedYear` > :PublishedYear_w1;
63
+
64
+ console.log(tmpQuery.query.parameters);
65
+ // => { Genre_w0: 'Science Fiction', PublishedYear_w1: 2000 }
66
+ ```
67
+
68
+ ## Sorting and Pagination
69
+
70
+ ```javascript
71
+ var tmpQuery = libFoxHound.new(_Fable)
72
+ .setDialect('MySQL')
73
+ .setScope('Books')
74
+ .addSort({Column: 'PublishedYear', Direction: 'Descending'})
75
+ .setCap(25)
76
+ .setBegin(0)
77
+ .buildReadQuery();
78
+
79
+ console.log(tmpQuery.query.body);
80
+ // => SELECT `Books`.* FROM `Books`
81
+ // ORDER BY PublishedYear DESC LIMIT 0, 25;
82
+ ```
83
+
84
+ ## Creating a Record
85
+
86
+ ```javascript
87
+ var tmpQuery = libFoxHound.new(_Fable)
88
+ .setDialect('MySQL')
89
+ .setScope('Books')
90
+ .addRecord({Title: 'Dune', Author: 'Frank Herbert', PublishedYear: 1965})
91
+ .buildCreateQuery();
92
+
93
+ console.log(tmpQuery.query.body);
94
+ // => INSERT INTO `Books` ( Title, Author, PublishedYear)
95
+ // VALUES ( :Title_0, :Author_1, :PublishedYear_2);
96
+
97
+ console.log(tmpQuery.query.parameters);
98
+ // => { Title_0: 'Dune', Author_1: 'Frank Herbert', PublishedYear_2: 1965 }
99
+ ```
100
+
101
+ ## Updating a Record
102
+
103
+ ```javascript
104
+ var tmpQuery = libFoxHound.new(_Fable)
105
+ .setDialect('MySQL')
106
+ .setScope('Books')
107
+ .addFilter('IDBook', 42)
108
+ .addRecord({Title: 'Dune Messiah', PublishedYear: 1969})
109
+ .buildUpdateQuery();
110
+
111
+ console.log(tmpQuery.query.body);
112
+ // => UPDATE `Books` SET Title = :Title_0, PublishedYear = :PublishedYear_1
113
+ // WHERE IDBook = :IDBook_w0;
114
+ ```
115
+
116
+ ## Deleting a Record
117
+
118
+ ```javascript
119
+ var tmpQuery = libFoxHound.new(_Fable)
120
+ .setDialect('MySQL')
121
+ .setScope('Books')
122
+ .addFilter('IDBook', 42)
123
+ .buildDeleteQuery();
124
+
125
+ console.log(tmpQuery.query.body);
126
+ // => DELETE FROM `Books` WHERE IDBook = :IDBook_w0;
127
+ ```
128
+
129
+ ## Switching Dialects
130
+
131
+ The same query configuration works across all dialects:
132
+
133
+ ```javascript
134
+ var tmpQuery = libFoxHound.new(_Fable)
135
+ .setScope('Books')
136
+ .setDataElements(['Title', 'Author'])
137
+ .addFilter('Genre', 'Fantasy')
138
+ .setCap(10);
139
+
140
+ // MySQL
141
+ tmpQuery.setDialect('MySQL').buildReadQuery();
142
+ console.log(tmpQuery.query.body);
143
+ // => SELECT `Title`, `Author` FROM `Books`
144
+ // WHERE `Books`.`Genre` = :Genre_w0 LIMIT 10;
145
+
146
+ // PostgreSQL
147
+ tmpQuery.setDialect('PostgreSQL').buildReadQuery();
148
+ console.log(tmpQuery.query.body);
149
+ // => SELECT "Title", "Author" FROM "Books"
150
+ // WHERE "Genre" = :Genre_w0 LIMIT 10;
151
+
152
+ // MSSQL
153
+ tmpQuery.setDialect('MSSQL').buildReadQuery();
154
+ console.log(tmpQuery.query.body);
155
+ // => SELECT [Title], [Author] FROM [Books]
156
+ // WHERE Genre = @Genre_w0 OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;
157
+ ```
158
+
159
+ ## Using with a Schema
160
+
161
+ Attaching a schema enables automatic management of identity, timestamp, and soft-delete columns:
162
+
163
+ ```javascript
164
+ var tmpQuery = libFoxHound.new(_Fable)
165
+ .setDialect('MySQL')
166
+ .setScope('Books')
167
+ .addRecord({IDBook: null, Title: 'Neuromancer', Author: 'William Gibson'});
168
+
169
+ tmpQuery.query.schema = [
170
+ {Column: 'IDBook', Type: 'AutoIdentity'},
171
+ {Column: 'Title', Type: 'String'},
172
+ {Column: 'Author', Type: 'String'},
173
+ {Column: 'CreateDate', Type: 'CreateDate'},
174
+ {Column: 'CreatingIDUser', Type: 'CreateIDUser'},
175
+ {Column: 'UpdateDate', Type: 'UpdateDate'},
176
+ {Column: 'UpdatingIDUser', Type: 'UpdateIDUser'},
177
+ {Column: 'Deleted', Type: 'Deleted'},
178
+ {Column: 'DeleteDate', Type: 'DeleteDate'},
179
+ {Column: 'DeletingIDUser', Type: 'DeleteIDUser'}
180
+ ];
181
+ tmpQuery.query.IDUser = 5;
182
+
183
+ tmpQuery.buildCreateQuery();
184
+
185
+ console.log(tmpQuery.query.body);
186
+ // => INSERT INTO `Books` ( IDBook, Title, Author, CreateDate, ...)
187
+ // VALUES ( NULL, :Title_1, :Author_2, NOW(3), ...);
188
+ ```
189
+
190
+ ## Next Steps
191
+
192
+ - [Architecture](architecture.md) — understand FoxHound's internal design
193
+ - [Filters](filters.md) — learn about filter operators and grouping
194
+ - [Schema Integration](schema.md) — use schemas for automatic column management
195
+ - [Dialects](dialects/README.md) — explore dialect-specific features
196
+ - [API Reference](api/README.md) — complete function reference
@@ -1,5 +1,5 @@
1
1
  {
2
- "Generated": "2026-02-18T01:02:40.710Z",
2
+ "Generated": "2026-03-03T14:33:09.873Z",
3
3
  "GitHubOrg": "stevenvelozo",
4
4
  "DefaultBranch": "master",
5
5
  "Groups": [
@@ -69,6 +69,44 @@
69
69
  "Key": "docs",
70
70
  "Description": "",
71
71
  "Modules": [
72
+ {
73
+ "Name": "api",
74
+ "Repo": "api",
75
+ "Group": "docs",
76
+ "Branch": "master",
77
+ "HasDocs": true,
78
+ "HasCover": false,
79
+ "Sidebar": [],
80
+ "DocFiles": [
81
+ "api/README.md",
82
+ "api/addFilter.md",
83
+ "api/addJoin.md",
84
+ "api/addRecord.md",
85
+ "api/addSort.md",
86
+ "api/behaviorFlags.md",
87
+ "api/buildQuery.md",
88
+ "api/clone.md",
89
+ "api/queryOverrides.md",
90
+ "api/setCap.md",
91
+ "api/setDataElements.md",
92
+ "api/setDialect.md",
93
+ "api/setDistinct.md",
94
+ "api/setIDUser.md",
95
+ "api/setScope.md"
96
+ ]
97
+ },
98
+ {
99
+ "Name": "css",
100
+ "Repo": "css",
101
+ "Group": "docs",
102
+ "Branch": "master",
103
+ "HasDocs": true,
104
+ "HasCover": false,
105
+ "Sidebar": [],
106
+ "DocFiles": [
107
+ "css/docuserve.css"
108
+ ]
109
+ },
72
110
  {
73
111
  "Name": "dialects",
74
112
  "Repo": "dialects",
@@ -82,6 +120,7 @@
82
120
  "dialects/alasql.md",
83
121
  "dialects/mssql.md",
84
122
  "dialects/mysql.md",
123
+ "dialects/postgresql.md",
85
124
  "dialects/sqlite.md"
86
125
  ]
87
126
  },