pgsql-template-tag 0.0.5 → 0.0.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/src/core.d.ts +133 -7
- package/dist/src/core.d.ts.map +1 -1
- package/dist/src/core.js +175 -31
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/sql.d.ts +37 -5
- package/dist/src/sql.d.ts.map +1 -1
- package/dist/src/sql.js +16 -2
- package/package.json +8 -4
- package/src/core.ts +339 -38
- package/src/index.ts +1 -1
- package/src/sql.ts +54 -4
package/dist/src/core.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { UnionToTuple } from "type-fest";
|
|
1
2
|
/**
|
|
2
3
|
* SQL クエリー内で使用される値の型定義です。
|
|
3
4
|
*/
|
|
@@ -5,12 +6,123 @@ export type Value = unknown;
|
|
|
5
6
|
/**
|
|
6
7
|
* SQL クエリーの構築に使用できる生の値、または別の Sql インスタンスを表す型です。
|
|
7
8
|
*/
|
|
8
|
-
export type RawValue = Value | Sql;
|
|
9
|
+
export type RawValue = Value | Slot | Sql;
|
|
10
|
+
/**
|
|
11
|
+
* Slot クラスを一意に識別するためのシンボルです。
|
|
12
|
+
*/
|
|
13
|
+
declare const SLOT_SYMBOL: unique symbol;
|
|
14
|
+
/**
|
|
15
|
+
* Slot クラスの基底となる型定義です。
|
|
16
|
+
*/
|
|
17
|
+
declare const SlotTypes: {
|
|
18
|
+
new (): {
|
|
19
|
+
/**
|
|
20
|
+
* このプロパティーは、TypeScript の `extends Slot` で `Slot` インスタンスのみに一致させるためにあります。そのため、`Slot` と同じプロパティーを持つオブジェクトに対して一致することはありません。
|
|
21
|
+
*/
|
|
22
|
+
readonly ["~kind"]: typeof SLOT_SYMBOL;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* スロットを表すクラスです。
|
|
27
|
+
*
|
|
28
|
+
* スロットは後から値を注入可能なプレースホルダーです。
|
|
29
|
+
*
|
|
30
|
+
* @template TName スロットの名前となる文字列リテラル型です。
|
|
31
|
+
* @template TValue スロットに許容される値の型です。
|
|
32
|
+
*/
|
|
33
|
+
export declare class Slot<const TName extends string = string, TValue extends RawValue = RawValue> extends SlotTypes {
|
|
34
|
+
/**
|
|
35
|
+
* スロット名です。
|
|
36
|
+
*/
|
|
37
|
+
readonly name: TName;
|
|
38
|
+
/**
|
|
39
|
+
* デフォルト値です。
|
|
40
|
+
*/
|
|
41
|
+
readonly defaultValue: TValue;
|
|
42
|
+
/**
|
|
43
|
+
* 新しい Slot インスタンスを初期化します。
|
|
44
|
+
*
|
|
45
|
+
* @param name スロット名です。
|
|
46
|
+
* @param defaultValue デフォルト値です。
|
|
47
|
+
*/
|
|
48
|
+
constructor(...args: null extends TValue ? [name: TName, defaultValue?: TValue] : [name: TName, defaultValue: TValue]);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* オブジェクトのバリューの型を抽出するヘルパー型です。
|
|
52
|
+
*
|
|
53
|
+
* @template T 対象となるオブジェクト型です。
|
|
54
|
+
*/
|
|
55
|
+
type $ValueOf<T> = T[keyof T];
|
|
56
|
+
/**
|
|
57
|
+
* スロットの配列から、再帰的に値をマージして型を決定します。
|
|
58
|
+
*
|
|
59
|
+
* @template TSlots スロットのタプル型です。
|
|
60
|
+
*/
|
|
61
|
+
type $MergeSlotValue<TSlots> = TSlots extends [
|
|
62
|
+
Slot<string, infer TValue>,
|
|
63
|
+
infer TSlot,
|
|
64
|
+
...infer TOtherSlots
|
|
65
|
+
] ? TValue & $MergeSlotValue<[TSlot, ...TOtherSlots]> : TSlots extends [Slot<string, infer TValue>] ? TValue : never;
|
|
66
|
+
/**
|
|
67
|
+
* RawValue の配列からスロット情報を抽出し、名前ごとのマップ型に変換します。
|
|
68
|
+
*
|
|
69
|
+
* @template TValues RawValue の読み取り専用配列型です。
|
|
70
|
+
*/
|
|
71
|
+
type $MapSlotValue<TValues extends readonly RawValue[]> = TValues extends readonly (infer TSlot extends Slot)[] ? {
|
|
72
|
+
[TName in TSlot["name"]]: $MergeSlotValue<UnionToTuple<Extract<TSlot, Slot<TName>>>>;
|
|
73
|
+
} : {};
|
|
74
|
+
/**
|
|
75
|
+
* 指定された値のリストに対して、スロットを実際の内容で置き換えた型を生成します。
|
|
76
|
+
*
|
|
77
|
+
* @template TValues 置き換え対象の配列型です。
|
|
78
|
+
* @template TSlots スロット名と値のマップ型です。
|
|
79
|
+
*/
|
|
80
|
+
type $FillSlots<TValues, TSlots> = TValues extends [infer TValue, ...infer TOtherValues] ? [
|
|
81
|
+
TValue extends Slot<infer TName extends Extract<keyof TSlots, string>, infer TSlotValue> ? TSlotValue extends TSlots[TName] ? TSlotValue : TValue : TValue,
|
|
82
|
+
...$FillSlots<TOtherValues, TSlots>
|
|
83
|
+
] : [];
|
|
84
|
+
/**
|
|
85
|
+
* スロットを埋めるための部分的な引数型を定義します。
|
|
86
|
+
*
|
|
87
|
+
* @template TSlots スロット名と値のマップ型です。
|
|
88
|
+
*/
|
|
89
|
+
type _FillSlots<TSlots> = {
|
|
90
|
+
readonly [TName in Extract<keyof TSlots, string>]?: TSlots[TName];
|
|
91
|
+
} | Iterable<readonly [
|
|
92
|
+
name: $ValueOf<{
|
|
93
|
+
[TName in Extract<keyof TSlots, string>]: TName | Slot<TName, TSlots[TName]>;
|
|
94
|
+
}>,
|
|
95
|
+
value: $ValueOf<TSlots>
|
|
96
|
+
]>;
|
|
97
|
+
/**
|
|
98
|
+
* すべてのスロットを埋めるために必要な引数型を定義します。
|
|
99
|
+
*
|
|
100
|
+
* @template TSlots スロット名と値のマップ型です。
|
|
101
|
+
*/
|
|
102
|
+
type _FillAllSlots<TSlots> = {
|
|
103
|
+
readonly [TName in Extract<keyof TSlots, string>]: TSlots[TName];
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* スロットの部分的な補完に使用する外部向けの型定義です。
|
|
107
|
+
*
|
|
108
|
+
* @template TValues RawValue の配列です。
|
|
109
|
+
*/
|
|
110
|
+
export type FillSlots<TValues extends readonly RawValue[] = readonly RawValue[]> = _FillSlots<$MapSlotValue<TValues>>;
|
|
111
|
+
/**
|
|
112
|
+
* すべてのスロットの強制的な補完に使用する外部向けの型定義です。
|
|
113
|
+
*
|
|
114
|
+
* @template TValues RawValue の配列です。
|
|
115
|
+
*/
|
|
116
|
+
export type FillAllSlots<TValues extends readonly RawValue[] = readonly RawValue[]> = _FillAllSlots<$MapSlotValue<TValues>>;
|
|
9
117
|
/**
|
|
10
118
|
* 安全な SQL クエリーを構築するためのクラスです。
|
|
119
|
+
*
|
|
11
120
|
* プレースホルダーを使用したパラメーター化クエリーを生成します。
|
|
121
|
+
*
|
|
122
|
+
* @template TRawBindings クエリーに渡される生の値のタプル型です。
|
|
12
123
|
*/
|
|
13
|
-
export declare class Sql {
|
|
124
|
+
export declare class Sql<const TRawBindings extends readonly RawValue[] = readonly RawValue[]> {
|
|
125
|
+
#private;
|
|
14
126
|
/**
|
|
15
127
|
* 構築された SQL クエリーテキストを取得します。
|
|
16
128
|
*
|
|
@@ -23,17 +135,29 @@ export declare class Sql {
|
|
|
23
135
|
* クエリーに使用されるパラメーター値の配列です。
|
|
24
136
|
*/
|
|
25
137
|
readonly values: readonly Value[];
|
|
26
|
-
/**
|
|
27
|
-
* 内部状態を保持するためのプロパティーです。
|
|
28
|
-
*/
|
|
29
|
-
private readonly _;
|
|
30
138
|
/**
|
|
31
139
|
* 新しい Sql インスタンスを初期化します。
|
|
32
140
|
*
|
|
33
141
|
* @param rawStrings SQL の断片となる文字列の配列です。
|
|
34
142
|
* @param rawBindings 文字列の間に挿入される値の配列です。
|
|
35
143
|
*/
|
|
36
|
-
constructor(rawStrings: readonly string[], rawBindings:
|
|
144
|
+
constructor(rawStrings: readonly string[], rawBindings: TRawBindings);
|
|
145
|
+
/**
|
|
146
|
+
* スロットを値で埋めます。
|
|
147
|
+
*
|
|
148
|
+
* @template TSlots 指定されたスロットのマップ型です。
|
|
149
|
+
* @param slots スロットの値です。
|
|
150
|
+
* @returns スロットが埋められた新しい Sql インスタンスです。
|
|
151
|
+
*/
|
|
152
|
+
fill<TSlots extends FillSlots<TRawBindings>>(slots: TSlots): Sql<$FillSlots<TRawBindings, TSlots>>;
|
|
153
|
+
/**
|
|
154
|
+
* すべてのスロットを値で埋めます。
|
|
155
|
+
*
|
|
156
|
+
* @template TSlots 全てのスロットをカバーするマップ型です。
|
|
157
|
+
* @param slots スロットの値です。
|
|
158
|
+
* @returns スロットが埋められた新しい Sql インスタンスです。
|
|
159
|
+
*/
|
|
160
|
+
fillAll<TSlots extends FillAllSlots<TRawBindings>>(slots: TSlots): Sql<$FillSlots<TRawBindings, TSlots>>;
|
|
37
161
|
/**
|
|
38
162
|
* オブジェクトを JSON 形式に変換可能な形式で返します。
|
|
39
163
|
*
|
|
@@ -52,6 +176,7 @@ export declare class Sql {
|
|
|
52
176
|
}
|
|
53
177
|
/**
|
|
54
178
|
* 生の文字列を SQL 断片として扱います。
|
|
179
|
+
*
|
|
55
180
|
* この値はパラメーター化の対象にならず、そのままクエリーに含まれます。
|
|
56
181
|
*
|
|
57
182
|
* @param value SQL に含める生の文字列です。
|
|
@@ -90,4 +215,5 @@ export declare function ident(value: string): string;
|
|
|
90
215
|
* @returns エスケープ済みのリテラル文字列を返します。
|
|
91
216
|
*/
|
|
92
217
|
export declare function literal(value: string): string;
|
|
218
|
+
export {};
|
|
93
219
|
//# sourceMappingURL=core.d.ts.map
|
package/dist/src/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"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"}
|
package/dist/src/core.js
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
7
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
|
+
};
|
|
12
|
+
var _Sql_instances, _a, _Sql_state, _Sql_fill;
|
|
13
|
+
import { isPlainObject } from "es-toolkit/predicate";
|
|
14
|
+
/**
|
|
15
|
+
* Slot クラスの基底となる型定義です。
|
|
16
|
+
*/
|
|
17
|
+
const SlotTypes = class {
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* スロットを表すクラスです。
|
|
21
|
+
*
|
|
22
|
+
* スロットは後から値を注入可能なプレースホルダーです。
|
|
23
|
+
*
|
|
24
|
+
* @template TName スロットの名前となる文字列リテラル型です。
|
|
25
|
+
* @template TValue スロットに許容される値の型です。
|
|
26
|
+
*/
|
|
27
|
+
export class Slot extends SlotTypes {
|
|
28
|
+
constructor(name, defaultValue) {
|
|
29
|
+
super();
|
|
30
|
+
if (arguments.length < 2) {
|
|
31
|
+
defaultValue = null;
|
|
32
|
+
}
|
|
33
|
+
this.name = name;
|
|
34
|
+
this.defaultValue = defaultValue;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
1
37
|
/**
|
|
2
38
|
* 安全な SQL クエリーを構築するためのクラスです。
|
|
39
|
+
*
|
|
3
40
|
* プレースホルダーを使用したパラメーター化クエリーを生成します。
|
|
41
|
+
*
|
|
42
|
+
* @template TRawBindings クエリーに渡される生の値のタプル型です。
|
|
4
43
|
*/
|
|
5
44
|
export class Sql {
|
|
6
45
|
/**
|
|
@@ -12,15 +51,15 @@ export class Sql {
|
|
|
12
51
|
*/
|
|
13
52
|
get text() {
|
|
14
53
|
// キャッシュが存在しない場合にのみ、文字列を構築します。
|
|
15
|
-
if (this.
|
|
16
|
-
let i = 0, text = this.
|
|
54
|
+
if (__classPrivateFieldGet(this, _Sql_state, "f").text === undefined) {
|
|
55
|
+
let i = 0, text = __classPrivateFieldGet(this, _Sql_state, "f").parts[0];
|
|
17
56
|
// 文字列の断片とプレースホルダー($1, $2...)を交互に結合します。
|
|
18
|
-
for (; i < this.
|
|
19
|
-
text += "$" + this.
|
|
57
|
+
for (; i < __classPrivateFieldGet(this, _Sql_state, "f").phIds.length; i++) {
|
|
58
|
+
text += "$" + __classPrivateFieldGet(this, _Sql_state, "f").phIds[i] + __classPrivateFieldGet(this, _Sql_state, "f").parts[i + 1];
|
|
20
59
|
}
|
|
21
|
-
this.
|
|
60
|
+
__classPrivateFieldGet(this, _Sql_state, "f").text = text;
|
|
22
61
|
}
|
|
23
|
-
return this.
|
|
62
|
+
return __classPrivateFieldGet(this, _Sql_state, "f").text;
|
|
24
63
|
}
|
|
25
64
|
/**
|
|
26
65
|
* 新しい Sql インスタンスを初期化します。
|
|
@@ -29,6 +68,11 @@ export class Sql {
|
|
|
29
68
|
* @param rawBindings 文字列の間に挿入される値の配列です。
|
|
30
69
|
*/
|
|
31
70
|
constructor(rawStrings, rawBindings) {
|
|
71
|
+
_Sql_instances.add(this);
|
|
72
|
+
/**
|
|
73
|
+
* 内部状態を保持するためのプロパティーです。
|
|
74
|
+
*/
|
|
75
|
+
_Sql_state.set(this, void 0);
|
|
32
76
|
if (rawStrings.length === 0) {
|
|
33
77
|
throw new TypeError("Expected at least 1 string");
|
|
34
78
|
}
|
|
@@ -38,51 +82,98 @@ export class Sql {
|
|
|
38
82
|
const strings = [rawStrings[0]];
|
|
39
83
|
const bindings = [];
|
|
40
84
|
const placeholderIds = [];
|
|
85
|
+
const idx2slot = new Map();
|
|
86
|
+
const slot2idx = new Map();
|
|
41
87
|
/** 値の重複を排除し、同じ値には同じプレースホルダー ID を割り当てるためのマップです。 */
|
|
42
88
|
const valueToId = new Map();
|
|
89
|
+
/** スロットごとのプレースホルダー ID を管理します。 */
|
|
90
|
+
const slotToId = new Map();
|
|
91
|
+
/**
|
|
92
|
+
* 値を bindings に登録し、placeholderId を取得します。
|
|
93
|
+
*/
|
|
94
|
+
const registerValue = (value) => {
|
|
95
|
+
let placeholderId = valueToId.get(value);
|
|
96
|
+
if (placeholderId === undefined) {
|
|
97
|
+
bindings.push(value);
|
|
98
|
+
placeholderId = bindings.length;
|
|
99
|
+
valueToId.set(value, placeholderId);
|
|
100
|
+
}
|
|
101
|
+
return placeholderId;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* スロットを bindings に登録し、placeholderId を取得します。
|
|
105
|
+
*/
|
|
106
|
+
const registerSlot = (slot) => {
|
|
107
|
+
let placeholderId = slotToId.get(slot);
|
|
108
|
+
if (placeholderId === undefined) {
|
|
109
|
+
bindings.push(slot.defaultValue);
|
|
110
|
+
placeholderId = bindings.length;
|
|
111
|
+
slotToId.set(slot, placeholderId);
|
|
112
|
+
const index = placeholderId - 1;
|
|
113
|
+
idx2slot.set(index, slot);
|
|
114
|
+
let idxes = slot2idx.get(slot.name);
|
|
115
|
+
if (idxes === undefined) {
|
|
116
|
+
idxes = new Set();
|
|
117
|
+
slot2idx.set(slot.name, idxes);
|
|
118
|
+
}
|
|
119
|
+
idxes.add(index);
|
|
120
|
+
}
|
|
121
|
+
return placeholderId;
|
|
122
|
+
};
|
|
43
123
|
// 提供された全てのバインディング値を走査して、SQL 文字列と値を正規化します。
|
|
44
124
|
for (let i = 0; i < rawBindings.length; i++) {
|
|
45
125
|
const child = rawBindings[i];
|
|
46
126
|
const rawString = rawStrings[i + 1];
|
|
47
127
|
// バインディング値が Sql インスタンス(ネストされたクエリー)の場合の処理です。
|
|
48
|
-
if (child instanceof
|
|
128
|
+
if (child instanceof _a) {
|
|
49
129
|
// 現在の最後の文字列断片に、ネストされた Sql の最初の断片を結合します。
|
|
50
|
-
strings[strings.length - 1] += child.
|
|
130
|
+
strings[strings.length - 1] += __classPrivateFieldGet(child, _Sql_state, "f").parts[0];
|
|
51
131
|
// ネストされた Sql のプレースホルダーと値を再マッピングします。
|
|
52
|
-
for (let j = 0; j < child.
|
|
53
|
-
const childPlaceholderId = child.
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
valueToId.set(value, placeholderId);
|
|
60
|
-
}
|
|
61
|
-
strings.push(child._.s[j + 1]);
|
|
132
|
+
for (let j = 0; j < __classPrivateFieldGet(child, _Sql_state, "f").phIds.length; j++) {
|
|
133
|
+
const childPlaceholderId = __classPrivateFieldGet(child, _Sql_state, "f").phIds[j];
|
|
134
|
+
const valueIndex = childPlaceholderId - 1;
|
|
135
|
+
const value = child.values[valueIndex];
|
|
136
|
+
const slot = __classPrivateFieldGet(child, _Sql_state, "f").idx2slot.get(valueIndex);
|
|
137
|
+
const placeholderId = slot !== undefined ? registerSlot(slot) : registerValue(value);
|
|
138
|
+
strings.push(__classPrivateFieldGet(child, _Sql_state, "f").parts[j + 1]);
|
|
62
139
|
placeholderIds.push(placeholderId);
|
|
63
140
|
}
|
|
64
141
|
// ネストされた Sql の展開が終わった後に、後続の生の文字列を結合します。
|
|
65
142
|
strings[strings.length - 1] += rawString;
|
|
66
143
|
}
|
|
67
144
|
else {
|
|
68
|
-
|
|
69
|
-
if (placeholderId === undefined) {
|
|
70
|
-
bindings.push(child);
|
|
71
|
-
placeholderId = bindings.length;
|
|
72
|
-
valueToId.set(child, placeholderId);
|
|
73
|
-
}
|
|
145
|
+
const placeholderId = child instanceof Slot ? registerSlot(child) : registerValue(child);
|
|
74
146
|
strings.push(rawString);
|
|
75
147
|
placeholderIds.push(placeholderId);
|
|
76
148
|
}
|
|
77
149
|
}
|
|
78
150
|
this.values = bindings;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
151
|
+
__classPrivateFieldSet(this, _Sql_state, {
|
|
152
|
+
parts: strings,
|
|
153
|
+
phIds: placeholderIds,
|
|
154
|
+
idx2slot,
|
|
155
|
+
slot2idx,
|
|
156
|
+
}, "f");
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* スロットを値で埋めます。
|
|
160
|
+
*
|
|
161
|
+
* @template TSlots 指定されたスロットのマップ型です。
|
|
162
|
+
* @param slots スロットの値です。
|
|
163
|
+
* @returns スロットが埋められた新しい Sql インスタンスです。
|
|
164
|
+
*/
|
|
165
|
+
fill(slots) {
|
|
166
|
+
return __classPrivateFieldGet(this, _Sql_instances, "m", _Sql_fill).call(this, slots, false);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* すべてのスロットを値で埋めます。
|
|
170
|
+
*
|
|
171
|
+
* @template TSlots 全てのスロットをカバーするマップ型です。
|
|
172
|
+
* @param slots スロットの値です。
|
|
173
|
+
* @returns スロットが埋められた新しい Sql インスタンスです。
|
|
174
|
+
*/
|
|
175
|
+
fillAll(slots) {
|
|
176
|
+
return __classPrivateFieldGet(this, _Sql_instances, "m", _Sql_fill).call(this, slots, true);
|
|
86
177
|
}
|
|
87
178
|
/**
|
|
88
179
|
* オブジェクトを JSON 形式に変換可能な形式で返します。
|
|
@@ -104,8 +195,61 @@ export class Sql {
|
|
|
104
195
|
return this.text;
|
|
105
196
|
}
|
|
106
197
|
}
|
|
198
|
+
_a = Sql, _Sql_state = new WeakMap(), _Sql_instances = new WeakSet(), _Sql_fill = function _Sql_fill(slots, all) {
|
|
199
|
+
if (isPlainObject(slots)) {
|
|
200
|
+
slots = Object.entries(slots);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
// 一旦 Map のインスタンスにすることで、重複する名前またはスロットを 1 つに絞ります。
|
|
204
|
+
slots = new Map(slots);
|
|
205
|
+
}
|
|
206
|
+
const { parts, idx2slot, slot2idx } = __classPrivateFieldGet(this, _Sql_state, "f");
|
|
207
|
+
const filled = new Set();
|
|
208
|
+
const values = this.values.slice();
|
|
209
|
+
for (const [target, value] of new Map(slots)) {
|
|
210
|
+
let idxes;
|
|
211
|
+
if (typeof target === "string") {
|
|
212
|
+
idxes = slot2idx.get(target);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
// インスタンスが直接指定された場合、全インデックスから一致するものを探します。
|
|
216
|
+
for (const [idx, slot] of idx2slot) {
|
|
217
|
+
if (slot === target) {
|
|
218
|
+
idxes || (idxes = new Set());
|
|
219
|
+
idxes.add(idx);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (idxes === undefined) {
|
|
224
|
+
// スロットが見つからない場合は無視します。
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
// 該当するすべてのプレースホルダーインデックスを新しい値で更新します。
|
|
228
|
+
for (const idx of idxes) {
|
|
229
|
+
values[idx] = value;
|
|
230
|
+
filled.add(idx);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// 全て埋める必要がある場合、未解決のスロットが残っていないか検証します。
|
|
234
|
+
if (all) {
|
|
235
|
+
for (let idx = 0; idx < values.length; idx++) {
|
|
236
|
+
if (idx2slot.has(idx) && !filled.has(idx)) {
|
|
237
|
+
const missingSlots = new Set();
|
|
238
|
+
missingSlots.add(idx2slot.get(idx).name);
|
|
239
|
+
for (; idx < values.length; idx++) {
|
|
240
|
+
if (idx2slot.has(idx)) {
|
|
241
|
+
missingSlots.add(idx2slot.get(idx).name);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
throw new Error(`Not all slots are filled. Missing: ${[...missingSlots].join(", ")}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return new _a(parts, values);
|
|
249
|
+
};
|
|
107
250
|
/**
|
|
108
251
|
* 生の文字列を SQL 断片として扱います。
|
|
252
|
+
*
|
|
109
253
|
* この値はパラメーター化の対象にならず、そのままクエリーに含まれます。
|
|
110
254
|
*
|
|
111
255
|
* @param value SQL に含める生の文字列です。
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAE1F,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/src/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { empty, join, raw, ident
|
|
1
|
+
export { Sql, Slot, empty, join, raw, ident } from "./core.js";
|
|
2
2
|
export { sql } from "./sql.js";
|
package/dist/src/sql.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { join, raw, Sql, ident, literal } from "./core.js";
|
|
1
|
+
import { join, raw, Sql, ident, literal, Slot, RawValue } from "./core.js";
|
|
2
2
|
declare namespace sql {
|
|
3
3
|
/**
|
|
4
4
|
* SQL クエリーの構築に使用できる生の値、または別の Sql インスタンスを表す型です。
|
|
@@ -8,14 +8,36 @@ declare namespace sql {
|
|
|
8
8
|
* SQL クエリー内で使用される値の型定義です。
|
|
9
9
|
*/
|
|
10
10
|
type Value = import("./core.js").Value;
|
|
11
|
+
/**
|
|
12
|
+
* スロットを表すクラスです。
|
|
13
|
+
*
|
|
14
|
+
* スロットは後から値を注入可能なプレースホルダーです。
|
|
15
|
+
*
|
|
16
|
+
* @template TName スロットの名前となる文字列リテラル型です。
|
|
17
|
+
* @template TValue スロットに許容される値の型です。
|
|
18
|
+
*/
|
|
19
|
+
type Slot<TName extends string = string, TValue extends RawValue = RawValue> = import("./core.js").Slot<TName, TValue>;
|
|
11
20
|
/**
|
|
12
21
|
* 安全な SQL クエリーを構築するためのクラス型です。
|
|
22
|
+
*
|
|
23
|
+
* @template TRawBindings クエリーに渡される生の値のタプル型です。
|
|
13
24
|
*/
|
|
14
|
-
type Sql = import("./core.js").Sql
|
|
25
|
+
type Sql<TRawBindings extends readonly RawValue[] = readonly RawValue[]> = import("./core.js").Sql<TRawBindings>;
|
|
15
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* 新しい Slot インスタンスを作成します。
|
|
29
|
+
*
|
|
30
|
+
* @template TName スロットの名前となる文字列リテラル型です。
|
|
31
|
+
* @template TValue スロットに許容される値の型です。
|
|
32
|
+
* @param name スロット名です。
|
|
33
|
+
* @param defaultValue デフォルト値です。
|
|
34
|
+
* @returns 作成された新しい Slot インスタンスです。
|
|
35
|
+
*/
|
|
36
|
+
declare function slot<const TName extends string, TValue extends RawValue = RawValue>(name: TName, defaultValue?: TValue): sql.Slot<TName, TValue>;
|
|
16
37
|
/**
|
|
17
38
|
* テンプレートリテラルを使用して SQL クエリーを安全に構築するためのタグ関数です。
|
|
18
39
|
*
|
|
40
|
+
* @template TRawBindings クエリーに渡される生の値のタプル型です。
|
|
19
41
|
* @param strings テンプレートリテラルの静的な文字列部分の配列です。
|
|
20
42
|
* @param bindings テンプレートリテラルに埋め込まれた動的な値の配列です。
|
|
21
43
|
* @returns パラメーター化された SQL 情報を保持する Sql インスタンスを返します。
|
|
@@ -24,15 +46,25 @@ declare namespace sql {
|
|
|
24
46
|
* const query = sql`SELECT * FROM users WHERE id = ${1}`;
|
|
25
47
|
* ```
|
|
26
48
|
*/
|
|
27
|
-
declare const sql: ((strings: TemplateStringsArray, ...bindings:
|
|
49
|
+
declare const sql: (<const TRawBindings extends readonly RawValue[]>(strings: TemplateStringsArray, ...bindings: TRawBindings) => sql.Sql<TRawBindings>) & {
|
|
28
50
|
/**
|
|
29
|
-
* Sql
|
|
51
|
+
* Sql クラスです。
|
|
30
52
|
*/
|
|
31
53
|
readonly Sql: typeof Sql;
|
|
32
54
|
/**
|
|
33
55
|
* 生の文字列を SQL 断片として扱うための関数です。
|
|
34
56
|
*/
|
|
35
57
|
readonly raw: typeof raw;
|
|
58
|
+
/**
|
|
59
|
+
* 新しい Slot インスタンスを作成する関数です。
|
|
60
|
+
*/
|
|
61
|
+
readonly slot: typeof slot;
|
|
62
|
+
/**
|
|
63
|
+
* スロットを表すクラスです。
|
|
64
|
+
*
|
|
65
|
+
* スロットは後から値を注入可能なプレースホルダーです。
|
|
66
|
+
*/
|
|
67
|
+
readonly Slot: typeof Slot;
|
|
36
68
|
/**
|
|
37
69
|
* 複数の SQL 断片を結合するための関数です。
|
|
38
70
|
*/
|
|
@@ -40,7 +72,7 @@ declare const sql: ((strings: TemplateStringsArray, ...bindings: readonly sql.Ra
|
|
|
40
72
|
/**
|
|
41
73
|
* 空の SQL クエリーを表す定数です。
|
|
42
74
|
*/
|
|
43
|
-
readonly empty: Sql
|
|
75
|
+
readonly empty: Sql<readonly unknown[]>;
|
|
44
76
|
/**
|
|
45
77
|
* 識別子(テーブル名等)を安全にエスケープするための関数です。
|
|
46
78
|
*/
|
package/dist/src/sql.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAElF,kBAAU,GAAG,CAAC;IACZ;;OAEG;IACH,KAAY,QAAQ,GAAG,OAAO,WAAW,EAAE,QAAQ,CAAC;IAEpD;;OAEG;IACH,KAAY,KAAK,GAAG,OAAO,WAAW,EAAE,KAAK,CAAC;IAE9C;;;;;;;OAOG;IACH,KAAY,IAAI,CACd,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,MAAM,SAAS,QAAQ,GAAG,QAAQ,IAChC,OAAO,WAAW,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAE5C;;;;OAIG;IACH,KAAY,GAAG,CAAC,YAAY,SAAS,SAAS,QAAQ,EAAE,GAAG,SAAS,QAAQ,EAAE,IAC5E,OAAO,WAAW,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;CACzC;AAED;;;;;;;;GAQG;AACH,iBAAS,IAAI,CAAC,KAAK,CAAC,KAAK,SAAS,MAAM,EAAE,MAAM,SAAS,QAAQ,GAAG,QAAQ,EAC1E,IAAI,EAAE,KAAK,EACX,YAAY,CAAC,EAAE,MAAM,GACpB,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AAM3B;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,GAAG,UACY,YAAY,SAAS,SAAS,QAAQ,EAAE,WAChD,oBAAoB,eAChB,YAAY,KACxB,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;IAItB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;;;OAIG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;CAGN,CAAC;AAEF,OAAO,EAAE,GAAG,EAAE,CAAC"}
|
package/dist/src/sql.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { empty, join, raw, Sql, ident, literal } from "./core.js";
|
|
1
|
+
import { empty, join, raw, Sql, ident, literal, Slot } from "./core.js";
|
|
2
|
+
function slot(...args) {
|
|
3
|
+
return new sql.Slot(...args);
|
|
4
|
+
}
|
|
2
5
|
/**
|
|
3
6
|
* テンプレートリテラルを使用して SQL クエリーを安全に構築するためのタグ関数です。
|
|
4
7
|
*
|
|
8
|
+
* @template TRawBindings クエリーに渡される生の値のタプル型です。
|
|
5
9
|
* @param strings テンプレートリテラルの静的な文字列部分の配列です。
|
|
6
10
|
* @param bindings テンプレートリテラルに埋め込まれた動的な値の配列です。
|
|
7
11
|
* @returns パラメーター化された SQL 情報を保持する Sql インスタンスを返します。
|
|
@@ -14,13 +18,23 @@ const sql = /*#__PURE__*/ Object.assign(function sql(strings, ...bindings) {
|
|
|
14
18
|
return new Sql(strings, bindings);
|
|
15
19
|
}, {
|
|
16
20
|
/**
|
|
17
|
-
* Sql
|
|
21
|
+
* Sql クラスです。
|
|
18
22
|
*/
|
|
19
23
|
Sql,
|
|
20
24
|
/**
|
|
21
25
|
* 生の文字列を SQL 断片として扱うための関数です。
|
|
22
26
|
*/
|
|
23
27
|
raw,
|
|
28
|
+
/**
|
|
29
|
+
* 新しい Slot インスタンスを作成する関数です。
|
|
30
|
+
*/
|
|
31
|
+
slot,
|
|
32
|
+
/**
|
|
33
|
+
* スロットを表すクラスです。
|
|
34
|
+
*
|
|
35
|
+
* スロットは後から値を注入可能なプレースホルダーです。
|
|
36
|
+
*/
|
|
37
|
+
Slot,
|
|
24
38
|
/**
|
|
25
39
|
* 複数の SQL 断片を結合するための関数です。
|
|
26
40
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pgsql-template-tag",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "",
|
|
5
5
|
"homepage": "https://github.com/tai-kun/pgsql-template-tag",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
"default": "./dist/src/index.js"
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"es-toolkit": "^1.46.1",
|
|
30
|
+
"type-fest": "^5.6.0"
|
|
31
|
+
},
|
|
28
32
|
"devDependencies": {
|
|
29
33
|
"@tsconfig/node24": "^24.0.4",
|
|
30
34
|
"@tsconfig/strictest": "^2.0.8",
|
|
@@ -33,9 +37,9 @@
|
|
|
33
37
|
"@vitest/browser": "^4.1.5",
|
|
34
38
|
"@vitest/browser-playwright": "^4.1.5",
|
|
35
39
|
"npm-check-updates": "^20.0.2",
|
|
36
|
-
"oxfmt": "^0.
|
|
37
|
-
"oxlint": "^1.
|
|
38
|
-
"oxlint-tsgolint": "^0.22.
|
|
40
|
+
"oxfmt": "^0.47.0",
|
|
41
|
+
"oxlint": "^1.62.0",
|
|
42
|
+
"oxlint-tsgolint": "^0.22.1",
|
|
39
43
|
"playwright": "^1.59.1",
|
|
40
44
|
"typescript": "^6.0.3",
|
|
41
45
|
"vite": "^8.0.10",
|
package/src/core.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { isPlainObject } from "es-toolkit/predicate";
|
|
2
|
+
import type { UnionToTuple } from "type-fest";
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* SQL クエリー内で使用される値の型定義です。
|
|
3
6
|
*/
|
|
@@ -7,7 +10,167 @@ export type Value = unknown;
|
|
|
7
10
|
* SQL クエリーの構築に使用できる生の値、または別の Sql インスタンスを表す型です。
|
|
8
11
|
*/
|
|
9
12
|
// oxlint-disable-next-line typescript/no-redundant-type-constituents
|
|
10
|
-
export type RawValue = Value | Sql;
|
|
13
|
+
export type RawValue = Value | Slot | Sql;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Slot クラスを一意に識別するためのシンボルです。
|
|
17
|
+
*/
|
|
18
|
+
declare const SLOT_SYMBOL: unique symbol;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Slot クラスの基底となる型定義です。
|
|
22
|
+
*/
|
|
23
|
+
const SlotTypes = class {} as {
|
|
24
|
+
new (): {
|
|
25
|
+
/**
|
|
26
|
+
* このプロパティーは、TypeScript の `extends Slot` で `Slot` インスタンスのみに一致させるためにあります。そのため、`Slot` と同じプロパティーを持つオブジェクトに対して一致することはありません。
|
|
27
|
+
*/
|
|
28
|
+
readonly ["~kind"]: typeof SLOT_SYMBOL;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* スロットを表すクラスです。
|
|
34
|
+
*
|
|
35
|
+
* スロットは後から値を注入可能なプレースホルダーです。
|
|
36
|
+
*
|
|
37
|
+
* @template TName スロットの名前となる文字列リテラル型です。
|
|
38
|
+
* @template TValue スロットに許容される値の型です。
|
|
39
|
+
*/
|
|
40
|
+
export class Slot<
|
|
41
|
+
const TName extends string = string,
|
|
42
|
+
TValue extends RawValue = RawValue,
|
|
43
|
+
> extends SlotTypes {
|
|
44
|
+
/**
|
|
45
|
+
* スロット名です。
|
|
46
|
+
*/
|
|
47
|
+
public readonly name: TName;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* デフォルト値です。
|
|
51
|
+
*/
|
|
52
|
+
public readonly defaultValue: TValue;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 新しい Slot インスタンスを初期化します。
|
|
56
|
+
*
|
|
57
|
+
* @param name スロット名です。
|
|
58
|
+
* @param defaultValue デフォルト値です。
|
|
59
|
+
*/
|
|
60
|
+
public constructor(
|
|
61
|
+
...args: null extends TValue
|
|
62
|
+
? [name: TName, defaultValue?: TValue]
|
|
63
|
+
: [name: TName, defaultValue: TValue]
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
public constructor(name: TName, defaultValue?: RawValue) {
|
|
67
|
+
super();
|
|
68
|
+
|
|
69
|
+
if (arguments.length < 2) {
|
|
70
|
+
defaultValue = null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.name = name;
|
|
74
|
+
this.defaultValue = defaultValue as TValue;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* オブジェクトのバリューの型を抽出するヘルパー型です。
|
|
80
|
+
*
|
|
81
|
+
* @template T 対象となるオブジェクト型です。
|
|
82
|
+
*/
|
|
83
|
+
type $ValueOf<T> = T[keyof T];
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* スロットの配列から、再帰的に値をマージして型を決定します。
|
|
87
|
+
*
|
|
88
|
+
* @template TSlots スロットのタプル型です。
|
|
89
|
+
*/
|
|
90
|
+
type $MergeSlotValue<TSlots> = TSlots extends [
|
|
91
|
+
Slot<string, infer TValue>,
|
|
92
|
+
infer TSlot,
|
|
93
|
+
...infer TOtherSlots,
|
|
94
|
+
]
|
|
95
|
+
? TValue & $MergeSlotValue<[TSlot, ...TOtherSlots]>
|
|
96
|
+
: TSlots extends [Slot<string, infer TValue>]
|
|
97
|
+
? TValue
|
|
98
|
+
: never;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* RawValue の配列からスロット情報を抽出し、名前ごとのマップ型に変換します。
|
|
102
|
+
*
|
|
103
|
+
* @template TValues RawValue の読み取り専用配列型です。
|
|
104
|
+
*/
|
|
105
|
+
type $MapSlotValue<TValues extends readonly RawValue[]> =
|
|
106
|
+
TValues extends readonly (infer TSlot extends Slot)[]
|
|
107
|
+
? {
|
|
108
|
+
// `Slot<"id", string | number> | Slot<"id", string>` の場合、`(string | number) & (string)` となるように、各スロットの積集合をとります。
|
|
109
|
+
[TName in TSlot["name"]]: $MergeSlotValue<UnionToTuple<Extract<TSlot, Slot<TName>>>>;
|
|
110
|
+
}
|
|
111
|
+
: {};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 指定された値のリストに対して、スロットを実際の内容で置き換えた型を生成します。
|
|
115
|
+
*
|
|
116
|
+
* @template TValues 置き換え対象の配列型です。
|
|
117
|
+
* @template TSlots スロット名と値のマップ型です。
|
|
118
|
+
*/
|
|
119
|
+
type $FillSlots<TValues, TSlots> = TValues extends [infer TValue, ...infer TOtherValues]
|
|
120
|
+
? [
|
|
121
|
+
TValue extends Slot<infer TName extends Extract<keyof TSlots, string>, infer TSlotValue>
|
|
122
|
+
? TSlotValue extends TSlots[TName]
|
|
123
|
+
? TSlotValue
|
|
124
|
+
: TValue
|
|
125
|
+
: TValue,
|
|
126
|
+
...$FillSlots<TOtherValues, TSlots>,
|
|
127
|
+
]
|
|
128
|
+
: [];
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* スロットを埋めるための部分的な引数型を定義します。
|
|
132
|
+
*
|
|
133
|
+
* @template TSlots スロット名と値のマップ型です。
|
|
134
|
+
*/
|
|
135
|
+
type _FillSlots<TSlots> =
|
|
136
|
+
| {
|
|
137
|
+
readonly [TName in Extract<keyof TSlots, string>]?: TSlots[TName];
|
|
138
|
+
}
|
|
139
|
+
| Iterable<
|
|
140
|
+
readonly [
|
|
141
|
+
name: $ValueOf<{
|
|
142
|
+
[TName in Extract<keyof TSlots, string>]: TName | Slot<TName, TSlots[TName]>;
|
|
143
|
+
}>,
|
|
144
|
+
value: $ValueOf<TSlots>,
|
|
145
|
+
]
|
|
146
|
+
>;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* すべてのスロットを埋めるために必要な引数型を定義します。
|
|
150
|
+
*
|
|
151
|
+
* @template TSlots スロット名と値のマップ型です。
|
|
152
|
+
*/
|
|
153
|
+
type _FillAllSlots<TSlots> = {
|
|
154
|
+
readonly [TName in Extract<keyof TSlots, string>]: TSlots[TName];
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* スロットの部分的な補完に使用する外部向けの型定義です。
|
|
159
|
+
*
|
|
160
|
+
* @template TValues RawValue の配列です。
|
|
161
|
+
*/
|
|
162
|
+
export type FillSlots<TValues extends readonly RawValue[] = readonly RawValue[]> = _FillSlots<
|
|
163
|
+
$MapSlotValue<TValues>
|
|
164
|
+
>;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* すべてのスロットの強制的な補完に使用する外部向けの型定義です。
|
|
168
|
+
*
|
|
169
|
+
* @template TValues RawValue の配列です。
|
|
170
|
+
*/
|
|
171
|
+
export type FillAllSlots<TValues extends readonly RawValue[] = readonly RawValue[]> = _FillAllSlots<
|
|
172
|
+
$MapSlotValue<TValues>
|
|
173
|
+
>;
|
|
11
174
|
|
|
12
175
|
/**
|
|
13
176
|
* Sql クラスの内部状態を管理するためのプライベートな型定義です。
|
|
@@ -16,24 +179,37 @@ type PrivateState = {
|
|
|
16
179
|
/**
|
|
17
180
|
* クエリーを構成する静的な文字列の配列です。
|
|
18
181
|
*/
|
|
19
|
-
readonly
|
|
182
|
+
readonly parts: readonly [string, ...string[]];
|
|
20
183
|
|
|
21
184
|
/**
|
|
22
185
|
* プレースホルダーに対応するインデックス(1 から始まる数値)の配列です。
|
|
23
186
|
*/
|
|
24
|
-
readonly
|
|
187
|
+
readonly phIds: readonly number[];
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* values のインデックス -> スロット情報 のマップです。
|
|
191
|
+
*/
|
|
192
|
+
readonly idx2slot: ReadonlyMap<number, Slot>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* スロット名 -> values のインデックス のマップです。
|
|
196
|
+
*/
|
|
197
|
+
readonly slot2idx: ReadonlyMap<string, ReadonlySet<number>>;
|
|
25
198
|
|
|
26
199
|
/**
|
|
27
200
|
* キャッシュされた最終的なクエリーテキストです。
|
|
28
201
|
*/
|
|
29
|
-
|
|
202
|
+
text?: string;
|
|
30
203
|
};
|
|
31
204
|
|
|
32
205
|
/**
|
|
33
206
|
* 安全な SQL クエリーを構築するためのクラスです。
|
|
207
|
+
*
|
|
34
208
|
* プレースホルダーを使用したパラメーター化クエリーを生成します。
|
|
209
|
+
*
|
|
210
|
+
* @template TRawBindings クエリーに渡される生の値のタプル型です。
|
|
35
211
|
*/
|
|
36
|
-
export class Sql {
|
|
212
|
+
export class Sql<const TRawBindings extends readonly RawValue[] = readonly RawValue[]> {
|
|
37
213
|
/**
|
|
38
214
|
* 構築された SQL クエリーテキストを取得します。
|
|
39
215
|
*
|
|
@@ -43,19 +219,19 @@ export class Sql {
|
|
|
43
219
|
*/
|
|
44
220
|
public get text(): string {
|
|
45
221
|
// キャッシュが存在しない場合にのみ、文字列を構築します。
|
|
46
|
-
if (this.
|
|
222
|
+
if (this.#state.text === undefined) {
|
|
47
223
|
let i = 0,
|
|
48
|
-
text = this.
|
|
224
|
+
text = this.#state.parts[0];
|
|
49
225
|
|
|
50
226
|
// 文字列の断片とプレースホルダー($1, $2...)を交互に結合します。
|
|
51
|
-
for (; i < this.
|
|
52
|
-
text += "$" + this.
|
|
227
|
+
for (; i < this.#state.phIds.length; i++) {
|
|
228
|
+
text += "$" + this.#state.phIds[i] + this.#state.parts[i + 1];
|
|
53
229
|
}
|
|
54
230
|
|
|
55
|
-
this.
|
|
231
|
+
this.#state.text = text;
|
|
56
232
|
}
|
|
57
233
|
|
|
58
|
-
return this.
|
|
234
|
+
return this.#state.text;
|
|
59
235
|
}
|
|
60
236
|
|
|
61
237
|
/**
|
|
@@ -66,7 +242,7 @@ export class Sql {
|
|
|
66
242
|
/**
|
|
67
243
|
* 内部状態を保持するためのプロパティーです。
|
|
68
244
|
*/
|
|
69
|
-
|
|
245
|
+
readonly #state: PrivateState;
|
|
70
246
|
|
|
71
247
|
/**
|
|
72
248
|
* 新しい Sql インスタンスを初期化します。
|
|
@@ -74,7 +250,7 @@ export class Sql {
|
|
|
74
250
|
* @param rawStrings SQL の断片となる文字列の配列です。
|
|
75
251
|
* @param rawBindings 文字列の間に挿入される値の配列です。
|
|
76
252
|
*/
|
|
77
|
-
public constructor(rawStrings: readonly string[], rawBindings:
|
|
253
|
+
public constructor(rawStrings: readonly string[], rawBindings: TRawBindings) {
|
|
78
254
|
if (rawStrings.length === 0) {
|
|
79
255
|
throw new TypeError("Expected at least 1 string");
|
|
80
256
|
}
|
|
@@ -88,10 +264,52 @@ export class Sql {
|
|
|
88
264
|
const strings: [string, ...string[]] = [rawStrings[0]!];
|
|
89
265
|
const bindings: Value[] = [];
|
|
90
266
|
const placeholderIds: number[] = [];
|
|
267
|
+
const idx2slot = new Map<number, Slot>();
|
|
268
|
+
const slot2idx = new Map<string, Set<number>>();
|
|
91
269
|
|
|
92
270
|
/** 値の重複を排除し、同じ値には同じプレースホルダー ID を割り当てるためのマップです。 */
|
|
93
271
|
const valueToId = new Map<Value, number>();
|
|
94
272
|
|
|
273
|
+
/** スロットごとのプレースホルダー ID を管理します。 */
|
|
274
|
+
const slotToId = new Map<Slot, number>();
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* 値を bindings に登録し、placeholderId を取得します。
|
|
278
|
+
*/
|
|
279
|
+
const registerValue = (value: Value): number => {
|
|
280
|
+
let placeholderId = valueToId.get(value);
|
|
281
|
+
if (placeholderId === undefined) {
|
|
282
|
+
bindings.push(value);
|
|
283
|
+
placeholderId = bindings.length;
|
|
284
|
+
valueToId.set(value, placeholderId);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return placeholderId;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* スロットを bindings に登録し、placeholderId を取得します。
|
|
292
|
+
*/
|
|
293
|
+
const registerSlot = (slot: Slot): number => {
|
|
294
|
+
let placeholderId = slotToId.get(slot);
|
|
295
|
+
if (placeholderId === undefined) {
|
|
296
|
+
bindings.push(slot.defaultValue);
|
|
297
|
+
placeholderId = bindings.length;
|
|
298
|
+
slotToId.set(slot, placeholderId);
|
|
299
|
+
|
|
300
|
+
const index = placeholderId - 1;
|
|
301
|
+
idx2slot.set(index, slot);
|
|
302
|
+
let idxes = slot2idx.get(slot.name);
|
|
303
|
+
if (idxes === undefined) {
|
|
304
|
+
idxes = new Set();
|
|
305
|
+
slot2idx.set(slot.name, idxes);
|
|
306
|
+
}
|
|
307
|
+
idxes.add(index);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return placeholderId;
|
|
311
|
+
};
|
|
312
|
+
|
|
95
313
|
// 提供された全てのバインディング値を走査して、SQL 文字列と値を正規化します。
|
|
96
314
|
for (let i = 0; i < rawBindings.length; i++) {
|
|
97
315
|
const child = rawBindings[i];
|
|
@@ -100,33 +318,26 @@ export class Sql {
|
|
|
100
318
|
// バインディング値が Sql インスタンス(ネストされたクエリー)の場合の処理です。
|
|
101
319
|
if (child instanceof Sql) {
|
|
102
320
|
// 現在の最後の文字列断片に、ネストされた Sql の最初の断片を結合します。
|
|
103
|
-
strings[strings.length - 1] += child.
|
|
321
|
+
strings[strings.length - 1] += child.#state.parts[0];
|
|
104
322
|
|
|
105
323
|
// ネストされた Sql のプレースホルダーと値を再マッピングします。
|
|
106
|
-
for (let j = 0; j < child.
|
|
107
|
-
const childPlaceholderId = child.
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
valueToId.set(value, placeholderId);
|
|
115
|
-
}
|
|
324
|
+
for (let j = 0; j < child.#state.phIds.length; j++) {
|
|
325
|
+
const childPlaceholderId = child.#state.phIds[j]!;
|
|
326
|
+
const valueIndex = childPlaceholderId - 1;
|
|
327
|
+
const value = child.values[valueIndex]!;
|
|
328
|
+
|
|
329
|
+
const slot = child.#state.idx2slot.get(valueIndex);
|
|
330
|
+
|
|
331
|
+
const placeholderId = slot !== undefined ? registerSlot(slot) : registerValue(value);
|
|
116
332
|
|
|
117
|
-
strings.push(child.
|
|
333
|
+
strings.push(child.#state.parts[j + 1]!);
|
|
118
334
|
placeholderIds.push(placeholderId);
|
|
119
335
|
}
|
|
120
336
|
|
|
121
337
|
// ネストされた Sql の展開が終わった後に、後続の生の文字列を結合します。
|
|
122
338
|
strings[strings.length - 1] += rawString;
|
|
123
339
|
} else {
|
|
124
|
-
|
|
125
|
-
if (placeholderId === undefined) {
|
|
126
|
-
bindings.push(child);
|
|
127
|
-
placeholderId = bindings.length;
|
|
128
|
-
valueToId.set(child, placeholderId);
|
|
129
|
-
}
|
|
340
|
+
const placeholderId = child instanceof Slot ? registerSlot(child) : registerValue(child);
|
|
130
341
|
|
|
131
342
|
strings.push(rawString);
|
|
132
343
|
placeholderIds.push(placeholderId);
|
|
@@ -135,13 +346,102 @@ export class Sql {
|
|
|
135
346
|
|
|
136
347
|
this.values = bindings;
|
|
137
348
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
349
|
+
this.#state = {
|
|
350
|
+
parts: strings,
|
|
351
|
+
phIds: placeholderIds,
|
|
352
|
+
idx2slot,
|
|
353
|
+
slot2idx,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* スロットを値で埋める内部メソッドです。
|
|
359
|
+
*
|
|
360
|
+
* @param slots スロットのマップまたはエントリーの配列です。
|
|
361
|
+
* @param all 全てのスロットが埋まっているかチェックするかどうかです。
|
|
362
|
+
* @returns 新しい Sql インスタンスを返します。
|
|
363
|
+
*/
|
|
364
|
+
#fill(slots: FillSlots<Slot[]>, all: boolean): Sql {
|
|
365
|
+
if (isPlainObject(slots)) {
|
|
366
|
+
slots = Object.entries(slots);
|
|
367
|
+
} else {
|
|
368
|
+
// 一旦 Map のインスタンスにすることで、重複する名前またはスロットを 1 つに絞ります。
|
|
369
|
+
slots = new Map(slots);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const { parts, idx2slot, slot2idx } = this.#state;
|
|
373
|
+
const filled = new Set<number>();
|
|
374
|
+
const values = this.values.slice();
|
|
375
|
+
for (const [target, value] of new Map(slots)) {
|
|
376
|
+
let idxes: ReadonlySet<number> | undefined;
|
|
377
|
+
if (typeof target === "string") {
|
|
378
|
+
idxes = slot2idx.get(target);
|
|
379
|
+
} else {
|
|
380
|
+
// インスタンスが直接指定された場合、全インデックスから一致するものを探します。
|
|
381
|
+
for (const [idx, slot] of idx2slot) {
|
|
382
|
+
if (slot === target) {
|
|
383
|
+
idxes ||= new Set();
|
|
384
|
+
(idxes as Set<number>).add(idx);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (idxes === undefined) {
|
|
390
|
+
// スロットが見つからない場合は無視します。
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// 該当するすべてのプレースホルダーインデックスを新しい値で更新します。
|
|
395
|
+
for (const idx of idxes) {
|
|
396
|
+
values[idx] = value;
|
|
397
|
+
filled.add(idx);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// 全て埋める必要がある場合、未解決のスロットが残っていないか検証します。
|
|
402
|
+
if (all) {
|
|
403
|
+
for (let idx = 0; idx < values.length; idx++) {
|
|
404
|
+
if (idx2slot.has(idx) && !filled.has(idx)) {
|
|
405
|
+
const missingSlots = new Set<string>();
|
|
406
|
+
missingSlots.add(idx2slot.get(idx)!.name);
|
|
407
|
+
for (; idx < values.length; idx++) {
|
|
408
|
+
if (idx2slot.has(idx)) {
|
|
409
|
+
missingSlots.add(idx2slot.get(idx)!.name);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
throw new Error(`Not all slots are filled. Missing: ${[...missingSlots].join(", ")}`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return new Sql(parts, values);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* スロットを値で埋めます。
|
|
423
|
+
*
|
|
424
|
+
* @template TSlots 指定されたスロットのマップ型です。
|
|
425
|
+
* @param slots スロットの値です。
|
|
426
|
+
* @returns スロットが埋められた新しい Sql インスタンスです。
|
|
427
|
+
*/
|
|
428
|
+
public fill<TSlots extends FillSlots<TRawBindings>>(
|
|
429
|
+
slots: TSlots,
|
|
430
|
+
): Sql<$FillSlots<TRawBindings, TSlots>> {
|
|
431
|
+
return this.#fill(slots, false);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* すべてのスロットを値で埋めます。
|
|
436
|
+
*
|
|
437
|
+
* @template TSlots 全てのスロットをカバーするマップ型です。
|
|
438
|
+
* @param slots スロットの値です。
|
|
439
|
+
* @returns スロットが埋められた新しい Sql インスタンスです。
|
|
440
|
+
*/
|
|
441
|
+
public fillAll<TSlots extends FillAllSlots<TRawBindings>>(
|
|
442
|
+
slots: TSlots,
|
|
443
|
+
): Sql<$FillSlots<TRawBindings, TSlots>> {
|
|
444
|
+
return this.#fill(slots, true);
|
|
145
445
|
}
|
|
146
446
|
|
|
147
447
|
/**
|
|
@@ -171,6 +471,7 @@ export class Sql {
|
|
|
171
471
|
|
|
172
472
|
/**
|
|
173
473
|
* 生の文字列を SQL 断片として扱います。
|
|
474
|
+
*
|
|
174
475
|
* この値はパラメーター化の対象にならず、そのままクエリーに含まれます。
|
|
175
476
|
*
|
|
176
477
|
* @param value SQL に含める生の文字列です。
|
package/src/index.ts
CHANGED
package/src/sql.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { empty, join, raw, Sql, ident, literal } from "./core.js";
|
|
1
|
+
import { empty, join, raw, Sql, ident, literal, Slot, RawValue } from "./core.js";
|
|
2
2
|
|
|
3
3
|
namespace sql {
|
|
4
4
|
/**
|
|
@@ -11,15 +11,50 @@ namespace sql {
|
|
|
11
11
|
*/
|
|
12
12
|
export type Value = import("./core.js").Value;
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* スロットを表すクラスです。
|
|
16
|
+
*
|
|
17
|
+
* スロットは後から値を注入可能なプレースホルダーです。
|
|
18
|
+
*
|
|
19
|
+
* @template TName スロットの名前となる文字列リテラル型です。
|
|
20
|
+
* @template TValue スロットに許容される値の型です。
|
|
21
|
+
*/
|
|
22
|
+
export type Slot<
|
|
23
|
+
TName extends string = string,
|
|
24
|
+
TValue extends RawValue = RawValue,
|
|
25
|
+
> = import("./core.js").Slot<TName, TValue>;
|
|
26
|
+
|
|
14
27
|
/**
|
|
15
28
|
* 安全な SQL クエリーを構築するためのクラス型です。
|
|
29
|
+
*
|
|
30
|
+
* @template TRawBindings クエリーに渡される生の値のタプル型です。
|
|
16
31
|
*/
|
|
17
|
-
export type Sql =
|
|
32
|
+
export type Sql<TRawBindings extends readonly RawValue[] = readonly RawValue[]> =
|
|
33
|
+
import("./core.js").Sql<TRawBindings>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 新しい Slot インスタンスを作成します。
|
|
38
|
+
*
|
|
39
|
+
* @template TName スロットの名前となる文字列リテラル型です。
|
|
40
|
+
* @template TValue スロットに許容される値の型です。
|
|
41
|
+
* @param name スロット名です。
|
|
42
|
+
* @param defaultValue デフォルト値です。
|
|
43
|
+
* @returns 作成された新しい Slot インスタンスです。
|
|
44
|
+
*/
|
|
45
|
+
function slot<const TName extends string, TValue extends RawValue = RawValue>(
|
|
46
|
+
name: TName,
|
|
47
|
+
defaultValue?: TValue,
|
|
48
|
+
): sql.Slot<TName, TValue>;
|
|
49
|
+
|
|
50
|
+
function slot(...args: [any]): sql.Slot {
|
|
51
|
+
return new sql.Slot(...args);
|
|
18
52
|
}
|
|
19
53
|
|
|
20
54
|
/**
|
|
21
55
|
* テンプレートリテラルを使用して SQL クエリーを安全に構築するためのタグ関数です。
|
|
22
56
|
*
|
|
57
|
+
* @template TRawBindings クエリーに渡される生の値のタプル型です。
|
|
23
58
|
* @param strings テンプレートリテラルの静的な文字列部分の配列です。
|
|
24
59
|
* @param bindings テンプレートリテラルに埋め込まれた動的な値の配列です。
|
|
25
60
|
* @returns パラメーター化された SQL 情報を保持する Sql インスタンスを返します。
|
|
@@ -29,12 +64,15 @@ namespace sql {
|
|
|
29
64
|
* ```
|
|
30
65
|
*/
|
|
31
66
|
const sql = /*#__PURE__*/ Object.assign(
|
|
32
|
-
function sql
|
|
67
|
+
function sql<const TRawBindings extends readonly RawValue[]>(
|
|
68
|
+
strings: TemplateStringsArray,
|
|
69
|
+
...bindings: TRawBindings
|
|
70
|
+
): sql.Sql<TRawBindings> {
|
|
33
71
|
return new Sql(strings, bindings);
|
|
34
72
|
},
|
|
35
73
|
{
|
|
36
74
|
/**
|
|
37
|
-
* Sql
|
|
75
|
+
* Sql クラスです。
|
|
38
76
|
*/
|
|
39
77
|
Sql,
|
|
40
78
|
|
|
@@ -43,6 +81,18 @@ const sql = /*#__PURE__*/ Object.assign(
|
|
|
43
81
|
*/
|
|
44
82
|
raw,
|
|
45
83
|
|
|
84
|
+
/**
|
|
85
|
+
* 新しい Slot インスタンスを作成する関数です。
|
|
86
|
+
*/
|
|
87
|
+
slot,
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* スロットを表すクラスです。
|
|
91
|
+
*
|
|
92
|
+
* スロットは後から値を注入可能なプレースホルダーです。
|
|
93
|
+
*/
|
|
94
|
+
Slot,
|
|
95
|
+
|
|
46
96
|
/**
|
|
47
97
|
* 複数の SQL 断片を結合するための関数です。
|
|
48
98
|
*/
|