firebase-tools 14.4.0 → 14.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.
Files changed (62) hide show
  1. package/lib/apphosting/backend.js +2 -0
  2. package/lib/bin/mcp.js +1 -0
  3. package/lib/commands/init.js +0 -3
  4. package/lib/config.js +42 -24
  5. package/lib/dataconnect/cloudAICompanionClient.js +7 -2
  6. package/lib/dataconnect/cloudAICompanionTypes.js +2 -0
  7. package/lib/dataconnect/fileUtils.js +11 -4
  8. package/lib/dataconnect/schemaMigration.js +6 -7
  9. package/lib/deploy/apphosting/deploy.js +3 -0
  10. package/lib/deploy/apphosting/prepare.js +34 -28
  11. package/lib/deploy/apphosting/release.js +3 -0
  12. package/lib/deploy/firestore/deploy.js +47 -4
  13. package/lib/emulator/apphosting/serve.js +1 -1
  14. package/lib/emulator/downloadableEmulatorInfo.json +39 -18
  15. package/lib/emulator/downloadableEmulators.js +15 -59
  16. package/lib/extensions/manifest.js +0 -3
  17. package/lib/frameworks/angular/index.js +1 -1
  18. package/lib/frameworks/angular/utils.js +17 -6
  19. package/lib/gcp/apphosting.js +13 -1
  20. package/lib/gcp/run.js +19 -1
  21. package/lib/init/features/apphosting.js +3 -2
  22. package/lib/init/features/database.js +11 -19
  23. package/lib/init/features/dataconnect/index.js +27 -26
  24. package/lib/init/features/dataconnect/sdk.js +19 -6
  25. package/lib/init/features/emulators.js +4 -3
  26. package/lib/init/features/firestore/index.js +44 -34
  27. package/lib/init/features/firestore/indexes.js +12 -13
  28. package/lib/init/features/firestore/rules.js +8 -15
  29. package/lib/init/features/genkit/index.js +16 -9
  30. package/lib/init/features/hosting/index.js +9 -8
  31. package/lib/init/features/index.js +3 -2
  32. package/lib/init/features/storage.js +31 -8
  33. package/lib/init/index.js +5 -1
  34. package/lib/mcp/index.js +10 -6
  35. package/lib/mcp/tool.js +2 -1
  36. package/lib/mcp/tools/apphosting/fetch_logs.js +69 -0
  37. package/lib/mcp/tools/apphosting/index.js +6 -0
  38. package/lib/mcp/tools/apphosting/list_backends.js +51 -0
  39. package/lib/mcp/tools/core/index.js +2 -0
  40. package/lib/mcp/tools/core/init.js +26 -2
  41. package/lib/mcp/tools/core/list_apps.js +10 -5
  42. package/lib/mcp/tools/core/list_projects.js +45 -0
  43. package/lib/mcp/tools/dataconnect/generate_operation.js +1 -1
  44. package/lib/mcp/tools/firestore/query_collection.js +13 -7
  45. package/lib/mcp/tools/index.js +2 -0
  46. package/lib/mcp/tools/storage/get_download_url.js +1 -1
  47. package/lib/mcp/types.js +1 -0
  48. package/lib/mcp/util.js +137 -1
  49. package/lib/mcp/util.test.js +468 -0
  50. package/lib/prompt.js +1 -1
  51. package/lib/track.js +1 -1
  52. package/package.json +1 -1
  53. package/schema/connector-yaml.json +12 -0
  54. package/schema/extension-yaml.json +17 -4
  55. package/schema/firebase-config.json +3 -0
  56. package/standalone/package.json +1 -1
  57. package/templates/dataconnect-prompts/operation-generation-cursor-windsurf-rule.txt +273 -0
  58. package/templates/dataconnect-prompts/schema-generation-cursor-windsurf-rule.txt +653 -0
  59. package/templates/genkit/firebase.1.0.0.template +5 -0
  60. package/templates/init/firestore/firestore.rules +2 -0
  61. package/templates/init/functions/typescript/package.lint.json +1 -1
  62. package/templates/init/functions/typescript/package.nolint.json +1 -1
@@ -0,0 +1,653 @@
1
+ Description: Use this tool to generate Firebase Data Connect schema.
2
+
3
+ You are an expert of Firebase Data Connect.
4
+
5
+ - Data Connect offers customized GraphQL directives to let you customize SQL mapping in the schema. Follow https://firebase.google.com/docs/reference/data-connect/gql/directive to incorporate Data Connect directive in.
6
+
7
+ - Do not overwrite the schema with generic GraghQL syntax
8
+
9
+ For example, if I were to ask for a schema for a GraphQL database that contains a table called "users" with a field called "name" and another table called "posts" with a field called "body", I would get the following schema:
10
+ ```
11
+ type User @table {
12
+ name: String!
13
+ }
14
+
15
+ type Post @table {
16
+ body: String!
17
+ author: User
18
+ }
19
+ ```
20
+
21
+ Simple Firebase Data Connect schema often takes the following form:
22
+ ```graphql
23
+ type TableName @table {
24
+ uuidField: UUID
25
+ uuidArrayField: [UUID]
26
+ stringField: String
27
+ stringArrayField: [String]
28
+ intField: Int
29
+ intArrayField: [Int]
30
+ int64Field: Int64
31
+ int64ArrayField: [Int64]
32
+ floatField: Float
33
+ floatArrayField: [Float]
34
+ booleanField: Boolean
35
+ booleanArrayField: [Boolean]
36
+ timestampField: Timestamp
37
+ timestampArrayField: [Timestamp]
38
+ dateField: Date
39
+ dateArrayField: [Date]
40
+ vectorField: Vector @col(size:168)
41
+ }
42
+ ```
43
+
44
+ Leave out objects named after `Query` and `Mutation`
45
+
46
+ Firebase Data Connect implicitly adds `id: UUID!` to every table and implicitly makes it primary key. Therefore, leave out the `id` field.
47
+
48
+ Use `UUID` type instead of `ID` type or `String` type for id-like fields.
49
+
50
+ Array reference fields, like `[SomeTable]` and `[SomeTable!]!`, are not supported. Use the singular reference field instead.
51
+ For example, for a one-to-many relationship like one user is assiend to many bugs in a software project:
52
+ ```graphql
53
+ type User @table {
54
+ name: String! @col(name: "name", dataType: "varchar(30)")
55
+ # bugs: [Bug] # Not supported. Do not use
56
+ }
57
+
58
+ type Bug @table {
59
+ title: String!
60
+ assignee: User
61
+ reporter: User
62
+ }
63
+ ```
64
+
65
+ For another example, for a many-to-many relationship like each crew member is assigned to many chores and each chores requires many crews to complete:
66
+ ```graphql
67
+ type Crew @table {
68
+ name: String!
69
+ # assignedChores: [Chore!]! # No supported. Do not use
70
+ }
71
+
72
+ type Chore @table {
73
+ name: String!
74
+ description: String!
75
+ # assignedCrews: [Crews!]! # No supported. Do not use
76
+ }
77
+
78
+ type Assignment @table {
79
+ crew: Crew!
80
+ chore: Chore!
81
+ }
82
+ ```
83
+
84
+
85
+ Be sure that your response contains a valid Firebase Data Connect schema in a single GraphQL code block inside of triple backticks and closely follows my instructions and description.
86
+
87
+
88
+ # Directives
89
+
90
+ Directives define specific behaviors that can be applied to fields or types within a GraphQL schema.
91
+
92
+ ## Data Connect Defined
93
+
94
+ ### @col on `FIELD_DEFINITION` {:#col}
95
+ Customizes a field that represents a SQL database table column.
96
+
97
+ Data Connect maps scalar Fields on @`@table` type to a SQL column of
98
+ corresponding data type.
99
+
100
+ - scalar @`UUID` maps to @`uuid`.
101
+ - scalar @`String` maps to @`text`.
102
+ - scalar @`Int` maps to @`int`.
103
+ - scalar @`Int64` maps to @`bigint`.
104
+ - scalar @`Float` maps to @`double precision`.
105
+ - scalar @`Boolean` maps to @`boolean`.
106
+ - scalar @`Date` maps to @`date`.
107
+ - scalar @`Timestamp` maps to @`timestamptz`.
108
+ - scalar @`Any` maps to @`jsonb`.
109
+ - scalar @`Vector` maps to @`pgvector`.
110
+
111
+ Array scalar fields are mapped to @Postgres arrays.
112
+
113
+ ###### Example: Serial Primary Key
114
+
115
+ For example, you can define auto-increment primary key.
116
+
117
+ ```graphql
118
+ type Post @table {
119
+ id: Int! @col(name: "post_id", dataType: "serial")
120
+ }
121
+ ```
122
+
123
+ Data Connect converts it to the following SQL table schema.
124
+
125
+ ```sql
126
+ CREATE TABLE "public"."post" (
127
+ "post_id" serial NOT NULL,
128
+ PRIMARY KEY ("id")
129
+ )
130
+ ```
131
+
132
+ ###### Example: Vector
133
+
134
+ ```graphql
135
+ type Post @table {
136
+ content: String! @col(name: "post_content")
137
+ contentEmbedding: Vector! @col(size:768)
138
+ }
139
+ ```
140
+
141
+ | Argument | Type | Description |
142
+ |---|---|---|
143
+ | `name` | @`String` | The SQL database column name. Defaults to snake_case of the field name. |
144
+ | `dataType` | @`String` | Configures the custom SQL data type. Each GraphQL type can map to multiple SQL data types. Refer to @Postgres supported data types. Incompatible SQL data type will lead to undefined behavior. |
145
+ | `size` | @`Int` | Required on @`Vector` columns. It specifies the length of the Vector. `textembedding-gecko@003` model generates @`Vector` of `@col(size:768)`. |
146
+
147
+ ### @default on `FIELD_DEFINITION` {:#default}
148
+ Specifies the default value for a column field.
149
+
150
+ For example:
151
+
152
+ ```graphql
153
+ type User @table(key: "uid") {
154
+ uid: String! @default(expr: "auth.uid")
155
+ number: Int! @col(dataType: "serial")
156
+ createdAt: Date! @default(expr: "request.time")
157
+ role: String! @default(value: "Member")
158
+ credit: Int! @default(value: 100)
159
+ }
160
+ ```
161
+
162
+ The supported arguments vary based on the field type.
163
+
164
+ | Argument | Type | Description |
165
+ |---|---|---|
166
+ | `value` | @`Any` | A constant value validated against the field's GraphQL type during compilation. |
167
+ | `expr` | @`Any_Expr` | A CEL expression whose return value must match the field's data type. |
168
+ | `sql` | @`Any_SQL` | A raw SQL expression, whose SQL data type must match the underlying column. The value is any variable-free expression (in particular, cross-references to other columns in the current table are not allowed). Subqueries are not allowed either. See @PostgreSQL defaults for more details. |
169
+
170
+ ### Default Expression `@default(expr: "request.time")`
171
+ To automatically updates a date when a row in the table is created.
172
+
173
+ For example: createdAt column automatically updates when a user is created.
174
+
175
+ ```graphql
176
+ type User @table(key: "uid") {
177
+ // other fields
178
+ createdAt: Date! @default(expr: "request.time")
179
+ }
180
+ ```
181
+
182
+ ### @index on `FIELD_DEFINITION` | `OBJECT` {:#index}
183
+ Defines a database index to optimize query performance.
184
+
185
+ ```graphql
186
+ type User @table @index(fields: ["name", "phoneNumber"], order: [ASC, DESC]) {
187
+ name: String @index
188
+ phoneNumber: Int64 @index
189
+ tags: [String] @index # GIN Index
190
+ }
191
+ ```
192
+
193
+ ##### Single Field Index
194
+
195
+ You can put @`@index` on a @`@col` field to create a SQL index.
196
+
197
+ `@index(order)` matters little for single field indexes, as they can be scanned
198
+ in both directions.
199
+
200
+ ##### Composite Index
201
+
202
+ You can put `@index(fields: [...])` on @`@table` type to define composite indexes.
203
+
204
+ `@index(order: [...])` can customize the index order to satisfy particular
205
+ filter and order requirement.
206
+
207
+ | Argument | Type | Description |
208
+ |---|---|---|
209
+ | `name` | @`String` | Configure the SQL database index id. If not overridden, Data Connect generates the index name: - `{table_name}_{first_field}_{second_field}_aa_idx` - `{table_name}_{field_name}_idx` |
210
+ | `fields` | [`[String!]`](scalar.md#String) | Only allowed and required when used on a @`@table` type. Specifies the fields to create the index on. |
211
+ | `order` | [`[IndexFieldOrder!]`](enum.md#IndexFieldOrder) | Only allowed for `BTREE` @`@index` on @`@table` type. Specifies the order for each indexed column. Defaults to all `ASC`. |
212
+ | `type` | @`IndexType` | Customize the index type. For most index, it defaults to `BTREE`. For array fields, only allowed @`IndexType` is `GIN`. For @`Vector` fields, defaults to `HNSW`, may configure to `IVFFLAT`. |
213
+ | `vector_method` | @`VectorSimilarityMethod` | Only allowed when used on vector field. Defines the vector similarity method. Defaults to `INNER_PRODUCT`. |
214
+
215
+ ### @ref on `FIELD_DEFINITION` {:#ref}
216
+ Defines a foreign key reference to another table.
217
+
218
+ For example, we can define a many-to-one relation.
219
+
220
+ ```graphql
221
+ type ManyTable @table {
222
+ refField: OneTable!
223
+ }
224
+ type OneTable @table {
225
+ someField: String!
226
+ }
227
+ ```
228
+ Data Connect adds implicit foreign key column and relation query field. So the
229
+ above schema is equivalent to the following schema.
230
+
231
+ ```graphql
232
+ type ManyTable @table {
233
+ id: UUID! @default(expr: "uuidV4()")
234
+ refField: OneTable! @ref(fields: "refFieldId", references: "id")
235
+ refFieldId: UUID!
236
+ }
237
+ type OneTable @table {
238
+ id: UUID! @default(expr: "uuidV4()")
239
+ someField: UUID!
240
+ # Generated Fields:
241
+ # manyTables_on_refField: [ManyTable!]!
242
+ }
243
+ ```
244
+ Data Connect generates the necessary foreign key constraint.
245
+
246
+ ```sql
247
+ CREATE TABLE "public"."many_table" (
248
+ "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
249
+ "ref_field_id" uuid NOT NULL,
250
+ PRIMARY KEY ("id"),
251
+ CONSTRAINT "many_table_ref_field_id_fkey" FOREIGN KEY ("ref_field_id") REFERENCES "public"."one_table" ("id") ON DELETE CASCADE
252
+ )
253
+ ```
254
+
255
+ ###### Example: Traverse the Reference Field
256
+
257
+ ```graphql
258
+ query ($id: UUID!) {
259
+ manyTable(id: $id) {
260
+ refField { id }
261
+ }
262
+ }
263
+ ```
264
+
265
+ ###### Example: Reverse Traverse the Reference field
266
+
267
+ ```graphql
268
+ query ($id: UUID!) {
269
+ oneTable(id: $id) {
270
+ manyTables_on_refField { id }
271
+ }
272
+ }
273
+ ```
274
+
275
+ ##### Optional Many-to-One Relation
276
+
277
+ An optional foreign key reference will be set to null if the referenced row is deleted.
278
+
279
+ In this example, if a `User` is deleted, the `assignee` and `reporter`
280
+ references will be set to null.
281
+
282
+ ```graphql
283
+ type Bug @table {
284
+ title: String!
285
+ assignee: User
286
+ reproter: User
287
+ }
288
+
289
+ type User @table { name: String! }
290
+ ```
291
+
292
+ ##### Required Many-to-One Relation
293
+
294
+ A required foreign key reference will cascade delete if the referenced row is
295
+ deleted.
296
+
297
+ In this example, if a `Post` is deleted, associated comments will also be
298
+ deleted.
299
+
300
+ ```graphql
301
+ type Comment @table {
302
+ post: Post!
303
+ content: String!
304
+ }
305
+
306
+ type Post @table { title: String! }
307
+ ```
308
+
309
+ ##### Many To Many Relation
310
+
311
+ You can define a many-to-many relation with a join table.
312
+
313
+ ```graphql
314
+ type Membership @table(key: ["group", "user"]) {
315
+ group: Group!
316
+ user: User!
317
+ role: String! @default(value: "member")
318
+ }
319
+
320
+ type Group @table { name: String! }
321
+ type User @table { name: String! }
322
+ ```
323
+
324
+ When Data Connect sees a table with two reference field as its primary key, it
325
+ knows this is a join table, so expands the many-to-many query field.
326
+
327
+ ```graphql
328
+ type Group @table {
329
+ name: String!
330
+ # Generated Fields:
331
+ # users_via_Membership: [User!]!
332
+ # memberships_on_group: [Membership!]!
333
+ }
334
+ type User @table {
335
+ name: String!
336
+ # Generated Fields:
337
+ # groups_via_Membership: [Group!]!
338
+ # memberships_on_user: [Membership!]!
339
+ }
340
+ ```
341
+
342
+ ###### Example: Traverse the Many-To-Many Relation
343
+
344
+ ```graphql
345
+ query ($id: UUID!) {
346
+ group(id: $id) {
347
+ users: users_via_Membership {
348
+ name
349
+ }
350
+ }
351
+ }
352
+ ```
353
+
354
+ ###### Example: Traverse to the Join Table
355
+
356
+ ```graphql
357
+ query ($id: UUID!) {
358
+ group(id: $id) {
359
+ memberships: memberships_on_group {
360
+ user { name }
361
+ role
362
+ }
363
+ }
364
+ }
365
+ ```
366
+
367
+ ##### One To One Relation
368
+
369
+ You can even define a one-to-one relation with the help of @`@unique` or `@table(key)`.
370
+
371
+ ```graphql
372
+ type User @table {
373
+ name: String
374
+ }
375
+ type Account @table {
376
+ user: User! @unique
377
+ }
378
+ # Alternatively, use primary key constraint.
379
+ # type Account @table(key: "user") {
380
+ # user: User!
381
+ # }
382
+ ```
383
+
384
+ ###### Example: Transerse the Reference Field
385
+
386
+ ```graphql
387
+ query ($id: UUID!) {
388
+ account(id: $id) {
389
+ user { id }
390
+ }
391
+ }
392
+ ```
393
+
394
+ ###### Example: Reverse Traverse the Reference field
395
+
396
+ ```graphql
397
+ query ($id: UUID!) {
398
+ user(id: $id) {
399
+ account_on_user { id }
400
+ }
401
+ }
402
+ ```
403
+
404
+ ##### Customizations
405
+
406
+ - `@ref(constraintName)` can customize the SQL foreign key constraint name (`table_name_ref_field_fkey` above).
407
+ - `@ref(fields)` can customize the foreign key field names.
408
+ - `@ref(references)` can customize the constraint to reference other columns.
409
+ By default, `@ref(references)` is the primary key of the @`@ref` table.
410
+ Other fields with @`@unique` may also be referred in the foreign key constraint.
411
+
412
+ | Argument | Type | Description |
413
+ |---|---|---|
414
+ | `constraintName` | @`String` | The SQL database foreign key constraint name. Defaults to snake_case `{table_name}_{field_name}_fkey`. |
415
+ | `fields` | [`[String!]`](scalar.md#String) | Foreign key fields. Defaults to `{tableName}{PrimaryIdName}`. |
416
+ | `references` | [`[String!]`](scalar.md#String) | The fields that the foreign key references in the other table. Defaults to its primary key. |
417
+
418
+ ### @table on `OBJECT` {:#table}
419
+ Defines a relational database table.
420
+
421
+ In this example, we defined one table with a field named `myField`.
422
+
423
+ ```graphql
424
+ type TableName @table {
425
+ myField: String
426
+ }
427
+ ```
428
+ Data Connect adds an implicit `id` primary key column. So the above schema is equivalent to:
429
+
430
+ ```graphql
431
+ type TableName @table(key: "id") {
432
+ id: String @default(expr: "uuidV4()")
433
+ myField: String
434
+ }
435
+ ```
436
+
437
+ Data Connect generates the following SQL table and CRUD operations to use it.
438
+
439
+ ```sql
440
+ CREATE TABLE "public"."table_name" (
441
+ "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
442
+ "my_field" text NULL,
443
+ PRIMARY KEY ("id")
444
+ )
445
+ ```
446
+
447
+ * You can lookup a row: `query ($id: UUID!) { tableName(id: $id) { myField } } `
448
+ * You can find rows using: `query tableNames(limit: 20) { myField }`
449
+ * You can insert a row: `mutation { tableName_insert(data: {myField: "foo"}) }`
450
+ * You can update a row: `mutation ($id: UUID!) { tableName_update(id: $id, data: {myField: "bar"}) }`
451
+ * You can delete a row: `mutation ($id: UUID!) { tableName_delete(id: $id) }`
452
+
453
+ ##### Customizations
454
+
455
+ - `@table(singular)` and `@table(plural)` can customize the singular and plural name.
456
+ - `@table(name)` can customize the Postgres table name.
457
+ - `@table(key)` can customize the primary key field name and type.
458
+
459
+ For example, the `User` table often has a `uid` as its primary key.
460
+
461
+ ```graphql
462
+ type User @table(key: "uid") {
463
+ uid: String!
464
+ name: String
465
+ }
466
+ ```
467
+
468
+ * You can securely lookup a row: `query { user(key: {uid_expr: "auth.uid"}) { name } } `
469
+ * You can securely insert a row: `mutation { user_insert(data: {uid_expr: "auth.uid" name: "Fred"}) }`
470
+ * You can securely update a row: `mutation { user_update(key: {uid_expr: "auth.uid"}, data: {name: "New Name"}) }`
471
+ * You can securely delete a row: `mutation { user_delete(key: {uid_expr: "auth.uid"}) }`
472
+
473
+ @`@table` type can be configured further with:
474
+
475
+ - Custom SQL data types for columns. See @`@col`.
476
+ - Add SQL indexes. See @`@index`.
477
+ - Add SQL unique constraints. See @`@unique`.
478
+ - Add foreign key constraints to define relations. See @`@ref`.
479
+
480
+ | Argument | Type | Description |
481
+ |---|---|---|
482
+ | `name` | @`String` | Configures the SQL database table name. Defaults to snake_case like `table_name`. |
483
+ | `singular` | @`String` | Configures the singular name. Defaults to the camelCase like `tableName`. |
484
+ | `plural` | @`String` | Configures the plural name. Defaults to infer based on English plural pattern like `tableNames`. |
485
+ | `key` | [`[String!]`](scalar.md#String) | Defines the primary key of the table. Defaults to a single field named `id`. If not present already, Data Connect adds an implicit field `id: UUID! @default(expr: "uuidV4()")`. |
486
+
487
+ ### @unique on `FIELD_DEFINITION` | `OBJECT` {:#unique}
488
+ Defines unique constraints on @`@table`.
489
+
490
+ For example,
491
+
492
+ ```graphql
493
+ type User @table {
494
+ phoneNumber: Int64 @unique
495
+ }
496
+ type UserProfile @table {
497
+ user: User! @unique
498
+ address: String @unique
499
+ }
500
+ ```
501
+
502
+ - @`@unique` on a @`@col` field adds a single-column unique constraint.
503
+ - @`@unique` on a @`@table` type adds a composite unique constraint.
504
+ - @`@unique` on a @`@ref` defines a one-to-one relation. It adds unique constraint
505
+ on `@ref(fields)`.
506
+
507
+ @`@unique` ensures those fields can uniquely identify a row, so other @`@table`
508
+ type may define `@ref(references)` to refer to fields that has a unique constraint.
509
+
510
+ | Argument | Type | Description |
511
+ |---|---|---|
512
+ | `indexName` | @`String` | Configures the SQL database unique constraint name. If not overridden, Data Connect generates the unique constraint name: - `table_name_first_field_second_field_uidx` - `table_name_only_field_name_uidx` |
513
+ | `fields` | [`[String!]`](scalar.md#String) | Only allowed and required when used on OBJECT, this specifies the fields to create a unique constraint on. |
514
+
515
+ ### @view on `OBJECT` {:#view}
516
+ Defines a relational database Raw SQLview.
517
+
518
+ Data Connect generates GraphQL queries with WHERE and ORDER BY clauses.
519
+ However, not all SQL features has native GraphQL equivalent.
520
+
521
+ You can write **an arbitrary SQL SELECT statement**. Data Connect
522
+ would map Graphql fields on @`@view` type to columns in your SELECT statement.
523
+
524
+ * Scalar GQL fields (camelCase) should match a SQL column (snake_case)
525
+ in the SQL SELECT statement.
526
+ * Reference GQL field can point to another @`@table` type. Similar to foreign key
527
+ defined with @`@ref` on a @`@table` type, a @`@view` type establishes a relation
528
+ when `@ref(fields)` match `@ref(references)` on the target table.
529
+
530
+ In this example, you can use `@view(sql)` to define an aggregation view on existing
531
+ table.
532
+
533
+ ```graphql
534
+ type User @table {
535
+ name: String
536
+ score: Int
537
+ }
538
+ type UserAggregation @view(sql: """
539
+ SELECT
540
+ COUNT(*) as count,
541
+ SUM(score) as sum,
542
+ AVG(score) as average,
543
+ PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY score) AS median,
544
+ (SELECT id FROM "user" LIMIT 1) as example_id
545
+ FROM "user"
546
+ """) {
547
+ count: Int
548
+ sum: Int
549
+ average: Float
550
+ median: Float
551
+ example: User
552
+ exampleId: UUID
553
+ }
554
+ ```
555
+
556
+ ###### Example: Query Raw SQL View
557
+
558
+ ```graphql
559
+ query {
560
+ userAggregations {
561
+ count sum average median
562
+ exampleId example { id }
563
+ }
564
+ }
565
+ ```
566
+
567
+ ##### One-to-One View
568
+
569
+ An one-to-one companion @`@view` can be handy if you want to argument a @`@table`
570
+ with additional implied content.
571
+
572
+ ```graphql
573
+ type Restaurant @table {
574
+ name: String!
575
+ }
576
+ type Review @table {
577
+ restaurant: Restaurant!
578
+ rating: Int!
579
+ }
580
+ type RestaurantStats @view(sql: """
581
+ SELECT
582
+ restaurant_id,
583
+ COUNT(*) AS review_count,
584
+ AVG(rating) AS average_rating
585
+ FROM review
586
+ GROUP BY restaurant_id
587
+ """) {
588
+ restaurant: Restaurant @unique
589
+ reviewCount: Int
590
+ averageRating: Float
591
+ }
592
+ ```
593
+
594
+ In this example, @`@unique` convey the assumption that each `Restaurant` should
595
+ have only one `RestaurantStats` object.
596
+
597
+ ###### Example: Query One-to-One View
598
+
599
+ ```graphql
600
+ query ListRestaurants {
601
+ restaurants {
602
+ name
603
+ stats: restaurantStats_on_restaurant {
604
+ reviewCount
605
+ averageRating
606
+ }
607
+ }
608
+ }
609
+ ```
610
+
611
+ ###### Example: Filter based on One-to-One View
612
+
613
+ ```graphql
614
+ query BestRestaurants($minAvgRating: Float, $minReviewCount: Int) {
615
+ restaurants(where: {
616
+ restaurantStats_on_restaurant: {
617
+ averageRating: {ge: $minAvgRating}
618
+ reviewCount: {ge: $minReviewCount}
619
+ }
620
+ }) { name }
621
+ }
622
+ ```
623
+
624
+ ##### Customizations
625
+
626
+ - One of `@view(sql)` or `@view(name)` should be defined.
627
+ `@view(name)` can refer to a persisted SQL view in the Postgres schema.
628
+ - `@view(singular)` and `@view(plural)` can customize the singular and plural name.
629
+
630
+ @`@view` type can be configured further:
631
+
632
+ - @`@unique` lets you define one-to-one relation.
633
+ - @`@col` lets you customize SQL column mapping. For example, `@col(name: "column_in_select")`.
634
+
635
+ ##### Limitations
636
+
637
+ Raw SQL view doesn't have a primary key, so it doesn't support lookup. Other
638
+ @`@table` or @`@view` cannot have @`@ref` to a view either.
639
+
640
+ View cannot be mutated. You can perform CRUD operations on the underlying
641
+ table to alter its content.
642
+
643
+ - Important: Data Connect doesn't parse and validate SQL
644
+
645
+ - If the SQL view is invalid or undefined, related requests may fail.
646
+ - If the SQL view return incompatible types. Firebase Data Connect may surface
647
+ errors.
648
+ - If a field doesn't have a corresponding column in the SQL SELECT statement,
649
+ it will always be `null`.
650
+ - There is no way to ensure VIEW to TABLE @`@ref` constraint.
651
+ - All fields must be nullable in case they aren't found in the SELECT statement
652
+ or in the referenced table.
653
+ - You should always test @`@view`
@@ -15,6 +15,11 @@ import { onCallGenkit, hasClaim } from "firebase-functions/https";
15
15
  import { defineSecret } from "firebase-functions/params";
16
16
  const apiKey = defineSecret("GOOGLE_GENAI_API_KEY");
17
17
 
18
+ // The Firebase telemetry plugin exports a combination of metrics, traces, and logs to Google Cloud
19
+ // Observability. See https://firebase.google.com/docs/genkit/observability/telemetry-collection.
20
+ $TELEMETRY_COMMENTimport {enableFirebaseTelemetry} from "@genkit-ai/firebase";
21
+ $TELEMETRY_COMMENTenableFirebaseTelemetry();
22
+
18
23
  const ai = genkit({
19
24
  plugins: [
20
25
  $GENKIT_CONFIG_PLUGINS
@@ -1,3 +1,5 @@
1
+ rules_version='2'
2
+
1
3
  service cloud.firestore {
2
4
  match /databases/{database}/documents {
3
5
  match /{document=**} {
@@ -25,7 +25,7 @@
25
25
  "eslint-config-google": "^0.14.0",
26
26
  "eslint-plugin-import": "^2.25.4",
27
27
  "firebase-functions-test": "^3.1.0",
28
- "typescript": "^4.9.0"
28
+ "typescript": "^5.7.3"
29
29
  },
30
30
  "private": true
31
31
  }
@@ -18,7 +18,7 @@
18
18
  "firebase-functions": "^6.0.1"
19
19
  },
20
20
  "devDependencies": {
21
- "typescript": "^4.9.0",
21
+ "typescript": "^5.7.3",
22
22
  "firebase-functions-test": "^3.1.0"
23
23
  },
24
24
  "private": true