firebase-rest-firestore 0.1.0 → 0.2.1

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/client.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FirestoreClient = void 0;
3
+ exports.WriteResult = exports.DocumentSnapshot = exports.QuerySnapshot = exports.Query = exports.DocumentReference = exports.CollectionReference = exports.FirestoreClient = void 0;
4
4
  exports.createFirestoreClient = createFirestoreClient;
5
5
  const auth_1 = require("./utils/auth");
6
6
  const converter_1 = require("./utils/converter");
@@ -16,7 +16,19 @@ class FirestoreClient {
16
16
  constructor(config) {
17
17
  this.token = null;
18
18
  this.tokenExpiry = 0;
19
+ this.configChecked = false;
19
20
  this.config = config;
21
+ // ビルド時にはチェックを行わない
22
+ // 実際の操作時に遅延チェックを行う
23
+ }
24
+ /**
25
+ * 設定パラメータをチェック
26
+ * @private
27
+ */
28
+ checkConfig() {
29
+ if (this.configChecked) {
30
+ return;
31
+ }
20
32
  // 必須パラメータのチェック
21
33
  const requiredParams = [
22
34
  "projectId",
@@ -27,11 +39,14 @@ class FirestoreClient {
27
39
  if (missingParams.length > 0) {
28
40
  throw new Error(`Missing required Firestore configuration parameters: ${missingParams.join(", ")}`);
29
41
  }
42
+ this.configChecked = true;
30
43
  }
31
44
  /**
32
45
  * 認証トークンを取得(キャッシュあり)
33
46
  */
34
47
  async getToken() {
48
+ // 操作前に設定をチェック
49
+ this.checkConfig();
35
50
  const now = Date.now();
36
51
  // トークンが期限切れか未取得の場合は新しく取得
37
52
  if (!this.token || now >= this.tokenExpiry) {
@@ -41,6 +56,30 @@ class FirestoreClient {
41
56
  }
42
57
  return this.token;
43
58
  }
59
+ /**
60
+ * コレクションリファレンスを取得
61
+ * @param path コレクションパス
62
+ * @returns CollectionReferenceインスタンス
63
+ */
64
+ collection(path) {
65
+ // 設定チェックは実際の操作時に行われる
66
+ return new CollectionReference(this, path);
67
+ }
68
+ /**
69
+ * ドキュメントリファレンスを取得
70
+ * @param path ドキュメントパス
71
+ * @returns DocumentReferenceインスタンス
72
+ */
73
+ doc(path) {
74
+ // 設定チェックは実際の操作時に行われる
75
+ const parts = path.split("/");
76
+ if (parts.length % 2 === 0) {
77
+ throw new Error("Invalid document path. Document path must point to a document, not a collection.");
78
+ }
79
+ const collectionPath = parts.slice(0, parts.length - 1).join("/");
80
+ const docId = parts[parts.length - 1];
81
+ return new DocumentReference(this, collectionPath, docId);
82
+ }
44
83
  /**
45
84
  * Firestoreにドキュメントを作成
46
85
  * @param collectionName コレクション名
@@ -48,6 +87,8 @@ class FirestoreClient {
48
87
  * @returns 作成されたドキュメント
49
88
  */
50
89
  async create(collectionName, data) {
90
+ // 操作前に設定をチェック
91
+ this.checkConfig();
51
92
  const url = (0, path_1.getFirestoreBasePath)(this.config.projectId, collectionName);
52
93
  const firestoreData = (0, converter_1.convertToFirestoreDocument)(data);
53
94
  const token = await this.getToken();
@@ -72,6 +113,8 @@ class FirestoreClient {
72
113
  * @returns 取得したドキュメント(存在しない場合はnull)
73
114
  */
74
115
  async get(collectionName, documentId) {
116
+ // 操作前に設定をチェック
117
+ this.checkConfig();
75
118
  const url = `${(0, path_1.getFirestoreBasePath)(this.config.projectId, collectionName)}/${documentId}`;
76
119
  const token = await this.getToken();
77
120
  const response = await fetch(url, {
@@ -97,6 +140,8 @@ class FirestoreClient {
97
140
  * @returns 更新されたドキュメント
98
141
  */
99
142
  async update(collectionName, documentId, data) {
143
+ // 操作前に設定をチェック
144
+ this.checkConfig();
100
145
  const url = `${(0, path_1.getFirestoreBasePath)(this.config.projectId, collectionName)}/${documentId}`;
101
146
  const firestoreData = (0, converter_1.convertToFirestoreDocument)(data);
102
147
  const token = await this.getToken();
@@ -121,6 +166,8 @@ class FirestoreClient {
121
166
  * @returns 削除成功時はtrue
122
167
  */
123
168
  async delete(collectionName, documentId) {
169
+ // 操作前に設定をチェック
170
+ this.checkConfig();
124
171
  const url = `${(0, path_1.getFirestoreBasePath)(this.config.projectId, collectionName)}/${documentId}`;
125
172
  const token = await this.getToken();
126
173
  const response = await fetch(url, {
@@ -141,6 +188,8 @@ class FirestoreClient {
141
188
  * @returns 検索結果のドキュメント配列
142
189
  */
143
190
  async query(collectionName, options = {}) {
191
+ // 操作前に設定をチェック
192
+ this.checkConfig();
144
193
  const url = `${(0, path_1.getFirestoreBasePath)(this.config.projectId, collectionName)}:runQuery`;
145
194
  // クエリ構築
146
195
  const structuredQuery = {
@@ -166,7 +215,7 @@ class FirestoreClient {
166
215
  structuredQuery.orderBy = [
167
216
  {
168
217
  field: { fieldPath: options.orderBy },
169
- direction: "ASCENDING",
218
+ direction: options.orderDirection || "ASCENDING",
170
219
  },
171
220
  ];
172
221
  }
@@ -199,6 +248,416 @@ class FirestoreClient {
199
248
  }
200
249
  }
201
250
  exports.FirestoreClient = FirestoreClient;
251
+ /**
252
+ * コレクションリファレンスクラス
253
+ */
254
+ class CollectionReference {
255
+ constructor(client, path) {
256
+ this.client = client;
257
+ this.path = path;
258
+ this._queryConstraints = {
259
+ where: [],
260
+ };
261
+ }
262
+ /**
263
+ * ドキュメントリファレンスを取得
264
+ * @param documentPath ドキュメントID(省略時は自動生成)
265
+ * @returns DocumentReferenceインスタンス
266
+ */
267
+ doc(documentPath) {
268
+ const docId = documentPath || this._generateId();
269
+ return new DocumentReference(this.client, this.path, docId);
270
+ }
271
+ /**
272
+ * ドキュメントを追加(IDは自動生成)
273
+ * @param data ドキュメントデータ
274
+ * @returns 作成されたドキュメントのリファレンス
275
+ */
276
+ async add(data) {
277
+ const result = await this.client.create(this.path, data);
278
+ const docId = result.id;
279
+ return new DocumentReference(this.client, this.path, docId);
280
+ }
281
+ /**
282
+ * フィルター条件を追加
283
+ * @param fieldPath フィールドパス
284
+ * @param opStr 演算子
285
+ * @param value 値
286
+ * @returns Queryインスタンス
287
+ */
288
+ where(fieldPath, opStr, value) {
289
+ const query = new Query(this.client, this.path, {
290
+ ...this._queryConstraints,
291
+ });
292
+ // 演算子の変換
293
+ let firestoreOp;
294
+ switch (opStr) {
295
+ case "==":
296
+ firestoreOp = "EQUAL";
297
+ break;
298
+ case "!=":
299
+ firestoreOp = "NOT_EQUAL";
300
+ break;
301
+ case "<":
302
+ firestoreOp = "LESS_THAN";
303
+ break;
304
+ case "<=":
305
+ firestoreOp = "LESS_THAN_OR_EQUAL";
306
+ break;
307
+ case ">":
308
+ firestoreOp = "GREATER_THAN";
309
+ break;
310
+ case ">=":
311
+ firestoreOp = "GREATER_THAN_OR_EQUAL";
312
+ break;
313
+ case "array-contains":
314
+ firestoreOp = "ARRAY_CONTAINS";
315
+ break;
316
+ case "in":
317
+ firestoreOp = "IN";
318
+ break;
319
+ case "array-contains-any":
320
+ firestoreOp = "ARRAY_CONTAINS_ANY";
321
+ break;
322
+ case "not-in":
323
+ firestoreOp = "NOT_IN";
324
+ break;
325
+ default:
326
+ firestoreOp = opStr;
327
+ }
328
+ query._queryConstraints.where.push({
329
+ field: fieldPath,
330
+ op: firestoreOp,
331
+ value,
332
+ });
333
+ return query;
334
+ }
335
+ /**
336
+ * 並べ替え条件を追加
337
+ * @param fieldPath フィールドパス
338
+ * @param directionStr 並べ替え方向('asc'または'desc')
339
+ * @returns Queryインスタンス
340
+ */
341
+ orderBy(fieldPath, directionStr = "asc") {
342
+ const query = new Query(this.client, this.path, {
343
+ ...this._queryConstraints,
344
+ });
345
+ query._queryConstraints.orderBy = fieldPath;
346
+ query._queryConstraints.orderDirection =
347
+ directionStr === "asc" ? "ASCENDING" : "DESCENDING";
348
+ return query;
349
+ }
350
+ /**
351
+ * 取得件数の制限を設定
352
+ * @param limit 最大件数
353
+ * @returns Queryインスタンス
354
+ */
355
+ limit(limit) {
356
+ const query = new Query(this.client, this.path, {
357
+ ...this._queryConstraints,
358
+ });
359
+ query._queryConstraints.limit = limit;
360
+ return query;
361
+ }
362
+ /**
363
+ * スキップ件数を設定
364
+ * @param offset スキップ件数
365
+ * @returns Queryインスタンス
366
+ */
367
+ offset(offset) {
368
+ const query = new Query(this.client, this.path, {
369
+ ...this._queryConstraints,
370
+ });
371
+ query._queryConstraints.offset = offset;
372
+ return query;
373
+ }
374
+ /**
375
+ * クエリを実行
376
+ * @returns QuerySnapshotインスタンス
377
+ */
378
+ async get() {
379
+ const results = await this.client.query(this.path, this._queryConstraints);
380
+ return new QuerySnapshot(results);
381
+ }
382
+ /**
383
+ * ランダムなIDを生成
384
+ * @returns ランダムなID
385
+ */
386
+ _generateId() {
387
+ // 20文字のランダムなIDを生成
388
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
389
+ let id = "";
390
+ for (let i = 0; i < 20; i++) {
391
+ id += chars.charAt(Math.floor(Math.random() * chars.length));
392
+ }
393
+ return id;
394
+ }
395
+ }
396
+ exports.CollectionReference = CollectionReference;
397
+ /**
398
+ * ドキュメントリファレンスクラス
399
+ */
400
+ class DocumentReference {
401
+ constructor(client, collectionPath, docId) {
402
+ this.client = client;
403
+ this.collectionPath = collectionPath;
404
+ this.docId = docId;
405
+ }
406
+ /**
407
+ * ドキュメントIDを取得
408
+ */
409
+ get id() {
410
+ return this.docId;
411
+ }
412
+ /**
413
+ * ドキュメントのパスを取得
414
+ */
415
+ get path() {
416
+ return `${this.collectionPath}/${this.docId}`;
417
+ }
418
+ /**
419
+ * サブコレクションを取得
420
+ * @param collectionPath サブコレクション名
421
+ * @returns CollectionReferenceインスタンス
422
+ */
423
+ collection(collectionPath) {
424
+ return new CollectionReference(this.client, `${this.path}/${collectionPath}`);
425
+ }
426
+ /**
427
+ * ドキュメントを取得
428
+ * @returns DocumentSnapshotインスタンス
429
+ */
430
+ async get() {
431
+ const data = await this.client.get(this.collectionPath, this.docId);
432
+ return new DocumentSnapshot(this.docId, data);
433
+ }
434
+ /**
435
+ * ドキュメントを作成または上書き
436
+ * @param data ドキュメントデータ
437
+ * @param options オプション(mergeは現在サポートされていません)
438
+ * @returns WriteResultインスタンス
439
+ */
440
+ async set(data, options) {
441
+ // 既存のドキュメントを取得
442
+ const existingDoc = await this.client.get(this.collectionPath, this.docId);
443
+ if (existingDoc) {
444
+ // 既存のドキュメントがある場合は更新
445
+ const mergedData = options?.merge ? { ...existingDoc, ...data } : data;
446
+ await this.client.update(this.collectionPath, this.docId, mergedData);
447
+ }
448
+ else {
449
+ // 新規作成
450
+ const newData = { ...data, id: this.docId };
451
+ await this.client.create(this.collectionPath, newData);
452
+ }
453
+ return new WriteResult();
454
+ }
455
+ /**
456
+ * ドキュメントを更新
457
+ * @param data 更新データ
458
+ * @returns WriteResultインスタンス
459
+ */
460
+ async update(data) {
461
+ await this.client.update(this.collectionPath, this.docId, data);
462
+ return new WriteResult();
463
+ }
464
+ /**
465
+ * ドキュメントを削除
466
+ * @returns WriteResultインスタンス
467
+ */
468
+ async delete() {
469
+ await this.client.delete(this.collectionPath, this.docId);
470
+ return new WriteResult();
471
+ }
472
+ }
473
+ exports.DocumentReference = DocumentReference;
474
+ /**
475
+ * クエリクラス
476
+ */
477
+ class Query {
478
+ constructor(client, collectionPath, constraints) {
479
+ this.client = client;
480
+ this.collectionPath = collectionPath;
481
+ this._queryConstraints = constraints;
482
+ }
483
+ /**
484
+ * フィルター条件を追加
485
+ * @param fieldPath フィールドパス
486
+ * @param opStr 演算子
487
+ * @param value 値
488
+ * @returns Queryインスタンス
489
+ */
490
+ where(fieldPath, opStr, value) {
491
+ const query = new Query(this.client, this.collectionPath, {
492
+ ...this._queryConstraints,
493
+ });
494
+ // 演算子の変換
495
+ let firestoreOp;
496
+ switch (opStr) {
497
+ case "==":
498
+ firestoreOp = "EQUAL";
499
+ break;
500
+ case "!=":
501
+ firestoreOp = "NOT_EQUAL";
502
+ break;
503
+ case "<":
504
+ firestoreOp = "LESS_THAN";
505
+ break;
506
+ case "<=":
507
+ firestoreOp = "LESS_THAN_OR_EQUAL";
508
+ break;
509
+ case ">":
510
+ firestoreOp = "GREATER_THAN";
511
+ break;
512
+ case ">=":
513
+ firestoreOp = "GREATER_THAN_OR_EQUAL";
514
+ break;
515
+ case "array-contains":
516
+ firestoreOp = "ARRAY_CONTAINS";
517
+ break;
518
+ case "in":
519
+ firestoreOp = "IN";
520
+ break;
521
+ case "array-contains-any":
522
+ firestoreOp = "ARRAY_CONTAINS_ANY";
523
+ break;
524
+ case "not-in":
525
+ firestoreOp = "NOT_IN";
526
+ break;
527
+ default:
528
+ firestoreOp = opStr;
529
+ }
530
+ query._queryConstraints.where.push({
531
+ field: fieldPath,
532
+ op: firestoreOp,
533
+ value,
534
+ });
535
+ return query;
536
+ }
537
+ /**
538
+ * 並べ替え条件を追加
539
+ * @param fieldPath フィールドパス
540
+ * @param directionStr 並べ替え方向('asc'または'desc')
541
+ * @returns Queryインスタンス
542
+ */
543
+ orderBy(fieldPath, directionStr = "asc") {
544
+ const query = new Query(this.client, this.collectionPath, {
545
+ ...this._queryConstraints,
546
+ });
547
+ query._queryConstraints.orderBy = fieldPath;
548
+ query._queryConstraints.orderDirection =
549
+ directionStr === "asc" ? "ASCENDING" : "DESCENDING";
550
+ return query;
551
+ }
552
+ /**
553
+ * 取得件数の制限を設定
554
+ * @param limit 最大件数
555
+ * @returns Queryインスタンス
556
+ */
557
+ limit(limit) {
558
+ const query = new Query(this.client, this.collectionPath, {
559
+ ...this._queryConstraints,
560
+ });
561
+ query._queryConstraints.limit = limit;
562
+ return query;
563
+ }
564
+ /**
565
+ * スキップ件数を設定
566
+ * @param offset スキップ件数
567
+ * @returns Queryインスタンス
568
+ */
569
+ offset(offset) {
570
+ const query = new Query(this.client, this.collectionPath, {
571
+ ...this._queryConstraints,
572
+ });
573
+ query._queryConstraints.offset = offset;
574
+ return query;
575
+ }
576
+ /**
577
+ * クエリを実行
578
+ * @returns QuerySnapshotインスタンス
579
+ */
580
+ async get() {
581
+ const results = await this.client.query(this.collectionPath, this._queryConstraints);
582
+ return new QuerySnapshot(results);
583
+ }
584
+ }
585
+ exports.Query = Query;
586
+ /**
587
+ * クエリ結果クラス
588
+ */
589
+ class QuerySnapshot {
590
+ constructor(results) {
591
+ this._docs = results.map(doc => {
592
+ const { id, ...data } = doc;
593
+ return new DocumentSnapshot(id, data);
594
+ });
595
+ }
596
+ /**
597
+ * 結果のドキュメント配列
598
+ */
599
+ get docs() {
600
+ return this._docs;
601
+ }
602
+ /**
603
+ * 結果が空かどうか
604
+ */
605
+ get empty() {
606
+ return this._docs.length === 0;
607
+ }
608
+ /**
609
+ * 結果の件数
610
+ */
611
+ get size() {
612
+ return this._docs.length;
613
+ }
614
+ /**
615
+ * 各ドキュメントに対してコールバックを実行
616
+ * @param callback 各ドキュメントに対して実行するコールバック関数
617
+ */
618
+ forEach(callback) {
619
+ this._docs.forEach(callback);
620
+ }
621
+ }
622
+ exports.QuerySnapshot = QuerySnapshot;
623
+ /**
624
+ * ドキュメントスナップショットクラス
625
+ */
626
+ class DocumentSnapshot {
627
+ constructor(id, data) {
628
+ this._id = id;
629
+ this._data = data;
630
+ }
631
+ /**
632
+ * ドキュメントID
633
+ */
634
+ get id() {
635
+ return this._id;
636
+ }
637
+ /**
638
+ * ドキュメントが存在するかどうか
639
+ */
640
+ get exists() {
641
+ return this._data !== null;
642
+ }
643
+ /**
644
+ * ドキュメントデータを取得
645
+ * @returns ドキュメントデータ(存在しない場合はundefined)
646
+ */
647
+ data() {
648
+ return this._data || undefined;
649
+ }
650
+ }
651
+ exports.DocumentSnapshot = DocumentSnapshot;
652
+ /**
653
+ * 書き込み結果クラス
654
+ */
655
+ class WriteResult {
656
+ constructor() {
657
+ this.writeTime = new Date();
658
+ }
659
+ }
660
+ exports.WriteResult = WriteResult;
202
661
  /**
203
662
  * 新しいFirestoreクライアントインスタンスを作成
204
663
  * @param config Firestore設定オブジェクト
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export * from "./types";
2
- import { FirestoreClient, createFirestoreClient } from "./client";
2
+ import { FirestoreClient, createFirestoreClient, CollectionReference, DocumentReference, Query, QuerySnapshot, DocumentSnapshot, WriteResult } from "./client";
3
3
  export { getFirestoreToken } from "./utils/auth";
4
4
  export { convertToFirestoreValue, convertFromFirestoreValue, convertToFirestoreDocument, convertFromFirestoreDocument, } from "./utils/converter";
5
5
  export { getFirestoreBasePath, getDocumentId } from "./utils/path";
6
- export { FirestoreClient, createFirestoreClient };
6
+ export { FirestoreClient, createFirestoreClient, CollectionReference, DocumentReference, Query, QuerySnapshot, DocumentSnapshot, WriteResult, };
package/dist/index.js CHANGED
@@ -14,13 +14,19 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.createFirestoreClient = exports.FirestoreClient = exports.getDocumentId = exports.getFirestoreBasePath = exports.convertFromFirestoreDocument = exports.convertToFirestoreDocument = exports.convertFromFirestoreValue = exports.convertToFirestoreValue = exports.getFirestoreToken = void 0;
17
+ exports.WriteResult = exports.DocumentSnapshot = exports.QuerySnapshot = exports.Query = exports.DocumentReference = exports.CollectionReference = exports.createFirestoreClient = exports.FirestoreClient = exports.getDocumentId = exports.getFirestoreBasePath = exports.convertFromFirestoreDocument = exports.convertToFirestoreDocument = exports.convertFromFirestoreValue = exports.convertToFirestoreValue = exports.getFirestoreToken = void 0;
18
18
  // 型定義のエクスポート
19
19
  __exportStar(require("./types"), exports);
20
20
  // クライアントのエクスポート
21
21
  const client_1 = require("./client");
22
22
  Object.defineProperty(exports, "FirestoreClient", { enumerable: true, get: function () { return client_1.FirestoreClient; } });
23
23
  Object.defineProperty(exports, "createFirestoreClient", { enumerable: true, get: function () { return client_1.createFirestoreClient; } });
24
+ Object.defineProperty(exports, "CollectionReference", { enumerable: true, get: function () { return client_1.CollectionReference; } });
25
+ Object.defineProperty(exports, "DocumentReference", { enumerable: true, get: function () { return client_1.DocumentReference; } });
26
+ Object.defineProperty(exports, "Query", { enumerable: true, get: function () { return client_1.Query; } });
27
+ Object.defineProperty(exports, "QuerySnapshot", { enumerable: true, get: function () { return client_1.QuerySnapshot; } });
28
+ Object.defineProperty(exports, "DocumentSnapshot", { enumerable: true, get: function () { return client_1.DocumentSnapshot; } });
29
+ Object.defineProperty(exports, "WriteResult", { enumerable: true, get: function () { return client_1.WriteResult; } });
24
30
  // ユーティリティ関数のエクスポート
25
31
  var auth_1 = require("./utils/auth");
26
32
  Object.defineProperty(exports, "getFirestoreToken", { enumerable: true, get: function () { return auth_1.getFirestoreToken; } });
package/dist/types.d.ts CHANGED
@@ -58,6 +58,7 @@ export interface QueryOptions {
58
58
  value: any;
59
59
  }>;
60
60
  orderBy?: string;
61
+ orderDirection?: string;
61
62
  limit?: number;
62
63
  offset?: number;
63
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-rest-firestore",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Firebase Firestore REST API client for Edge runtime environments",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",