db("networks").where({ user_id: userId }).with({ tabs: db("tabs") .onField("network_id") .with({ $merge: db("channel_events") .onOwnField("channel_id") }) db.combine([ db("channels") .onField("network_id") .with({ events: db("channel_events") .onField("channel_id") .with({ notifications: db("notifications").onField("channel_events_id") }) }), db("private") ]) }) /* FIXME: tagging for (potentially nested) query modifications for eg. batching */ db("networks") .where({ user_id: userId }) .withMany("tabs", ({$db, id}) => { return $db("tabs") .where({ network_id: id }) .withOne("channel_data", ({$db, type, channel_id}) => { if (type === "channel") { return $db("channels") .where({ id: channel_id }) } }) .withMany("events", ({$db, type, channel_id, nickname}) => { if (type === "channel") { return $db("presences") .where({ channel_id: channel_id, user_id: userId }) .flatten(({$db, first_event, last_event}) => { return $db("channel_events") .where({ channel_id: channel_id }) .where(({id}) => id >= first_event && id <= last_event); }); } else if (type === "privateSession") { return $db("private_messages") .where({ user_id: userId, nickname: nickname }); } }) }) /* # Relation operations .withOne - subquery for each item, one result, store as property .withMany - subquery for each item, many results, store as property .merge - subquery for each item, one result, merge into item .flatten - subquery for each item, many results, replace item set with combined subquery result sets (can be done recursively) # Query phases Compilation - turn query into structured data, parse callbacks, etc. Validation - verify that all of the referenced tables/columns/etc. exist in the DB Scheduling - turn into underlying SQL queries Execution - run the query Any modification to a query (which is immutable) produces a new query, and existing compilation/validation/scheduling results do not carry over! Calling .execute(db/tx) directly on a built query will go through all four phases automatically; the developer may also choose to pre-compile their query with .compile(), and pre-validate it by calling .validate(db/tx), and then finally pre-schedule it by calling .schedule(). Alternatively, they can call .prepare(db/tx) which does all of those three steps? How to capture user-specified variables from outer scope? Also should wrap parsed callbacks within arrow function wrapper instead of array, to pass in variable definitions from outer callbacks. */