// Likes and lists of repositories. // // `repo_likes`: a person likes a repository, once. A repository shows how many people like it, and // a person's profile the repositories they like. // // `repo_lists`: named collections of repositories that a person or an organization keeps, public // (anyone can see them) or private (only that person, or the organization's members). `slug` is the // list's address under /lists//, made from its name. `repo_list_items` puts a // repository in a list; a list never shows anyone a repository they couldn't see anyway. 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 select = (name, values, opts = {}) => ({ type: "select", name, values, maxSelect: 1, required: true, ...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"); create( app, "repo_likes", [parent("repo", repos), parent("user", users), time("created_at", { required: true })], ["CREATE UNIQUE INDEX idx_repo_likes ON repo_likes (repo, user)", "CREATE INDEX idx_repo_likes_user ON repo_likes (user, created_at)"], ); const lists = create( app, "repo_lists", [ parent("owner", users), text("name", { required: true, max: 60 }), text("slug", { required: true, max: 60 }), text("description", { max: 300 }), select("visibility", ["public", "private"]), time("created_at", { required: true }), // When a repository was last added, or the list was made; lists are sorted by it. time("updated_at", { required: true }), ], ["CREATE UNIQUE INDEX idx_repo_lists_slug ON repo_lists (owner, slug)"], ); create( app, "repo_list_items", [parent("list", lists), parent("repo", repos), time("created_at", { required: true })], ["CREATE UNIQUE INDEX idx_repo_list_items ON repo_list_items (list, repo)", "CREATE INDEX idx_repo_list_items_repo ON repo_list_items (repo)"], ); }, (app) => { for (const name of ["repo_list_items", "repo_lists", "repo_likes"]) app.delete(app.findCollectionByNameOrId(name)); }, );