Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion packages/runtime/src/enhancements/node/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ export function makeProxy<T extends PrismaProxyHandler>(
return propVal;
}

return createHandlerProxy(makeHandler(target, prop), propVal, prop, errorTransformer);
return createHandlerProxy(makeHandler(target, prop), propVal, prop, proxy, errorTransformer);
},
});

Expand All @@ -303,10 +303,15 @@ function createHandlerProxy<T extends PrismaProxyHandler>(
handler: T,
origTarget: any,
model: string,
dbOrTx: any,
errorTransformer?: ErrorTransformer
): T {
return new Proxy(handler, {
get(target, propKey) {
if (propKey === '$parent') {
return dbOrTx;
}

const prop = target[propKey as keyof T];
if (typeof prop !== 'function') {
// the proxy handler doesn't have this method, fall back to the original target
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { loadSchema } from '@zenstackhq/testtools';

describe('Proxy Extension Context', () => {
it('works', async () => {
const { enhance } = await loadSchema(
`
model Counter {
model String @unique
value Int

@@allow('all', true)
}

model Address {
id String @id @default(cuid())
city String

@@allow('all', true)
}
`
);

const db = enhance();
const dbExtended = db.$extends({
client: {
$one() {
return 1;
}
},
model: {
$allModels: {
async createWithCounter(this: any, args: any) {
const modelName = this.$name;
const dbOrTx = this.$parent;

// prisma exposes some internal properties, makes sure these are still preserved
expect(dbOrTx._engine).toBeDefined();

const fn = async (tx: any) => {
const counter = await tx.counter.findUnique({
where: { model: modelName },
});

await tx.counter.upsert({
where: { model: modelName },
update: { value: (counter?.value ?? 0) + tx.$one() },
create: { model: modelName, value: tx.$one() },
});

return tx[modelName].create(args);
};

if (dbOrTx['$transaction']) {
// not running in a transaction, so we need to create a new transaction
return dbOrTx.$transaction(fn);
}

return fn(dbOrTx);
},
},
},
});

const cities = ['Vienna', 'New York', 'Delhi'];

await Promise.all([
...cities.map((city) => dbExtended.address.createWithCounter({ data: { city } })),
...cities.map((city) =>
dbExtended.$transaction((tx: any) => tx.address.createWithCounter({ data: { city: `${city}$tx` } }))
),
]);

await expect(dbExtended.counter.findUniqueOrThrow({ where: { model: 'Address' } })).resolves.toMatchObject({
model: 'Address',
value: cities.length * 2,
});
});
});
Loading