AK-21/Graphite-Industrial-Intelligence
0
1import { entityKind } from "../entity.js";2import {3 GelDeleteBase,4 GelInsertBuilder,5 GelSelectBuilder,6 GelUpdateBuilder,7 QueryBuilder8} from "./query-builders/index.js";9import { SelectionProxyHandler } from "../selection-proxy.js";10import { sql } from "../sql/sql.js";11import { WithSubquery } from "../subquery.js";12import { GelCountBuilder } from "./query-builders/count.js";13import { RelationalQueryBuilder } from "./query-builders/query.js";14import { GelRaw } from "./query-builders/raw.js";15class GelDatabase {16 constructor(dialect, session, schema) {17 this.dialect = dialect;18 this.session = session;19 this._ = schema ? {20 schema: schema.schema,21 fullSchema: schema.fullSchema,22 tableNamesMap: schema.tableNamesMap,23 session24 } : {25 schema: void 0,26 fullSchema: {},27 tableNamesMap: {},28 session29 };30 this.query = {};31 if (this._.schema) {32 for (const [tableName, columns] of Object.entries(this._.schema)) {33 this.query[tableName] = new RelationalQueryBuilder(34 schema.fullSchema,35 this._.schema,36 this._.tableNamesMap,37 schema.fullSchema[tableName],38 columns,39 dialect,40 session41 );42 }43 }44 this.$cache = { invalidate: async (_params) => {45 } };46 }47 static [entityKind] = "GelDatabase";48 query;49 /**50 * Creates a subquery that defines a temporary named result set as a CTE.51 *52 * It is useful for breaking down complex queries into simpler parts and for reusing the result set in subsequent parts of the query.53 *54 * See docs: {@link https://orm.drizzle.team/docs/select#with-clause}55 *56 * @param alias The alias for the subquery.57 *58 * Failure to provide an alias will result in a DrizzleTypeError, preventing the subquery from being referenced in other queries.59 *60 * @example61 *62 * ```ts63 * // Create a subquery with alias 'sq' and use it in the select query64 * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));65 *66 * const result = await db.with(sq).select().from(sq);67 * ```68 *69 * To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query, you need to add aliases to them:70 *71 * ```ts72 * // Select an arbitrary SQL value as a field in a CTE and reference it in the main query73 * const sq = db.$with('sq').as(db.select({74 * name: sql<string>`upper(${users.name})`.as('name'),75 * })76 * .from(users));77 *78 * const result = await db.with(sq).select({ name: sq.name }).from(sq);79 * ```80 */81 $with(alias) {82 const self = this;83 return {84 as(qb) {85 if (typeof qb === "function") {86 qb = qb(new QueryBuilder(self.dialect));87 }88 return new Proxy(89 new WithSubquery(qb.getSQL(), qb.getSelectedFields(), alias, true),90 new SelectionProxyHandler({ alias, sqlAliasedBehavior: "alias", sqlBehavior: "error" })91 );92 }93 };94 }95 $count(source, filters) {96 return new GelCountBuilder({ source, filters, session: this.session });97 }98 /**99 * Incorporates a previously defined CTE (using `$with`) into the main query.100 *101 * This method allows the main query to reference a temporary named result set.102 *103 * See docs: {@link https://orm.drizzle.team/docs/select#with-clause}104 *105 * @param queries The CTEs to incorporate into the main query.106 *107 * @example108 *109 * ```ts110 * // Define a subquery 'sq' as a CTE using $with111 * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));112 *113 * // Incorporate the CTE 'sq' into the main query and select from it114 * const result = await db.with(sq).select().from(sq);115 * ```116 */117 with(...queries) {118 const self = this;119 function select(fields) {120 return new GelSelectBuilder({121 fields: fields ?? void 0,122 session: self.session,123 dialect: self.dialect,124 withList: queries125 });126 }127 function selectDistinct(fields) {128 return new GelSelectBuilder({129 fields: fields ?? void 0,130 session: self.session,131 dialect: self.dialect,132 withList: queries,133 distinct: true134 });135 }136 function selectDistinctOn(on, fields) {137 return new GelSelectBuilder({138 fields: fields ?? void 0,139 session: self.session,140 dialect: self.dialect,141 withList: queries,142 distinct: { on }143 });144 }145 function update(table) {146 return new GelUpdateBuilder(table, self.session, self.dialect, queries);147 }148 function insert(table) {149 return new GelInsertBuilder(table, self.session, self.dialect, queries);150 }151 function delete_(table) {152 return new GelDeleteBase(table, self.session, self.dialect, queries);153 }154 return { select, selectDistinct, selectDistinctOn, update, insert, delete: delete_ };155 }156 select(fields) {157 return new GelSelectBuilder({158 fields: fields ?? void 0,159 session: this.session,160 dialect: this.dialect161 });162 }163 selectDistinct(fields) {164 return new GelSelectBuilder({165 fields: fields ?? void 0,166 session: this.session,167 dialect: this.dialect,168 distinct: true169 });170 }171 selectDistinctOn(on, fields) {172 return new GelSelectBuilder({173 fields: fields ?? void 0,174 session: this.session,175 dialect: this.dialect,176 distinct: { on }177 });178 }179 $cache;180 /**181 * Creates an update query.182 *183 * Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated.184 *185 * Use `.set()` method to specify which values to update.186 *187 * See docs: {@link https://orm.drizzle.team/docs/update}188 *189 * @param table The table to update.190 *191 * @example192 *193 * ```ts194 * // Update all rows in the 'cars' table195 * await db.update(cars).set({ color: 'red' });196 *197 * // Update rows with filters and conditions198 * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW'));199 *200 * // Update with returning clause201 * const updatedCar: Car[] = await db.update(cars)202 * .set({ color: 'red' })203 * .where(eq(cars.id, 1))204 * .returning();205 * ```206 */207 update(table) {208 return new GelUpdateBuilder(table, this.session, this.dialect);209 }210 /**211 * Creates an insert query.212 *213 * Calling this method will create new rows in a table. Use `.values()` method to specify which values to insert.214 *215 * See docs: {@link https://orm.drizzle.team/docs/insert}216 *217 * @param table The table to insert into.218 *219 * @example220 *221 * ```ts222 * // Insert one row223 * await db.insert(cars).values({ brand: 'BMW' });224 *225 * // Insert multiple rows226 * await db.insert(cars).values([{ brand: 'BMW' }, { brand: 'Porsche' }]);227 *228 * // Insert with returning clause229 * const insertedCar: Car[] = await db.insert(cars)230 * .values({ brand: 'BMW' })231 * .returning();232 * ```233 */234 insert(table) {235 return new GelInsertBuilder(table, this.session, this.dialect);236 }237 /**238 * Creates a delete query.239 *240 * Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted.241 *242 * See docs: {@link https://orm.drizzle.team/docs/delete}243 *244 * @param table The table to delete from.245 *246 * @example247 *248 * ```ts249 * // Delete all rows in the 'cars' table250 * await db.delete(cars);251 *252 * // Delete rows with filters and conditions253 * await db.delete(cars).where(eq(cars.color, 'green'));254 *255 * // Delete with returning clause256 * const deletedCar: Car[] = await db.delete(cars)257 * .where(eq(cars.id, 1))258 * .returning();259 * ```260 */261 delete(table) {262 return new GelDeleteBase(table, this.session, this.dialect);263 }264 // TODO views are not implemented265 // refreshMaterializedView<TView extends GelMaterializedView>(view: TView): GelRefreshMaterializedView<TQueryResult> {266 // return new GelRefreshMaterializedView(view, this.session, this.dialect);267 // }268 execute(query) {269 const sequel = typeof query === "string" ? sql.raw(query) : query.getSQL();270 const builtQuery = this.dialect.sqlToQuery(sequel);271 const prepared = this.session.prepareQuery(272 builtQuery,273 void 0,274 void 0,275 false276 );277 return new GelRaw(278 () => prepared.execute(void 0),279 sequel,280 builtQuery,281 (result) => prepared.mapResult(result, true)282 );283 }284 transaction(transaction) {285 return this.session.transaction(transaction);286 }287}288const withReplicas = (primary, replicas, getReplica = () => replicas[Math.floor(Math.random() * replicas.length)]) => {289 const select = (...args) => getReplica(replicas).select(...args);290 const selectDistinct = (...args) => getReplica(replicas).selectDistinct(...args);291 const selectDistinctOn = (...args) => getReplica(replicas).selectDistinctOn(...args);292 const _with = (...args) => getReplica(replicas).with(...args);293 const $with = (arg) => getReplica(replicas).$with(arg);294 const update = (...args) => primary.update(...args);295 const insert = (...args) => primary.insert(...args);296 const $delete = (...args) => primary.delete(...args);297 const execute = (...args) => primary.execute(...args);298 const transaction = (...args) => primary.transaction(...args);299 return {300 ...primary,301 update,302 insert,303 delete: $delete,304 execute,305 transaction,306 // refreshMaterializedView,307 $primary: primary,308 $replicas: replicas,309 select,310 selectDistinct,311 selectDistinctOn,312 $with,313 with: _with,314 get query() {315 return getReplica(replicas).query;316 }317 };318};319export {320 GelDatabase,321 withReplicas322};323//# sourceMappingURL=db.js.map