// Firestore from a server: documents written with every kind of value, fields changed with a mask,
// queries, pages, and batches, signed in with a service account.
//
//   GOOGLE_APPLICATION_CREDENTIALS=key.json quillo run firestore.qwe
//   (or FIRESTORE_EMULATOR_HOST=localhost:8200 FIRESTORE_PROJECT=demo for the emulator)
//   then open /write, /types, /update, /query, /pages, /batch, /atomic and /broken

use "firestore.qwer"

route GET /write {
    let made = firestore_create("cities", "oslo", {
        name: "Oslo",
        people: 709000,
        area: 454.0,
        capital: true,
        founded: { "$timestamp": "1048-01-01T00:00:00Z" },
        mayor: { "$ref": "people/anne" },
        where: { "$geo": [59.91, 10.75] },
        logo: { "$bytes": "aGVsbG8=" },
        tags: ["north", 7, null],
        stats: { rain: 763, nested: { deep: true } },
    })?
    { id: made._id, path: made._path, again: firestore_create("cities", "oslo", { name: "x" }).error }
}

route GET /types {
    let c = firestore_get("cities/oslo")?
    {
        people: c.people, area: c.area, capital: c.capital, founded: c.founded, mayor: c.mayor, where: c.where, logo: c.logo, tags: c.tags, stats: c.stats,
        none: firestore_get("cities/nowhere")?,
        typed: firestore_encode({ n: 1, s: "x", f: 1.5, l: [true], z: null })?,
        back: firestore_decode(firestore_encode({ n: 1, s: "x" })?.mapValue.fields),
    }
}

// Only `people` and one field inside `stats` change; everything else stays.
route GET /update {
    firestore_update("cities/oslo", { people: 710000, "stats.rain": 800 })?
    let c = firestore_get("cities/oslo")?
    { people: c.people, stats: c.stats, name: c.name, missing: firestore_update("cities/nowhere", { a: 1 }).error }
}

route GET /query {
    firestore_set("cities/bergen", { name: "Bergen", people: 285000, area: 465.0, capital: false, tags: ["west"], mayor_name: null })?
    firestore_set("cities/tromso", { name: "Tromso", people: 77000, area: 2521.0, capital: false, tags: ["north"], mayor_name: "Gunnar" })?
    firestore_set("cities/oslo/districts/grunerlokka", { name: "Grunerlokka" })?
    {
        big: firestore_query("cities", { where: [["people", ">", 100000]], order: [["people", "desc"]], select: ["name"] })? | map((c) => c.name),
        both: firestore_query("cities", { where: [["capital", "==", false], ["tags", "array-contains", "north"]] })? | map((c) => c.name),
        among: firestore_query("cities", { where: [["name", "in", ["Oslo", "Bergen"]]], order: ["name"] })? | map((c) => c.name),
        no_mayor: firestore_query("cities", { where: [["mayor_name", "==", null]] })? | map((c) => c.name),
        after: firestore_query("cities", { order: ["people"], start_after: [285000], limit: 1 })? | map((c) => c.name),
        sub: firestore_query("cities/oslo/districts", {})? | map((c) => c._path),
        bad_op: firestore_query("cities", { where: [["a", "~", 1]] }).error,
    }
}

route GET /pages {
    let one = firestore_list("cities", 2, "")?
    let two = firestore_list("cities", 2, one.next)?
    { first: one.documents | map((d) => d._id), second: two.documents | map((d) => d._id), end: two.next }
}

// One write fails; the others stand.
route GET /batch {
    let r = firestore_batch([
        { path: "counters/visits", data: { hits: 1, seen: { "$server_time": true } } },
        { op: "update", path: "counters/visits", data: { hits: { "$increment": 4 } } },
        { op: "create", path: "cities/oslo", data: { name: "Taken" } },
        { op: "delete", path: "cities/tromso" },
    ])?
    let c = firestore_get("counters/visits")?
    { ok: r.ok, failed: r.failed, hits: c.hits, has_time: c.seen != null, gone: firestore_get("cities/tromso")? }
}

// One write fails, so nothing happens.
route GET /atomic {
    let r = firestore_commit([
        { path: "cities/bergen", data: { name: "Changed" } },
        { op: "create", path: "cities/oslo", data: { name: "Taken" } },
    ])
    { error: r.error, still: firestore_get("cities/bergen")?.name, good: firestore_commit([{ path: "cities/stavanger", data: { name: "Stavanger" } }])?.results }
}

route GET /broken = {
    collection_as_doc: firestore_get("cities").error,
    doc_as_collection: firestore_list("cities/oslo", 5, "").error,
    bad_write: firestore_batch([{ op: "merge", path: "a/b", data: {} }]).error,
    deleted: firestore_delete("cities/stavanger")?,
}
