{"_id":"@bmstravel/nvp-db-adapter-prisma","name":"@bmstravel/nvp-db-adapter-prisma","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@bmstravel/nvp-db-adapter-prisma","version":"0.1.0","description":"🏆 Use like a Pro!!","license":"MIT","main":"lib/index.js","module":"es/index.js","types":"lib/index.d.ts","scripts":{"build":"father build","lint:fix":"eslint . --fix","lint-eslint":"eslint --ext .ts src","type-check":"tsc --pretty --noEmit","prettier":"prettier --write src","test":"father test","test:coverage":"father test --coverage"},"peerDependencies":{"@prisma/client":">=5.0.0 <8","moleculer":"^0.15.1"},"peerDependenciesMeta":{"@prisma/client":{"optional":true}},"devDependencies":{"@types/node":"^25.9.5"},"publishConfig":{"access":"public"},"authors":["phongnv86 <phongnguyenvan86@gmail.com>","phongnv86 <phongnv@media-one.vn>"],"gitHead":"769f5e94bd3ef9d3a0839d114594a399ce6e2d27","_id":"@bmstravel/nvp-db-adapter-prisma@0.1.0","_nodeVersion":"22.22.2","_npmVersion":"lerna/10.0.0/node@v22.22.2+arm64 (darwin)","dist":{"integrity":"sha512-61OaYAfiFvUh9K4FiexUe7hMkp+YTNkAs6VHoFXFLoR2ht40zoaJglhDcQaupNLgs2Qbpoam244AYXSZjEPFFg==","shasum":"de3cb235e70fbb07b337a9535ce8f8a5249db38c","tarball":"https://registry.npmjs.org/@bmstravel/nvp-db-adapter-prisma/-/nvp-db-adapter-prisma-0.1.0.tgz","fileCount":10,"unpackedSize":75444,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAxsYK4UBSeDfEz6Vv6qsdySelg0se+spDva/eRY95nCAiBVj+e69XIWN0VmppgGNT7EkyI3eEW/OtewZz67lSauIg=="}]},"_npmUser":{"name":"phongnv86","email":"phongnguyenvan86@gmail.com"},"directories":{},"maintainers":[{"name":"phongnv86","email":"phongnguyenvan86@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nvp-db-adapter-prisma_0.1.0_1787713476047_0.1828776949014499"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-26T03:04:35.870Z","0.1.0":"2026-08-26T03:04:36.697Z","modified":"2026-08-26T03:04:36.969Z"},"maintainers":[{"name":"phongnv86","email":"phongnguyenvan86@gmail.com"}],"description":"🏆 Use like a Pro!!","license":"MIT","readme":"# Adapter Prisma (Postgres, MySQL, SQLite, MongoDB, SQL Server, CockroachDB)\n\nAdapter database Moleculer cho [Prisma](https://www.prisma.io/). Có thể dùng như **adapter phụ** (cùng kiểu TypeORM `adapterTypeorm`) hoặc **adapter chính** (`orm: \"prisma\"`).\n\n`dbType` vẫn là dialect của database (`mysql` | `postgres` | `sqlite` | …). Chọn ORM bằng `orm: \"prisma\" | \"sequelize\" | \"typeorm\"`.\n\nPrisma Client được generate trong app tiêu thụ (`schema.prisma` + `prisma generate`). Truyền client đó vào adapter — package **không** tự tạo client đã generate.\n\nTương thích **Prisma 5, 6 và 7**. API model (`findMany`, `create`, `$connect`, …) không đổi. Prisma 7 bắt buộc **driver adapter** khi khởi tạo `PrismaClient` — tạo client trong app rồi truyền `client` vào `PrismaDbAdapter` (không gọi `new PrismaClient()` không tham số).\n\n## Cài đặt\n\n```bash\n# Prisma 5 / 6\nyarn add @bmstravel/nvp-db-adapter-prisma @prisma/client\nyarn add -D prisma\n\n# Prisma 7 (+ driver adapter theo dialect)\nyarn add @bmstravel/nvp-db-adapter-prisma @prisma/client @prisma/adapter-mariadb\n# postgres: @prisma/adapter-pg    sqlite: @prisma/adapter-better-sqlite3\nyarn add -D prisma\n```\n\nTrong app, định nghĩa `schema.prisma` rồi generate client:\n\n```bash\nnpx prisma generate\n```\n\n## Dùng với `integration-loyalty-api`\n\nCách làm giống TypeORM: **client singleton trong `src/models`**, rồi nhúng vào `DbServiceMixin` của service (ví dụ `store.service.ts`).\n\n### 1. Cài package trong app\n\nTrong `integration-loyalty-api`:\n\n```bash\n# Prisma 5 / 6\nyarn add @bmstravel/nvp-db-adapter-prisma @prisma/client\nyarn add -D prisma\n\n# Prisma 7 (MySQL/MariaDB)\nyarn add @bmstravel/nvp-db-adapter-prisma @prisma/client @prisma/adapter-mariadb\nyarn add -D prisma\n```\n\nThêm script generate (tuỳ chọn) vào `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"prisma:generate\": \"prisma generate\",\n    \"prisma:pull\": \"prisma db pull\"\n  }\n}\n```\n\n### 2. Schema Prisma (introspect DB hiện có)\n\nTạo `prisma/schema.prisma` ở thư mục gốc `integration-loyalty-api`. Prisma đọc `DATABASE_URL`; app đang dùng `SEQUELIZE_URI` / `Config.DB_*` — map URL đó (mặc định MySQL; đổi `provider` nếu `Config.DB_DIALECT` là `postgres`).\n\nPrisma 5 / 6:\n\n```prisma\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"mysql\"\n  url      = env(\"DATABASE_URL\")\n}\n```\n\nPrisma 7 (client không dùng Rust; `url` có thể chuyển sang `prisma.config.ts`):\n\n```prisma\ngenerator client {\n  provider = \"prisma-client\"\n  output   = \"../src/generated/prisma\"\n}\n\ndatasource db {\n  provider = \"mysql\"\n}\n```\n\nTrong `env/localhost.env` (hoặc env đang chạy) thêm:\n\n```bash\nDATABASE_URL=\"${SEQUELIZE_URI}\"\n```\n\nhoặc ghi đầy đủ: `mysql://USER:PASSWORD@HOST:PORT/DBNAME`.\n\nKéo model từ bảng đã có (Sequelize/TypeORM đang dùng cùng DB, không tạo bảng mới):\n\n```bash\nyarn prisma:pull\nyarn prisma:generate\n```\n\n`prisma db pull` sẽ tạo `model Store { ... }` map table `store`. Delegate trên client là `prisma.store` (camelCase).\n\n### 3. Tạo Prisma Client trong `src/models`\n\nSong song `src/models/typeOrmDataSource.ts` và singleton Sequelize trong `src/models/index.ts`.\n\n`src/models/prismaClient.ts` — **Prisma 5 / 6** (`new PrismaClient()` vẫn hợp lệ):\n\n```ts\nimport { PrismaClient } from \"@prisma/client\"\nimport { Config } from \"@src/common\"\n\nconst globalForPrisma = globalThis as unknown as { prisma?: PrismaClient }\n\nexport const prisma =\n\tglobalForPrisma.prisma ??\n\tnew PrismaClient({\n\t\tlog: Config.NODE_ENV === \"development\" ? [\"error\", \"warn\"] : [\"error\"],\n\t})\n\nif (Config.NODE_ENV !== \"production\") {\n\tglobalForPrisma.prisma = prisma\n}\n\nexport default prisma\n```\n\n**Prisma 7** — bắt buộc truyền driver adapter (MySQL/MariaDB như `Config.DB_DIALECT` mặc định của loyalty-api). Không được `new PrismaClient()` rỗng:\n\n```ts\nimport { PrismaClient } from \"../generated/prisma/client\"\nimport { PrismaMariaDb } from \"@prisma/adapter-mariadb\"\nimport { Config } from \"@src/common\"\n\nconst globalForPrisma = globalThis as unknown as { prisma?: PrismaClient }\n\nconst adapter = new PrismaMariaDb({\n\thost: Config.DB_HOST,\n\tport: Config.DB_PORT,\n\tuser: Config.DB_USER,\n\tpassword: Config.DB_PASSWORD,\n\tdatabase: Config.DB_NAME,\n\tconnectionLimit: 10,\n})\n\nexport const prisma =\n\tglobalForPrisma.prisma ??\n\tnew PrismaClient({\n\t\tadapter,\n\t\tlog: Config.NODE_ENV === \"development\" ? [\"error\", \"warn\"] : [\"error\"],\n\t})\n\nif (Config.NODE_ENV !== \"production\") {\n\tglobalForPrisma.prisma = prisma\n}\n\nexport default prisma\n```\n\nPostgres (Prisma 7): dùng `PrismaPg` từ `@prisma/adapter-pg` với `{ connectionString: Config.SEQUELIZE_URI }`.\n\nCách nhúng `adapterPrisma: new PrismaDbAdapter({ client: prisma, model: \"store\" })` **không đổi** giữa v5/v6/v7 — adapter chỉ gọi delegate (`findMany`, `create`, …).\n\nExport từ `src/models/index.ts` (cùng chỗ `SequelizeAdapter`):\n\n```ts\nexport { prisma, prisma as PrismaAdapter } from \"./prismaClient\"\n```\n\nMột `PrismaClient` dùng chung mọi service — giống `TypeOrmDataSource` / `SequelizeAdapter`.\n\n### 4. Nhúng client vào `store.service.ts`\n\nGiữ Sequelize làm adapter chính, Prisma đi qua `otherAdapters` giống TypeORM (`adapterTypeorm`):\n\n```ts\nimport { SequelizeAdapter } from \"@src/models\"\nimport TypeOrmDbAdapter from \"@bmstravel/nvp-db-adapter-typeorm\"\nimport PrismaDbAdapter from \"@bmstravel/nvp-db-adapter-prisma\"\nimport TypeOrmDataSource from \"@src/models/typeOrmDataSource\"\nimport StoreTypeOrmEntity from \"@src/models/typeorm/Store\"\nimport { prisma } from \"@src/models/prismaClient\"\nimport storeModel from \"@src/models/sequelize/store\"\n// ... StoreRegisterModel, StoreTableModel, ...\n\nnew DbServiceMixin(\n  \"store\",\n  {\n    adapter: {\n      sequelizeInstance: SequelizeAdapter,\n      model: storeModel,\n      sequelizeModels: {\n        storeRegister: StoreRegisterModel,\n        storesJoinVoucherShock: StoresJoinVoucherShockModel,\n        storeTable: StoreTableModel,\n        storeTableBooking: StoreTableBookingModel,\n        topup: TopupModel,\n      },\n    },\n  },\n  {\n    adapterTypeorm: new TypeOrmDbAdapter({\n      dataSource: TypeOrmDataSource,\n      model: StoreTypeOrmEntity,\n    }),\n    adapterPrisma: new PrismaDbAdapter({\n      client: prisma,\n      model: \"store\",\n      models: {\n        storeRegister: \"storeRegister\",\n        storesJoinVoucherShock: \"storesJoinVoucherShock\",\n        storeTable: \"storeTable\",\n        storeTableBooking: \"storeTableBooking\",\n        topup: \"topup\",\n      },\n    }),\n  }\n).start()\n```\n\n`model` / `models` là **tên delegate Prisma** (`prisma.store`), không phải class Sequelize/TypeORM. Tên đúng nằm trong `schema.prisma` sau `db pull`.\n\nGắn type trên service (cùng chỗ `adapterTypeorm` trong `src/types/db.service-interface.ts`):\n\n```ts\nimport type { PrismaDbAdapter } from \"@bmstravel/nvp-db-adapter-prisma\"\n\nexport interface IBaseService<...> extends IBaseServiceMethods, Service {\n  adapterTypeorm?: TypeOrmDbAdapter<any>\n  adapterPrisma?: PrismaDbAdapter\n  adapter?: IBaseAdapter<E>\n  // ...\n}\n```\n\n### 5. Gọi trong action\n\nSau `started`, service có `this.adapterPrisma` (vòng đời `init` / `connect` do `nvp-db` xử lý):\n\n```ts\nasync function handler(this: StoreService.IStoreService, ctx: Context) {\n  const stores = await this.adapterPrisma.find({\n    query: { status: STORE_STATUS.ACTIVE },\n    limit: 20,\n  })\n\n  const rows = await this.adapterPrisma.client.store.findMany({\n    where: { status: STORE_STATUS.ACTIVE },\n    take: 20,\n  })\n}\n```\n\nHoặc dùng Prisma làm adapter chính (thay Sequelize trên service đó):\n\n```ts\nnew DbServiceMixin(\"store\", {\n  adapter: {\n    dbType: \"mysql\",\n    orm: \"prisma\",\n    prismaClient: prisma,\n    model: \"store\",\n    prismaModels: {\n      storeRegister: \"storeRegister\",\n      storeTable: \"storeTable\",\n    },\n  },\n}).start()\n```\n\nKhi đó CRUD mặc định (`this.adapter.find` / `insert` / …) đi qua Prisma.\n\n## Adapter phụ (cùng Sequelize / TypeORM)\n\nCùng vị trí mixin với TypeORM trong `store.service.ts`:\n\n```ts\nimport { DbServiceMixin } from \"@bmstravel/nvp-mixins\"\nimport TypeOrmDbAdapter from \"@bmstravel/nvp-db-adapter-typeorm\"\nimport PrismaDbAdapter from \"@bmstravel/nvp-db-adapter-prisma\"\nimport { prisma } from \"./prismaClient\" // PrismaClient singleton của app\n\nnew DbServiceMixin(\n  \"store\",\n  {\n    adapter: {\n      dbType: \"postgres\",\n      orm: \"sequelize\",\n      sequelizeInstance,\n      model: storeModel,\n      sequelizeModels: { storeRegister: StoreRegisterModel },\n    },\n  },\n  {\n    adapterTypeorm: new TypeOrmDbAdapter({\n      dataSource: TypeOrmDataSource,\n      model: StoreTypeOrmEntity,\n    }),\n    adapterPrisma: new PrismaDbAdapter({\n      client: prisma,\n      model: \"store\",\n      models: {\n        storeRegister: \"storeRegister\",\n        storeTable: \"storeTable\",\n      },\n    }),\n  }\n).start()\n```\n\nSau khi service khởi động, dùng:\n\n```ts\nawait this.adapterPrisma.find({ query: { status: 1 }, limit: 10 })\nawait this.adapterPrisma.client.store.findMany({ where: { status: 1 } })\n```\n\nTuỳ chọn constructor:\n\n| Tuỳ chọn | Mô tả |\n|---|---|\n| `client` | Instance `PrismaClient` có sẵn (nên dùng singleton dùng chung) |\n| `PrismaClient` + `opts` | Class client + options; adapter gọi `new PrismaClient(opts)` lúc `connect()` (Prisma 7: `opts` phải có `adapter`) |\n| `model` | Tên delegate mặc định (`\"store\"` → `prisma.store`) hoặc object delegate |\n| `models` | Alias → tên delegate, dùng cho `usingModel()` / `find(..., \"storeRegister\")` |\n| `idField` | Trường khoá chính, mặc định `\"id\"` (bị ghi đè bởi `service.settings.idField` sau `init`) |\n\n## Adapter chính (`orm: \"prisma\"`)\n\n```ts\nimport { DbServiceMixin } from \"@bmstravel/nvp-mixins\"\nimport { prisma } from \"./prismaClient\"\n\nnew DbServiceMixin(\"store\", {\n  adapter: {\n    dbType: \"postgres\",\n    orm: \"prisma\",\n    prismaClient: prisma,\n    model: \"store\",\n    prismaModels: {\n      storeRegister: \"storeRegister\",\n    },\n  },\n}).start()\n```\n\nSequelize vẫn là ORM mặc định khi bỏ `orm` và `dbType` là `mysql` / `postgres` / `mariadb` / `sqlite`. TypeORM làm adapter chính: `orm: \"typeorm\"` kèm `typeormDataSource` và `model`.\n\nCRUD trên `this.adapter` đi qua Prisma (`findMany`, `create`, `update`, …). `search` được map sang Prisma `contains` trên `searchFields` (không phải full-text).\n\n## Lưu ý\n\n- Dùng chung một `PrismaClient` cho mọi service (cùng ý tưởng với `DataSource` TypeORM dùng chung). Gọi `$disconnect()` trên một service sẽ đóng client dùng chung đó.\n- Schema và migration nằm ở app, không nằm trong adapter này.\n- Prisma 5–7: truyền `client` đã khởi tạo. Prisma 7 phải tạo client với `{ adapter }` (hoặc `accelerateUrl`). `new PrismaClient()`, `datasources` và `datasourceUrl` đã bị gỡ ở v7.\n","readmeFilename":"README.md","_rev":"1-86ef4ce2cbc426f7c3ca7662cc091a5c"}