|
| 1 | +import { MongoContractSerializer } from '@prisma-next/family-mongo/ir'; |
| 2 | +import { mongoOrm } from '@prisma-next/mongo-orm'; |
| 3 | +import { MongoFieldFilter, MongoOrExpr } from '@prisma-next/mongo-query-ast/execution'; |
| 4 | +import { expect, it } from 'vitest'; |
| 5 | +import type { Contract } from './fixtures/generated/contract'; |
| 6 | +import ormContractJson from './fixtures/generated/contract.json'; |
| 7 | +import { describeWithMongoDB } from './setup'; |
| 8 | + |
| 9 | +const contract = new MongoContractSerializer().deserializeContract(ormContractJson) as Contract; |
| 10 | + |
| 11 | +// Ported from upstream MongoDB-only regressions: |
| 12 | +// #103 prisma/prisma#13089 — a `$`-prefixed string value is data, not a Mongo operator. |
| 13 | +// #104 prisma-engines prisma_22007 — `OR: [{ NOT: { f: "b" } }, { f: "c" } ]` evaluates to {a, c}. |
| 14 | +describeWithMongoDB('ported MongoDB regressions', (ctx) => { |
| 15 | + it('#103 filters by a string value containing a literal `$`', async () => { |
| 16 | + const db = ctx.client.db(ctx.dbName); |
| 17 | + await db.collection('users').insertMany([ |
| 18 | + { name: 'foo', email: 'foo@example.com', addresses: [] }, |
| 19 | + { name: '$foo', email: 'dollar-foo@example.com', addresses: [] }, |
| 20 | + ]); |
| 21 | + |
| 22 | + const orm = mongoOrm({ contract, executor: ctx.runtime }); |
| 23 | + const results = await orm.users.where(MongoFieldFilter.eq('name', '$foo')).all(); |
| 24 | + |
| 25 | + expect(results).toHaveLength(1); |
| 26 | + expect(results[0]).toMatchObject({ name: '$foo', email: 'dollar-foo@example.com' }); |
| 27 | + }); |
| 28 | + |
| 29 | + it('#103 updates a record matched by a string value containing a literal `$`', async () => { |
| 30 | + const db = ctx.client.db(ctx.dbName); |
| 31 | + await db.collection('users').insertMany([ |
| 32 | + { name: 'foo', email: 'foo@example.com', addresses: [] }, |
| 33 | + { name: '$foo', email: 'dollar-foo@example.com', addresses: [] }, |
| 34 | + ]); |
| 35 | + |
| 36 | + const orm = mongoOrm({ contract, executor: ctx.runtime }); |
| 37 | + const updated = await orm.users |
| 38 | + .where(MongoFieldFilter.eq('name', '$foo')) |
| 39 | + .update({ name: '$$foo' }); |
| 40 | + |
| 41 | + expect(updated).toMatchObject({ name: '$$foo', email: 'dollar-foo@example.com' }); |
| 42 | + |
| 43 | + const afterUpdate = await orm.users.where(MongoFieldFilter.eq('name', '$$foo')).all(); |
| 44 | + expect(afterUpdate).toHaveLength(1); |
| 45 | + expect(afterUpdate[0]).toMatchObject({ name: '$$foo' }); |
| 46 | + |
| 47 | + const originalGone = await orm.users.where(MongoFieldFilter.eq('name', '$foo')).all(); |
| 48 | + expect(originalGone).toHaveLength(0); |
| 49 | + }); |
| 50 | + |
| 51 | + it('#104 renders `OR: [{ NOT: b }, c ]` to the {a, c} result set', async () => { |
| 52 | + const db = ctx.client.db(ctx.dbName); |
| 53 | + await db.collection('users').insertMany([ |
| 54 | + { name: 'a', email: 'a@example.com', addresses: [] }, |
| 55 | + { name: 'b', email: 'b@example.com', addresses: [] }, |
| 56 | + { name: 'c', email: 'c@example.com', addresses: [] }, |
| 57 | + ]); |
| 58 | + |
| 59 | + const orm = mongoOrm({ contract, executor: ctx.runtime }); |
| 60 | + const filter = MongoOrExpr.of([ |
| 61 | + MongoFieldFilter.eq('name', 'b').not(), |
| 62 | + MongoFieldFilter.eq('name', 'c'), |
| 63 | + ]); |
| 64 | + const results = await orm.users.where(filter).orderBy({ name: 1 }).all(); |
| 65 | + |
| 66 | + expect(results).toHaveLength(2); |
| 67 | + expect(results.map((r) => r.name)).toEqual(['a', 'c']); |
| 68 | + }); |
| 69 | +}); |
0 commit comments