prisma-prefixed-ids 1.6.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,6 +14,8 @@ npm install prisma-prefixed-ids
14
14
 
15
15
  ## Usage
16
16
 
17
+ ### Object-Based Prefixes (Simple Configuration)
18
+
17
19
  ```typescript
18
20
  import { type Prisma, PrismaClient } from "@prisma/client";
19
21
  import { extendPrismaClient } from 'prisma-prefixed-ids';
@@ -26,7 +28,7 @@ type ModelName = Prisma.ModelName;
26
28
  // Create your Prisma client
27
29
  const prisma = new PrismaClient();
28
30
 
29
- // Define your model prefixes
31
+ // Define your model prefixes as an object
30
32
  const prefixes: Partial<Record<ModelName, string>> = {
31
33
  Organization: 'org',
32
34
  User: 'usr',
@@ -54,6 +56,63 @@ const organization = await extendedPrisma.organization.create({
54
56
  console.log(organization.id); // e.g., 'org_abc123...'
55
57
  ```
56
58
 
59
+ ### Function-Based Prefixes (Dynamic Configuration)
60
+
61
+ You can also use a function to determine prefixes dynamically. This is useful when you need conditional logic or want to compute prefixes based on the model name:
62
+
63
+ ```typescript
64
+ import { type Prisma, PrismaClient } from "@prisma/client";
65
+ import { extendPrismaClient } from 'prisma-prefixed-ids';
66
+
67
+ type ModelName = Prisma.ModelName;
68
+
69
+ const prisma = new PrismaClient();
70
+
71
+ // Define prefixes using a function
72
+ const extendedPrisma = extendPrismaClient(prisma, {
73
+ prefixes: (modelName: ModelName): string | null => {
74
+ // Return prefix for known models, null for unknown models
75
+ switch (modelName) {
76
+ case 'Organization':
77
+ return 'org';
78
+ case 'User':
79
+ return 'usr';
80
+ case 'Post':
81
+ return 'pst';
82
+ case 'Comment':
83
+ return 'cmt';
84
+ default:
85
+ return null; // No prefix for unknown models
86
+ }
87
+ },
88
+ });
89
+
90
+ // Or use a more dynamic approach
91
+ const extendedPrismaDynamic = extendPrismaClient(prisma, {
92
+ prefixes: (modelName: ModelName): string | null => {
93
+ // Convert model name to lowercase prefix
94
+ const prefix = modelName.toLowerCase().slice(0, 3);
95
+ // Only apply to certain models
96
+ const allowedModels = ['User', 'Post', 'Comment'];
97
+ return allowedModels.includes(modelName) ? prefix : null;
98
+ },
99
+ });
100
+
101
+ // Use the extended client
102
+ const user = await extendedPrisma.user.create({
103
+ data: {
104
+ name: 'John Doe',
105
+ // id will be automatically generated with prefix 'usr_'
106
+ },
107
+ });
108
+
109
+ console.log(user.id); // e.g., 'usr_abc123...'
110
+ ```
111
+
112
+ **Note:** When using function-based prefixes, return `null` for models that should not have prefixed IDs. The extension will skip ID generation for those models.
113
+
114
+ **Backward Compatibility:** The function-based prefix feature is fully backward compatible. Existing code using object-based prefixes will continue to work without any changes.
115
+
57
116
  ## Nested Writes Support (v1.5.0+)
58
117
 
59
118
  Since version 1.5.0, this package fully supports **nested writes** with automatic ID generation for all related records. This includes complex relationship operations like:
@@ -241,6 +300,7 @@ const customIdGenerator = (prefix: string) => {
241
300
  return `${prefix}_${nanoid()}`;
242
301
  };
243
302
 
303
+ // With object-based prefixes
244
304
  const extendedPrisma = extendPrismaClient(prisma, {
245
305
  prefixes: {
246
306
  Organization: 'org',
@@ -248,18 +308,32 @@ const extendedPrisma = extendPrismaClient(prisma, {
248
308
  },
249
309
  idGenerator: customIdGenerator,
250
310
  });
311
+
312
+ // With function-based prefixes
313
+ const extendedPrismaWithFunction = extendPrismaClient(prisma, {
314
+ prefixes: (modelName) => {
315
+ if (modelName === 'Organization') return 'org';
316
+ if (modelName === 'User') return 'usr';
317
+ return null;
318
+ },
319
+ idGenerator: customIdGenerator,
320
+ });
251
321
  ```
252
322
 
253
323
  ## Configuration Options
254
324
 
255
325
  The extension accepts the following configuration:
256
326
 
257
- - `prefixes`: A record mapping model names to their prefixes (required)
327
+ - `prefixes`: Either an object mapping model names to prefixes, or a function that returns a prefix for a given model name (required)
258
328
  - `idGenerator`: A function that generates IDs (optional, defaults to using nanoid)
259
329
 
260
330
  ### Prefixes Configuration
261
331
 
262
- The `prefixes` configuration is a simple object where:
332
+ The `prefixes` configuration can be provided in two ways:
333
+
334
+ #### Option 1: Object-Based (Simple)
335
+
336
+ A simple object where:
263
337
  - Keys are your Prisma model names (case sensitive)
264
338
  - Values are the prefixes you want to use (without the underscore, which is added automatically)
265
339
 
@@ -273,6 +347,45 @@ const prefixes = {
273
347
  };
274
348
  ```
275
349
 
350
+ #### Option 2: Function-Based (Dynamic)
351
+
352
+ A function that takes a model name and returns a prefix string or `null`:
353
+ - Accepts `modelName: ModelName` as parameter
354
+ - Returns `string | null`:
355
+ - Returns a `string` prefix for models that should have prefixed IDs
356
+ - Returns `null` for models that should not have prefixed IDs
357
+
358
+ Example:
359
+ ```typescript
360
+ const prefixes = (modelName: ModelName): string | null => {
361
+ // Simple mapping
362
+ const prefixMap: Record<string, string> = {
363
+ Organization: 'org',
364
+ User: 'usr',
365
+ Post: 'pst',
366
+ Comment: 'cmt',
367
+ };
368
+ return prefixMap[modelName] ?? null;
369
+ };
370
+
371
+ // Or with conditional logic
372
+ const prefixes = (modelName: ModelName): string | null => {
373
+ if (modelName.startsWith('System')) {
374
+ return 'sys'; // All system models get 'sys' prefix
375
+ }
376
+ if (modelName === 'User' || modelName === 'Organization') {
377
+ return modelName.toLowerCase().slice(0, 3);
378
+ }
379
+ return null; // Other models get no prefix
380
+ };
381
+ ```
382
+
383
+ **When to use function-based prefixes:**
384
+ - You need conditional logic based on model names
385
+ - You want to compute prefixes dynamically
386
+ - You have a large number of models and want to avoid maintaining a large object
387
+ - You need to apply prefixes based on naming patterns or conventions
388
+
276
389
  ### ID Generator Function
277
390
 
278
391
  The `idGenerator` function should:
package/dist/index.cjs CHANGED
@@ -172,6 +172,15 @@ function createPrefixedIdsExtension(config, dmmf) {
172
172
  }
173
173
  const { prefixes, idGenerator = defaultIdGenerator } = config;
174
174
  const prefixedId = (modelName) => {
175
+ // Check if prefixes is a function
176
+ if (typeof prefixes === "function") {
177
+ const prefix = prefixes(modelName);
178
+ if (prefix === null) {
179
+ return null;
180
+ }
181
+ return idGenerator(prefix);
182
+ }
183
+ // Otherwise, treat it as an object/map
175
184
  if (modelName in prefixes) {
176
185
  return idGenerator(prefixes[modelName]);
177
186
  }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,15 @@
1
- import { type PrismaClient } from "@prisma/client";
2
1
  export type ModelName = string;
2
+ /**
3
+ * Minimal interface representing a Prisma Client instance.
4
+ * This allows the library to work with any Prisma Client version (v6, v7+)
5
+ * without importing from @prisma/client directly.
6
+ */
7
+ export interface PrismaClientLike {
8
+ $extends: (extension: any) => any;
9
+ [key: string]: any;
10
+ }
3
11
  export type PrefixConfig<ModelName extends string> = {
4
- prefixes: Partial<Record<ModelName, string>>;
12
+ prefixes: Partial<Record<ModelName, string>> | ((modelName: ModelName) => string | null);
5
13
  idGenerator?: (prefix: string) => string;
6
14
  };
7
15
  type QueryArgs = {
@@ -24,7 +32,7 @@ export declare function createPrefixedIdsExtension<ModelName extends string>(con
24
32
  };
25
33
  };
26
34
  };
27
- export declare function extendPrismaClient<ModelName extends string = string, Client extends PrismaClient = PrismaClient>(prisma: Client, config: PrefixConfig<ModelName>): Client;
28
- export declare function getDMMF(clientOrContext: PrismaClient | any): any;
29
- export declare function getModelNames(prismaClient: PrismaClient): string[];
35
+ export declare function extendPrismaClient<ModelName extends string = string, Client extends PrismaClientLike = PrismaClientLike>(prisma: Client, config: PrefixConfig<ModelName>): Client;
36
+ export declare function getDMMF(clientOrContext: PrismaClientLike | any): any;
37
+ export declare function getModelNames(prismaClient: PrismaClientLike): string[];
30
38
  export {};
package/dist/index.js CHANGED
@@ -163,6 +163,15 @@ export function createPrefixedIdsExtension(config, dmmf) {
163
163
  }
164
164
  const { prefixes, idGenerator = defaultIdGenerator } = config;
165
165
  const prefixedId = (modelName) => {
166
+ // Check if prefixes is a function
167
+ if (typeof prefixes === "function") {
168
+ const prefix = prefixes(modelName);
169
+ if (prefix === null) {
170
+ return null;
171
+ }
172
+ return idGenerator(prefix);
173
+ }
174
+ // Otherwise, treat it as an object/map
166
175
  if (modelName in prefixes) {
167
176
  return idGenerator(prefixes[modelName]);
168
177
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prisma-prefixed-ids",
3
- "version": "1.6.1",
3
+ "version": "2.0.0",
4
4
  "description": "A Prisma extension that adds prefixed IDs to your models",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,9 +28,17 @@
28
28
  "clean:test-artifacts": "rm -rf test-client prisma/test.db prisma/test.db-journal",
29
29
  "test": "npm run test:unit && npm run test:integration",
30
30
  "test:unit": "jest --testPathIgnorePatterns=integration",
31
- "test:integration": "npm run db:setup && jest --testPathPattern=integration",
31
+ "test:integration": "npm run db:setup && jest --testPathPattern=integration --testPathIgnorePatterns='integration.mysql|integration.postgres'",
32
+ "test:mysql": "npm run db:setup:mysql && jest --testPathPattern=integration.mysql",
33
+ "test:postgres": "npm run db:setup:postgres && jest --testPathPattern=integration.postgres",
34
+ "db:setup:mysql": "npm run db:generate:mysql && npm run db:push:mysql",
35
+ "db:generate:mysql": "prisma generate --schema=tests/prisma/schema.mysql.prisma",
36
+ "db:push:mysql": "prisma db push --schema=tests/prisma/schema.mysql.prisma",
37
+ "db:setup:postgres": "npm run db:generate:postgres && npm run db:push:postgres",
38
+ "db:generate:postgres": "prisma generate --schema=tests/prisma/schema.postgres.prisma",
39
+ "db:push:postgres": "prisma db push --schema=tests/prisma/schema.postgres.prisma",
32
40
  "test:watch": "jest --watch",
33
- "test:coverage": "jest --coverage --collectCoverageFrom='src/**/*.ts' --coveragePathIgnorePatterns='src/__tests__'",
41
+ "test:coverage": "jest --coverage --collectCoverageFrom='src/**/*.ts' --coveragePathIgnorePatterns='src/__tests__' --testPathIgnorePatterns='integration'",
34
42
  "db:setup": "npm run db:generate && npm run db:push",
35
43
  "db:generate": "prisma generate",
36
44
  "db:push": "prisma db push",
@@ -39,7 +47,8 @@
39
47
  "lint:fix": "eslint . --ext .ts --fix",
40
48
  "format": "prettier --write \"src/**/*.ts\"",
41
49
  "format:check": "prettier --check \"src/**/*.ts\"",
42
- "git:push": "git push && git push --tags"
50
+ "git:push": "git push && git push --tags",
51
+ "trypublish": "npm publish --access public"
43
52
  },
44
53
  "keywords": [
45
54
  "prisma",
@@ -51,25 +60,30 @@
51
60
  "author": "Prageeth Silva <prageeth@codemode.com.au>",
52
61
  "license": "MIT",
53
62
  "dependencies": {
54
- "@prisma/client": "^5.0.0 || ^6.0.0",
63
+ "@prisma/client": "^6.0.0 || ^7.0.0",
55
64
  "nanoid": "^5.0.0"
56
65
  },
57
66
  "devDependencies": {
67
+ "@libsql/client": "^0.17.0",
68
+ "@prisma/adapter-libsql": "^7.3.0",
69
+ "@prisma/adapter-mariadb": "^7.3.0",
70
+ "@prisma/adapter-pg": "^7.3.0",
58
71
  "@types/jest": "^29.0.0",
59
- "@types/node": "^20.0.0",
60
72
  "@types/nanoid": "^2.0.0",
73
+ "@types/node": "^22.0.0",
61
74
  "@typescript-eslint/eslint-plugin": "^6.0.0",
62
75
  "@typescript-eslint/parser": "^6.0.0",
76
+ "dotenv": "^16.0.0",
63
77
  "eslint": "^8.56.0",
64
78
  "eslint-config-prettier": "^9.0.0",
65
79
  "jest": "^29.0.0",
66
80
  "prettier": "^3.0.0",
67
- "prisma": "^5.0.0",
81
+ "prisma": "^7.0.0",
68
82
  "ts-jest": "^29.0.0",
69
83
  "typescript": "^5.0.0"
70
84
  },
71
85
  "peerDependencies": {
72
- "@prisma/client": "^5.0.0 || ^6.0.0"
86
+ "@prisma/client": "^6.0.0 || ^7.0.0"
73
87
  },
74
88
  "prisma": {
75
89
  "schema": "tests/prisma/schema.prisma"