0
# Dialect Support
1
2
This document covers multi-database compatibility with dialect-specific features, optimizations, and configuration options for PostgreSQL, MySQL, Microsoft SQL Server, Oracle, and SQLite.
3
4
## Supported Dialects
5
6
The SQL builder supports five major database dialects with automatic query generation optimization for each.
7
8
```javascript { .api }
9
type SQLDialect = 'postgres' | 'mysql' | 'mssql' | 'oracle' | 'sqlite';
10
11
// Default dialect (PostgreSQL)
12
const DEFAULT_DIALECT = 'postgres';
13
14
// Set global dialect
15
sql.setDialect(dialect: SQLDialect, config?: object): void;
16
17
// Create dialect-specific instances
18
sql.create(dialect?: SQLDialect, config?: object): Sql;
19
20
// Get dialect implementation
21
function getDialect(dialectName: string): DialectImplementation;
22
```
23
24
## Dialect Configuration
25
26
### Global Dialect Setting
27
28
```javascript
29
// Set dialect globally (affects default sql instance)
30
sql.setDialect('mysql');
31
32
// All subsequent queries use MySQL syntax
33
const query = user.select().toQuery();
34
console.log(query.text); // Uses MySQL quotation marks: `user`.*
35
```
36
37
### Instance-Specific Dialects
38
39
```javascript
40
// Create separate instances for different databases
41
const pgSql = sql.create('postgres');
42
const mysqlSql = sql.create('mysql');
43
const mssqlSql = sql.create('mssql');
44
45
// Each instance generates appropriate SQL
46
const pgQuery = pgSql.define({ name: 'user', columns: ['id'] }).select().toQuery();
47
const mysqlQuery = mysqlSql.define({ name: 'user', columns: ['id'] }).select().toQuery();
48
49
console.log(pgQuery.text); // SELECT "user".* FROM "user"
50
console.log(mysqlQuery.text); // SELECT `user`.* FROM `user`
51
```
52
53
## PostgreSQL (postgres)
54
55
PostgreSQL is the default dialect with the richest feature set support.
56
57
### PostgreSQL-Specific Features
58
59
```javascript { .api }
60
// Advanced PostgreSQL features
61
query.distinctOn(...columns: any[]): Query; // DISTINCT ON
62
query.returning(...columns: any[]): Query; // RETURNING clause
63
query.onConflict(action: ConflictAction): Query; // ON CONFLICT (UPSERT)
64
65
// JSON operators
66
column.key(key: string): BinaryExpression; // -> operator
67
column.keyText(key: string): BinaryExpression; // ->> operator
68
column.path(path: string[]): BinaryExpression; // #> operator
69
column.pathText(path: string[]): BinaryExpression; // #>> operator
70
71
// Array operators
72
column.contains(value: any): BinaryExpression; // @> operator
73
column.containedBy(value: any): BinaryExpression; // <@ operator
74
column.overlap(value: any): BinaryExpression; // && operator
75
76
// Text search
77
column.match(query: string): BinaryExpression; // @@ operator
78
79
// Case-insensitive operations
80
column.ilike(pattern: string): BinaryExpression; // ILIKE
81
column.iregex(pattern: string): BinaryExpression; // ~* operator
82
```
83
84
Usage examples:
85
86
```javascript
87
sql.setDialect('postgres');
88
89
// DISTINCT ON (PostgreSQL specific)
90
const distinctOnQuery = user
91
.select(user.id, user.name, user.email)
92
.distinctOn(user.email)
93
.order(user.email, user.id)
94
.toQuery();
95
96
// RETURNING clause
97
const insertReturningQuery = user
98
.insert({ name: 'John', email: 'john@example.com' })
99
.returning(user.id, user.created_at)
100
.toQuery();
101
102
// ON CONFLICT (UPSERT)
103
const upsertQuery = user
104
.insert({ email: 'john@example.com', name: 'John Doe' })
105
.onConflict({
106
target: 'email',
107
action: { name: 'John Updated' }
108
})
109
.toQuery();
110
111
// JSON operations
112
const jsonQuery = user
113
.select(
114
user.id,
115
user.metadata.key('preferences').as('user_prefs'),
116
user.settings.path(['ui', 'theme']).as('theme')
117
)
118
.where(user.metadata.containsKey('preferences'))
119
.toQuery();
120
121
// Array operations
122
const arrayQuery = post
123
.select()
124
.where(post.tags.contains(['javascript', 'nodejs']))
125
.toQuery();
126
127
// Full-text search
128
const textSearchQuery = document
129
.select()
130
.where(document.search_vector.match('search & terms'))
131
.toQuery();
132
```
133
134
## MySQL (mysql)
135
136
MySQL dialect with MySQL-specific syntax and limitations.
137
138
### MySQL-Specific Features
139
140
```javascript { .api }
141
// MySQL features
142
query.onDuplicate(action: object): Query; // ON DUPLICATE KEY UPDATE
143
column.regexp(pattern: string): BinaryExpression; // REGEXP operator
144
column.rlike(pattern: string): BinaryExpression; // RLIKE operator
145
146
// MySQL quoting uses backticks
147
// Identifiers quoted with `identifier`
148
// Parameter placeholders use ? instead of $1, $2, etc.
149
```
150
151
Usage examples:
152
153
```javascript
154
sql.setDialect('mysql');
155
156
// MySQL uses backticks for identifiers
157
const mysqlQuery = user.select().toQuery();
158
console.log(mysqlQuery.text); // SELECT `user`.* FROM `user`
159
160
// ON DUPLICATE KEY UPDATE
161
const duplicateKeyQuery = user
162
.insert({ id: 1, name: 'John', email: 'john@example.com' })
163
.onDuplicate({
164
name: 'John Updated',
165
updated_at: new Date()
166
})
167
.toQuery();
168
169
// REGEXP operator
170
const regexpQuery = user
171
.select()
172
.where(user.email.regexp('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}'))
173
.toQuery();
174
175
// MySQL parameter style (uses ? placeholders)
176
const paramQuery = user
177
.select()
178
.where(user.name.equals('John'))
179
.toQuery();
180
console.log(paramQuery.text); // SELECT `user`.* FROM `user` WHERE (`user`.`name` = ?)
181
console.log(paramQuery.values); // ['John']
182
```
183
184
### MySQL Functions
185
186
```javascript
187
// MySQL-specific functions
188
const mysqlFunctions = {
189
CONCAT: sql.function('CONCAT'),
190
DATE_FORMAT: sql.function('DATE_FORMAT'),
191
SUBSTRING_INDEX: sql.function('SUBSTRING_INDEX'),
192
GROUP_CONCAT: sql.function('GROUP_CONCAT'),
193
IFNULL: sql.function('IFNULL')
194
};
195
196
const mysqlSpecificQuery = user
197
.select(
198
user.id,
199
mysqlFunctions.CONCAT(user.first_name, ' ', user.last_name).as('full_name'),
200
mysqlFunctions.DATE_FORMAT(user.created_at, '%Y-%m-%d').as('formatted_date'),
201
mysqlFunctions.IFNULL(user.nick_name, user.first_name).as('display_name')
202
)
203
.toQuery();
204
```
205
206
## Microsoft SQL Server (mssql)
207
208
SQL Server dialect with T-SQL specific features.
209
210
### MSSQL-Specific Features
211
212
```javascript { .api }
213
// SQL Server features
214
// Uses square brackets for identifier quoting: [identifier]
215
// Parameter placeholders use @p1, @p2, etc.
216
// Supports TOP clause instead of LIMIT
217
// Temporary tables prefixed with #
218
```
219
220
Usage examples:
221
222
```javascript
223
sql.setDialect('mssql');
224
225
// SQL Server uses square brackets
226
const mssqlQuery = user.select().toQuery();
227
console.log(mssqlQuery.text); // SELECT [user].* FROM [user]
228
229
// SQL Server parameter style
230
const mssqlParamQuery = user
231
.select()
232
.where(user.name.equals('John'))
233
.toQuery();
234
console.log(mssqlParamQuery.text); // Uses @p1, @p2, etc.
235
236
// Temporary tables
237
const tempTable = sql.define({
238
name: 'temp_users',
239
isTemporary: true,
240
columns: ['id', 'name']
241
});
242
243
const tempTableQuery = tempTable.create().toQuery();
244
// Creates table with # prefix: #temp_users
245
```
246
247
### SQL Server Functions
248
249
```javascript
250
// SQL Server specific functions
251
const mssqlFunctions = {
252
ISNULL: sql.function('ISNULL'),
253
DATEPART: sql.function('DATEPART'),
254
CHARINDEX: sql.function('CHARINDEX'),
255
LEN: sql.function('LEN'),
256
GETDATE: sql.function('GETDATE')
257
};
258
259
const mssqlSpecificQuery = user
260
.select(
261
user.id,
262
mssqlFunctions.ISNULL(user.middle_name, '').as('middle_name'),
263
mssqlFunctions.DATEPART('year', user.created_at).as('year_created'),
264
mssqlFunctions.LEN(user.name).as('name_length')
265
)
266
.toQuery();
267
```
268
269
## Oracle (oracle)
270
271
Oracle Database dialect with Oracle SQL specific syntax.
272
273
### Oracle-Specific Features
274
275
```javascript { .api }
276
// Oracle features
277
// Uses double quotes for identifier quoting: "identifier"
278
// Parameter placeholders use :1, :2, etc.
279
// Supports Oracle-specific functions and syntax
280
```
281
282
Usage examples:
283
284
```javascript
285
sql.setDialect('oracle');
286
287
// Oracle parameter style
288
const oracleQuery = user
289
.select()
290
.where(user.name.equals('John'))
291
.toQuery();
292
console.log(oracleQuery.text); // Uses :1, :2, etc. parameters
293
294
// Oracle ROWNUM for limiting (older versions)
295
const limitQuery = user
296
.select()
297
.where('ROWNUM <= 10')
298
.toQuery();
299
```
300
301
### Oracle Functions
302
303
```javascript
304
// Oracle-specific functions
305
const oracleFunctions = {
306
NVL: sql.function('NVL'),
307
NVL2: sql.function('NVL2'),
308
DECODE: sql.function('DECODE'),
309
EXTRACT: sql.function('EXTRACT'),
310
TO_CHAR: sql.function('TO_CHAR'),
311
TO_DATE: sql.function('TO_DATE'),
312
SYSDATE: sql.function('SYSDATE')
313
};
314
315
const oracleSpecificQuery = user
316
.select(
317
user.id,
318
oracleFunctions.NVL(user.nick_name, user.first_name).as('display_name'),
319
oracleFunctions.TO_CHAR(user.created_at, 'YYYY-MM-DD').as('formatted_date'),
320
oracleFunctions.EXTRACT('YEAR FROM', user.created_at).as('year_created')
321
)
322
.toQuery();
323
```
324
325
## SQLite (sqlite)
326
327
SQLite dialect optimized for the lightweight database engine.
328
329
### SQLite-Specific Features
330
331
```javascript { .api }
332
// SQLite features
333
// Uses double quotes for identifier quoting: "identifier"
334
// Parameter placeholders use ?, ?2, etc.
335
// Limited function support compared to other databases
336
// No complex joins in some operations
337
```
338
339
Usage examples:
340
341
```javascript
342
sql.setDialect('sqlite');
343
344
// SQLite parameter style
345
const sqliteQuery = user
346
.select()
347
.where(user.name.equals('John'))
348
.toQuery();
349
console.log(sqliteQuery.text); // Uses ? parameters
350
351
// SQLite date functions
352
const dateQuery = user
353
.select(
354
user.id,
355
user.name,
356
sql.function('DATE')(user.created_at).as('created_date'),
357
sql.function('STRFTIME')('%Y', user.created_at).as('created_year')
358
)
359
.toQuery();
360
```
361
362
### SQLite Functions
363
364
```javascript
365
// SQLite-specific functions
366
const sqliteFunctions = {
367
DATE: sql.function('DATE'),
368
TIME: sql.function('TIME'),
369
DATETIME: sql.function('DATETIME'),
370
STRFTIME: sql.function('STRFTIME'),
371
JULIANDAY: sql.function('JULIANDAY'),
372
IFNULL: sql.function('IFNULL')
373
};
374
375
const sqliteSpecificQuery = user
376
.select(
377
user.id,
378
sqliteFunctions.DATE(user.created_at).as('created_date'),
379
sqliteFunctions.STRFTIME('%Y-%m', user.created_at).as('year_month'),
380
sqliteFunctions.IFNULL(user.nick_name, user.first_name).as('display_name')
381
)
382
.toQuery();
383
```
384
385
## Cross-Dialect Compatibility
386
387
### Writing Portable Queries
388
389
```javascript
390
// Use standard SQL features for portability
391
function createPortableQuery(sqlInstance) {
392
return user
393
.select(
394
user.id,
395
user.name,
396
user.email
397
)
398
.where(
399
user.active.equals(true)
400
.and(user.created_at.gt(new Date('2023-01-01')))
401
)
402
.order(user.name.asc)
403
.limit(10)
404
.toQuery();
405
}
406
407
// Works across all dialects
408
const pgQuery = createPortableQuery(sql.create('postgres'));
409
const mysqlQuery = createPortableQuery(sql.create('mysql'));
410
const sqliteQuery = createPortableQuery(sql.create('sqlite'));
411
```
412
413
### Dialect-Specific Adaptations
414
415
```javascript
416
function createAdaptedQuery(sqlInstance) {
417
const baseQuery = user.select(user.id, user.name, user.email);
418
419
// Add dialect-specific features
420
switch (sqlInstance.dialectName) {
421
case 'postgres':
422
return baseQuery
423
.distinctOn(user.email)
424
.order(user.email, user.id)
425
.toQuery();
426
427
case 'mysql':
428
return baseQuery
429
.where(user.email.regexp('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}'))
430
.toQuery();
431
432
case 'mssql':
433
return baseQuery
434
.where(sql.function('LEN')(user.name).gt(2))
435
.toQuery();
436
437
default:
438
return baseQuery.toQuery();
439
}
440
}
441
```
442
443
## Dialect Configuration Options
444
445
### Custom Dialect Configuration
446
447
```javascript { .api }
448
interface DialectConfig {
449
// Custom configuration options per dialect
450
[key: string]: any;
451
}
452
453
// Configure dialect with options
454
sql.setDialect('postgres', {
455
// Custom PostgreSQL configuration
456
searchPath: ['public', 'custom_schema'],
457
timeZone: 'UTC'
458
});
459
460
sql.setDialect('mysql', {
461
// Custom MySQL configuration
462
charset: 'utf8mb4',
463
timezone: '+00:00'
464
});
465
```
466
467
## Feature Comparison Matrix
468
469
| Feature | PostgreSQL | MySQL | SQL Server | Oracle | SQLite |
470
|---------|------------|-------|------------|--------|--------|
471
| DISTINCT ON | ✓ | ✗ | ✗ | ✗ | ✗ |
472
| RETURNING | ✓ | ✗ | ✓ | ✓ | ✗ |
473
| ON CONFLICT | ✓ | ✗ | ✗ | ✗ | ✓ |
474
| ON DUPLICATE KEY | ✗ | ✓ | ✗ | ✗ | ✗ |
475
| JSON Operators | ✓ | ✓ | ✓ | ✓ | ✓ |
476
| Array Types | ✓ | ✗ | ✗ | ✓ | ✗ |
477
| Full-text Search | ✓ | ✓ | ✓ | ✓ | ✓ |
478
| Window Functions | ✓ | ✓ | ✓ | ✓ | ✓ |
479
| CTEs | ✓ | ✓ | ✓ | ✓ | ✓ |
480
| LIMIT/OFFSET | ✓ | ✓ | ✓ | ✓ | ✓ |
481
482
## Best Practices
483
484
### Dialect Selection
485
486
```javascript
487
// Choose dialect based on your database
488
const dbDialect = process.env.DB_TYPE || 'postgres';
489
sql.setDialect(dbDialect);
490
491
// Or create specific instances
492
const dbInstances = {
493
postgres: sql.create('postgres'),
494
mysql: sql.create('mysql'),
495
mssql: sql.create('mssql'),
496
oracle: sql.create('oracle'),
497
sqlite: sql.create('sqlite')
498
};
499
500
const currentSql = dbInstances[process.env.DB_TYPE];
501
```
502
503
### Error Handling
504
505
```javascript
506
// Handle dialect-specific errors
507
try {
508
sql.setDialect('unknown_dialect');
509
} catch (error) {
510
console.error('Unsupported dialect:', error.message);
511
// Fallback to default
512
sql.setDialect('postgres');
513
}
514
```
515
516
### Testing Across Dialects
517
518
```javascript
519
// Test queries across multiple dialects
520
const dialects = ['postgres', 'mysql', 'sqlite'];
521
const testResults = {};
522
523
dialects.forEach(dialect => {
524
const testSql = sql.create(dialect);
525
const query = user.select().where(user.active.equals(true)).toQuery();
526
testResults[dialect] = {
527
text: query.text,
528
values: query.values
529
};
530
});
531
532
console.log('Cross-dialect test results:', testResults);
533
```