Initial commit

This commit is contained in:
St. Nebula
2026-04-23 23:58:59 -05:00
commit 47b9e3c159
257 changed files with 18913 additions and 0 deletions
@@ -0,0 +1,303 @@
# Advanced Features Reference
## Contents
- [Vector Similarity Search](#vector-similarity-search)
- [Full-Text Search](#full-text-search)
- [Cloud Functions Integration](#cloud-functions-integration)
- [Data Seeding & Bulk Operations](#data-seeding--bulk-operations)
---
## Vector Similarity Search
Semantic search using Vertex AI embeddings and PostgreSQL's `pgvector`.
### Schema Setup
```graphql
type Movie @table {
id: UUID! @default(expr: "uuidV4()")
title: String!
description: String
# Vector field for embeddings - size must match model output (768 for gecko)
descriptionEmbedding: Vector! @col(size: 768)
}
```
### Generate Embeddings in Mutations
Use `_embed` server value to auto-generate embeddings via Vertex AI:
```graphql
mutation CreateMovieWithEmbedding($title: String!, $description: String!)
@auth(level: USER) {
movie_insert(data: {
title: $title,
description: $description,
descriptionEmbedding_embed: {
model: "textembedding-gecko@003",
text: $description
}
})
}
```
### Similarity Search Query
Data Connect generates `_similarity` fields for Vector columns:
```graphql
query SearchMovies($query: String!) @auth(level: PUBLIC) {
movies_descriptionEmbedding_similarity(
compare_embed: { model: "textembedding-gecko@003", text: $query },
method: L2, # L2, COSINE, or INNER_PRODUCT
within: 2.0, # Max distance threshold
limit: 5
) {
id
title
description
_metadata { distance } # See how close each result is
}
}
```
### Similarity Parameters
| Parameter | Description |
|-----------|-------------|
| `compare` | Raw Vector to compare against |
| `compare_embed` | Generate embedding from text via Vertex AI |
| `method` | Distance function: `L2`, `COSINE`, `INNER_PRODUCT` |
| `within` | Max distance (results further are excluded) |
| `where` | Additional filters |
| `limit` | Max results to return |
### Custom Embeddings
Pass pre-computed vectors directly:
```graphql
mutation StoreCustomEmbedding($id: UUID!, $embedding: Vector!) @auth(level: USER) {
movie_update(id: $id, data: { descriptionEmbedding: $embedding })
}
query SearchWithCustomVector($vector: Vector!) @auth(level: PUBLIC) {
movies_descriptionEmbedding_similarity(
compare: $vector,
method: COSINE,
limit: 10
) { id title }
}
```
---
## Full-Text Search
Fast keyword/phrase search using PostgreSQL's full-text capabilities.
### Enable with @searchable
```graphql
type Movie @table {
title: String! @searchable
description: String @searchable(language: "english")
genre: String @searchable
}
```
### Search Query
Data Connect generates `_search` fields:
```graphql
query SearchMovies($query: String!) @auth(level: PUBLIC) {
movies_search(
query: $query,
queryFormat: QUERY, # QUERY, PLAIN, PHRASE, or ADVANCED
limit: 20
) {
id title description
_metadata { relevance } # Relevance score
}
}
```
### Query Formats
| Format | Description |
|--------|-------------|
| `QUERY` | Web-style (default): quotes, AND, OR supported |
| `PLAIN` | Match all words, any order |
| `PHRASE` | Match exact phrase |
| `ADVANCED` | Full tsquery syntax |
### Tuning Results
```graphql
query SearchWithThreshold($query: String!) @auth(level: PUBLIC) {
movies_search(
query: $query,
relevanceThreshold: 0.05, # Min relevance score
where: { genre: { eq: "Action" }},
orderBy: [{ releaseYear: DESC }]
) { id title }
}
```
### Supported Languages
`english` (default), `french`, `german`, `spanish`, `italian`, `portuguese`, `dutch`, `danish`, `finnish`, `norwegian`, `swedish`, `russian`, `arabic`, `hindi`, `simple`
---
## Cloud Functions Integration
Trigger Cloud Functions when mutations execute.
### Basic Trigger (Node.js)
```typescript
import { onMutationExecuted } from "firebase-functions/dataconnect";
import { logger } from "firebase-functions";
export const onUserCreate = onMutationExecuted(
{
service: "myService",
connector: "default",
operation: "CreateUser",
region: "us-central1" // Must match Data Connect location
},
(event) => {
const variables = event.data.payload.variables;
const returnedData = event.data.payload.data;
logger.info("User created:", returnedData);
// Send welcome email, sync to analytics, etc.
}
);
```
### Basic Trigger (Python)
```python
from firebase_functions import dataconnect_fn, logger
@dataconnect_fn.on_mutation_executed(
service="myService",
connector="default",
operation="CreateUser"
)
def on_user_create(event: dataconnect_fn.Event):
variables = event.data.payload.variables
returned_data = event.data.payload.data
logger.info("User created:", returned_data)
```
### Event Data
```typescript
// event.authType: "app_user" | "unauthenticated" | "admin"
// event.authId: Firebase Auth UID (for app_user)
// event.data.payload.variables: mutation input variables
// event.data.payload.data: mutation response data
// event.data.payload.errors: any errors that occurred
```
### Filtering with Wildcards
```typescript
// Trigger on all User* mutations
export const onUserMutation = onMutationExecuted(
{ operation: "User*" },
(event) => { /* ... */ }
);
// Capture operation name
export const onAnyMutation = onMutationExecuted(
{ service: "myService", operation: "{operationName}" },
(event) => {
console.log("Operation:", event.params.operationName);
}
);
```
### Use Cases
- **Data sync**: Replicate to Firestore, BigQuery, external APIs
- **Notifications**: Send emails, push notifications on events
- **Async workflows**: Image processing, data aggregation
- **Audit logging**: Track all data changes
> ⚠️ **Avoid infinite loops**: Don't trigger mutations that would fire the same trigger. Use filters to exclude self-triggered events.
---
## Data Seeding & Bulk Operations
### Local Prototyping with _insertMany
```graphql
mutation SeedMovies @transaction {
movie_insertMany(data: [
{ id: "uuid-1", title: "Movie 1", genre: "Action" },
{ id: "uuid-2", title: "Movie 2", genre: "Drama" },
{ id: "uuid-3", title: "Movie 3", genre: "Comedy" }
])
}
```
### Reset Data with _upsertMany
```graphql
mutation ResetData {
movie_upsertMany(data: [
{ id: "uuid-1", title: "Movie 1", genre: "Action" },
{ id: "uuid-2", title: "Movie 2", genre: "Drama" }
])
}
```
### Clear All Data
```graphql
mutation ClearMovies {
movie_deleteMany(all: true)
}
```
### Production: Admin SDK Bulk Operations
```typescript
import { initializeApp } from 'firebase-admin/app';
import { getDataConnect } from 'firebase-admin/data-connect';
const app = initializeApp();
const dc = getDataConnect({ location: "us-central1", serviceId: "my-service" });
const movies = [
{ id: "uuid-1", title: "Movie 1", genre: "Action" },
{ id: "uuid-2", title: "Movie 2", genre: "Drama" }
];
// Bulk insert
await dc.insertMany("movie", movies);
// Bulk upsert
await dc.upsertMany("movie", movies);
// Single operations
await dc.insert("movie", movies[0]);
await dc.upsert("movie", movies[0]);
```
### Emulator Data Persistence
```bash
# Export emulator data
npx -y firebase-tools@latest emulators:export ./seed-data
# Start with saved data
npx -y firebase-tools@latest emulators:start --only dataconnect --import=./seed-data
```