@cougargrades/firebase-rest-firestore 1.6.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/README.ja.md +294 -0
- package/README.md +393 -0
- package/dist/cjs/client.d.ts +417 -0
- package/dist/cjs/client.js +1078 -0
- package/dist/cjs/index.d.ts +7 -0
- package/dist/cjs/index.js +43 -0
- package/dist/cjs/types.d.ts +127 -0
- package/dist/cjs/types.js +86 -0
- package/dist/cjs/utils/auth.d.ts +13 -0
- package/dist/cjs/utils/auth.js +94 -0
- package/dist/cjs/utils/config.d.ts +6 -0
- package/dist/cjs/utils/config.js +14 -0
- package/dist/cjs/utils/converter.d.ts +27 -0
- package/dist/cjs/utils/converter.js +132 -0
- 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 +127 -0
- package/dist/esm/types.js +81 -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 +126 -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 +127 -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 +65 -0
package/README.ja.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# Firebase REST Firestore
|
|
2
|
+
|
|
3
|
+
Firebase Firestore REST API クライアント - Cloudflare Workers や Vercel Edge Functions などのエッジランタイム環境向け。
|
|
4
|
+
|
|
5
|
+
## 特徴
|
|
6
|
+
|
|
7
|
+
- Firebase Admin SDK が利用できないエッジランタイム環境で動作
|
|
8
|
+
- 完全な CRUD 操作のサポート
|
|
9
|
+
- TypeScript サポート
|
|
10
|
+
- パフォーマンス向上のためのトークンキャッシング
|
|
11
|
+
- シンプルで直感的な API
|
|
12
|
+
- 環境変数への暗黙的な依存がない明示的な設定
|
|
13
|
+
|
|
14
|
+
## インストール
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install firebase-rest-firestore
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 使用方法
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { initializeFirestore } from "firebase-rest-firestore";
|
|
24
|
+
|
|
25
|
+
// SDK互換クライアントを初期化
|
|
26
|
+
const db = initializeFirestore({
|
|
27
|
+
projectId: "your-project-id",
|
|
28
|
+
privateKey: "your-private-key",
|
|
29
|
+
clientEmail: "your-client-email",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// コレクションリファレンスの取得
|
|
33
|
+
const gamesRef = db.collection("games");
|
|
34
|
+
|
|
35
|
+
// ドキュメントの追加
|
|
36
|
+
const gameRef = await gamesRef.add({
|
|
37
|
+
name: "New Game",
|
|
38
|
+
createdAt: new Date(),
|
|
39
|
+
score: 100,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// ドキュメントの取得
|
|
43
|
+
const gameSnapshot = await gameRef.get();
|
|
44
|
+
console.log(gameSnapshot.data());
|
|
45
|
+
|
|
46
|
+
// ドキュメントの更新
|
|
47
|
+
await gameRef.update({
|
|
48
|
+
score: 200,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// ドキュメントの削除
|
|
52
|
+
await gameRef.delete();
|
|
53
|
+
|
|
54
|
+
// クエリの実行
|
|
55
|
+
const highScoreGames = await gamesRef
|
|
56
|
+
.where("score", ">", 150)
|
|
57
|
+
.where("createdAt", "<", new Date())
|
|
58
|
+
.get();
|
|
59
|
+
|
|
60
|
+
highScoreGames.forEach(doc => {
|
|
61
|
+
console.log(doc.id, "=>", doc.data());
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## API リファレンス
|
|
66
|
+
|
|
67
|
+
### createFirestoreClient(config)
|
|
68
|
+
|
|
69
|
+
Firestore クライアントを作成します。
|
|
70
|
+
|
|
71
|
+
#### パラメータ
|
|
72
|
+
|
|
73
|
+
- `config` (object): クライアント設定
|
|
74
|
+
- `projectId` (string): Firebase プロジェクト ID
|
|
75
|
+
- `privateKey` (string): サービスアカウントの秘密鍵
|
|
76
|
+
- `clientEmail` (string): サービスアカウントのメールアドレス
|
|
77
|
+
|
|
78
|
+
#### 戻り値
|
|
79
|
+
|
|
80
|
+
以下のメソッドを持つ Firestore クライアントオブジェクト:
|
|
81
|
+
|
|
82
|
+
### collection(collectionPath).add(data)
|
|
83
|
+
|
|
84
|
+
コレクション内に自動生成された ID を持つ新しいドキュメントを作成します。
|
|
85
|
+
|
|
86
|
+
#### パラメータ
|
|
87
|
+
|
|
88
|
+
- `data` (object): ドキュメントデータ
|
|
89
|
+
|
|
90
|
+
#### 戻り値
|
|
91
|
+
|
|
92
|
+
作成されたドキュメントへの参照。
|
|
93
|
+
|
|
94
|
+
### collection(collectionPath).doc(id?).set(data)
|
|
95
|
+
|
|
96
|
+
指定された ID でドキュメントを作成または上書きします。ID が指定されていない場合は自動的に生成されます。
|
|
97
|
+
|
|
98
|
+
#### パラメータ
|
|
99
|
+
|
|
100
|
+
- `id` (string, オプション): ドキュメントの ID
|
|
101
|
+
- `data` (object): ドキュメントデータ
|
|
102
|
+
|
|
103
|
+
#### 戻り値
|
|
104
|
+
|
|
105
|
+
プロミス(作成または上書き操作の完了時に解決)。
|
|
106
|
+
|
|
107
|
+
### client.get(collection, id)
|
|
108
|
+
|
|
109
|
+
ドキュメントを取得します。
|
|
110
|
+
|
|
111
|
+
#### パラメータ
|
|
112
|
+
|
|
113
|
+
- `collection` (string): ドキュメントが属するコレクション名
|
|
114
|
+
- `id` (string): 取得するドキュメントの ID
|
|
115
|
+
|
|
116
|
+
#### 戻り値
|
|
117
|
+
|
|
118
|
+
ドキュメントデータを含むオブジェクト。ドキュメントが存在しない場合は null。
|
|
119
|
+
|
|
120
|
+
### client.update(collection, id, data)
|
|
121
|
+
|
|
122
|
+
既存のドキュメントを更新します。
|
|
123
|
+
|
|
124
|
+
#### パラメータ
|
|
125
|
+
|
|
126
|
+
- `collection` (string): ドキュメントが属するコレクション名
|
|
127
|
+
- `id` (string): 更新するドキュメントの ID
|
|
128
|
+
- `data` (object): 更新するフィールドを含むオブジェクト
|
|
129
|
+
|
|
130
|
+
#### 戻り値
|
|
131
|
+
|
|
132
|
+
更新されたドキュメントを表すオブジェクト。
|
|
133
|
+
|
|
134
|
+
### client.delete(collection, id)
|
|
135
|
+
|
|
136
|
+
ドキュメントを削除します。
|
|
137
|
+
|
|
138
|
+
#### パラメータ
|
|
139
|
+
|
|
140
|
+
- `collection` (string): ドキュメントが属するコレクション名
|
|
141
|
+
- `id` (string): 削除するドキュメントの ID
|
|
142
|
+
|
|
143
|
+
#### 戻り値
|
|
144
|
+
|
|
145
|
+
成功した場合は true。
|
|
146
|
+
|
|
147
|
+
### client.query(collection, filters, options?)
|
|
148
|
+
|
|
149
|
+
コレクションに対してクエリを実行します。
|
|
150
|
+
|
|
151
|
+
#### パラメータ
|
|
152
|
+
|
|
153
|
+
- `collection` (string): クエリするコレクション名
|
|
154
|
+
- `filters` (array): 各フィルタは[フィールド, 演算子, 値]の形式の配列
|
|
155
|
+
- `options` (object, オプション):
|
|
156
|
+
- `orderBy` (array, オプション): 並べ替えの指定(例:[['score', 'desc'], ['createdAt', 'asc']])
|
|
157
|
+
- `limit` (number, オプション): 結果の最大数
|
|
158
|
+
- `offset` (number, オプション): スキップする結果の数
|
|
159
|
+
- `startAt` (any, オプション): この値から始まるドキュメントを返す
|
|
160
|
+
- `startAfter` (any, オプション): この値の後に始まるドキュメントを返す
|
|
161
|
+
- `endAt` (any, オプション): この値で終わるドキュメントを返す
|
|
162
|
+
- `endBefore` (any, オプション): この値の前に終わるドキュメントを返す
|
|
163
|
+
|
|
164
|
+
#### 戻り値
|
|
165
|
+
|
|
166
|
+
クエリ条件に一致するドキュメントの配列。
|
|
167
|
+
|
|
168
|
+
## Next.js 環境での設定
|
|
169
|
+
|
|
170
|
+
Next.js アプリでは、サーバーサイドでのみ実行されるように設定してください:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// Initialize in a server component or API route
|
|
174
|
+
import { createFirestoreClient } from "firebase-rest-firestore";
|
|
175
|
+
|
|
176
|
+
export async function getServerSideProps() {
|
|
177
|
+
// Server-side only code
|
|
178
|
+
const firestore = createFirestoreClient({
|
|
179
|
+
projectId: process.env.FIREBASE_PROJECT_ID,
|
|
180
|
+
privateKey: process.env.FIREBASE_PRIVATE_KEY,
|
|
181
|
+
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const data = await firestore.query("collection", [
|
|
185
|
+
/* your filters */
|
|
186
|
+
]);
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
props: {
|
|
190
|
+
data: JSON.parse(JSON.stringify(data)),
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Cloudflare Workers 環境での使用
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { createFirestoreClient } from "firebase-rest-firestore";
|
|
200
|
+
|
|
201
|
+
export default {
|
|
202
|
+
async fetch(request, env) {
|
|
203
|
+
const firestore = createFirestoreClient({
|
|
204
|
+
projectId: env.FIREBASE_PROJECT_ID,
|
|
205
|
+
privateKey: env.FIREBASE_PRIVATE_KEY,
|
|
206
|
+
clientEmail: env.FIREBASE_CLIENT_EMAIL,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// APIロジックの実装...
|
|
210
|
+
const data = await firestore.query("collection", [
|
|
211
|
+
/* your filters */
|
|
212
|
+
]);
|
|
213
|
+
|
|
214
|
+
return new Response(JSON.stringify(data), {
|
|
215
|
+
headers: { "Content-Type": "application/json" },
|
|
216
|
+
});
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## クイックスタート
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
import { createFirestoreClient } from "firebase-rest-firestore";
|
|
225
|
+
|
|
226
|
+
// 設定オブジェクトでクライアントを初期化
|
|
227
|
+
const firestore = createFirestoreClient({
|
|
228
|
+
projectId: "your-project-id",
|
|
229
|
+
privateKey: "your-private-key",
|
|
230
|
+
clientEmail: "your-client-email",
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// ドキュメントの追加
|
|
234
|
+
const newDoc = await firestore.add("collection", {
|
|
235
|
+
name: "テストドキュメント",
|
|
236
|
+
value: 100,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// ドキュメントの取得
|
|
240
|
+
const doc = await firestore.get("collection", newDoc.id);
|
|
241
|
+
|
|
242
|
+
// ドキュメントの更新
|
|
243
|
+
await firestore.update("collection", newDoc.id, { value: 200 });
|
|
244
|
+
|
|
245
|
+
// ドキュメントのクエリ
|
|
246
|
+
const querySnapshot = await firestore
|
|
247
|
+
.collection("games")
|
|
248
|
+
.where("score", ">", 50)
|
|
249
|
+
.where("active", "==", true)
|
|
250
|
+
.orderBy("score", "desc")
|
|
251
|
+
.limit(10)
|
|
252
|
+
.get();
|
|
253
|
+
|
|
254
|
+
const games = [];
|
|
255
|
+
querySnapshot.forEach(doc => {
|
|
256
|
+
games.push({
|
|
257
|
+
id: doc.id,
|
|
258
|
+
...doc.data(),
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
console.log("Games with score > 50:", games);
|
|
262
|
+
|
|
263
|
+
// ドキュメントの削除
|
|
264
|
+
await firestore.delete("collection", newDoc.id);
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## 設定
|
|
268
|
+
|
|
269
|
+
Firestore の権限を持つ Firebase サービスアカウントが必要です:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
createFirestoreClient({
|
|
273
|
+
projectId: "your-project-id",
|
|
274
|
+
privateKey: "your-private-key", // エスケープされた改行(\\n)を含む場合、自動的にフォーマットされます
|
|
275
|
+
clientEmail: "your-client-email",
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## API リファレンス
|
|
280
|
+
|
|
281
|
+
### add(collectionName, data)
|
|
282
|
+
|
|
283
|
+
コレクションに新しいドキュメントを追加します。
|
|
284
|
+
|
|
285
|
+
パラメータ:
|
|
286
|
+
|
|
287
|
+
- `collectionName`: コレクション名
|
|
288
|
+
- `data`: 追加するドキュメントデータ
|
|
289
|
+
|
|
290
|
+
戻り値: 自動生成された ID を持つ追加されたドキュメント。
|
|
291
|
+
|
|
292
|
+
## ライセンス
|
|
293
|
+
|
|
294
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# Firebase REST Firestore
|
|
2
|
+
|
|
3
|
+
[日本語版はこちら(Japanese Version)](./README.ja.md)
|
|
4
|
+
|
|
5
|
+
Firebase Firestore REST API client for Edge runtime environments like Cloudflare Workers and Vercel Edge Functions.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Works in Edge runtime environments where Firebase Admin SDK is not available
|
|
10
|
+
- Full CRUD operations support
|
|
11
|
+
- TypeScript support
|
|
12
|
+
- Token caching for better performance
|
|
13
|
+
- Simple and intuitive API
|
|
14
|
+
- Explicit configuration without hidden environment variable dependencies
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install firebase-rest-firestore
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { createFirestoreClient } from "firebase-rest-firestore";
|
|
26
|
+
|
|
27
|
+
// Create a client with your configuration
|
|
28
|
+
const firestore = createFirestoreClient({
|
|
29
|
+
projectId: "your-project-id",
|
|
30
|
+
privateKey: "your-private-key",
|
|
31
|
+
clientEmail: "your-client-email",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Add a document
|
|
35
|
+
const newDoc = await firestore.add("collection", {
|
|
36
|
+
name: "Test Document",
|
|
37
|
+
value: 100,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Get a document
|
|
41
|
+
const doc = await firestore.get("collection", newDoc.id);
|
|
42
|
+
|
|
43
|
+
// Update a document
|
|
44
|
+
await firestore.update("collection", newDoc.id, { value: 200 });
|
|
45
|
+
|
|
46
|
+
// Query documents
|
|
47
|
+
const querySnapshot = await firestore
|
|
48
|
+
.collection("games")
|
|
49
|
+
.where("score", ">", 50)
|
|
50
|
+
.where("active", "==", true)
|
|
51
|
+
.orderBy("score", "desc")
|
|
52
|
+
.limit(10)
|
|
53
|
+
.get();
|
|
54
|
+
|
|
55
|
+
// Process query results
|
|
56
|
+
const games = [];
|
|
57
|
+
querySnapshot.forEach(doc => {
|
|
58
|
+
games.push({
|
|
59
|
+
id: doc.id,
|
|
60
|
+
...doc.data(),
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
console.log("Games with score > 50:", games);
|
|
64
|
+
|
|
65
|
+
// Delete a document
|
|
66
|
+
await firestore.delete("collection", newDoc.id);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
The `FirestoreConfig` object requires the following properties:
|
|
72
|
+
|
|
73
|
+
| Property | Description |
|
|
74
|
+
| ----------- | ---------------------------- |
|
|
75
|
+
| projectId | Firebase project ID |
|
|
76
|
+
| privateKey | Service account private key |
|
|
77
|
+
| clientEmail | Service account client email |
|
|
78
|
+
|
|
79
|
+
## API Reference
|
|
80
|
+
|
|
81
|
+
### FirestoreClient
|
|
82
|
+
|
|
83
|
+
The main class for interacting with Firestore.
|
|
84
|
+
|
|
85
|
+
#### collection(collectionPath).add(data)
|
|
86
|
+
|
|
87
|
+
Creates a new document with an auto-generated ID in the specified collection.
|
|
88
|
+
|
|
89
|
+
Parameters:
|
|
90
|
+
|
|
91
|
+
- `data`: Document data to be added
|
|
92
|
+
|
|
93
|
+
Returns: A reference to the created document.
|
|
94
|
+
|
|
95
|
+
#### collection(collectionPath).doc(id?).set(data)
|
|
96
|
+
|
|
97
|
+
Creates or overwrites a document with the specified ID. If no ID is provided, one will be auto-generated.
|
|
98
|
+
|
|
99
|
+
Parameters:
|
|
100
|
+
|
|
101
|
+
- `id` (optional): Document ID
|
|
102
|
+
- `data`: Document data
|
|
103
|
+
|
|
104
|
+
Returns: A promise that resolves when the set operation is complete.
|
|
105
|
+
|
|
106
|
+
#### get(collectionName, documentId)
|
|
107
|
+
|
|
108
|
+
Retrieves a document by ID.
|
|
109
|
+
|
|
110
|
+
#### update(collectionName, documentId, data)
|
|
111
|
+
|
|
112
|
+
Updates an existing document.
|
|
113
|
+
|
|
114
|
+
#### delete(collectionName, documentId)
|
|
115
|
+
|
|
116
|
+
Deletes a document.
|
|
117
|
+
|
|
118
|
+
#### query(collectionName, options)
|
|
119
|
+
|
|
120
|
+
Queries documents in a collection with filtering, ordering, and pagination.
|
|
121
|
+
|
|
122
|
+
### createFirestoreClient(config)
|
|
123
|
+
|
|
124
|
+
Creates a new FirestoreClient instance with the provided configuration.
|
|
125
|
+
|
|
126
|
+
#### add(collectionName, data)
|
|
127
|
+
|
|
128
|
+
Adds a new document to the specified collection.
|
|
129
|
+
|
|
130
|
+
Parameters:
|
|
131
|
+
|
|
132
|
+
- `collectionName`: Name of the collection
|
|
133
|
+
- `data`: Document data to be added
|
|
134
|
+
|
|
135
|
+
Returns: The added document with auto-generated ID.
|
|
136
|
+
|
|
137
|
+
## Error Handling
|
|
138
|
+
|
|
139
|
+
Firebase REST Firestore throws exceptions with appropriate error messages when API requests fail. Here's an example of error handling:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
try {
|
|
143
|
+
// Try to get a document
|
|
144
|
+
const game = await firestore.get("games", "non-existent-id");
|
|
145
|
+
|
|
146
|
+
// If document doesn't exist, null is returned
|
|
147
|
+
if (game === null) {
|
|
148
|
+
console.log("Document not found");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Process document if it exists
|
|
153
|
+
console.log("Fetched game:", game);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
// Handle API errors (authentication, network, etc.)
|
|
156
|
+
console.error("Firestore error:", error.message);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Common error cases:
|
|
161
|
+
|
|
162
|
+
- Authentication errors (invalid credentials)
|
|
163
|
+
- Network errors
|
|
164
|
+
- Invalid query parameters
|
|
165
|
+
- Firestore rate limits
|
|
166
|
+
|
|
167
|
+
## Query Options Details
|
|
168
|
+
|
|
169
|
+
The `query` method supports the following options for filtering, sorting, and paginating Firestore documents:
|
|
170
|
+
|
|
171
|
+
### where
|
|
172
|
+
|
|
173
|
+
Specify multiple filter conditions. Each condition is an object with the following properties:
|
|
174
|
+
|
|
175
|
+
- `field`: The field name to filter on
|
|
176
|
+
- `op`: The comparison operator. Available values:
|
|
177
|
+
- `EQUAL`: Equal to
|
|
178
|
+
- `NOT_EQUAL`: Not equal to
|
|
179
|
+
- `LESS_THAN`: Less than
|
|
180
|
+
- `LESS_THAN_OR_EQUAL`: Less than or equal to
|
|
181
|
+
- `GREATER_THAN`: Greater than
|
|
182
|
+
- `GREATER_THAN_OR_EQUAL`: Greater than or equal to
|
|
183
|
+
- `ARRAY_CONTAINS`: Array contains
|
|
184
|
+
- `IN`: Equal to any of the specified values
|
|
185
|
+
- `ARRAY_CONTAINS_ANY`: Array contains any of the specified values
|
|
186
|
+
- `NOT_IN`: Not equal to any of the specified values
|
|
187
|
+
- `value`: The value to compare against
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// Query games with score > 50 and active = true
|
|
191
|
+
const games = await firestore.query("games", {
|
|
192
|
+
where: [
|
|
193
|
+
{ field: "score", op: "GREATER_THAN", value: 50 },
|
|
194
|
+
{ field: "active", op: "EQUAL", value: true },
|
|
195
|
+
],
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### orderBy
|
|
200
|
+
|
|
201
|
+
Specifies the field name to sort results by. Results are sorted in ascending order by default.
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
// Sort by creation time
|
|
205
|
+
const games = await firestore.query("games", {
|
|
206
|
+
orderBy: "createdAt",
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### limit
|
|
211
|
+
|
|
212
|
+
Limits the maximum number of results returned.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
// Get at most 10 documents
|
|
216
|
+
const games = await firestore.query("games", {
|
|
217
|
+
limit: 10,
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### offset
|
|
222
|
+
|
|
223
|
+
Specifies the number of results to skip. Useful for pagination.
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
// Skip the first 20 results and get the next 10
|
|
227
|
+
const games = await firestore.query("games", {
|
|
228
|
+
offset: 20,
|
|
229
|
+
limit: 10,
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Example of a compound query:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
// Get top 10 active games by score
|
|
237
|
+
const topGames = await firestore.query("games", {
|
|
238
|
+
where: [{ field: "active", op: "EQUAL", value: true }],
|
|
239
|
+
orderBy: "score", // Sort by score
|
|
240
|
+
limit: 10,
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Edge Runtime Examples
|
|
245
|
+
|
|
246
|
+
### Cloudflare Workers
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
// Set these environment variables in wrangler.toml
|
|
250
|
+
// FIREBASE_PROJECT_ID
|
|
251
|
+
// FIREBASE_PRIVATE_KEY
|
|
252
|
+
// FIREBASE_CLIENT_EMAIL
|
|
253
|
+
|
|
254
|
+
import { createFirestoreClient } from "firebase-rest-firestore";
|
|
255
|
+
|
|
256
|
+
export default {
|
|
257
|
+
async fetch(request, env, ctx) {
|
|
258
|
+
// Load configuration from environment variables
|
|
259
|
+
const firestore = createFirestoreClient({
|
|
260
|
+
projectId: env.FIREBASE_PROJECT_ID,
|
|
261
|
+
privateKey: env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, "\n"),
|
|
262
|
+
clientEmail: env.FIREBASE_CLIENT_EMAIL,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const url = new URL(request.url);
|
|
266
|
+
const path = url.pathname;
|
|
267
|
+
|
|
268
|
+
// Example API endpoint
|
|
269
|
+
if (path === "/api/games" && request.method === "GET") {
|
|
270
|
+
try {
|
|
271
|
+
// Get active games
|
|
272
|
+
const games = await firestore.query("games", {
|
|
273
|
+
where: [{ field: "active", op: "EQUAL", value: true }],
|
|
274
|
+
limit: 10,
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
return new Response(JSON.stringify(games), {
|
|
278
|
+
headers: { "Content-Type": "application/json" },
|
|
279
|
+
});
|
|
280
|
+
} catch (error) {
|
|
281
|
+
return new Response(JSON.stringify({ error: error.message }), {
|
|
282
|
+
status: 500,
|
|
283
|
+
headers: { "Content-Type": "application/json" },
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return new Response("Not found", { status: 404 });
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Vercel Edge Functions
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
// Set these environment variables in .env.local
|
|
297
|
+
// FIREBASE_PROJECT_ID
|
|
298
|
+
// FIREBASE_PRIVATE_KEY
|
|
299
|
+
// FIREBASE_CLIENT_EMAIL
|
|
300
|
+
|
|
301
|
+
import { createFirestoreClient } from "firebase-rest-firestore";
|
|
302
|
+
|
|
303
|
+
export const config = {
|
|
304
|
+
runtime: "edge",
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
export default async function handler(request) {
|
|
308
|
+
// Load configuration from environment variables
|
|
309
|
+
const firestore = createFirestoreClient({
|
|
310
|
+
projectId: process.env.FIREBASE_PROJECT_ID,
|
|
311
|
+
privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, "\n"),
|
|
312
|
+
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
// Get the latest 10 documents
|
|
317
|
+
const documents = await firestore.query("posts", {
|
|
318
|
+
orderBy: "createdAt",
|
|
319
|
+
limit: 10,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
return new Response(JSON.stringify(documents), {
|
|
323
|
+
headers: { "Content-Type": "application/json" },
|
|
324
|
+
});
|
|
325
|
+
} catch (error) {
|
|
326
|
+
return new Response(JSON.stringify({ error: error.message }), {
|
|
327
|
+
status: 500,
|
|
328
|
+
headers: { "Content-Type": "application/json" },
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Performance Considerations
|
|
335
|
+
|
|
336
|
+
### Token Caching
|
|
337
|
+
|
|
338
|
+
Firebase REST Firestore caches JWT tokens to improve performance. By default, tokens are cached for 50 minutes (actual token expiry is 1 hour). This eliminates the need to generate a new token for each request, improving API request speed.
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
// Tokens are cached internally, so multiple requests
|
|
342
|
+
// have minimal authentication overhead
|
|
343
|
+
const doc1 = await firestore.get("collection", "doc1");
|
|
344
|
+
const doc2 = await firestore.get("collection", "doc2");
|
|
345
|
+
const doc3 = await firestore.get("collection", "doc3");
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Query Optimization
|
|
349
|
+
|
|
350
|
+
When dealing with large amounts of data, consider the following:
|
|
351
|
+
|
|
352
|
+
1. **Set appropriate limits**: Always use the `limit` parameter to restrict the number of documents returned.
|
|
353
|
+
|
|
354
|
+
2. **Query only needed fields**: Future versions will add support for retrieving only specific fields.
|
|
355
|
+
|
|
356
|
+
3. **Create indexes**: For complex queries, create appropriate indexes in the Firebase console.
|
|
357
|
+
|
|
358
|
+
4. **Use pagination**: When retrieving large datasets, implement pagination using `offset` and `limit`.
|
|
359
|
+
|
|
360
|
+
### Edge Environment Considerations
|
|
361
|
+
|
|
362
|
+
In edge environments, be aware of:
|
|
363
|
+
|
|
364
|
+
1. **Cold starts**: Initial execution has token generation overhead.
|
|
365
|
+
|
|
366
|
+
2. **Memory usage**: Be mindful of memory limits when processing large amounts of data.
|
|
367
|
+
|
|
368
|
+
3. **Timeouts**: Long-running queries may hit edge environment timeout limits.
|
|
369
|
+
|
|
370
|
+
## Limitations and Roadmap
|
|
371
|
+
|
|
372
|
+
### Current Limitations
|
|
373
|
+
|
|
374
|
+
- **Batch operations**: The current version does not support batch processing for operating on multiple documents at once.
|
|
375
|
+
- **Transactions**: Atomic transaction operations are not supported.
|
|
376
|
+
- **Real-time listeners**: Due to the nature of REST APIs, real-time data synchronization is not supported.
|
|
377
|
+
- **Subcollections**: The current version has limited direct support for nested subcollections.
|
|
378
|
+
|
|
379
|
+
### Future Roadmap
|
|
380
|
+
|
|
381
|
+
The following features are planned for future versions:
|
|
382
|
+
|
|
383
|
+
- Batch operations support
|
|
384
|
+
- Basic transaction support
|
|
385
|
+
- Improved subcollection support
|
|
386
|
+
- More detailed query options (compound indexes, etc.)
|
|
387
|
+
- Performance optimizations
|
|
388
|
+
|
|
389
|
+
Please report feature requests and bugs via GitHub Issues.
|
|
390
|
+
|
|
391
|
+
## License
|
|
392
|
+
|
|
393
|
+
MIT
|