{"_id":"@desolint/db-factories","_rev":"2-9654cd88ce4adc44fcab0b0f051c1b7b","name":"@desolint/db-factories","dist-tags":{"latest":"0.0.2"},"versions":{"0.0.1":{"name":"@desolint/db-factories","version":"0.0.1","keywords":["factories","mongodb","mongoose","prisma","postgresql","crud"],"author":{"name":"Amjad Majed"},"license":"MIT","_id":"@desolint/db-factories@0.0.1","maintainers":[{"name":"amjad992","email":"contact@amjadmajed.com"}],"homepage":"https://github.com/desolint/package-db-factories#readme","bugs":{"url":"https://github.com/desolint/package-db-factories/issues"},"dist":{"shasum":"23047649a6e71413c629f9b03f3447d1584bbbac","tarball":"https://registry.npmjs.org/@desolint/db-factories/-/db-factories-0.0.1.tgz","fileCount":36,"integrity":"sha512-yx7SanOy92hN8/pUIcSkTcL6uxWkT/yTF0HBEnBwiF8zoeVXxL1+F/lkpZQscUAdrOeXEUuAu6Pgy45Z7MAoEg==","signatures":[{"sig":"MEUCIQCn+9V84uTRVDe5vuHFGJQ4rkE4vdV8xquJww4Et/+gRwIgECmNSoQHA4zljWmNRJb5EpSbVw6oZTjFgbs9oJygQO4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":255592},"engines":{"node":">=22"},"exports":{"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing/index.js","require":"./dist/testing/index.js"},"./utils/mongo":{"types":"./dist/utils/mongo/index.d.ts","import":"./dist/utils/mongo/index.js","require":"./dist/utils/mongo/index.js"},"./config/mongo":{"types":"./dist/config/mongo/index.d.ts","import":"./dist/config/mongo/index.js","require":"./dist/config/mongo/index.js"},"./schema/mongo":{"types":"./dist/schema/mongo/index.d.ts","import":"./dist/schema/mongo/index.js","require":"./dist/schema/mongo/index.js"},"./utils/prisma":{"types":"./dist/utils/prisma/index.d.ts","import":"./dist/utils/prisma/index.js","require":"./dist/utils/prisma/index.js"},"./config/prisma":{"types":"./dist/config/prisma/index.d.ts","import":"./dist/config/prisma/index.js","require":"./dist/config/prisma/index.js"},"./schema/prisma":{"types":"./dist/schema/prisma/index.d.ts","import":"./dist/schema/prisma/index.js","require":"./dist/schema/prisma/index.js"},"./services/mongo":{"types":"./dist/services/mongo/index.d.ts","import":"./dist/services/mongo/index.js","require":"./dist/services/mongo/index.js"},"./services/prisma":{"types":"./dist/services/prisma/index.d.ts","import":"./dist/services/prisma/index.js","require":"./dist/services/prisma/index.js"},"./utils/config/mongo":{"types":"./dist/utils/config/mongo/index.d.ts","import":"./dist/utils/config/mongo/index.js","require":"./dist/utils/config/mongo/index.js"},"./utils/config/prisma":{"types":"./dist/utils/config/prisma/index.d.ts","import":"./dist/utils/config/prisma/index.js","require":"./dist/utils/config/prisma/index.js"}},"gitHead":"19a034febcc419f318898cbb496f9015f8637d5b","scripts":{"lint":"eslint","test":"jest","build":"tsc --noEmit && node scripts/build.mjs","prepare":"husky","lint:fix":"eslint --fix"},"_npmUser":{"name":"amjad992","email":"contact@amjadmajed.com"},"repository":{"url":"git+https://github.com/desolint/package-db-factories.git","type":"git"},"_npmVersion":"10.9.3","description":"Generic, injectable DB CRUD factories for Mongo (Mongoose) and Prisma. No root export — import only what you need: @desolint/db-factories/config/mongo, /config/prisma, /schema/mongo, /schema/prisma, /services/mongo, /services/prisma, /utils/mongo, /utils/","directories":{},"lint-staged":{"**/*.{json,md}":["npx prettier --write"],"**/*.{js,jsx,ts,tsx}":["npm run lint","npx prettier --write"]},"_nodeVersion":"22.20.0","publishConfig":{"access":"public"},"typesVersions":{"*":{"testing":["dist/testing/index.d.ts"],"utils/mongo":["dist/utils/mongo/index.d.ts"],"config/mongo":["dist/config/mongo/index.d.ts"],"schema/mongo":["dist/schema/mongo/index.d.ts"],"utils/prisma":["dist/utils/prisma/index.d.ts"],"config/prisma":["dist/config/prisma/index.d.ts"],"schema/prisma":["dist/schema/prisma/index.d.ts"],"services/mongo":["dist/services/mongo/index.d.ts"],"services/prisma":["dist/services/prisma/index.d.ts"],"utils/config/mongo":["dist/utils/config/mongo/index.d.ts"],"utils/config/prisma":["dist/utils/config/prisma/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","jiti":"^2.7.0","husky":"^9.1.7","eslint":"^9.39.2","esbuild":"^0.28.2","globals":"^17.7.0","ts-jest":"^29.4.11","ts-node":"^10.9.2","mongoose":"^8.22.0","prettier":"^3.9.6","@eslint/js":"^9.37.0","typescript":"^5.9.3","@types/jest":"^29.5.14","@types/node":"^24.13.3","lint-staged":"^17.1.0","@types/semver":"^7.8.0","typescript-eslint":"^8.65.0","dts-bundle-generator":"^9.5.1","eslint-plugin-import":"^2.32.0","mongodb-memory-server":"^9.5.0"},"peerDependencies":{"mongoose":"^8","mongodb-memory-server":"^9"},"peerDependenciesMeta":{"mongoose":{"optional":true},"mongodb-memory-server":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/db-factories_0.0.1_1788191924696_0.655468482371226","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@desolint/db-factories","version":"0.0.2","description":"Generic, injectable DB CRUD factories for Mongo (Mongoose) and Prisma. No root export — import only what you need: @desolint/db-factories/config/mongo, /config/prisma, /schema/mongo, /schema/prisma, /services/mongo, /services/prisma, /utils/mongo, /utils/","exports":{"./config/mongo":{"types":"./dist/config/mongo/index.d.ts","import":"./dist/config/mongo/index.js","require":"./dist/config/mongo/index.js"},"./config/prisma":{"types":"./dist/config/prisma/index.d.ts","import":"./dist/config/prisma/index.js","require":"./dist/config/prisma/index.js"},"./schema/mongo":{"types":"./dist/schema/mongo/index.d.ts","import":"./dist/schema/mongo/index.js","require":"./dist/schema/mongo/index.js"},"./schema/prisma":{"types":"./dist/schema/prisma/index.d.ts","import":"./dist/schema/prisma/index.js","require":"./dist/schema/prisma/index.js"},"./services/mongo":{"types":"./dist/services/mongo/index.d.ts","import":"./dist/services/mongo/index.js","require":"./dist/services/mongo/index.js"},"./services/prisma":{"types":"./dist/services/prisma/index.d.ts","import":"./dist/services/prisma/index.js","require":"./dist/services/prisma/index.js"},"./utils/mongo":{"types":"./dist/utils/mongo/index.d.ts","import":"./dist/utils/mongo/index.js","require":"./dist/utils/mongo/index.js"},"./utils/prisma":{"types":"./dist/utils/prisma/index.d.ts","import":"./dist/utils/prisma/index.js","require":"./dist/utils/prisma/index.js"},"./utils/config/mongo":{"types":"./dist/utils/config/mongo/index.d.ts","import":"./dist/utils/config/mongo/index.js","require":"./dist/utils/config/mongo/index.js"},"./utils/config/prisma":{"types":"./dist/utils/config/prisma/index.d.ts","import":"./dist/utils/config/prisma/index.js","require":"./dist/utils/config/prisma/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing/index.js","require":"./dist/testing/index.js"}},"typesVersions":{"*":{"config/mongo":["dist/config/mongo/index.d.ts"],"config/prisma":["dist/config/prisma/index.d.ts"],"schema/mongo":["dist/schema/mongo/index.d.ts"],"schema/prisma":["dist/schema/prisma/index.d.ts"],"services/mongo":["dist/services/mongo/index.d.ts"],"services/prisma":["dist/services/prisma/index.d.ts"],"utils/mongo":["dist/utils/mongo/index.d.ts"],"utils/prisma":["dist/utils/prisma/index.d.ts"],"utils/config/mongo":["dist/utils/config/mongo/index.d.ts"],"utils/config/prisma":["dist/utils/config/prisma/index.d.ts"],"testing":["dist/testing/index.d.ts"]}},"engines":{"node":">=22"},"scripts":{"build":"tsc --noEmit && node scripts/build.mjs","test":"jest","lint":"eslint","lint:fix":"eslint --fix","prepare":"husky"},"keywords":["factories","mongodb","mongoose","prisma","postgresql","crud"],"author":{"name":"Amjad Majed"},"license":"MIT","peerDependencies":{"mongodb-memory-server":"^9","mongoose":"^8"},"peerDependenciesMeta":{"mongodb-memory-server":{"optional":true},"mongoose":{"optional":true}},"devDependencies":{"@eslint/js":"^9.37.0","@types/jest":"^29.5.14","@types/node":"^24.13.3","@types/semver":"^7.8.0","dts-bundle-generator":"^9.5.1","esbuild":"^0.28.2","eslint":"^9.39.2","eslint-plugin-import":"^2.32.0","globals":"^17.7.0","husky":"^9.1.7","jest":"^29.7.0","jiti":"^2.7.0","lint-staged":"^17.1.0","mongodb-memory-server":"^9.5.0","mongoose":"^8.22.0","prettier":"^3.9.6","ts-jest":"^29.4.11","ts-node":"^10.9.2","typescript":"^5.9.3","typescript-eslint":"^8.65.0"},"lint-staged":{"**/*.{js,jsx,ts,tsx}":["npm run lint","npx prettier --write"],"**/*.{json,md}":["npx prettier --write"]},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/desolint/package-db-factories.git"},"_id":"@desolint/db-factories@0.0.2","gitHead":"d761df2aecbe72fc951b4d3c5a3a0033725a7cf2","bugs":{"url":"https://github.com/desolint/package-db-factories/issues"},"homepage":"https://github.com/desolint/package-db-factories#readme","_nodeVersion":"22.20.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-d1B4QluxmSY18dy8tDu6EswNyrcEQ37UiWBGu6BguO+T0Jw+5sryc6qUroDcVn2KEQgMjgNJmYvZNdFWRAbC2w==","shasum":"cd079998389a508b7940aed12ad5e31f4ce8c5d6","tarball":"https://registry.npmjs.org/@desolint/db-factories/-/db-factories-0.0.2.tgz","fileCount":36,"unpackedSize":269178,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAOQf5VmC8G8yO/LSmAyTqurpVt0s7KVT76VIeevu1YEAiEAolgn+XSUVzKKMKzMRu4+7PRJftyI8n9rfOyjgFwSii4="}]},"_npmUser":{"name":"amjad992","email":"contact@amjadmajed.com"},"directories":{},"maintainers":[{"name":"amjad992","email":"contact@amjadmajed.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/db-factories_0.0.2_1788301667745_0.045393549933450794"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T15:58:44.521Z","modified":"2026-09-01T22:27:48.070Z","0.0.1":"2026-08-31T15:58:44.828Z","0.0.2":"2026-09-01T22:27:47.899Z"},"bugs":{"url":"https://github.com/desolint/package-db-factories/issues"},"author":{"name":"Amjad Majed"},"license":"MIT","homepage":"https://github.com/desolint/package-db-factories#readme","keywords":["factories","mongodb","mongoose","prisma","postgresql","crud"],"repository":{"type":"git","url":"git+https://github.com/desolint/package-db-factories.git"},"description":"Generic, injectable DB CRUD factories for Mongo (Mongoose) and Prisma. No root export — import only what you need: @desolint/db-factories/config/mongo, /config/prisma, /schema/mongo, /schema/prisma, /services/mongo, /services/prisma, /utils/mongo, /utils/","maintainers":[{"name":"amjad992","email":"contact@amjadmajed.com"}],"readme":"# @desolint/db-factories\n\nGeneric, injectable DB CRUD factories for Mongo (Mongoose) and Prisma.\n\n**No root export.** `import ... from '@desolint/db-factories'` resolves to\nnothing — every subpath below is adapter-specific, so the import path itself\nis the adapter choice. There's no runtime dispatch, no `type` field to pass,\nno risk of a mongo call silently hitting the prisma branch: you import\n`/mongo` or `/prisma`, and that's the only adapter that code can ever talk\nto.\n\n```\n@desolint/db-factories/config/mongo     @desolint/db-factories/config/prisma\n@desolint/db-factories/schema/mongo     @desolint/db-factories/schema/prisma\n@desolint/db-factories/services/mongo   @desolint/db-factories/services/prisma\n@desolint/db-factories/utils/mongo      @desolint/db-factories/utils/prisma\n@desolint/db-factories/utils/config/mongo   @desolint/db-factories/utils/config/prisma\n@desolint/db-factories/testing\n```\n\n| Subpath                        | What it's for                                                                               |\n| ------------------------------ | ------------------------------------------------------------------------------------------- |\n| `/config/{mongo,prisma}`       | Open the database connection. Nothing else.                                                 |\n| `/schema/{mongo,prisma}`       | Define/reference a model.                                                                   |\n| `/services/{mongo,prisma}`     | The actual CRUD calls — `create`, `find`, `updateOne`, etc.                                 |\n| `/utils/{mongo,prisma}`        | Standalone helpers you call directly (transactions, id validation, field merging).          |\n| `/utils/config/{mongo,prisma}` | Tune how the CRUD factories behave (query scoping, pagination defaults, soft-delete field). |\n| `/testing`                     | Spin up a real, disposable Mongo for tests. Mongo only.                                     |\n\n---\n\n## Requirements\n\n- **Node.js 22 or newer** (declared in `engines`)\n- **npm 7 or newer**\n\n## Install\n\n```bash\n# Mongo consumers\nnpm install @desolint/db-factories mongoose\n\n# Prisma consumers\nnpm install @desolint/db-factories\n```\n\nUnlike most packages here, **you must name your adapter explicitly.** Both peers are\ndeclared `optional` in `peerDependenciesMeta`, and npm does _not_ auto-install optional\npeers — that is deliberate, because a Prisma-only consumer should never be made to pull\nin Mongoose, and vice versa.\n\nIf you use the `/testing` helpers, add the in-memory Mongo server as a dev dependency:\n\n```bash\nnpm install --save-dev mongodb-memory-server\n```\n\n### Why `mongoose` is a peer dependency, not a regular one\n\n`mongoose` holds a **global model registry and connection state**. If this package\nbundled its own copy, models you register in your application would live on a\ndifferent instance than the one these factories query — so lookups would fail, or\nsilently run against a connection you never opened.\n\nDeclaring it as a peer means npm reuses **the copy your application already has**\ninstead of nesting a second one. You keep control of the version; this package just\nstates the range it works with (`mongoose@^8`).\n\nPrisma's generated client (`@prisma/client`) is entirely consumer-owned — this library\nnever imports it itself, so it is not a peer at all.\n\n---\n\n## Quick start\n\n### Mongo\n\n```js\n// config/db.js\nimport {initializeConnection} from '@desolint/db-factories/config/mongo';\n\ninitializeConnection({\n  connectionString: process.env.DATABASE_URL,\n  onConnection: () => console.log('Connected to Database'),\n  onError: (error) => console.error('Error connecting Database', {error}),\n});\n```\n\n```js\n// models/Users.js\nimport {Schema, model} from '@desolint/db-factories/schema/mongo';\n\nconst userSchema = new Schema({\n  email: {type: String, required: true, unique: true},\n  password: {type: String, required: true},\n});\n\nexport default model('User', userSchema);\n```\n\n```js\n// controllers/users.js\nimport * as DbFactory from '@desolint/db-factories/services/mongo';\nimport UsersModel from '../models/Users.js';\n\nconst {\n  doc: user,\n  success,\n  error,\n} = await DbFactory.create({\n  model: UsersModel,\n  data: req.body,\n});\n```\n\n### Prisma\n\n```js\n// config/db.js\nimport {PrismaPg} from '@prisma/adapter-pg';\nimport {PrismaClient} from '@prisma/client';\nimport {initializeConnection} from '@desolint/db-factories/config/prisma';\n\nconst prismaClient = new PrismaClient({\n  adapter: new PrismaPg({connectionString: process.env.DATABASE_URL}),\n});\n\ninitializeConnection({\n  client: prismaClient,\n  onConnection: () => console.log('Connected to Database'),\n  onError: (error) => console.error('Error connecting Database', {error}),\n});\n\nexport {prismaClient};\n```\n\n```js\n// controllers/users.js\nimport {create, findOne} from '@desolint/db-factories/services/prisma';\nimport {prismaClient} from '../config/db.js';\n\nconst {\n  doc: user,\n  success,\n  error,\n} = await create({\n  model: prismaClient.user,\n  data: req.body,\n});\n```\n\n---\n\n## `/config/mongo`\n\nDatabase connection setup. Nothing else lives here — CRUD-behavior tuning is\n`/utils/config/mongo`, not this.\n\n### `initializeConnection({ connectionString, options?, onConnection?, onError? })`\n\nConnects the shared mongoose singleton and returns it. Fire-and-forget —\n`onConnection`/`onError` are listeners on `mongoose.connection`, not a\npromise this function returns, so `await`ing it doesn't mean the connection\nis open yet.\n\n| Param              | Type                        | Required | Notes                                           |\n| ------------------ | --------------------------- | -------- | ----------------------------------------------- |\n| `connectionString` | `string`                    | yes      | Mongo connection URI.                           |\n| `options`          | `ConnectOptions` (mongoose) | no       | Passed straight to `mongoose.connect()`.        |\n| `onConnection`     | `() => void`                | no       | Fires once, on the connection's `'open'` event. |\n| `onError`          | `(error: Error) => void`    | no       | Fires on the connection's `'error'` event.      |\n\nReturns: the `mongoose` singleton itself (`Mongoose`), so you can reach\n`mongoose.connection`, `mongoose.startSession()`, etc. off the return value\nif you don't want a separate `/utils/mongo` import.\n\n---\n\n## `/config/prisma`\n\n### `initializeConnection({ client, onConnection?, onError? })`\n\nWires up a **consumer-owned, already-instantiated** Prisma client to the\nsame connect/onConnection/onError lifecycle as the mongo adapter. Prisma's\ngenerated client is built from your own `schema.prisma`, so unlike mongo\nthis can't construct a client itself — you build it, this just connects it.\n\n| Param          | Type                     | Required | Notes                                     |\n| -------------- | ------------------------ | -------- | ----------------------------------------- |\n| `client`       | `PrismaClientLike`       | yes      | Your instantiated `PrismaClient`.         |\n| `onConnection` | `() => void`             | no       | Fires after `client.$connect()` resolves. |\n| `onError`      | `(error: Error) => void` | no       | Fires if `client.$connect()` rejects.     |\n\nReturns: the same `client` you passed in.\n\n---\n\n## `/schema/mongo`\n\nEverything needed to define/reference a mongo model. The raw `mongoose`\nobject itself is deliberately **not** exported here — that's `/config/mongo`\nand `/utils/mongo`'s job (connecting, sessions), not schema definition's.\n\n| Export             | Kind             | What it is                                                                                                                                                                                                            |\n| ------------------ | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `Schema`           | value (class)    | Mongoose's schema builder — `new Schema({...})`.                                                                                                                                                                      |\n| `Types`            | value            | Mongoose's `Types` namespace (`Types.ObjectId`, etc.).                                                                                                                                                                |\n| `model`            | value (function) | Registers a schema against the shared mongoose singleton and returns the model — `model('User', userSchema)`.                                                                                                         |\n| `ModelType`        | type             | The type of what `model()` returns — for annotating, e.g. `function foo(m: ModelType<IUser>)`. **Not named `Model`** — deliberately, so it doesn't sit next to the `model` function differing only by capitalization. |\n| `IndexOptions`     | type             | Mongoose's index-options type, for `schema.index(fields, options)`.                                                                                                                                                   |\n| `HydratedDocument` | type             | The type of a document mongoose hands back from a query (has instance methods, etc.), e.g. `HydratedDocument<IUser>`.                                                                                                 |\n\n```ts\nimport {Schema, model} from '@desolint/db-factories/schema/mongo';\nimport type {\n  ModelType,\n  HydratedDocument,\n} from '@desolint/db-factories/schema/mongo';\n\ninterface IUser {\n  email: string;\n}\n\nconst userSchema = new Schema<IUser>({email: {type: String, required: true}});\nconst UsersModel: ModelType<IUser> = model('User', userSchema);\n\ntype UserDoc = HydratedDocument<IUser>;\n```\n\n---\n\n## `/schema/prisma`\n\nPrisma has no schema-authoring API this library could export —\n`prisma/schema.prisma` is the only place a model is actually defined, and\nit's yours, compiled by the Prisma CLI into your own generated client. What\nthis subpath gives you instead is **structural typing** for that generated\nclient, so this library's own functions can type-check against it without\never importing `@prisma/client` itself.\n\n| Export                    | Kind | What it is                                                                                                 |\n| ------------------------- | ---- | ---------------------------------------------------------------------------------------------------------- |\n| `PrismaClientLike`        | type | Structural stand-in for your `PrismaClient` — just `$connect`/`$disconnect`/`$transaction`.                |\n| `PrismaModelDelegate<T>`  | type | Structural stand-in for one table delegate off your client, e.g. `prismaClient.user`.                      |\n| `PrismaTransactionClient` | type | The type of the client a `$transaction` callback receives (e.g. `tx` in `client.$transaction(tx => ...)`). |\n\n```ts\nimport type { PrismaModelDelegate } from '@desolint/db-factories/schema/prisma';\n\nfunction findAll(model: PrismaModelDelegate<any>) { ... }\n```\n\n---\n\n## `/services/mongo`\n\nThin re-exports of `MongoFactories` — every function here forwards straight\nto the mongo implementation, no dispatch involved. `model` is always a\nmongoose `Model`.\n\n| Function            | Signature                                     | Returns                                                  | What it does                                                                                                                                  |\n| ------------------- | --------------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |\n| `create`            | `{ model, data, session?, options? }`         | `ServiceResult<T \\| T[], 'doc'>`                         | Creates one document (`data` an object) or many (`data` an array).                                                                            |\n| `find`              | `{ model, query?, options?, session? }`       | `ServiceResult<unknown[], 'docs'> & { pagination? }`     | Finds all matching documents. `options.pagination = { include, includeCount }` to get pagination metadata back.                               |\n| `findOne`           | `{ model, query?, options?, session? }`       | `ServiceResult<unknown, 'doc'>`                          | Finds a single matching document.                                                                                                             |\n| `findById`          | `{ model, _id, session?, options? }`          | same as `findOne`                                        | `findOne` scoped to `{ _id }`.                                                                                                                |\n| `updateOne`         | `{ model, query?, data, session?, options? }` | `MutationResult`                                         | Updates one matching document, doesn't return it (`isDocumentUpdated`).                                                                       |\n| `updateMany`        | `{ model, query?, data, session?, options? }` | `MutationResult`                                         | Updates every matching document (`areDocumentsUpdated`).                                                                                      |\n| `findOneAndUpdate`  | `{ model, query?, data, session?, options? }` | `ServiceResult<unknown, 'doc'> & { isDocumentUpdated? }` | Updates one matching document and returns it.                                                                                                 |\n| `findByIdAndUpdate` | `{ model, _id, data, session?, options? }`    | same as `findOneAndUpdate`                               | `findOneAndUpdate` scoped to `{ _id }`.                                                                                                       |\n| `findAllAndUpdate`  | `{ model, query?, data, session?, options? }` | `ServiceResult<unknown[], 'docs'>`                       | Updates every matching document and returns them all.                                                                                         |\n| `deleteOne`         | `{ model, query?, session?, options? }`       | `MutationResult`                                         | Soft-deletes one matching document by default (sets the configured `softDeleteField`); pass `options.hardDelete: true` to actually remove it. |\n| `deleteMany`        | `{ model, query?, session?, options? }`       | `MutationResult`                                         | Same as `deleteOne`, for every matching document.                                                                                             |\n| `findOneAndDelete`  | `{ model, query?, session?, options? }`       | `ServiceResult<unknown, 'doc'> & { isDocumentDeleted? }` | Deletes one matching document and returns it.                                                                                                 |\n| `findByIdAndDelete` | `{ model, _id, session?, options? }`          | same as `findOneAndDelete`                               | Scoped to `{ _id }`.                                                                                                                          |\n| `findAllAndDelete`  | `{ model, query?, session?, options? }`       | `ServiceResult<unknown[], 'docs'>`                       | Deletes every matching document and returns them all.                                                                                         |\n| `countDocuments`    | `{ model, query?, options?, session? }`       | `{ success, error?, count? }`                            | Counts matching documents (soft-deleted ones excluded by default).                                                                            |\n| `aggregate`         | `{ model, pipeline, options? }`               | `ServiceResult<unknown[], 'docs'>`                       | Runs a raw aggregation pipeline. **Mongo only** — see below.                                                                                  |\n\n`query` is a mongoose `FilterQuery`. `options` is `IMongoOptions`:\n\n```ts\ninterface IMongoOptions {\n  includeDeleted?: boolean; // include soft-deleted docs\n  populateFields?: string; // mongoose .populate() path(s)\n  fieldsInclusion?: {\n    // projection\n    include?: string[];\n    exclude?: string[];\n    includeSpecificFields?: string[];\n  };\n  pagination?: {include?: boolean; includeCount?: boolean};\n  hardDelete?: boolean; // deleteOne/deleteMany: actually remove, don't soft-delete\n}\n```\n\n**Why `aggregate` is only here, not in `/services/prisma`:** Mongo's\naggregation pipeline has no Prisma equivalent this library wraps. Rather\nthan exporting it from both and throwing at runtime for a Prisma consumer,\nit simply doesn't exist to import on the Prisma side — you find out at\n`import` time, not at call time.\n\nAlso exported: `IFieldsInclusion`, `IMongoOptions`, `MutationResult`,\n`ServiceResult`, `ClientSession`, `FilterQuery` (types, for annotating your\nown service functions' params/returns).\n\n---\n\n## `/services/prisma`\n\nSame 15 functions as `/services/mongo`, minus `aggregate`, forwarding\nstraight to `PrismaFactories`. `model` is always a Prisma model delegate\n(e.g. `prismaClient.user`).\n\n| Function                                                                                   | Signature                               | Notes vs. the mongo version                                                                                                                                                                |\n| ------------------------------------------------------------------------------------------ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `create`                                                                                   | `{ model, data }`                       | No `session`/`options` — Prisma create doesn't need them.                                                                                                                                  |\n| `find`                                                                                     | `{ model, query?, options?, session? }` | `session` is accepted but ignored (Prisma has no session concept — pass a transaction client as `model` instead, see `/utils/prisma`).                                                     |\n| `findOne`                                                                                  | `{ model, query?, options?, session? }` | Uses Prisma's `findFirst` under the hood.                                                                                                                                                  |\n| `findById`                                                                                 | `{ model, _id, options? }`              | `findOne` scoped to `{ _id }`.                                                                                                                                                             |\n| `updateOne` / `updateMany`                                                                 | `{ model, query?, data, options? }`     | Same shape as mongo.                                                                                                                                                                       |\n| `findOneAndUpdate` / `findByIdAndUpdate` / `findAllAndUpdate`                              | same param shape as mongo, no `session` | Prisma has no atomic \"find and update in one call\" — these find the match first, then update by its id. Not atomic; wrap in `/utils/prisma`'s `wrapWithTransaction` if you need atomicity. |\n| `deleteOne` / `deleteMany` / `findOneAndDelete` / `findByIdAndDelete` / `findAllAndDelete` | same shape as mongo                     | Soft-delete by default via the configured `softDeleteField`, same as mongo.                                                                                                                |\n| `countDocuments`                                                                           | `{ model, query?, options? }`           | —                                                                                                                                                                                          |\n\n`options` is `IPrismaOptions`:\n\n```ts\ninterface IPrismaOptions {\n  includeDeleted?: boolean;\n  pagination?: {include?: boolean; includeCount?: boolean};\n  hardDelete?: boolean;\n  select?: Record<string, boolean>; // passthrough straight to Prisma's own `select`\n}\n```\n\nAlso exported: `IPrismaOptions`, `MutationResult`, `ServiceResult` (types).\n\n---\n\n## `/utils/mongo`\n\nStandalone mongo helpers you call directly in your own code — not part of\nconnecting (`/config/mongo`) or defining a schema (`/schema/mongo`).\n\n| Export                                              | What it does                                                                                                                                                                                                                  |\n| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `startSession()`                                    | Mongoose's own `startSession` — for a consumer that wants to manage a transaction session by hand instead of using `wrapWithTransaction`.                                                                                     |\n| `wrapWithTransaction()({ fn })`                     | Curried helper: start a session, run `fn(session)`, commit on success / abort on throw, always end the session. Pass the returned `session` into `/services/mongo` calls' `session` param to run them inside the transaction. |\n| `isObjectIdOrHexString(value)`                      | Validates a value looks like a Mongo ObjectId (24-hex-char string or an actual ObjectId) — for your own validators/schemas.                                                                                                   |\n| `mergeAndDeduplicateFields({ fields?, scopedTo? })` | Merges two field-name arrays and dedupes — building block for compound-unique-index field lists (e.g. a soft-delete plugin combining a unique field with tenant-scoping fields).                                              |\n\n```js\nimport {wrapWithTransaction} from '@desolint/db-factories/utils/mongo';\nimport * as DbFactory from '@desolint/db-factories/services/mongo';\n\nawait wrapWithTransaction()({\n  fn: async (session) => {\n    await DbFactory.create({model: UsersModel, data: userData, session});\n    await DbFactory.create({model: OrganizationsModel, data: orgData, session});\n  },\n});\n```\n\n---\n\n## `/utils/prisma`\n\n| Export                                    | What it does                                                                                                                                                                                                                                           |\n| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `wrapWithTransaction({ client })({ fn })` | Curried helper matching mongo's shape, but Prisma's transaction model is a whole different client passed into the callback (`tx`), not a session object passed alongside the same model reference — use `tx.user` etc. inside `fn`, not `client.user`. |\n\n```js\nimport {wrapWithTransaction} from '@desolint/db-factories/utils/prisma';\nimport * as DbFactory from '@desolint/db-factories/services/prisma';\n\nawait wrapWithTransaction({client: prismaClient})({\n  fn: async (tx) => {\n    await DbFactory.create({model: tx.user, data: userData});\n    await DbFactory.create({model: tx.organization, data: orgData});\n  },\n});\n```\n\n---\n\n## `/utils/config/mongo`\n\nGlobal, in-memory tuning for how `/services/mongo`'s CRUD functions\nbehave — **not** connection setup (that's `/config/mongo`). Call once at\napp startup; every later `/services/mongo` call picks it up automatically,\nsince `MongoFactories` reads the current config internally on every call.\n\n| Export                                                                                  | What it does                                                                                                                      |\n| --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |\n| `configureMongoFactories({ queryTransformer?, paginationProvider?, softDeleteField? })` | Sets any subset of the three. Unset fields keep whatever they already were.                                                       |\n| `getMongoFactoriesConfig()`                                                             | Reads the current config.                                                                                                         |\n| `resetMongoFactoriesConfig()`                                                           | Restores the built-in defaults. Mainly for test isolation (e.g. a `beforeEach`), so one test's config doesn't leak into the next. |\n\nDefaults: `queryTransformer` is a no-op (`({query}) => query`),\n`paginationProvider` returns `{ page: 1, limit: 20, sort: { createdAt: -1 } }`,\n`softDeleteField` is `'deletedAt'`.\n\n```js\nimport {configureMongoFactories} from '@desolint/db-factories/utils/config/mongo';\n\n// Scope every query app-wide to the current tenant, without adding\n// { organizationId } to every single /services/mongo call by hand.\nconfigureMongoFactories({\n  queryTransformer: ({query}) => ({\n    ...query,\n    organizationId: getCurrentTenantId(),\n  }),\n  softDeleteField: 'removedAt',\n});\n```\n\n## `/utils/config/prisma`\n\nSame three functions, Prisma-shaped config, plus one extra field:\n\n| Export                                                                                             | What it does                                                                                               |\n| -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |\n| `configurePrismaFactories({ queryTransformer?, paginationProvider?, softDeleteField?, idField? })` | `idField` — Prisma has no fixed primary-key field name the way Mongo always has `_id`; defaults to `'id'`. |\n| `getPrismaFactoriesConfig()`                                                                       | —                                                                                                          |\n| `resetPrismaFactoriesConfig()`                                                                     | —                                                                                                          |\n\n**If you don't need any of this** (no soft-delete field rename, no\napp-wide query scoping, default pagination shape is fine) — you'll never\ncall these, and that's fine. It's dependency injection for the CRUD\nfactories' default behavior, not something every consumer needs to touch.\n\n---\n\n## `/testing`\n\nMongo only. Spins up a real, disposable MongoDB (via\n`mongodb-memory-server`) and connects the same shared mongoose singleton\n`/config/mongo` uses — so tests exercise real Mongo behavior instead of a\nseparate mocked path. `mongodb-memory-server` is an optional peer\ndependency; it's only required if you actually import this subpath.\n\n| Export                                                      | What it does                                                                                                                                            |\n| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `connectMockMongoose()`                                     | Starts a disposable in-memory MongoDB, connects mongoose to it, waits for the connection to actually open. Returns `{ mongoServer, mongooseInstance }`. |\n| `disconnectMockMongoose({ mongoServer, mongooseInstance })` | Drops the database, disconnects mongoose, stops the disposable server.                                                                                  |\n\n```js\nimport {\n  connectMockMongoose,\n  disconnectMockMongoose,\n} from '@desolint/db-factories/testing';\n\nlet mongoServer, mongooseInstance;\n\nbeforeAll(async () => {\n  ({mongoServer, mongooseInstance} = await connectMockMongoose());\n});\n\nafterAll(async () => {\n  await disconnectMockMongoose({mongoServer, mongooseInstance});\n});\n```\n\n---\n\n## Return-shape reference\n\nEvery `/services/*` function returns one of these two shapes:\n\n```ts\n// Reads (create, find, findOne, findOneAndUpdate, findOneAndDelete, aggregate, ...)\ntype ServiceResult<T, K extends string> = {\n  success: boolean;\n  error?: unknown;\n} & Partial<Record<K, T | null>>;\n// e.g. { success: true, doc: {...} } or { success: false, error: ... }\n\n// Writes with no document returned (updateOne, updateMany, deleteOne, deleteMany)\ninterface MutationResult {\n  success: boolean;\n  error?: unknown;\n  responseObj?: unknown;\n  isDocumentUpdated?: boolean;\n  areDocumentsUpdated?: boolean;\n  isDocumentDeleted?: boolean;\n  areDocumentsDeleted?: boolean;\n  deleteType?: 'hardDelete' | 'softDelete';\n}\n```\n\nEvery function returns `{ success: false, error }` on failure instead of\nthrowing — check `success` before trusting the rest of the shape.\n\n---\n\n## Soft delete\n\n`deleteOne`/`deleteMany`/`findOneAndDelete`/`findByIdAndDelete`/`findAllAndDelete`\nsoft-delete by default: they set the configured `softDeleteField` (default\n`'deletedAt'`) instead of removing the row/document. Every read\n(`find`/`findOne`/`countDocuments`/...) implicitly excludes soft-deleted\nrecords unless you pass `options.includeDeleted: true`. Pass\n`options.hardDelete: true` to a delete call to actually remove the record.\nChange the field name via `configureMongoFactories`/`configurePrismaFactories`\n(`/utils/config/{mongo,prisma}`).\n\n---\n\n## Development\n\n```bash\nnpm install     # install dependencies\nnpm run build   # type-check, then bundle each subpath into dist/\nnpm test        # jest\nnpm run lint    # eslint\n```\n\n`scripts/build.mjs` bundles each subpath into one self-contained JS file plus a\n`.d.ts`, then deletes everything else from `dist/` — internal modules\n(`src/mongodb/*`, `src/prisma/*`, `src/shared/*`) never ship, so there is nothing for an editor or a\n`moduleResolution: \"node\"` consumer to resolve beyond the eleven public subpaths\ndocumented above.\n\n---\n\n## License\n\nMIT © Desolint — see [LICENSE](./LICENSE).\n\nFree to use, modify and redistribute, commercially or otherwise. Provided\n\"as is\", without warranty or liability of any kind.\n","readmeFilename":"README.md"}