Skip to content

Commit

Permalink
Release 1.1.6
Browse files Browse the repository at this point in the history
  • Loading branch information
dennemark committed Dec 5, 2024
1 parent 233abda commit 64077dc
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 107 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@


## [1.1.6](https://github.com/dennemark/prisma-extension-casl/compare/1.1.5...1.1.6) (2024-12-05)

### Bug Fixes

* :bug: custom batching function to allow before and after queries ([233abda](https://github.com/dennemark/prisma-extension-casl/commit/233abdafbac3607761e822dd528d7b7733f4d72d))

## [1.1.5](https://github.com/dennemark/prisma-extension-casl/compare/1.1.4...1.1.5) (2024-12-05)

### Bug Fixes
Expand Down
11 changes: 11 additions & 0 deletions dist/index.d.mts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ type PrismaExtensionCaslOptions = {
beforeQuery?: (tx: Prisma.TransactionClient) => Promise<void>;
/** uses transaction to allow using client queries after actual query, if fails, whole query will be rolled back */
afterQuery?: (tx: Prisma.TransactionClient) => Promise<void>;
/** max wait for batch transaction - default 30000 */
txMaxWait?: number;
/** timeout for batch transaction - default 30000 */
txTimeout?: number;
};
type PrismaCaslOperation = 'create' | 'createMany' | 'createManyAndReturn' | 'upsert' | 'findFirst' | 'findFirstOrThrow' | 'findMany' | 'findUnique' | 'findUniqueOrThrow' | 'aggregate' | 'count' | 'groupBy' | 'update' | 'updateMany' | 'delete' | 'deleteMany';

Expand Down Expand Up @@ -109,6 +113,13 @@ declare function useCaslAbilities(getAbilityFactory: () => AbilityBuilder<PureAb
};
};
};
/**
* recreates getBatchId from prisma
* //https://github.com/prisma/prisma/blob/1a9ef0fbd3948ee708add6816a33743e1ff7df9c/packages/client/src/runtime/core/jsonProtocol/getBatchId.ts#L4
*
* @param query
* @returns
*/
declare function getBatchId(query: any): string | undefined;

export { applyCaslToQuery, getBatchId, useCaslAbilities };
11 changes: 11 additions & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ type PrismaExtensionCaslOptions = {
beforeQuery?: (tx: Prisma.TransactionClient) => Promise<void>;
/** uses transaction to allow using client queries after actual query, if fails, whole query will be rolled back */
afterQuery?: (tx: Prisma.TransactionClient) => Promise<void>;
/** max wait for batch transaction - default 30000 */
txMaxWait?: number;
/** timeout for batch transaction - default 30000 */
txTimeout?: number;
};
type PrismaCaslOperation = 'create' | 'createMany' | 'createManyAndReturn' | 'upsert' | 'findFirst' | 'findFirstOrThrow' | 'findMany' | 'findUnique' | 'findUniqueOrThrow' | 'aggregate' | 'count' | 'groupBy' | 'update' | 'updateMany' | 'delete' | 'deleteMany';

Expand Down Expand Up @@ -109,6 +113,13 @@ declare function useCaslAbilities(getAbilityFactory: () => AbilityBuilder<PureAb
};
};
};
/**
* recreates getBatchId from prisma
* //https://github.com/prisma/prisma/blob/1a9ef0fbd3948ee708add6816a33743e1ff7df9c/packages/client/src/runtime/core/jsonProtocol/getBatchId.ts#L4
*
* @param query
* @returns
*/
declare function getBatchId(query: any): string | undefined;

export { applyCaslToQuery, getBatchId, useCaslAbilities };
139 changes: 86 additions & 53 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1475,13 +1475,17 @@ function filterQueryResults(result, mask, creationTree, abilities, model, operat

// src/index.ts
function useCaslAbilities(getAbilityFactory, opts) {
const txMaxWait = opts?.txMaxWait ?? 3e4;
const txTimeout = opts?.txTimeout ?? 3e4;
return import_client2.Prisma.defineExtension((client) => {
const transactionsToBatch = /* @__PURE__ */ new Set();
let tickActive = false;
const batches = {};
const allOperations = (getAbilities) => ({
async $allOperations({ args, query, model, operation, ...rest }) {
const fluentModel = getFluentModel(model, rest);
const [fluentRelationModel, fluentRelationField] = (fluentModel !== model ? Object.entries(relationFieldsByModel[model]).find(([k2, v4]) => v4.type === fluentModel) : void 0) ?? [void 0, void 0];
const transaction = rest.__internalParams.transaction;
const __internalParams = rest.__internalParams;
const transaction = __internalParams.transaction;
const debug = (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && args.debugCasl;
const debugAllErrors = args.debugCasl;
delete args.debugCasl;
Expand Down Expand Up @@ -1552,70 +1556,99 @@ function useCaslAbilities(getAbilityFactory, opts) {
if (transaction && transaction.kind === "batch") {
throw new Error("Sequential transactions are not supported in prisma-extension-casl.");
}
const transactionQuery = async (txClient) => {
if (opts?.beforeQuery) {
await opts.beforeQuery(txClient);
}
if (operationAbility.action === "update" || operationAbility.action === "create" || operation === "deleteMany") {
const getMany = operation === "deleteMany" || operation === "updateMany";
const manyResult = getMany ? await txClient[model].findMany(caslQuery.args.where ? { where: caslQuery.args.where } : void 0).then((res) => {
return operation === "updateMany" ? res.map((r2) => ({ ...caslQuery.args.data, id: r2.id })) : res;
}) : [];
const op = operation === "createMany" ? "createManyAndReturn" : operation;
return txClient[model][op](caslQuery.args).then(async (result) => {
if (opts?.afterQuery) {
await opts.afterQuery(txClient);
}
const filteredResult = cleanupResults(getMany ? manyResult : result);
const results = operation === "createMany" ? { count: result.length } : getMany ? { count: manyResult.length } : filteredResult;
return results;
});
} else {
return txClient[model][operation](caslQuery.args).then(async (result) => {
if (opts?.afterQuery) {
await opts.afterQuery(txClient);
}
const fluentField = getFluentField(rest);
if (fluentField) {
return cleanupResults(result?.[fluentField]);
}
return cleanupResults(result);
});
}
};
if (transaction && transaction.kind === "itx") {
return transactionQuery(client._createItxClient(transaction));
const hash = transaction?.id ?? "batch";
if (!batches[hash]) {
batches[hash] = [];
}
if (!tickActive) {
tickActive = true;
process.nextTick(() => {
dispatchBatches(transaction);
tickActive = false;
});
}
const batchQuery = (model2, action, args2, callback) => new Promise((resolve, reject) => {
batches[hash].push({
params: __internalParams,
model: model2,
action,
args: args2,
reject,
resolve,
callback
});
});
if (operationAbility.action === "update" || operationAbility.action === "create" || operation === "deleteMany") {
const getMany = operation === "deleteMany" || operation === "updateMany";
const op = operation === "createMany" ? "createManyAndReturn" : operation;
return batchQuery(model, op, caslQuery.args, async (result) => {
const filteredResult = cleanupResults(result);
const results = operation === "createMany" || operation === "deleteMany" || operation === "updateMany" ? { count: result.length } : filteredResult;
return results;
});
} else {
return client.$transaction(async (tx) => {
const transactionId = tx[Symbol.for("prisma.client.transaction.id")].toString();
transactionsToBatch.add(transactionId);
return transactionQuery(tx).finally(() => {
transactionsToBatch.delete(transactionId);
});
}, {
//https://github.com/prisma/prisma/issues/20015
maxWait: 1e4
// default prisma pool timeout. would be better to get it from client
return batchQuery(model, operation, caslQuery.args, async (result) => {
const fluentField = getFluentField(rest);
if (fluentField) {
return cleanupResults(result?.[fluentField]);
}
return cleanupResults(result);
});
}
}
});
client._requestHandler.dataloader.options.batchBy = (request) => {
const batchId = getBatchId(request.protocolQuery);
if (request.transaction?.id && (!transactionsToBatch.has(request.transaction.id.toString()) && batchId)) {
return `transaction-${request.transaction.id}`;
if (request.transaction?.id) {
return `transaction-${request.transaction.id}${batchId ? `-${batchId}` : ""}`;
}
return batchId;
};
const dispatchBatches = (transaction) => {
for (const [key, batch] of Object.entries(batches)) {
delete batches[key];
const runBatchTransaction = async (tx) => {
if (opts?.beforeQuery) {
await opts.beforeQuery(tx);
}
const results = await Promise.all(
batch.map((request) => {
return tx[request.model][request.action](request.args).then((res) => request.callback(res)).catch((e4) => {
throw e4;
});
})
);
if (opts?.afterQuery) {
await opts?.afterQuery(tx);
}
return results;
};
new Promise((resolve, reject) => {
if (transaction && transaction.kind === "itx") {
runBatchTransaction(client._createItxClient(transaction)).then(resolve).catch(reject);
} else {
client.$transaction(async (tx) => {
return runBatchTransaction(tx);
}, {
maxWait: txMaxWait,
timeout: txTimeout
}).then(resolve).catch(reject);
}
}).then((results) => {
results.forEach((result, index) => {
batch[index].resolve(result);
});
}).catch((e4) => {
for (const request of batch) {
request.reject(e4);
}
delete batches[key];
});
}
};
return client.$extends({
name: "prisma-extension-casl",
client: {
// https://github.com/prisma/prisma/issues/20678
// $transaction(...props: Parameters<(typeof client)['$transaction']>): ReturnType<(typeof client)['$transaction']> {
// return transactionStore.run({ alreadyInTransaction: true }, () => {
// return client.$transaction(...props);
// });
// },
$casl(extendFactory) {
return client.$extends({
query: {
Expand Down
Loading

0 comments on commit 64077dc

Please sign in to comment.