prisma-mock 0.12.2 → 1.0.0-alpha.1

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.
@@ -0,0 +1,6 @@
1
+ import type { Prisma, PrismaClient } from "@prisma/client";
2
+ import { MockPrismaOptions, PrismaMockData } from "./types";
3
+ declare const createPrismaMock: <PClient extends PrismaClient<Prisma.PrismaClientOptions, never, import("@prisma/client/runtime/library").DefaultArgs>, P extends typeof Prisma>(prisma: P, options?: MockPrismaOptions<P>) => P & {
4
+ $getInternalState: () => Required<Partial<{ [key in import("./types").IsTable<Uncapitalize<import("./types").IsString<keyof PClient>>>]: import("./types").PrismaList<PClient, key>; }>>;
5
+ };
6
+ export default createPrismaMock;
package/lib/client.js ADDED
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const delegate_1 = require("./delegate");
7
+ const indexes_1 = __importDefault(require("./indexes"));
8
+ const deepCopy_1 = require("./utils/deepCopy");
9
+ const fieldHelpers_1 = require("./utils/fieldHelpers");
10
+ // Creates a mock Prisma client.
11
+ // @param prisma - The Prisma namespace or client constructor.
12
+ // @param options - Options for configuring the mock client:
13
+ // - data: Initial mock data for your models (default: {}).
14
+ // - caseInsensitive: If true, string matching is case-insensitive (default: false).
15
+ // - enableIndexes: If true, enables index lookups for performance (default: false).
16
+ // - mockClient: Optionally provide your own mock client (jest-mock-extended or vitest-mock-extended) instance to use.
17
+ // @returns A mock Prisma client with all model methods and access to internal state.
18
+ const createPrismaMock = (prisma, options = {
19
+ datamodel: prisma.dmmf.datamodel,
20
+ caseInsensitive: false,
21
+ enableIndexes: false,
22
+ data: {}
23
+ }) => {
24
+ // Reference object to hold the mock data state
25
+ let ref = {
26
+ data: options.data || {},
27
+ };
28
+ // Initialize the mock client (either use provided one or create new)
29
+ let client = options.mockClient ? options.mockClient : {};
30
+ /**
31
+ * Helper function to implement mock methods consistently
32
+ * @param name - Method name to mock
33
+ * @param fnc - Function implementation
34
+ */
35
+ const mockImplementation = (name, fnc) => {
36
+ if (options.mockClient) {
37
+ client[name].mockImplementation(fnc);
38
+ }
39
+ else {
40
+ client[name] = fnc;
41
+ }
42
+ };
43
+ // Create indexes if enabled in options
44
+ const indexes = (0, indexes_1.default)(!!options.enableIndexes, prisma);
45
+ // Determine if case-insensitive matching should be used
46
+ const caseInsensitive = options.caseInsensitive || false;
47
+ // Mock $transaction method for handling database transactions
48
+ mockImplementation("$transaction", async (actions) => {
49
+ const res = [];
50
+ if (Array.isArray(actions)) {
51
+ // Handle array of promises (parallel execution)
52
+ for (const action of actions) {
53
+ res.push(await action);
54
+ }
55
+ return res;
56
+ }
57
+ else {
58
+ // Handle callback function (serial execution with rollback on error)
59
+ const snapshot = (0, deepCopy_1.deepCopy)(ref.data);
60
+ try {
61
+ // @ts-ignore
62
+ return await actions(client);
63
+ }
64
+ catch (error) {
65
+ // Rollback data on error
66
+ ref.data = snapshot;
67
+ throw error;
68
+ }
69
+ }
70
+ });
71
+ // Mock connection methods
72
+ mockImplementation("$connect", async () => { });
73
+ mockImplementation("$disconnect", async () => { });
74
+ mockImplementation("$use", async () => {
75
+ throw new Error("$use is not yet implemented in prisma-mock");
76
+ });
77
+ // Create delegate functions for model operations
78
+ const Delegate = (0, delegate_1.createDelegate)({ ref, prisma, datamodel: options.datamodel, caseInsensitive, indexes });
79
+ // Initialize each model in the datamodel
80
+ prisma.dmmf.datamodel.models.forEach((model) => {
81
+ if (!model)
82
+ return;
83
+ // Convert model name to camelCase for consistency
84
+ const c = (0, fieldHelpers_1.getCamelCase)(model.name);
85
+ // Initialize empty array for model if it doesn't exist
86
+ if (!ref.data[c]) {
87
+ ref.data = {
88
+ ...(ref.data || {}),
89
+ [c]: [],
90
+ };
91
+ }
92
+ // Remove multi-field IDs from the data structure
93
+ ref.data = (0, fieldHelpers_1.removeMultiFieldIds)(model, ref.data);
94
+ // Set up indexes for each field in the model
95
+ model.fields.forEach((field) => {
96
+ const isPrimaryKey = !!model.primaryKey?.fields.includes(field.name);
97
+ indexes.addIndexFieldIfNeeded(c, field, isPrimaryKey);
98
+ });
99
+ // Update indexes with existing data
100
+ ref.data[c].forEach((item) => {
101
+ indexes.updateItem(c, item, null);
102
+ });
103
+ // Create delegate functions for this model
104
+ const objs = Delegate(c, model);
105
+ // Bind delegate functions to the client
106
+ Object.keys(objs).forEach((fncName) => {
107
+ // Skip private methods (those starting with underscore)
108
+ if (fncName.indexOf("_") === 0)
109
+ return;
110
+ // Initialize model namespace if it doesn't exist
111
+ if (!client[c])
112
+ client[c] = {};
113
+ // Bind the delegate function to the client
114
+ if (options.mockClient) {
115
+ client[c][fncName].mockImplementation(async (...params) => {
116
+ return objs[fncName](...params);
117
+ });
118
+ }
119
+ else {
120
+ client[c][fncName] = async (...params) => {
121
+ return objs[fncName](...params);
122
+ };
123
+ }
124
+ });
125
+ });
126
+ // Add method to access internal state for testing/debugging
127
+ client['$getInternalState'] = () => ref.data;
128
+ // @ts-ignore
129
+ return client;
130
+ };
131
+ exports.default = createPrismaMock;
@@ -0,0 +1,3 @@
1
+ import type { Prisma } from "@prisma/client";
2
+ import { PrismaMockData } from "../types";
3
+ export default function createAutoincrement(): <P>(prop: string, field: Prisma.DMMF.Field, data?: Partial<{ [key in import("../types").IsTable<Uncapitalize<import("../types").IsString<keyof P>>>]: import("../types").PrismaList<P, key>; }>) => Number | BigInt;
@@ -0,0 +1,2 @@
1
+ declare const createCuid: () => () => string;
2
+ export default createCuid;
@@ -0,0 +1,5 @@
1
+ import type { Prisma } from "@prisma/client";
2
+ import { PrismaMockData } from "../types";
3
+ export default function createHandleDefault(): <P>(prop: string, field: Prisma.DMMF.Field, ref: {
4
+ data: Partial<{ [key in import("../types").IsTable<Uncapitalize<import("../types").IsString<keyof P>>>]: import("../types").PrismaList<P, key>; }>;
5
+ }) => any;
@@ -0,0 +1,2 @@
1
+ declare const createNow: () => Date;
2
+ export default createNow;
@@ -0,0 +1,2 @@
1
+ declare const createUuid: () => () => string;
2
+ export default createUuid;
@@ -0,0 +1,48 @@
1
+ import type { Prisma } from "@prisma/client";
2
+ import createIndexes from "./indexes";
3
+ import { CreateArgs } from "./types";
4
+ /**
5
+ * Creates a delegate function that handles Prisma-like operations for a specific model
6
+ * This is the main factory function that generates model-specific CRUD operations
7
+ */
8
+ export declare const createDelegate: <P extends typeof Prisma>({ ref, prisma, datamodel, caseInsensitive, indexes }: {
9
+ ref: any;
10
+ prisma: P;
11
+ datamodel: P["dmmf"]["datamodel"];
12
+ caseInsensitive: boolean;
13
+ indexes: ReturnType<typeof createIndexes>;
14
+ }) => (prop: string, model: Prisma.DMMF.Model) => {
15
+ aggregate: (args: any) => any;
16
+ groupBy: (args: any) => any[];
17
+ findOne: (args: any) => any;
18
+ findUnique: (args: any) => any;
19
+ findUniqueOrThrow: (args: any) => any;
20
+ findMany: (args: any) => any[];
21
+ findFirst: (args: any) => any;
22
+ findFirstOrThrow: (args: any) => any;
23
+ create: (args: CreateArgs) => any;
24
+ createMany: (args: any) => {
25
+ count: any;
26
+ };
27
+ createManyAndReturn: (args: any) => any;
28
+ delete: (args: any) => any;
29
+ update: (args: any) => any;
30
+ deleteMany: (args: any) => {
31
+ count: number;
32
+ };
33
+ updateMany: (args: any) => {
34
+ count: number;
35
+ };
36
+ updateManyAndReturn: (args: any) => any[];
37
+ /**
38
+ * Upsert operation: update if exists, create if not
39
+ */
40
+ upsert(args: any): any;
41
+ /**
42
+ * Count operation: returns the number of records matching the criteria
43
+ */
44
+ count(args: any): number;
45
+ _sortFunc: (orderBy: any) => (a: any, b: any) => any;
46
+ _findMany: (args: any) => any[];
47
+ _createMany: (args: any) => any;
48
+ };
package/lib/delegate.js CHANGED
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createDelegate = void 0;
7
- const client_1 = require("@prisma/client");
8
7
  const defaults_1 = __importDefault(require("./defaults"));
9
8
  const errors_1 = require("./errors");
10
9
  const fieldHelpers_1 = require("./utils/fieldHelpers");
@@ -15,10 +14,7 @@ const getWhereOnIds_1 = __importDefault(require("./utils/getWhereOnIds"));
15
14
  * Creates a delegate function that handles Prisma-like operations for a specific model
16
15
  * This is the main factory function that generates model-specific CRUD operations
17
16
  */
18
- const createDelegate = (ref, // Reference to the mock data store
19
- datamodel, // Prisma datamodel definition
20
- caseInsensitive, // Whether string comparisons should be case insensitive
21
- indexes) => {
17
+ const createDelegate = ({ ref, prisma, datamodel = prisma.dmmf.datamodel, caseInsensitive, indexes }) => {
22
18
  // Initialize default value handler
23
19
  const handleDefaults = (0, defaults_1.default)();
24
20
  // Store many-to-many relationship data separately from the main data store
@@ -52,7 +48,7 @@ indexes) => {
52
48
  return Delegate(name, otherModel);
53
49
  };
54
50
  // Create matching function for WHERE clauses
55
- const matchFnc = (0, queryMatching_1.default)({ getFieldRelationshipWhere, getDelegateForFieldName, model, datamodel, caseInsensitive });
51
+ const matchFnc = (0, queryMatching_1.default)({ prisma, getFieldRelationshipWhere, getDelegateForFieldName, model, datamodel, caseInsensitive });
56
52
  /**
57
53
  * Sorting function that handles both simple and nested orderBy clauses
58
54
  * Supports multiple sort criteria and nested relation sorting
@@ -71,7 +67,7 @@ indexes) => {
71
67
  // Validate that only one sort field is provided
72
68
  const keys = Object.keys(orderBy);
73
69
  if (keys.length > 1) {
74
- (0, errors_1.throwValidationError)(`Argument orderBy of needs exactly one argument, but you provided ${keys.join(" and ")}. Please choose one.`);
70
+ (0, errors_1.throwValidationError)(prisma, `Argument orderBy of needs exactly one argument, but you provided ${keys.join(" and ")}. Please choose one.`);
75
71
  }
76
72
  // Create include function to handle nested relations during sorting
77
73
  const incl = includes({
@@ -138,7 +134,7 @@ indexes) => {
138
134
  if (isCreating && (field.isUnique || field.isId)) {
139
135
  const existing = findOne({ where: { [field.name]: inputFieldData } });
140
136
  if (existing) {
141
- (0, errors_1.throwKnownError)(`Unique constraint failed on the fields: (\`${field.name}\`)`, { code: 'P2002', meta: { target: [field.name] } });
137
+ (0, errors_1.throwKnownError)(prisma, `Unique constraint failed on the fields: (\`${field.name}\`)`, { code: 'P2002', meta: { target: [field.name] } });
142
138
  }
143
139
  }
144
140
  // Handle relation fields (object type)
@@ -155,7 +151,7 @@ indexes) => {
155
151
  where
156
152
  })).filter(Boolean);
157
153
  if (items.length !== inputFieldData.set.length) {
158
- (0, errors_1.throwKnownError)(`An operation failed because it depends on one or more records that were required but not found. Expected ${inputFieldData.set.length} records to be connected, found only ${items.length}.`);
154
+ (0, errors_1.throwKnownError)(prisma, `An operation failed because it depends on one or more records that were required but not found. Expected ${inputFieldData.set.length} records to be connected, found only ${items.length}.`);
159
155
  }
160
156
  // Update many-to-many data store
161
157
  const idField = model?.fields.find((f) => f.isId)?.name;
@@ -200,7 +196,7 @@ indexes) => {
200
196
  return (0, shallowCompare_1.shallowCompare)(target, valueToMatch);
201
197
  });
202
198
  if (!matchingRow) {
203
- (0, errors_1.throwKnownError)("An operation failed because it depends on one or more records that were required but not found. {cause}");
199
+ (0, errors_1.throwKnownError)(prisma, "An operation failed because it depends on one or more records that were required but not found. {cause}");
204
200
  }
205
201
  }
206
202
  connectionValue = matchingRow[keyToGet];
@@ -525,7 +521,7 @@ indexes) => {
525
521
  const findOrThrow = (args) => {
526
522
  const found = findOne(args);
527
523
  if (!found) {
528
- (0, errors_1.throwKnownError)(`No ${prop.slice(0, 1).toUpperCase()}${prop.slice(1)} found`);
524
+ (0, errors_1.throwKnownError)(prisma, `No ${prop.slice(0, 1).toUpperCase()}${prop.slice(1)} found`);
529
525
  }
530
526
  return found;
531
527
  };
@@ -589,7 +585,7 @@ indexes) => {
589
585
  res = res.map((item) => {
590
586
  const newItem = {};
591
587
  Object.keys(item).forEach((key) => {
592
- if (item[key] === client_1.Prisma.JsonNull || item[key] === client_1.Prisma.DbNull) {
588
+ if (item[key] === prisma.JsonNull || item[key] === prisma.DbNull) {
593
589
  newItem[key] = null;
594
590
  }
595
591
  else {
@@ -840,7 +836,7 @@ indexes) => {
840
836
  if (!hasMatch) {
841
837
  if (args.skipForeignKeysChecks)
842
838
  return;
843
- (0, errors_1.throwKnownError)("An operation failed because it depends on one or more records that were required but not found. Record to update not found.", { meta: { cause: "Record to update not found." } });
839
+ (0, errors_1.throwKnownError)(prisma, "An operation failed because it depends on one or more records that were required but not found. Record to update not found.", { meta: { cause: "Record to update not found." } });
844
840
  }
845
841
  ref.data = {
846
842
  ...ref.data,
@@ -1079,7 +1075,7 @@ indexes) => {
1079
1075
  delete: (args) => {
1080
1076
  const item = findOne(args);
1081
1077
  if (!item) {
1082
- (0, errors_1.throwKnownError)("An operation failed because it depends on one or more records that were required but not found. Record to delete does not exist.", { meta: { cause: "Record to delete does not exist." } });
1078
+ (0, errors_1.throwKnownError)(prisma, "An operation failed because it depends on one or more records that were required but not found. Record to delete does not exist.", { meta: { cause: "Record to delete does not exist." } });
1083
1079
  }
1084
1080
  const deleted = deleteMany(args);
1085
1081
  if (deleted.length) {
@@ -0,0 +1,9 @@
1
+ import type { Prisma } from "@prisma/client";
2
+ export declare const throwKnownError: (prisma: typeof Prisma, message: string, { code, meta }?: {
3
+ code?: string;
4
+ meta?: any;
5
+ }) => void;
6
+ export declare const throwValidationError: (prisma: typeof Prisma, message: string, { code, meta }?: {
7
+ code?: string;
8
+ meta?: any;
9
+ }) => void;
package/lib/errors.js CHANGED
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.throwValidationError = exports.throwKnownError = void 0;
4
- const client_1 = require("@prisma/client");
5
- const throwPrismaError = (message, { code = "P2025", meta } = {}, errorClass = client_1.Prisma.PrismaClientKnownRequestError) => {
6
- const clientVersion = client_1.Prisma.prismaVersion.client;
4
+ const throwPrismaError = (prisma, message, { code = "P2025", meta } = {}, errorClass = prisma.PrismaClientKnownRequestError) => {
5
+ const clientVersion = prisma.prismaVersion.client;
7
6
  // PrismaClientKnownRequestError prototype changed in version 4.7.0
8
7
  // from: constructor(message: string, code: string, clientVersion: string, meta?: any)
9
8
  // to: constructor(message: string, { code, clientVersion, meta, batchRequestIdx }: KnownErrorParams)
@@ -26,11 +25,11 @@ const throwPrismaError = (message, { code = "P2025", meta } = {}, errorClass = c
26
25
  error.meta = meta;
27
26
  throw error;
28
27
  };
29
- const throwKnownError = (message, { code = "P2025", meta } = {}) => {
30
- throwPrismaError(message, { code, meta }, client_1.Prisma.PrismaClientKnownRequestError);
28
+ const throwKnownError = (prisma, message, { code = "P2025", meta } = {}) => {
29
+ throwPrismaError(prisma, message, { code, meta }, prisma.PrismaClientKnownRequestError);
31
30
  };
32
31
  exports.throwKnownError = throwKnownError;
33
- const throwValidationError = (message, { code = "P2025", meta } = {}) => {
34
- throwPrismaError(message, { code, meta }, client_1.Prisma.PrismaClientValidationError);
32
+ const throwValidationError = (prisma, message, { code = "P2025", meta } = {}) => {
33
+ throwPrismaError(prisma, message, { code, meta }, prisma.PrismaClientValidationError);
35
34
  };
36
35
  exports.throwValidationError = throwValidationError;
package/lib/index.d.ts ADDED
@@ -0,0 +1,73 @@
1
+ import { Prisma } from "@prisma/client/default";
2
+ import { MockPrismaOptions } from "./types";
3
+ export default function createPrismaClient(options?: MockPrismaOptions<typeof Prisma>): typeof Prisma & {
4
+ $getInternalState: () => Required<Partial<{
5
+ account: Partial<{
6
+ name: string;
7
+ id: number;
8
+ sort: number;
9
+ }>[];
10
+ user: Partial<{
11
+ name: string;
12
+ id: number;
13
+ sort: number;
14
+ accountId: number;
15
+ role: import(".prisma/client").$Enums.Role;
16
+ clicks: number;
17
+ deleted: boolean;
18
+ uniqueField: string;
19
+ age: number;
20
+ }>[];
21
+ stripe: Partial<{
22
+ id: number;
23
+ sort: number;
24
+ accountId: number;
25
+ customerId: string;
26
+ active: boolean;
27
+ }>[];
28
+ answers: Partial<{
29
+ id: number;
30
+ title: string;
31
+ }>[];
32
+ userAnswers: Partial<{
33
+ value: string;
34
+ answerId: number;
35
+ userId: number;
36
+ }>[];
37
+ element: Partial<{
38
+ value: string;
39
+ userId: number;
40
+ e_id: number;
41
+ json: Prisma.JsonValue;
42
+ }>[];
43
+ document: Partial<{
44
+ name: string;
45
+ id: string;
46
+ }>[];
47
+ post: Partial<{
48
+ id: number;
49
+ title: string;
50
+ published: boolean;
51
+ authorId: number;
52
+ updated: Date;
53
+ created: Date;
54
+ }>[];
55
+ pet: Partial<{
56
+ name: string;
57
+ id: number;
58
+ ownerId: number;
59
+ }>[];
60
+ toy: Partial<{
61
+ name: string;
62
+ id: number;
63
+ ownerId: number;
64
+ }>[];
65
+ transaction: Partial<{
66
+ id: string;
67
+ initiator: string;
68
+ }>[];
69
+ dbGeneratedId: Partial<{
70
+ id: string;
71
+ }>[];
72
+ }>>;
73
+ };
package/lib/index.js CHANGED
@@ -3,128 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const client_1 = require("@prisma/client");
7
- const delegate_1 = require("./delegate");
8
- const indexes_1 = __importDefault(require("./indexes"));
9
- const deepCopy_1 = require("./utils/deepCopy");
10
- const fieldHelpers_1 = require("./utils/fieldHelpers");
11
- /**
12
- * Creates a mock Prisma client with the specified data and options
13
- * @param data - Initial mock data for the Prisma models
14
- * @param datamodel - Prisma datamodel (defaults to Prisma.dmmf.datamodel)
15
- * @param mockClient - Optional existing mock client to extend
16
- * @param options - Configuration options for the mock client
17
- * @returns A mock Prisma client with all model methods and internal state access
18
- */
19
- const createPrismaMock = (data = {}, datamodel = client_1.Prisma.dmmf.datamodel, mockClient, options = {
20
- caseInsensitive: false,
21
- enableIndexes: false,
22
- }) => {
23
- // Reference object to hold the mock data state
24
- let ref = {
25
- data,
26
- };
27
- // Initialize the mock client (either use provided one or create new)
28
- let client = mockClient ? mockClient : {};
29
- /**
30
- * Helper function to implement mock methods consistently
31
- * @param name - Method name to mock
32
- * @param fnc - Function implementation
33
- */
34
- const mockImplementation = (name, fnc) => {
35
- if (mockClient) {
36
- client[name].mockImplementation(fnc);
37
- }
38
- else {
39
- client[name] = fnc;
40
- }
41
- };
42
- // Create indexes if enabled in options
43
- const indexes = (0, indexes_1.default)(!!options.enableIndexes);
44
- // Determine if case-insensitive matching should be used
45
- const caseInsensitive = options.caseInsensitive || false;
46
- // Mock $transaction method for handling database transactions
47
- mockImplementation("$transaction", async (actions) => {
48
- const res = [];
49
- if (Array.isArray(actions)) {
50
- // Handle array of promises (parallel execution)
51
- for (const action of actions) {
52
- res.push(await action);
53
- }
54
- return res;
55
- }
56
- else {
57
- // Handle callback function (serial execution with rollback on error)
58
- const snapshot = (0, deepCopy_1.deepCopy)(ref.data);
59
- try {
60
- // @ts-ignore
61
- return await actions(client);
62
- }
63
- catch (error) {
64
- // Rollback data on error
65
- ref.data = snapshot;
66
- throw error;
67
- }
68
- }
69
- });
70
- // Mock connection methods
71
- mockImplementation("$connect", async () => { });
72
- mockImplementation("$disconnect", async () => { });
73
- mockImplementation("$use", async () => {
74
- throw new Error("$use is not yet implemented in prisma-mock");
75
- });
76
- // Create delegate functions for model operations
77
- const Delegate = (0, delegate_1.createDelegate)(ref, datamodel, caseInsensitive, indexes);
78
- // Initialize each model in the datamodel
79
- datamodel.models.forEach((model) => {
80
- if (!model)
81
- return;
82
- // Convert model name to camelCase for consistency
83
- const c = (0, fieldHelpers_1.getCamelCase)(model.name);
84
- // Initialize empty array for model if it doesn't exist
85
- if (!ref.data[c]) {
86
- ref.data = {
87
- ...(ref.data || {}),
88
- [c]: [],
89
- };
90
- }
91
- // Remove multi-field IDs from the data structure
92
- ref.data = (0, fieldHelpers_1.removeMultiFieldIds)(model, ref.data);
93
- // Set up indexes for each field in the model
94
- model.fields.forEach((field) => {
95
- const isPrimaryKey = !!model.primaryKey?.fields.includes(field.name);
96
- indexes.addIndexFieldIfNeeded(c, field, isPrimaryKey);
97
- });
98
- // Update indexes with existing data
99
- ref.data[c].forEach((item) => {
100
- indexes.updateItem(c, item, null);
101
- });
102
- // Create delegate functions for this model
103
- const objs = Delegate(c, model);
104
- // Bind delegate functions to the client
105
- Object.keys(objs).forEach((fncName) => {
106
- // Skip private methods (those starting with underscore)
107
- if (fncName.indexOf("_") === 0)
108
- return;
109
- // Initialize model namespace if it doesn't exist
110
- if (!client[c])
111
- client[c] = {};
112
- // Bind the delegate function to the client
113
- if (mockClient) {
114
- client[c][fncName].mockImplementation(async (...params) => {
115
- return objs[fncName](...params);
116
- });
117
- }
118
- else {
119
- client[c][fncName] = async (...params) => {
120
- return objs[fncName](...params);
121
- };
122
- }
123
- });
124
- });
125
- // Add method to access internal state for testing/debugging
126
- client['$getInternalState'] = () => ref.data;
127
- // @ts-ignore
128
- return client;
129
- };
130
- exports.default = createPrismaMock;
6
+ const default_1 = require("@prisma/client/default");
7
+ const client_1 = __importDefault(require("./client"));
8
+ function createPrismaClient(options) {
9
+ return (0, client_1.default)(default_1.Prisma, options);
10
+ }
11
+ exports.default = createPrismaClient;
@@ -0,0 +1,15 @@
1
+ import type { Prisma } from "@prisma/client";
2
+ /**
3
+ * Creates an indexing system for Prisma mock data to improve query performance.
4
+ * This module maintains in-memory indexes on specified fields to enable fast lookups
5
+ * instead of scanning all records.
6
+ *
7
+ * @param isEnabled - Whether indexing is enabled. When false, all operations are no-ops.
8
+ * @returns Object containing methods for managing indexes and performing indexed lookups
9
+ */
10
+ export default function createIndexes(isEnabled: boolean, prisma: typeof Prisma): {
11
+ addIndexFieldIfNeeded: (tableName: string, field: Prisma.DMMF.Field, isPrimary: boolean) => void;
12
+ getIndexedItems: (tableName: string, where: any) => any;
13
+ updateItem: (tableName: string, item: any, oldItem: any | null) => void;
14
+ deleteItemByField: (tableName: string, field: Prisma.DMMF.Field, item: any) => void;
15
+ };
package/lib/indexes.js CHANGED
@@ -8,7 +8,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
8
8
  * @param isEnabled - Whether indexing is enabled. When false, all operations are no-ops.
9
9
  * @returns Object containing methods for managing indexes and performing indexed lookups
10
10
  */
11
- function createIndexes(isEnabled = true) {
11
+ function createIndexes(isEnabled = true, prisma) {
12
12
  // Main data structures for storing indexed data
13
13
  // items: tableName -> fieldName -> fieldValue -> array of items with that value
14
14
  let items = {};
@@ -0,0 +1,76 @@
1
+ import { Prisma, PrismaClient } from "@prisma/client";
2
+ import { DeepMockApi, MockPrismaOptions, PrismaMockData } from "./types";
3
+ /**
4
+ * @deprecated Use default export instead
5
+ */
6
+ export default function createPrismaClient(data?: PrismaMockData<PrismaClient>, datamodel?: Prisma.DMMF.Datamodel, mockClient?: DeepMockApi, options?: Omit<MockPrismaOptions<typeof Prisma>, "data">): typeof Prisma & {
7
+ $getInternalState: () => Required<Partial<{
8
+ account: Partial<{
9
+ name: string;
10
+ id: number;
11
+ sort: number;
12
+ }>[];
13
+ user: Partial<{
14
+ name: string;
15
+ id: number;
16
+ sort: number;
17
+ accountId: number;
18
+ role: import(".prisma/client").$Enums.Role;
19
+ clicks: number;
20
+ deleted: boolean;
21
+ uniqueField: string;
22
+ age: number;
23
+ }>[];
24
+ stripe: Partial<{
25
+ id: number;
26
+ sort: number;
27
+ accountId: number;
28
+ customerId: string;
29
+ active: boolean;
30
+ }>[];
31
+ answers: Partial<{
32
+ id: number;
33
+ title: string;
34
+ }>[];
35
+ userAnswers: Partial<{
36
+ value: string;
37
+ answerId: number;
38
+ userId: number;
39
+ }>[];
40
+ element: Partial<{
41
+ value: string;
42
+ userId: number;
43
+ e_id: number;
44
+ json: Prisma.JsonValue;
45
+ }>[];
46
+ document: Partial<{
47
+ name: string;
48
+ id: string;
49
+ }>[];
50
+ post: Partial<{
51
+ id: number;
52
+ title: string;
53
+ published: boolean;
54
+ authorId: number;
55
+ updated: Date;
56
+ created: Date;
57
+ }>[];
58
+ pet: Partial<{
59
+ name: string;
60
+ id: number;
61
+ ownerId: number;
62
+ }>[];
63
+ toy: Partial<{
64
+ name: string;
65
+ id: number;
66
+ ownerId: number;
67
+ }>[];
68
+ transaction: Partial<{
69
+ id: string;
70
+ initiator: string;
71
+ }>[];
72
+ dbGeneratedId: Partial<{
73
+ id: string;
74
+ }>[];
75
+ }>>;
76
+ };
package/lib/legacy.js ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const client_1 = require("@prisma/client");
7
+ const client_2 = __importDefault(require("./client"));
8
+ const jest_mock_extended_1 = require("jest-mock-extended");
9
+ /**
10
+ * @deprecated Use default export instead
11
+ */
12
+ function createPrismaClient(data = {}, datamodel, mockClient, options) {
13
+ if (datamodel !== client_1.Prisma.dmmf.datamodel) {
14
+ throw new Error("datamodel !== Prisma.dmmf.datamodel is not supported, please use createPrismaMock instead");
15
+ }
16
+ let client = (0, client_2.default)(client_1.Prisma, {
17
+ data,
18
+ // @ts-ignore
19
+ mockClient: mockClient || (0, jest_mock_extended_1.mockDeep)(),
20
+ ...options
21
+ });
22
+ return client;
23
+ }
24
+ exports.default = createPrismaClient;
package/lib/types.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import type { Prisma } from "@prisma/client";
2
+ export type DeepMockApi = {
3
+ mockImplementation: (fnc: any) => void;
4
+ };
5
+ export type UnwrapPromise<P extends any> = P extends Promise<infer R> ? R : P;
6
+ export type PrismaDelegate = {
7
+ findUnique: (...args: Array<any>) => Promise<any>;
8
+ };
9
+ export type IsTable<S> = S extends `\$${infer fnc}` ? never : S;
10
+ export type IsString<S extends any> = S extends string ? S : never;
11
+ export type PrismaList<P extends {
12
+ [key: string]: any;
13
+ }, K extends string> = P[K] extends PrismaDelegate ? Array<Partial<UnwrapPromise<ReturnType<P[K]["findUnique"]>>>> : never;
14
+ export type PrismaMockData<P> = Partial<{
15
+ [key in IsTable<Uncapitalize<IsString<keyof P>>>]: PrismaList<P, key>;
16
+ }>;
17
+ export type Where = any;
18
+ export type Item = any;
19
+ export type Args = any;
20
+ export type CreateArgs = any;
21
+ export type MockPrismaOptions<P extends typeof Prisma> = {
22
+ datamodel: P["dmmf"]["datamodel"];
23
+ mockClient?: DeepMockApi;
24
+ caseInsensitive?: boolean;
25
+ enableIndexes?: boolean;
26
+ data?: any;
27
+ };
@@ -0,0 +1 @@
1
+ export declare function deepCopy<T>(source: T): T;
@@ -0,0 +1 @@
1
+ export declare function deepEqual(a: any, b: any): boolean;
@@ -0,0 +1,13 @@
1
+ import type { Prisma } from "@prisma/client";
2
+ import { Item } from "../types";
3
+ export declare function isFieldDefault(f: Prisma.DMMF.FieldDefault | readonly Prisma.DMMF.FieldDefaultScalar[] | Prisma.DMMF.FieldDefaultScalar): f is Prisma.DMMF.FieldDefault;
4
+ export declare function isDefinedWithValue<T extends object>(v: T, key: string): boolean;
5
+ export declare const getCamelCase: (name: any) => any;
6
+ export declare const removeMultiFieldIds: (model: Prisma.DMMF.Model, data: any) => any;
7
+ export declare const createGetFieldRelationshipWhere: (datamodel: Omit<Prisma.DMMF.Datamodel, 'indexes'>, manyToManyData: {
8
+ [relationName: string]: {
9
+ [type: string]: any;
10
+ }[];
11
+ }) => (item: any, field: Prisma.DMMF.Field, model: Prisma.DMMF.Model) => {
12
+ [x: string]: any;
13
+ };
@@ -0,0 +1 @@
1
+ export default function getNestedValue(keys: string[], values: any): any;
@@ -0,0 +1,2 @@
1
+ import type { Prisma } from "@prisma/client";
2
+ export default function getWhereOnIds(model: Prisma.DMMF.Model, item: any): {};
@@ -0,0 +1 @@
1
+ export default function pad(s: string, size: number): string;
@@ -0,0 +1,13 @@
1
+ import type { Prisma } from "@prisma/client";
2
+ import { createGetFieldRelationshipWhere } from "./fieldHelpers";
3
+ import { Where } from "../types";
4
+ type Props = {
5
+ getFieldRelationshipWhere: ReturnType<typeof createGetFieldRelationshipWhere>;
6
+ getDelegateForFieldName: (field: Prisma.DMMF.Field["type"]) => any;
7
+ model: Prisma.DMMF.Model;
8
+ datamodel: Omit<Prisma.DMMF.Datamodel, 'indexes'>;
9
+ caseInsensitive: boolean;
10
+ prisma: typeof Prisma;
11
+ };
12
+ export default function createMatch({ prisma, getFieldRelationshipWhere, getDelegateForFieldName, model, datamodel, caseInsensitive }: Props): (where: Where) => (item: any) => boolean;
13
+ export {};
@@ -3,12 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const client_1 = require("@prisma/client");
7
6
  const deepEqual_1 = require("./deepEqual");
8
7
  const shallowCompare_1 = require("./shallowCompare");
9
8
  const getNestedValue_1 = __importDefault(require("./getNestedValue"));
10
9
  const fieldHelpers_1 = require("./fieldHelpers");
11
- function createMatch({ getFieldRelationshipWhere, getDelegateForFieldName, model, datamodel, caseInsensitive }) {
10
+ function createMatch({ prisma, getFieldRelationshipWhere, getDelegateForFieldName, model, datamodel, caseInsensitive }) {
12
11
  const matchItem = (child, item, where) => {
13
12
  let val = item[child];
14
13
  const filter = where[child];
@@ -134,16 +133,16 @@ function createMatch({ getFieldRelationshipWhere, getDelegateForFieldName, model
134
133
  }
135
134
  if ("equals" in matchFilter && match) {
136
135
  // match = deepEqual(matchFilter.equals, val)
137
- if (matchFilter.equals === client_1.Prisma.DbNull) {
138
- if (val === client_1.Prisma.DbNull) {
136
+ if (matchFilter.equals === prisma.DbNull) {
137
+ if (val === prisma.DbNull) {
139
138
  }
140
- match = val === client_1.Prisma.DbNull;
139
+ match = val === prisma.DbNull;
141
140
  }
142
- else if (matchFilter.equals === client_1.Prisma.AnyNull) {
143
- match = val === client_1.Prisma.DbNull || val === client_1.Prisma.JsonNull;
141
+ else if (matchFilter.equals === prisma.AnyNull) {
142
+ match = val === prisma.DbNull || val === prisma.JsonNull;
144
143
  }
145
144
  else {
146
- if (val === client_1.Prisma.DbNull) {
145
+ if (val === prisma.DbNull) {
147
146
  match = false;
148
147
  }
149
148
  else {
@@ -205,11 +204,11 @@ function createMatch({ getFieldRelationshipWhere, getDelegateForFieldName, model
205
204
  match = matchFilter.in.includes(val);
206
205
  }
207
206
  if ("not" in matchFilter && match) {
208
- if (matchFilter.not === client_1.Prisma.DbNull) {
209
- match = val !== client_1.Prisma.DbNull;
207
+ if (matchFilter.not === prisma.DbNull) {
208
+ match = val !== prisma.DbNull;
210
209
  }
211
210
  else {
212
- if (val === client_1.Prisma.DbNull) {
211
+ if (val === prisma.DbNull) {
213
212
  match = false;
214
213
  }
215
214
  else {
@@ -0,0 +1,5 @@
1
+ export declare const shallowCompare: (a: {
2
+ [key: string]: any;
3
+ }, b: {
4
+ [key: string]: any;
5
+ }) => boolean;
package/package.json CHANGED
@@ -1,17 +1,34 @@
1
1
  {
2
2
  "name": "prisma-mock",
3
- "version": "0.12.2",
3
+ "version": "1.0.0-alpha.1",
4
4
  "description": "Mock prisma for unit testing database",
5
5
  "main": "lib/index.js",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/demonsters/prisma-mock.git"
9
9
  },
10
+ "bin": {
11
+ "prisma-mock": "./prisma-dmmf-generator.mjs"
12
+ },
10
13
  "license": "MIT",
11
14
  "types": "lib/",
12
15
  "files": [
13
16
  "lib/"
14
17
  ],
18
+ "exports": {
19
+ ".": {
20
+ "types": "./lib/index.d.ts",
21
+ "default": "./lib/index.js"
22
+ },
23
+ "./legacy": {
24
+ "types": "./lib/legacy.d.ts",
25
+ "default": "./lib/legacy.js"
26
+ },
27
+ "./client": {
28
+ "types": "./lib/client.d.ts",
29
+ "default": "./lib/client.js"
30
+ }
31
+ },
15
32
  "devDependencies": {
16
33
  "@changesets/cli": "^2.29.5",
17
34
  "@prisma/client": "6.11.1",
@@ -42,6 +59,5 @@
42
59
  },
43
60
  "dependencies": {
44
61
  "jest-mock-extended": "^3.0.6"
45
- },
46
- "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
62
+ }
47
63
  }
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ import { writeFile } from "fs/promises"
3
+ import helper from "@prisma/generator-helper"
4
+
5
+ helper.generatorHandler({
6
+ onManifest: () => ({
7
+ prettyName: "prisma-mock",
8
+ version: "1.0.0",
9
+ }),
10
+ onGenerate({ generator, dmmf }) {
11
+ if (!generator.output?.value)
12
+ throw new Error("Missing output path in generator configuration")
13
+
14
+ const exports = Object.entries(dmmf.datamodel).reduce(
15
+ (acc, [k, v], idx, arr) =>
16
+ acc +
17
+ `export const ${k} = ${JSON.stringify(v, null, 2)};\n${
18
+ arr[idx + 1] ? "\n" : ""
19
+ }`,
20
+ ""
21
+ )
22
+
23
+ return writeFile(generator.output.value, exports, "utf8")
24
+ },
25
+ })