You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
3.7 KiB
JavaScript

"use strict";
const util = require("util");
let { select, onlyColumns, where, withRelations, withDerived, column, through, inValues, sql, postProcess } = require("../operations");
function withOwner() {
return withRelations({ owner: "owner_id" });
}
// TODO: Allow specifying placeholders that can be filled in later, for truly reusable query builders (so that eg. query planning only needs to be done once, this could even use prepared statements under the hood)
let query = select("projects", [
onlyColumns([ "id", "name" ]),
where({
active: true,
visible: true,
primary_category_id: inValues([ 2, 3, 5, 7, 8 ])
}),
// FIXME: where pivot table entry exists for category in that list
withRelations({
primaryCategory: belongsTo({
column: "primary_category_id",
query: [ withOwner() ]
}),
categories: through({
path: [ "projects_categories.project_id", "category_id" ],
query: [ // Optional extra clauses for the query on the pivot table, eg. for filtering entries
where({ adminApproved: true })
]
}),
// all user groups for a given project ID -> all memberships for the given user group IDs -> for each membership, the record referenced by the given user_id
users: through([ "user_groups.project_id", "membership.user_group_id", "user_id" ]),
// ... expands to ...
users: through([
has(foreignColumn({ table: "user_groups", column: "project_id" })),
has(foreignColumn({ table: "memberships", column: "user_group_id" })),
belongsTo(column("project_id")),
]),
owner: "owner_id",
// ... expands to
owner: belongsTo({ column: "owner_id" }),
releases: "releases.project_id",
// ... expands to ...
releases: has({ column: "releases.project_id" })
// primaryCategory: [
// column("primary_category_id"),
// withOwner()
// ],
// categories: has(through({
// table: "projects_categories",
// localSide: "project_id",
// remoteSide: "category_id",
// })),
// users: has(through({
// table: "user_groups",
// localSide: "project_id",
// remoteSide: through({
// table: "memberships",
// localSide: "user_group_id",
// remoteSide: "user_id"
// })
// })),
// categories: [
// through({
// table: "projects_categories",
// localSide: "project_id",
// remoteSide: "category_id",
// query: [ // Optional extra clauses for the query on the pivot table, eg. for filtering entries
// where({ adminApproved: true })
// ]
// }),
// withOwner()
// ],
}),
withDerived({
capitalizedName: sql("UPPER(name)"),
teamCount: sql("moderator_count + admin_count"),
nameDistance: (project) => wordDistanceAlgorithm(project.name, "someReferenceName") // NOTE: This could have returned a Promise!
}),
mapCase({ from: "snake", to: "camel" })
]);
console.log(util.inspect(query, { depth: null, colors: true }));
// FIXME: Pre-processing (eg. inverse case-mapping for inserted objects or WHERE clauses) - maybe pre-processing that subscribes to particular operations? Something along the lines of axios interceptors perhaps
// FIXME: `either`/`all` for OR/AND representation respectively?
// FIXME: I guess `withDerived` could be implemented externally, as something that (depending on value type) either a) adds a column selector or b) adds a post-processing hook
// FIXME: Aggregrates (GROUP BY)
// return db.execute(query);
/* Hypothetical `mapCase` implementation */
function mapObjectCase(object, from, to) {
return mapObject(object, (key, value) => {
return [
caseMapper(key, from, to),
value
];
});
}
function mapCase({ from, to }) {
return postProcess((results) => {
// NOTE: This could have returned a Promise!
return results.map((result) => mapObjectCase(result, from, to));
});
}