kysely 0.29.0-rc.0 → 0.29.0

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.
Files changed (29) hide show
  1. package/dist/dialect/database-introspector.d.ts +0 -13
  2. package/dist/dialect/mssql/mssql-dialect-config.d.ts +1 -11
  3. package/dist/dialect/mssql/mssql-driver.js +3 -7
  4. package/dist/dialect/mssql/mssql-introspector.d.ts +1 -7
  5. package/dist/dialect/mssql/mssql-introspector.js +0 -5
  6. package/dist/dialect/mysql/mysql-introspector.d.ts +1 -7
  7. package/dist/dialect/mysql/mysql-introspector.js +0 -5
  8. package/dist/dialect/mysql/mysql-query-compiler.d.ts +6 -0
  9. package/dist/dialect/mysql/mysql-query-compiler.js +10 -1
  10. package/dist/dialect/postgres/postgres-introspector.d.ts +1 -7
  11. package/dist/dialect/postgres/postgres-introspector.js +18 -17
  12. package/dist/dialect/sqlite/sqlite-introspector.d.ts +1 -7
  13. package/dist/dialect/sqlite/sqlite-introspector.js +0 -5
  14. package/dist/dialect/sqlite/sqlite-query-compiler.d.ts +1 -0
  15. package/dist/dialect/sqlite/sqlite-query-compiler.js +4 -0
  16. package/dist/expression/expression-builder.d.ts +0 -6
  17. package/dist/expression/expression-builder.js +0 -4
  18. package/dist/operation-node/drop-table-node.d.ts +7 -3
  19. package/dist/operation-node/insert-query-node.d.ts +0 -2
  20. package/dist/operation-node/operation-node-transformer.js +0 -1
  21. package/dist/operation-node/primary-key-constraint-node.d.ts +0 -10
  22. package/dist/operation-node/primary-key-constraint-node.js +0 -6
  23. package/dist/plugin/parse-json-results/parse-json-results-plugin.d.ts +2 -2
  24. package/dist/plugin/parse-json-results/parse-json-results-plugin.js +12 -12
  25. package/dist/query-builder/json-path-builder.js +8 -0
  26. package/dist/query-builder/update-query-builder.js +1 -1
  27. package/dist/query-compiler/default-query-compiler.d.ts +1 -0
  28. package/dist/query-compiler/default-query-compiler.js +12 -10
  29. package/package.json +11 -12
@@ -10,12 +10,6 @@ export interface DatabaseIntrospector {
10
10
  * Get tables and views metadata.
11
11
  */
12
12
  getTables(options?: DatabaseMetadataOptions): Promise<TableMetadata[]>;
13
- /**
14
- * Get the database metadata such as table and column names.
15
- *
16
- * @deprecated Use getTables() instead.
17
- */
18
- getMetadata(options?: DatabaseMetadataOptions): Promise<DatabaseMetadata>;
19
13
  }
20
14
  export interface DatabaseMetadataOptions {
21
15
  /**
@@ -27,13 +21,6 @@ export interface DatabaseMetadataOptions {
27
21
  export interface SchemaMetadata {
28
22
  readonly name: string;
29
23
  }
30
- export interface DatabaseMetadata {
31
- /**
32
- * The tables and views found in the database.
33
- * The propery isView can be used to tell them apart.
34
- */
35
- readonly tables: TableMetadata[];
36
- }
37
24
  export interface TableMetadata {
38
25
  readonly name: string;
39
26
  readonly isView: boolean;
@@ -1,4 +1,3 @@
1
- import type { KyselyTypeError } from '../../util/type-error.js';
2
1
  export interface MssqlDialectConfig {
3
2
  /**
4
3
  * When `true`, connections are reset to their initial states when released
@@ -74,10 +73,6 @@ export interface Tedious {
74
73
  connectionFactory: () => TediousConnection | Promise<TediousConnection>;
75
74
  ISOLATION_LEVEL: TediousIsolationLevel;
76
75
  Request: TediousRequestClass;
77
- /**
78
- * @deprecated use {@link MssqlDialectConfig.resetConnectionsOnRelease} instead.
79
- */
80
- resetConnectionOnRelease?: KyselyTypeError<'deprecated: use `MssqlDialectConfig.resetConnectionsOnRelease` instead'>;
81
76
  TYPES: TediousTypes;
82
77
  }
83
78
  export interface TediousConnection {
@@ -142,12 +137,7 @@ export interface Tarn {
142
137
  * Tarn.js' pool options, excluding `create`, `destroy` and `validate` functions,
143
138
  * which must be implemented by this dialect.
144
139
  */
145
- options: Omit<TarnPoolOptions<any>, 'create' | 'destroy' | 'validate'> & {
146
- /**
147
- * @deprecated use {@link MssqlDialectConfig.validateConnections} instead.
148
- */
149
- validateConnections?: KyselyTypeError<'deprecated: use `MssqlDialectConfig.validateConnections` instead'>;
150
- };
140
+ options: Omit<TarnPoolOptions<any>, 'create' | 'destroy' | 'validate'>;
151
141
  /**
152
142
  * Tarn.js' Pool class.
153
143
  */
@@ -13,9 +13,8 @@ export class MssqlDriver {
13
13
  constructor(config) {
14
14
  this.#config = freeze({ ...config });
15
15
  const { tarn, tedious, validateConnections } = this.#config;
16
- const { validateConnections: deprecatedValidateConnections, ...poolOptions } = tarn.options;
17
16
  this.#pool = new tarn.Pool({
18
- ...poolOptions,
17
+ ...tarn.options,
19
18
  create: async () => {
20
19
  const connection = await tedious.connectionFactory();
21
20
  return await new MssqlConnection(connection, tedious).connect();
@@ -25,8 +24,7 @@ export class MssqlDriver {
25
24
  },
26
25
  // @ts-ignore `tarn` accepts a function that returns a promise here, but
27
26
  // the types are not aligned and it type errors.
28
- validate: validateConnections === false ||
29
- deprecatedValidateConnections === false
27
+ validate: validateConnections === false
30
28
  ? undefined
31
29
  : (connection) => connection[PRIVATE_VALIDATE_METHOD](),
32
30
  });
@@ -53,8 +51,7 @@ export class MssqlDriver {
53
51
  await connection.rollbackTransaction(savepointName);
54
52
  }
55
53
  async releaseConnection(connection) {
56
- if (this.#config.resetConnectionsOnRelease ||
57
- this.#config.tedious.resetConnectionOnRelease) {
54
+ if (this.#config.resetConnectionsOnRelease) {
58
55
  await connection[PRIVATE_RESET_METHOD]();
59
56
  }
60
57
  this.#pool.release(connection);
@@ -68,7 +65,6 @@ class MssqlConnection {
68
65
  #hasSocketError;
69
66
  #tedious;
70
67
  #inflightRequest;
71
- #sessionId;
72
68
  constructor(connection, tedious) {
73
69
  this.#connection = connection;
74
70
  this.#hasSocketError = false;
@@ -1,5 +1,5 @@
1
1
  import type { Kysely } from '../../kysely.js';
2
- import type { DatabaseIntrospector, DatabaseMetadata, DatabaseMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
2
+ import type { DatabaseIntrospector, DatabaseMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
3
3
  export declare class MssqlIntrospector implements DatabaseIntrospector {
4
4
  #private;
5
5
  constructor(db: Kysely<any>);
@@ -11,10 +11,4 @@ export declare class MssqlIntrospector implements DatabaseIntrospector {
11
11
  * Get tables and views metadata.
12
12
  */
13
13
  getTables(options?: DatabaseMetadataOptions): Promise<TableMetadata[]>;
14
- /**
15
- * Get the database metadata such as table and column names.
16
- *
17
- * @deprecated Use getTables() instead.
18
- */
19
- getMetadata(options?: DatabaseMetadataOptions): Promise<DatabaseMetadata>;
20
14
  }
@@ -100,9 +100,4 @@ export class MssqlIntrospector {
100
100
  }
101
101
  return Object.values(tableDictionary);
102
102
  }
103
- async getMetadata(options) {
104
- return {
105
- tables: await this.getTables(options),
106
- };
107
- }
108
103
  }
@@ -1,4 +1,4 @@
1
- import type { DatabaseIntrospector, DatabaseMetadata, DatabaseMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
1
+ import type { DatabaseIntrospector, DatabaseMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
2
2
  import type { Kysely } from '../../kysely.js';
3
3
  export declare class MysqlIntrospector implements DatabaseIntrospector {
4
4
  #private;
@@ -11,10 +11,4 @@ export declare class MysqlIntrospector implements DatabaseIntrospector {
11
11
  * Get tables and views metadata.
12
12
  */
13
13
  getTables(options?: DatabaseMetadataOptions): Promise<TableMetadata[]>;
14
- /**
15
- * Get the database metadata such as table and column names.
16
- *
17
- * @deprecated Use getTables() instead.
18
- */
19
- getMetadata(options?: DatabaseMetadataOptions): Promise<DatabaseMetadata>;
20
14
  }
@@ -46,11 +46,6 @@ export class MysqlIntrospector {
46
46
  const rawColumns = await query.execute();
47
47
  return this.#parseTableMetadata(rawColumns);
48
48
  }
49
- async getMetadata(options) {
50
- return {
51
- tables: await this.getTables(options),
52
- };
53
- }
54
49
  #parseTableMetadata(columns) {
55
50
  return columns.reduce((tables, it) => {
56
51
  let table = tables.find((tbl) => tbl.name === it.TABLE_NAME);
@@ -17,5 +17,11 @@ export declare class MysqlQueryCompiler extends DefaultQueryCompiler {
17
17
  * @see https://dev.mysql.com/doc/refman/9.6/en/string-literals.html
18
18
  */
19
19
  protected sanitizeStringLiteral(value: string): string;
20
+ /**
21
+ * Member values appear inside `"..."` in the JSON path, which itself sits
22
+ * inside a SQL string literal. They must therefore be escaped twice — once
23
+ * for the JSON path grammar, then again for MySQL's string literal parser.
24
+ */
25
+ protected sanitizeJSONPathMemberValue(value: string): string;
20
26
  protected visitCreateIndex(node: CreateIndexNode): void;
21
27
  }
@@ -1,7 +1,8 @@
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
+ const LITERAL_ESCAPE_REGEX = /[\\']/g;
4
4
  const ID_WRAP_REGEX = /`/g;
5
+ const JSON_PATH_MEMBER_ESCAPE_REGEX = /[\\'"]/g;
5
6
  export class MysqlQueryCompiler extends DefaultQueryCompiler {
6
7
  getCurrentParameterPlaceholder() {
7
8
  return '?';
@@ -37,6 +38,14 @@ export class MysqlQueryCompiler extends DefaultQueryCompiler {
37
38
  sanitizeStringLiteral(value) {
38
39
  return value.replace(LITERAL_ESCAPE_REGEX, (char) => char === '\\' ? '\\\\' : "''");
39
40
  }
41
+ /**
42
+ * Member values appear inside `"..."` in the JSON path, which itself sits
43
+ * inside a SQL string literal. They must therefore be escaped twice — once
44
+ * for the JSON path grammar, then again for MySQL's string literal parser.
45
+ */
46
+ sanitizeJSONPathMemberValue(value) {
47
+ return value.replace(JSON_PATH_MEMBER_ESCAPE_REGEX, (char) => char === '\\' ? '\\\\\\\\' : char === "'" ? "''" : '\\\\"');
48
+ }
40
49
  visitCreateIndex(node) {
41
50
  this.append('create ');
42
51
  if (node.unique) {
@@ -1,4 +1,4 @@
1
- import type { DatabaseIntrospector, DatabaseMetadata, DatabaseMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
1
+ import type { DatabaseIntrospector, DatabaseMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
2
2
  import type { Kysely } from '../../kysely.js';
3
3
  export declare class PostgresIntrospector implements DatabaseIntrospector {
4
4
  #private;
@@ -11,10 +11,4 @@ export declare class PostgresIntrospector implements DatabaseIntrospector {
11
11
  * Get tables and views metadata.
12
12
  */
13
13
  getTables(options?: DatabaseMetadataOptions): Promise<TableMetadata[]>;
14
- /**
15
- * Get the database metadata such as table and column names.
16
- *
17
- * @deprecated Use getTables() instead.
18
- */
19
- getMetadata(options?: DatabaseMetadataOptions): Promise<DatabaseMetadata>;
20
14
  }
@@ -66,27 +66,28 @@ export class PostgresIntrospector {
66
66
  const rawColumns = await query.execute();
67
67
  return this.#parseTableMetadata(rawColumns);
68
68
  }
69
- async getMetadata(options) {
70
- return {
71
- tables: await this.getTables(options),
72
- };
73
- }
74
69
  #parseTableMetadata(columns) {
75
- const tableDictionary = new Map();
76
- for (let i = 0, len = columns.length; i < len; i++) {
77
- const column = columns[i];
78
- const { schema, table } = column;
79
- const tableKey = `schema:${schema};table:${table}`;
80
- if (!tableDictionary.has(tableKey)) {
81
- tableDictionary.set(tableKey, freeze({
70
+ const tables = [];
71
+ const schemas = new Map();
72
+ for (const column of columns) {
73
+ let schema = schemas.get(column.schema);
74
+ if (!schema) {
75
+ schema = new Map();
76
+ schemas.set(column.schema, schema);
77
+ }
78
+ let table = schema.get(column.table);
79
+ if (!table) {
80
+ table = freeze({
82
81
  columns: [],
83
82
  isForeign: column.table_type === 'f',
84
83
  isView: column.table_type === 'v',
85
- name: table,
86
- schema,
87
- }));
84
+ name: column.table,
85
+ schema: column.schema,
86
+ });
87
+ schema.set(column.table, table);
88
+ tables.push(table);
88
89
  }
89
- tableDictionary.get(tableKey).columns.push(freeze({
90
+ table.columns.push(freeze({
90
91
  comment: column.column_description ?? undefined,
91
92
  dataType: column.type,
92
93
  dataTypeSchema: column.type_schema,
@@ -96,6 +97,6 @@ export class PostgresIntrospector {
96
97
  name: column.column,
97
98
  }));
98
99
  }
99
- return Array.from(tableDictionary.values());
100
+ return tables;
100
101
  }
101
102
  }
@@ -1,4 +1,4 @@
1
- import type { DatabaseIntrospector, DatabaseMetadata, DatabaseMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
1
+ import type { DatabaseIntrospector, DatabaseMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
2
2
  import type { Kysely } from '../../kysely.js';
3
3
  export declare class SqliteIntrospector implements DatabaseIntrospector {
4
4
  #private;
@@ -11,10 +11,4 @@ export declare class SqliteIntrospector implements DatabaseIntrospector {
11
11
  * Get tables and views metadata.
12
12
  */
13
13
  getTables(options?: DatabaseMetadataOptions): Promise<TableMetadata[]>;
14
- /**
15
- * Get the database metadata such as table and column names.
16
- *
17
- * @deprecated Use getTables() instead.
18
- */
19
- getMetadata(options?: DatabaseMetadataOptions): Promise<DatabaseMetadata>;
20
14
  }
@@ -13,11 +13,6 @@ export class SqliteIntrospector {
13
13
  async getTables(options = { withInternalKyselyTables: false }) {
14
14
  return await this.#getTableMetadata(options);
15
15
  }
16
- async getMetadata(options) {
17
- return {
18
- tables: await this.getTables(options),
19
- };
20
- }
21
16
  #tablesQuery(qb, options) {
22
17
  let tablesQuery = qb
23
18
  .selectFrom('sqlite_master')
@@ -10,5 +10,6 @@ export declare class SqliteQueryCompiler extends DefaultQueryCompiler {
10
10
  protected getRightIdentifierWrapper(): string;
11
11
  protected getAutoIncrement(): string;
12
12
  protected sanitizeIdentifier(identifier: string): string;
13
+ protected sanitizeJSONPathMemberValue(value: string): string;
13
14
  protected visitDefaultInsertValue(_: DefaultInsertValueNode): void;
14
15
  }
@@ -1,6 +1,7 @@
1
1
  /// <reference types="./sqlite-query-compiler.d.ts" />
2
2
  import { DefaultQueryCompiler } from '../../query-compiler/default-query-compiler.js';
3
3
  const ID_WRAP_REGEX = /"/g;
4
+ const JSON_PATH_MEMBER_ESCAPE_REGEX = /[\\'"]/g;
4
5
  export class SqliteQueryCompiler extends DefaultQueryCompiler {
5
6
  visitOrAction(node) {
6
7
  this.append('or ');
@@ -27,6 +28,9 @@ export class SqliteQueryCompiler extends DefaultQueryCompiler {
27
28
  sanitizeIdentifier(identifier) {
28
29
  return identifier.replace(ID_WRAP_REGEX, '""');
29
30
  }
31
+ sanitizeJSONPathMemberValue(value) {
32
+ return value.replace(JSON_PATH_MEMBER_ESCAPE_REGEX, (char) => char === '\\' ? '\\\\' : char === "'" ? "''" : '\\"');
33
+ }
30
34
  visitDefaultInsertValue(_) {
31
35
  // sqlite doesn't support the `default` keyword in inserts.
32
36
  this.append('null');
@@ -908,12 +908,6 @@ export interface ExpressionBuilder<DB, TB extends keyof DB> {
908
908
  * ```
909
909
  */
910
910
  cast<T, RE extends ReferenceExpression<DB, TB> = ReferenceExpression<DB, TB>>(expr: RE, dataType: DataTypeExpression): ExpressionWrapper<DB, TB, T>;
911
- /**
912
- * See {@link QueryCreator.withSchema}
913
- *
914
- * @deprecated Will be removed in kysely 0.25.0.
915
- */
916
- withSchema(schema: string): ExpressionBuilder<DB, TB>;
917
911
  }
918
912
  export declare function createExpressionBuilder<DB, TB extends keyof DB>(executor?: QueryExecutor): ExpressionBuilder<DB, TB>;
919
913
  export declare function expressionBuilder<DB, TB extends keyof DB>(_: SelectQueryBuilder<DB, TB, any>): ExpressionBuilder<DB, TB>;
@@ -2,7 +2,6 @@
2
2
  import { createSelectQueryBuilder, } from '../query-builder/select-query-builder.js';
3
3
  import { SelectQueryNode } from '../operation-node/select-query-node.js';
4
4
  import { parseTableExpressionOrList, parseTable, } from '../parser/table-parser.js';
5
- import { WithSchemaPlugin } from '../plugin/with-schema/with-schema-plugin.js';
6
5
  import { createQueryId } from '../util/query-id.js';
7
6
  import { createFunctionModule, } from '../query-builder/function-module.js';
8
7
  import { parseJSONReference, parseReferenceExpression, parseStringReference, } from '../parser/reference-parser.js';
@@ -112,9 +111,6 @@ export function createExpressionBuilder(executor = NOOP_QUERY_EXECUTOR) {
112
111
  cast(expr, dataType) {
113
112
  return new ExpressionWrapper(CastNode.create(parseReferenceExpression(expr), parseDataTypeExpression(dataType)));
114
113
  },
115
- withSchema(schema) {
116
- return createExpressionBuilder(executor.withPluginAtFront(new WithSchemaPlugin(schema)));
117
- },
118
114
  });
119
115
  eb.fn = createFunctionModule();
120
116
  eb.eb = eb;
@@ -1,6 +1,10 @@
1
1
  import type { OperationNode } from './operation-node.js';
2
2
  import type { TableNode } from './table-node.js';
3
- export type DropTablexNodeParams = Omit<Partial<DropTableNode>, 'kind' | 'table'>;
3
+ export type DropTableNodeParams = Omit<Partial<DropTableNode>, 'kind' | 'table'>;
4
+ /**
5
+ * @deprecated use {@link DropTableNodeParams} instead.
6
+ */
7
+ export type DropTablexNodeParams = DropTableNodeParams;
4
8
  export interface DropTableNode extends OperationNode {
5
9
  readonly kind: 'DropTableNode';
6
10
  readonly table: TableNode;
@@ -10,8 +14,8 @@ export interface DropTableNode extends OperationNode {
10
14
  }
11
15
  type DropTableNodeFactory = Readonly<{
12
16
  is(node: OperationNode): node is DropTableNode;
13
- create(table: TableNode, params?: DropTablexNodeParams): Readonly<DropTableNode>;
14
- cloneWith(dropIndex: DropTableNode, params: DropTablexNodeParams): Readonly<DropTableNode>;
17
+ create(table: TableNode, params?: DropTableNodeParams): Readonly<DropTableNode>;
18
+ cloneWith(dropIndex: DropTableNode, params: DropTableNodeParams): Readonly<DropTableNode>;
15
19
  }>;
16
20
  /**
17
21
  * @internal
@@ -19,8 +19,6 @@ export interface InsertQueryNode extends OperationNode {
19
19
  readonly onConflict?: OnConflictNode;
20
20
  readonly onDuplicateKey?: OnDuplicateKeyNode;
21
21
  readonly with?: WithNode;
22
- /** @deprecated use {@link orAction} instead. */
23
- readonly ignore?: boolean;
24
22
  readonly orAction?: OrActionNode;
25
23
  readonly replace?: boolean;
26
24
  readonly explain?: ExplainNode;
@@ -275,7 +275,6 @@ export class OperationNodeTransformer {
275
275
  onDuplicateKey: this.transformNode(node.onDuplicateKey, queryId),
276
276
  endModifiers: this.transformNodeList(node.endModifiers, queryId),
277
277
  with: this.transformNode(node.with, queryId),
278
- ignore: node.ignore,
279
278
  orAction: this.transformNode(node.orAction, queryId),
280
279
  replace: node.replace,
281
280
  explain: this.transformNode(node.explain, queryId),
@@ -18,14 +18,4 @@ type PrimaryKeyConstraintNodeFactory = Readonly<{
18
18
  * @internal
19
19
  */
20
20
  export declare const PrimaryKeyConstraintNode: PrimaryKeyConstraintNodeFactory;
21
- /**
22
- * Backwards compatibility for a typo in the codebase.
23
- *
24
- * @deprecated Use {@link PrimaryKeyConstraintNode} instead.
25
- */
26
- export declare const PrimaryConstraintNode: Readonly<{
27
- is(node: OperationNode): node is PrimaryKeyConstraintNode;
28
- create(columns: string[], constraintName?: string): Readonly<PrimaryKeyConstraintNode>;
29
- cloneWith(node: PrimaryKeyConstraintNode, props: PrimaryKeyConstraintNodeProps): Readonly<PrimaryKeyConstraintNode>;
30
- }>;
31
21
  export {};
@@ -22,9 +22,3 @@ export const PrimaryKeyConstraintNode = freeze({
22
22
  return freeze({ ...node, ...props });
23
23
  },
24
24
  });
25
- /**
26
- * Backwards compatibility for a typo in the codebase.
27
- *
28
- * @deprecated Use {@link PrimaryKeyConstraintNode} instead.
29
- */
30
- export const PrimaryConstraintNode = PrimaryKeyConstraintNode;
@@ -9,10 +9,10 @@ export interface ParseJSONResultsPluginOptions {
9
9
  * Defaults to a function that checks if the string starts and ends with `{}` or `[]` - meaning anything that might be a JSON string, is attempted to be parsed - and if fails, proceeds.
10
10
  *
11
11
  * @param value - The string value to check.
12
- * @param path - The JSON path leading to this value. e.g. `$[0].users[0].profile`
12
+ * @param jsonPath - The JSON path leading to this value. e.g. `$[0]."users"[0]."profile"`
13
13
  * @return `true` if the string should be JSON parsed.
14
14
  */
15
- shouldParse?: (value: string, path: string) => boolean;
15
+ shouldParse?: (value: string, jsonPath: string) => boolean;
16
16
  /**
17
17
  * When `'in-place'`, arrays' and objects' values are parsed in-place. This is
18
18
  * the most time and space efficient option.
@@ -54,7 +54,7 @@ export class ParseJSONResultsPlugin {
54
54
  objectStrategy: options.objectStrategy || 'in-place',
55
55
  reviver: options.reviver || ((_, value) => value),
56
56
  shouldParse: shouldParse
57
- ? (value, path) => maybeJson(value) && shouldParse(value, path)
57
+ ? (value, jsonPath) => maybeJson(value) && shouldParse(value, jsonPath)
58
58
  : maybeJson,
59
59
  });
60
60
  }
@@ -69,28 +69,28 @@ export class ParseJSONResultsPlugin {
69
69
  };
70
70
  }
71
71
  }
72
- function parseArray(arr, path, options) {
72
+ function parseArray(arr, jsonPath, options) {
73
73
  const target = options.objectStrategy === 'create' ? new Array(arr.length) : arr;
74
74
  for (let i = 0; i < arr.length; ++i) {
75
- target[i] = parse(arr[i], `${path}[${i}]`, options);
75
+ target[i] = parse(arr[i], `${jsonPath}[${i}]`, options);
76
76
  }
77
77
  return target;
78
78
  }
79
- function parse(value, path, options) {
79
+ function parse(value, jsonPath, options) {
80
80
  if (isString(value)) {
81
- return parseString(value, path, options);
81
+ return parseString(value, jsonPath, options);
82
82
  }
83
83
  if (Array.isArray(value)) {
84
- return parseArray(value, path, options);
84
+ return parseArray(value, jsonPath, options);
85
85
  }
86
86
  if (isPlainObject(value)) {
87
- return parseObject(value, path, options);
87
+ return parseObject(value, jsonPath, options);
88
88
  }
89
89
  return value;
90
90
  }
91
- function parseString(str, path, options) {
91
+ function parseString(str, jsonPath, options) {
92
92
  const { shouldParse } = options;
93
- if (!shouldParse(str, path)) {
93
+ if (!shouldParse(str, jsonPath)) {
94
94
  return str;
95
95
  }
96
96
  try {
@@ -106,7 +106,7 @@ function parseString(str, path, options) {
106
106
  delete value.prototype;
107
107
  }
108
108
  return options.reviver(key, value, ...otherArgs);
109
- }), path, { ...options, objectStrategy: 'in-place' });
109
+ }), jsonPath, { ...options, objectStrategy: 'in-place' });
110
110
  }
111
111
  catch (error) {
112
112
  // custom JSON detection should expose parsing errors.
@@ -122,7 +122,7 @@ function maybeJson(value) {
122
122
  return ((value.startsWith('{') && value.endsWith('}')) ||
123
123
  (value.startsWith('[') && value.endsWith(']')));
124
124
  }
125
- function parseObject(obj, path, options) {
125
+ function parseObject(obj, jsonPath, options) {
126
126
  const { objectStrategy } = options;
127
127
  const target = objectStrategy === 'create' ? {} : obj;
128
128
  for (const key of Object.keys(obj)) {
@@ -130,7 +130,7 @@ function parseObject(obj, path, options) {
130
130
  if (key === '__proto__') {
131
131
  continue;
132
132
  }
133
- const parsed = parse(obj[key], `${path}.${key}`, options);
133
+ const parsed = parse(obj[key], `${jsonPath}."${key}"`, options);
134
134
  // prevent prototype pollution
135
135
  if (key === 'constructor' &&
136
136
  isPlainObject(parsed) &&
@@ -7,6 +7,7 @@ import { JSONPathNode } from '../operation-node/json-path-node.js';
7
7
  import { JSONReferenceNode } from '../operation-node/json-reference-node.js';
8
8
  import { isOperationNodeSource } from '../operation-node/operation-node-source.js';
9
9
  import { ValueNode } from '../operation-node/value-node.js';
10
+ const HASH_NEGATIVE_INDEX_REGEX = /^#-\d+$/;
10
11
  export class JSONPathBuilder {
11
12
  #node;
12
13
  constructor(node) {
@@ -80,6 +81,13 @@ export class JSONPathBuilder {
80
81
  * ```
81
82
  */
82
83
  at(index) {
84
+ if ((typeof index !== 'number' && typeof index !== 'string') ||
85
+ (typeof index === 'number' && !Number.isInteger(index)) ||
86
+ (typeof index === 'string' &&
87
+ index !== 'last' &&
88
+ !HASH_NEGATIVE_INDEX_REGEX.test(index))) {
89
+ throw new Error(`Unexpected index value in .at(...): ${index}`);
90
+ }
83
91
  return this.#createBuilderWithPathLeg('ArrayLocation', index);
84
92
  }
85
93
  /**
@@ -8,7 +8,7 @@ import { UpdateQueryNode } from '../operation-node/update-query-node.js';
8
8
  import { parseUpdate, } from '../parser/update-set-parser.js';
9
9
  import { freeze } from '../util/object-utils.js';
10
10
  import { UpdateResult } from './update-result.js';
11
- import { isNoResultErrorConstructor, NoResultError, } from './no-result-error.js';
11
+ import { isNoResultErrorConstructor, NoResultError } from './no-result-error.js';
12
12
  import { parseReferentialBinaryOperation, parseValueBinaryOperationOrExpression, } from '../parser/binary-operation-parser.js';
13
13
  import { parseValueExpression, } from '../parser/value-parser.js';
14
14
  import { LimitNode } from '../operation-node/limit-node.js';
@@ -229,6 +229,7 @@ export declare class DefaultQueryCompiler extends OperationNodeVisitor implement
229
229
  protected getRightExplainOptionsWrapper(): string;
230
230
  protected sanitizeIdentifier(identifier: string): string;
231
231
  protected sanitizeStringLiteral(value: string): string;
232
+ protected sanitizeJSONPathMemberValue(value: string): string;
232
233
  protected addParameter(parameter: unknown): void;
233
234
  protected appendImmediateValue(value: unknown): void;
234
235
  protected appendStringLiteral(value: string): void;
@@ -9,8 +9,8 @@ import { freeze, isString, isNumber, isBoolean, isNull, isDate, isBigInt, } from
9
9
  import { CreateViewNode } from '../operation-node/create-view-node.js';
10
10
  import { SetOperationNode } from '../operation-node/set-operation-node.js';
11
11
  import { WhenNode } from '../operation-node/when-node.js';
12
- import { logOnce } from '../util/log-once.js';
13
12
  const LIT_WRAP_REGEX = /'/g;
13
+ const JSON_PATH_MEMBER_WRAP_REGEX = /['"]/g;
14
14
  export class DefaultQueryCompiler extends OperationNodeVisitor {
15
15
  #sql = '';
16
16
  #parameters = [];
@@ -164,11 +164,6 @@ export class DefaultQueryCompiler extends OperationNodeVisitor {
164
164
  this.append(' ');
165
165
  }
166
166
  this.append(node.replace ? 'replace' : 'insert');
167
- // TODO: remove in 0.29.
168
- if (node.ignore) {
169
- logOnce('`InsertQueryNode.ignore` is deprecated. Use `InsertQueryNode.orAction` instead.');
170
- this.append(' ignore');
171
- }
172
167
  if (node.orAction) {
173
168
  this.append(' ');
174
169
  this.visitNode(node.orAction);
@@ -1220,13 +1215,17 @@ export class DefaultQueryCompiler extends OperationNodeVisitor {
1220
1215
  }
1221
1216
  visitJSONPathLeg(node) {
1222
1217
  const isArrayLocation = node.type === 'ArrayLocation';
1223
- this.append(isArrayLocation ? '[' : '.');
1224
- this.append(typeof node.value === 'string'
1225
- ? this.sanitizeStringLiteral(node.value)
1226
- : String(node.value));
1218
+ const value = String(node.value);
1227
1219
  if (isArrayLocation) {
1220
+ this.append('[');
1221
+ this.append(this.sanitizeStringLiteral(value));
1228
1222
  this.append(']');
1229
1223
  }
1224
+ else {
1225
+ this.append('."');
1226
+ this.append(this.sanitizeJSONPathMemberValue(value));
1227
+ this.append('"');
1228
+ }
1230
1229
  }
1231
1230
  visitJSONOperatorChain(node) {
1232
1231
  for (let i = 0, len = node.values.length; i < len; i++) {
@@ -1375,6 +1374,9 @@ export class DefaultQueryCompiler extends OperationNodeVisitor {
1375
1374
  sanitizeStringLiteral(value) {
1376
1375
  return value.replace(LIT_WRAP_REGEX, "''");
1377
1376
  }
1377
+ sanitizeJSONPathMemberValue(value) {
1378
+ return value.replace(JSON_PATH_MEMBER_WRAP_REGEX, (char) => char === "'" ? "''" : '\\"');
1379
+ }
1378
1380
  addParameter(parameter) {
1379
1381
  this.#parameters.push(parameter);
1380
1382
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "kysely",
3
- "version": "0.29.0-rc.0",
3
+ "version": "0.29.0",
4
4
  "description": "Type safe SQL query builder",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "git://github.com/kysely-org/kysely.git"
7
+ "url": "git+https://github.com/kysely-org/kysely.git"
8
8
  },
9
9
  "homepage": "https://kysely.dev",
10
10
  "keywords": [
@@ -25,7 +25,7 @@
25
25
  "plugins"
26
26
  ],
27
27
  "engines": {
28
- "node": ">=20.0.0"
28
+ "node": ">=22.0.0"
29
29
  },
30
30
  "type": "module",
31
31
  "main": "dist/index.js",
@@ -63,40 +63,39 @@
63
63
  "devDependencies": {
64
64
  "@arethetypeswrong/cli": "0.18.2",
65
65
  "@ark/attest": "0.56.0",
66
- "@electric-sql/pglite": "0.4.4",
66
+ "@electric-sql/pglite": "0.4.5",
67
67
  "@types/better-sqlite3": "7.6.13",
68
68
  "@types/chai": "5.2.3",
69
69
  "@types/chai-as-promised": "8.0.2",
70
70
  "@types/mocha": "10.0.10",
71
- "@types/node": "25.5.2",
71
+ "@types/node": "25.6.1",
72
72
  "@types/pg": "8.20.0",
73
73
  "@types/pg-cursor": "2.7.2",
74
74
  "@types/prototype-pollution-vulnerable-lodash.merge-dont-upgrade": "npm:@types/lodash.merge@4.6.1",
75
75
  "@types/semver": "7.7.1",
76
76
  "@types/sinon": "21.0.1",
77
- "better-sqlite3": "12.8.0",
77
+ "better-sqlite3": "12.9.0",
78
78
  "chai": "6.2.2",
79
79
  "chai-as-promised": "8.0.2",
80
80
  "esbuild": "0.28.0",
81
81
  "jsr": "0.14.3",
82
82
  "lodash": "4.18.1",
83
83
  "mocha": "11.7.5",
84
- "mysql2": "3.21.0",
84
+ "mysql2": "3.22.3",
85
85
  "pathe": "2.0.3",
86
86
  "pg": "8.20.0",
87
87
  "pg-cursor": "2.19.0",
88
- "pkg-types": "2.3.0",
89
88
  "playwright": "1.59.1",
90
- "prettier": "3.8.1",
89
+ "prettier": "3.8.3",
91
90
  "prototype-pollution-vulnerable-lodash.merge-dont-upgrade": "npm:lodash.merge@4.6.1",
92
91
  "semver": "7.7.4",
93
- "sinon": "21.0.3",
94
- "std-env": "4.0.0",
92
+ "sinon": "22.0.0",
93
+ "std-env": "4.1.0",
95
94
  "tarn": "3.0.2",
96
95
  "tedious": "19.2.1",
97
96
  "tsd": "0.33.0",
98
97
  "tsx": "4.21.0",
99
- "typescript": "6.0.2"
98
+ "typescript": "6.0.3"
100
99
  },
101
100
  "scripts": {
102
101
  "clean": "rm -rf dist & rm -rf test/node/dist & rm -rf test/browser/bundle.js",