kysely 0.9.3 → 0.9.7
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/dist/cjs/dialect/mysql/mysql-dialect.d.ts +11 -0
- package/dist/cjs/dialect/mysql/mysql-dialect.js +7 -0
- package/dist/cjs/dialect/postgres/postgres-dialect.d.ts +13 -1
- package/dist/cjs/dialect/postgres/postgres-dialect.js +10 -0
- package/dist/cjs/dialect/postgres/postgres-driver.js +2 -2
- package/dist/cjs/dialect/postgres/postgres-query-compiler.js +1 -1
- package/dist/cjs/driver/runtime-driver.d.ts +3 -2
- package/dist/cjs/driver/runtime-driver.js +57 -4
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/kysely.d.ts +31 -9
- package/dist/cjs/kysely.js +25 -9
- package/dist/cjs/migration/migration.d.ts +32 -0
- package/dist/cjs/operation-node/operator-node.d.ts +1 -1
- package/dist/cjs/operation-node/operator-node.js +1 -0
- package/dist/cjs/parser/join-parser.d.ts +4 -4
- package/dist/cjs/plugin/camel-case/camel-case-plugin.js +5 -116
- package/dist/cjs/plugin/camel-case/camel-case-transformer.d.ts +8 -0
- package/dist/cjs/plugin/camel-case/camel-case-transformer.js +19 -0
- package/dist/cjs/plugin/camel-case/camel-case.d.ts +15 -0
- package/dist/cjs/plugin/camel-case/camel-case.js +109 -0
- package/dist/cjs/plugin/kysely-plugin.d.ts +1 -1
- package/dist/cjs/query-builder/query-builder.d.ts +35 -0
- package/dist/cjs/query-builder/query-builder.js +37 -0
- package/dist/cjs/query-executor/default-query-executor.d.ts +1 -0
- package/dist/cjs/query-executor/default-query-executor.js +6 -0
- package/dist/cjs/query-executor/noop-query-executor.d.ts +1 -0
- package/dist/cjs/query-executor/noop-query-executor.js +3 -0
- package/dist/cjs/query-executor/query-executor.d.ts +9 -4
- package/dist/cjs/util/log.d.ts +19 -0
- package/dist/cjs/util/log.js +37 -0
- package/dist/cjs/util/random-string.js +6 -3
- package/dist/cjs/util/type-utils.d.ts +4 -4
- package/dist/esm/dialect/mysql/mysql-dialect.d.ts +11 -0
- package/dist/esm/dialect/mysql/mysql-dialect.js +7 -0
- package/dist/esm/dialect/mysql/mysql-driver.js +1 -1
- package/dist/esm/dialect/postgres/postgres-dialect.d.ts +13 -1
- package/dist/esm/dialect/postgres/postgres-dialect.js +10 -0
- package/dist/esm/dialect/postgres/postgres-driver.js +2 -2
- package/dist/esm/dialect/postgres/postgres-query-compiler.js +1 -1
- package/dist/esm/driver/runtime-driver.d.ts +3 -2
- package/dist/esm/driver/runtime-driver.js +57 -4
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/kysely.d.ts +31 -9
- package/dist/esm/kysely.js +25 -9
- package/dist/esm/migration/migration.d.ts +32 -0
- package/dist/esm/operation-node/operator-node.d.ts +1 -1
- package/dist/esm/operation-node/operator-node.js +1 -0
- package/dist/esm/parser/join-parser.d.ts +4 -4
- package/dist/esm/plugin/camel-case/camel-case-plugin.js +4 -115
- package/dist/esm/plugin/camel-case/camel-case-transformer.d.ts +8 -0
- package/dist/esm/plugin/camel-case/camel-case-transformer.js +15 -0
- package/dist/esm/plugin/camel-case/camel-case.d.ts +15 -0
- package/dist/esm/plugin/camel-case/camel-case.js +104 -0
- package/dist/esm/plugin/kysely-plugin.d.ts +1 -1
- package/dist/esm/query-builder/query-builder.d.ts +35 -0
- package/dist/esm/query-builder/query-builder.js +37 -0
- package/dist/esm/query-executor/default-query-executor.d.ts +1 -0
- package/dist/esm/query-executor/default-query-executor.js +6 -0
- package/dist/esm/query-executor/noop-query-executor.d.ts +1 -0
- package/dist/esm/query-executor/noop-query-executor.js +3 -0
- package/dist/esm/query-executor/query-executor.d.ts +9 -4
- package/dist/esm/util/log.d.ts +19 -0
- package/dist/esm/util/log.js +33 -0
- package/dist/esm/util/random-string.js +6 -3
- package/dist/esm/util/type-utils.d.ts +4 -4
- package/package.json +4 -1
package/dist/esm/kysely.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { DatabaseIntrospector } from './introspection/database-introspector.js';
|
|
|
10
10
|
import { Driver, IsolationLevel } from './driver/driver.js';
|
|
11
11
|
import { ParseContext } from './parser/parse-context.js';
|
|
12
12
|
import { FunctionBuilder } from './query-builder/function-builder.js';
|
|
13
|
+
import { LogLevel } from './util/log.js';
|
|
13
14
|
/**
|
|
14
15
|
* The main Kysely class.
|
|
15
16
|
*
|
|
@@ -127,15 +128,20 @@ export declare class Kysely<DB> extends QueryCreator<DB> {
|
|
|
127
128
|
*/
|
|
128
129
|
get fn(): FunctionBuilder<DB, keyof DB>;
|
|
129
130
|
/**
|
|
130
|
-
*
|
|
131
|
-
* otherwise it's committed.
|
|
131
|
+
* Creates a {@link TransactionBuilder} that can be used to run queries inside a transaction.
|
|
132
132
|
*
|
|
133
|
-
* @
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
133
|
+
* The returned {@link TransactionBuilder} can be used to configure the transaction. The
|
|
134
|
+
* {@link TransactionBuilder.execute} method can then be called to run the transaction.
|
|
135
|
+
* {@link TransactionBuilder.execute} takes a function that is run inside the
|
|
136
|
+
* transaction. If the function throws, the transaction is rolled back. Otherwise
|
|
137
|
+
* the transaction is committed.
|
|
138
|
+
*
|
|
139
|
+
* The callback function passed to the {@link TransactionBuilder.execute | execute}
|
|
140
|
+
* method gets the transaction object as its only argument. The transaction is
|
|
141
|
+
* of type {@link Transaction} which inherits {@link Kysely}. Any query
|
|
142
|
+
* started through the transaction object is executed inside the transaction.
|
|
138
143
|
*
|
|
144
|
+
* @example
|
|
139
145
|
* ```ts
|
|
140
146
|
* const catto = await db.transaction().execute(async (trx) => {
|
|
141
147
|
* const jennifer = await trx.insertInto('person')
|
|
@@ -188,6 +194,10 @@ export declare class Kysely<DB> extends QueryCreator<DB> {
|
|
|
188
194
|
* ```
|
|
189
195
|
*/
|
|
190
196
|
connection(): ConnectionBuilder<DB>;
|
|
197
|
+
/**
|
|
198
|
+
* Returns a copy of this Kysely instance with the given plugin installed.
|
|
199
|
+
*/
|
|
200
|
+
withPlugin(plugin: KyselyPlugin): Kysely<DB>;
|
|
191
201
|
/**
|
|
192
202
|
* Returns a copy of this Kysely instance without any plugins.
|
|
193
203
|
*/
|
|
@@ -220,8 +230,20 @@ export interface KyselyProps {
|
|
|
220
230
|
}
|
|
221
231
|
export declare function isKyselyProps(obj: unknown): obj is KyselyProps;
|
|
222
232
|
export interface KyselyConfig {
|
|
223
|
-
dialect: Dialect;
|
|
224
|
-
plugins?: KyselyPlugin[];
|
|
233
|
+
readonly dialect: Dialect;
|
|
234
|
+
readonly plugins?: KyselyPlugin[];
|
|
235
|
+
/**
|
|
236
|
+
* A list of log levels to log.
|
|
237
|
+
*
|
|
238
|
+
* Currently there's only two levels: `query` and `error`.
|
|
239
|
+
* This will be expanded based on user feedback later.
|
|
240
|
+
*
|
|
241
|
+
* Log levels:
|
|
242
|
+
*
|
|
243
|
+
* - query: Log each query's SQL and duration using console.log
|
|
244
|
+
* - error: Log all query errors using console.error
|
|
245
|
+
*/
|
|
246
|
+
readonly log?: ReadonlyArray<LogLevel>;
|
|
225
247
|
}
|
|
226
248
|
export declare class ConnectionBuilder<DB> {
|
|
227
249
|
#private;
|
package/dist/esm/kysely.js
CHANGED
|
@@ -12,6 +12,7 @@ import { TRANSACTION_ISOLATION_LEVELS, } from './driver/driver.js';
|
|
|
12
12
|
import { preventAwait } from './util/prevent-await.js';
|
|
13
13
|
import { DefaultParseContext } from './parser/parse-context.js';
|
|
14
14
|
import { FunctionBuilder } from './query-builder/function-builder.js';
|
|
15
|
+
import { Log } from './util/log.js';
|
|
15
16
|
/**
|
|
16
17
|
* The main Kysely class.
|
|
17
18
|
*
|
|
@@ -57,15 +58,16 @@ export class Kysely extends QueryCreator {
|
|
|
57
58
|
constructor(args) {
|
|
58
59
|
if (isKyselyProps(args)) {
|
|
59
60
|
super({ executor: args.executor, parseContext: args.parseContext });
|
|
60
|
-
this.#props = freeze(args);
|
|
61
|
+
this.#props = freeze({ ...args });
|
|
61
62
|
}
|
|
62
63
|
else {
|
|
63
64
|
const dialect = args.dialect;
|
|
64
65
|
const driver = dialect.createDriver();
|
|
65
66
|
const compiler = dialect.createQueryCompiler();
|
|
66
67
|
const adapter = dialect.createAdapter();
|
|
68
|
+
const log = new Log(args.log ?? []);
|
|
67
69
|
const parseContext = new DefaultParseContext(adapter);
|
|
68
|
-
const runtimeDriver = new RuntimeDriver(driver);
|
|
70
|
+
const runtimeDriver = new RuntimeDriver(driver, log);
|
|
69
71
|
const connectionProvider = new DefaultConnectionProvider(runtimeDriver);
|
|
70
72
|
const executor = new DefaultQueryExecutor(compiler, connectionProvider, args.plugins ?? []);
|
|
71
73
|
super({ executor, parseContext });
|
|
@@ -163,15 +165,20 @@ export class Kysely extends QueryCreator {
|
|
|
163
165
|
return new FunctionBuilder({ executor: this.#props.executor });
|
|
164
166
|
}
|
|
165
167
|
/**
|
|
166
|
-
*
|
|
167
|
-
* otherwise it's committed.
|
|
168
|
+
* Creates a {@link TransactionBuilder} that can be used to run queries inside a transaction.
|
|
168
169
|
*
|
|
169
|
-
* @
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
170
|
+
* The returned {@link TransactionBuilder} can be used to configure the transaction. The
|
|
171
|
+
* {@link TransactionBuilder.execute} method can then be called to run the transaction.
|
|
172
|
+
* {@link TransactionBuilder.execute} takes a function that is run inside the
|
|
173
|
+
* transaction. If the function throws, the transaction is rolled back. Otherwise
|
|
174
|
+
* the transaction is committed.
|
|
175
|
+
*
|
|
176
|
+
* The callback function passed to the {@link TransactionBuilder.execute | execute}
|
|
177
|
+
* method gets the transaction object as its only argument. The transaction is
|
|
178
|
+
* of type {@link Transaction} which inherits {@link Kysely}. Any query
|
|
179
|
+
* started through the transaction object is executed inside the transaction.
|
|
174
180
|
*
|
|
181
|
+
* @example
|
|
175
182
|
* ```ts
|
|
176
183
|
* const catto = await db.transaction().execute(async (trx) => {
|
|
177
184
|
* const jennifer = await trx.insertInto('person')
|
|
@@ -228,6 +235,15 @@ export class Kysely extends QueryCreator {
|
|
|
228
235
|
connection() {
|
|
229
236
|
return new ConnectionBuilder({ ...this.#props });
|
|
230
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* Returns a copy of this Kysely instance with the given plugin installed.
|
|
240
|
+
*/
|
|
241
|
+
withPlugin(plugin) {
|
|
242
|
+
return new Kysely({
|
|
243
|
+
...this.#props,
|
|
244
|
+
executor: this.#props.executor.withPlugin(plugin),
|
|
245
|
+
});
|
|
246
|
+
}
|
|
231
247
|
/**
|
|
232
248
|
* Returns a copy of this Kysely instance without any plugins.
|
|
233
249
|
*/
|
|
@@ -24,6 +24,38 @@ export declare class MigrationModule {
|
|
|
24
24
|
* path.join(__dirname, 'migrations')
|
|
25
25
|
* )
|
|
26
26
|
* ```
|
|
27
|
+
*
|
|
28
|
+
* In the next example, we use a record of migration objects instead of file folder path.
|
|
29
|
+
* The keys in the object are migration names that can be anything you want. The order of
|
|
30
|
+
* the migrations is determined based on the alphabetical order of the keys in the record.
|
|
31
|
+
* This can be useful if you are using a bundler like webpack or esbuild.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* await db.migration.migrateToLatest({
|
|
36
|
+
* migration1: {
|
|
37
|
+
* async up(db: Kysely<any>): Promise<void> {
|
|
38
|
+
* ...
|
|
39
|
+
* },
|
|
40
|
+
*
|
|
41
|
+
* async down(db: Kysely<any>): Promise<void> {
|
|
42
|
+
* ...
|
|
43
|
+
* }
|
|
44
|
+
* },
|
|
45
|
+
*
|
|
46
|
+
* migration2: {
|
|
47
|
+
* async up(db: Kysely<any>): Promise<void> {
|
|
48
|
+
* ...
|
|
49
|
+
* },
|
|
50
|
+
*
|
|
51
|
+
* async down(db: Kysely<any>): Promise<void> {
|
|
52
|
+
* ...
|
|
53
|
+
* }
|
|
54
|
+
* },
|
|
55
|
+
*
|
|
56
|
+
* ...
|
|
57
|
+
* })
|
|
58
|
+
* ```
|
|
27
59
|
*/
|
|
28
60
|
migrateToLatest(migrationsFolderPath: string): Promise<void>;
|
|
29
61
|
migrateToLatest(allMigrations: Record<string, Migration>): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ArrayItemType } from '../util/type-utils.js';
|
|
2
2
|
import { OperationNode } from './operation-node.js';
|
|
3
|
-
export declare const OPERATORS: readonly ["=", "==", "!=", "<>", ">", ">=", "<", "<=", "in", "not in", "is", "is not", "like", "not like", "ilike", "not ilike", "@>", "<@", "?", "?", "?&", "!<", "!>", "<=>", "!~", "~", "~*", "!~*", "exists", "not exists"];
|
|
3
|
+
export declare const OPERATORS: readonly ["=", "==", "!=", "<>", ">", ">=", "<", "<=", "in", "not in", "is", "is not", "like", "not like", "ilike", "not ilike", "@>", "<@", "?", "?", "?&", "!<", "!>", "<=>", "!~", "~", "~*", "!~*", "exists", "not exists", "&&"];
|
|
4
4
|
export declare type Operator = ArrayItemType<typeof OPERATORS>;
|
|
5
5
|
export interface OperatorNode extends OperationNode {
|
|
6
6
|
readonly kind: 'OperatorNode';
|
|
@@ -3,9 +3,9 @@ import { AnyColumn, AnyColumnWithTable } from '../util/type-utils.js';
|
|
|
3
3
|
import { ExtractAliasFromTableExpression, TableExpressionDatabase } from './table-parser.js';
|
|
4
4
|
import { JoinBuilder } from '../query-builder/join-builder.js';
|
|
5
5
|
import { ParseContext } from './parse-context.js';
|
|
6
|
-
export declare type JoinReferenceExpression<DB, TB extends keyof DB,
|
|
7
|
-
export declare type JoinCallbackExpression<DB, TB extends keyof DB,
|
|
8
|
-
declare type AnyJoinColumn<DB, TB extends keyof DB,
|
|
9
|
-
declare type AnyJoinColumnWithTable<DB, TB extends keyof DB,
|
|
6
|
+
export declare type JoinReferenceExpression<DB, TB extends keyof DB, TE> = AnyJoinColumn<DB, TB, TE> | AnyJoinColumnWithTable<DB, TB, TE>;
|
|
7
|
+
export declare type JoinCallbackExpression<DB, TB extends keyof DB, TE> = (join: JoinBuilder<TableExpressionDatabase<DB, TE>, TB | ExtractAliasFromTableExpression<DB, TE>>) => JoinBuilder<any, any>;
|
|
8
|
+
declare type AnyJoinColumn<DB, TB extends keyof DB, TE> = AnyColumn<TableExpressionDatabase<DB, TE>, TB | ExtractAliasFromTableExpression<DB, TE>>;
|
|
9
|
+
declare type AnyJoinColumnWithTable<DB, TB extends keyof DB, TE> = AnyColumnWithTable<TableExpressionDatabase<DB, TE>, TB | ExtractAliasFromTableExpression<DB, TE>>;
|
|
10
10
|
export declare function parseJoin(ctx: ParseContext, joinType: JoinType, args: any[]): JoinNode;
|
|
11
11
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { OperationNodeTransformer } from '../../operation-node/operation-node-transformer.js';
|
|
2
1
|
import { isObject } from '../../util/object-utils.js';
|
|
2
|
+
import { SnakeCaseTransformer } from './camel-case-transformer.js';
|
|
3
|
+
import { createCamelCaseMapper, createSnakeCaseMapper, } from './camel-case.js';
|
|
3
4
|
/**
|
|
4
5
|
* A plugin that converts snake_case identifiers in the database into
|
|
5
6
|
* camelCase in the javascript side.
|
|
@@ -69,8 +70,8 @@ export class CamelCasePlugin {
|
|
|
69
70
|
#snakeCase;
|
|
70
71
|
#snakeCaseTransformer;
|
|
71
72
|
constructor(opt = {}) {
|
|
72
|
-
this.#camelCase =
|
|
73
|
-
this.#snakeCase =
|
|
73
|
+
this.#camelCase = createCamelCaseMapper(opt);
|
|
74
|
+
this.#snakeCase = createSnakeCaseMapper(opt);
|
|
74
75
|
this.#snakeCaseTransformer = new SnakeCaseTransformer(this.snakeCase.bind(this));
|
|
75
76
|
}
|
|
76
77
|
transformQuery(args) {
|
|
@@ -105,118 +106,6 @@ export class CamelCasePlugin {
|
|
|
105
106
|
return this.#camelCase(str);
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
|
-
class SnakeCaseTransformer extends OperationNodeTransformer {
|
|
109
|
-
#snakeCase;
|
|
110
|
-
constructor(snakeCase) {
|
|
111
|
-
super();
|
|
112
|
-
this.#snakeCase = snakeCase;
|
|
113
|
-
}
|
|
114
|
-
transformIdentifier(node) {
|
|
115
|
-
node = super.transformIdentifier(node);
|
|
116
|
-
return {
|
|
117
|
-
...node,
|
|
118
|
-
identifier: this.#snakeCase(node.identifier),
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
109
|
function canMap(obj) {
|
|
123
110
|
return isObject(obj) && !(obj instanceof Date) && !Buffer.isBuffer(obj);
|
|
124
111
|
}
|
|
125
|
-
function createSnakeCase({ upperCase = false, underscoreBeforeDigits = false, underscoreBetweenUppercaseLetters = false, } = {}) {
|
|
126
|
-
return memoize((str) => {
|
|
127
|
-
if (str.length === 0) {
|
|
128
|
-
return str;
|
|
129
|
-
}
|
|
130
|
-
const upper = str.toUpperCase();
|
|
131
|
-
const lower = str.toLowerCase();
|
|
132
|
-
let out = lower[0];
|
|
133
|
-
for (let i = 1, l = str.length; i < l; ++i) {
|
|
134
|
-
const char = str[i];
|
|
135
|
-
const prevChar = str[i - 1];
|
|
136
|
-
const upperChar = upper[i];
|
|
137
|
-
const prevUpperChar = upper[i - 1];
|
|
138
|
-
const lowerChar = lower[i];
|
|
139
|
-
const prevLowerChar = lower[i - 1];
|
|
140
|
-
// If underScoreBeforeDigits is true then, well, insert an underscore
|
|
141
|
-
// before digits :). Only the first digit gets an underscore if
|
|
142
|
-
// there are multiple.
|
|
143
|
-
if (underscoreBeforeDigits && isDigit(char) && !isDigit(prevChar)) {
|
|
144
|
-
out += '_' + char;
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
// Test if `char` is an upper-case character and that the character
|
|
148
|
-
// actually has different upper and lower case versions.
|
|
149
|
-
if (char === upperChar && upperChar !== lowerChar) {
|
|
150
|
-
const prevCharacterIsUppercase = prevChar === prevUpperChar && prevUpperChar !== prevLowerChar;
|
|
151
|
-
// If underscoreBetweenUppercaseLetters is true, we always place an underscore
|
|
152
|
-
// before consecutive uppercase letters (e.g. "fooBAR" becomes "foo_b_a_r").
|
|
153
|
-
// Otherwise, we don't (e.g. "fooBAR" becomes "foo_bar").
|
|
154
|
-
if (underscoreBetweenUppercaseLetters || !prevCharacterIsUppercase) {
|
|
155
|
-
out += '_' + lowerChar;
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
out += lowerChar;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
out += char;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
if (upperCase) {
|
|
166
|
-
return out.toUpperCase();
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
return out;
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
function createCamelCase({ upperCase = false } = {}) {
|
|
174
|
-
return memoize((str) => {
|
|
175
|
-
if (str.length === 0) {
|
|
176
|
-
return str;
|
|
177
|
-
}
|
|
178
|
-
if (upperCase && isAllUpperCaseSnakeCase(str)) {
|
|
179
|
-
// Only convert to lower case if the string is all upper
|
|
180
|
-
// case snake_case. This allows camelCase strings to go
|
|
181
|
-
// through without changing.
|
|
182
|
-
str = str.toLowerCase();
|
|
183
|
-
}
|
|
184
|
-
let out = str[0];
|
|
185
|
-
for (let i = 1, l = str.length; i < l; ++i) {
|
|
186
|
-
const char = str[i];
|
|
187
|
-
const prevChar = str[i - 1];
|
|
188
|
-
if (char !== '_') {
|
|
189
|
-
if (prevChar === '_') {
|
|
190
|
-
out += char.toUpperCase();
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
out += char;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return out;
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
function isAllUpperCaseSnakeCase(str) {
|
|
201
|
-
for (let i = 1, l = str.length; i < l; ++i) {
|
|
202
|
-
const char = str[i];
|
|
203
|
-
if (char !== '_' && char !== char.toUpperCase()) {
|
|
204
|
-
return false;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return true;
|
|
208
|
-
}
|
|
209
|
-
function isDigit(char) {
|
|
210
|
-
return char >= '0' && char <= '9';
|
|
211
|
-
}
|
|
212
|
-
function memoize(func) {
|
|
213
|
-
const cache = new Map();
|
|
214
|
-
return (str) => {
|
|
215
|
-
let mapped = cache.get(str);
|
|
216
|
-
if (!mapped) {
|
|
217
|
-
mapped = func(str);
|
|
218
|
-
cache.set(str, mapped);
|
|
219
|
-
}
|
|
220
|
-
return mapped;
|
|
221
|
-
};
|
|
222
|
-
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IdentifierNode } from '../../operation-node/identifier-node.js';
|
|
2
|
+
import { OperationNodeTransformer } from '../../operation-node/operation-node-transformer.js';
|
|
3
|
+
import { StringMapper } from './camel-case.js';
|
|
4
|
+
export declare class SnakeCaseTransformer extends OperationNodeTransformer {
|
|
5
|
+
#private;
|
|
6
|
+
constructor(snakeCase: StringMapper);
|
|
7
|
+
protected transformIdentifier(node: IdentifierNode): IdentifierNode;
|
|
8
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { OperationNodeTransformer } from '../../operation-node/operation-node-transformer.js';
|
|
2
|
+
export class SnakeCaseTransformer extends OperationNodeTransformer {
|
|
3
|
+
#snakeCase;
|
|
4
|
+
constructor(snakeCase) {
|
|
5
|
+
super();
|
|
6
|
+
this.#snakeCase = snakeCase;
|
|
7
|
+
}
|
|
8
|
+
transformIdentifier(node) {
|
|
9
|
+
node = super.transformIdentifier(node);
|
|
10
|
+
return {
|
|
11
|
+
...node,
|
|
12
|
+
identifier: this.#snakeCase(node.identifier),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare type StringMapper = (str: string) => string;
|
|
2
|
+
/**
|
|
3
|
+
* Creates a function that transforms camel case strings to snake case.
|
|
4
|
+
*/
|
|
5
|
+
export declare function createSnakeCaseMapper({ upperCase, underscoreBeforeDigits, underscoreBetweenUppercaseLetters, }?: {
|
|
6
|
+
upperCase?: boolean | undefined;
|
|
7
|
+
underscoreBeforeDigits?: boolean | undefined;
|
|
8
|
+
underscoreBetweenUppercaseLetters?: boolean | undefined;
|
|
9
|
+
}): StringMapper;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a function that transforms snake case strings to camel case.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createCamelCaseMapper({ upperCase, }?: {
|
|
14
|
+
upperCase?: boolean | undefined;
|
|
15
|
+
}): StringMapper;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a function that transforms camel case strings to snake case.
|
|
3
|
+
*/
|
|
4
|
+
export function createSnakeCaseMapper({ upperCase = false, underscoreBeforeDigits = false, underscoreBetweenUppercaseLetters = false, } = {}) {
|
|
5
|
+
return memoize((str) => {
|
|
6
|
+
if (str.length === 0) {
|
|
7
|
+
return str;
|
|
8
|
+
}
|
|
9
|
+
const upper = str.toUpperCase();
|
|
10
|
+
const lower = str.toLowerCase();
|
|
11
|
+
let out = lower[0];
|
|
12
|
+
for (let i = 1, l = str.length; i < l; ++i) {
|
|
13
|
+
const char = str[i];
|
|
14
|
+
const prevChar = str[i - 1];
|
|
15
|
+
const upperChar = upper[i];
|
|
16
|
+
const prevUpperChar = upper[i - 1];
|
|
17
|
+
const lowerChar = lower[i];
|
|
18
|
+
const prevLowerChar = lower[i - 1];
|
|
19
|
+
// If underScoreBeforeDigits is true then, well, insert an underscore
|
|
20
|
+
// before digits :). Only the first digit gets an underscore if
|
|
21
|
+
// there are multiple.
|
|
22
|
+
if (underscoreBeforeDigits && isDigit(char) && !isDigit(prevChar)) {
|
|
23
|
+
out += '_' + char;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
// Test if `char` is an upper-case character and that the character
|
|
27
|
+
// actually has different upper and lower case versions.
|
|
28
|
+
if (char === upperChar && upperChar !== lowerChar) {
|
|
29
|
+
const prevCharacterIsUppercase = prevChar === prevUpperChar && prevUpperChar !== prevLowerChar;
|
|
30
|
+
// If underscoreBetweenUppercaseLetters is true, we always place an underscore
|
|
31
|
+
// before consecutive uppercase letters (e.g. "fooBAR" becomes "foo_b_a_r").
|
|
32
|
+
// Otherwise, we don't (e.g. "fooBAR" becomes "foo_bar").
|
|
33
|
+
if (underscoreBetweenUppercaseLetters || !prevCharacterIsUppercase) {
|
|
34
|
+
out += '_' + lowerChar;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
out += lowerChar;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
out += char;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (upperCase) {
|
|
45
|
+
return out.toUpperCase();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Creates a function that transforms snake case strings to camel case.
|
|
54
|
+
*/
|
|
55
|
+
export function createCamelCaseMapper({ upperCase = false, } = {}) {
|
|
56
|
+
return memoize((str) => {
|
|
57
|
+
if (str.length === 0) {
|
|
58
|
+
return str;
|
|
59
|
+
}
|
|
60
|
+
if (upperCase && isAllUpperCaseSnakeCase(str)) {
|
|
61
|
+
// Only convert to lower case if the string is all upper
|
|
62
|
+
// case snake_case. This allows camelCase strings to go
|
|
63
|
+
// through without changing.
|
|
64
|
+
str = str.toLowerCase();
|
|
65
|
+
}
|
|
66
|
+
let out = str[0];
|
|
67
|
+
for (let i = 1, l = str.length; i < l; ++i) {
|
|
68
|
+
const char = str[i];
|
|
69
|
+
const prevChar = str[i - 1];
|
|
70
|
+
if (char !== '_') {
|
|
71
|
+
if (prevChar === '_') {
|
|
72
|
+
out += char.toUpperCase();
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
out += char;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function isAllUpperCaseSnakeCase(str) {
|
|
83
|
+
for (let i = 1, l = str.length; i < l; ++i) {
|
|
84
|
+
const char = str[i];
|
|
85
|
+
if (char !== '_' && char !== char.toUpperCase()) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
function isDigit(char) {
|
|
92
|
+
return char >= '0' && char <= '9';
|
|
93
|
+
}
|
|
94
|
+
function memoize(func) {
|
|
95
|
+
const cache = new Map();
|
|
96
|
+
return (str) => {
|
|
97
|
+
let mapped = cache.get(str);
|
|
98
|
+
if (!mapped) {
|
|
99
|
+
mapped = func(str);
|
|
100
|
+
cache.set(str, mapped);
|
|
101
|
+
}
|
|
102
|
+
return mapped;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -21,7 +21,7 @@ export interface KyselyPlugin {
|
|
|
21
21
|
* return args.node
|
|
22
22
|
* },
|
|
23
23
|
*
|
|
24
|
-
* transformResult(args: PluginTransformResultArgs): QueryResult<
|
|
24
|
+
* transformResult(args: PluginTransformResultArgs): QueryResult<UnknownRow> {
|
|
25
25
|
* const data = this.data.get(args.queryId)
|
|
26
26
|
* return args.result
|
|
27
27
|
* }
|
|
@@ -1582,6 +1582,41 @@ export declare class QueryBuilder<DB, TB extends keyof DB, O = {}> implements Op
|
|
|
1582
1582
|
* ```
|
|
1583
1583
|
*/
|
|
1584
1584
|
unionAll(expression: UnionExpression<DB, O>): QueryBuilder<DB, TB, O>;
|
|
1585
|
+
/**
|
|
1586
|
+
* Simply calls the given function passing `this` as the only argument.
|
|
1587
|
+
*
|
|
1588
|
+
* This method can be useful when adding optional method calls:
|
|
1589
|
+
*
|
|
1590
|
+
* @example
|
|
1591
|
+
* ```ts
|
|
1592
|
+
* db.selectFrom('person')
|
|
1593
|
+
* .selectAll()
|
|
1594
|
+
* .call((qb) => {
|
|
1595
|
+
* if (something) {
|
|
1596
|
+
* return qb.where('something', '=', something)
|
|
1597
|
+
* } else {
|
|
1598
|
+
* return qb.where('somethingElse', '=', somethingElse)
|
|
1599
|
+
* }
|
|
1600
|
+
* })
|
|
1601
|
+
* .execute()
|
|
1602
|
+
* ```
|
|
1603
|
+
*
|
|
1604
|
+
* The next example uses a helper funtion `log` to log a query:
|
|
1605
|
+
*
|
|
1606
|
+
* @example
|
|
1607
|
+
* ```ts
|
|
1608
|
+
* function log<T extends AnyQueryBuilder>(qb: T): T {
|
|
1609
|
+
* console.log(qb.compile())
|
|
1610
|
+
* return qb
|
|
1611
|
+
* }
|
|
1612
|
+
*
|
|
1613
|
+
* db.selectFrom('person')
|
|
1614
|
+
* .selectAll()
|
|
1615
|
+
* .call(log)
|
|
1616
|
+
* .execute()
|
|
1617
|
+
* ```
|
|
1618
|
+
*/
|
|
1619
|
+
call<T>(func: (qb: this) => T): T;
|
|
1585
1620
|
/**
|
|
1586
1621
|
* Gives an alias for the query. This method is only useful for sub queries.
|
|
1587
1622
|
*
|
|
@@ -815,6 +815,43 @@ export class QueryBuilder {
|
|
|
815
815
|
queryNode: SelectQueryNode.cloneWithUnion(this.#props.queryNode, parseUnion(expression, true)),
|
|
816
816
|
});
|
|
817
817
|
}
|
|
818
|
+
/**
|
|
819
|
+
* Simply calls the given function passing `this` as the only argument.
|
|
820
|
+
*
|
|
821
|
+
* This method can be useful when adding optional method calls:
|
|
822
|
+
*
|
|
823
|
+
* @example
|
|
824
|
+
* ```ts
|
|
825
|
+
* db.selectFrom('person')
|
|
826
|
+
* .selectAll()
|
|
827
|
+
* .call((qb) => {
|
|
828
|
+
* if (something) {
|
|
829
|
+
* return qb.where('something', '=', something)
|
|
830
|
+
* } else {
|
|
831
|
+
* return qb.where('somethingElse', '=', somethingElse)
|
|
832
|
+
* }
|
|
833
|
+
* })
|
|
834
|
+
* .execute()
|
|
835
|
+
* ```
|
|
836
|
+
*
|
|
837
|
+
* The next example uses a helper funtion `log` to log a query:
|
|
838
|
+
*
|
|
839
|
+
* @example
|
|
840
|
+
* ```ts
|
|
841
|
+
* function log<T extends AnyQueryBuilder>(qb: T): T {
|
|
842
|
+
* console.log(qb.compile())
|
|
843
|
+
* return qb
|
|
844
|
+
* }
|
|
845
|
+
*
|
|
846
|
+
* db.selectFrom('person')
|
|
847
|
+
* .selectAll()
|
|
848
|
+
* .call(log)
|
|
849
|
+
* .execute()
|
|
850
|
+
* ```
|
|
851
|
+
*/
|
|
852
|
+
call(func) {
|
|
853
|
+
return func(this);
|
|
854
|
+
}
|
|
818
855
|
/**
|
|
819
856
|
* Gives an alias for the query. This method is only useful for sub queries.
|
|
820
857
|
*
|
|
@@ -9,6 +9,7 @@ export declare class DefaultQueryExecutor extends QueryExecutor {
|
|
|
9
9
|
constructor(compiler: QueryCompiler, connectionProvider: ConnectionProvider, plugins?: KyselyPlugin[]);
|
|
10
10
|
compileQuery(node: RootOperationNode): CompiledQuery;
|
|
11
11
|
protected executeQueryImpl<R>(compiledQuery: CompiledQuery): Promise<QueryResult<R>>;
|
|
12
|
+
withPlugin(plugin: KyselyPlugin): DefaultQueryExecutor;
|
|
12
13
|
withPluginAtFront(plugin: KyselyPlugin): DefaultQueryExecutor;
|
|
13
14
|
withConnectionProvider(connectionProvider: ConnectionProvider): QueryExecutor;
|
|
14
15
|
withoutPlugins(): QueryExecutor;
|
|
@@ -15,6 +15,12 @@ export class DefaultQueryExecutor extends QueryExecutor {
|
|
|
15
15
|
return connection.executeQuery(compiledQuery);
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
|
+
withPlugin(plugin) {
|
|
19
|
+
return new DefaultQueryExecutor(this.#compiler, this.#connectionProvider, [
|
|
20
|
+
...this.plugins,
|
|
21
|
+
plugin,
|
|
22
|
+
]);
|
|
23
|
+
}
|
|
18
24
|
withPluginAtFront(plugin) {
|
|
19
25
|
return new DefaultQueryExecutor(this.#compiler, this.#connectionProvider, [
|
|
20
26
|
plugin,
|
|
@@ -11,6 +11,7 @@ export declare class NoopQueryExecutor extends QueryExecutor {
|
|
|
11
11
|
compileQuery(): CompiledQuery;
|
|
12
12
|
protected executeQueryImpl<R>(): Promise<QueryResult<R>>;
|
|
13
13
|
withConnectionProvider(): QueryExecutor;
|
|
14
|
+
withPlugin(plugin: KyselyPlugin): NoopQueryExecutor;
|
|
14
15
|
withPluginAtFront(plugin: KyselyPlugin): NoopQueryExecutor;
|
|
15
16
|
withoutPlugins(): QueryExecutor;
|
|
16
17
|
}
|
|
@@ -14,6 +14,9 @@ export class NoopQueryExecutor extends QueryExecutor {
|
|
|
14
14
|
withConnectionProvider() {
|
|
15
15
|
throw new Error('this query cannot have a connection provider');
|
|
16
16
|
}
|
|
17
|
+
withPlugin(plugin) {
|
|
18
|
+
return new NoopQueryExecutor([...this.plugins, plugin]);
|
|
19
|
+
}
|
|
17
20
|
withPluginAtFront(plugin) {
|
|
18
21
|
return new NoopQueryExecutor([plugin, ...this.plugins]);
|
|
19
22
|
}
|
|
@@ -35,15 +35,20 @@ export declare abstract class QueryExecutor {
|
|
|
35
35
|
* Executes a compiled query.
|
|
36
36
|
*/
|
|
37
37
|
protected abstract executeQueryImpl<R>(compiledQuery: CompiledQuery, queryId: QueryId): Promise<QueryResult<R>>;
|
|
38
|
+
/**
|
|
39
|
+
* Returns a copy of this executor with a new connection provider.
|
|
40
|
+
*/
|
|
41
|
+
abstract withConnectionProvider(connectionProvider: ConnectionProvider): QueryExecutor;
|
|
38
42
|
/**
|
|
39
43
|
* Returns a copy of this executor with a plugin added as the
|
|
40
|
-
*
|
|
44
|
+
* last plugin.
|
|
41
45
|
*/
|
|
42
|
-
abstract
|
|
46
|
+
abstract withPlugin(plugin: KyselyPlugin): QueryExecutor;
|
|
43
47
|
/**
|
|
44
|
-
* Returns a copy of this executor with a
|
|
48
|
+
* Returns a copy of this executor with a plugin added as the
|
|
49
|
+
* first plugin.
|
|
45
50
|
*/
|
|
46
|
-
abstract
|
|
51
|
+
abstract withPluginAtFront(plugin: KyselyPlugin): QueryExecutor;
|
|
47
52
|
/**
|
|
48
53
|
* Returns a copy of this executor without any plugins.
|
|
49
54
|
*/
|