@m1212e/rumble 0.12.12 → 0.12.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/README.md +10 -5
- package/out/index.cjs +70 -28
- package/out/index.cjs.map +1 -1
- package/out/index.d.cts +25 -13
- package/out/index.d.cts.map +1 -1
- package/out/{index.d.ts → index.d.mts} +26 -14
- package/out/index.d.mts.map +1 -0
- package/out/{index.js → index.mjs} +73 -16
- package/out/index.mjs.map +1 -0
- package/package.json +14 -14
- package/out/index.d.ts.map +0 -1
- package/out/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -129,10 +129,10 @@ rumble({
|
|
|
129
129
|
## Helpers
|
|
130
130
|
Rumble offers various helpers to make it easy and fast to implement your api. Ofcourse you can write your api by hand using the provided `schemaBuilder` from the rumble initiator, but since this might get repetitive, the provided helpers automate a lot of this work for you while also automatically applying the concepts of rumble directly into your api.
|
|
131
131
|
|
|
132
|
-
###
|
|
133
|
-
`
|
|
132
|
+
### whereArg
|
|
133
|
+
`whereArg` is a helper to implement query arguments for filtering the results of a query for certain results. In many cases you would implement arguments for a query with something as `matchUsername: t.arg.string()` which is supposed to restrict the query to users which have that username. The whereArg helper implements such a filter tailored to the specific entity which you then can directly pass on to the database query.
|
|
134
134
|
```ts
|
|
135
|
-
const WhereArgs =
|
|
135
|
+
const WhereArgs = whereArg({
|
|
136
136
|
table: "posts",
|
|
137
137
|
});
|
|
138
138
|
|
|
@@ -210,6 +210,9 @@ const enumRef = enum_({
|
|
|
210
210
|
```
|
|
211
211
|
> The enum parameter allows other fields to be used to reference an enum. This is largely due to how this is used internally. Because of the way how drizzle handles enums, we are not able to provide type safety with enums. In case you actually need to use it, the above way is the recommended approach.
|
|
212
212
|
|
|
213
|
+
### and more...
|
|
214
|
+
See [the example file](./example/src/main.ts) or clone it and let intellisense guide you. Rumble offers various other helpers which might become handy!
|
|
215
|
+
|
|
213
216
|
## Running the server
|
|
214
217
|
In case you directly want to run a server from your rumble instance, you can do so by using the `createYoga` function. It returns a graphql `yoga` instance which can be used to provide a graphql api in [a multitude of ways](https://the-guild.dev/graphql/yoga-server/docs/integrations/z-other-environments).
|
|
215
218
|
```ts
|
|
@@ -242,7 +245,9 @@ await clientCreator({
|
|
|
242
245
|
// to point to your custom client
|
|
243
246
|
});
|
|
244
247
|
```
|
|
245
|
-
> The client uses [urql](https://nearform.com/open-source/urql/docs/basics/core/) under the hood. If you would like more info on how the internals work, please see
|
|
248
|
+
> The client uses [urql](https://nearform.com/open-source/urql/docs/basics/core/) under the hood. If you would like more info on how the internals work, please see their docs.
|
|
249
|
+
|
|
250
|
+
This way of generating code is especially helpful in monorepos, where it is convenient to output client code when running the server during development. If you do not use a monorepo and want to decouple the generation process, see below.
|
|
246
251
|
|
|
247
252
|
An example usage might look like this:
|
|
248
253
|
```ts
|
|
@@ -272,7 +277,7 @@ users.subscribe((s) => s?.at(0));
|
|
|
272
277
|
// you can directly access the values of an awaited result
|
|
273
278
|
console.log(users.firstName)
|
|
274
279
|
```
|
|
275
|
-
### Alternative
|
|
280
|
+
### Alternative decoupled client generation
|
|
276
281
|
As an alternative to use the client generator with a fully instanciated rumble instance, you can also import the `generateFromSchema` function from rumble and pass it a standard `GraphQLSchema` object to generate the client:
|
|
277
282
|
```ts
|
|
278
283
|
import { generateFromSchema } from "@m1212e/rumble";
|
package/out/index.cjs
CHANGED
|
@@ -22,35 +22,21 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
|
|
23
23
|
//#endregion
|
|
24
24
|
let node_fs_promises = require("node:fs/promises");
|
|
25
|
-
node_fs_promises = __toESM(node_fs_promises);
|
|
26
25
|
let node_path = require("node:path");
|
|
27
|
-
node_path = __toESM(node_path);
|
|
28
26
|
let graphql = require("graphql");
|
|
29
|
-
graphql = __toESM(graphql);
|
|
30
27
|
let es_toolkit = require("es-toolkit");
|
|
31
|
-
es_toolkit = __toESM(es_toolkit);
|
|
32
28
|
let wonka = require("wonka");
|
|
33
|
-
wonka = __toESM(wonka);
|
|
34
29
|
let __escape_tech_graphql_armor = require("@escape.tech/graphql-armor");
|
|
35
|
-
__escape_tech_graphql_armor = __toESM(__escape_tech_graphql_armor);
|
|
36
30
|
let __graphql_yoga_plugin_disable_introspection = require("@graphql-yoga/plugin-disable-introspection");
|
|
37
|
-
__graphql_yoga_plugin_disable_introspection = __toESM(__graphql_yoga_plugin_disable_introspection);
|
|
38
31
|
let graphql_yoga = require("graphql-yoga");
|
|
39
|
-
graphql_yoga = __toESM(graphql_yoga);
|
|
40
32
|
let sofa_api = require("sofa-api");
|
|
41
|
-
sofa_api = __toESM(sofa_api);
|
|
42
33
|
let drizzle_orm = require("drizzle-orm");
|
|
43
|
-
drizzle_orm = __toESM(drizzle_orm);
|
|
44
34
|
let drizzle_orm_casing = require("drizzle-orm/casing");
|
|
45
|
-
drizzle_orm_casing = __toESM(drizzle_orm_casing);
|
|
46
35
|
let drizzle_orm_pg_core = require("drizzle-orm/pg-core");
|
|
47
|
-
drizzle_orm_pg_core = __toESM(drizzle_orm_pg_core);
|
|
48
36
|
let pluralize = require("pluralize");
|
|
49
37
|
pluralize = __toESM(pluralize);
|
|
50
38
|
let drizzle_orm_mysql_core = require("drizzle-orm/mysql-core");
|
|
51
|
-
drizzle_orm_mysql_core = __toESM(drizzle_orm_mysql_core);
|
|
52
39
|
let drizzle_orm_sqlite_core = require("drizzle-orm/sqlite-core");
|
|
53
|
-
drizzle_orm_sqlite_core = __toESM(drizzle_orm_sqlite_core);
|
|
54
40
|
let __pothos_core = require("@pothos/core");
|
|
55
41
|
__pothos_core = __toESM(__pothos_core);
|
|
56
42
|
let __pothos_plugin_drizzle = require("@pothos/plugin-drizzle");
|
|
@@ -58,7 +44,6 @@ __pothos_plugin_drizzle = __toESM(__pothos_plugin_drizzle);
|
|
|
58
44
|
let __pothos_plugin_smart_subscriptions = require("@pothos/plugin-smart-subscriptions");
|
|
59
45
|
__pothos_plugin_smart_subscriptions = __toESM(__pothos_plugin_smart_subscriptions);
|
|
60
46
|
let graphql_scalars = require("graphql-scalars");
|
|
61
|
-
graphql_scalars = __toESM(graphql_scalars);
|
|
62
47
|
|
|
63
48
|
//#region lib/client/generate/client.ts
|
|
64
49
|
function generateClient({ apiUrl, rumbleImportPath, useExternalUrqlClient, availableSubscriptions }) {
|
|
@@ -259,25 +244,21 @@ function makeGraphQLQuery({ queryName, input, client, enableSubscription = false
|
|
|
259
244
|
const argsString = stringifyArgumentObjectToGraphqlList(input[argsKey] ?? {});
|
|
260
245
|
const operationString = (operationVerb) => `${operationVerb} ${otwQueryName} { ${queryName}${argsString} { ${stringifySelection(input)} }}`;
|
|
261
246
|
let awaitedReturnValueReference;
|
|
262
|
-
const
|
|
247
|
+
const observable = (0, wonka.pipe)((0, wonka.merge)([client.query(operationString("query"), {}), enableSubscription ? client.subscription(operationString("subscription"), {}) : wonka.empty]), (0, wonka.map)((v) => {
|
|
263
248
|
const data = v.data?.[queryName];
|
|
264
249
|
if (!data && v.error) throw v.error;
|
|
265
250
|
return data;
|
|
266
251
|
}), (0, wonka.onPush)((data) => {
|
|
267
252
|
if (awaitedReturnValueReference) Object.assign(awaitedReturnValueReference, data);
|
|
268
|
-
}));
|
|
253
|
+
}), wonka.toObservable);
|
|
269
254
|
const promise = new Promise((resolve) => {
|
|
270
|
-
const unsub =
|
|
255
|
+
const unsub = observable.subscribe((v) => {
|
|
271
256
|
unsub();
|
|
272
|
-
|
|
273
|
-
awaitedReturnValueReference = {
|
|
274
|
-
...v,
|
|
275
|
-
...newObservableWithAwaitedValue
|
|
276
|
-
};
|
|
257
|
+
awaitedReturnValueReference = Object.assign(v, observable);
|
|
277
258
|
resolve(awaitedReturnValueReference);
|
|
278
259
|
}).unsubscribe;
|
|
279
260
|
});
|
|
280
|
-
Object.assign(promise,
|
|
261
|
+
Object.assign(promise, observable);
|
|
281
262
|
return promise;
|
|
282
263
|
}
|
|
283
264
|
function makeGraphQLMutation({ mutationName, input, client }) {
|
|
@@ -716,6 +697,8 @@ function tableHelper({ db, table }) {
|
|
|
716
697
|
if (!foundRelation) throw new RumbleError(`Could not find schema for ${JSON.stringify(table)}`);
|
|
717
698
|
const foundSchema = Object.values(db._.schema).find((schema) => schema.dbName === foundRelation.table[drizzleOriginalNameSymbol]);
|
|
718
699
|
if (!foundSchema) throw new RumbleError(`Could not find schema for ${JSON.stringify(table)}`);
|
|
700
|
+
const fullSchema = db._.fullSchema?.[foundSchema.tsName];
|
|
701
|
+
if (!fullSchema) throw new RumbleError(`Could not find full schema for ${JSON.stringify(table)}`);
|
|
719
702
|
return {
|
|
720
703
|
columns: foundSchema.columns,
|
|
721
704
|
primaryKey: foundSchema.primaryKey,
|
|
@@ -723,7 +706,8 @@ function tableHelper({ db, table }) {
|
|
|
723
706
|
dbName: foundSchema.dbName,
|
|
724
707
|
tsName: foundSchema.tsName,
|
|
725
708
|
foundSchema,
|
|
726
|
-
foundRelation
|
|
709
|
+
foundRelation,
|
|
710
|
+
fullSchema
|
|
727
711
|
};
|
|
728
712
|
}
|
|
729
713
|
|
|
@@ -1078,6 +1062,7 @@ const createWhereArgImplementer = ({ db, schemaBuilder, enumImplementer }) => {
|
|
|
1078
1062
|
const clientCreatorImplementer = ({ builtSchema }) => {
|
|
1079
1063
|
if (process.env.NODE_ENV !== "development") console.warn("Running rumble client generation in non development mode. Are you sure this is correct?");
|
|
1080
1064
|
const clientCreator = async ({ apiUrl, outputPath, rumbleImportPath, useExternalUrqlClient }) => {
|
|
1065
|
+
if (process.env.NODE_ENV !== "development") console.warn("Running rumble client generation in non development mode. Are you sure this is correct?");
|
|
1081
1066
|
await generateFromSchema({
|
|
1082
1067
|
schema: builtSchema(),
|
|
1083
1068
|
outputPath,
|
|
@@ -1102,6 +1087,56 @@ const createContextFunction = ({ context: makeUserContext, abilityBuilder }) =>
|
|
|
1102
1087
|
};
|
|
1103
1088
|
};
|
|
1104
1089
|
|
|
1090
|
+
//#endregion
|
|
1091
|
+
//#region lib/helpers/protoMapper.ts
|
|
1092
|
+
function deepSetProto(obj, proto = Object.prototype, seen = /* @__PURE__ */ new WeakSet()) {
|
|
1093
|
+
if (obj === null || typeof obj !== "object") return;
|
|
1094
|
+
if (seen.has(obj)) return;
|
|
1095
|
+
seen.add(obj);
|
|
1096
|
+
Object.setPrototypeOf(obj, proto);
|
|
1097
|
+
for (const key of Object.keys(obj)) deepSetProto(obj[key], proto, seen);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
//#endregion
|
|
1101
|
+
//#region lib/countQuery.ts
|
|
1102
|
+
const createCountQueryImplementer = ({ db, schemaBuilder, whereArgImplementer, makePubSubInstance }) => {
|
|
1103
|
+
return ({ table, listAction = "read", isAllowed }) => {
|
|
1104
|
+
const WhereArg = whereArgImplementer({ table });
|
|
1105
|
+
const { registerOnInstance } = makePubSubInstance({ table });
|
|
1106
|
+
const tableSchema = tableHelper({
|
|
1107
|
+
db,
|
|
1108
|
+
table
|
|
1109
|
+
});
|
|
1110
|
+
return schemaBuilder.queryFields((t) => {
|
|
1111
|
+
return { [`${pluralize.default.plural(table.toString())}Count`]: t.field({
|
|
1112
|
+
type: "Int",
|
|
1113
|
+
nullable: false,
|
|
1114
|
+
smartSubscription: true,
|
|
1115
|
+
description: `Count all ${pluralize.default.plural(table.toString())}`,
|
|
1116
|
+
subscribe: (subscriptions, _root, _args, _ctx, _info) => {
|
|
1117
|
+
registerOnInstance({
|
|
1118
|
+
instance: subscriptions,
|
|
1119
|
+
action: "created"
|
|
1120
|
+
});
|
|
1121
|
+
registerOnInstance({
|
|
1122
|
+
instance: subscriptions,
|
|
1123
|
+
action: "removed"
|
|
1124
|
+
});
|
|
1125
|
+
},
|
|
1126
|
+
args: { where: t.arg({
|
|
1127
|
+
type: WhereArg,
|
|
1128
|
+
required: false
|
|
1129
|
+
}) },
|
|
1130
|
+
resolve: async (root, args, ctx, info) => {
|
|
1131
|
+
if (isAllowed && !await isAllowed(ctx)) throw new RumbleErrorSafe("Not allowed to perform this action");
|
|
1132
|
+
deepSetProto(args);
|
|
1133
|
+
return db.select({ count: (0, drizzle_orm.count)() }).from(tableSchema.fullSchema).where(ctx.abilities[table].filter(listAction).merge(mapNullFieldsToUndefined(args)).sql.where).then(assertFirstEntryExists).then((r) => r.count);
|
|
1134
|
+
}
|
|
1135
|
+
}) };
|
|
1136
|
+
});
|
|
1137
|
+
};
|
|
1138
|
+
};
|
|
1139
|
+
|
|
1105
1140
|
//#endregion
|
|
1106
1141
|
//#region lib/helpers/sofaOpenAPIWebhookDocs.ts
|
|
1107
1142
|
const sofaOpenAPIWebhookDocs = {
|
|
@@ -1550,7 +1585,7 @@ const createQueryImplementer = ({ db, schemaBuilder, search, whereArgImplementer
|
|
|
1550
1585
|
},
|
|
1551
1586
|
args: manyArgs,
|
|
1552
1587
|
resolve: (query, _root, args, ctx, _info) => {
|
|
1553
|
-
|
|
1588
|
+
deepSetProto(args);
|
|
1554
1589
|
adjustQueryArgsForSearch({
|
|
1555
1590
|
search,
|
|
1556
1591
|
args,
|
|
@@ -1573,7 +1608,7 @@ const createQueryImplementer = ({ db, schemaBuilder, search, whereArgImplementer
|
|
|
1573
1608
|
description: `Get a single ${pluralize.default.singular(table.toString())} by ID`,
|
|
1574
1609
|
args: { id: t.arg.id({ required: true }) },
|
|
1575
1610
|
resolve: (query, _root, args, ctx, _info) => {
|
|
1576
|
-
|
|
1611
|
+
deepSetProto(args);
|
|
1577
1612
|
const filter = ctx.abilities[table].filter(readAction).merge({ where: { [primaryKeyField.name]: args.id } }).query.single;
|
|
1578
1613
|
const q = query(filter);
|
|
1579
1614
|
if (filter.columns) q.columns = filter.columns;
|
|
@@ -1849,6 +1884,12 @@ export const db = drizzle(
|
|
|
1849
1884
|
orderArgImplementer: orderArg,
|
|
1850
1885
|
makePubSubInstance
|
|
1851
1886
|
});
|
|
1887
|
+
const countQuery = createCountQueryImplementer({
|
|
1888
|
+
...rumbleInput,
|
|
1889
|
+
schemaBuilder,
|
|
1890
|
+
whereArgImplementer: whereArg,
|
|
1891
|
+
makePubSubInstance
|
|
1892
|
+
});
|
|
1852
1893
|
const builtSchema = lazy(() => schemaBuilder.toSchema());
|
|
1853
1894
|
const createYoga = (args) => {
|
|
1854
1895
|
const enableApiDocs = args?.enableApiDocs ?? process?.env?.NODE_ENV === "development";
|
|
@@ -1882,7 +1923,8 @@ export const db = drizzle(
|
|
|
1882
1923
|
clientCreator: clientCreatorImplementer({
|
|
1883
1924
|
...rumbleInput,
|
|
1884
1925
|
builtSchema
|
|
1885
|
-
})
|
|
1926
|
+
}),
|
|
1927
|
+
countQuery
|
|
1886
1928
|
};
|
|
1887
1929
|
};
|
|
1888
1930
|
|