Skip to content

Instantly share code, notes, and snippets.

@K3TH3R
Created November 5, 2020 08:06
Show Gist options
  • Save K3TH3R/f10f37a38b7f13c7412fb3a21ad089d6 to your computer and use it in GitHub Desktop.
Save K3TH3R/f10f37a38b7f13c7412fb3a21ad089d6 to your computer and use it in GitHub Desktop.
Loads/updates the schema in a Fauna database.
// Required packages: faunadb, dotenv.
// FAUNA_SECRET: should be the secret of an admin key in the target DB.
const fs = require("fs");
const https = require("https");
const path = require("path");
const { Client, query: q } = require("faunadb");
require('dotenv').config({ path: path.join(__dirname, '.env') });
const { FAUNA_SECRET, UPD_FUN, UPD_GQL, UPD_KEY, UPD_ROLE } = process.env;
function schemaGql() {
return new Promise((resolve, reject) => {
const data = fs.readFileSync(path.join(__dirname, "schema.gql"));
const req = https.request({
hostname: "graphql.fauna.com",
port: 443,
path: "/import",
method: "POST",
headers: {
Authorization: `Bearer ${FAUNA_SECRET}`
}
}, res => {
console.debug(`GQL imported, status: ${res.statusCode}`);
res.on("data", b => console.log(b.toString()));
res.on("end", resolve);
});
req.on("error", reject);
req.end(data);
});
}
function unlessExists(label, upd, ref, then, otherwise) {
return {
label,
query: q.If(
// false disables check and assumes it exists:
ref ? q.Exists(ref) : true,
(upd && otherwise) || "exists",
then
),
}
}
function index(def) {
return unlessExists(
`INDEX ${def.name}`,
false, // Cannot change terms or values so there's no in updating indexes.
q.Index(def.name),
q.CreateIndex(def),
);
}
function uniqueIndex(name, collection, ...fields) {
return index({
name,
unique: true,
source: { collection: q.Collection(collection) },
terms: fields.map(name => ({ field: ["data", name] })),
});
}
function searchIndex(name, collection, terms, ...values) {
return index({
name,
unique: false,
source: { collection: q.Collection(collection) },
terms: terms && terms.length > 0
? terms.map(name => ({ field: ["data", name] }))
: undefined,
values: values.length > 0
? [
...values.map(name => ({ field: ["data", name] })),
{ field: ["ref"] }
]
: undefined
})
}
function fun(name, def) {
const f = q.Function(name)
return unlessExists(
`FUNCTION ${name}`,
UPD_FUN,
f,
q.CreateFunction({ name, ...def }),
q.Update(f, def)
);
}
function role(name, def) {
const r = q.Role(name);
return unlessExists(
`ROLE ${name}`,
UPD_ROLE,
r,
q.CreateRole({ name, ...def }),
q.Update(r, def)
);
}
function key(name, role) {
return unlessExists(
`KEY ${name}`,
UPD_KEY,
false,
q.Abort("Unexpected"),
q.CreateKey({ name, role })
)
}
async function schemaFql(skip, cli, ...defs) {
const ok = [];
const failed = [];
for (const def of defs) {
if (skip && skip(def.label)) {
console.log(def.label, "SKIP");
continue;
}
try {
const res = await cli.query(def.query);
console.log(def.label, "OK", res);
ok.push('\n ' + def.label);
} catch (e) {
console.error(def.label, "FAILED", e);
failed.push('\n ' + def.label);
}
}
ok.length > 0 && console.log("OK", ...ok);
failed.length > 0 && console.error("FAILED", ...failed);
}
async function schema() {
UPD_GQL && await schemaGql();
await schemaFql(
false,
new Client({ secret: FAUNA_SECRET }),
// uniqueIndex("name", "collection", "field1", "field2"),
// index({ ... }),
// fun("Name", { body: q.Query(q.Lambda(["arg"], ... )) }),
// role("name", { ... }),
// key("name", q.Role("name")),
);
}
schema();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment