@m1212e/rumble 0.23.11 → 0.23.14
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.cjs +64 -56
- package/out/index.cjs.map +1 -1
- package/out/index.d.cts +29 -22
- package/out/index.d.cts.map +1 -1
- package/out/index.d.mts +29 -22
- package/out/index.d.mts.map +1 -1
- package/out/index.mjs +63 -56
- package/out/index.mjs.map +1 -1
- package/package.json +2 -1
package/out/index.mjs
CHANGED
|
@@ -18,6 +18,7 @@ import DrizzlePlugin from "@pothos/plugin-drizzle";
|
|
|
18
18
|
import SmartSubscriptionsPlugin, { subscribeOptionsFromIterator } from "@pothos/plugin-smart-subscriptions";
|
|
19
19
|
import TracingPlugin, { isRootField, wrapResolver } from "@pothos/plugin-tracing";
|
|
20
20
|
import { BigIntResolver, ByteResolver, DateResolver, DateTimeISOResolver, JSONResolver } from "graphql-scalars";
|
|
21
|
+
import DataLoader from "dataloader";
|
|
21
22
|
//#region lib/types/rumbleError.ts
|
|
22
23
|
/**
|
|
23
24
|
* An error that gets raised by rumble whenever something does not go according to plan.
|
|
@@ -180,7 +181,7 @@ function mapNullFieldsToUndefined(obj) {
|
|
|
180
181
|
}
|
|
181
182
|
//#endregion
|
|
182
183
|
//#region package.json
|
|
183
|
-
var version = "0.23.
|
|
184
|
+
var version = "0.23.14";
|
|
184
185
|
//#endregion
|
|
185
186
|
//#region lib/helpers/mergeFilters.ts
|
|
186
187
|
const EmptyFilter$1 = Symbol.for("drizzle:EmptyFilter");
|
|
@@ -390,6 +391,7 @@ function buildIndex(db) {
|
|
|
390
391
|
columns,
|
|
391
392
|
primaryKey,
|
|
392
393
|
relations: entry.relations ?? {},
|
|
394
|
+
isTable: isTable(tableObj),
|
|
393
395
|
foundRelation: entry
|
|
394
396
|
};
|
|
395
397
|
byTsName.set(resolved.name, resolved);
|
|
@@ -434,6 +436,7 @@ function tableHelper({ db, table }) {
|
|
|
434
436
|
dbName: entry.dbName,
|
|
435
437
|
tsName: entry.name,
|
|
436
438
|
table: entry.table,
|
|
439
|
+
isTable: entry.isTable,
|
|
437
440
|
foundRelation: entry.foundRelation
|
|
438
441
|
};
|
|
439
442
|
}
|
|
@@ -456,6 +459,10 @@ const makeNothingRegisteredWarner = (logger) => debounce((model, action) => {
|
|
|
456
459
|
const createAbilityBuilder = ({ db, actions, defaultLimit, otel, logger: loggerConfig }) => {
|
|
457
460
|
const log = loggerConfig?.enabled ? loggerConfig.logger : void 0;
|
|
458
461
|
const nothingRegisteredWarningLogger = makeNothingRegisteredWarner(log);
|
|
462
|
+
const tableRelationNames = Object.keys(db.query).filter((name) => tableHelper({
|
|
463
|
+
db,
|
|
464
|
+
table: name
|
|
465
|
+
}).isTable);
|
|
459
466
|
let hasBeenBuilt = false;
|
|
460
467
|
const createBuilderForTable = () => {
|
|
461
468
|
const queryFilters = /* @__PURE__ */ new Map();
|
|
@@ -541,7 +548,7 @@ by: (explicitFilter) => {
|
|
|
541
548
|
}
|
|
542
549
|
};
|
|
543
550
|
};
|
|
544
|
-
const buildersPerTable = Object.fromEntries(
|
|
551
|
+
const buildersPerTable = Object.fromEntries(tableRelationNames.map((tableName) => [tableName, createBuilderForTable()]));
|
|
545
552
|
return {
|
|
546
553
|
...buildersPerTable,
|
|
547
554
|
/**
|
|
@@ -569,7 +576,7 @@ by: (explicitFilter) => {
|
|
|
569
576
|
db,
|
|
570
577
|
table: tableName
|
|
571
578
|
});
|
|
572
|
-
if (Object.keys(tableSchema.primaryKey).length === 0) throw new RumbleError(`No primary key found for entity ${tableName
|
|
579
|
+
if (Object.keys(tableSchema.primaryKey).length === 0) throw new RumbleError(`No primary key found for entity ${String(tableName)}`);
|
|
573
580
|
const primaryKeyField = Object.values(tableSchema.primaryKey)[0];
|
|
574
581
|
const distinctValues = createDistinctValuesFromSQLType(primaryKeyField.getSQLType());
|
|
575
582
|
const blockEverythingFilter = { where: { AND: [{ [primaryKeyField.name]: distinctValues.value1 }, { [primaryKeyField.name]: distinctValues.value2 }] } };
|
|
@@ -719,7 +726,7 @@ by: (explicitFilter) => {
|
|
|
719
726
|
}
|
|
720
727
|
if (!filters) {
|
|
721
728
|
span?.setAttribute("abilities.status", "blocked_everything");
|
|
722
|
-
nothingRegisteredWarningLogger(tableName
|
|
729
|
+
nothingRegisteredWarningLogger(String(tableName), action);
|
|
723
730
|
return transformToResponse(blockEverythingFilter);
|
|
724
731
|
}
|
|
725
732
|
const dynamicResults = new Array(dynamicQueryFilters[action].length);
|
|
@@ -748,10 +755,10 @@ by: (explicitFilter) => {
|
|
|
748
755
|
};
|
|
749
756
|
if (otel?.enabled && otel.tracer) return otel.tracer.startActiveSpan(`rumble.abilities.prepare`, (span) => {
|
|
750
757
|
span.setAttribute("rumble.action", action);
|
|
751
|
-
span.setAttribute("rumble.table", tableName
|
|
758
|
+
span.setAttribute("rumble.table", String(tableName));
|
|
752
759
|
try {
|
|
753
760
|
const attrs = {
|
|
754
|
-
"rumble.table": tableName
|
|
761
|
+
"rumble.table": String(tableName),
|
|
755
762
|
"rumble.action": action
|
|
756
763
|
};
|
|
757
764
|
const proxy = new Proxy(span, { get(target, prop) {
|
|
@@ -770,7 +777,7 @@ by: (explicitFilter) => {
|
|
|
770
777
|
});
|
|
771
778
|
else {
|
|
772
779
|
const attrs = {
|
|
773
|
-
"rumble.table": tableName
|
|
780
|
+
"rumble.table": String(tableName),
|
|
774
781
|
"rumble.action": action
|
|
775
782
|
};
|
|
776
783
|
const result = assembleAbilities(log ? { setAttribute: (k, v) => {
|
|
@@ -782,10 +789,10 @@ by: (explicitFilter) => {
|
|
|
782
789
|
} };
|
|
783
790
|
} };
|
|
784
791
|
};
|
|
785
|
-
const abilitiesPerTable = Object.fromEntries(
|
|
792
|
+
const abilitiesPerTable = Object.fromEntries(tableRelationNames.map((tableName) => [tableName, createFilterForTable(tableName)]));
|
|
786
793
|
hasBeenBuilt = true;
|
|
787
794
|
return (ctx) => {
|
|
788
|
-
return Object.fromEntries(
|
|
795
|
+
return Object.fromEntries(tableRelationNames.map((tableName) => [tableName, abilitiesPerTable[tableName].withContext(ctx)]));
|
|
789
796
|
};
|
|
790
797
|
}
|
|
791
798
|
}
|
|
@@ -1191,11 +1198,11 @@ const createCountQueryImplementer = ({ db, schemaBuilder, whereArgImplementer, m
|
|
|
1191
1198
|
table
|
|
1192
1199
|
});
|
|
1193
1200
|
return schemaBuilder.queryFields((t) => {
|
|
1194
|
-
return { [`${pluralize.plural(table
|
|
1201
|
+
return { [`${pluralize.plural(String(table))}Count`]: t.field({
|
|
1195
1202
|
type: "Int",
|
|
1196
1203
|
nullable: false,
|
|
1197
1204
|
smartSubscription: true,
|
|
1198
|
-
description: `Count all ${pluralize.plural(table
|
|
1205
|
+
description: `Count all ${pluralize.plural(String(table))}`,
|
|
1199
1206
|
subscribe: (subscriptions, _root, _args, _ctx, _info) => {
|
|
1200
1207
|
registerOnInstance({
|
|
1201
1208
|
instance: subscriptions,
|
|
@@ -1662,20 +1669,20 @@ const createObjectImplementer = ({ db, search, logger: loggerConfig, schemaBuild
|
|
|
1662
1669
|
});
|
|
1663
1670
|
if (Object.keys(tableSchema.primaryKey).length === 0) {
|
|
1664
1671
|
const log = loggerConfig?.enabled ? loggerConfig.logger : void 0;
|
|
1665
|
-
const msg = `Could not find primary key for ${table
|
|
1666
|
-
log ? log.warn({ "rumble.table": table
|
|
1672
|
+
const msg = `Could not find primary key for ${String(table)}. Cannot register subscriptions!`;
|
|
1673
|
+
log ? log.warn({ "rumble.table": String(table) }, msg) : console.warn(msg);
|
|
1667
1674
|
}
|
|
1668
1675
|
const primaryKey = Object.values(tableSchema.primaryKey)[0];
|
|
1669
1676
|
const { registerOnInstance } = makePubSubInstance({ table });
|
|
1670
1677
|
return schemaBuilder.drizzleObject(table, {
|
|
1671
|
-
name: refName ?? capitalize(table
|
|
1678
|
+
name: refName ?? capitalize(String(table)),
|
|
1672
1679
|
subscribe: (subscriptions, element, _context) => {
|
|
1673
1680
|
if (!primaryKey) return;
|
|
1674
1681
|
const primaryKeyValue = element[primaryKey.name];
|
|
1675
1682
|
if (!primaryKeyValue) {
|
|
1676
1683
|
const log = loggerConfig?.enabled ? loggerConfig.logger : void 0;
|
|
1677
|
-
const msg = `Could not find primary key value for element on ${table
|
|
1678
|
-
log ? log.warn({ "rumble.table": table
|
|
1684
|
+
const msg = `Could not find primary key value for element on ${String(table)}. Cannot register subscription!`;
|
|
1685
|
+
log ? log.warn({ "rumble.table": String(table) }, msg) : console.warn(msg);
|
|
1679
1686
|
return;
|
|
1680
1687
|
}
|
|
1681
1688
|
registerOnInstance({
|
|
@@ -1921,10 +1928,10 @@ const createQueryImplementer = ({ db, schemaBuilder, search, logger: loggerConfi
|
|
|
1921
1928
|
});
|
|
1922
1929
|
const primaryKeyField = Object.values(tableSchema.primaryKey)[0];
|
|
1923
1930
|
const { registerOnInstance } = makePubSubInstance({ table });
|
|
1924
|
-
const pluralName = pluralize.plural(table
|
|
1925
|
-
const singularName = pluralize.singular(table
|
|
1931
|
+
const pluralName = pluralize.plural(String(table));
|
|
1932
|
+
const singularName = pluralize.singular(String(table));
|
|
1926
1933
|
for (const name of [pluralName, singularName]) {
|
|
1927
|
-
if (registeredQueryFieldNames.has(name)) throw new RumbleError(`Duplicate query field "${name}": the table "${table
|
|
1934
|
+
if (registeredQueryFieldNames.has(name)) throw new RumbleError(`Duplicate query field "${name}": the table "${String(table)}" generates a query field that collides with one already registered. Use unique table names (or refNames) to avoid plural/singular collisions (e.g. "post" and "posts").`);
|
|
1928
1935
|
registeredQueryFieldNames.add(name);
|
|
1929
1936
|
}
|
|
1930
1937
|
return schemaBuilder.queryFields((t) => {
|
|
@@ -2275,6 +2282,30 @@ var RuntimeFiltersPlugin = class extends BasePlugin {
|
|
|
2275
2282
|
tracer;
|
|
2276
2283
|
tracerEnabled;
|
|
2277
2284
|
logger;
|
|
2285
|
+
filterLoaders = /* @__PURE__ */ new WeakMap();
|
|
2286
|
+
getLoader(context, filter) {
|
|
2287
|
+
let perContext = this.filterLoaders.get(context);
|
|
2288
|
+
if (!perContext) {
|
|
2289
|
+
perContext = /* @__PURE__ */ new Map();
|
|
2290
|
+
this.filterLoaders.set(context, perContext);
|
|
2291
|
+
}
|
|
2292
|
+
let loader = perContext.get(filter);
|
|
2293
|
+
if (!loader) {
|
|
2294
|
+
const prefetchPromise = filter.prefetch ? filter.prefetch({ context }) : void 0;
|
|
2295
|
+
loader = new DataLoader(async (entities) => {
|
|
2296
|
+
const prefetched = prefetchPromise ? await prefetchPromise : void 0;
|
|
2297
|
+
const allowed = await filter.filter({
|
|
2298
|
+
context,
|
|
2299
|
+
entities,
|
|
2300
|
+
prefetched
|
|
2301
|
+
});
|
|
2302
|
+
const allowedSet = new Set(allowed);
|
|
2303
|
+
return entities.map((entity) => allowedSet.has(entity) ? entity : null);
|
|
2304
|
+
}, { cache: false });
|
|
2305
|
+
perContext.set(filter, loader);
|
|
2306
|
+
}
|
|
2307
|
+
return loader;
|
|
2308
|
+
}
|
|
2278
2309
|
onTypeConfig(typeConfig) {
|
|
2279
2310
|
this.tracer = this.builder.options.otel?.tracer;
|
|
2280
2311
|
this.tracerEnabled = this.builder.options.otel?.enabled;
|
|
@@ -2291,44 +2322,20 @@ var RuntimeFiltersPlugin = class extends BasePlugin {
|
|
|
2291
2322
|
const runFilters = async (span) => {
|
|
2292
2323
|
const allFilters = Array.isArray(filters) ? filters : [filters];
|
|
2293
2324
|
span?.setAttribute("filters.total", allFilters.length);
|
|
2294
|
-
const
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2325
|
+
const loaders = allFilters.map((filter) => this.getLoader(context, filter));
|
|
2326
|
+
let resolved;
|
|
2327
|
+
if (this.tracer && this.tracerEnabled) resolved = await this.tracer.startActiveSpan(`rumble.filter.resolve`, async (span) => {
|
|
2328
|
+
span.setAttribute("graphql.field.name", fieldConfig.name);
|
|
2329
|
+
try {
|
|
2330
|
+
return await resolver(parent, args, context, info);
|
|
2331
|
+
} finally {
|
|
2332
|
+
span.end();
|
|
2302
2333
|
}
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
let resolved, prefetchedFilters;
|
|
2309
|
-
if (this.tracer && this.tracerEnabled) {
|
|
2310
|
-
const o = await this.tracer.startActiveSpan(`rumble.filter.resolve`, async (span) => {
|
|
2311
|
-
span.setAttribute("graphql.field.name", fieldConfig.name);
|
|
2312
|
-
try {
|
|
2313
|
-
return await Promise.all([resolver(parent, args, context, info), prefetchedFiltersPromises]);
|
|
2314
|
-
} finally {
|
|
2315
|
-
span.end();
|
|
2316
|
-
}
|
|
2317
|
-
});
|
|
2318
|
-
resolved = o[0];
|
|
2319
|
-
prefetchedFilters = o[1];
|
|
2320
|
-
} else {
|
|
2321
|
-
const o = await Promise.all([resolver(parent, args, context, info), prefetchedFiltersPromises]);
|
|
2322
|
-
resolved = o[0];
|
|
2323
|
-
prefetchedFilters = o[1];
|
|
2324
|
-
}
|
|
2325
|
-
const allowed = Array.from((await Promise.all(prefetchedFilters.map((f) => f({
|
|
2326
|
-
context,
|
|
2327
|
-
entities: Array.isArray(resolved) ? resolved : [resolved]
|
|
2328
|
-
})))).reduce((acc, val) => {
|
|
2329
|
-
for (const element of val) acc.add(element);
|
|
2330
|
-
return acc;
|
|
2331
|
-
}, /* @__PURE__ */ new Set()));
|
|
2334
|
+
});
|
|
2335
|
+
else resolved = await resolver(parent, args, context, info);
|
|
2336
|
+
const entities = Array.isArray(resolved) ? resolved : [resolved];
|
|
2337
|
+
const perFilterResults = await Promise.all(loaders.map((loader) => Promise.all(entities.map((entity) => loader.load(entity)))));
|
|
2338
|
+
const allowed = entities.filter((_, index) => perFilterResults.some((results) => results[index] != null));
|
|
2332
2339
|
span?.setAttribute("filters.allowed", allowed.length);
|
|
2333
2340
|
this.logger?.debug({
|
|
2334
2341
|
"graphql.field.name": fieldConfig.name,
|