@m1212e/rumble 0.0.6 → 0.0.7
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/index.cjs +1 -1
- package/index.cjs.map +1 -1
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/package.json +1 -1
package/index.cjs
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
'use strict';var P=require('@pothos/core'),O=require('@pothos/plugin-drizzle'),graphqlYoga=require('graphql-yoga'),drizzleOrm=require('drizzle-orm');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var P__default=/*#__PURE__*/_interopDefault(P);var O__default=/*#__PURE__*/_interopDefault(O);function
|
1
|
+
'use strict';var P=require('@pothos/core'),O=require('@pothos/plugin-drizzle'),graphqlYoga=require('graphql-yoga'),drizzleOrm=require('drizzle-orm');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var P__default=/*#__PURE__*/_interopDefault(P);var O__default=/*#__PURE__*/_interopDefault(O);function E(t){return typeof t!="function"}function A(t){return typeof t=="function"&&t.constructor.name!=="AsyncFunction"}var h=({db:t})=>{let s={},l={},b=d=>({allow:a=>{let i=l[d];i||(i={},l[d]=i);let r=Array.isArray(a)?a:[a];for(let p of r){let n=i[p];n||(n=[],i[p]=n);}return {when:p=>{for(let n of r)i[n].push(p);}}}});for(let d of Object.keys(t.query))s[d]=b(d);return {...s,registeredConditions:l,buildWithUserContext:d=>{let a={},i=r=>({filter:p=>{let n=l[r];if(!n)throw "TODO (No allowed entry found for this condition) #1";let c=n[p];if(!c)throw "TODO (No allowed entry found for this condition) #2";let C=c.filter(E),x=c.filter(A).map(e=>e(d)),o=[...C,...x],m;for(let e of o)e.limit&&(m===void 0||e.limit>m)&&(m=e.limit);let f;for(let e of o)e.columns&&(f===void 0?f=e.columns:f={...f,...e.columns});let D=o.filter(e=>e.where).map(e=>e.where);return {where:D.length>0?drizzleOrm.or(...D):void 0,columns:f,limit:m}}});for(let r of Object.keys(t.query))a[r]=i(r);return a}}};var y=class extends Error{constructor(s){super(s),this.name="RumbleError";}};var R=({db:t,nativeServerOptions:s,context:l,onlyQuery:b=!1,actions:d=["create","read","update","delete"]})=>{let a=h({db:t}),i=async n=>{let c=l?await l(n):{};return {...c,abilities:a.buildWithUserContext(c)}},r=new P__default.default({plugins:[O__default.default],drizzle:{client:t},defaultFieldNullability:!1,defaultInputFieldRequiredness:!0});return r.queryType({}),b||r.mutationType({}),{abilityBuilder:a,schemaBuilder:r,yoga:()=>graphqlYoga.createYoga({...s,schema:r.toSchema(),context:i}),implementDefaultObject:({tableName:n,name:c,readAction:C="read"})=>{let x=t._.schema[n];return r.drizzleObject(n,{name:c,fields:o=>{let m=(u,e)=>{switch(u){case"serial":return o.exposeInt(e);case"int":return o.exposeInt(e);case"string":return o.exposeString(e);case"text":return o.exposeString(e);case"boolean":return o.exposeBoolean(e);default:throw new y(`Unknown SQL type: ${u}. Please open an issue so it can be added.`)}},f=Object.entries(x.columns).reduce((u,[e,B])=>(u[e]=m(B.getSQLType(),B.name),u),{}),D=Object.entries(x.relations).reduce((u,[e,B])=>(u[e]=o.relation(e,{query:(U,T)=>T.abilities[n].filter(C)}),u),{});return {...f,...D}}})}}};var z=t=>{if(!t)throw new y("Value not found but required (findFirst)");return t},w=t=>{let s=t.at(0);if(!s)throw new y("Value not found but required (firstEntry)");return s};exports.RumbleError=y;exports.assertFindFirstExists=z;exports.assertFirstEntryExists=w;exports.rumble=R;//# sourceMappingURL=index.cjs.map
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/index.cjs.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../lib/abilities/builder.ts","../lib/helpers/rumbleError.ts","../lib/gql/builder.ts","../lib/helpers/helper.ts"],"names":["isSimpleCondition","condition","isSyncFunctionCondition","createAbilityBuilder","db","builder","registeredConditions","createEntityObject","entityKey","action","conditionsPerEntity","actions","conditionsPerEntityAndAction","userContext","simpleConditions","syncFunctionConditions","allConditionObjects","highestLimit","conditionObject","combinedAllowedColumns","accumulatedWhereConditions","o","or","RumbleError","message","rumble","nativeServerOptions","makeUserContext","onlyQuery","abilityBuilder","makeContext","req","nativeBuilder","SchemaBuilder","DrizzlePlugin","createYoga","tableName","name","readAction","schema","t","mapSQLTypeStringToExposedPothosType","sqlType","columnName","fields","acc","key","value","relations","_args","ctx","assertFindFirstExists","assertFirstEntryExists","v"],"mappings":"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","file":"index.cjs","sourcesContent":["import { SQL, or } from \"drizzle-orm\";\nimport type { ExcludeFromUnionIfNotOnlyType } from \"../helpers/unionTypeExclude\";\nimport type { ExcludeFirst } from \"../helpers/unionTypeExtractor\";\nimport type {\n\tGenericDrizzleDbTypeConstraints,\n\tQueryConditionObject,\n} from \"../types/genericDrizzleDbType\";\n\nexport type AbilityBuilder = ReturnType<typeof createAbilityBuilder>;\n\ntype Condition<DBParameters, UserContext> =\n\t| SimpleCondition<DBParameters>\n\t| SyncFunctionCondition<DBParameters, UserContext>;\n// | AsyncFunctionCondition<DBParameters, UserContext>;\n\ntype SimpleCondition<DBParameters> = DBParameters;\ntype SyncFunctionCondition<DBParameters, UserContext> = (\n\tcontext: UserContext,\n) => DBParameters;\n// type AsyncFunctionCondition<DBParameters, UserContext> = (\n// \tcontext: UserContext,\n// ) => Promise<DBParameters>;\n\n// type guards for the condition types\nfunction isSimpleCondition<DBParameters, UserContext>(\n\tcondition: Condition<DBParameters, UserContext>,\n): condition is SimpleCondition<DBParameters> {\n\treturn typeof condition !== \"function\";\n}\n\nfunction isSyncFunctionCondition<DBParameters, UserContext>(\n\tcondition: Condition<DBParameters, UserContext>,\n): condition is SyncFunctionCondition<DBParameters, UserContext> {\n\treturn (\n\t\ttypeof condition === \"function\" &&\n\t\tcondition.constructor.name !== \"AsyncFunction\"\n\t);\n}\n\n// function isAsyncFunctionCondition<DBParameters, UserContext>(\n// \tcondition: Condition<DBParameters, UserContext>,\n// ): condition is AsyncFunctionCondition<DBParameters, UserContext> {\n// \treturn (\n// \t\ttypeof condition === \"function\" &&\n// \t\tcondition.constructor.name === \"AsyncFunction\"\n// \t);\n// }\n\nexport const createAbilityBuilder = <\n\tUserContext extends Record<string, any>,\n\tDB extends GenericDrizzleDbTypeConstraints,\n\tAction extends string,\n>({\n\tdb,\n}: {\n\tdb: DB;\n}) => {\n\ttype DBQueryKey = keyof DB[\"query\"];\n\ttype DBParameters = Parameters<DB[\"query\"][DBQueryKey][\"findMany\"]>[0];\n\n\tconst builder: {\n\t\t[key in DBQueryKey]: ReturnType<typeof createEntityObject>;\n\t} = {} as any;\n\n\tconst registeredConditions: {\n\t\t[key in DBQueryKey]: {\n\t\t\t[key in Action[number]]: (\n\t\t\t\t| QueryConditionObject\n\t\t\t\t| ((context: UserContext) => QueryConditionObject)\n\t\t\t)[];\n\t\t\t// | ((context: UserContext) => Promise<QueryConditionObject>)\n\t\t};\n\t} = {} as any;\n\n\tconst createEntityObject = (entityKey: DBQueryKey) => ({\n\t\tallow: (action: Action | Action[]) => {\n\t\t\tlet conditionsPerEntity = registeredConditions[entityKey];\n\t\t\tif (!conditionsPerEntity) {\n\t\t\t\tconditionsPerEntity = {} as any;\n\t\t\t\tregisteredConditions[entityKey] = conditionsPerEntity;\n\t\t\t}\n\n\t\t\tconst actions = Array.isArray(action) ? action : [action];\n\t\t\tfor (const action of actions) {\n\t\t\t\tlet conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\tif (!conditionsPerEntityAndAction) {\n\t\t\t\t\tconditionsPerEntityAndAction = [];\n\t\t\t\t\tconditionsPerEntity[action] = conditionsPerEntityAndAction;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\twhen: (condition: Condition<DBParameters, UserContext>) => {\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tconst conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\t\t\tconditionsPerEntityAndAction.push(condition);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n\n\tfor (const entityKey of Object.keys(db.query) as DBQueryKey[]) {\n\t\tbuilder[entityKey] = createEntityObject(entityKey);\n\t}\n\treturn {\n\t\t...builder,\n\t\tregisteredConditions,\n\t\tbuildWithUserContext: (userContext: UserContext) => {\n\t\t\tconst builder: {\n\t\t\t\t[key in DBQueryKey]: ReturnType<typeof createEntityObject>;\n\t\t\t} = {} as any;\n\n\t\t\tconst createEntityObject = (entityKey: DBQueryKey) => ({\n\t\t\t\tfilter: (action: Action) => {\n\t\t\t\t\tconst conditionsPerEntity = registeredConditions[entityKey];\n\t\t\t\t\tif (!conditionsPerEntity) {\n\t\t\t\t\t\tthrow \"TODO (No allowed entry found for this condition) #1\";\n\t\t\t\t\t}\n\n\t\t\t\t\tconst conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\t\tif (!conditionsPerEntityAndAction) {\n\t\t\t\t\t\tthrow \"TODO (No allowed entry found for this condition) #2\";\n\t\t\t\t\t}\n\n\t\t\t\t\tconst simpleConditions =\n\t\t\t\t\t\tconditionsPerEntityAndAction.filter(isSimpleCondition);\n\n\t\t\t\t\tconst syncFunctionConditions = conditionsPerEntityAndAction\n\t\t\t\t\t\t.filter(isSyncFunctionCondition)\n\t\t\t\t\t\t.map((condition) => condition(userContext));\n\n\t\t\t\t\t// const asyncFunctionConditions = await Promise.all(\n\t\t\t\t\t// \tconditionsPerEntityAndAction\n\t\t\t\t\t// \t\t.filter(isAsyncFunctionCondition)\n\t\t\t\t\t// \t\t.map((condition) => condition(userContext)),\n\t\t\t\t\t// );\n\n\t\t\t\t\tconst allConditionObjects = [\n\t\t\t\t\t\t...simpleConditions,\n\t\t\t\t\t\t...syncFunctionConditions,\n\t\t\t\t\t\t// ...asyncFunctionConditions,\n\t\t\t\t\t];\n\n\t\t\t\t\tlet highestLimit = undefined;\n\t\t\t\t\tfor (const conditionObject of allConditionObjects) {\n\t\t\t\t\t\tif (conditionObject.limit) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\thighestLimit === undefined ||\n\t\t\t\t\t\t\t\tconditionObject.limit > highestLimit\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\thighestLimit = conditionObject.limit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet combinedAllowedColumns: Record<string, any> | undefined =\n\t\t\t\t\t\tundefined;\n\t\t\t\t\tfor (const conditionObject of allConditionObjects) {\n\t\t\t\t\t\tif (conditionObject.columns) {\n\t\t\t\t\t\t\tif (combinedAllowedColumns === undefined) {\n\t\t\t\t\t\t\t\tcombinedAllowedColumns = conditionObject.columns;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcombinedAllowedColumns = {\n\t\t\t\t\t\t\t\t\t...combinedAllowedColumns,\n\t\t\t\t\t\t\t\t\t...conditionObject.columns,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst accumulatedWhereConditions = allConditionObjects\n\t\t\t\t\t\t.filter((o) => o.where)\n\t\t\t\t\t\t.map((o) => o.where);\n\n\t\t\t\t\tconst combinedWhere =\n\t\t\t\t\t\taccumulatedWhereConditions.length > 0\n\t\t\t\t\t\t\t? or(...accumulatedWhereConditions)\n\t\t\t\t\t\t\t: undefined;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\twhere: combinedWhere,\n\t\t\t\t\t\tcolumns: combinedAllowedColumns,\n\t\t\t\t\t\tlimit: highestLimit,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tfor (const entityKey of Object.keys(db.query) as DBQueryKey[]) {\n\t\t\t\tbuilder[entityKey] = createEntityObject(entityKey);\n\t\t\t}\n\n\t\t\treturn builder;\n\t\t},\n\t};\n};\n","export class RumbleError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"RumbleError\";\n\t}\n}\n","import SchemaBuilder, { FieldRef } from \"@pothos/core\";\nimport DrizzlePlugin from \"@pothos/plugin-drizzle\";\nimport { type YogaServerOptions, createYoga } from \"graphql-yoga\";\nimport { createAbilityBuilder } from \"../abilities/builder\";\nimport { RumbleError } from \"../helpers/rumbleError\";\nimport type { GenericDrizzleDbTypeConstraints } from \"../types/genericDrizzleDbType\";\n\nexport const rumble = <\n\tUserContext extends Record<string, any>,\n\tDB extends GenericDrizzleDbTypeConstraints,\n\tRequestEvent extends Record<string, any>,\n\tAction extends string = \"create\" | \"read\" | \"update\" | \"delete\",\n>({\n\tdb,\n\tnativeServerOptions,\n\tcontext: makeUserContext,\n\tonlyQuery = false,\n\tactions = [\"create\", \"read\", \"update\", \"delete\"] as Action[],\n}: {\n\t/**\n\t * Your drizzle database instance\n\t */\n\tdb: DB;\n\t/**\n\t * Optional options for the native GraphQL Yoga server\n\t */\n\tnativeServerOptions?:\n\t\t| Omit<YogaServerOptions<RequestEvent, any>, \"schema\" | \"context\">\n\t\t| undefined;\n\t/**\n\t * A function for providing context for each request based on the incoming HTTP Request.\n\t * The type of the parameter equals the HTTPRequest type of your chosen server.\n\t */\n\tcontext?:\n\t\t| ((event: RequestEvent) => Promise<UserContext> | UserContext)\n\t\t| undefined;\n\t/**\n\t * If you only want to create queries and do not need mutations, enable this\n\t */\n\tonlyQuery?: boolean;\n\t/**\n\t * The actions that are available\n\t */\n\tactions?: Action[];\n}) => {\n\tconst abilityBuilder = createAbilityBuilder<UserContext, DB, Action>({\n\t\tdb,\n\t});\n\n\tconst makeContext = async (req: RequestEvent) => {\n\t\tconst userContext = makeUserContext\n\t\t\t? await makeUserContext(req)\n\t\t\t: ({} as UserContext);\n\t\treturn {\n\t\t\t...userContext,\n\t\t\tabilities: abilityBuilder.buildWithUserContext(userContext),\n\t\t};\n\t};\n\n\tconst nativeBuilder = new SchemaBuilder<{\n\t\tContext: Awaited<ReturnType<typeof makeContext>>;\n\t\t// Scalars: Scalars<Prisma.Decimal, Prisma.InputJsonValue | null, Prisma.InputJsonValue> & {\n\t\t// \tFile: {\n\t\t// \t\tInput: File;\n\t\t// \t\tOutput: never;\n\t\t// \t};\n\t\t// \tJSONObject: {\n\t\t// \t\tInput: any;\n\t\t// \t\tOutput: any;\n\t\t// \t};\n\t\t// };\n\t\tDrizzleSchema: DB[\"_\"][\"fullSchema\"];\n\t\tDefaultFieldNullability: false;\n\t\tDefaultArgumentNullability: false;\n\t\tDefaultInputFieldRequiredness: true;\n\t}>({\n\t\tplugins: [DrizzlePlugin],\n\t\tdrizzle: {\n\t\t\tclient: db,\n\t\t},\n\t\tdefaultFieldNullability: false,\n\t\tdefaultInputFieldRequiredness: true,\n\t});\n\n\tnativeBuilder.queryType({});\n\n\tif (!onlyQuery) {\n\t\tnativeBuilder.mutationType({});\n\t}\n\n\tconst implementDefaultObject = <\n\t\tExplicitTableName extends Parameters<typeof nativeBuilder.drizzleObject>[0],\n\t\tRefName extends string,\n\t>({\n\t\ttableName,\n\t\tname,\n\t\treadAction = \"read\" as Action,\n\t}: {\n\t\ttableName: ExplicitTableName;\n\t\tname: RefName;\n\t\treadAction?: Action;\n\t}) => {\n\t\tconst schema = db._.schema![tableName];\n\t\treturn nativeBuilder.drizzleObject(tableName, {\n\t\t\tname,\n\t\t\tfields: (t) => {\n\t\t\t\tconst mapSQLTypeStringToExposedPothosType = (\n\t\t\t\t\tsqlType: string,\n\t\t\t\t\tcolumnName: string,\n\t\t\t\t) => {\n\t\t\t\t\tswitch (sqlType) {\n\t\t\t\t\t\tcase \"serial\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeInt(columnName);\n\t\t\t\t\t\tcase \"int\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeInt(columnName);\n\t\t\t\t\t\tcase \"string\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeString(columnName);\n\t\t\t\t\t\tcase \"text\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeString(columnName);\n\t\t\t\t\t\tcase \"boolean\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeBoolean(columnName);\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow new RumbleError(\n\t\t\t\t\t\t\t\t`Unknown SQL type: ${sqlType}. Please open an issue so it can be added.`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tconst fields = Object.entries(schema.columns).reduce(\n\t\t\t\t\t(acc, [key, value]) => {\n\t\t\t\t\t\tacc[key] = mapSQLTypeStringToExposedPothosType(\n\t\t\t\t\t\t\tvalue.getSQLType(),\n\t\t\t\t\t\t\tvalue.name,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{} as Record<\n\t\t\t\t\t\tstring,\n\t\t\t\t\t\tReturnType<typeof mapSQLTypeStringToExposedPothosType>\n\t\t\t\t\t>,\n\t\t\t\t);\n\n\t\t\t\tconst relations = Object.entries(schema.relations).reduce(\n\t\t\t\t\t(acc, [key, value]) => {\n\t\t\t\t\t\tacc[key] = t.relation(key, {\n\t\t\t\t\t\t\tquery: (_args: any, ctx: any) =>\n\t\t\t\t\t\t\t\tctx.abilities[tableName].filter(readAction),\n\t\t\t\t\t\t} as any) as any;\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{} as Record<\n\t\t\t\t\t\tstring,\n\t\t\t\t\t\tReturnType<typeof mapSQLTypeStringToExposedPothosType>\n\t\t\t\t\t>,\n\t\t\t\t);\n\n\t\t\t\treturn {\n\t\t\t\t\t...fields,\n\t\t\t\t\t...relations,\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t};\n\n\treturn {\n\t\t/**\n * The ability builder. Use it to declare whats allowed for each entity in your DB.\n * \n * @example\n * \n * ```ts\n * // users can edit themselves\n abilityBuilder.users\n .allow([\"read\", \"update\", \"delete\"])\n .when(({ userId }) => ({ where: eq(schema.users.id, userId) }));\n \n // everyone can read posts\n abilityBuilder.posts.allow(\"read\");\n * \n * ```\n */\n\t\tabilityBuilder,\n\t\t/**\n\t\t * The pothos schema builder. See https://pothos-graphql.dev/docs/plugins/drizzle\n\t\t */\n\t\tschemaBuilder: nativeBuilder,\n\t\t/**\n * The native yoga instance. Can be used to run an actual HTTP server.\n * \n * @example\n * \n * ```ts\n import { createServer } from \"node:http\";\n * const server = createServer(yoga());\n server.listen(3000, () => {\n console.log(\"Visit http://localhost:3000/graphql\");\n });\n * ```\n */\n\t\tyoga: () =>\n\t\t\tcreateYoga<RequestEvent>({\n\t\t\t\t...nativeServerOptions,\n\t\t\t\tschema: nativeBuilder.toSchema(),\n\t\t\t\tcontext: makeContext,\n\t\t\t}),\n\t\t/**\n\t\t * A function for creating default objects for your schema\n\t\t */\n\t\timplementDefaultObject,\n\t};\n};\n","import { RumbleError } from \"./rumbleError\";\n\n/**\n * \n * Helper function to map a drizzle findFirst query result,\n * which may be optional, to a correct drizzle type.\n * \n * @throws RumbleError\n * \n * @example\n * \n * ```ts\n * schemaBuilder.queryFields((t) => {\n return {\n findFirstUser: t.drizzleField({\n type: UserRef,\n resolve: (query, root, args, ctx, info) => {\n return (\n db.query.users\n .findFirst({\n ...query,\n where: ctx.abilities.users.filter(\"read\").where,\n })\n // note that we need to manually raise an error if the value is not found\n .then(assertFindFirstExists)\n );\n },\n }),\n };\n });\n * ```\n */\nexport const assertFindFirstExists = <T>(value: T | undefined): T => {\n\tif (!value) throw new RumbleError(\"Value not found but required (findFirst)\");\n\treturn value;\n};\n\n/**\n * \n * Helper function to map a drizzle findFirst query result,\n * which may be optional, to a correct drizzle type.\n * \n * @throws RumbleError\n * \n * @example\n * \n * ```ts\n schemaBuilder.mutationFields((t) => {\n return {\n updateUsername: t.drizzleField({\n type: UserRef,\n args: {\n userId: t.arg.int({ required: true }),\n newName: t.arg.string({ required: true }),\n },\n resolve: (query, root, args, ctx, info) => {\n return db\n .update(schema.users)\n .set({\n name: args.newName,\n })\n .where(\n and(\n eq(schema.users.id, args.userId),\n ctx.abilities.users.filter(\"update\").where\n )\n )\n .returning({ id: schema.users.id, name: schema.users.name })\n // note that we need to manually raise an error if the value is not found\n .then(assertFirstEntryExists);\n },\n }),\n };\n });\n * ```\n */\nexport const assertFirstEntryExists = <T>(value: T[]): T => {\n\tconst v = value.at(0);\n\tif (!v) throw new RumbleError(\"Value not found but required (firstEntry)\");\n\treturn v;\n};\n"]}
|
1
|
+
{"version":3,"sources":["../lib/abilities/builder.ts","../lib/helpers/rumbleError.ts","../lib/gql/builder.ts","../lib/helpers/helper.ts"],"names":["isSimpleCondition","condition","isSyncFunctionCondition","createAbilityBuilder","db","builder","registeredConditions","createEntityObject","entityKey","action","conditionsPerEntity","actions","conditionsPerEntityAndAction","userContext","simpleConditions","syncFunctionConditions","allConditionObjects","highestLimit","conditionObject","combinedAllowedColumns","accumulatedWhereConditions","o","or","RumbleError","message","rumble","nativeServerOptions","makeUserContext","onlyQuery","abilityBuilder","makeContext","req","nativeBuilder","SchemaBuilder","DrizzlePlugin","createYoga","tableName","name","readAction","schema","t","mapSQLTypeStringToExposedPothosType","sqlType","columnName","fields","acc","key","value","relations","_args","ctx","assertFindFirstExists","assertFirstEntryExists","v"],"mappings":"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","file":"index.cjs","sourcesContent":["import { or } from \"drizzle-orm\";\nimport type {\n\tGenericDrizzleDbTypeConstraints,\n\tQueryConditionObject,\n} from \"../types/genericDrizzleDbType\";\n\nexport type AbilityBuilder = ReturnType<typeof createAbilityBuilder>;\n\ntype Condition<DBParameters, UserContext> =\n\t| SimpleCondition<DBParameters>\n\t| SyncFunctionCondition<DBParameters, UserContext>;\n// | AsyncFunctionCondition<DBParameters, UserContext>;\n\ntype SimpleCondition<DBParameters> = DBParameters;\ntype SyncFunctionCondition<DBParameters, UserContext> = (\n\tcontext: UserContext,\n) => DBParameters;\n// type AsyncFunctionCondition<DBParameters, UserContext> = (\n// \tcontext: UserContext,\n// ) => Promise<DBParameters>;\n\n// type guards for the condition types\nfunction isSimpleCondition<DBParameters, UserContext>(\n\tcondition: Condition<DBParameters, UserContext>,\n): condition is SimpleCondition<DBParameters> {\n\treturn typeof condition !== \"function\";\n}\n\nfunction isSyncFunctionCondition<DBParameters, UserContext>(\n\tcondition: Condition<DBParameters, UserContext>,\n): condition is SyncFunctionCondition<DBParameters, UserContext> {\n\treturn (\n\t\ttypeof condition === \"function\" &&\n\t\tcondition.constructor.name !== \"AsyncFunction\"\n\t);\n}\n\n// function isAsyncFunctionCondition<DBParameters, UserContext>(\n// \tcondition: Condition<DBParameters, UserContext>,\n// ): condition is AsyncFunctionCondition<DBParameters, UserContext> {\n// \treturn (\n// \t\ttypeof condition === \"function\" &&\n// \t\tcondition.constructor.name === \"AsyncFunction\"\n// \t);\n// }\n\nexport const createAbilityBuilder = <\n\tUserContext extends Record<string, any>,\n\tDB extends GenericDrizzleDbTypeConstraints,\n\tAction extends string,\n>({\n\tdb,\n}: {\n\tdb: DB;\n}) => {\n\ttype DBQueryKey = keyof DB[\"query\"];\n\ttype DBParameters = Parameters<DB[\"query\"][DBQueryKey][\"findMany\"]>[0];\n\n\tconst builder: {\n\t\t[key in DBQueryKey]: ReturnType<typeof createEntityObject>;\n\t} = {} as any;\n\n\tconst registeredConditions: {\n\t\t[key in DBQueryKey]: {\n\t\t\t[key in Action[number]]: (\n\t\t\t\t| QueryConditionObject\n\t\t\t\t| ((context: UserContext) => QueryConditionObject)\n\t\t\t)[];\n\t\t\t// | ((context: UserContext) => Promise<QueryConditionObject>)\n\t\t};\n\t} = {} as any;\n\n\tconst createEntityObject = (entityKey: DBQueryKey) => ({\n\t\tallow: (action: Action | Action[]) => {\n\t\t\tlet conditionsPerEntity = registeredConditions[entityKey];\n\t\t\tif (!conditionsPerEntity) {\n\t\t\t\tconditionsPerEntity = {} as any;\n\t\t\t\tregisteredConditions[entityKey] = conditionsPerEntity;\n\t\t\t}\n\n\t\t\tconst actions = Array.isArray(action) ? action : [action];\n\t\t\tfor (const action of actions) {\n\t\t\t\tlet conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\tif (!conditionsPerEntityAndAction) {\n\t\t\t\t\tconditionsPerEntityAndAction = [];\n\t\t\t\t\tconditionsPerEntity[action] = conditionsPerEntityAndAction;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\twhen: (condition: Condition<DBParameters, UserContext>) => {\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tconst conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\t\t\tconditionsPerEntityAndAction.push(condition);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n\n\tfor (const entityKey of Object.keys(db.query) as DBQueryKey[]) {\n\t\tbuilder[entityKey] = createEntityObject(entityKey);\n\t}\n\treturn {\n\t\t...builder,\n\t\tregisteredConditions,\n\t\tbuildWithUserContext: (userContext: UserContext) => {\n\t\t\tconst builder: {\n\t\t\t\t[key in DBQueryKey]: ReturnType<typeof createEntityObject>;\n\t\t\t} = {} as any;\n\n\t\t\tconst createEntityObject = (entityKey: DBQueryKey) => ({\n\t\t\t\tfilter: (action: Action) => {\n\t\t\t\t\tconst conditionsPerEntity = registeredConditions[entityKey];\n\t\t\t\t\tif (!conditionsPerEntity) {\n\t\t\t\t\t\tthrow \"TODO (No allowed entry found for this condition) #1\";\n\t\t\t\t\t}\n\n\t\t\t\t\tconst conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\t\tif (!conditionsPerEntityAndAction) {\n\t\t\t\t\t\tthrow \"TODO (No allowed entry found for this condition) #2\";\n\t\t\t\t\t}\n\n\t\t\t\t\tconst simpleConditions =\n\t\t\t\t\t\tconditionsPerEntityAndAction.filter(isSimpleCondition);\n\n\t\t\t\t\tconst syncFunctionConditions = conditionsPerEntityAndAction\n\t\t\t\t\t\t.filter(isSyncFunctionCondition)\n\t\t\t\t\t\t.map((condition) => condition(userContext));\n\n\t\t\t\t\t// const asyncFunctionConditions = await Promise.all(\n\t\t\t\t\t// \tconditionsPerEntityAndAction\n\t\t\t\t\t// \t\t.filter(isAsyncFunctionCondition)\n\t\t\t\t\t// \t\t.map((condition) => condition(userContext)),\n\t\t\t\t\t// );\n\n\t\t\t\t\tconst allConditionObjects = [\n\t\t\t\t\t\t...simpleConditions,\n\t\t\t\t\t\t...syncFunctionConditions,\n\t\t\t\t\t\t// ...asyncFunctionConditions,\n\t\t\t\t\t];\n\n\t\t\t\t\tlet highestLimit = undefined;\n\t\t\t\t\tfor (const conditionObject of allConditionObjects) {\n\t\t\t\t\t\tif (conditionObject.limit) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\thighestLimit === undefined ||\n\t\t\t\t\t\t\t\tconditionObject.limit > highestLimit\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\thighestLimit = conditionObject.limit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet combinedAllowedColumns: Record<string, any> | undefined =\n\t\t\t\t\t\tundefined;\n\t\t\t\t\tfor (const conditionObject of allConditionObjects) {\n\t\t\t\t\t\tif (conditionObject.columns) {\n\t\t\t\t\t\t\tif (combinedAllowedColumns === undefined) {\n\t\t\t\t\t\t\t\tcombinedAllowedColumns = conditionObject.columns;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcombinedAllowedColumns = {\n\t\t\t\t\t\t\t\t\t...combinedAllowedColumns,\n\t\t\t\t\t\t\t\t\t...conditionObject.columns,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst accumulatedWhereConditions = allConditionObjects\n\t\t\t\t\t\t.filter((o) => o.where)\n\t\t\t\t\t\t.map((o) => o.where);\n\n\t\t\t\t\tconst combinedWhere =\n\t\t\t\t\t\taccumulatedWhereConditions.length > 0\n\t\t\t\t\t\t\t? or(...accumulatedWhereConditions)\n\t\t\t\t\t\t\t: undefined;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\twhere: combinedWhere,\n\t\t\t\t\t\tcolumns: combinedAllowedColumns,\n\t\t\t\t\t\tlimit: highestLimit,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tfor (const entityKey of Object.keys(db.query) as DBQueryKey[]) {\n\t\t\t\tbuilder[entityKey] = createEntityObject(entityKey);\n\t\t\t}\n\n\t\t\treturn builder;\n\t\t},\n\t};\n};\n","export class RumbleError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"RumbleError\";\n\t}\n}\n","import SchemaBuilder from \"@pothos/core\";\nimport DrizzlePlugin from \"@pothos/plugin-drizzle\";\nimport { type YogaServerOptions, createYoga } from \"graphql-yoga\";\nimport { createAbilityBuilder } from \"../abilities/builder\";\nimport { RumbleError } from \"../helpers/rumbleError\";\nimport type { GenericDrizzleDbTypeConstraints } from \"../types/genericDrizzleDbType\";\n\nexport const rumble = <\n\tUserContext extends Record<string, any>,\n\tDB extends GenericDrizzleDbTypeConstraints,\n\tRequestEvent extends Record<string, any>,\n\tAction extends string = \"create\" | \"read\" | \"update\" | \"delete\",\n>({\n\tdb,\n\tnativeServerOptions,\n\tcontext: makeUserContext,\n\tonlyQuery = false,\n\tactions = [\"create\", \"read\", \"update\", \"delete\"] as Action[],\n}: {\n\t/**\n\t * Your drizzle database instance\n\t */\n\tdb: DB;\n\t/**\n\t * Optional options for the native GraphQL Yoga server\n\t */\n\tnativeServerOptions?:\n\t\t| Omit<YogaServerOptions<RequestEvent, any>, \"schema\" | \"context\">\n\t\t| undefined;\n\t/**\n\t * A function for providing context for each request based on the incoming HTTP Request.\n\t * The type of the parameter equals the HTTPRequest type of your chosen server.\n\t */\n\tcontext?:\n\t\t| ((event: RequestEvent) => Promise<UserContext> | UserContext)\n\t\t| undefined;\n\t/**\n\t * If you only want to create queries and do not need mutations, enable this\n\t */\n\tonlyQuery?: boolean;\n\t/**\n\t * The actions that are available\n\t */\n\tactions?: Action[];\n}) => {\n\tconst abilityBuilder = createAbilityBuilder<UserContext, DB, Action>({\n\t\tdb,\n\t});\n\n\tconst makeContext = async (req: RequestEvent) => {\n\t\tconst userContext = makeUserContext\n\t\t\t? await makeUserContext(req)\n\t\t\t: ({} as UserContext);\n\t\treturn {\n\t\t\t...userContext,\n\t\t\tabilities: abilityBuilder.buildWithUserContext(userContext),\n\t\t};\n\t};\n\n\tconst nativeBuilder = new SchemaBuilder<{\n\t\tContext: Awaited<ReturnType<typeof makeContext>>;\n\t\t// Scalars: Scalars<Prisma.Decimal, Prisma.InputJsonValue | null, Prisma.InputJsonValue> & {\n\t\t// \tFile: {\n\t\t// \t\tInput: File;\n\t\t// \t\tOutput: never;\n\t\t// \t};\n\t\t// \tJSONObject: {\n\t\t// \t\tInput: any;\n\t\t// \t\tOutput: any;\n\t\t// \t};\n\t\t// };\n\t\tDrizzleSchema: DB[\"_\"][\"fullSchema\"];\n\t\tDefaultFieldNullability: false;\n\t\tDefaultArgumentNullability: false;\n\t\tDefaultInputFieldRequiredness: true;\n\t}>({\n\t\tplugins: [DrizzlePlugin],\n\t\tdrizzle: {\n\t\t\tclient: db,\n\t\t},\n\t\tdefaultFieldNullability: false,\n\t\tdefaultInputFieldRequiredness: true,\n\t});\n\n\tnativeBuilder.queryType({});\n\n\tif (!onlyQuery) {\n\t\tnativeBuilder.mutationType({});\n\t}\n\n\tconst implementDefaultObject = <\n\t\tExplicitTableName extends Parameters<typeof nativeBuilder.drizzleObject>[0],\n\t\tRefName extends string,\n\t>({\n\t\ttableName,\n\t\tname,\n\t\treadAction = \"read\" as Action,\n\t}: {\n\t\ttableName: ExplicitTableName;\n\t\tname: RefName;\n\t\treadAction?: Action;\n\t}) => {\n\t\tconst schema = db._.schema![tableName];\n\t\treturn nativeBuilder.drizzleObject(tableName, {\n\t\t\tname,\n\t\t\tfields: (t) => {\n\t\t\t\tconst mapSQLTypeStringToExposedPothosType = (\n\t\t\t\t\tsqlType: string,\n\t\t\t\t\tcolumnName: string,\n\t\t\t\t) => {\n\t\t\t\t\tswitch (sqlType) {\n\t\t\t\t\t\tcase \"serial\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeInt(columnName);\n\t\t\t\t\t\tcase \"int\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeInt(columnName);\n\t\t\t\t\t\tcase \"string\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeString(columnName);\n\t\t\t\t\t\tcase \"text\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeString(columnName);\n\t\t\t\t\t\tcase \"boolean\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeBoolean(columnName);\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow new RumbleError(\n\t\t\t\t\t\t\t\t`Unknown SQL type: ${sqlType}. Please open an issue so it can be added.`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tconst fields = Object.entries(schema.columns).reduce(\n\t\t\t\t\t(acc, [key, value]) => {\n\t\t\t\t\t\tacc[key] = mapSQLTypeStringToExposedPothosType(\n\t\t\t\t\t\t\tvalue.getSQLType(),\n\t\t\t\t\t\t\tvalue.name,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{} as Record<\n\t\t\t\t\t\tstring,\n\t\t\t\t\t\tReturnType<typeof mapSQLTypeStringToExposedPothosType>\n\t\t\t\t\t>,\n\t\t\t\t);\n\n\t\t\t\tconst relations = Object.entries(schema.relations).reduce(\n\t\t\t\t\t(acc, [key, value]) => {\n\t\t\t\t\t\tacc[key] = t.relation(key, {\n\t\t\t\t\t\t\tquery: (_args: any, ctx: any) =>\n\t\t\t\t\t\t\t\tctx.abilities[tableName].filter(readAction),\n\t\t\t\t\t\t} as any) as any;\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{} as Record<\n\t\t\t\t\t\tstring,\n\t\t\t\t\t\tReturnType<typeof mapSQLTypeStringToExposedPothosType>\n\t\t\t\t\t>,\n\t\t\t\t);\n\n\t\t\t\treturn {\n\t\t\t\t\t...fields,\n\t\t\t\t\t...relations,\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t};\n\n\treturn {\n\t\t/**\n * The ability builder. Use it to declare whats allowed for each entity in your DB.\n * \n * @example\n * \n * ```ts\n * // users can edit themselves\n abilityBuilder.users\n .allow([\"read\", \"update\", \"delete\"])\n .when(({ userId }) => ({ where: eq(schema.users.id, userId) }));\n \n // everyone can read posts\n abilityBuilder.posts.allow(\"read\");\n * \n * ```\n */\n\t\tabilityBuilder,\n\t\t/**\n\t\t * The pothos schema builder. See https://pothos-graphql.dev/docs/plugins/drizzle\n\t\t */\n\t\tschemaBuilder: nativeBuilder,\n\t\t/**\n * The native yoga instance. Can be used to run an actual HTTP server.\n * \n * @example\n * \n * ```ts\n import { createServer } from \"node:http\";\n * const server = createServer(yoga());\n server.listen(3000, () => {\n console.log(\"Visit http://localhost:3000/graphql\");\n });\n * ```\n */\n\t\tyoga: () =>\n\t\t\tcreateYoga<RequestEvent>({\n\t\t\t\t...nativeServerOptions,\n\t\t\t\tschema: nativeBuilder.toSchema(),\n\t\t\t\tcontext: makeContext,\n\t\t\t}),\n\t\t/**\n\t\t * A function for creating default objects for your schema\n\t\t */\n\t\timplementDefaultObject,\n\t};\n};\n","import { RumbleError } from \"./rumbleError\";\n\n/**\n * \n * Helper function to map a drizzle findFirst query result,\n * which may be optional, to a correct drizzle type.\n * \n * @throws RumbleError\n * \n * @example\n * \n * ```ts\n * schemaBuilder.queryFields((t) => {\n return {\n findFirstUser: t.drizzleField({\n type: UserRef,\n resolve: (query, root, args, ctx, info) => {\n return (\n db.query.users\n .findFirst({\n ...query,\n where: ctx.abilities.users.filter(\"read\").where,\n })\n // note that we need to manually raise an error if the value is not found\n .then(assertFindFirstExists)\n );\n },\n }),\n };\n });\n * ```\n */\nexport const assertFindFirstExists = <T>(value: T | undefined): T => {\n\tif (!value) throw new RumbleError(\"Value not found but required (findFirst)\");\n\treturn value;\n};\n\n/**\n * \n * Helper function to map a drizzle findFirst query result,\n * which may be optional, to a correct drizzle type.\n * \n * @throws RumbleError\n * \n * @example\n * \n * ```ts\n schemaBuilder.mutationFields((t) => {\n return {\n updateUsername: t.drizzleField({\n type: UserRef,\n args: {\n userId: t.arg.int({ required: true }),\n newName: t.arg.string({ required: true }),\n },\n resolve: (query, root, args, ctx, info) => {\n return db\n .update(schema.users)\n .set({\n name: args.newName,\n })\n .where(\n and(\n eq(schema.users.id, args.userId),\n ctx.abilities.users.filter(\"update\").where\n )\n )\n .returning({ id: schema.users.id, name: schema.users.name })\n // note that we need to manually raise an error if the value is not found\n .then(assertFirstEntryExists);\n },\n }),\n };\n });\n * ```\n */\nexport const assertFirstEntryExists = <T>(value: T[]): T => {\n\tconst v = value.at(0);\n\tif (!v) throw new RumbleError(\"Value not found but required (firstEntry)\");\n\treturn v;\n};\n"]}
|
package/index.d.ts
CHANGED
@@ -7,7 +7,7 @@ import * as graphql_yoga from 'graphql-yoga';
|
|
7
7
|
import { YogaServerOptions } from 'graphql-yoga';
|
8
8
|
import * as drizzle_orm from 'drizzle-orm';
|
9
9
|
|
10
|
-
|
10
|
+
import { drizzleTableKey } from "@pothos/plugin-drizzle"
|
11
11
|
declare class DrizzleObjectRef<Types extends SchemaTypes, Table extends keyof Types["DrizzleRelationSchema"] = keyof Types["DrizzleRelationSchema"], T = {}> extends ObjectRef<Types, T> {
|
12
12
|
[drizzleTableKey]: Types["DrizzleRelationSchema"][Table];
|
13
13
|
[abstractReturnShapeKey]: WithBrand<T>;
|
package/index.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
import P from'@pothos/core';import O from'@pothos/plugin-drizzle';import {createYoga}from'graphql-yoga';import {or}from'drizzle-orm';function
|
1
|
+
import P from'@pothos/core';import O from'@pothos/plugin-drizzle';import {createYoga}from'graphql-yoga';import {or}from'drizzle-orm';function E(t){return typeof t!="function"}function A(t){return typeof t=="function"&&t.constructor.name!=="AsyncFunction"}var h=({db:t})=>{let s={},l={},b=d=>({allow:a=>{let i=l[d];i||(i={},l[d]=i);let r=Array.isArray(a)?a:[a];for(let p of r){let n=i[p];n||(n=[],i[p]=n);}return {when:p=>{for(let n of r)i[n].push(p);}}}});for(let d of Object.keys(t.query))s[d]=b(d);return {...s,registeredConditions:l,buildWithUserContext:d=>{let a={},i=r=>({filter:p=>{let n=l[r];if(!n)throw "TODO (No allowed entry found for this condition) #1";let c=n[p];if(!c)throw "TODO (No allowed entry found for this condition) #2";let C=c.filter(E),x=c.filter(A).map(e=>e(d)),o=[...C,...x],m;for(let e of o)e.limit&&(m===void 0||e.limit>m)&&(m=e.limit);let f;for(let e of o)e.columns&&(f===void 0?f=e.columns:f={...f,...e.columns});let D=o.filter(e=>e.where).map(e=>e.where);return {where:D.length>0?or(...D):void 0,columns:f,limit:m}}});for(let r of Object.keys(t.query))a[r]=i(r);return a}}};var y=class extends Error{constructor(s){super(s),this.name="RumbleError";}};var R=({db:t,nativeServerOptions:s,context:l,onlyQuery:b=!1,actions:d=["create","read","update","delete"]})=>{let a=h({db:t}),i=async n=>{let c=l?await l(n):{};return {...c,abilities:a.buildWithUserContext(c)}},r=new P({plugins:[O],drizzle:{client:t},defaultFieldNullability:!1,defaultInputFieldRequiredness:!0});return r.queryType({}),b||r.mutationType({}),{abilityBuilder:a,schemaBuilder:r,yoga:()=>createYoga({...s,schema:r.toSchema(),context:i}),implementDefaultObject:({tableName:n,name:c,readAction:C="read"})=>{let x=t._.schema[n];return r.drizzleObject(n,{name:c,fields:o=>{let m=(u,e)=>{switch(u){case"serial":return o.exposeInt(e);case"int":return o.exposeInt(e);case"string":return o.exposeString(e);case"text":return o.exposeString(e);case"boolean":return o.exposeBoolean(e);default:throw new y(`Unknown SQL type: ${u}. Please open an issue so it can be added.`)}},f=Object.entries(x.columns).reduce((u,[e,B])=>(u[e]=m(B.getSQLType(),B.name),u),{}),D=Object.entries(x.relations).reduce((u,[e,B])=>(u[e]=o.relation(e,{query:(U,T)=>T.abilities[n].filter(C)}),u),{});return {...f,...D}}})}}};var z=t=>{if(!t)throw new y("Value not found but required (findFirst)");return t},w=t=>{let s=t.at(0);if(!s)throw new y("Value not found but required (firstEntry)");return s};export{y as RumbleError,z as assertFindFirstExists,w as assertFirstEntryExists,R as rumble};//# sourceMappingURL=index.js.map
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../lib/abilities/builder.ts","../lib/helpers/rumbleError.ts","../lib/gql/builder.ts","../lib/helpers/helper.ts"],"names":["isSimpleCondition","condition","isSyncFunctionCondition","createAbilityBuilder","db","builder","registeredConditions","createEntityObject","entityKey","action","conditionsPerEntity","actions","conditionsPerEntityAndAction","userContext","simpleConditions","syncFunctionConditions","allConditionObjects","highestLimit","conditionObject","combinedAllowedColumns","accumulatedWhereConditions","o","or","RumbleError","message","rumble","nativeServerOptions","makeUserContext","onlyQuery","abilityBuilder","makeContext","req","nativeBuilder","SchemaBuilder","DrizzlePlugin","createYoga","tableName","name","readAction","schema","t","mapSQLTypeStringToExposedPothosType","sqlType","columnName","fields","acc","key","value","relations","_args","ctx","assertFindFirstExists","assertFirstEntryExists","v"],"mappings":"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","file":"index.js","sourcesContent":["import { SQL, or } from \"drizzle-orm\";\nimport type { ExcludeFromUnionIfNotOnlyType } from \"../helpers/unionTypeExclude\";\nimport type { ExcludeFirst } from \"../helpers/unionTypeExtractor\";\nimport type {\n\tGenericDrizzleDbTypeConstraints,\n\tQueryConditionObject,\n} from \"../types/genericDrizzleDbType\";\n\nexport type AbilityBuilder = ReturnType<typeof createAbilityBuilder>;\n\ntype Condition<DBParameters, UserContext> =\n\t| SimpleCondition<DBParameters>\n\t| SyncFunctionCondition<DBParameters, UserContext>;\n// | AsyncFunctionCondition<DBParameters, UserContext>;\n\ntype SimpleCondition<DBParameters> = DBParameters;\ntype SyncFunctionCondition<DBParameters, UserContext> = (\n\tcontext: UserContext,\n) => DBParameters;\n// type AsyncFunctionCondition<DBParameters, UserContext> = (\n// \tcontext: UserContext,\n// ) => Promise<DBParameters>;\n\n// type guards for the condition types\nfunction isSimpleCondition<DBParameters, UserContext>(\n\tcondition: Condition<DBParameters, UserContext>,\n): condition is SimpleCondition<DBParameters> {\n\treturn typeof condition !== \"function\";\n}\n\nfunction isSyncFunctionCondition<DBParameters, UserContext>(\n\tcondition: Condition<DBParameters, UserContext>,\n): condition is SyncFunctionCondition<DBParameters, UserContext> {\n\treturn (\n\t\ttypeof condition === \"function\" &&\n\t\tcondition.constructor.name !== \"AsyncFunction\"\n\t);\n}\n\n// function isAsyncFunctionCondition<DBParameters, UserContext>(\n// \tcondition: Condition<DBParameters, UserContext>,\n// ): condition is AsyncFunctionCondition<DBParameters, UserContext> {\n// \treturn (\n// \t\ttypeof condition === \"function\" &&\n// \t\tcondition.constructor.name === \"AsyncFunction\"\n// \t);\n// }\n\nexport const createAbilityBuilder = <\n\tUserContext extends Record<string, any>,\n\tDB extends GenericDrizzleDbTypeConstraints,\n\tAction extends string,\n>({\n\tdb,\n}: {\n\tdb: DB;\n}) => {\n\ttype DBQueryKey = keyof DB[\"query\"];\n\ttype DBParameters = Parameters<DB[\"query\"][DBQueryKey][\"findMany\"]>[0];\n\n\tconst builder: {\n\t\t[key in DBQueryKey]: ReturnType<typeof createEntityObject>;\n\t} = {} as any;\n\n\tconst registeredConditions: {\n\t\t[key in DBQueryKey]: {\n\t\t\t[key in Action[number]]: (\n\t\t\t\t| QueryConditionObject\n\t\t\t\t| ((context: UserContext) => QueryConditionObject)\n\t\t\t)[];\n\t\t\t// | ((context: UserContext) => Promise<QueryConditionObject>)\n\t\t};\n\t} = {} as any;\n\n\tconst createEntityObject = (entityKey: DBQueryKey) => ({\n\t\tallow: (action: Action | Action[]) => {\n\t\t\tlet conditionsPerEntity = registeredConditions[entityKey];\n\t\t\tif (!conditionsPerEntity) {\n\t\t\t\tconditionsPerEntity = {} as any;\n\t\t\t\tregisteredConditions[entityKey] = conditionsPerEntity;\n\t\t\t}\n\n\t\t\tconst actions = Array.isArray(action) ? action : [action];\n\t\t\tfor (const action of actions) {\n\t\t\t\tlet conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\tif (!conditionsPerEntityAndAction) {\n\t\t\t\t\tconditionsPerEntityAndAction = [];\n\t\t\t\t\tconditionsPerEntity[action] = conditionsPerEntityAndAction;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\twhen: (condition: Condition<DBParameters, UserContext>) => {\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tconst conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\t\t\tconditionsPerEntityAndAction.push(condition);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n\n\tfor (const entityKey of Object.keys(db.query) as DBQueryKey[]) {\n\t\tbuilder[entityKey] = createEntityObject(entityKey);\n\t}\n\treturn {\n\t\t...builder,\n\t\tregisteredConditions,\n\t\tbuildWithUserContext: (userContext: UserContext) => {\n\t\t\tconst builder: {\n\t\t\t\t[key in DBQueryKey]: ReturnType<typeof createEntityObject>;\n\t\t\t} = {} as any;\n\n\t\t\tconst createEntityObject = (entityKey: DBQueryKey) => ({\n\t\t\t\tfilter: (action: Action) => {\n\t\t\t\t\tconst conditionsPerEntity = registeredConditions[entityKey];\n\t\t\t\t\tif (!conditionsPerEntity) {\n\t\t\t\t\t\tthrow \"TODO (No allowed entry found for this condition) #1\";\n\t\t\t\t\t}\n\n\t\t\t\t\tconst conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\t\tif (!conditionsPerEntityAndAction) {\n\t\t\t\t\t\tthrow \"TODO (No allowed entry found for this condition) #2\";\n\t\t\t\t\t}\n\n\t\t\t\t\tconst simpleConditions =\n\t\t\t\t\t\tconditionsPerEntityAndAction.filter(isSimpleCondition);\n\n\t\t\t\t\tconst syncFunctionConditions = conditionsPerEntityAndAction\n\t\t\t\t\t\t.filter(isSyncFunctionCondition)\n\t\t\t\t\t\t.map((condition) => condition(userContext));\n\n\t\t\t\t\t// const asyncFunctionConditions = await Promise.all(\n\t\t\t\t\t// \tconditionsPerEntityAndAction\n\t\t\t\t\t// \t\t.filter(isAsyncFunctionCondition)\n\t\t\t\t\t// \t\t.map((condition) => condition(userContext)),\n\t\t\t\t\t// );\n\n\t\t\t\t\tconst allConditionObjects = [\n\t\t\t\t\t\t...simpleConditions,\n\t\t\t\t\t\t...syncFunctionConditions,\n\t\t\t\t\t\t// ...asyncFunctionConditions,\n\t\t\t\t\t];\n\n\t\t\t\t\tlet highestLimit = undefined;\n\t\t\t\t\tfor (const conditionObject of allConditionObjects) {\n\t\t\t\t\t\tif (conditionObject.limit) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\thighestLimit === undefined ||\n\t\t\t\t\t\t\t\tconditionObject.limit > highestLimit\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\thighestLimit = conditionObject.limit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet combinedAllowedColumns: Record<string, any> | undefined =\n\t\t\t\t\t\tundefined;\n\t\t\t\t\tfor (const conditionObject of allConditionObjects) {\n\t\t\t\t\t\tif (conditionObject.columns) {\n\t\t\t\t\t\t\tif (combinedAllowedColumns === undefined) {\n\t\t\t\t\t\t\t\tcombinedAllowedColumns = conditionObject.columns;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcombinedAllowedColumns = {\n\t\t\t\t\t\t\t\t\t...combinedAllowedColumns,\n\t\t\t\t\t\t\t\t\t...conditionObject.columns,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst accumulatedWhereConditions = allConditionObjects\n\t\t\t\t\t\t.filter((o) => o.where)\n\t\t\t\t\t\t.map((o) => o.where);\n\n\t\t\t\t\tconst combinedWhere =\n\t\t\t\t\t\taccumulatedWhereConditions.length > 0\n\t\t\t\t\t\t\t? or(...accumulatedWhereConditions)\n\t\t\t\t\t\t\t: undefined;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\twhere: combinedWhere,\n\t\t\t\t\t\tcolumns: combinedAllowedColumns,\n\t\t\t\t\t\tlimit: highestLimit,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tfor (const entityKey of Object.keys(db.query) as DBQueryKey[]) {\n\t\t\t\tbuilder[entityKey] = createEntityObject(entityKey);\n\t\t\t}\n\n\t\t\treturn builder;\n\t\t},\n\t};\n};\n","export class RumbleError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"RumbleError\";\n\t}\n}\n","import SchemaBuilder, { FieldRef } from \"@pothos/core\";\nimport DrizzlePlugin from \"@pothos/plugin-drizzle\";\nimport { type YogaServerOptions, createYoga } from \"graphql-yoga\";\nimport { createAbilityBuilder } from \"../abilities/builder\";\nimport { RumbleError } from \"../helpers/rumbleError\";\nimport type { GenericDrizzleDbTypeConstraints } from \"../types/genericDrizzleDbType\";\n\nexport const rumble = <\n\tUserContext extends Record<string, any>,\n\tDB extends GenericDrizzleDbTypeConstraints,\n\tRequestEvent extends Record<string, any>,\n\tAction extends string = \"create\" | \"read\" | \"update\" | \"delete\",\n>({\n\tdb,\n\tnativeServerOptions,\n\tcontext: makeUserContext,\n\tonlyQuery = false,\n\tactions = [\"create\", \"read\", \"update\", \"delete\"] as Action[],\n}: {\n\t/**\n\t * Your drizzle database instance\n\t */\n\tdb: DB;\n\t/**\n\t * Optional options for the native GraphQL Yoga server\n\t */\n\tnativeServerOptions?:\n\t\t| Omit<YogaServerOptions<RequestEvent, any>, \"schema\" | \"context\">\n\t\t| undefined;\n\t/**\n\t * A function for providing context for each request based on the incoming HTTP Request.\n\t * The type of the parameter equals the HTTPRequest type of your chosen server.\n\t */\n\tcontext?:\n\t\t| ((event: RequestEvent) => Promise<UserContext> | UserContext)\n\t\t| undefined;\n\t/**\n\t * If you only want to create queries and do not need mutations, enable this\n\t */\n\tonlyQuery?: boolean;\n\t/**\n\t * The actions that are available\n\t */\n\tactions?: Action[];\n}) => {\n\tconst abilityBuilder = createAbilityBuilder<UserContext, DB, Action>({\n\t\tdb,\n\t});\n\n\tconst makeContext = async (req: RequestEvent) => {\n\t\tconst userContext = makeUserContext\n\t\t\t? await makeUserContext(req)\n\t\t\t: ({} as UserContext);\n\t\treturn {\n\t\t\t...userContext,\n\t\t\tabilities: abilityBuilder.buildWithUserContext(userContext),\n\t\t};\n\t};\n\n\tconst nativeBuilder = new SchemaBuilder<{\n\t\tContext: Awaited<ReturnType<typeof makeContext>>;\n\t\t// Scalars: Scalars<Prisma.Decimal, Prisma.InputJsonValue | null, Prisma.InputJsonValue> & {\n\t\t// \tFile: {\n\t\t// \t\tInput: File;\n\t\t// \t\tOutput: never;\n\t\t// \t};\n\t\t// \tJSONObject: {\n\t\t// \t\tInput: any;\n\t\t// \t\tOutput: any;\n\t\t// \t};\n\t\t// };\n\t\tDrizzleSchema: DB[\"_\"][\"fullSchema\"];\n\t\tDefaultFieldNullability: false;\n\t\tDefaultArgumentNullability: false;\n\t\tDefaultInputFieldRequiredness: true;\n\t}>({\n\t\tplugins: [DrizzlePlugin],\n\t\tdrizzle: {\n\t\t\tclient: db,\n\t\t},\n\t\tdefaultFieldNullability: false,\n\t\tdefaultInputFieldRequiredness: true,\n\t});\n\n\tnativeBuilder.queryType({});\n\n\tif (!onlyQuery) {\n\t\tnativeBuilder.mutationType({});\n\t}\n\n\tconst implementDefaultObject = <\n\t\tExplicitTableName extends Parameters<typeof nativeBuilder.drizzleObject>[0],\n\t\tRefName extends string,\n\t>({\n\t\ttableName,\n\t\tname,\n\t\treadAction = \"read\" as Action,\n\t}: {\n\t\ttableName: ExplicitTableName;\n\t\tname: RefName;\n\t\treadAction?: Action;\n\t}) => {\n\t\tconst schema = db._.schema![tableName];\n\t\treturn nativeBuilder.drizzleObject(tableName, {\n\t\t\tname,\n\t\t\tfields: (t) => {\n\t\t\t\tconst mapSQLTypeStringToExposedPothosType = (\n\t\t\t\t\tsqlType: string,\n\t\t\t\t\tcolumnName: string,\n\t\t\t\t) => {\n\t\t\t\t\tswitch (sqlType) {\n\t\t\t\t\t\tcase \"serial\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeInt(columnName);\n\t\t\t\t\t\tcase \"int\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeInt(columnName);\n\t\t\t\t\t\tcase \"string\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeString(columnName);\n\t\t\t\t\t\tcase \"text\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeString(columnName);\n\t\t\t\t\t\tcase \"boolean\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeBoolean(columnName);\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow new RumbleError(\n\t\t\t\t\t\t\t\t`Unknown SQL type: ${sqlType}. Please open an issue so it can be added.`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tconst fields = Object.entries(schema.columns).reduce(\n\t\t\t\t\t(acc, [key, value]) => {\n\t\t\t\t\t\tacc[key] = mapSQLTypeStringToExposedPothosType(\n\t\t\t\t\t\t\tvalue.getSQLType(),\n\t\t\t\t\t\t\tvalue.name,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{} as Record<\n\t\t\t\t\t\tstring,\n\t\t\t\t\t\tReturnType<typeof mapSQLTypeStringToExposedPothosType>\n\t\t\t\t\t>,\n\t\t\t\t);\n\n\t\t\t\tconst relations = Object.entries(schema.relations).reduce(\n\t\t\t\t\t(acc, [key, value]) => {\n\t\t\t\t\t\tacc[key] = t.relation(key, {\n\t\t\t\t\t\t\tquery: (_args: any, ctx: any) =>\n\t\t\t\t\t\t\t\tctx.abilities[tableName].filter(readAction),\n\t\t\t\t\t\t} as any) as any;\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{} as Record<\n\t\t\t\t\t\tstring,\n\t\t\t\t\t\tReturnType<typeof mapSQLTypeStringToExposedPothosType>\n\t\t\t\t\t>,\n\t\t\t\t);\n\n\t\t\t\treturn {\n\t\t\t\t\t...fields,\n\t\t\t\t\t...relations,\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t};\n\n\treturn {\n\t\t/**\n * The ability builder. Use it to declare whats allowed for each entity in your DB.\n * \n * @example\n * \n * ```ts\n * // users can edit themselves\n abilityBuilder.users\n .allow([\"read\", \"update\", \"delete\"])\n .when(({ userId }) => ({ where: eq(schema.users.id, userId) }));\n \n // everyone can read posts\n abilityBuilder.posts.allow(\"read\");\n * \n * ```\n */\n\t\tabilityBuilder,\n\t\t/**\n\t\t * The pothos schema builder. See https://pothos-graphql.dev/docs/plugins/drizzle\n\t\t */\n\t\tschemaBuilder: nativeBuilder,\n\t\t/**\n * The native yoga instance. Can be used to run an actual HTTP server.\n * \n * @example\n * \n * ```ts\n import { createServer } from \"node:http\";\n * const server = createServer(yoga());\n server.listen(3000, () => {\n console.log(\"Visit http://localhost:3000/graphql\");\n });\n * ```\n */\n\t\tyoga: () =>\n\t\t\tcreateYoga<RequestEvent>({\n\t\t\t\t...nativeServerOptions,\n\t\t\t\tschema: nativeBuilder.toSchema(),\n\t\t\t\tcontext: makeContext,\n\t\t\t}),\n\t\t/**\n\t\t * A function for creating default objects for your schema\n\t\t */\n\t\timplementDefaultObject,\n\t};\n};\n","import { RumbleError } from \"./rumbleError\";\n\n/**\n * \n * Helper function to map a drizzle findFirst query result,\n * which may be optional, to a correct drizzle type.\n * \n * @throws RumbleError\n * \n * @example\n * \n * ```ts\n * schemaBuilder.queryFields((t) => {\n return {\n findFirstUser: t.drizzleField({\n type: UserRef,\n resolve: (query, root, args, ctx, info) => {\n return (\n db.query.users\n .findFirst({\n ...query,\n where: ctx.abilities.users.filter(\"read\").where,\n })\n // note that we need to manually raise an error if the value is not found\n .then(assertFindFirstExists)\n );\n },\n }),\n };\n });\n * ```\n */\nexport const assertFindFirstExists = <T>(value: T | undefined): T => {\n\tif (!value) throw new RumbleError(\"Value not found but required (findFirst)\");\n\treturn value;\n};\n\n/**\n * \n * Helper function to map a drizzle findFirst query result,\n * which may be optional, to a correct drizzle type.\n * \n * @throws RumbleError\n * \n * @example\n * \n * ```ts\n schemaBuilder.mutationFields((t) => {\n return {\n updateUsername: t.drizzleField({\n type: UserRef,\n args: {\n userId: t.arg.int({ required: true }),\n newName: t.arg.string({ required: true }),\n },\n resolve: (query, root, args, ctx, info) => {\n return db\n .update(schema.users)\n .set({\n name: args.newName,\n })\n .where(\n and(\n eq(schema.users.id, args.userId),\n ctx.abilities.users.filter(\"update\").where\n )\n )\n .returning({ id: schema.users.id, name: schema.users.name })\n // note that we need to manually raise an error if the value is not found\n .then(assertFirstEntryExists);\n },\n }),\n };\n });\n * ```\n */\nexport const assertFirstEntryExists = <T>(value: T[]): T => {\n\tconst v = value.at(0);\n\tif (!v) throw new RumbleError(\"Value not found but required (firstEntry)\");\n\treturn v;\n};\n"]}
|
1
|
+
{"version":3,"sources":["../lib/abilities/builder.ts","../lib/helpers/rumbleError.ts","../lib/gql/builder.ts","../lib/helpers/helper.ts"],"names":["isSimpleCondition","condition","isSyncFunctionCondition","createAbilityBuilder","db","builder","registeredConditions","createEntityObject","entityKey","action","conditionsPerEntity","actions","conditionsPerEntityAndAction","userContext","simpleConditions","syncFunctionConditions","allConditionObjects","highestLimit","conditionObject","combinedAllowedColumns","accumulatedWhereConditions","o","or","RumbleError","message","rumble","nativeServerOptions","makeUserContext","onlyQuery","abilityBuilder","makeContext","req","nativeBuilder","SchemaBuilder","DrizzlePlugin","createYoga","tableName","name","readAction","schema","t","mapSQLTypeStringToExposedPothosType","sqlType","columnName","fields","acc","key","value","relations","_args","ctx","assertFindFirstExists","assertFirstEntryExists","v"],"mappings":"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","file":"index.js","sourcesContent":["import { or } from \"drizzle-orm\";\nimport type {\n\tGenericDrizzleDbTypeConstraints,\n\tQueryConditionObject,\n} from \"../types/genericDrizzleDbType\";\n\nexport type AbilityBuilder = ReturnType<typeof createAbilityBuilder>;\n\ntype Condition<DBParameters, UserContext> =\n\t| SimpleCondition<DBParameters>\n\t| SyncFunctionCondition<DBParameters, UserContext>;\n// | AsyncFunctionCondition<DBParameters, UserContext>;\n\ntype SimpleCondition<DBParameters> = DBParameters;\ntype SyncFunctionCondition<DBParameters, UserContext> = (\n\tcontext: UserContext,\n) => DBParameters;\n// type AsyncFunctionCondition<DBParameters, UserContext> = (\n// \tcontext: UserContext,\n// ) => Promise<DBParameters>;\n\n// type guards for the condition types\nfunction isSimpleCondition<DBParameters, UserContext>(\n\tcondition: Condition<DBParameters, UserContext>,\n): condition is SimpleCondition<DBParameters> {\n\treturn typeof condition !== \"function\";\n}\n\nfunction isSyncFunctionCondition<DBParameters, UserContext>(\n\tcondition: Condition<DBParameters, UserContext>,\n): condition is SyncFunctionCondition<DBParameters, UserContext> {\n\treturn (\n\t\ttypeof condition === \"function\" &&\n\t\tcondition.constructor.name !== \"AsyncFunction\"\n\t);\n}\n\n// function isAsyncFunctionCondition<DBParameters, UserContext>(\n// \tcondition: Condition<DBParameters, UserContext>,\n// ): condition is AsyncFunctionCondition<DBParameters, UserContext> {\n// \treturn (\n// \t\ttypeof condition === \"function\" &&\n// \t\tcondition.constructor.name === \"AsyncFunction\"\n// \t);\n// }\n\nexport const createAbilityBuilder = <\n\tUserContext extends Record<string, any>,\n\tDB extends GenericDrizzleDbTypeConstraints,\n\tAction extends string,\n>({\n\tdb,\n}: {\n\tdb: DB;\n}) => {\n\ttype DBQueryKey = keyof DB[\"query\"];\n\ttype DBParameters = Parameters<DB[\"query\"][DBQueryKey][\"findMany\"]>[0];\n\n\tconst builder: {\n\t\t[key in DBQueryKey]: ReturnType<typeof createEntityObject>;\n\t} = {} as any;\n\n\tconst registeredConditions: {\n\t\t[key in DBQueryKey]: {\n\t\t\t[key in Action[number]]: (\n\t\t\t\t| QueryConditionObject\n\t\t\t\t| ((context: UserContext) => QueryConditionObject)\n\t\t\t)[];\n\t\t\t// | ((context: UserContext) => Promise<QueryConditionObject>)\n\t\t};\n\t} = {} as any;\n\n\tconst createEntityObject = (entityKey: DBQueryKey) => ({\n\t\tallow: (action: Action | Action[]) => {\n\t\t\tlet conditionsPerEntity = registeredConditions[entityKey];\n\t\t\tif (!conditionsPerEntity) {\n\t\t\t\tconditionsPerEntity = {} as any;\n\t\t\t\tregisteredConditions[entityKey] = conditionsPerEntity;\n\t\t\t}\n\n\t\t\tconst actions = Array.isArray(action) ? action : [action];\n\t\t\tfor (const action of actions) {\n\t\t\t\tlet conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\tif (!conditionsPerEntityAndAction) {\n\t\t\t\t\tconditionsPerEntityAndAction = [];\n\t\t\t\t\tconditionsPerEntity[action] = conditionsPerEntityAndAction;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\twhen: (condition: Condition<DBParameters, UserContext>) => {\n\t\t\t\t\tfor (const action of actions) {\n\t\t\t\t\t\tconst conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\t\t\tconditionsPerEntityAndAction.push(condition);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n\n\tfor (const entityKey of Object.keys(db.query) as DBQueryKey[]) {\n\t\tbuilder[entityKey] = createEntityObject(entityKey);\n\t}\n\treturn {\n\t\t...builder,\n\t\tregisteredConditions,\n\t\tbuildWithUserContext: (userContext: UserContext) => {\n\t\t\tconst builder: {\n\t\t\t\t[key in DBQueryKey]: ReturnType<typeof createEntityObject>;\n\t\t\t} = {} as any;\n\n\t\t\tconst createEntityObject = (entityKey: DBQueryKey) => ({\n\t\t\t\tfilter: (action: Action) => {\n\t\t\t\t\tconst conditionsPerEntity = registeredConditions[entityKey];\n\t\t\t\t\tif (!conditionsPerEntity) {\n\t\t\t\t\t\tthrow \"TODO (No allowed entry found for this condition) #1\";\n\t\t\t\t\t}\n\n\t\t\t\t\tconst conditionsPerEntityAndAction = conditionsPerEntity[action];\n\t\t\t\t\tif (!conditionsPerEntityAndAction) {\n\t\t\t\t\t\tthrow \"TODO (No allowed entry found for this condition) #2\";\n\t\t\t\t\t}\n\n\t\t\t\t\tconst simpleConditions =\n\t\t\t\t\t\tconditionsPerEntityAndAction.filter(isSimpleCondition);\n\n\t\t\t\t\tconst syncFunctionConditions = conditionsPerEntityAndAction\n\t\t\t\t\t\t.filter(isSyncFunctionCondition)\n\t\t\t\t\t\t.map((condition) => condition(userContext));\n\n\t\t\t\t\t// const asyncFunctionConditions = await Promise.all(\n\t\t\t\t\t// \tconditionsPerEntityAndAction\n\t\t\t\t\t// \t\t.filter(isAsyncFunctionCondition)\n\t\t\t\t\t// \t\t.map((condition) => condition(userContext)),\n\t\t\t\t\t// );\n\n\t\t\t\t\tconst allConditionObjects = [\n\t\t\t\t\t\t...simpleConditions,\n\t\t\t\t\t\t...syncFunctionConditions,\n\t\t\t\t\t\t// ...asyncFunctionConditions,\n\t\t\t\t\t];\n\n\t\t\t\t\tlet highestLimit = undefined;\n\t\t\t\t\tfor (const conditionObject of allConditionObjects) {\n\t\t\t\t\t\tif (conditionObject.limit) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\thighestLimit === undefined ||\n\t\t\t\t\t\t\t\tconditionObject.limit > highestLimit\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\thighestLimit = conditionObject.limit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet combinedAllowedColumns: Record<string, any> | undefined =\n\t\t\t\t\t\tundefined;\n\t\t\t\t\tfor (const conditionObject of allConditionObjects) {\n\t\t\t\t\t\tif (conditionObject.columns) {\n\t\t\t\t\t\t\tif (combinedAllowedColumns === undefined) {\n\t\t\t\t\t\t\t\tcombinedAllowedColumns = conditionObject.columns;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcombinedAllowedColumns = {\n\t\t\t\t\t\t\t\t\t...combinedAllowedColumns,\n\t\t\t\t\t\t\t\t\t...conditionObject.columns,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst accumulatedWhereConditions = allConditionObjects\n\t\t\t\t\t\t.filter((o) => o.where)\n\t\t\t\t\t\t.map((o) => o.where);\n\n\t\t\t\t\tconst combinedWhere =\n\t\t\t\t\t\taccumulatedWhereConditions.length > 0\n\t\t\t\t\t\t\t? or(...accumulatedWhereConditions)\n\t\t\t\t\t\t\t: undefined;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\twhere: combinedWhere,\n\t\t\t\t\t\tcolumns: combinedAllowedColumns,\n\t\t\t\t\t\tlimit: highestLimit,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tfor (const entityKey of Object.keys(db.query) as DBQueryKey[]) {\n\t\t\t\tbuilder[entityKey] = createEntityObject(entityKey);\n\t\t\t}\n\n\t\t\treturn builder;\n\t\t},\n\t};\n};\n","export class RumbleError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"RumbleError\";\n\t}\n}\n","import SchemaBuilder from \"@pothos/core\";\nimport DrizzlePlugin from \"@pothos/plugin-drizzle\";\nimport { type YogaServerOptions, createYoga } from \"graphql-yoga\";\nimport { createAbilityBuilder } from \"../abilities/builder\";\nimport { RumbleError } from \"../helpers/rumbleError\";\nimport type { GenericDrizzleDbTypeConstraints } from \"../types/genericDrizzleDbType\";\n\nexport const rumble = <\n\tUserContext extends Record<string, any>,\n\tDB extends GenericDrizzleDbTypeConstraints,\n\tRequestEvent extends Record<string, any>,\n\tAction extends string = \"create\" | \"read\" | \"update\" | \"delete\",\n>({\n\tdb,\n\tnativeServerOptions,\n\tcontext: makeUserContext,\n\tonlyQuery = false,\n\tactions = [\"create\", \"read\", \"update\", \"delete\"] as Action[],\n}: {\n\t/**\n\t * Your drizzle database instance\n\t */\n\tdb: DB;\n\t/**\n\t * Optional options for the native GraphQL Yoga server\n\t */\n\tnativeServerOptions?:\n\t\t| Omit<YogaServerOptions<RequestEvent, any>, \"schema\" | \"context\">\n\t\t| undefined;\n\t/**\n\t * A function for providing context for each request based on the incoming HTTP Request.\n\t * The type of the parameter equals the HTTPRequest type of your chosen server.\n\t */\n\tcontext?:\n\t\t| ((event: RequestEvent) => Promise<UserContext> | UserContext)\n\t\t| undefined;\n\t/**\n\t * If you only want to create queries and do not need mutations, enable this\n\t */\n\tonlyQuery?: boolean;\n\t/**\n\t * The actions that are available\n\t */\n\tactions?: Action[];\n}) => {\n\tconst abilityBuilder = createAbilityBuilder<UserContext, DB, Action>({\n\t\tdb,\n\t});\n\n\tconst makeContext = async (req: RequestEvent) => {\n\t\tconst userContext = makeUserContext\n\t\t\t? await makeUserContext(req)\n\t\t\t: ({} as UserContext);\n\t\treturn {\n\t\t\t...userContext,\n\t\t\tabilities: abilityBuilder.buildWithUserContext(userContext),\n\t\t};\n\t};\n\n\tconst nativeBuilder = new SchemaBuilder<{\n\t\tContext: Awaited<ReturnType<typeof makeContext>>;\n\t\t// Scalars: Scalars<Prisma.Decimal, Prisma.InputJsonValue | null, Prisma.InputJsonValue> & {\n\t\t// \tFile: {\n\t\t// \t\tInput: File;\n\t\t// \t\tOutput: never;\n\t\t// \t};\n\t\t// \tJSONObject: {\n\t\t// \t\tInput: any;\n\t\t// \t\tOutput: any;\n\t\t// \t};\n\t\t// };\n\t\tDrizzleSchema: DB[\"_\"][\"fullSchema\"];\n\t\tDefaultFieldNullability: false;\n\t\tDefaultArgumentNullability: false;\n\t\tDefaultInputFieldRequiredness: true;\n\t}>({\n\t\tplugins: [DrizzlePlugin],\n\t\tdrizzle: {\n\t\t\tclient: db,\n\t\t},\n\t\tdefaultFieldNullability: false,\n\t\tdefaultInputFieldRequiredness: true,\n\t});\n\n\tnativeBuilder.queryType({});\n\n\tif (!onlyQuery) {\n\t\tnativeBuilder.mutationType({});\n\t}\n\n\tconst implementDefaultObject = <\n\t\tExplicitTableName extends Parameters<typeof nativeBuilder.drizzleObject>[0],\n\t\tRefName extends string,\n\t>({\n\t\ttableName,\n\t\tname,\n\t\treadAction = \"read\" as Action,\n\t}: {\n\t\ttableName: ExplicitTableName;\n\t\tname: RefName;\n\t\treadAction?: Action;\n\t}) => {\n\t\tconst schema = db._.schema![tableName];\n\t\treturn nativeBuilder.drizzleObject(tableName, {\n\t\t\tname,\n\t\t\tfields: (t) => {\n\t\t\t\tconst mapSQLTypeStringToExposedPothosType = (\n\t\t\t\t\tsqlType: string,\n\t\t\t\t\tcolumnName: string,\n\t\t\t\t) => {\n\t\t\t\t\tswitch (sqlType) {\n\t\t\t\t\t\tcase \"serial\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeInt(columnName);\n\t\t\t\t\t\tcase \"int\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeInt(columnName);\n\t\t\t\t\t\tcase \"string\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeString(columnName);\n\t\t\t\t\t\tcase \"text\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeString(columnName);\n\t\t\t\t\t\tcase \"boolean\":\n\t\t\t\t\t\t\t// @ts-expect-error\n\t\t\t\t\t\t\treturn t.exposeBoolean(columnName);\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow new RumbleError(\n\t\t\t\t\t\t\t\t`Unknown SQL type: ${sqlType}. Please open an issue so it can be added.`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tconst fields = Object.entries(schema.columns).reduce(\n\t\t\t\t\t(acc, [key, value]) => {\n\t\t\t\t\t\tacc[key] = mapSQLTypeStringToExposedPothosType(\n\t\t\t\t\t\t\tvalue.getSQLType(),\n\t\t\t\t\t\t\tvalue.name,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{} as Record<\n\t\t\t\t\t\tstring,\n\t\t\t\t\t\tReturnType<typeof mapSQLTypeStringToExposedPothosType>\n\t\t\t\t\t>,\n\t\t\t\t);\n\n\t\t\t\tconst relations = Object.entries(schema.relations).reduce(\n\t\t\t\t\t(acc, [key, value]) => {\n\t\t\t\t\t\tacc[key] = t.relation(key, {\n\t\t\t\t\t\t\tquery: (_args: any, ctx: any) =>\n\t\t\t\t\t\t\t\tctx.abilities[tableName].filter(readAction),\n\t\t\t\t\t\t} as any) as any;\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{} as Record<\n\t\t\t\t\t\tstring,\n\t\t\t\t\t\tReturnType<typeof mapSQLTypeStringToExposedPothosType>\n\t\t\t\t\t>,\n\t\t\t\t);\n\n\t\t\t\treturn {\n\t\t\t\t\t...fields,\n\t\t\t\t\t...relations,\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t};\n\n\treturn {\n\t\t/**\n * The ability builder. Use it to declare whats allowed for each entity in your DB.\n * \n * @example\n * \n * ```ts\n * // users can edit themselves\n abilityBuilder.users\n .allow([\"read\", \"update\", \"delete\"])\n .when(({ userId }) => ({ where: eq(schema.users.id, userId) }));\n \n // everyone can read posts\n abilityBuilder.posts.allow(\"read\");\n * \n * ```\n */\n\t\tabilityBuilder,\n\t\t/**\n\t\t * The pothos schema builder. See https://pothos-graphql.dev/docs/plugins/drizzle\n\t\t */\n\t\tschemaBuilder: nativeBuilder,\n\t\t/**\n * The native yoga instance. Can be used to run an actual HTTP server.\n * \n * @example\n * \n * ```ts\n import { createServer } from \"node:http\";\n * const server = createServer(yoga());\n server.listen(3000, () => {\n console.log(\"Visit http://localhost:3000/graphql\");\n });\n * ```\n */\n\t\tyoga: () =>\n\t\t\tcreateYoga<RequestEvent>({\n\t\t\t\t...nativeServerOptions,\n\t\t\t\tschema: nativeBuilder.toSchema(),\n\t\t\t\tcontext: makeContext,\n\t\t\t}),\n\t\t/**\n\t\t * A function for creating default objects for your schema\n\t\t */\n\t\timplementDefaultObject,\n\t};\n};\n","import { RumbleError } from \"./rumbleError\";\n\n/**\n * \n * Helper function to map a drizzle findFirst query result,\n * which may be optional, to a correct drizzle type.\n * \n * @throws RumbleError\n * \n * @example\n * \n * ```ts\n * schemaBuilder.queryFields((t) => {\n return {\n findFirstUser: t.drizzleField({\n type: UserRef,\n resolve: (query, root, args, ctx, info) => {\n return (\n db.query.users\n .findFirst({\n ...query,\n where: ctx.abilities.users.filter(\"read\").where,\n })\n // note that we need to manually raise an error if the value is not found\n .then(assertFindFirstExists)\n );\n },\n }),\n };\n });\n * ```\n */\nexport const assertFindFirstExists = <T>(value: T | undefined): T => {\n\tif (!value) throw new RumbleError(\"Value not found but required (findFirst)\");\n\treturn value;\n};\n\n/**\n * \n * Helper function to map a drizzle findFirst query result,\n * which may be optional, to a correct drizzle type.\n * \n * @throws RumbleError\n * \n * @example\n * \n * ```ts\n schemaBuilder.mutationFields((t) => {\n return {\n updateUsername: t.drizzleField({\n type: UserRef,\n args: {\n userId: t.arg.int({ required: true }),\n newName: t.arg.string({ required: true }),\n },\n resolve: (query, root, args, ctx, info) => {\n return db\n .update(schema.users)\n .set({\n name: args.newName,\n })\n .where(\n and(\n eq(schema.users.id, args.userId),\n ctx.abilities.users.filter(\"update\").where\n )\n )\n .returning({ id: schema.users.id, name: schema.users.name })\n // note that we need to manually raise an error if the value is not found\n .then(assertFirstEntryExists);\n },\n }),\n };\n });\n * ```\n */\nexport const assertFirstEntryExists = <T>(value: T[]): T => {\n\tconst v = value.at(0);\n\tif (!v) throw new RumbleError(\"Value not found but required (firstEntry)\");\n\treturn v;\n};\n"]}
|
package/package.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"name":"@m1212e/rumble","module":"index.ts","type":"module","peerDependencies":{"typescript":"^5.7.2","drizzle-orm":"^0.38.3"},"dependencies":{"@pothos/plugin-drizzle":"^0.5.3","graphql-yoga":"^5.10.8","@pothos/core":"^4.3.0"},"version":"0.0.
|
1
|
+
{"name":"@m1212e/rumble","module":"index.ts","type":"module","peerDependencies":{"typescript":"^5.7.2","drizzle-orm":"^0.38.3"},"dependencies":{"@pothos/plugin-drizzle":"^0.5.3","graphql-yoga":"^5.10.8","@pothos/core":"^4.3.0"},"version":"0.0.7","exports":{"./package.json":"./package.json",".":{"require":"./index.cjs","import":"./index.js","node":"./index.cjs","default":"./index.cjs"}}}
|