kysely 0.28.12 → 0.28.14

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.
@@ -9,5 +9,13 @@ export declare class MysqlQueryCompiler extends DefaultQueryCompiler {
9
9
  protected getLeftIdentifierWrapper(): string;
10
10
  protected getRightIdentifierWrapper(): string;
11
11
  protected sanitizeIdentifier(identifier: string): string;
12
+ /**
13
+ * MySQL requires escaping backslashes in string literals when using the
14
+ * default NO_BACKSLASH_ESCAPES=OFF mode. Without this, a backslash
15
+ * followed by a quote (\') can break out of the string literal.
16
+ *
17
+ * @see https://dev.mysql.com/doc/refman/9.6/en/string-literals.html
18
+ */
19
+ protected sanitizeStringLiteral(value: string): string;
12
20
  protected visitCreateIndex(node: CreateIndexNode): void;
13
21
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MysqlQueryCompiler = void 0;
4
4
  const default_query_compiler_js_1 = require("../../query-compiler/default-query-compiler.js");
5
+ const LITERAL_ESCAPE_REGEX = /\\|'/g;
5
6
  const ID_WRAP_REGEX = /`/g;
6
7
  class MysqlQueryCompiler extends default_query_compiler_js_1.DefaultQueryCompiler {
7
8
  getCurrentParameterPlaceholder() {
@@ -20,14 +21,24 @@ class MysqlQueryCompiler extends default_query_compiler_js_1.DefaultQueryCompile
20
21
  return '';
21
22
  }
22
23
  getLeftIdentifierWrapper() {
23
- return '`';
24
+ return ID_WRAP_REGEX.source;
24
25
  }
25
26
  getRightIdentifierWrapper() {
26
- return '`';
27
+ return ID_WRAP_REGEX.source;
27
28
  }
28
29
  sanitizeIdentifier(identifier) {
29
30
  return identifier.replace(ID_WRAP_REGEX, '``');
30
31
  }
32
+ /**
33
+ * MySQL requires escaping backslashes in string literals when using the
34
+ * default NO_BACKSLASH_ESCAPES=OFF mode. Without this, a backslash
35
+ * followed by a quote (\') can break out of the string literal.
36
+ *
37
+ * @see https://dev.mysql.com/doc/refman/9.6/en/string-literals.html
38
+ */
39
+ sanitizeStringLiteral(value) {
40
+ return value.replace(LITERAL_ESCAPE_REGEX, (char) => char === '\\' ? '\\\\' : "''");
41
+ }
31
42
  visitCreateIndex(node) {
32
43
  this.append('create ');
33
44
  if (node.unique) {
@@ -28,6 +28,14 @@ export declare class CaseThenBuilder<DB, TB extends keyof DB, W, O> {
28
28
  *
29
29
  * A `then` call can be followed by {@link Whenable.when}, {@link CaseWhenBuilder.else},
30
30
  * {@link CaseWhenBuilder.end} or {@link CaseWhenBuilder.endCase} call.
31
+ *
32
+ * **Note:** Numbers, booleans, and `null` values are inlined directly into the
33
+ * SQL query string (e.g. `then 1`, `then true`, `then null`) instead of being
34
+ * added as parameterized values (e.g. `then $1`). This allows the database
35
+ * engine to correctly infer the data type of the `case` expression result.
36
+ * Without this behavior, all results would be returned as strings.
37
+ *
38
+ * String values are always parameterized as usual.
31
39
  */
32
40
  then<E extends Expression<unknown>>(expression: E): CaseWhenBuilder<DB, TB, W, O | ExtractTypeFromValueExpression<E>>;
33
41
  then<V>(value: V): CaseWhenBuilder<DB, TB, W, O | V>;
@@ -47,6 +55,14 @@ export declare class CaseWhenBuilder<DB, TB extends keyof DB, W, O> implements W
47
55
  * Adds an `else` clause to the `case` statement.
48
56
  *
49
57
  * An `else` call must be followed by an {@link Endable.end} or {@link Endable.endCase} call.
58
+ *
59
+ * **Note:** Numbers, booleans, and `null` values are inlined directly into the
60
+ * SQL query string (e.g. `else 0`, `else false`, `else null`) instead of being
61
+ * added as parameterized values (e.g. `else $1`). This allows the database
62
+ * engine to correctly infer the data type of the `case` expression result.
63
+ * Without this behavior, all results would be returned as strings.
64
+ *
65
+ * String values are always parameterized as usual.
50
66
  */
51
67
  else<E extends Expression<unknown>>(expression: E): CaseEndBuilder<DB, TB, O | ExtractTypeFromValueExpression<E>>;
52
68
  else<V>(value: V): CaseEndBuilder<DB, TB, O | V>;
@@ -392,7 +392,7 @@ class DefaultQueryCompiler extends operation_node_visitor_js_1.OperationNodeVisi
392
392
  }
393
393
  visitCreateTable(node) {
394
394
  this.append('create ');
395
- if (node.frontModifiers && node.frontModifiers.length > 0) {
395
+ if (node.frontModifiers?.length) {
396
396
  this.compileList(node.frontModifiers, ' ');
397
397
  this.append(' ');
398
398
  }
@@ -404,22 +404,22 @@ class DefaultQueryCompiler extends operation_node_visitor_js_1.OperationNodeVisi
404
404
  this.append('if not exists ');
405
405
  }
406
406
  this.visitNode(node.table);
407
- if (node.selectQuery) {
408
- this.append(' as ');
409
- this.visitNode(node.selectQuery);
410
- }
411
- else {
407
+ if (!node.selectQuery) {
412
408
  this.append(' (');
413
409
  this.compileList([...node.columns, ...(node.constraints ?? [])]);
414
410
  this.append(')');
415
- if (node.onCommit) {
416
- this.append(' on commit ');
417
- this.append(node.onCommit);
418
- }
419
- if (node.endModifiers && node.endModifiers.length > 0) {
420
- this.append(' ');
421
- this.compileList(node.endModifiers, ' ');
422
- }
411
+ }
412
+ if (node.onCommit) {
413
+ this.append(' on commit ');
414
+ this.append(node.onCommit);
415
+ }
416
+ if (node.endModifiers?.length) {
417
+ this.append(' ');
418
+ this.compileList(node.endModifiers, ' ');
419
+ }
420
+ if (node.selectQuery) {
421
+ this.append(' as ');
422
+ this.visitNode(node.selectQuery);
423
423
  }
424
424
  }
425
425
  visitColumnDefinition(node) {
@@ -144,7 +144,7 @@ export type Selectable<R> = DrainOuterGeneric<{
144
144
  * // }
145
145
  * ```
146
146
  */
147
- export type Insertable<R> = DrainOuterGeneric<{
147
+ export type Insertable<R> = DrainOuterGeneric<object & {
148
148
  [K in NonNullableInsertKeys<R>]: InsertType<R[K]>;
149
149
  } & {
150
150
  [K in NullableInsertKeys<R>]?: InsertType<R[K]>;
@@ -9,5 +9,13 @@ export declare class MysqlQueryCompiler extends DefaultQueryCompiler {
9
9
  protected getLeftIdentifierWrapper(): string;
10
10
  protected getRightIdentifierWrapper(): string;
11
11
  protected sanitizeIdentifier(identifier: string): string;
12
+ /**
13
+ * MySQL requires escaping backslashes in string literals when using the
14
+ * default NO_BACKSLASH_ESCAPES=OFF mode. Without this, a backslash
15
+ * followed by a quote (\') can break out of the string literal.
16
+ *
17
+ * @see https://dev.mysql.com/doc/refman/9.6/en/string-literals.html
18
+ */
19
+ protected sanitizeStringLiteral(value: string): string;
12
20
  protected visitCreateIndex(node: CreateIndexNode): void;
13
21
  }
@@ -1,5 +1,6 @@
1
1
  /// <reference types="./mysql-query-compiler.d.ts" />
2
2
  import { DefaultQueryCompiler } from '../../query-compiler/default-query-compiler.js';
3
+ const LITERAL_ESCAPE_REGEX = /\\|'/g;
3
4
  const ID_WRAP_REGEX = /`/g;
4
5
  export class MysqlQueryCompiler extends DefaultQueryCompiler {
5
6
  getCurrentParameterPlaceholder() {
@@ -18,14 +19,24 @@ export class MysqlQueryCompiler extends DefaultQueryCompiler {
18
19
  return '';
19
20
  }
20
21
  getLeftIdentifierWrapper() {
21
- return '`';
22
+ return ID_WRAP_REGEX.source;
22
23
  }
23
24
  getRightIdentifierWrapper() {
24
- return '`';
25
+ return ID_WRAP_REGEX.source;
25
26
  }
26
27
  sanitizeIdentifier(identifier) {
27
28
  return identifier.replace(ID_WRAP_REGEX, '``');
28
29
  }
30
+ /**
31
+ * MySQL requires escaping backslashes in string literals when using the
32
+ * default NO_BACKSLASH_ESCAPES=OFF mode. Without this, a backslash
33
+ * followed by a quote (\') can break out of the string literal.
34
+ *
35
+ * @see https://dev.mysql.com/doc/refman/9.6/en/string-literals.html
36
+ */
37
+ sanitizeStringLiteral(value) {
38
+ return value.replace(LITERAL_ESCAPE_REGEX, (char) => char === '\\' ? '\\\\' : "''");
39
+ }
29
40
  visitCreateIndex(node) {
30
41
  this.append('create ');
31
42
  if (node.unique) {
@@ -28,6 +28,14 @@ export declare class CaseThenBuilder<DB, TB extends keyof DB, W, O> {
28
28
  *
29
29
  * A `then` call can be followed by {@link Whenable.when}, {@link CaseWhenBuilder.else},
30
30
  * {@link CaseWhenBuilder.end} or {@link CaseWhenBuilder.endCase} call.
31
+ *
32
+ * **Note:** Numbers, booleans, and `null` values are inlined directly into the
33
+ * SQL query string (e.g. `then 1`, `then true`, `then null`) instead of being
34
+ * added as parameterized values (e.g. `then $1`). This allows the database
35
+ * engine to correctly infer the data type of the `case` expression result.
36
+ * Without this behavior, all results would be returned as strings.
37
+ *
38
+ * String values are always parameterized as usual.
31
39
  */
32
40
  then<E extends Expression<unknown>>(expression: E): CaseWhenBuilder<DB, TB, W, O | ExtractTypeFromValueExpression<E>>;
33
41
  then<V>(value: V): CaseWhenBuilder<DB, TB, W, O | V>;
@@ -47,6 +55,14 @@ export declare class CaseWhenBuilder<DB, TB extends keyof DB, W, O> implements W
47
55
  * Adds an `else` clause to the `case` statement.
48
56
  *
49
57
  * An `else` call must be followed by an {@link Endable.end} or {@link Endable.endCase} call.
58
+ *
59
+ * **Note:** Numbers, booleans, and `null` values are inlined directly into the
60
+ * SQL query string (e.g. `else 0`, `else false`, `else null`) instead of being
61
+ * added as parameterized values (e.g. `else $1`). This allows the database
62
+ * engine to correctly infer the data type of the `case` expression result.
63
+ * Without this behavior, all results would be returned as strings.
64
+ *
65
+ * String values are always parameterized as usual.
50
66
  */
51
67
  else<E extends Expression<unknown>>(expression: E): CaseEndBuilder<DB, TB, O | ExtractTypeFromValueExpression<E>>;
52
68
  else<V>(value: V): CaseEndBuilder<DB, TB, O | V>;
@@ -390,7 +390,7 @@ export class DefaultQueryCompiler extends OperationNodeVisitor {
390
390
  }
391
391
  visitCreateTable(node) {
392
392
  this.append('create ');
393
- if (node.frontModifiers && node.frontModifiers.length > 0) {
393
+ if (node.frontModifiers?.length) {
394
394
  this.compileList(node.frontModifiers, ' ');
395
395
  this.append(' ');
396
396
  }
@@ -402,22 +402,22 @@ export class DefaultQueryCompiler extends OperationNodeVisitor {
402
402
  this.append('if not exists ');
403
403
  }
404
404
  this.visitNode(node.table);
405
- if (node.selectQuery) {
406
- this.append(' as ');
407
- this.visitNode(node.selectQuery);
408
- }
409
- else {
405
+ if (!node.selectQuery) {
410
406
  this.append(' (');
411
407
  this.compileList([...node.columns, ...(node.constraints ?? [])]);
412
408
  this.append(')');
413
- if (node.onCommit) {
414
- this.append(' on commit ');
415
- this.append(node.onCommit);
416
- }
417
- if (node.endModifiers && node.endModifiers.length > 0) {
418
- this.append(' ');
419
- this.compileList(node.endModifiers, ' ');
420
- }
409
+ }
410
+ if (node.onCommit) {
411
+ this.append(' on commit ');
412
+ this.append(node.onCommit);
413
+ }
414
+ if (node.endModifiers?.length) {
415
+ this.append(' ');
416
+ this.compileList(node.endModifiers, ' ');
417
+ }
418
+ if (node.selectQuery) {
419
+ this.append(' as ');
420
+ this.visitNode(node.selectQuery);
421
421
  }
422
422
  }
423
423
  visitColumnDefinition(node) {
@@ -144,7 +144,7 @@ export type Selectable<R> = DrainOuterGeneric<{
144
144
  * // }
145
145
  * ```
146
146
  */
147
- export type Insertable<R> = DrainOuterGeneric<{
147
+ export type Insertable<R> = DrainOuterGeneric<object & {
148
148
  [K in NonNullableInsertKeys<R>]: InsertType<R[K]>;
149
149
  } & {
150
150
  [K in NullableInsertKeys<R>]?: InsertType<R[K]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kysely",
3
- "version": "0.28.12",
3
+ "version": "0.28.14",
4
4
  "description": "Type safe SQL query builder",
5
5
  "repository": {
6
6
  "type": "git",
@@ -68,6 +68,7 @@
68
68
  "default": "./dist/cjs/helpers/sqlite.js"
69
69
  }
70
70
  },
71
+ "sideEffects": false,
71
72
  "author": "Sami Koskimäki <sami@jakso.me>",
72
73
  "license": "MIT",
73
74
  "contributors": [
@@ -86,14 +87,14 @@
86
87
  "@types/pg-cursor": "^2.7.2",
87
88
  "@types/semver": "^7.7.1",
88
89
  "@types/sinon": "^21.0.0",
89
- "better-sqlite3": "^12.6.2",
90
+ "better-sqlite3": "^12.8.0",
90
91
  "chai": "^6.2.2",
91
92
  "chai-as-promised": "^8.0.2",
92
93
  "esbuild": "^0.27.4",
93
94
  "jsr": "^0.14.3",
94
95
  "lodash": "^4.17.23",
95
96
  "mocha": "^11.7.5",
96
- "mysql2": "^3.19.1",
97
+ "mysql2": "^3.20.0",
97
98
  "pathe": "^2.0.3",
98
99
  "pg": "^8.20.0",
99
100
  "pg-cursor": "^2.19.0",
@@ -101,7 +102,7 @@
101
102
  "playwright": "^1.58.2",
102
103
  "prettier": "^3.8.1",
103
104
  "semver": "^7.7.4",
104
- "sinon": "^21.0.2",
105
+ "sinon": "^21.0.3",
105
106
  "std-env": "^4.0.0",
106
107
  "tarn": "^3.0.2",
107
108
  "tedious": "^19.2.1",