@rwillians/qx 0.1.2 → 0.1.3

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,660 @@
1
+ import * as std from './standard-schema';
2
+ import * as u from './utils';
3
+ // // // // // // // // // // // // // // // // // // // // // // // //
4
+ // SYMBOLS //
5
+ // // // // // // // // // // // // // // // // // // // // // // // //
6
+ /**
7
+ * @private Symbol used to store the table name on aliased tables.
8
+ * @since 0.1.0
9
+ * @version 1
10
+ */
11
+ const TABLE_NAME = Symbol.for('~exto.table-name');
12
+ /**
13
+ * @private Symbol used to store the table alias on aliased tables.
14
+ * @since 0.1.0
15
+ * @version 1
16
+ */
17
+ const TABLE_ALIAS = Symbol.for('~exto.table-alias');
18
+ /**
19
+ * @private A builder for column properties.
20
+ * @since 0.1.0
21
+ * @version 1
22
+ */
23
+ class ColumnPropsBuilder {
24
+ props;
25
+ constructor(props) {
26
+ this.props = props;
27
+ }
28
+ /**
29
+ * @public Marks the column as autoincrementing.
30
+ * @since 0.1.0
31
+ * @version 1
32
+ */
33
+ autoincrement() {
34
+ if (this.props.type !== 'INTEGER')
35
+ throw new Error('Autoincrement can only be set on integer columns');
36
+ return new ColumnPropsBuilder({ ...this.props, autoincrement: true });
37
+ }
38
+ /**
39
+ * @public Sets a default value for the column.
40
+ * @since 0.1.0
41
+ * @version 1
42
+ */
43
+ default(value) {
44
+ return new ColumnPropsBuilder({ ...this.props, default: value });
45
+ }
46
+ /**
47
+ * @public Marks the column as nullable.
48
+ * @since 0.1.0
49
+ * @version 1
50
+ * @throws {Error} if the column is a primary key.
51
+ */
52
+ nullable() {
53
+ if (this.props.primaryKey)
54
+ throw new Error('Cannot set nullable on a primary key column');
55
+ const { schema, ...props } = this.props;
56
+ return new ColumnPropsBuilder({ ...props, nullable: true, schema: std.nullable(schema) });
57
+ }
58
+ /**
59
+ * @public Marks the column as a primary key.
60
+ * @since 0.1.0
61
+ * @version 1
62
+ * @throws {Error} if the column is nullable.
63
+ */
64
+ primaryKey() {
65
+ if (this.props.nullable)
66
+ throw new Error('Cannot make a nullable column a primary key');
67
+ return new ColumnPropsBuilder({ ...this.props, primaryKey: true });
68
+ }
69
+ }
70
+ /**
71
+ * @public A way to define a column with a custom standard schema.
72
+ * @since 0.1.0
73
+ * @version 1
74
+ */
75
+ const defineColumn = (baseProps) => new ColumnPropsBuilder(baseProps);
76
+ /**
77
+ * @public Built-in column types.
78
+ * @since 0.1.0
79
+ * @version 1
80
+ */
81
+ const types = {
82
+ /**
83
+ * @public Defines a column type that accepts binary data.
84
+ * @since 0.1.0
85
+ * @version 1
86
+ */
87
+ binary: () => defineColumn({
88
+ type: 'BINARY',
89
+ schema: std.instanceOf(Uint8Array),
90
+ }),
91
+ /**
92
+ * @public Defines a column type that accepts boolean values.
93
+ * @since 0.1.0
94
+ * @version 1
95
+ */
96
+ boolean: () => defineColumn({
97
+ type: 'BOOLEAN',
98
+ schema: std.boolean(),
99
+ }),
100
+ /**
101
+ * @public Defines a column type that accepts a Date object, an
102
+ * ISO 8601 date string, or a Unix timestamp in milliseconds.
103
+ * @since 0.1.0
104
+ * @version 1
105
+ */
106
+ datetime: () => defineColumn({
107
+ type: 'DATETIME',
108
+ schema: std.date(),
109
+ }),
110
+ /**
111
+ * @public Defines a column type that accepts floating-point numbers.
112
+ * @since 0.1.0
113
+ * @version 1
114
+ */
115
+ float: () => defineColumn({
116
+ type: 'FLOAT',
117
+ schema: std.number({ min: Number.MIN_VALUE, max: Number.MAX_VALUE }),
118
+ }),
119
+ /**
120
+ * @public Defines a column type that accepts integer numbers.
121
+ * @since 0.1.0
122
+ * @version 1
123
+ */
124
+ integer: () => defineColumn({
125
+ type: 'INTEGER',
126
+ schema: std.integer({ min: Number.MIN_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER }),
127
+ }),
128
+ /**
129
+ * @public Defines a column type that accepts small strings (VARCHAR,
130
+ * up to 255 characters).
131
+ * @since 0.1.0
132
+ * @version 1
133
+ * @throws {Error} if the specified size is greater than 255.
134
+ */
135
+ string: ({ size = 255 } = {}) => defineColumn({
136
+ type: 'VARCHAR',
137
+ schema: std.string({ max: u.lte(size, 255) }),
138
+ size,
139
+ }),
140
+ /**
141
+ * @public Defines a column type that accepts large strings (TEXT).
142
+ * @since 0.1.0
143
+ * @version 1
144
+ */
145
+ text: () => defineColumn({
146
+ type: 'TEXT',
147
+ schema: std.string(),
148
+ }),
149
+ };
150
+ /**
151
+ * @private Creates the `as` function for aliasing a table.
152
+ * @since 0.1.0
153
+ * @version 1
154
+ */
155
+ const aliasedTableFn = (table) => (alias) => {
156
+ const columns = Object.fromEntries(Object
157
+ .entries(table.columns)
158
+ .map(([cname, col]) => [cname, { ...col, table: alias }]));
159
+ return { [TABLE_NAME]: table.name, [TABLE_ALIAS]: alias, ...columns };
160
+ };
161
+ /**
162
+ * @public Defines a new table.
163
+ * @since 0.1.0
164
+ * @version 1
165
+ */
166
+ const defineTable = (tname, shapeFn) => {
167
+ const columns = Object.fromEntries(Object
168
+ .entries(shapeFn(types))
169
+ .map(([cname, { props }]) => [cname, { ...props, name: cname, table: tname }]));
170
+ const table = { name: tname, columns };
171
+ return { ...table, as: aliasedTableFn(table) };
172
+ };
173
+ /**
174
+ * @public Expression builders.
175
+ * @since 0.1.0
176
+ * @version 1
177
+ */
178
+ const expr = {
179
+ // // // // // // // // // // // // // // // // // // // // // // //
180
+ // BINARY OP EXPRESSIONS //
181
+ // // // // // // // // // // // // // // // // // // // // // // //
182
+ /**
183
+ * @public Builds an equality expression.
184
+ * @since 0.1.0
185
+ * @version 1
186
+ */
187
+ eq: (lhs, rhs) => ({ lhs, op: '=', rhs }),
188
+ /**
189
+ * @public Builds a not-equal expression.
190
+ * @since 0.1.0
191
+ * @version 1
192
+ */
193
+ ne: (lhs, rhs) => ({ lhs, op: '!=', rhs }),
194
+ /**
195
+ * @public Builds a less-than expression.
196
+ * @since 0.1.0
197
+ * @version 1
198
+ */
199
+ lt: (lhs, rhs) => ({ lhs, op: '<', rhs }),
200
+ /**
201
+ * @public Builds a less-than-or-equal expression.
202
+ * @since 0.1.0
203
+ * @version 1
204
+ */
205
+ lte: (lhs, rhs) => ({ lhs, op: '<=', rhs }),
206
+ /**
207
+ * @public Builds a greater-than expression.
208
+ * @since 0.1.0
209
+ * @version 1
210
+ */
211
+ gt: (lhs, rhs) => ({ lhs, op: '>', rhs }),
212
+ /**
213
+ * @public Builds a greater-than-or-equal expression.
214
+ * @since 0.1.0
215
+ * @version 1
216
+ */
217
+ gte: (lhs, rhs) => ({ lhs, op: '>=', rhs }),
218
+ /**
219
+ * @public Builds a LIKE expression.
220
+ * @since 0.1.0
221
+ * @version 1
222
+ */
223
+ like: (lhs, rhs) => ({ lhs, op: 'LIKE', rhs }),
224
+ /**
225
+ * @public Builds a NOT LIKE expression.
226
+ * @since 0.1.0
227
+ * @version 1
228
+ */
229
+ notLike: (lhs, rhs) => ({ lhs, op: 'NOT LIKE', rhs }),
230
+ /**
231
+ * @public Builds an IN expression.
232
+ * @since 0.1.0
233
+ * @version 1
234
+ */
235
+ in: (lhs, rhs) => ({ lhs, op: 'IN', rhs }),
236
+ /**
237
+ * @public Builds a NOT IN expression.
238
+ * @since 0.1.0
239
+ * @version 1
240
+ */
241
+ notIn: (lhs, rhs) => ({ lhs, op: 'NOT IN', rhs }),
242
+ /**
243
+ * @public Builds an IS expression.
244
+ * @since 0.1.0
245
+ * @version 1
246
+ */
247
+ is: (lhs, rhs) => ({ lhs, op: 'IS', rhs }),
248
+ /**
249
+ * @public Builds an IS NOT expression.
250
+ * @since 0.1.0
251
+ * @version 1
252
+ */
253
+ isNot: (lhs, rhs) => ({ lhs, op: 'IS NOT', rhs }),
254
+ // // // // // // // // // // // // // // // // // // // // // // //
255
+ // BOOLEAN OP EXPRESSIONS //
256
+ // // // // // // // // // // // // // // // // // // // // // // //
257
+ /**
258
+ * @public Builds an AND expression.
259
+ * @since 0.1.0
260
+ * @version 1
261
+ */
262
+ and: (exprs) => ({ and: exprs }),
263
+ /**
264
+ * @public Builds an OR expression.
265
+ * @since 0.1.0
266
+ * @version 1
267
+ */
268
+ or: (exprs) => ({ or: exprs }),
269
+ /**
270
+ * @public Builds a NOT expression.
271
+ * @since 0.1.0
272
+ * @version 1
273
+ */
274
+ not: (expr) => ({ not: expr }),
275
+ };
276
+ /**
277
+ * @public Expression type guards.
278
+ * @since 0.1.0
279
+ * @version 1
280
+ */
281
+ const is = {
282
+ // // // // // // // // // // // // // // // // // // // // // // //
283
+ // BINARY OP EXPRESSIONS //
284
+ // // // // // // // // // // // // // // // // // // // // // // //
285
+ /**
286
+ * @public Checks whether the given value is a binary op expression.
287
+ * @since 0.1.0
288
+ * @version 1
289
+ */
290
+ binaryOp: (expr) => u.isPlainObject(expr) && 'op' in expr && 'lhs' in expr && 'rhs' in expr,
291
+ /**
292
+ * @public Checks whether the given value is an equality expression.
293
+ * @since 0.1.0
294
+ * @version 1
295
+ */
296
+ eq: (expr) => u.isPlainObject(expr) && 'op' in expr && expr.op === '=',
297
+ /**
298
+ * @public Checks whether the given value is a not-equal expression.
299
+ * @since 0.1.0
300
+ * @version 1
301
+ */
302
+ ne: (expr) => u.isPlainObject(expr) && 'op' in expr && expr.op === '!=',
303
+ /**
304
+ * @public Checks whether the given value is a less-than expression.
305
+ * @since 0.1.0
306
+ * @version 1
307
+ */
308
+ lt: (expr) => u.isPlainObject(expr) && 'op' in expr && expr.op === '<',
309
+ /**
310
+ * @public Checks whether the given value is a less-than-or-equal expression.
311
+ * @since 0.1.0
312
+ * @version 1
313
+ */
314
+ lte: (expr) => u.isPlainObject(expr) && 'op' in expr && expr.op === '<=',
315
+ /**
316
+ * @public Checks whether the given value is a greater-than expression.
317
+ * @since 0.1.0
318
+ * @version 1
319
+ */
320
+ gt: (expr) => u.isPlainObject(expr) && 'op' in expr && expr.op === '>',
321
+ /**
322
+ * @public Checks whether the given value is a greater-than-or-equal expression.
323
+ * @since 0.1.0
324
+ * @version 1
325
+ */
326
+ gte: (expr) => u.isPlainObject(expr) && 'op' in expr && expr.op === '>=',
327
+ /**
328
+ * @public Checks whether the given value is a LIKE expression.
329
+ * @since 0.1.0
330
+ * @version 1
331
+ */
332
+ like: (expr) => u.isPlainObject(expr) && 'op' in expr && expr.op === 'LIKE',
333
+ /**
334
+ * @public Checks whether the given value is a NOT LIKE expression.
335
+ * @since 0.1.0
336
+ * @version 1
337
+ */
338
+ notLike: (expr) => u.isPlainObject(expr) && 'op' in expr && expr.op === 'NOT LIKE',
339
+ /**
340
+ * @public Checks whether the given value is an IN expression.
341
+ * @since 0.1.0
342
+ * @version 1
343
+ */
344
+ in: (expr) => u.isPlainObject(expr) && 'op' in expr && expr.op === 'IN',
345
+ /**
346
+ * @public Checks whether the given value is a NOT IN expression.
347
+ * @since 0.1.0
348
+ * @version 1
349
+ */
350
+ notIn: (expr) => u.isPlainObject(expr) && 'op' in expr && expr.op === 'NOT IN',
351
+ /**
352
+ * @public Checks whether the given value is an IS expression.
353
+ * @since 0.1.0
354
+ * @version 1
355
+ */
356
+ is: (expr) => u.isPlainObject(expr) && 'is' in expr,
357
+ // // // // // // // // // // // // // // // // // // // // // // //
358
+ // BOOLEAN OP EXPRESSIONS //
359
+ // // // // // // // // // // // // // // // // // // // // // // //
360
+ /**
361
+ * @public Checks whether the given value is an AND expression.
362
+ * @since 0.1.0
363
+ * @version 1
364
+ */
365
+ and: (expr) => u.isPlainObject(expr) && 'and' in expr,
366
+ /**
367
+ * @public Checks whether the given value is an OR expression.
368
+ * @since 0.1.0
369
+ * @version 1
370
+ */
371
+ or: (expr) => u.isPlainObject(expr) && 'or' in expr,
372
+ /**
373
+ * @public Checks whether the given value is a NOT expression.
374
+ * @since 0.1.0
375
+ * @version 1
376
+ */
377
+ not: (expr) => u.isPlainObject(expr) && 'not' in expr,
378
+ // // // // // // // // // // // // // // // // // // // // // // //
379
+ // LITERALS //
380
+ // // // // // // // // // // // // // // // // // // // // // // //
381
+ /**
382
+ * @public Checks whether the given value is a boolean literal.
383
+ * @since 0.1.0
384
+ * @version 1
385
+ */
386
+ boolean: (value) => typeof value === 'boolean',
387
+ /**
388
+ * @public Checks whether the given value is a date literal.
389
+ * @since 0.1.0
390
+ * @version 1
391
+ */
392
+ date: (value) => value instanceof Date,
393
+ /**
394
+ * @public Checks whether the given value is a null literal.
395
+ * @since 0.1.0
396
+ * @version 1
397
+ */
398
+ null: (expr) => expr === null,
399
+ /**
400
+ * @public Checks whether the given value is a number literal.
401
+ * @since 0.1.0
402
+ * @version 1
403
+ */
404
+ number: (expr) => typeof expr === 'number',
405
+ /**
406
+ * @public Checks whether the given value is a string literal.
407
+ * @since 0.1.0
408
+ * @version 1
409
+ */
410
+ string: (expr) => typeof expr === 'string',
411
+ // // // // // // // // // // // // // // // // // // // // // // //
412
+ // OTHERS //
413
+ // // // // // // // // // // // // // // // // // // // // // // //
414
+ /**
415
+ * @public Checks whether the given value is a literal expression.
416
+ * @since 0.1.0
417
+ * @version 1
418
+ */
419
+ literal: (expr) => expr === null || expr instanceof Date || ['boolean', 'number', 'string'].includes(typeof expr),
420
+ /**
421
+ * @public Checks whether the given value is a column expression.
422
+ * @since 0.1.0
423
+ * @version 1
424
+ */
425
+ column: (expr) => u.isPlainObject(expr) && 'type' in expr && 'schema' in expr,
426
+ };
427
+ ;
428
+ ;
429
+ // // // // // // // // // // // // // // // // // // // // // // // //
430
+ // CREATE STATEMENTS //
431
+ // // // // // // // // // // // // // // // // // // // // // // // //
432
+ /**
433
+ * @public Create statement builder.
434
+ * @since 0.1.0
435
+ * @version 1
436
+ */
437
+ const create = {
438
+ /**
439
+ * @public Prepares a create table statement.
440
+ * @since 0.1.0
441
+ * @version 1
442
+ */
443
+ table: (table, options = {}) => ({
444
+ /**
445
+ * @public Executes the create table statement onto the given
446
+ * database.
447
+ * @since 0.1.0
448
+ * @version 1
449
+ */
450
+ onto: async (db) => db.createTable({
451
+ ...options,
452
+ table: table.name,
453
+ columns: Object.values(table.columns),
454
+ }),
455
+ }),
456
+ };
457
+ // // // // // // // // // // // // // // // // // // // // // // // //
458
+ // INSERT STATEMENT //
459
+ // // // // // // // // // // // // // // // // // // // // // // // //
460
+ /**
461
+ * @private Resolves the value of a column before insertion. This is
462
+ * where default values are applied if the column is either
463
+ * missing or nullish.
464
+ * @since 0.1.0
465
+ * @version 1
466
+ */
467
+ const resolveInsertValue = (column, row) => {
468
+ if (column.default)
469
+ return row[column.name] ?? u.resolve(column.default);
470
+ // ↓ it's ok to omit nullable columns, let's make it null if undefined
471
+ if (column.nullable)
472
+ return row[column.name] ?? null;
473
+ return row[column.name];
474
+ };
475
+ /**
476
+ * @private Prepares a row for insertion. Only known fields are kept,
477
+ * additional fields get disposed of.
478
+ * @since 0.1.0
479
+ * @version 1
480
+ */
481
+ const prepareForInsert = (shape) => (row) => Object.fromEntries(Object
482
+ .entries(shape)
483
+ .map(([key, column]) => [key, resolveInsertValue(column, row)]));
484
+ /**
485
+ * @private Takes from the given table only the columns that can be
486
+ * present on insertion. It excludes, for example,
487
+ * autoincrement columns.
488
+ * @since 0.1.0
489
+ * @version 1
490
+ */
491
+ const getInsertShape = (table) => Object.fromEntries(Object
492
+ .entries(table.columns)
493
+ .filter(([_, col]) => !col.autoincrement));
494
+ /**
495
+ * @private Builds the standard schema to be used to parse / validate
496
+ * rows before insertion.
497
+ * @since 0.1.0
498
+ * @version 1
499
+ */
500
+ const buildInsertSchema = (shape) => std.strictObject(u.mapValues(shape, (column) => column.schema));
501
+ /**
502
+ * @public Insert statement builder.
503
+ * @since 0.1.0
504
+ * @version 1
505
+ */
506
+ class InsertBuilder {
507
+ table;
508
+ rows;
509
+ constructor(table, rows = []) {
510
+ this.table = table;
511
+ this.rows = rows;
512
+ }
513
+ /**
514
+ * @public Adds one or more rows to be inserted.
515
+ * @since 0.1.0
516
+ * @version 1
517
+ */
518
+ insert(rows) {
519
+ this.rows.push(...(u.wrap(rows)));
520
+ return this;
521
+ }
522
+ /**
523
+ * @public Executes the insert statement onto the given database.
524
+ * @since 0.1.0
525
+ * @version 1
526
+ */
527
+ async run(db) {
528
+ if (this.rows.length === 0)
529
+ return [];
530
+ const insertShape = getInsertShape(this.table);
531
+ const schema = std.array(buildInsertSchema(insertShape));
532
+ const result = std.parse(schema, this.rows.map(prepareForInsert(insertShape)));
533
+ if (result.issues)
534
+ throw new Error('Failed validation: ' + JSON.stringify(result.issues, null, 2));
535
+ const rows = await db.insert({
536
+ table: this.table.name,
537
+ records: result.value,
538
+ insertShape,
539
+ returnShape: this.table.columns,
540
+ });
541
+ return rows;
542
+ }
543
+ ;
544
+ }
545
+ /**
546
+ * @public Starts an insert statement for the given table.
547
+ * @since 0.1.0
548
+ * @version 1
549
+ */
550
+ const into = (table) => new InsertBuilder(table);
551
+ /**
552
+ * @private Transforms a {@link Query} into a {@link SelectStatement}.
553
+ * @since 0.1.0
554
+ * @version 1
555
+ */
556
+ const toSelectStatement = (query) => ({
557
+ ...query,
558
+ registry: u.mapValues(query.registry, table => table[TABLE_NAME]),
559
+ });
560
+ /**
561
+ * @public Select statement builder with a fluent API.
562
+ *
563
+ * We only need to keep track of two types in here:
564
+ * - the registry of aliased tables, so they can be
565
+ * referenced in expressions and selection; and
566
+ * - the selected columns, so we can infer the returning
567
+ * type of the query.
568
+ * @since 0.1.0
569
+ * @version 1
570
+ */
571
+ class QueryBuilder {
572
+ query;
573
+ constructor(query) {
574
+ this.query = query;
575
+ }
576
+ /**
577
+ * @public Executes the select statement against the given database,
578
+ * returning all matching rows.
579
+ * @since 0.1.0
580
+ * @version 1
581
+ */
582
+ async all(db) {
583
+ // @TODO calls query engine with the query object
584
+ return db.query(toSelectStatement(this.query));
585
+ }
586
+ /**
587
+ * @public Sets a limit on the number of rows to be returned.
588
+ * @since 0.1.0
589
+ * @version 1
590
+ */
591
+ limit(n) {
592
+ return new QueryBuilder({ ...this.query, limit: n });
593
+ }
594
+ /**
595
+ * @public Sets an offset for the rows to be returned.
596
+ * @since 0.1.0
597
+ * @version 1
598
+ */
599
+ offset(n) {
600
+ return new QueryBuilder({ ...this.query, offset: n });
601
+ }
602
+ /**
603
+ * @public Executes the select statement against the given database,
604
+ * returning the first matching row.
605
+ * @since 0.1.0
606
+ * @version 1
607
+ */
608
+ async one(db) {
609
+ // @TODO calls query engine with the query object
610
+ const op = toSelectStatement({ ...this.query, limit: 1, offset: 0 });
611
+ const rows = await db.query(op);
612
+ if (rows.length === 0)
613
+ return null;
614
+ return rows[0];
615
+ }
616
+ /**
617
+ * @public Defines the order by clause of the query.
618
+ * @since 0.1.0
619
+ * @version 1
620
+ */
621
+ orderBy(fn) {
622
+ return new QueryBuilder({ ...this.query, orderBy: fn(this.query.registry) });
623
+ }
624
+ /**
625
+ * @public Defines the selection of the query.
626
+ * @since 0.1.0
627
+ * @version 1
628
+ */
629
+ select(fn) {
630
+ return new QueryBuilder({ ...this.query, select: fn(this.query.registry) });
631
+ }
632
+ /**
633
+ * @public Defines the where clause of the query. If there's already
634
+ * a WHERE clause in the query, the new clause will be
635
+ * ANDed to the existing one.
636
+ * @since 0.1.0
637
+ * @version 1
638
+ */
639
+ where(fn) {
640
+ const value = fn(this.query.registry);
641
+ const where = this.query.where === undefined ? value
642
+ : is.and(this.query.where) ? expr.and([...this.query.where.and, value])
643
+ : expr.and([this.query.where, value]);
644
+ return new QueryBuilder({ ...this.query, where });
645
+ }
646
+ }
647
+ /**
648
+ * @public Starts a select statement from the given table.
649
+ * @since 0.1.0
650
+ * @version 1
651
+ */
652
+ const from = (table) => new QueryBuilder({
653
+ registry: { [table[TABLE_ALIAS]]: table },
654
+ from: table[TABLE_ALIAS],
655
+ select: { ...table },
656
+ });
657
+ // // // // // // // // // // // // // // // // // // // // // // // //
658
+ // EXPORTS //
659
+ // // // // // // // // // // // // // // // // // // // // // // // //
660
+ export { create, defineTable as table, expr, from, into, is, types as t, };
@@ -0,0 +1,7 @@
1
+ import { type ILogger } from './index';
2
+ /**
3
+ * @public Creates a basic console logger that logs all queries.
4
+ * @since 0.1.0
5
+ * @version 1
6
+ */
7
+ export declare const createPrettyLogger: () => ILogger;
@@ -0,0 +1,11 @@
1
+ import { inspect } from 'node:util';
2
+ import { highlight } from 'sql-highlight';
3
+ import {} from './index';
4
+ /**
5
+ * @public Creates a basic console logger that logs all queries.
6
+ * @since 0.1.0
7
+ * @version 1
8
+ */
9
+ export const createPrettyLogger = () => ({
10
+ debug: (sql, params) => { process.stdout.write(highlight(sql) + ' ' + inspect(params, false, null, true) + '\n'); },
11
+ });