# Firebase code on Sovaria
Source: https://sovaria.in/docs/firebase-to-sovaria

Run Firestore (modular), Auth, Storage and callable-function code on Sovaria in every SDK: the same documents, queries, snapshots, batches, transactions and field transforms; how rules, auth and storage map.

Sovaria's document collections have Firestore's model — collections, documents, subcollections, queries with cursors, live snapshots, batched writes, transactions and field transforms — and every SDK has Firebase's API for them. Move the data with [Migrate from Supabase or Firebase](https://sovaria.in/docs/migrate-from-supabase-or-firebase); then change imports, not code.

TypeScript:
```ts
import { createClient } from '@sovaria/sdk'
import { getFirestore, collection, doc, query, where, orderBy, limit, startAfter, onSnapshot,
  getDocs, setDoc, updateDoc, addDoc, writeBatch, runTransaction, serverTimestamp, increment, arrayUnion } from '@sovaria/sdk/firestore'

const sovaria = createClient(SOVARIA_URL, SOVARIA_ANON_KEY)
const db = getFirestore(sovaria)

const q = query(collection(db, 'rooms', roomId, 'messages'), where('hidden', '==', false), orderBy('sentAt'), limit(50))
const stop = onSnapshot(q, (snap) => snap.docChanges().forEach((c) => render(c.type, c.doc.data())))
await addDoc(collection(db, 'rooms', roomId, 'messages'), { text, sentAt: serverTimestamp() })
await updateDoc(doc(db, 'rooms', roomId), { count: increment(1), members: arrayUnion(userId) })
```

Python:
```python
from sovaria.collections import FieldValue

messages = sovaria.collection("rooms").doc(room_id).collection("messages")
page = await messages.where("hidden", "==", False).order_by("sent_at").limit(50).get()
await messages.add({"text": text, "sent_at": FieldValue.server_timestamp()})
await sovaria.collection("rooms").doc(room_id).update({"count": FieldValue.increment(1)})
```

Swift:
```swift
let db = Firestore.firestore(sovaria)
let q = db.collection("rooms").document(roomId).collection("messages")
  .whereField("hidden", isEqualTo: false).order(by: "sentAt").limit(to: 50)
let listener = q.addSnapshotListener { snap, error in render(snap?.documentChanges) }
try await db.collection("rooms").document(roomId).updateData(["count": FieldValue.increment(1)])
```

Kotlin:
```kotlin
val db = FirebaseFirestore.getInstance(sovaria)
val q = db.collection("rooms").document(roomId).collection("messages")
  .whereEqualTo("hidden", false).orderBy("sentAt").limit(50)
val reg = q.addSnapshotListener { snap, e -> render(snap?.documentChanges) }
db.collection("rooms").document(roomId).update("count", FieldValue.increment(1))
```

Dart:
```dart
final db = FirebaseFirestore.instanceFor(sovaria);
final q = db.collection('rooms').doc(roomId).collection('messages')
    .where('hidden', isEqualTo: false).orderBy('sentAt').limit(50);
q.snapshots().listen((snap) => render(snap.docChanges));
await db.collection('rooms').doc(roomId).update({'count': FieldValue.increment(1)});
```

| Firebase | Sovaria |
|---|---|
| Firestore `collection` / `doc` / `getDoc(s)` / `setDoc` (merge) / `addDoc` / `updateDoc` / `deleteDoc` | The same names ([Firebase-style code (Firestore API)](https://sovaria.in/docs/firestore-compat)). |
| `where` / `orderBy` / `limit` / `limitToLast` / `startAt` / `startAfter` / `endAt` / `endBefore`, `or()` / `and()` | The same ([Querying documents](https://sovaria.in/docs/document-queries)). |
| `onSnapshot` with `docChanges()` and `metadata` | The same, over Sovaria's live listeners ([Live listeners](https://sovaria.in/docs/live-listeners)). |
| `writeBatch`, `runTransaction` | The same; transactions retry when a document they read changed ([Transactions, batches and field transforms](https://sovaria.in/docs/document-transactions)). |
| `serverTimestamp`, `increment`, `arrayUnion`, `arrayRemove`, `deleteField` | The same field transforms. |
| `getCountFromServer`, `sum`, `average`, `findNearest` | The same aggregates and vector search ([Vector search on documents](https://sovaria.in/docs/document-vector-search)). |
| Security rules | Collection rules: who may read and write which documents, checked on every call ([How access is decided](https://sovaria.in/docs/access-model)). |
| `signInWithEmailAndPassword(auth, e, p)` / `onAuthStateChanged` | `sovaria.auth.signInWithPassword({ email: e, password: p })` / `onAuthStateChange` ([Email and password](https://sovaria.in/docs/email-and-password)). |
| `uploadBytes(ref(storage, path), file)` / `getDownloadURL` | `sovaria.storage.from(bucket).upload(path, file)` / `getPublicUrl` or `createSignedUrl` ([Working with files](https://sovaria.in/docs/storage-files)). |
| `httpsCallable(functions, 'f')(data)` | `sovaria.functions.call('f', data)` ([Deploying and running functions](https://sovaria.in/docs/functions-deploy-and-run)). |
| Firebase Remote Config, Analytics, Crashlytics | `sovaria.config`, `sovaria.analytics`, `sovaria.crashes` ([Product analytics](https://sovaria.in/docs/product-analytics)). |

> **Note:** Firebase Auth users move with their passwords (the Firebase scrypt parameters from `firebase auth:export`); they upgrade to Sovaria's hashing at their first sign-in. Collections and subcollections keep their paths; Storage files keep theirs.
