Vectrum
Sign In
82 lines · 2.7 KB · JavaScript
// Releases: a git tag with notes and downloadable files (binaries, installers, checksums). The
// files themselves are kept on disk under data/releases/; these records describe them.

const text = (name, opts = {}) => ({ type: "text", name, max: 1000, ...opts });
const number = (name, opts = {}) => ({ type: "number", name, onlyInt: true, ...opts });
const time = (name, opts = {}) => number(name, { min: 0, ...opts });
const relation = (name, collection, opts = {}) => ({
  type: "relation",
  name,
  collectionId: collection.id,
  maxSelect: 1,
  cascadeDelete: false,
  ...opts,
});
const parent = (name, collection) => relation(name, collection, { required: true, cascadeDelete: true });

function create(app, name, fields, indexes = []) {
  const collection = new Collection({
    type: "base",
    name,
    listRule: null,
    viewRule: null,
    createRule: null,
    updateRule: null,
    deleteRule: null,
    fields,
    indexes,
  });
  app.save(collection);
  return collection;
}

migrate(
  (app) => {
    const users = app.findCollectionByNameOrId("users");
    const repos = app.findCollectionByNameOrId("repos");

    const releases = create(
      app,
      "releases",
      [
        parent("repo", repos),
        // The tag name without refs/tags/. A draft's tag may not exist yet.
        text("tag", { required: true, max: 255 }),
        // The branch or commit the tag is created from, if it doesn't exist when the release is published
        text("target", { max: 255 }),
        text("title", { max: 256 }),
        text("body", { max: 65536 }),
        { type: "bool", name: "draft" },
        { type: "bool", name: "prerelease" },
        relation("author", users),
        time("created_at", { required: true }),
        time("updated_at", { required: true }),
        // 0 while it's a draft
        time("published_at"),
      ],
      ["CREATE UNIQUE INDEX idx_releases_repo_tag ON releases (repo, tag)", "CREATE INDEX idx_releases_published ON releases (repo, published_at)"],
    );

    create(
      app,
      "release_assets",
      [
        parent("release", releases),
        text("name", { required: true, max: 255 }),
        number("size", { min: 0 }),
        // hex
        text("sha256", { required: true, max: 64 }),
        number("download_count", { min: 0 }),
        relation("uploader", users),
        time("created_at", { required: true }),
        // When the file was last replaced
        time("updated_at", { required: true }),
      ],
      ["CREATE UNIQUE INDEX idx_release_assets_name ON release_assets (release, name)"],
    );
  },
  (app) => {
    app.delete(app.findCollectionByNameOrId("release_assets"));
    app.delete(app.findCollectionByNameOrId("releases"));
  },
);