squel 5.13.0 → 6.0.2
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/CHANGELOG.md +28 -1
- package/README.md +159 -186
- package/dist/browser/squel.min.js +1 -0
- package/dist/cjs/index.js +1814 -0
- package/dist/cjs/index.js.map +14 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/index.js +1783 -0
- package/dist/esm/index.js.map +14 -0
- package/dist/esm/package.json +1 -0
- package/dist/types/core.d.ts +12 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/mssql.d.ts +2 -0
- package/dist/types/mssql.d.ts.map +1 -0
- package/dist/types/mysql.d.ts +2 -0
- package/dist/types/mysql.d.ts.map +1 -0
- package/dist/types/postgres.d.ts +2 -0
- package/dist/types/postgres.d.ts.map +1 -0
- package/dist/types/types.d.ts +206 -0
- package/dist/types/types.d.ts.map +1 -0
- package/package.json +61 -41
- package/CONTRIBUTING.md +0 -28
- package/RELEASE.md +0 -13
- package/dist/squel-basic.js +0 -3067
- package/dist/squel-basic.min.js +0 -2
- package/dist/squel.d.ts +0 -1750
- package/dist/squel.js +0 -3982
- package/dist/squel.min.js +0 -2
- package/gulpfile.js +0 -117
- package/performance/select.js +0 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,31 @@
|
|
|
1
|
-
# Changelog
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
|
+
|
|
5
|
+
## [6.0.2](https://github.com/hiddentao/squel/compare/v6.0.1...v6.0.2) (2026-04-14)
|
|
6
|
+
|
|
7
|
+
## 6.0.1 (2026-04-14)
|
|
8
|
+
|
|
9
|
+
## 6.0.0
|
|
10
|
+
|
|
11
|
+
This is a modernization release. The public API is unchanged — existing calls to `squel.select()`, `squel.useFlavour("postgres")`, and friends continue to work.
|
|
12
|
+
|
|
13
|
+
### Breaking Changes
|
|
14
|
+
|
|
15
|
+
* `engines.node` raised to `>=18` (from `>=0.12`).
|
|
16
|
+
* Package shape changed: the `squel.js` / `squel.min.js` / `squel-basic.js` / `squel-basic.min.js` UMD bundles are replaced by `dist/esm/`, `dist/cjs/`, and `dist/browser/squel.min.js` (IIFE for CDN / script tags).
|
|
17
|
+
* The separate "basic" bundle is gone — the main entry contains all flavours. ESM tree-shaking removes unused flavours for bundler users.
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
* Source rewritten in TypeScript with first-class type declarations generated from source (no more hand-maintained `.d.ts`).
|
|
22
|
+
* Dual CJS + ESM output with conditional `exports` map.
|
|
23
|
+
* Biome for lint + format; Bun as the toolchain; bun:test for tests.
|
|
24
|
+
* GitHub Actions CI and automated releases on `master` via commit-and-tag-version with npm provenance.
|
|
25
|
+
* Conventional Commits enforced via husky + commitlint.
|
|
26
|
+
|
|
27
|
+
## 28 Jul 2020 (5.13.1)
|
|
28
|
+
* Deprecate in NPM (#384)
|
|
2
29
|
|
|
3
30
|
## 18 Jun 2019 (5.13.0)
|
|
4
31
|
* Added note to top of README stating that Squel is no longer actively maintained.
|
package/README.md
CHANGED
|
@@ -1,55 +1,87 @@
|
|
|
1
|
-
#
|
|
1
|
+
# squel — SQL query string builder
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/hiddentao/squel/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/squel)
|
|
5
|
+
[](https://www.npmjs.com/package/squel)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
[](https://cdnjs.com/libraries/squel)
|
|
7
|
-
[](https://badge.fury.io/js/squel)
|
|
8
|
-
[](https://www.npmjs.com/package/squel)
|
|
9
|
-
[](https://discord.gg/PBAR2Bz)
|
|
10
|
-
[](https://twitter.com/hiddentao)
|
|
9
|
+
A flexible and powerful SQL query string builder for JavaScript and TypeScript.
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Full documentation (guide and API) at [https://hiddentao.github.io/squel](https://hiddentao.github.io/squel).
|
|
11
|
+
Full guide and API documentation at [https://hiddentao.github.io/squel](https://hiddentao.github.io/squel).
|
|
15
12
|
|
|
16
13
|
## Features
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
- Written in TypeScript with first-class type definitions.
|
|
16
|
+
- Works in Node.js and the browser.
|
|
17
|
+
- Supports the standard SQL queries: `SELECT`, `UPDATE`, `INSERT`, `DELETE`.
|
|
18
|
+
- Supports non-standard commands for MySQL, PostgreSQL, and Microsoft SQL Server.
|
|
19
|
+
- Supports parameterized queries for safe value escaping.
|
|
20
|
+
- Extensible — build any custom query or command you need.
|
|
21
|
+
- Fluent method-chaining API.
|
|
22
|
+
- Ships as dual ESM + CommonJS with a minified IIFE bundle for CDN use.
|
|
26
23
|
|
|
27
|
-
**
|
|
24
|
+
> **Warning:** Do not ever pass queries generated on the client side to your web server for execution. Such a configuration would make it trivial for a casual attacker to execute arbitrary queries — as with an SQL-injection vector, but much easier to exploit and practically impossible to protect against.
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
actively developed alternatives such as [Knex](http://knexjs.org/)_
|
|
26
|
+
Squel is suitable for production use. If you want richer ORM features you may also want to consider [Knex](https://knexjs.org/).
|
|
31
27
|
|
|
32
28
|
## Installation
|
|
33
29
|
|
|
34
|
-
Install using [npm](http://npmjs.org/):
|
|
35
|
-
|
|
36
30
|
```bash
|
|
37
|
-
|
|
31
|
+
# npm
|
|
32
|
+
npm install squel
|
|
33
|
+
|
|
34
|
+
# bun
|
|
35
|
+
bun add squel
|
|
36
|
+
|
|
37
|
+
# yarn
|
|
38
|
+
yarn add squel
|
|
39
|
+
|
|
40
|
+
# pnpm
|
|
41
|
+
pnpm add squel
|
|
38
42
|
```
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
Squel requires Node.js 18 or newer.
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
* `squel.min.js` - minified version of `squel.js`
|
|
44
|
-
* `squel-basic.js` - unminified version of Squel with only the standard SQL commands
|
|
45
|
-
* `squel-basic.min.js` - minified version of `squel-basic.js`
|
|
46
|
+
## Usage
|
|
46
47
|
|
|
48
|
+
### ESM / TypeScript
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
```typescript
|
|
51
|
+
import squel from "squel"
|
|
52
|
+
|
|
53
|
+
const query = squel.select().from("books").field("title").toString()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### CommonJS
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
const squel = require("squel").default
|
|
60
|
+
// or: const { squel } = require("squel")
|
|
61
|
+
|
|
62
|
+
const query = squel.select().from("books").field("title").toString()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Browser (CDN)
|
|
66
|
+
|
|
67
|
+
```html
|
|
68
|
+
<script src="https://unpkg.com/squel/dist/browser/squel.min.js"></script>
|
|
69
|
+
<script>
|
|
70
|
+
// `squel` is available on the global scope
|
|
71
|
+
const query = squel.select().from("books").field("title").toString()
|
|
72
|
+
</script>
|
|
73
|
+
```
|
|
49
74
|
|
|
50
|
-
|
|
75
|
+
## Package layout
|
|
51
76
|
|
|
52
|
-
|
|
77
|
+
The published package contains:
|
|
78
|
+
|
|
79
|
+
- `dist/esm/` — ES module build (`import squel from "squel"`).
|
|
80
|
+
- `dist/cjs/` — CommonJS build (`require("squel")`).
|
|
81
|
+
- `dist/types/` — TypeScript declaration files.
|
|
82
|
+
- `dist/browser/squel.min.js` — minified IIFE bundle for `<script>` tags (exposes `window.squel`).
|
|
83
|
+
|
|
84
|
+
## Examples
|
|
53
85
|
|
|
54
86
|
### SELECT
|
|
55
87
|
|
|
@@ -84,10 +116,10 @@ squel.select({ autoQuoteFieldNames: true })
|
|
|
84
116
|
|
|
85
117
|
You can build parameterized queries:
|
|
86
118
|
|
|
87
|
-
```
|
|
119
|
+
```javascript
|
|
88
120
|
/*
|
|
89
121
|
{
|
|
90
|
-
text: "SELECT `t1`.`id`, `t1`.`name` as "My name", `t1`.`started` as "Date" FROM table `t1` WHERE age IN (RANGE(?, ?)) ORDER BY id ASC LIMIT 20",
|
|
122
|
+
text: "SELECT `t1`.`id`, `t1`.`name` as \"My name\", `t1`.`started` as \"Date\" FROM table `t1` WHERE age IN (RANGE(?, ?)) ORDER BY id ASC LIMIT 20",
|
|
91
123
|
values: [1, 1.2]
|
|
92
124
|
}
|
|
93
125
|
*/
|
|
@@ -102,15 +134,14 @@ squel.select({ autoQuoteFieldNames: true })
|
|
|
102
134
|
.toParam()
|
|
103
135
|
```
|
|
104
136
|
|
|
105
|
-
|
|
106
137
|
You can use nested queries:
|
|
107
138
|
|
|
108
139
|
```javascript
|
|
109
140
|
// SELECT s.id FROM (SELECT * FROM students) `s` INNER JOIN (SELECT id FROM marks) `m` ON (m.id = s.id)
|
|
110
141
|
squel.select()
|
|
111
|
-
.from(
|
|
112
|
-
.field(
|
|
113
|
-
.join(
|
|
142
|
+
.from(squel.select().from("students"), "s")
|
|
143
|
+
.field("id")
|
|
144
|
+
.join(squel.select().from("marks").field("id"), "m", "m.id = s.id")
|
|
114
145
|
.toString()
|
|
115
146
|
```
|
|
116
147
|
|
|
@@ -129,11 +160,11 @@ squel.update()
|
|
|
129
160
|
.set("test.id", 1)
|
|
130
161
|
.table("test2")
|
|
131
162
|
.set("test2.val", 1.2)
|
|
132
|
-
.table("test3","a")
|
|
163
|
+
.table("test3", "a")
|
|
133
164
|
.setFields({
|
|
134
165
|
"a.name": "Ram",
|
|
135
166
|
"a.email": null,
|
|
136
|
-
"a.count = a.count + 1": undefined
|
|
167
|
+
"a.count = a.count + 1": undefined,
|
|
137
168
|
})
|
|
138
169
|
.toString()
|
|
139
170
|
```
|
|
@@ -141,59 +172,28 @@ squel.update()
|
|
|
141
172
|
### INSERT
|
|
142
173
|
|
|
143
174
|
```javascript
|
|
144
|
-
// INSERT INTO test (f1) VALUES (1)
|
|
175
|
+
// INSERT INTO test (f1, f2) VALUES (1, 1.2)
|
|
145
176
|
squel.insert()
|
|
146
177
|
.into("test")
|
|
147
178
|
.set("f1", 1)
|
|
148
|
-
.
|
|
149
|
-
|
|
150
|
-
// INSERT INTO test (name, age) VALUES ('Thomas', 29), ('Jane', 31)
|
|
151
|
-
squel.insert()
|
|
152
|
-
.into("test")
|
|
153
|
-
.setFieldsRows([
|
|
154
|
-
{ name: "Thomas", age: 29 },
|
|
155
|
-
{ name: "Jane", age: 31 }
|
|
156
|
-
])
|
|
179
|
+
.set("f2", 1.2)
|
|
157
180
|
.toString()
|
|
158
181
|
```
|
|
159
182
|
|
|
160
183
|
### DELETE
|
|
161
184
|
|
|
162
185
|
```javascript
|
|
163
|
-
// DELETE FROM test
|
|
186
|
+
// DELETE FROM test WHERE (f1 = 2) ORDER BY f2 LIMIT 1
|
|
164
187
|
squel.delete()
|
|
165
188
|
.from("test")
|
|
189
|
+
.where("f1 = 2")
|
|
190
|
+
.order("f2")
|
|
191
|
+
.limit(1)
|
|
166
192
|
.toString()
|
|
167
|
-
|
|
168
|
-
// DELETE FROM table1 WHERE (table1.id = 2) ORDER BY id DESC LIMIT 2
|
|
169
|
-
squel.delete()
|
|
170
|
-
.from("table1")
|
|
171
|
-
.where("table1.id = ?", 2)
|
|
172
|
-
.order("id", false)
|
|
173
|
-
.limit(2)
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### Paramterized queries
|
|
177
|
-
|
|
178
|
-
Use the `useParam()` method to obtain a parameterized query with a separate list of formatted parameter values:
|
|
179
|
-
|
|
180
|
-
```javascript
|
|
181
|
-
// { text: "INSERT INTO test (f1, f2, f3, f4, f5) VALUES (?, ?, ?, ?, ?)", values: [1, 1.2, "TRUE", "blah", "NULL"] }
|
|
182
|
-
squel.insert()
|
|
183
|
-
.into("test")
|
|
184
|
-
.set("f1", 1)
|
|
185
|
-
.set("f2", 1.2)
|
|
186
|
-
.set("f3", true)
|
|
187
|
-
.set("f4", "blah")
|
|
188
|
-
.set("f5", null)
|
|
189
|
-
.toParam()
|
|
190
193
|
```
|
|
191
194
|
|
|
192
|
-
|
|
193
195
|
### Expression builder
|
|
194
196
|
|
|
195
|
-
There is also an expression builder which allows you to build complex expressions for `WHERE` and `ON` clauses:
|
|
196
|
-
|
|
197
197
|
```javascript
|
|
198
198
|
// test = 3 OR test = 4
|
|
199
199
|
squel.expr()
|
|
@@ -215,168 +215,141 @@ squel.expr()
|
|
|
215
215
|
.and("inner = ?", 4)
|
|
216
216
|
.or(
|
|
217
217
|
squel.expr()
|
|
218
|
-
.and("inner IN ?", [
|
|
218
|
+
.and("inner IN ?", ["str1", "str2", null])
|
|
219
219
|
)
|
|
220
220
|
)
|
|
221
221
|
.toString()
|
|
222
222
|
|
|
223
223
|
// SELECT * FROM test INNER JOIN test2 ON (test.id = test2.id) WHERE (test = 3 OR test = 4)
|
|
224
224
|
squel.select()
|
|
225
|
-
.join(
|
|
226
|
-
.where(
|
|
225
|
+
.join("test2", null, squel.expr().and("test.id = test2.id"))
|
|
226
|
+
.where(squel.expr().or("test = 3").or("test = 4"))
|
|
227
|
+
.toString()
|
|
227
228
|
```
|
|
228
229
|
|
|
229
230
|
### Custom value types
|
|
230
231
|
|
|
231
|
-
By default Squel does not support the use of object instances as field values. Instead it lets you tell it how you want
|
|
232
|
-
specific object types to be handled:
|
|
232
|
+
By default Squel does not support the use of object instances as field values. Instead it lets you tell it how you want specific object types to be handled:
|
|
233
233
|
|
|
234
234
|
```javascript
|
|
235
235
|
// handler for objects of type Date
|
|
236
|
-
squel.registerValueHandler(Date,
|
|
237
|
-
|
|
238
|
-
})
|
|
236
|
+
squel.registerValueHandler(Date, (date) => {
|
|
237
|
+
return `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`
|
|
238
|
+
})
|
|
239
239
|
|
|
240
|
-
squel.update()
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
squel.update()
|
|
241
|
+
.table("students")
|
|
242
|
+
.set("start_date", new Date(2013, 5, 1))
|
|
243
|
+
.toString()
|
|
244
244
|
|
|
245
245
|
// UPDATE students SET start_date = '2013/6/1'
|
|
246
246
|
```
|
|
247
247
|
|
|
248
|
-
|
|
249
|
-
_Note that custom value handlers can be overridden on a per-instance basis (see the [docs](https://hiddentao.github.io/squel))_
|
|
248
|
+
Custom value handlers can also be overridden on a per-instance basis (see the [docs](https://hiddentao.github.io/squel)).
|
|
250
249
|
|
|
251
250
|
### Custom queries
|
|
252
251
|
|
|
253
|
-
Squel
|
|
252
|
+
Squel lets you extend the built-in query builders or create entirely new kinds of queries:
|
|
254
253
|
|
|
255
254
|
```javascript
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
255
|
+
class CommandBlock extends squel.cls.Block {
|
|
256
|
+
command(command, arg) {
|
|
257
|
+
this._command = command
|
|
258
|
+
this._arg = arg
|
|
259
|
+
}
|
|
260
|
+
compress(level) {
|
|
261
|
+
this.command("compress", level)
|
|
262
|
+
}
|
|
263
|
+
_toParamString(options) {
|
|
264
|
+
let text = this._command.toUpperCase()
|
|
265
|
+
const values = []
|
|
266
|
+
if (options.buildParameterized) {
|
|
267
|
+
text += " ?"
|
|
268
|
+
values.push(this._arg)
|
|
269
|
+
} else {
|
|
270
|
+
text += ` ${this._arg}`
|
|
271
|
+
}
|
|
272
|
+
return { text, values }
|
|
273
|
+
}
|
|
267
274
|
}
|
|
268
275
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
// generic parameter block
|
|
280
|
-
var ParamBlock = function() {};
|
|
281
|
-
util.inherits(ParamBlock, squel.cls.Block);
|
|
282
|
-
|
|
283
|
-
ParamBlock.prototype.param = function(p) {
|
|
284
|
-
this._p = p;
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
ParamBlock.prototype.buildStr = function() {
|
|
288
|
-
return this._p;
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
// pragma query builder
|
|
293
|
-
var PragmaQuery = function(options) {
|
|
294
|
-
squel.cls.QueryBuilder.call(this, options, [
|
|
295
|
-
new squel.cls.StringBlock(options, 'PRAGMA'),
|
|
296
|
-
new CommandBlock(),
|
|
297
|
-
new ParamBlock()
|
|
298
|
-
]);
|
|
299
|
-
};
|
|
300
|
-
util.inherits(PragmaQuery, squel.cls.QueryBuilder);
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
// convenience method (we can override built-in squel methods this way too)
|
|
304
|
-
squel.pragma = function(options) {
|
|
305
|
-
return new PragmaQuery(options)
|
|
306
|
-
};
|
|
307
|
-
|
|
276
|
+
class PragmaQuery extends squel.cls.QueryBuilder {
|
|
277
|
+
constructor(options) {
|
|
278
|
+
super(options, [
|
|
279
|
+
new squel.cls.StringBlock(options, "PRAGMA"),
|
|
280
|
+
new CommandBlock(options),
|
|
281
|
+
])
|
|
282
|
+
}
|
|
283
|
+
}
|
|
308
284
|
|
|
309
|
-
|
|
310
|
-
// Build a PRAGMA query
|
|
311
|
-
// ------------------------------------------------------
|
|
285
|
+
squel.pragma = (options) => new PragmaQuery(options)
|
|
312
286
|
|
|
313
|
-
squel.pragma()
|
|
314
|
-
|
|
315
|
-
.param('test')
|
|
316
|
-
.toString();
|
|
287
|
+
squel.pragma().compress(9).toString()
|
|
288
|
+
// 'PRAGMA COMPRESS 9'
|
|
317
289
|
|
|
318
|
-
|
|
290
|
+
squel.pragma().compress(9).toParam()
|
|
291
|
+
// { text: 'PRAGMA COMPRESS ?', values: [9] }
|
|
319
292
|
```
|
|
320
293
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
* https://github.com/bostrt/squel-top-start-at (blog post about it: http://blog.bostrt.net/extending-squel-js/)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
## Non-standard SQL
|
|
294
|
+
## Non-standard SQL flavours
|
|
327
295
|
|
|
328
|
-
Squel supports the standard SQL commands and reserved words.
|
|
329
|
-
non-standard commands. To make things easy Squel allows for different 'flavours' of SQL to be loaded and used.
|
|
296
|
+
Squel supports the standard SQL commands and reserved words. A number of database engines provide their own non-standard commands; Squel makes it easy to load different "flavours" of SQL that augment the core builders with engine-specific features.
|
|
330
297
|
|
|
331
|
-
|
|
332
|
-
for use with Postgres).
|
|
333
|
-
|
|
334
|
-
To use this in node.js:
|
|
298
|
+
Available flavours: `mysql`, `mssql`, `postgres` (e.g. `INSERT ... RETURNING` for Postgres, `ON DUPLICATE KEY UPDATE` for MySQL).
|
|
335
299
|
|
|
336
300
|
```javascript
|
|
337
|
-
|
|
301
|
+
import squel from "squel"
|
|
302
|
+
|
|
303
|
+
const pg = squel.useFlavour("postgres")
|
|
304
|
+
const mysql = squel.useFlavour("mysql")
|
|
305
|
+
const mssql = squel.useFlavour("mssql")
|
|
338
306
|
```
|
|
339
307
|
|
|
340
|
-
For
|
|
308
|
+
For browser use:
|
|
341
309
|
|
|
342
310
|
```html
|
|
343
|
-
<script
|
|
344
|
-
<script
|
|
345
|
-
|
|
311
|
+
<script src="https://unpkg.com/squel/dist/browser/squel.min.js"></script>
|
|
312
|
+
<script>
|
|
313
|
+
const pg = squel.useFlavour("postgres")
|
|
346
314
|
</script>
|
|
347
315
|
```
|
|
348
316
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
Read the the [API docs](http://hiddentao.github.io/squel/api.html) to find out available commands. Flavours of SQL which get added to
|
|
352
|
-
Squel in the future will be usable in the above manner.
|
|
353
|
-
|
|
354
|
-
## Building it
|
|
317
|
+
See the [API docs](http://hiddentao.github.io/squel/api.html) for a full reference.
|
|
355
318
|
|
|
356
|
-
|
|
319
|
+
## Migrating from v5
|
|
357
320
|
|
|
358
|
-
|
|
359
|
-
$ npm test <-- this will build the code and run the tests
|
|
321
|
+
v6.0.0 is a modernization release. The public API is unchanged — all your existing `squel.select()`, `squel.useFlavour('postgres')`, and related calls continue to work.
|
|
360
322
|
|
|
361
|
-
|
|
323
|
+
The breaking changes are all about **package shape**:
|
|
362
324
|
|
|
363
|
-
|
|
325
|
+
- **Engines:** `engines.node` is now `>=18`. If you need support for older runtimes, stay on v5.
|
|
326
|
+
- **Output layout:** the `squel.js` / `squel.min.js` / `squel-basic.js` / `squel-basic.min.js` UMD bundles have been replaced. Consumers now import from `dist/esm/`, `dist/cjs/`, or the IIFE at `dist/browser/squel.min.js` (see the [Package layout](#package-layout) section).
|
|
327
|
+
- **No separate "basic" bundle.** The main entry point includes all flavours. ESM users benefit from tree-shaking; script-tag users get the single IIFE.
|
|
328
|
+
- **UMD dropped.** If you loaded `squel.min.js` via `<script>`, switch to `dist/browser/squel.min.js` (same global `window.squel`).
|
|
364
329
|
|
|
330
|
+
## Development
|
|
365
331
|
|
|
366
|
-
|
|
332
|
+
```bash
|
|
333
|
+
bun install # install dependencies
|
|
334
|
+
bun run check # lint & format check (biome)
|
|
335
|
+
bun run typecheck # TypeScript type checking
|
|
336
|
+
bun test # run the test suite
|
|
337
|
+
bun run build # produce dist/esm, dist/cjs, dist/types, dist/browser
|
|
338
|
+
```
|
|
367
339
|
|
|
368
|
-
|
|
340
|
+
## Releasing
|
|
369
341
|
|
|
370
|
-
|
|
342
|
+
Releases are automated. Landing a conventional commit on `master` triggers the release workflow, which bumps the version, updates `CHANGELOG.md`, creates a tag, and publishes to npm with provenance. See [`RELEASE.md`](RELEASE.md) for details.
|
|
371
343
|
|
|
372
|
-
|
|
344
|
+
## Contributing
|
|
373
345
|
|
|
346
|
+
Contributions are welcome! Please see [`CONTRIBUTING.md`](CONTRIBUTING.md).
|
|
374
347
|
|
|
375
348
|
## Ports to other languages
|
|
376
349
|
|
|
377
|
-
|
|
378
|
-
|
|
350
|
+
- .NET — https://github.com/seymourpoler/Squel.net
|
|
351
|
+
- Crystal — https://github.com/seymourpoler/Squel.crystal
|
|
379
352
|
|
|
380
353
|
## License
|
|
381
354
|
|
|
382
|
-
MIT
|
|
355
|
+
MIT — see [`LICENSE.md`](LICENSE.md).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(()=>{var{defineProperty:b,getOwnPropertyNames:Q,getOwnPropertyDescriptor:V}=Object,$=Object.prototype.hasOwnProperty;var O=new WeakMap,z=(c)=>{var t=O.get(c),s;if(t)return t;if(t=b({},"__esModule",{value:!0}),c&&typeof c==="object"||typeof c==="function")Q(c).map((i)=>!$.call(t,i)&&b(t,i,{get:()=>c[i],enumerable:!(s=V(c,i))||s.enumerable}));return O.set(c,t),t};var A=(c,t)=>{for(var s in t)b(c,s,{get:t[s],enumerable:!0,configurable:!0,set:(i)=>t[s]=()=>i})};var C={};A(C,{squel:()=>S,default:()=>D});var P={name:"squel",version:"6.0.2",description:"SQL query string builder",keywords:["sql","database","rdbms","query-builder","mysql","postgres","mssql"],author:"Ramesh Nair <ram@hiddentao.com> (http://www.hiddentao.com/)",contributors:["Ramesh Nair <ram@hiddentao.com> (http://www.hiddentao.com/)","Sergej Brjuchanov <serges@seznam.cz>"],license:"MIT",repository:{type:"git",url:"https://github.com/hiddentao/squel.git"},homepage:"https://github.com/hiddentao/squel",bugs:{url:"https://github.com/hiddentao/squel/issues"},type:"module",main:"./dist/cjs/index.js",module:"./dist/esm/index.js",types:"./dist/types/index.d.ts",exports:{".":{types:"./dist/types/index.d.ts",import:"./dist/esm/index.js",require:"./dist/cjs/index.js"},"./browser":"./dist/browser/squel.min.js"},files:["dist","README.md","LICENSE.md","CHANGELOG.md"],engines:{node:">=18.0.0"},publishConfig:{access:"public",provenance:!0},scripts:{build:"bun run scripts/build.ts",test:"bun test","test:coverage":"bun test --coverage --coverage-reporter=lcov","test:watch":"bun test --watch",lint:"biome check --write ./src ./tests ./scripts",format:"biome format --write ./src ./tests ./scripts",check:"biome check ./src ./tests ./scripts",typecheck:"tsc --noEmit",prepare:"husky",prepublishOnly:"bun run build && bun run test"},dependencies:{},devDependencies:{"@biomejs/biome":"^1.9.4","@commitlint/cli":"^19.8.1","@commitlint/config-conventional":"^19.8.1","@types/bun":"latest","@types/node":"^22.0.0","commit-and-tag-version":"^12.6.0",husky:"^9.1.7",typescript:"^5.3.0"}};function p(c,t){return c.length?c+t:c}function f(c,...t){if(c&&t){for(let s of t)if(s&&typeof s==="object")for(let i of Object.getOwnPropertyNames(s))c[i]=s[i]}return c}function x(c){return!!c&&c.constructor.prototype===Object.prototype}function B(c){return!!c&&c.constructor.prototype===Array.prototype}function E(c){if(!c)return c;let t=c;if(typeof t.clone==="function")return t.clone();if(x(c)||B(c)){let s=new t.constructor;for(let i of Object.getOwnPropertyNames(c))if(typeof t[i]!=="function")s[i]=E(t[i]);return s}return JSON.parse(JSON.stringify(c))}function v(c,t,s){let i=typeof t;if(i!=="function"&&i!=="string")throw Error("type must be a class constructor or string");if(typeof s!=="function")throw Error("handler must be a function");for(let e of c)if(e.type===t){e.handler=s;return}c.push({type:t,handler:s})}function T(c,t,s){return F(c,t)||F(c,s)}function F(c,t){for(let s of t)if(typeof c===s.type||typeof s.type!=="string"&&c instanceof s.type)return s.handler;return}function N(c=null){let t={isSquelBuilder(e){return!!e&&!!e._toParamString}},s=(e)=>{return!t.isSquelBuilder(e)||!e.options.rawNesting};t.DefaultQueryBuilderOptions={autoQuoteTableNames:!1,autoQuoteFieldNames:!1,autoQuoteAliasNames:!0,useAsForTableAliasNames:!1,nameQuoteCharacter:"`",tableAliasQuoteCharacter:"`",fieldAliasQuoteCharacter:'"',valueHandlers:[],parameterCharacter:"?",numberedParameters:!1,numberedParametersPrefix:"$",numberedParametersStartAt:1,replaceSingleQuotes:!1,singleQuoteReplacement:"''",separator:" ",stringFormatter:null,rawNesting:!1},t.globalValueHandlers=[],t.registerValueHandler=(e,n)=>{v(t.globalValueHandlers,e,n)},t.Cloneable=class{clone(){let e=new this.constructor;return f(e,E(f({},this)))}},t.BaseBuilder=class extends t.Cloneable{options;constructor(e){super();let n=JSON.parse(JSON.stringify(t.DefaultQueryBuilderOptions));n.stringFormatter=t.DefaultQueryBuilderOptions.stringFormatter,this.options=f(n,e)}registerValueHandler(e,n){return v(this.options.valueHandlers,e,n),this}_sanitizeExpression(e){if(!t.isSquelBuilder(e)){if(typeof e!=="string")throw Error("expression must be a string or builder instance")}return e}_sanitizeName(e,n){if(typeof e!=="string")throw Error(`${n} must be a string`);return e}_sanitizeField(e){if(!t.isSquelBuilder(e))return this._sanitizeName(e,"field name");return e}_sanitizeBaseBuilder(e){if(t.isSquelBuilder(e))return e;throw Error("must be a builder instance")}_sanitizeTable(e,n){if(typeof e!=="string")try{return this._sanitizeBaseBuilder(e)}catch(r){throw Error("table name must be a string or a builder")}return this._sanitizeName(e,"table")}_sanitizeTableAlias(e){return this._sanitizeName(e,"table alias")}_sanitizeFieldAlias(e){return this._sanitizeName(e,"field alias")}_sanitizeLimitOffset(e){let n=Number.parseInt(e,10);if(n<0||Number.isNaN(n))throw Error("limit/offset must be >= 0");return n}_sanitizeValue(e){let n=typeof e;if(e===null);else if(n==="string"||n==="number"||n==="boolean");else if(t.isSquelBuilder(e));else if(!T(e,this.options.valueHandlers,t.globalValueHandlers))throw Error("field value must be a string, number, boolean, null or one of the registered custom value types");return e}_escapeValue(e){return this.options.replaceSingleQuotes&&e?e.replace(/'/g,this.options.singleQuoteReplacement):e}_formatTableName(e){if(this.options.autoQuoteTableNames){let n=this.options.nameQuoteCharacter;e=`${n}${e}${n}`}return e}_formatFieldAlias(e){if(this.options.autoQuoteAliasNames){let n=this.options.fieldAliasQuoteCharacter;e=`${n}${e}${n}`}return e}_formatTableAlias(e){if(this.options.autoQuoteAliasNames){let n=this.options.tableAliasQuoteCharacter;e=`${n}${e}${n}`}return this.options.useAsForTableAliasNames?`AS ${e}`:e}_formatFieldName(e,n={}){if(this.options.autoQuoteFieldNames){let r=this.options.nameQuoteCharacter;if(n.ignorePeriodsForFieldNameQuotes)e=`${r}${e}${r}`;else e=e.split(".").map((a)=>a==="*"?a:`${r}${a}${r}`).join(".")}return e}_formatCustomValue(e,n,r){let a=T(e,this.options.valueHandlers,t.globalValueHandlers);if(a){if(e=a(e,n,r),e&&e.rawNesting)return{formatted:!0,rawNesting:!0,value:e.value}}return{formatted:!!a,value:e}}_formatValueForParamArray(e,n={}){if(B(e))return e.map((r)=>this._formatValueForParamArray(r,n));return this._formatCustomValue(e,!0,n).value}_formatValueForQueryString(e,n={}){let{rawNesting:r,formatted:a,value:o}=this._formatCustomValue(e,!1,n),l=o;if(a){if(r)return l;return this._applyNestingFormatting(l,s(e))}if(B(l))l=l.map((u)=>this._formatValueForQueryString(u)),l=this._applyNestingFormatting(l.join(", "),s(l));else{let u=typeof l;if(l===null)l="NULL";else if(u==="boolean")l=l?"TRUE":"FALSE";else if(t.isSquelBuilder(l))l=this._applyNestingFormatting(l.toString(),s(l));else if(u!=="number"){if(u==="string"&&this.options.stringFormatter)return this.options.stringFormatter(l);if(n.dontQuote)l=`${l}`;else l=`'${this._escapeValue(l)}'`}}return l}_applyNestingFormatting(e,n=!0){if(e&&typeof e==="string"&&n&&!this.options.rawNesting){let r=e.charAt(0)==="("&&e.charAt(e.length-1)===")";if(r){let a=0,o=1;while(e.length-1>++a){let l=e.charAt(a);if(l==="(")o++;else if(l===")"){if(o--,o<1){r=!1;break}}}}if(!r)e=`(${e})`}return e}_buildString(e,n,r={}){let{nested:a,buildParameterized:o,formattingOptions:l}=r;n=n||[],e=e||"";let u="",d=-1,h=[],y=this.options.parameterCharacter,_=0;while(e.length>_)if(e.substring(_,_+y.length)===y){let g=n[++d];if(o)if(t.isSquelBuilder(g)){let w=g._toParamString({buildParameterized:o,nested:!0});u+=w.text,w.values.forEach((k)=>h.push(k))}else if(g=this._formatValueForParamArray(g,l),B(g)){let w=g.map(()=>y).join(", ");u+=`(${w})`,g.forEach((k)=>h.push(k))}else u+=y,h.push(g);else u+=this._formatValueForQueryString(g,l);_+=y.length}else u+=e.charAt(_),_++;return{text:this._applyNestingFormatting(u,!!a),values:h}}_buildManyStrings(e,n,r={}){let a=[],o=[];for(let u=0;e.length>u;++u){let d=e[u],h=n[u],{text:y,values:_}=this._buildString(d,h,{buildParameterized:r.buildParameterized,nested:!1});a.push(y),_.forEach((g)=>o.push(g))}let l=a.join(this.options.separator);return{text:l.length?this._applyNestingFormatting(l,!!r.nested):"",values:o}}_toParamString(e){throw Error("Not yet implemented")}toString(e={}){return this._toParamString(e).text}toParam(e={}){return this._toParamString({...e,buildParameterized:!0})}},t.Expression=class extends t.BaseBuilder{_nodes;constructor(e){super(e);this._nodes=[]}and(e,...n){return e=this._sanitizeExpression(e),this._nodes.push({type:"AND",expr:e,para:n}),this}or(e,...n){return e=this._sanitizeExpression(e),this._nodes.push({type:"OR",expr:e,para:n}),this}_toParamString(e={}){let n=[],r=[];for(let a of this._nodes){let{type:o,expr:l,para:u}=a,{text:d,values:h}=t.isSquelBuilder(l)?l._toParamString({buildParameterized:e.buildParameterized,nested:!0}):this._buildString(l,u,{buildParameterized:e.buildParameterized});if(n.length)n.push(o);n.push(d),h.forEach((y)=>r.push(y))}return n=n.join(" "),{text:this._applyNestingFormatting(n,!!e.nested),values:r}}},t.Case=class extends t.BaseBuilder{_fieldName=null;_cases;_elseValue=null;constructor(e,n={}){super(n);let r=null;if(x(e))n=e;else if(e)r=this._sanitizeField(e);this._fieldName=r,this.options=f(Object.assign({},t.DefaultQueryBuilderOptions),n),this._cases=[]}when(e,...n){return this._cases.unshift({expression:e,values:n||[]}),this}then(e){if(this._cases.length===0)throw Error("when() needs to be called first");return this._cases[0].result=e,this}else(e){return this._elseValue=e,this}_toParamString(e={}){let n="",r=[];for(let{expression:a,values:o,result:l}of this._cases){n=p(n," ");let u=this._buildString(a,o,{buildParameterized:e.buildParameterized,nested:!0});n+=`WHEN ${u.text} THEN ${this._formatValueForQueryString(l)}`,u.values.forEach((d)=>r.push(d))}if(n.length){if(n+=` ELSE ${this._formatValueForQueryString(this._elseValue)} END`,this._fieldName)n=`${this._fieldName} ${n}`;n=`CASE ${n}`}else n=this._formatValueForQueryString(this._elseValue);return{text:n,values:r}}},t.Block=class extends t.BaseBuilder{constructor(e){super(e)}exposedMethods(){let e={},n=this;while(n){for(let r of Object.getOwnPropertyNames(n))if(r!=="constructor"&&typeof n[r]==="function"&&r.charAt(0)!=="_"&&!t.Block.prototype[r])e[r]=n[r];n=Object.getPrototypeOf(n)}return e}},t.StringBlock=class extends t.Block{_str;constructor(e,n){super(e);this._str=n}_toParamString(e={}){return{text:this._str,values:[]}}},t.FunctionBlock=class extends t.Block{_strings;_values;constructor(e){super(e);this._strings=[],this._values=[]}function(e,...n){this._strings.push(e),this._values.push(n)}_toParamString(e={}){return this._buildManyStrings(this._strings,this._values,e)}},t.registerValueHandler(t.FunctionBlock,(e,n=!1)=>{return n?e.toParam():e.toString()}),t.AbstractTableBlock=class extends t.Block{_tables;constructor(e,n){super(e);this._tables=[]}_table(e,n=null){if(n=n?this._sanitizeTableAlias(n):n,e=this._sanitizeTable(e),this.options.singleTable)this._tables=[];this._tables.push({table:e,alias:n})}_hasTable(){return this._tables.length>0}_toParamString(e={}){let n="",r=[];if(this._hasTable()){for(let{table:a,alias:o}of this._tables){n=p(n,", ");let l;if(t.isSquelBuilder(a)){let{text:u,values:d}=a._toParamString({buildParameterized:e.buildParameterized,nested:!0});l=u,d.forEach((h)=>r.push(h))}else l=this._formatTableName(a);if(o)l+=` ${this._formatTableAlias(o)}`;n+=l}if(this.options.prefix)n=`${this.options.prefix} ${n}`}return{text:n,values:r}}},t.TargetTableBlock=class extends t.AbstractTableBlock{target(e){this._table(e)}},t.UpdateTableBlock=class extends t.AbstractTableBlock{table(e,n=null){this._table(e,n)}_toParamString(e={}){if(!this._hasTable())throw Error("table() needs to be called");return super._toParamString(e)}},t.FromTableBlock=class extends t.AbstractTableBlock{constructor(e){super(f({},e,{prefix:"FROM"}))}from(e,n=null){this._table(e,n)}},t.IntoTableBlock=class extends t.AbstractTableBlock{constructor(e){super(f({},e,{prefix:"INTO",singleTable:!0}))}into(e){this._table(e)}_toParamString(e={}){if(!this._hasTable())throw Error("into() needs to be called");return super._toParamString(e)}},t.GetFieldBlock=class extends t.Block{_fields;constructor(e){super(e);this._fields=[]}fields(e,n={}){if(B(e))for(let r of e)this.field(r,null,n);else for(let r in e){let a=e[r];this.field(r,a,n)}}field(e,n=null,r={}){if(n=n?this._sanitizeFieldAlias(n):n,e=this._sanitizeField(e),this._fields.filter((o)=>o.name===e&&o.alias===n).length)return this;this._fields.push({name:e,alias:n,options:r});return}_toParamString(e={}){let{queryBuilder:n,buildParameterized:r}=e,a="",o=[];for(let l of this._fields){a=p(a,", ");let{name:u,alias:d,options:h}=l;if(typeof u==="string")a+=this._formatFieldName(u,h);else{let y=u._toParamString({nested:!0,buildParameterized:r});a+=y.text,y.values.forEach((_)=>o.push(_))}if(d)a+=` AS ${this._formatFieldAlias(d)}`}if(!a.length){let l=n?.getBlock(t.FromTableBlock);if(l&&l._hasTable())a="*"}return{text:a,values:o}}},t.AbstractSetFieldBlock=class extends t.Block{_fields;_values;_valueOptions;constructor(e){super(e);this._fields=[],this._values=[[]],this._valueOptions=[[]]}_reset(){this._fields=[],this._values=[[]],this._valueOptions=[[]]}_set(e,n,r={}){if(this._values.length>1)throw Error("Cannot set multiple rows of fields this way.");if(typeof n<"u")n=this._sanitizeValue(n);e=this._sanitizeField(e);let a=this._fields.indexOf(e);if(a===-1)this._fields.push(e),a=this._fields.length-1;this._values[0][a]=n,this._valueOptions[0][a]=r}_setFields(e,n={}){if(typeof e!=="object")throw Error(`Expected an object but got ${typeof e}`);for(let r in e)this._set(r,e[r],n)}_setFieldsRows(e,n={}){if(!B(e))throw Error(`Expected an array of objects but got ${typeof e}`);this._reset();for(let r=0;e.length>r;++r){let a=e[r];for(let o in a){let l=a[o];o=this._sanitizeField(o),l=this._sanitizeValue(l);let u=this._fields.indexOf(o);if(r>0&&u===-1)throw Error("All fields in subsequent rows must match the fields in the first row");if(u===-1)this._fields.push(o),u=this._fields.length-1;if(!B(this._values[r]))this._values[r]=[],this._valueOptions[r]=[];this._values[r][u]=l,this._valueOptions[r][u]=n}}}},t.SetFieldBlock=class extends t.AbstractSetFieldBlock{set(e,n,r){this._set(e,n,r)}setFields(e,n){this._setFields(e,n)}_toParamString(e={}){let{buildParameterized:n}=e;if(this._fields.length<=0)throw Error("set() needs to be called");let r="",a=[];for(let o=0;o<this._fields.length;++o){r=p(r,", ");let l=this._formatFieldName(this._fields[o]),u=this._values[0][o];if(l.indexOf("=")<0)l=`${l} = ${this.options.parameterCharacter}`;let d=this._buildString(l,[u],{buildParameterized:n,formattingOptions:this._valueOptions[0][o]});r+=d.text,d.values.forEach((h)=>a.push(h))}return{text:`SET ${r}`,values:a}}},t.InsertFieldValueBlock=class extends t.AbstractSetFieldBlock{set(e,n,r={}){this._set(e,n,r)}setFields(e,n){this._setFields(e,n)}setFieldsRows(e,n){this._setFieldsRows(e,n)}_toParamString(e={}){let{buildParameterized:n}=e,r=this._fields.map((l)=>this._formatFieldName(l)).join(", "),a=[],o=[];for(let l=0;l<this._values.length;++l){a[l]="";for(let u=0;u<this._values[l].length;++u){let d=this._buildString(this.options.parameterCharacter,[this._values[l][u]],{buildParameterized:n,formattingOptions:this._valueOptions[l][u]});d.values.forEach((h)=>o.push(h)),a[l]=p(a[l],", "),a[l]+=d.text}}return{text:r.length?`(${r}) VALUES (${a.join("), (")})`:"",values:o}}},t.InsertFieldsFromQueryBlock=class extends t.Block{_fields;_query=null;constructor(e){super(e);this._fields=[]}fromQuery(e,n){this._fields=e.map((r)=>this._sanitizeField(r)),this._query=this._sanitizeBaseBuilder(n)}_toParamString(e={}){let n="",r=[];if(this._fields.length&&this._query){let{text:a,values:o}=this._query._toParamString({buildParameterized:e.buildParameterized,nested:!0});n=`(${this._fields.join(", ")}) ${this._applyNestingFormatting(a)}`,r=o}return{text:n,values:r}}},t.DistinctBlock=class extends t.Block{_useDistinct=!1;distinct(){this._useDistinct=!0}_toParamString(){return{text:this._useDistinct?"DISTINCT":"",values:[]}}},t.GroupByBlock=class extends t.Block{_groups;constructor(e){super(e);this._groups=[]}group(e){this._groups.push(this._sanitizeField(e))}_toParamString(e={}){return{text:this._groups.length?`GROUP BY ${this._groups.join(", ")}`:"",values:[]}}},t.AbstractVerbSingleValueBlock=class extends t.Block{_value=null;constructor(e){super(e)}_setValue(e){this._value=e!==null?this._sanitizeLimitOffset(e):e}_toParamString(e={}){let n=this._value!==null?`${this.options.verb} ${this.options.parameterCharacter}`:"",r=this._value!==null?[this._value]:[];return this._buildString(n,r,e)}},t.OffsetBlock=class extends t.AbstractVerbSingleValueBlock{constructor(e){super(f({},e,{verb:"OFFSET"}))}offset(e){this._setValue(e)}},t.LimitBlock=class extends t.AbstractVerbSingleValueBlock{constructor(e){super(f({},e,{verb:"LIMIT"}))}limit(e){this._setValue(e)}},t.AbstractConditionBlock=class extends t.Block{_conditions;constructor(e){super(e);this._conditions=[]}_condition(e,...n){e=this._sanitizeExpression(e),this._conditions.push({expr:e,values:n||[]})}_toParamString(e={}){let n=[],r=[];for(let{expr:o,values:l}of this._conditions){let u=t.isSquelBuilder(o)?o._toParamString({buildParameterized:e.buildParameterized}):this._buildString(o,l,{buildParameterized:e.buildParameterized});if(u.text.length)n.push(u.text);u.values.forEach((d)=>r.push(d))}let a=n.join(") AND (");return{text:a.length?`${this.options.verb} (${a})`:"",values:r}}},t.WhereBlock=class extends t.AbstractConditionBlock{constructor(e){super(f({},e,{verb:"WHERE"}))}where(e,...n){this._condition(e,...n)}},t.HavingBlock=class extends t.AbstractConditionBlock{constructor(e){super(f({},e,{verb:"HAVING"}))}having(e,...n){this._condition(e,...n)}},t.OrderByBlock=class extends t.Block{_orders;constructor(e){super(e);this._orders=[]}order(e,n,...r){e=this._sanitizeField(e);let a;if(typeof n==="string")a=n;else if(n===void 0)a="ASC";else if(n===null)a=null;else a=n?"ASC":"DESC";this._orders.push({field:e,dir:a,values:r||[]})}_toParamString(e={}){let n="",r=[];for(let{field:a,dir:o,values:l}of this._orders){n=p(n,", ");let u=this._buildString(a,l,{buildParameterized:e.buildParameterized});if(n+=u.text,B(u.values))u.values.forEach((d)=>r.push(d));if(o!==null)n+=` ${o}`}return{text:n.length?`ORDER BY ${n}`:"",values:r}}},t.JoinBlock=class extends t.Block{_joins;constructor(e){super(e);this._joins=[]}join(e,n=null,r=null,a="INNER"){e=this._sanitizeTable(e,!0),n=n?this._sanitizeTableAlias(n):n,r=r?this._sanitizeExpression(r):r,this._joins.push({type:a,table:e,alias:n,condition:r})}left_join(e,n=null,r=null){this.join(e,n,r,"LEFT")}right_join(e,n=null,r=null){this.join(e,n,r,"RIGHT")}outer_join(e,n=null,r=null){this.join(e,n,r,"OUTER")}left_outer_join(e,n=null,r=null){this.join(e,n,r,"LEFT OUTER")}full_join(e,n=null,r=null){this.join(e,n,r,"FULL")}cross_join(e,n=null,r=null){this.join(e,n,r,"CROSS")}_toParamString(e={}){let n="",r=[];for(let{type:a,table:o,alias:l,condition:u}of this._joins){n=p(n,this.options.separator);let d;if(t.isSquelBuilder(o)){let h=o._toParamString({buildParameterized:e.buildParameterized,nested:!0});h.values.forEach((y)=>r.push(y)),d=h.text}else d=this._formatTableName(o);if(n+=`${a} JOIN ${d}`,l)n+=` ${this._formatTableAlias(l)}`;if(u){n+=" ON ";let h;if(t.isSquelBuilder(u))h=u._toParamString({buildParameterized:e.buildParameterized});else h=this._buildString(u,[],{buildParameterized:e.buildParameterized});n+=this._applyNestingFormatting(h.text),h.values.forEach((y)=>r.push(y))}}return{text:n,values:r}}},t.UnionBlock=class extends t.Block{_unions;constructor(e){super(e);this._unions=[]}union(e,n="UNION"){e=this._sanitizeTable(e),this._unions.push({type:n,table:e})}union_all(e){this.union(e,"UNION ALL")}_toParamString(e={}){let n="",r=[];for(let{type:a,table:o}of this._unions){n=p(n,this.options.separator);let l;if(o instanceof t.BaseBuilder){let u=o._toParamString({buildParameterized:e.buildParameterized,nested:!0});l=u.text,u.values.forEach((d)=>r.push(d))}else n=this._formatTableName(o),l="";n+=`${a} ${l}`}return{text:n,values:r}}},t.QueryBuilder=class extends t.BaseBuilder{blocks;constructor(e,n){super(e);this.blocks=n||[];for(let r of this.blocks){let a=r.exposedMethods();for(let o in a){let l=a[o];if(this[o]!==void 0)throw Error(`Builder already has a builder method called: ${o}`);((u,d,h)=>{this[d]=(...y)=>{return h.call(u,...y),this}})(r,o,l)}}}registerValueHandler(e,n){for(let r of this.blocks)r.registerValueHandler(e,n);return super.registerValueHandler(e,n),this}updateOptions(e){this.options=f(this.options,e);for(let n of this.blocks)n.options=f(n.options,e)}_toParamString(e={}){let n=f({},this.options,e),r=this.blocks.map((d)=>d._toParamString({buildParameterized:n.buildParameterized,queryBuilder:this})),a=r.map((d)=>d.text),o=r.map((d)=>d.values),l=a.filter((d)=>d.length>0).join(n.separator),u=[];if(o.forEach((d)=>d.forEach((h)=>u.push(h))),!n.nested){if(n.numberedParameters){let d=n.numberedParametersStartAt!==void 0?n.numberedParametersStartAt:1,h=n.parameterCharacter.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&");l=l.replace(new RegExp(h,"g"),()=>{return`${n.numberedParametersPrefix}${d++}`})}}return{text:this._applyNestingFormatting(l,!!n.nested),values:u}}clone(){let e=this.blocks.map((n)=>n.clone());return new this.constructor(this.options,e)}getBlock(e){return this.blocks.filter((n)=>n instanceof e)[0]}},t.Select=class extends t.QueryBuilder{constructor(e,n=null){n=n||[new t.StringBlock(e,"SELECT"),new t.FunctionBlock(e),new t.DistinctBlock(e),new t.GetFieldBlock(e),new t.FromTableBlock(e),new t.JoinBlock(e),new t.WhereBlock(e),new t.GroupByBlock(e),new t.HavingBlock(e),new t.OrderByBlock(e),new t.LimitBlock(e),new t.OffsetBlock(e),new t.UnionBlock(e)];super(e,n)}},t.Update=class extends t.QueryBuilder{constructor(e,n=null){n=n||[new t.StringBlock(e,"UPDATE"),new t.UpdateTableBlock(e),new t.SetFieldBlock(e),new t.WhereBlock(e),new t.OrderByBlock(e),new t.LimitBlock(e)];super(e,n)}},t.Delete=class extends t.QueryBuilder{constructor(e,n=null){n=n||[new t.StringBlock(e,"DELETE"),new t.TargetTableBlock(e),new t.FromTableBlock(f({},e,{singleTable:!0})),new t.JoinBlock(e),new t.WhereBlock(e),new t.OrderByBlock(e),new t.LimitBlock(e)];super(e,n)}},t.Insert=class extends t.QueryBuilder{constructor(e,n=null){n=n||[new t.StringBlock(e,"INSERT"),new t.IntoTableBlock(e),new t.InsertFieldValueBlock(e),new t.InsertFieldsFromQueryBlock(e)];super(e,n)}};let i={VERSION:P.version,flavour:c,expr:(e)=>new t.Expression(e),case:(e,n)=>new t.Case(e,n),select:(e,n)=>new t.Select(e,n),update:(e,n)=>new t.Update(e,n),insert:(e,n)=>new t.Insert(e,n),delete:(e,n)=>new t.Delete(e,n),str:(...e)=>{let n=new t.FunctionBlock;return n.function(...e),n},rstr:(...e)=>{let n=new t.FunctionBlock({rawNesting:!0});return n.function(...e),n},registerValueHandler:t.registerValueHandler};return i.remove=i.delete,i.cls=t,i}var m=N();m.flavours={};m.useFlavour=function(t=null){if(!t)return m;if(m.flavours[t]instanceof Function){let s=N(t);return m.flavours[t].call(null,s),s.flavours=m.flavours,s.useFlavour=m.useFlavour,s}throw Error(`Flavour not available: ${t}`)};var S=m;m.flavours.mysql=(c)=>{let t=c.cls;t.MysqlOnDuplicateKeyUpdateBlock=class extends t.AbstractSetFieldBlock{onDupUpdate(s,i,e){this._set(s,i,e)}_toParamString(s={}){let i="",e=[];for(let n=0;n<this._fields.length;++n){i=p(i,", ");let r=this._fields[n],a=this._values[0][n],o=this._valueOptions[0][n];if(typeof a>"u")i+=r;else{let l=this._buildString(`${r} = ${this.options.parameterCharacter}`,[a],{buildParameterized:s.buildParameterized,formattingOptions:o});i+=l.text,l.values.forEach((u)=>e.push(u))}}return{text:!i.length?"":`ON DUPLICATE KEY UPDATE ${i}`,values:e}}},t.Insert=class extends t.QueryBuilder{constructor(s,i=null){i=i||[new t.StringBlock(s,"INSERT"),new t.IntoTableBlock(s),new t.InsertFieldValueBlock(s),new t.InsertFieldsFromQueryBlock(s),new t.MysqlOnDuplicateKeyUpdateBlock(s)];super(s,i)}},t.Replace=class extends t.QueryBuilder{constructor(s,i=null){i=i||[new t.StringBlock(s,"REPLACE"),new t.IntoTableBlock(s),new t.InsertFieldValueBlock(s),new t.InsertFieldsFromQueryBlock(s)];super(s,i)}},c.replace=(s,i)=>new t.Replace(s,i)};m.flavours.postgres=(c)=>{let t=c.cls;t.DefaultQueryBuilderOptions.numberedParameters=!0,t.DefaultQueryBuilderOptions.numberedParametersStartAt=1,t.DefaultQueryBuilderOptions.autoQuoteAliasNames=!1,t.DefaultQueryBuilderOptions.useAsForTableAliasNames=!0,t.PostgresOnConflictKeyUpdateBlock=class extends t.AbstractSetFieldBlock{_onConflict;_dupFields;constructor(s){super(s);this._onConflict=!1,this._dupFields=[]}onConflict(s,i){if(this._onConflict=!0,!s)return;if(!B(s))s=[s];if(this._dupFields=s.map(this._sanitizeField.bind(this)),i)Object.keys(i).forEach((e)=>{this._set(e,i[e])})}_toParamString(s={}){let i="",e=[];for(let r=0;r<this._fields.length;++r){i=p(i,", ");let a=this._fields[r],o=this._values[0][r],l=this._valueOptions[0][r];if(typeof o>"u")i+=a;else{let u=this._buildString(`${a} = ${this.options.parameterCharacter}`,[o],{buildParameterized:s.buildParameterized,formattingOptions:l});i+=u.text,u.values.forEach((d)=>e.push(d))}}let n={text:"",values:e};if(this._onConflict){let r=this._dupFields.length?`(${this._dupFields.join(", ")}) `:"",a=i.length?`UPDATE SET ${i}`:"NOTHING";n.text=`ON CONFLICT ${r}DO ${a}`}return n}},t.ReturningBlock=class extends t.Block{_fields;constructor(s){super(s);this._fields=[]}returning(s,i=null,e={}){if(i=i?this._sanitizeFieldAlias(i):i,s=this._sanitizeField(s),this._fields.filter((r)=>r.name===s&&r.alias===i).length)return this;this._fields.push({name:s,alias:i,options:e})}_toParamString(s={}){let{buildParameterized:i}=s,e="",n=[];for(let r of this._fields){e=p(e,", ");let{name:a,alias:o,options:l}=r;if(typeof a==="string")e+=this._formatFieldName(a,l);else{let u=a._toParamString({nested:!0,buildParameterized:i});e+=u.text,u.values.forEach((d)=>n.push(d))}if(o)e+=` AS ${this._formatFieldAlias(o)}`}return{text:e.length>0?`RETURNING ${e}`:"",values:n}}},t.WithBlock=class extends t.Block{_tables;constructor(s){super(s);this._tables=[]}with(s,i){this._tables.push({alias:s,table:i})}_toParamString(s={}){let i=[],e=[];for(let{alias:n,table:r}of this._tables){let a=r._toParamString({buildParameterized:s.buildParameterized,nested:!0});i.push(`${n} AS ${a.text}`),a.values.forEach((o)=>e.push(o))}return{text:i.length?`WITH ${i.join(", ")}`:"",values:e}}},t.DistinctOnBlock=class extends t.Block{_useDistinct=!1;_distinctFields;constructor(s){super(s);this._distinctFields=[]}distinct(...s){this._useDistinct=!0,s.forEach((i)=>{this._distinctFields.push(this._sanitizeField(i))})}_toParamString(){let s="";if(this._useDistinct){if(s="DISTINCT",this._distinctFields.length)s+=` ON (${this._distinctFields.join(", ")})`}return{text:s,values:[]}}},t.Select=class extends t.QueryBuilder{constructor(s,i=null){i=i||[new t.WithBlock(s),new t.StringBlock(s,"SELECT"),new t.FunctionBlock(s),new t.DistinctOnBlock(s),new t.GetFieldBlock(s),new t.FromTableBlock(s),new t.JoinBlock(s),new t.WhereBlock(s),new t.GroupByBlock(s),new t.HavingBlock(s),new t.OrderByBlock(s),new t.LimitBlock(s),new t.OffsetBlock(s),new t.UnionBlock(s)];super(s,i)}},t.Insert=class extends t.QueryBuilder{constructor(s,i=null){i=i||[new t.WithBlock(s),new t.StringBlock(s,"INSERT"),new t.IntoTableBlock(s),new t.InsertFieldValueBlock(s),new t.InsertFieldsFromQueryBlock(s),new t.PostgresOnConflictKeyUpdateBlock(s),new t.ReturningBlock(s)];super(s,i)}},t.Update=class extends t.QueryBuilder{constructor(s,i=null){i=i||[new t.WithBlock(s),new t.StringBlock(s,"UPDATE"),new t.UpdateTableBlock(s),new t.SetFieldBlock(s),new t.FromTableBlock(s),new t.WhereBlock(s),new t.OrderByBlock(s),new t.LimitBlock(s),new t.ReturningBlock(s)];super(s,i)}},t.Delete=class extends t.QueryBuilder{constructor(s,i=null){i=i||[new t.WithBlock(s),new t.StringBlock(s,"DELETE"),new t.TargetTableBlock(s),new t.FromTableBlock({...s,singleTable:!0}),new t.JoinBlock(s),new t.WhereBlock(s),new t.OrderByBlock(s),new t.LimitBlock(s),new t.ReturningBlock(s)];super(s,i)}}};m.flavours.mssql=(c)=>{let t=c.cls;t.DefaultQueryBuilderOptions.replaceSingleQuotes=!0,t.DefaultQueryBuilderOptions.autoQuoteAliasNames=!1,t.DefaultQueryBuilderOptions.numberedParametersPrefix="@",c.registerValueHandler(Date,(s)=>{let i=s;return`'${i.getUTCFullYear()}-${i.getUTCMonth()+1}-${i.getUTCDate()} ${i.getUTCHours()}:${i.getUTCMinutes()}:${i.getUTCSeconds()}'`}),t.MssqlLimitOffsetTopBlock=class extends t.Block{_limits;_offsets;ParentBlock;LimitBlock;TopBlock;OffsetBlock;constructor(s){super(s);this._limits=null,this._offsets=null;let i=function(e){e=this._sanitizeLimitOffset(e),this._parent._limits=e};this.ParentBlock=class extends t.Block{_parent;constructor(e){super(e.options);this._parent=e}},this.LimitBlock=class extends this.ParentBlock{limit;constructor(e){super(e);this.limit=i}_toParamString(){let e="";if(this._parent._limits&&this._parent._offsets)e=`FETCH NEXT ${this._parent._limits} ROWS ONLY`;return{text:e,values:[]}}},this.TopBlock=class extends this.ParentBlock{top;constructor(e){super(e);this.top=i}_toParamString(){let e="";if(this._parent._limits&&!this._parent._offsets)e=`TOP (${this._parent._limits})`;return{text:e,values:[]}}},this.OffsetBlock=class extends this.ParentBlock{offset(e){this._parent._offsets=this._sanitizeLimitOffset(e)}_toParamString(){let e="";if(this._parent._offsets)e=`OFFSET ${this._parent._offsets} ROWS`;return{text:e,values:[]}}}}LIMIT(){return new this.LimitBlock(this)}TOP(){return new this.TopBlock(this)}OFFSET(){return new this.OffsetBlock(this)}},t.MssqlUpdateTopBlock=class extends t.Block{_limits;limit;top;constructor(s){super(s);this._limits=null;let i=(e)=>{this._limits=this._sanitizeLimitOffset(e)};this.limit=i,this.top=i}_toParamString(){return{text:this._limits?`TOP (${this._limits})`:"",values:[]}}},t.MssqlInsertFieldValueBlock=class extends t.InsertFieldValueBlock{_outputs;constructor(s){super(s);this._outputs=[]}output(s){if(typeof s==="string")this._outputs.push(`INSERTED.${this._sanitizeField(s)}`);else s.forEach((i)=>{this._outputs.push(`INSERTED.${this._sanitizeField(i)}`)})}_toParamString(s){let i=super._toParamString(s);if(i.text.length&&this._outputs.length>0){let e=`OUTPUT ${this._outputs.join(", ")} `,n=i.text.indexOf("VALUES");i.text=i.text.substring(0,n)+e+i.text.substring(n)}return i}},t.MssqlUpdateDeleteOutputBlock=class extends t.Block{_outputs;constructor(s){super(s);this._outputs=[]}outputs(s){for(let i in s)this.output(i,s[i])}output(s,i=null){s=this._sanitizeField(s),i=i?this._sanitizeFieldAlias(i):i,this._outputs.push({name:this.options.forDelete?`DELETED.${s}`:`INSERTED.${s}`,alias:i})}_toParamString(s){let i="";if(this._outputs.length){for(let e of this._outputs)if(i=p(i,", "),i+=e.name,e.alias)i+=` AS ${this._formatFieldAlias(e.alias)}`;i=`OUTPUT ${i}`}return{text:i,values:[]}}},t.Select=class extends t.QueryBuilder{constructor(s,i=null){let e=new t.MssqlLimitOffsetTopBlock(s);i=i||[new t.StringBlock(s,"SELECT"),new t.DistinctBlock(s),e.TOP(),new t.GetFieldBlock(s),new t.FromTableBlock(s),new t.JoinBlock(s),new t.WhereBlock(s),new t.GroupByBlock(s),new t.OrderByBlock(s),e.OFFSET(),e.LIMIT(),new t.UnionBlock(s)];super(s,i)}},t.Update=class extends t.QueryBuilder{constructor(s,i=null){i=i||[new t.StringBlock(s,"UPDATE"),new t.MssqlUpdateTopBlock(s),new t.UpdateTableBlock(s),new t.SetFieldBlock(s),new t.MssqlUpdateDeleteOutputBlock(s),new t.WhereBlock(s)];super(s,i)}},t.Delete=class extends t.QueryBuilder{constructor(s,i=null){i=i||[new t.StringBlock(s,"DELETE"),new t.TargetTableBlock(s),new t.FromTableBlock(f({},s,{singleTable:!0})),new t.JoinBlock(s),new t.MssqlUpdateDeleteOutputBlock(f({},s,{forDelete:!0})),new t.WhereBlock(s),new t.OrderByBlock(s),new t.LimitBlock(s)];super(s,i)}},t.Insert=class extends t.QueryBuilder{constructor(s,i=null){i=i||[new t.StringBlock(s,"INSERT"),new t.IntoTableBlock(s),new t.MssqlInsertFieldValueBlock(s),new t.InsertFieldsFromQueryBlock(s)];super(s,i)}}};var D=S;})();
|