@m1212e/rumble 0.18.9 → 0.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/out/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { t as lazy } from "./lazy-BgeBy3-B.mjs";
2
- import { t as generateFromSchema } from "./generate-BxAyU8HE.mjs";
1
+ import { t as lazy } from "./lazy-C7IyM4M4.mjs";
2
+ import { t as generateFromSchema } from "./generate-B4w-hX0K.mjs";
3
3
  import { GraphQLError } from "graphql";
4
4
  import { EnvelopArmorPlugin } from "@escape.tech/graphql-armor";
5
5
  import { useDisableIntrospection } from "@graphql-yoga/plugin-disable-introspection";
@@ -7,9 +7,9 @@ import { SpanStatusCode, trace } from "@opentelemetry/api";
7
7
  import { AttributeNames, SpanNames, createOpenTelemetryWrapper } from "@pothos/tracing-opentelemetry";
8
8
  import { capitalize, cloneDeep, debounce, merge, toMerged } from "es-toolkit";
9
9
  import { createPubSub, createYoga } from "graphql-yoga";
10
- import { One, count, relationsFilterToSQL, sql } from "drizzle-orm";
11
- import { CasingCache, toCamelCase } from "drizzle-orm/casing";
12
- import { PgEnumColumn, PgTable } from "drizzle-orm/pg-core";
10
+ import { One, count, getTableColumns, getTableName, is, isTable, relationsFilterToSQL, sql } from "drizzle-orm";
11
+ import { toCamelCase } from "drizzle-orm/casing";
12
+ import { PgColumn, PgEnumColumn, PgEnumObjectColumn, PgTable, isPgEnum } from "drizzle-orm/pg-core";
13
13
  import pluralize from "pluralize";
14
14
  import { MySqlTable } from "drizzle-orm/mysql-core";
15
15
  import { SQLiteTable } from "drizzle-orm/sqlite-core";
@@ -180,7 +180,7 @@ function mapNullFieldsToUndefined(obj) {
180
180
  }
181
181
  //#endregion
182
182
  //#region package.json
183
- var version = "0.18.9";
183
+ var version = "0.21.2";
184
184
  //#endregion
185
185
  //#region lib/helpers/mergeFilters.ts
186
186
  function mergeFilters(filterA, filterB, mode = "AND") {
@@ -300,26 +300,70 @@ function createDistinctValuesFromSQLType(sqlType) {
300
300
  }
301
301
  //#endregion
302
302
  //#region lib/helpers/tableHelpers.ts
303
- const drizzleNameSymbol = Symbol.for("drizzle:Name");
304
- const drizzleOriginalNameSymbol = Symbol.for("drizzle:OriginalName");
305
- const drizzleBaseNameSymbol = Symbol.for("drizzle:BaseName");
303
+ const indexCache = /* @__PURE__ */ new WeakMap();
304
+ function buildIndex(db) {
305
+ const byTsName = /* @__PURE__ */ new Map();
306
+ const byDbName = /* @__PURE__ */ new Map();
307
+ const byTableRef = /* @__PURE__ */ new Map();
308
+ for (const [tsName, rawEntry] of Object.entries(db._.relations ?? {})) {
309
+ const entry = rawEntry;
310
+ const tableObj = entry.table;
311
+ if (!tableObj) continue;
312
+ const columns = isTable(tableObj) ? getTableColumns(tableObj) : {};
313
+ const primaryKey = Object.fromEntries(Object.entries(columns).filter(([, col]) => col.primary));
314
+ const dbName = isTable(tableObj) ? getTableName(tableObj) : entry.name ?? tsName;
315
+ const resolved = {
316
+ name: entry.name ?? tsName,
317
+ dbName,
318
+ table: tableObj,
319
+ columns,
320
+ primaryKey,
321
+ relations: entry.relations ?? {},
322
+ foundRelation: entry
323
+ };
324
+ byTsName.set(resolved.name, resolved);
325
+ byDbName.set(resolved.dbName, resolved);
326
+ byTableRef.set(tableObj, resolved);
327
+ }
328
+ return {
329
+ byTsName,
330
+ byDbName,
331
+ byTableRef
332
+ };
333
+ }
334
+ function getIndex(db) {
335
+ let idx = indexCache.get(db);
336
+ if (!idx) {
337
+ idx = buildIndex(db);
338
+ indexCache.set(db, idx);
339
+ }
340
+ return idx;
341
+ }
306
342
  function tableHelper({ db, table }) {
307
- if (typeof table !== "string") table = table.tsName || table.dbName || table[drizzleNameSymbol] || table[drizzleOriginalNameSymbol] || table[drizzleBaseNameSymbol];
308
- const foundRelation = Object.values(db._.relations).find((schema) => schema.name === table || schema.table[drizzleNameSymbol] === table || schema.table[drizzleOriginalNameSymbol] === table || schema.table[drizzleBaseNameSymbol] === table);
309
- if (!foundRelation) throw new RumbleError(`Could not find schema for ${JSON.stringify(table)}`);
310
- const foundSchema = Object.values(db._.schema).find((schema) => schema.dbName === foundRelation.table[drizzleOriginalNameSymbol]);
311
- if (!foundSchema) throw new RumbleError(`Could not find schema for ${JSON.stringify(table)}`);
312
- const fullSchema = db._.fullSchema?.[foundSchema.tsName];
313
- if (!fullSchema) throw new RumbleError(`Could not find full schema for ${JSON.stringify(table)}`);
343
+ const idx = getIndex(db);
344
+ let entry;
345
+ if (typeof table === "string") entry = idx.byTsName.get(table) ?? idx.byDbName.get(table);
346
+ else if (table && typeof table === "object") {
347
+ const t = table;
348
+ if (t.table) {
349
+ entry = idx.byTableRef.get(t.table);
350
+ if (!entry && t.name) entry = idx.byTsName.get(t.name) ?? idx.byDbName.get(t.name);
351
+ }
352
+ if (!entry) entry = idx.byTableRef.get(t);
353
+ if (!entry && isTable(t)) {
354
+ const dbName = getTableName(t);
355
+ entry = idx.byDbName.get(dbName);
356
+ }
357
+ }
358
+ if (!entry) throw new RumbleError(`Could not find schema for ${JSON.stringify(typeof table === "string" ? table : "<table-object>")}`);
314
359
  return {
315
- columns: foundSchema.columns,
316
- primaryKey: foundSchema.primaryKey,
317
- relations: foundRelation.relations,
318
- dbName: foundSchema.dbName,
319
- tsName: foundSchema.tsName,
320
- foundSchema,
321
- foundRelation,
322
- fullSchema
360
+ columns: entry.columns,
361
+ primaryKey: entry.primaryKey,
362
+ relations: entry.relations,
363
+ dbName: entry.dbName,
364
+ tsName: entry.name,
365
+ table: entry.table,
366
+ foundRelation: entry.foundRelation
323
367
  };
324
368
  }
325
369
  //#endregion
@@ -472,7 +516,7 @@ by: (explicitFilter) => {
472
516
  return limit ?? void 0;
473
517
  });
474
518
  const sqlTransformedWhere = lazy(() => {
475
- const casing = db._.session?.dialect?.casing ?? new CasingCache();
519
+ const casing = db._.session?.dialect?.casing;
476
520
  return filters?.where ? relationsFilterToSQL(tableSchema.foundRelation.table, filters.where, tableSchema.relations, db._.relations, casing) : void 0;
477
521
  });
478
522
  if (filters?.columns) return {
@@ -673,9 +717,10 @@ const createOrderArgImplementer = ({ db, schemaBuilder }) => {
673
717
  return acc;
674
718
  }, {});
675
719
  const relations = Object.entries(tableSchema.relations ?? {}).reduce((acc, [key, value]) => {
720
+ const targetTsName = value.targetTableName;
676
721
  const referenceModel = orderArgImplementer({ dbName: tableHelper({
677
722
  db,
678
- table: value.targetTable
723
+ table: targetTsName
679
724
  }).dbName });
680
725
  acc[key] = t.field({
681
726
  type: referenceModel,
@@ -698,27 +743,45 @@ const createOrderArgImplementer = ({ db, schemaBuilder }) => {
698
743
  //#endregion
699
744
  //#region lib/enum.ts
700
745
  /**
701
- * Checks if a schema type is an enum
746
+ * Checks if a column is a Postgres enum column
702
747
  */
703
748
  function isEnumSchema(schemaType) {
704
- return schemaType instanceof PgEnumColumn;
749
+ return is(schemaType, PgEnumColumn) || is(schemaType, PgEnumObjectColumn);
705
750
  }
706
- const createEnumImplementer = ({ db, schemaBuilder }) => {
751
+ const createEnumImplementer = ({ schema, schemaBuilder }) => {
707
752
  const referenceStorage = /* @__PURE__ */ new Map();
708
- const enumImplementer = ({ tsName, enumColumn, refName }) => {
753
+ /**
754
+ * Registers a Postgres enum as a GraphQL enum type.
755
+ *
756
+ * You can identify the enum in three ways:
757
+ * - `tsName`: the exported TypeScript identifier from your schema module. This is the
758
+ * most typesafe form, only valid enum keys autocomplete, typos are caught at compile time.
759
+ * - `enum`: pass the pgEnum object directly.
760
+ * - `enumColumn`: pass a column that uses the enum.
761
+ *
762
+ * Use `refName` to override the auto-generated GraphQL type name.
763
+ */
764
+ const enumImplementer = (args) => {
765
+ const { refName } = args;
766
+ const tsName = args.tsName;
767
+ const enumObjectArg = args.enum;
768
+ const enumColumn = args.enumColumn;
769
+ let enumObject = enumObjectArg;
770
+ if (tsName) {
771
+ const candidate = schema[tsName];
772
+ if (!candidate || !isPgEnum(candidate)) throw new RumbleError(`Could not find a pgEnum exported as ${JSON.stringify(tsName)} in the provided schema. Make sure the identifier exists and refers to a value created with \`pgEnum(...)\`.`);
773
+ enumObject = candidate;
774
+ }
775
+ if (!enumObject && !enumColumn) throw new RumbleError("Could not determine enum structure! Pass one of 'tsName' (requires `schema` on rumble()), 'enum' (the pgEnum object), or 'enumColumn' (a column that uses the enum).");
709
776
  let enumSchemaName;
710
777
  let enumValues;
711
- if (tsName) {
712
- const schemaEnum = db._.fullSchema[tsName];
713
- enumSchemaName = tsName.toString();
714
- const enumCol = Object.values(db._.schema).filter((s) => typeof s === "object").map((s) => Object.values(s.columns)).flat(2).filter(isEnumSchema).find((e) => e.config.enum === schemaEnum);
715
- if (!enumCol) throw new RumbleError(`Could not find applied enum column for ${tsName.toString()}.
716
- Please ensure that you use the enum at least once as a column of a table!`);
717
- enumValues = enumCol.enumValues;
778
+ if (enumObject) {
779
+ enumSchemaName = enumObject.enumName;
780
+ enumValues = enumObject.enumValues;
718
781
  } else if (enumColumn) {
719
- const entry = Object.entries(db._.fullSchema).filter(([_, value]) => enumColumn.config.enum === value)[0];
720
- if (!entry) throw new RumbleError(`Could not find enum entry for ${enumColumn.config.name}.`);
721
- enumSchemaName = entry[0];
782
+ const pgEnum = enumColumn.enum;
783
+ if (!pgEnum) throw new RumbleError(`Could not find enum definition on column. Make sure the column is a pgEnum column.`);
784
+ enumSchemaName = pgEnum.enumName;
722
785
  enumValues = enumColumn.enumValues;
723
786
  }
724
787
  if (!enumSchemaName || !enumValues) throw new RumbleError("Could not determine enum structure!");
@@ -794,9 +857,10 @@ const createWhereArgImplementer = ({ db, schemaBuilder, enumImplementer }) => {
794
857
  return acc;
795
858
  }, {});
796
859
  const relations = Object.entries(tableSchema.relations ?? {}).reduce((acc, [key, value]) => {
860
+ const targetTsName = value.targetTableName;
797
861
  const referenceModel = whereArgImplementer({ dbName: tableHelper({
798
862
  db,
799
- table: value.targetTable
863
+ table: targetTsName
800
864
  }).dbName });
801
865
  acc[key] = t.field({
802
866
  type: referenceModel,
@@ -891,10 +955,10 @@ const createCountQueryImplementer = ({ db, schemaBuilder, whereArgImplementer, m
891
955
  type: WhereArg,
892
956
  required: false
893
957
  }) },
894
- resolve: async (root, args, ctx, info) => {
958
+ resolve: async (_root, args, ctx, _info) => {
895
959
  if (isAllowed && !await isAllowed(ctx)) throw new RumbleErrorSafe("Not allowed to perform this action");
896
960
  deepSetProto(args);
897
- return db.select({ count: count() }).from(tableSchema.fullSchema).where(ctx.abilities[table].filter(listAction).merge(mapNullFieldsToUndefined(args)).sql.where).then(assertFirstEntryExists).then((r) => r.count);
961
+ return db.select({ count: count() }).from(tableSchema.table).where(ctx.abilities[table].filter(listAction).merge(mapNullFieldsToUndefined(args)).sql.where).then(assertFirstEntryExists).then((r) => r.count);
898
962
  }
899
963
  }) };
900
964
  });
@@ -1018,16 +1082,23 @@ function buildPothosResponseTypeFromGraphQLType({ builder, sqlType, fieldName, n
1018
1082
  }
1019
1083
  //#endregion
1020
1084
  //#region lib/helpers/determineDialectFromSchema.ts
1085
+ const dialectCache = /* @__PURE__ */ new WeakMap();
1021
1086
  function determineDBDialectFromSchema(schema) {
1087
+ const cached = dialectCache.get(schema);
1088
+ if (cached) return cached;
1022
1089
  const found = /* @__PURE__ */ new Set();
1023
1090
  for (const table of Object.values(schema).map((t) => t.table)) {
1024
- if (typeof table !== "object") continue;
1025
- if (table instanceof PgTable) found.add("postgres");
1026
- else if (table instanceof MySqlTable) found.add("mysql");
1027
- else if (table instanceof SQLiteTable) found.add("sqlite");
1091
+ if (!table || typeof table !== "object") continue;
1092
+ if (is(table, PgTable)) found.add("postgres");
1093
+ else if (is(table, MySqlTable)) found.add("mysql");
1094
+ else if (is(table, SQLiteTable)) found.add("sqlite");
1028
1095
  }
1029
1096
  const dialects = Array.from(found);
1030
- if (dialects.length === 1) return dialects[0];
1097
+ if (dialects.length === 1) {
1098
+ const only = dialects[0];
1099
+ dialectCache.set(schema, only);
1100
+ return only;
1101
+ }
1031
1102
  if (dialects.length === 0) throw new Error("No tables found in schema, could not determine dialect");
1032
1103
  throw new Error(`Multiple dialects found in schema: ${dialects.join(", ")}`);
1033
1104
  }
@@ -1059,7 +1130,7 @@ async function initSearchIfApplicable(input) {
1059
1130
  */
1060
1131
  function adjustQueryArgsForSearch({ search, args, tableSchema, abilities }) {
1061
1132
  if (search?.enabled && args.search && args.search.length > 0) {
1062
- const columnsToSearch = (abilities.query.many.columns ? Object.entries(tableSchema.columns).filter(([key]) => abilities.query.many.columns[key]) : Object.entries(tableSchema.columns)).filter(([key, col]) => isStringLikeSQLTypeString(col.getSQLType()) || isIDLikeSQLTypeString(col.getSQLType()));
1133
+ const columnsToSearch = (abilities.query.many.columns ? Object.entries(tableSchema.columns).filter(([key]) => abilities.query.many.columns[key]) : Object.entries(tableSchema.columns)).filter(([_key, col]) => isStringLikeSQLTypeString(col.getSQLType()) || isIDLikeSQLTypeString(col.getSQLType()));
1063
1134
  const searchParam = sql`${args.search}`;
1064
1135
  args.extras = { search_distance: (table) => sql`${sql.join(columnsToSearch.map(([key]) => {
1065
1136
  return sql`COALESCE((${table[key]}::TEXT <-> ${searchParam}), 1)`;
@@ -1125,7 +1196,7 @@ const createObjectImplementer = ({ db, search, schemaBuilder, makePubSubInstance
1125
1196
  fields: (t) => {
1126
1197
  const columns = tableSchema.columns;
1127
1198
  const configMap = /* @__PURE__ */ new Map();
1128
- const userAdjustments = adjust?.(new Proxy(t, { get: (target, prop, receiver) => {
1199
+ const userAdjustments = adjust?.(new Proxy(t, { get: (target, prop, _receiver) => {
1129
1200
  if (typeof target[prop] !== "function" || prop === "arg" || prop === "builder" || prop === "graphqlKind" || prop === "kind" || prop === "listRef" || prop === "table" || prop === "typename" || prop === "variant" || prop.toString().startsWith("boolean") || prop.toString().startsWith("float") || prop.toString().startsWith("id") || prop.toString().startsWith("int") || prop.toString().startsWith("string") || prop.toString().startsWith("expose")) return target[prop];
1130
1201
  return (...params) => {
1131
1202
  const ref = target[prop](...params);
@@ -1147,9 +1218,12 @@ const createObjectImplementer = ({ db, search, schemaBuilder, makePubSubInstance
1147
1218
  return acc;
1148
1219
  }
1149
1220
  let isArray = false;
1150
- if (column.dimensions > 0) {
1151
- if (column.dimensions !== 1) throw new RumbleError("Only one-dimensional arrays are supported for default object implementation");
1152
- isArray = true;
1221
+ if (is(column, PgColumn)) {
1222
+ const dimensions = column.dimensions;
1223
+ if (dimensions && dimensions > 0) {
1224
+ if (dimensions !== 1) throw new RumbleError("Only one-dimensional arrays are supported for default object implementation");
1225
+ isArray = true;
1226
+ }
1153
1227
  }
1154
1228
  if (isEnumSchema(column)) {
1155
1229
  const enumImpl = enumImplementer({ enumColumn: column });
@@ -1168,9 +1242,10 @@ const createObjectImplementer = ({ db, search, schemaBuilder, makePubSubInstance
1168
1242
  return acc;
1169
1243
  }, {});
1170
1244
  const relations = Object.entries(tableSchema.relations ?? {}).reduce((acc, [key, value]) => {
1245
+ const targetTsName = value.targetTableName;
1171
1246
  const relationSchema = tableHelper({
1172
1247
  db,
1173
- table: value.targetTable
1248
+ table: targetTsName
1174
1249
  });
1175
1250
  const WhereArg = whereArgImplementer({ dbName: relationSchema.dbName });
1176
1251
  const OrderArg = orderArgImplementer({ dbName: relationSchema.dbName });
@@ -1178,7 +1253,7 @@ const createObjectImplementer = ({ db, search, schemaBuilder, makePubSubInstance
1178
1253
  let nullable = false;
1179
1254
  let isMany = true;
1180
1255
  let filterSpecifier = "many";
1181
- if (value instanceof One) {
1256
+ if (is(value, One)) {
1182
1257
  isMany = false;
1183
1258
  nullable = value.optional || !value.sourceColumns.every((column) => column.notNull);
1184
1259
  filterSpecifier = "single";
@@ -1246,7 +1321,7 @@ const createObjectImplementer = ({ db, search, schemaBuilder, makePubSubInstance
1246
1321
  fields.search_distance = t.float({
1247
1322
  description: "The search distance of the object. If a search is provided, this field will be populated with the search distance.",
1248
1323
  nullable: true,
1249
- resolve: (parent, args, ctx, info) => parent.search_distance
1324
+ resolve: (parent, _args, _ctx, _info) => parent.search_distance
1250
1325
  });
1251
1326
  }
1252
1327
  return {
@@ -1611,9 +1686,10 @@ const createSchemaBuilder = ({ db, disableDefaultObjects, pubsub, pothosConfig,
1611
1686
  client: db,
1612
1687
  relations: db._.relations,
1613
1688
  getTableConfig(table) {
1689
+ const columns = isTable(table) ? Object.values(getTableColumns(table)) : [];
1614
1690
  return {
1615
- columns: Object.values(table[Symbol.for("drizzle:Columns")]),
1616
- primaryKeys: Object.values(table[Symbol.for("drizzle:Columns")]).filter((v) => v.primary)
1691
+ columns,
1692
+ primaryKeys: columns.filter((v) => v.primary)
1617
1693
  };
1618
1694
  }
1619
1695
  },
@@ -1639,19 +1715,6 @@ const createSchemaBuilder = ({ db, disableDefaultObjects, pubsub, pothosConfig,
1639
1715
  //#endregion
1640
1716
  //#region lib/rumble.ts
1641
1717
  const rumble = (rumbleInput) => {
1642
- if (!rumbleInput.db._.schema) throw new RumbleError(`
1643
- rumble could not find any schema in the provided drizzle instance.
1644
- Make sure you import the schema and pass it to the drizzle instance:
1645
-
1646
- export const db = drizzle(
1647
- "postgres://postgres:postgres@localhost:5432/postgres",
1648
- {
1649
- relations,
1650
- schema, // <--- add this line
1651
- },
1652
- );
1653
-
1654
- `);
1655
1718
  if (!rumbleInput.db._.relations) throw new RumbleError(`
1656
1719
  rumble could not find any relations in the provided drizzle instance.
1657
1720
  Make sure you import the relations and pass them to the drizzle instance:
@@ -1660,10 +1723,21 @@ export const db = drizzle(
1660
1723
  "postgres://postgres:postgres@localhost:5432/postgres",
1661
1724
  {
1662
1725
  relations, // <--- add this line
1663
- schema,
1664
1726
  },
1665
1727
  );
1666
1728
 
1729
+ `);
1730
+ if (!rumbleInput.schema || typeof rumbleInput.schema !== "object" || Object.keys(rumbleInput.schema).length === 0) throw new RumbleError(`
1731
+ rumble requires the drizzle schema object to be passed when initializing.
1732
+ Import your schema module and pass it alongside \`db\`:
1733
+
1734
+ import * as schema from "./db/schema";
1735
+
1736
+ export const r = rumble({
1737
+ db,
1738
+ schema, // <--- add this line
1739
+ });
1740
+
1667
1741
  `);
1668
1742
  if (!rumbleInput.actions) rumbleInput.actions = [
1669
1743
  "read",