firebase-rest-firestore 1.1.2 → 1.5.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.
- package/dist/cjs/client.d.ts +417 -0
- package/dist/cjs/client.js +1078 -0
- package/dist/{index.d.ts → cjs/index.d.ts} +1 -1
- package/dist/{index.js → cjs/index.js} +1 -2
- package/dist/{types.d.ts → cjs/types.d.ts} +4 -0
- package/dist/cjs/utils/auth.d.ts +13 -0
- package/dist/{utils → cjs/utils}/auth.js +14 -10
- package/dist/cjs/utils/config.d.ts +6 -0
- package/dist/{utils → cjs/utils}/config.js +0 -12
- package/dist/cjs/utils/path.d.ts +73 -0
- package/dist/cjs/utils/path.js +176 -0
- package/dist/esm/client.d.ts +417 -0
- package/dist/esm/client.js +1066 -0
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.js +11 -0
- package/dist/esm/types.d.ts +69 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/utils/auth.d.ts +13 -0
- package/dist/esm/utils/auth.js +57 -0
- package/dist/esm/utils/config.d.ts +6 -0
- package/dist/esm/utils/config.js +11 -0
- package/dist/esm/utils/converter.d.ts +27 -0
- package/dist/esm/utils/converter.js +107 -0
- package/dist/esm/utils/path.d.ts +73 -0
- package/dist/esm/utils/path.js +169 -0
- package/dist/types/client.d.ts +417 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/types.d.ts +69 -0
- package/dist/types/utils/auth.d.ts +13 -0
- package/dist/types/utils/config.d.ts +6 -0
- package/dist/types/utils/converter.d.ts +27 -0
- package/dist/types/utils/path.d.ts +73 -0
- package/package.json +18 -5
- package/dist/client.d.ts +0 -381
- package/dist/client.js +0 -878
- package/dist/utils/auth.d.ts +0 -13
- package/dist/utils/config.d.ts +0 -13
- package/dist/utils/path.d.ts +0 -14
- package/dist/utils/path.js +0 -27
- /package/dist/{types.js → cjs/types.js} +0 -0
- /package/dist/{utils → cjs/utils}/converter.d.ts +0 -0
- /package/dist/{utils → cjs/utils}/converter.js +0 -0
package/dist/client.js
DELETED
|
@@ -1,878 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WriteResult = exports.DocumentSnapshot = exports.QuerySnapshot = exports.Query = exports.CollectionGroup = exports.DocumentReference = exports.CollectionReference = exports.FirestoreClient = void 0;
|
|
4
|
-
exports.createFirestoreClient = createFirestoreClient;
|
|
5
|
-
const auth_1 = require("./utils/auth");
|
|
6
|
-
const converter_1 = require("./utils/converter");
|
|
7
|
-
const path_1 = require("./utils/path");
|
|
8
|
-
const config_1 = require("./utils/config");
|
|
9
|
-
/**
|
|
10
|
-
* Firestoreクライアントクラス
|
|
11
|
-
*/
|
|
12
|
-
class FirestoreClient {
|
|
13
|
-
/**
|
|
14
|
-
* コンストラクタ
|
|
15
|
-
* @param config Firestore設定オブジェクト
|
|
16
|
-
*/
|
|
17
|
-
constructor(config) {
|
|
18
|
-
this.token = null;
|
|
19
|
-
this.tokenExpiry = 0;
|
|
20
|
-
this.configChecked = false;
|
|
21
|
-
this.config = config;
|
|
22
|
-
// ビルド時にはチェックを行わない
|
|
23
|
-
// 実際の操作時に遅延チェックを行う
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* 設定パラメータをチェック
|
|
27
|
-
* @private
|
|
28
|
-
*/
|
|
29
|
-
checkConfig() {
|
|
30
|
-
if (this.configChecked) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
// 必須パラメータのチェック
|
|
34
|
-
const requiredParams = [
|
|
35
|
-
"projectId",
|
|
36
|
-
"privateKey",
|
|
37
|
-
"clientEmail",
|
|
38
|
-
];
|
|
39
|
-
const missingParams = requiredParams.filter(param => !this.config[param]);
|
|
40
|
-
if (missingParams.length > 0) {
|
|
41
|
-
throw new Error(`Missing required Firestore configuration parameters: ${missingParams.join(", ")}`);
|
|
42
|
-
}
|
|
43
|
-
this.configChecked = true;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* 認証トークンを取得(キャッシュあり)
|
|
47
|
-
*/
|
|
48
|
-
async getToken() {
|
|
49
|
-
// 操作前に設定をチェック
|
|
50
|
-
this.checkConfig();
|
|
51
|
-
const now = Date.now();
|
|
52
|
-
// トークンが期限切れか未取得の場合は新しく取得
|
|
53
|
-
if (!this.token || now >= this.tokenExpiry) {
|
|
54
|
-
this.token = await (0, auth_1.getFirestoreToken)(this.config);
|
|
55
|
-
// 50分後に期限切れとする(実際は1時間)
|
|
56
|
-
this.tokenExpiry = now + 50 * 60 * 1000;
|
|
57
|
-
}
|
|
58
|
-
return this.token;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* コレクションリファレンスを取得
|
|
62
|
-
* @param path コレクションパス
|
|
63
|
-
* @returns CollectionReferenceインスタンス
|
|
64
|
-
*/
|
|
65
|
-
collection(path) {
|
|
66
|
-
// 設定チェックは実際の操作時に行われる
|
|
67
|
-
return new CollectionReference(this, path);
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* ドキュメントリファレンスを取得
|
|
71
|
-
* @param path ドキュメントパス
|
|
72
|
-
* @returns DocumentReferenceインスタンス
|
|
73
|
-
*/
|
|
74
|
-
doc(path) {
|
|
75
|
-
// 設定チェックは実際の操作時に行われる
|
|
76
|
-
const parts = path.split("/");
|
|
77
|
-
if (parts.length % 2 === 0) {
|
|
78
|
-
throw new Error("Invalid document path. Document path must point to a document, not a collection.");
|
|
79
|
-
}
|
|
80
|
-
const collectionPath = parts.slice(0, parts.length - 1).join("/");
|
|
81
|
-
const docId = parts[parts.length - 1];
|
|
82
|
-
return new DocumentReference(this, collectionPath, docId);
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* コレクショングループリファレンスを取得
|
|
86
|
-
* @param path コレクショングループのID
|
|
87
|
-
* @returns CollectionGroupインスタンス
|
|
88
|
-
*/
|
|
89
|
-
collectionGroup(path) {
|
|
90
|
-
return new CollectionGroup(this, path);
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Firestoreにドキュメントを追加
|
|
94
|
-
* @param collectionName コレクション名
|
|
95
|
-
* @param data 追加するデータ
|
|
96
|
-
* @returns 追加されたドキュメント
|
|
97
|
-
*/
|
|
98
|
-
async add(collectionName, data) {
|
|
99
|
-
// 操作前に設定をチェック
|
|
100
|
-
this.checkConfig();
|
|
101
|
-
const url = (0, path_1.getFirestoreBasePath)(this.config.projectId, collectionName, this.config.databaseId);
|
|
102
|
-
const firestoreData = (0, converter_1.convertToFirestoreDocument)(data);
|
|
103
|
-
const token = await this.getToken();
|
|
104
|
-
const response = await fetch(url, {
|
|
105
|
-
method: "POST",
|
|
106
|
-
headers: {
|
|
107
|
-
"Content-Type": "application/json",
|
|
108
|
-
Authorization: `Bearer ${token}`,
|
|
109
|
-
},
|
|
110
|
-
body: JSON.stringify(firestoreData),
|
|
111
|
-
});
|
|
112
|
-
if (!response.ok) {
|
|
113
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
114
|
-
}
|
|
115
|
-
const result = (await response.json());
|
|
116
|
-
return (0, converter_1.convertFromFirestoreDocument)(result);
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* ドキュメントを取得
|
|
120
|
-
* @param collectionName コレクション名
|
|
121
|
-
* @param documentId ドキュメントID
|
|
122
|
-
* @returns 取得したドキュメント(存在しない場合はnull)
|
|
123
|
-
*/
|
|
124
|
-
async get(collectionName, documentId) {
|
|
125
|
-
// 操作前に設定をチェック
|
|
126
|
-
this.checkConfig();
|
|
127
|
-
const url = `${(0, path_1.getFirestoreBasePath)(this.config.projectId, collectionName, this.config.databaseId)}/${documentId}`;
|
|
128
|
-
const token = await this.getToken();
|
|
129
|
-
const response = await fetch(url, {
|
|
130
|
-
method: "GET",
|
|
131
|
-
headers: {
|
|
132
|
-
Authorization: `Bearer ${token}`,
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
if (response.status === 404) {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
if (!response.ok) {
|
|
139
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
140
|
-
}
|
|
141
|
-
const result = (await response.json());
|
|
142
|
-
return (0, converter_1.convertFromFirestoreDocument)(result);
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* ドキュメントを更新
|
|
146
|
-
* @param collectionName コレクション名
|
|
147
|
-
* @param documentId ドキュメントID
|
|
148
|
-
* @param data 更新するデータ
|
|
149
|
-
* @returns 更新されたドキュメント
|
|
150
|
-
*/
|
|
151
|
-
async update(collectionName, documentId, data) {
|
|
152
|
-
// 操作前に設定をチェック
|
|
153
|
-
this.checkConfig();
|
|
154
|
-
const url = `${(0, path_1.getFirestoreBasePath)(this.config.projectId, collectionName, this.config.databaseId)}/${documentId}`;
|
|
155
|
-
// 既存のドキュメントを取得してからマージする
|
|
156
|
-
const existingDoc = await this.get(collectionName, documentId);
|
|
157
|
-
if (existingDoc) {
|
|
158
|
-
data = { ...existingDoc, ...data };
|
|
159
|
-
}
|
|
160
|
-
const firestoreData = (0, converter_1.convertToFirestoreDocument)(data);
|
|
161
|
-
const token = await this.getToken();
|
|
162
|
-
const response = await fetch(url, {
|
|
163
|
-
method: "PATCH",
|
|
164
|
-
headers: {
|
|
165
|
-
"Content-Type": "application/json",
|
|
166
|
-
Authorization: `Bearer ${token}`,
|
|
167
|
-
},
|
|
168
|
-
body: JSON.stringify(firestoreData),
|
|
169
|
-
});
|
|
170
|
-
if (!response.ok) {
|
|
171
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
172
|
-
}
|
|
173
|
-
const result = (await response.json());
|
|
174
|
-
return (0, converter_1.convertFromFirestoreDocument)(result);
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* ドキュメントを削除
|
|
178
|
-
* @param collectionName コレクション名
|
|
179
|
-
* @param documentId ドキュメントID
|
|
180
|
-
* @returns 削除成功時はtrue
|
|
181
|
-
*/
|
|
182
|
-
async delete(collectionName, documentId) {
|
|
183
|
-
// 操作前に設定をチェック
|
|
184
|
-
this.checkConfig();
|
|
185
|
-
const url = `${(0, path_1.getFirestoreBasePath)(this.config.projectId, collectionName, this.config.databaseId)}/${documentId}`;
|
|
186
|
-
const token = await this.getToken();
|
|
187
|
-
const response = await fetch(url, {
|
|
188
|
-
method: "DELETE",
|
|
189
|
-
headers: {
|
|
190
|
-
Authorization: `Bearer ${token}`,
|
|
191
|
-
},
|
|
192
|
-
});
|
|
193
|
-
if (!response.ok) {
|
|
194
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
195
|
-
}
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* コレクションのドキュメントを検索
|
|
200
|
-
* @param collectionPath コレクションパス
|
|
201
|
-
* @param options クエリオプション
|
|
202
|
-
* @param allDescendants 子孫コレクションを含むかどうか
|
|
203
|
-
* @returns 検索結果のドキュメント配列
|
|
204
|
-
*/
|
|
205
|
-
async query(collectionPath, options = {}, allDescendants) {
|
|
206
|
-
// 操作前に設定をチェック
|
|
207
|
-
this.checkConfig();
|
|
208
|
-
// :runQueryはコレクション単位ではなく、ドキュメントルート単位で実行
|
|
209
|
-
// コレクション名パス形式の場合は、endpointをドキュメントルートに置き換える。collectionNameはコレクションIDにする
|
|
210
|
-
// e.g) パス形式: collectionPath = "/users/123/items" の場合は、collectionPaths = ["users", "123", "items"], collectionName = "items", basePath += "/users/123"
|
|
211
|
-
// e.g) 単一形式: collectionPath = "items" の場合は、collectionPaths = ["items"], collectionName = "items", basePath += ""
|
|
212
|
-
const collectionPaths = collectionPath.split("/");
|
|
213
|
-
let basePath = `https://firestore.googleapis.com/v1/projects/${this.config.projectId}/databases/${this.config.databaseId || "(default)"}/documents`;
|
|
214
|
-
let collectionName = collectionPath;
|
|
215
|
-
if (collectionPaths.length > 1) {
|
|
216
|
-
basePath = `${basePath}/${collectionPaths.slice(0, -1).join("/")}`;
|
|
217
|
-
collectionName = collectionPaths[collectionPaths.length - 1];
|
|
218
|
-
}
|
|
219
|
-
const url = `${basePath}:runQuery`;
|
|
220
|
-
// クエリ構築
|
|
221
|
-
//allDescendants: falseの場合は直下のcollectionを参照。trueの場合は子孫コレクションも参照
|
|
222
|
-
const structuredQuery = {
|
|
223
|
-
from: [
|
|
224
|
-
{
|
|
225
|
-
collectionId: collectionName,
|
|
226
|
-
allDescendants,
|
|
227
|
-
},
|
|
228
|
-
],
|
|
229
|
-
};
|
|
230
|
-
// フィルター条件
|
|
231
|
-
if (options.where && options.where.length > 0) {
|
|
232
|
-
// シンプルなケース: 1つの条件の場合
|
|
233
|
-
if (options.where.length === 1) {
|
|
234
|
-
const condition = options.where[0];
|
|
235
|
-
structuredQuery.where = {
|
|
236
|
-
fieldFilter: {
|
|
237
|
-
field: { fieldPath: condition.field },
|
|
238
|
-
op: condition.op,
|
|
239
|
-
value: (0, converter_1.convertToFirestoreValue)(condition.value),
|
|
240
|
-
},
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
else {
|
|
244
|
-
// 複数条件の場合
|
|
245
|
-
structuredQuery.where = {
|
|
246
|
-
compositeFilter: {
|
|
247
|
-
op: "AND",
|
|
248
|
-
filters: options.where.map(condition => ({
|
|
249
|
-
fieldFilter: {
|
|
250
|
-
field: { fieldPath: condition.field },
|
|
251
|
-
op: condition.op,
|
|
252
|
-
value: (0, converter_1.convertToFirestoreValue)(condition.value),
|
|
253
|
-
},
|
|
254
|
-
})),
|
|
255
|
-
},
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
// 並べ替え
|
|
260
|
-
if (options.orderBy) {
|
|
261
|
-
structuredQuery.orderBy = [
|
|
262
|
-
{
|
|
263
|
-
field: { fieldPath: options.orderBy },
|
|
264
|
-
direction: options.orderDirection || "ASCENDING",
|
|
265
|
-
},
|
|
266
|
-
];
|
|
267
|
-
}
|
|
268
|
-
// 制限
|
|
269
|
-
if (options.limit) {
|
|
270
|
-
structuredQuery.limit = options.limit;
|
|
271
|
-
}
|
|
272
|
-
// オフセット
|
|
273
|
-
if (options.offset) {
|
|
274
|
-
structuredQuery.offset = options.offset;
|
|
275
|
-
}
|
|
276
|
-
const token = await this.getToken();
|
|
277
|
-
// 修正: structuredQueryをラップしたリクエストボディを作成
|
|
278
|
-
const requestBody = {
|
|
279
|
-
structuredQuery: structuredQuery,
|
|
280
|
-
};
|
|
281
|
-
console.log("クエリリクエスト:", JSON.stringify(requestBody, null, 2));
|
|
282
|
-
try {
|
|
283
|
-
const response = await fetch(url, {
|
|
284
|
-
method: "POST",
|
|
285
|
-
headers: {
|
|
286
|
-
"Content-Type": "application/json",
|
|
287
|
-
Authorization: `Bearer ${token}`,
|
|
288
|
-
},
|
|
289
|
-
body: JSON.stringify(requestBody),
|
|
290
|
-
});
|
|
291
|
-
const responseText = await response.text();
|
|
292
|
-
console.log("API レスポンス:", responseText);
|
|
293
|
-
if (!response.ok) {
|
|
294
|
-
throw new Error(`Firestore API error: ${response.statusText} - ${responseText}`);
|
|
295
|
-
}
|
|
296
|
-
const results = JSON.parse(responseText);
|
|
297
|
-
console.log("変換前の結果:", results);
|
|
298
|
-
const convertedResults = results
|
|
299
|
-
.filter(item => item.document)
|
|
300
|
-
.map(item => (0, converter_1.convertFromFirestoreDocument)(item.document));
|
|
301
|
-
console.log("変換後の結果:", convertedResults);
|
|
302
|
-
return convertedResults;
|
|
303
|
-
}
|
|
304
|
-
catch (error) {
|
|
305
|
-
console.error("クエリ実行エラー:", error);
|
|
306
|
-
throw error;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
exports.FirestoreClient = FirestoreClient;
|
|
311
|
-
/**
|
|
312
|
-
* コレクションリファレンスクラス
|
|
313
|
-
*/
|
|
314
|
-
class CollectionReference {
|
|
315
|
-
constructor(client, path) {
|
|
316
|
-
this.client = client;
|
|
317
|
-
this.path = path;
|
|
318
|
-
this._queryConstraints = {
|
|
319
|
-
where: [],
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* すべての子孫コレクションを含むかどうか
|
|
324
|
-
*/
|
|
325
|
-
get allDescendants() {
|
|
326
|
-
return false;
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* ドキュメントリファレンスを取得
|
|
330
|
-
* @param documentPath ドキュメントID(省略時は自動生成)
|
|
331
|
-
* @returns DocumentReferenceインスタンス
|
|
332
|
-
*/
|
|
333
|
-
doc(documentPath) {
|
|
334
|
-
const docId = documentPath || this._generateId();
|
|
335
|
-
return new DocumentReference(this.client, this.path, docId);
|
|
336
|
-
}
|
|
337
|
-
/**
|
|
338
|
-
* ドキュメントを追加(IDは自動生成)
|
|
339
|
-
* @param data ドキュメントデータ
|
|
340
|
-
* @returns 作成されたドキュメントのリファレンス
|
|
341
|
-
*/
|
|
342
|
-
async add(data) {
|
|
343
|
-
const result = await this.client.add(this.path, data);
|
|
344
|
-
const docId = result.id;
|
|
345
|
-
return new DocumentReference(this.client, this.path, docId);
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* フィルター条件を追加
|
|
349
|
-
* @param fieldPath フィールドパス
|
|
350
|
-
* @param opStr 演算子
|
|
351
|
-
* @param value 値
|
|
352
|
-
* @returns Queryインスタンス
|
|
353
|
-
*/
|
|
354
|
-
where(fieldPath, opStr, value) {
|
|
355
|
-
const query = new Query(this.client, this.path, {
|
|
356
|
-
...this._queryConstraints,
|
|
357
|
-
}, this.allDescendants);
|
|
358
|
-
// 演算子の変換
|
|
359
|
-
let firestoreOp;
|
|
360
|
-
switch (opStr) {
|
|
361
|
-
case "==":
|
|
362
|
-
firestoreOp = "EQUAL";
|
|
363
|
-
break;
|
|
364
|
-
case "!=":
|
|
365
|
-
firestoreOp = "NOT_EQUAL";
|
|
366
|
-
break;
|
|
367
|
-
case "<":
|
|
368
|
-
firestoreOp = "LESS_THAN";
|
|
369
|
-
break;
|
|
370
|
-
case "<=":
|
|
371
|
-
firestoreOp = "LESS_THAN_OR_EQUAL";
|
|
372
|
-
break;
|
|
373
|
-
case ">":
|
|
374
|
-
firestoreOp = "GREATER_THAN";
|
|
375
|
-
break;
|
|
376
|
-
case ">=":
|
|
377
|
-
firestoreOp = "GREATER_THAN_OR_EQUAL";
|
|
378
|
-
break;
|
|
379
|
-
case "array-contains":
|
|
380
|
-
firestoreOp = "ARRAY_CONTAINS";
|
|
381
|
-
break;
|
|
382
|
-
case "in":
|
|
383
|
-
firestoreOp = "IN";
|
|
384
|
-
break;
|
|
385
|
-
case "array-contains-any":
|
|
386
|
-
firestoreOp = "ARRAY_CONTAINS_ANY";
|
|
387
|
-
break;
|
|
388
|
-
case "not-in":
|
|
389
|
-
firestoreOp = "NOT_IN";
|
|
390
|
-
break;
|
|
391
|
-
default:
|
|
392
|
-
firestoreOp = opStr;
|
|
393
|
-
}
|
|
394
|
-
query._queryConstraints.where.push({
|
|
395
|
-
field: fieldPath,
|
|
396
|
-
op: firestoreOp,
|
|
397
|
-
value,
|
|
398
|
-
});
|
|
399
|
-
return query;
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* 並べ替え条件を追加
|
|
403
|
-
* @param fieldPath フィールドパス
|
|
404
|
-
* @param directionStr 並べ替え方向('asc'または'desc')
|
|
405
|
-
* @returns Queryインスタンス
|
|
406
|
-
*/
|
|
407
|
-
orderBy(fieldPath, directionStr = "asc") {
|
|
408
|
-
const query = new Query(this.client, this.path, {
|
|
409
|
-
...this._queryConstraints,
|
|
410
|
-
}, this.allDescendants);
|
|
411
|
-
query._queryConstraints.orderBy = fieldPath;
|
|
412
|
-
query._queryConstraints.orderDirection =
|
|
413
|
-
directionStr === "asc" ? "ASCENDING" : "DESCENDING";
|
|
414
|
-
return query;
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* 取得件数の制限を設定
|
|
418
|
-
* @param limit 最大件数
|
|
419
|
-
* @returns Queryインスタンス
|
|
420
|
-
*/
|
|
421
|
-
limit(limit) {
|
|
422
|
-
const query = new Query(this.client, this.path, {
|
|
423
|
-
...this._queryConstraints,
|
|
424
|
-
}, this.allDescendants);
|
|
425
|
-
query._queryConstraints.limit = limit;
|
|
426
|
-
return query;
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* スキップ件数を設定
|
|
430
|
-
* @param offset スキップ件数
|
|
431
|
-
* @returns Queryインスタンス
|
|
432
|
-
*/
|
|
433
|
-
offset(offset) {
|
|
434
|
-
const query = new Query(this.client, this.path, {
|
|
435
|
-
...this._queryConstraints,
|
|
436
|
-
}, this.allDescendants);
|
|
437
|
-
query._queryConstraints.offset = offset;
|
|
438
|
-
return query;
|
|
439
|
-
}
|
|
440
|
-
/**
|
|
441
|
-
* クエリを実行
|
|
442
|
-
* @returns QuerySnapshotインスタンス
|
|
443
|
-
*/
|
|
444
|
-
async get() {
|
|
445
|
-
const results = await this.client.query(this.path, this._queryConstraints, this.allDescendants);
|
|
446
|
-
return new QuerySnapshot(results);
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* ランダムなIDを生成
|
|
450
|
-
* @returns ランダムなID
|
|
451
|
-
*/
|
|
452
|
-
_generateId() {
|
|
453
|
-
// 20文字のランダムなIDを生成
|
|
454
|
-
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
455
|
-
let id = "";
|
|
456
|
-
for (let i = 0; i < 20; i++) {
|
|
457
|
-
id += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
458
|
-
}
|
|
459
|
-
return id;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
exports.CollectionReference = CollectionReference;
|
|
463
|
-
/**
|
|
464
|
-
* ドキュメントリファレンスクラス
|
|
465
|
-
*/
|
|
466
|
-
class DocumentReference {
|
|
467
|
-
constructor(client, collectionPath, docId) {
|
|
468
|
-
this.client = client;
|
|
469
|
-
this.collectionPath = collectionPath;
|
|
470
|
-
this.docId = docId;
|
|
471
|
-
}
|
|
472
|
-
/**
|
|
473
|
-
* ドキュメントIDを取得
|
|
474
|
-
*/
|
|
475
|
-
get id() {
|
|
476
|
-
return this.docId;
|
|
477
|
-
}
|
|
478
|
-
/**
|
|
479
|
-
* ドキュメントのパスを取得
|
|
480
|
-
*/
|
|
481
|
-
get path() {
|
|
482
|
-
return `${this.collectionPath}/${this.docId}`;
|
|
483
|
-
}
|
|
484
|
-
/**
|
|
485
|
-
* サブコレクションを取得
|
|
486
|
-
* @param collectionPath サブコレクション名
|
|
487
|
-
* @returns CollectionReferenceインスタンス
|
|
488
|
-
*/
|
|
489
|
-
collection(collectionPath) {
|
|
490
|
-
return new CollectionReference(this.client, `${this.path}/${collectionPath}`);
|
|
491
|
-
}
|
|
492
|
-
/**
|
|
493
|
-
* ドキュメントを取得
|
|
494
|
-
* @returns DocumentSnapshotインスタンス
|
|
495
|
-
*/
|
|
496
|
-
async get() {
|
|
497
|
-
const data = await this.client.get(this.collectionPath, this.docId);
|
|
498
|
-
return new DocumentSnapshot(this.docId, data);
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* ドキュメントを作成または上書き
|
|
502
|
-
* @param data ドキュメントデータ
|
|
503
|
-
* @param options オプション(mergeは現在サポートされていません)
|
|
504
|
-
* @returns WriteResultインスタンス
|
|
505
|
-
*/
|
|
506
|
-
async set(data, options) {
|
|
507
|
-
// 既存のドキュメントを取得
|
|
508
|
-
const existingDoc = await this.client.get(this.collectionPath, this.docId);
|
|
509
|
-
if (existingDoc) {
|
|
510
|
-
// 既存のドキュメントがある場合は更新
|
|
511
|
-
const mergedData = options?.merge ? { ...existingDoc, ...data } : data;
|
|
512
|
-
await this.client.update(this.collectionPath, this.docId, mergedData);
|
|
513
|
-
}
|
|
514
|
-
else {
|
|
515
|
-
// 新規作成
|
|
516
|
-
const newData = { ...data, id: this.docId };
|
|
517
|
-
await this.client.add(this.collectionPath, newData);
|
|
518
|
-
}
|
|
519
|
-
return new WriteResult();
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* ドキュメントを更新
|
|
523
|
-
* @param data 更新データ
|
|
524
|
-
* @returns WriteResultインスタンス
|
|
525
|
-
*/
|
|
526
|
-
async update(data) {
|
|
527
|
-
await this.client.update(this.collectionPath, this.docId, data);
|
|
528
|
-
return new WriteResult();
|
|
529
|
-
}
|
|
530
|
-
/**
|
|
531
|
-
* ドキュメントを削除
|
|
532
|
-
* @returns WriteResultインスタンス
|
|
533
|
-
*/
|
|
534
|
-
async delete() {
|
|
535
|
-
await this.client.delete(this.collectionPath, this.docId);
|
|
536
|
-
return new WriteResult();
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
exports.DocumentReference = DocumentReference;
|
|
540
|
-
/**
|
|
541
|
-
* コレクショングループ
|
|
542
|
-
*/
|
|
543
|
-
class CollectionGroup {
|
|
544
|
-
constructor(client, path) {
|
|
545
|
-
this.client = client;
|
|
546
|
-
this.path = path;
|
|
547
|
-
this._queryConstraints = {
|
|
548
|
-
where: [],
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
/**
|
|
552
|
-
* すべての子孫コレクションを含むかどうか
|
|
553
|
-
*/
|
|
554
|
-
get allDescendants() {
|
|
555
|
-
return true;
|
|
556
|
-
}
|
|
557
|
-
/**
|
|
558
|
-
* フィルター条件を追加
|
|
559
|
-
* @param fieldPath フィールドパス
|
|
560
|
-
* @param opStr 演算子
|
|
561
|
-
* @param value 値
|
|
562
|
-
* @returns Queryインスタンス
|
|
563
|
-
*/
|
|
564
|
-
where(fieldPath, opStr, value) {
|
|
565
|
-
const query = new Query(this.client, this.path, {
|
|
566
|
-
...this._queryConstraints,
|
|
567
|
-
}, this.allDescendants);
|
|
568
|
-
// 演算子の変換
|
|
569
|
-
let firestoreOp;
|
|
570
|
-
switch (opStr) {
|
|
571
|
-
case "==":
|
|
572
|
-
firestoreOp = "EQUAL";
|
|
573
|
-
break;
|
|
574
|
-
case "!=":
|
|
575
|
-
firestoreOp = "NOT_EQUAL";
|
|
576
|
-
break;
|
|
577
|
-
case "<":
|
|
578
|
-
firestoreOp = "LESS_THAN";
|
|
579
|
-
break;
|
|
580
|
-
case "<=":
|
|
581
|
-
firestoreOp = "LESS_THAN_OR_EQUAL";
|
|
582
|
-
break;
|
|
583
|
-
case ">":
|
|
584
|
-
firestoreOp = "GREATER_THAN";
|
|
585
|
-
break;
|
|
586
|
-
case ">=":
|
|
587
|
-
firestoreOp = "GREATER_THAN_OR_EQUAL";
|
|
588
|
-
break;
|
|
589
|
-
case "array-contains":
|
|
590
|
-
firestoreOp = "ARRAY_CONTAINS";
|
|
591
|
-
break;
|
|
592
|
-
case "in":
|
|
593
|
-
firestoreOp = "IN";
|
|
594
|
-
break;
|
|
595
|
-
case "array-contains-any":
|
|
596
|
-
firestoreOp = "ARRAY_CONTAINS_ANY";
|
|
597
|
-
break;
|
|
598
|
-
case "not-in":
|
|
599
|
-
firestoreOp = "NOT_IN";
|
|
600
|
-
break;
|
|
601
|
-
default:
|
|
602
|
-
firestoreOp = opStr;
|
|
603
|
-
}
|
|
604
|
-
query._queryConstraints.where.push({
|
|
605
|
-
field: fieldPath,
|
|
606
|
-
op: firestoreOp,
|
|
607
|
-
value,
|
|
608
|
-
});
|
|
609
|
-
return query;
|
|
610
|
-
}
|
|
611
|
-
/**
|
|
612
|
-
* 並べ替え条件を追加
|
|
613
|
-
* @param fieldPath フィールドパス
|
|
614
|
-
* @param directionStr 並べ替え方向('asc'または'desc')
|
|
615
|
-
* @returns Queryインスタンス
|
|
616
|
-
*/
|
|
617
|
-
orderBy(fieldPath, directionStr = "asc") {
|
|
618
|
-
const query = new Query(this.client, this.path, {
|
|
619
|
-
...this._queryConstraints,
|
|
620
|
-
}, this.allDescendants);
|
|
621
|
-
query._queryConstraints.orderBy = fieldPath;
|
|
622
|
-
query._queryConstraints.orderDirection =
|
|
623
|
-
directionStr === "asc" ? "ASCENDING" : "DESCENDING";
|
|
624
|
-
return query;
|
|
625
|
-
}
|
|
626
|
-
/**
|
|
627
|
-
* 取得件数の制限を設定
|
|
628
|
-
* @param limit 最大件数
|
|
629
|
-
* @returns Queryインスタンス
|
|
630
|
-
*/
|
|
631
|
-
limit(limit) {
|
|
632
|
-
const query = new Query(this.client, this.path, {
|
|
633
|
-
...this._queryConstraints,
|
|
634
|
-
}, this.allDescendants);
|
|
635
|
-
query._queryConstraints.limit = limit;
|
|
636
|
-
return query;
|
|
637
|
-
}
|
|
638
|
-
/**
|
|
639
|
-
* スキップ件数を設定
|
|
640
|
-
* @param offset スキップ件数
|
|
641
|
-
* @returns Queryインスタンス
|
|
642
|
-
*/
|
|
643
|
-
offset(offset) {
|
|
644
|
-
const query = new Query(this.client, this.path, {
|
|
645
|
-
...this._queryConstraints,
|
|
646
|
-
}, this.allDescendants);
|
|
647
|
-
query._queryConstraints.offset = offset;
|
|
648
|
-
return query;
|
|
649
|
-
}
|
|
650
|
-
/**
|
|
651
|
-
* クエリを実行
|
|
652
|
-
* @returns QuerySnapshotインスタンス
|
|
653
|
-
*/
|
|
654
|
-
async get() {
|
|
655
|
-
const results = await this.client.query(this.path, this._queryConstraints, this.allDescendants);
|
|
656
|
-
return new QuerySnapshot(results);
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
exports.CollectionGroup = CollectionGroup;
|
|
660
|
-
/**
|
|
661
|
-
* クエリクラス
|
|
662
|
-
*/
|
|
663
|
-
class Query {
|
|
664
|
-
constructor(client, collectionPath, constraints, allDescendants) {
|
|
665
|
-
this.client = client;
|
|
666
|
-
this.collectionPath = collectionPath;
|
|
667
|
-
this._queryConstraints = constraints;
|
|
668
|
-
this.allDescendants = allDescendants;
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* フィルター条件を追加
|
|
672
|
-
* @param fieldPath フィールドパス
|
|
673
|
-
* @param opStr 演算子
|
|
674
|
-
* @param value 値
|
|
675
|
-
* @returns Queryインスタンス
|
|
676
|
-
*/
|
|
677
|
-
where(fieldPath, opStr, value) {
|
|
678
|
-
const query = new Query(this.client, this.collectionPath, {
|
|
679
|
-
...this._queryConstraints,
|
|
680
|
-
}, this.allDescendants);
|
|
681
|
-
// 演算子の変換
|
|
682
|
-
let firestoreOp;
|
|
683
|
-
switch (opStr) {
|
|
684
|
-
case "==":
|
|
685
|
-
firestoreOp = "EQUAL";
|
|
686
|
-
break;
|
|
687
|
-
case "!=":
|
|
688
|
-
firestoreOp = "NOT_EQUAL";
|
|
689
|
-
break;
|
|
690
|
-
case "<":
|
|
691
|
-
firestoreOp = "LESS_THAN";
|
|
692
|
-
break;
|
|
693
|
-
case "<=":
|
|
694
|
-
firestoreOp = "LESS_THAN_OR_EQUAL";
|
|
695
|
-
break;
|
|
696
|
-
case ">":
|
|
697
|
-
firestoreOp = "GREATER_THAN";
|
|
698
|
-
break;
|
|
699
|
-
case ">=":
|
|
700
|
-
firestoreOp = "GREATER_THAN_OR_EQUAL";
|
|
701
|
-
break;
|
|
702
|
-
case "array-contains":
|
|
703
|
-
firestoreOp = "ARRAY_CONTAINS";
|
|
704
|
-
break;
|
|
705
|
-
case "in":
|
|
706
|
-
firestoreOp = "IN";
|
|
707
|
-
break;
|
|
708
|
-
case "array-contains-any":
|
|
709
|
-
firestoreOp = "ARRAY_CONTAINS_ANY";
|
|
710
|
-
break;
|
|
711
|
-
case "not-in":
|
|
712
|
-
firestoreOp = "NOT_IN";
|
|
713
|
-
break;
|
|
714
|
-
default:
|
|
715
|
-
firestoreOp = opStr;
|
|
716
|
-
}
|
|
717
|
-
query._queryConstraints.where.push({
|
|
718
|
-
field: fieldPath,
|
|
719
|
-
op: firestoreOp,
|
|
720
|
-
value,
|
|
721
|
-
});
|
|
722
|
-
return query;
|
|
723
|
-
}
|
|
724
|
-
/**
|
|
725
|
-
* 並べ替え条件を追加
|
|
726
|
-
* @param fieldPath フィールドパス
|
|
727
|
-
* @param directionStr 並べ替え方向('asc'または'desc')
|
|
728
|
-
* @returns Queryインスタンス
|
|
729
|
-
*/
|
|
730
|
-
orderBy(fieldPath, directionStr = "asc") {
|
|
731
|
-
const query = new Query(this.client, this.collectionPath, {
|
|
732
|
-
...this._queryConstraints,
|
|
733
|
-
}, this.allDescendants);
|
|
734
|
-
query._queryConstraints.orderBy = fieldPath;
|
|
735
|
-
query._queryConstraints.orderDirection =
|
|
736
|
-
directionStr === "asc" ? "ASCENDING" : "DESCENDING";
|
|
737
|
-
return query;
|
|
738
|
-
}
|
|
739
|
-
/**
|
|
740
|
-
* 取得件数の制限を設定
|
|
741
|
-
* @param limit 最大件数
|
|
742
|
-
* @returns Queryインスタンス
|
|
743
|
-
*/
|
|
744
|
-
limit(limit) {
|
|
745
|
-
const query = new Query(this.client, this.collectionPath, {
|
|
746
|
-
...this._queryConstraints,
|
|
747
|
-
}, this.allDescendants);
|
|
748
|
-
query._queryConstraints.limit = limit;
|
|
749
|
-
return query;
|
|
750
|
-
}
|
|
751
|
-
/**
|
|
752
|
-
* スキップ件数を設定
|
|
753
|
-
* @param offset スキップ件数
|
|
754
|
-
* @returns Queryインスタンス
|
|
755
|
-
*/
|
|
756
|
-
offset(offset) {
|
|
757
|
-
const query = new Query(this.client, this.collectionPath, {
|
|
758
|
-
...this._queryConstraints,
|
|
759
|
-
}, this.allDescendants);
|
|
760
|
-
query._queryConstraints.offset = offset;
|
|
761
|
-
return query;
|
|
762
|
-
}
|
|
763
|
-
/**
|
|
764
|
-
* クエリを実行
|
|
765
|
-
* @returns QuerySnapshotインスタンス
|
|
766
|
-
*/
|
|
767
|
-
async get() {
|
|
768
|
-
const results = await this.client.query(this.collectionPath, this._queryConstraints, this.allDescendants);
|
|
769
|
-
return new QuerySnapshot(results);
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
exports.Query = Query;
|
|
773
|
-
/**
|
|
774
|
-
* クエリ結果クラス
|
|
775
|
-
*/
|
|
776
|
-
class QuerySnapshot {
|
|
777
|
-
constructor(results) {
|
|
778
|
-
this._docs = results.map(doc => {
|
|
779
|
-
const { id, ...data } = doc;
|
|
780
|
-
return new DocumentSnapshot(id, data);
|
|
781
|
-
});
|
|
782
|
-
}
|
|
783
|
-
/**
|
|
784
|
-
* 結果のドキュメント配列
|
|
785
|
-
*/
|
|
786
|
-
get docs() {
|
|
787
|
-
return this._docs;
|
|
788
|
-
}
|
|
789
|
-
/**
|
|
790
|
-
* 結果が空かどうか
|
|
791
|
-
*/
|
|
792
|
-
get empty() {
|
|
793
|
-
return this._docs.length === 0;
|
|
794
|
-
}
|
|
795
|
-
/**
|
|
796
|
-
* 結果の件数
|
|
797
|
-
*/
|
|
798
|
-
get size() {
|
|
799
|
-
return this._docs.length;
|
|
800
|
-
}
|
|
801
|
-
/**
|
|
802
|
-
* 各ドキュメントに対してコールバックを実行
|
|
803
|
-
* @param callback 各ドキュメントに対して実行するコールバック関数
|
|
804
|
-
*/
|
|
805
|
-
forEach(callback) {
|
|
806
|
-
this._docs.forEach(callback);
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
exports.QuerySnapshot = QuerySnapshot;
|
|
810
|
-
/**
|
|
811
|
-
* ドキュメントスナップショットクラス
|
|
812
|
-
*/
|
|
813
|
-
class DocumentSnapshot {
|
|
814
|
-
constructor(id, data) {
|
|
815
|
-
this._id = id;
|
|
816
|
-
this._data = data;
|
|
817
|
-
}
|
|
818
|
-
/**
|
|
819
|
-
* ドキュメントID
|
|
820
|
-
*/
|
|
821
|
-
get id() {
|
|
822
|
-
return this._id;
|
|
823
|
-
}
|
|
824
|
-
/**
|
|
825
|
-
* ドキュメントが存在するかどうか
|
|
826
|
-
*/
|
|
827
|
-
get exists() {
|
|
828
|
-
return this._data !== null;
|
|
829
|
-
}
|
|
830
|
-
/**
|
|
831
|
-
* ドキュメントデータを取得
|
|
832
|
-
* @returns ドキュメントデータ(存在しない場合はundefined)
|
|
833
|
-
*/
|
|
834
|
-
data() {
|
|
835
|
-
return this._data || undefined;
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
exports.DocumentSnapshot = DocumentSnapshot;
|
|
839
|
-
/**
|
|
840
|
-
* 書き込み結果クラス
|
|
841
|
-
*/
|
|
842
|
-
class WriteResult {
|
|
843
|
-
constructor() {
|
|
844
|
-
this.writeTime = new Date();
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
exports.WriteResult = WriteResult;
|
|
848
|
-
/**
|
|
849
|
-
* 新しいFirestoreクライアントインスタンスを作成
|
|
850
|
-
* @param config Firestore設定オブジェクト
|
|
851
|
-
* @returns FirestoreClientインスタンス
|
|
852
|
-
*
|
|
853
|
-
* @example
|
|
854
|
-
* // デフォルトデータベースに接続
|
|
855
|
-
* const db = createFirestoreClient({
|
|
856
|
-
* projectId: 'your-project-id',
|
|
857
|
-
* privateKey: 'your-private-key',
|
|
858
|
-
* clientEmail: 'your-client-email'
|
|
859
|
-
* });
|
|
860
|
-
*
|
|
861
|
-
* // 異なる名前のデータベースに接続
|
|
862
|
-
* const customDb = createFirestoreClient({
|
|
863
|
-
* projectId: 'your-project-id',
|
|
864
|
-
* privateKey: 'your-private-key',
|
|
865
|
-
* clientEmail: 'your-client-email',
|
|
866
|
-
* databaseId: 'your-database-id'
|
|
867
|
-
* });
|
|
868
|
-
*/
|
|
869
|
-
function createFirestoreClient(config) {
|
|
870
|
-
// 秘密鍵のフォーマットを確認
|
|
871
|
-
if (config.privateKey) {
|
|
872
|
-
config = {
|
|
873
|
-
...config,
|
|
874
|
-
privateKey: (0, config_1.formatPrivateKey)(config.privateKey),
|
|
875
|
-
};
|
|
876
|
-
}
|
|
877
|
-
return new FirestoreClient(config);
|
|
878
|
-
}
|