@dismissible/nestjs-postgres-storage 0.0.2-canary.c91edbc.0 → 0.0.2-canary.d2f56d7.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.
@@ -0,0 +1,35 @@
1
+ import { fileURLToPath } from 'url';
2
+ import { dirname, join } from 'path';
3
+ import { defineConfig } from 'prisma/config';
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const prismaDir = join(__dirname, 'prisma');
7
+
8
+ /**
9
+ * Prisma configuration for @dismissible/nestjs-postgres-storage.
10
+ *
11
+ * This config is used by the dismissible-prisma CLI and can be used directly
12
+ * by consumers who need to extend or customize the configuration.
13
+ *
14
+ * For consumers who want to use the base config in their own prisma.config.mjs:
15
+ *
16
+ * @example
17
+ * ```javascript
18
+ * import { defineConfig } from 'prisma/config';
19
+ * import { basePrismaConfig } from '@dismissible/nestjs-postgres-storage';
20
+ *
21
+ * export default defineConfig(basePrismaConfig);
22
+ * ```
23
+ */
24
+ export default defineConfig({
25
+ schema: join(prismaDir, 'schema.prisma'),
26
+ migrations: {
27
+ path: join(prismaDir, 'migrations'),
28
+ },
29
+ datasource: {
30
+ url:
31
+ process.env.DATABASE_URL ??
32
+ process.env.DISMISSIBLE_POSTGRES_STORAGE_CONNECTION_STRING ??
33
+ '',
34
+ },
35
+ });
package/src/index.ts CHANGED
@@ -2,4 +2,5 @@ export * from './postgres-storage.adapter';
2
2
  export * from './postgres-storage.config';
3
3
  export * from './postgres-storage.module';
4
4
  export * from './prisma.service';
5
+ export * from './prisma-config';
5
6
  export * from './schema-path';
@@ -1,5 +1,4 @@
1
1
  import { mock } from 'ts-jest-mocker';
2
- import { Prisma } from '../prisma/generated/prisma/client';
3
2
  import { PostgresStorageAdapter } from './postgres-storage.adapter';
4
3
  import { PrismaService } from './prisma.service';
5
4
  import { IDismissibleLogger } from '@dismissible/nestjs-logger';
@@ -64,7 +63,6 @@ describe('PostgresStorageAdapter', () => {
64
63
  userId: 'user-123',
65
64
  createdAt: new Date('2024-01-15T10:30:00.000Z'),
66
65
  dismissedAt: null,
67
- metadata: null,
68
66
  };
69
67
  mockDismissibleItem.findUnique.mockResolvedValue(dbItem);
70
68
 
@@ -75,34 +73,12 @@ describe('PostgresStorageAdapter', () => {
75
73
  userId: 'user-123',
76
74
  createdAt: new Date('2024-01-15T10:30:00.000Z'),
77
75
  dismissedAt: undefined,
78
- metadata: undefined,
79
76
  });
80
77
  expect(mockLogger.debug).toHaveBeenCalledWith('PostgreSQL storage hit', {
81
78
  userId: 'user-123',
82
79
  itemId: 'item-456',
83
80
  });
84
81
  });
85
-
86
- it('should return item with metadata when present', async () => {
87
- const dbItem = {
88
- id: 'item-456',
89
- userId: 'user-123',
90
- createdAt: new Date('2024-01-15T10:30:00.000Z'),
91
- dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
92
- metadata: { version: 2, category: 'promotional' },
93
- };
94
- mockDismissibleItem.findUnique.mockResolvedValue(dbItem);
95
-
96
- const result = await adapter.get('user-123', 'item-456');
97
-
98
- expect(result).toEqual({
99
- id: 'item-456',
100
- userId: 'user-123',
101
- createdAt: new Date('2024-01-15T10:30:00.000Z'),
102
- dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
103
- metadata: { version: 2, category: 'promotional' },
104
- });
105
- });
106
82
  });
107
83
 
108
84
  describe('create', () => {
@@ -117,7 +93,6 @@ describe('PostgresStorageAdapter', () => {
117
93
  userId: 'user-123',
118
94
  createdAt: new Date('2024-01-15T10:30:00.000Z'),
119
95
  dismissedAt: null,
120
- metadata: null,
121
96
  };
122
97
  mockDismissibleItem.create.mockResolvedValue(dbItem);
123
98
 
@@ -128,7 +103,6 @@ describe('PostgresStorageAdapter', () => {
128
103
  userId: 'user-123',
129
104
  createdAt: new Date('2024-01-15T10:30:00.000Z'),
130
105
  dismissedAt: undefined,
131
- metadata: undefined,
132
106
  });
133
107
  expect(mockDismissibleItem.create).toHaveBeenCalledWith({
134
108
  data: {
@@ -136,7 +110,6 @@ describe('PostgresStorageAdapter', () => {
136
110
  userId: 'user-123',
137
111
  createdAt: new Date('2024-01-15T10:30:00.000Z'),
138
112
  dismissedAt: null,
139
- metadata: Prisma.JsonNull,
140
113
  },
141
114
  });
142
115
  expect(mockLogger.debug).toHaveBeenCalledWith('PostgreSQL storage create', {
@@ -144,33 +117,6 @@ describe('PostgresStorageAdapter', () => {
144
117
  itemId: 'item-456',
145
118
  });
146
119
  });
147
-
148
- it('should create an item with metadata', async () => {
149
- const item: DismissibleItemDto = {
150
- id: 'item-456',
151
- userId: 'user-123',
152
- createdAt: new Date('2024-01-15T10:30:00.000Z'),
153
- metadata: { version: 2 },
154
- };
155
- const dbItem = {
156
- id: 'item-456',
157
- userId: 'user-123',
158
- createdAt: new Date('2024-01-15T10:30:00.000Z'),
159
- dismissedAt: null,
160
- metadata: { version: 2 },
161
- };
162
- mockDismissibleItem.create.mockResolvedValue(dbItem);
163
-
164
- const result = await adapter.create(item);
165
-
166
- expect(result).toEqual({
167
- id: 'item-456',
168
- userId: 'user-123',
169
- createdAt: new Date('2024-01-15T10:30:00.000Z'),
170
- dismissedAt: undefined,
171
- metadata: { version: 2 },
172
- });
173
- });
174
120
  });
175
121
 
176
122
  describe('update', () => {
@@ -186,7 +132,6 @@ describe('PostgresStorageAdapter', () => {
186
132
  userId: 'user-123',
187
133
  createdAt: new Date('2024-01-15T10:30:00.000Z'),
188
134
  dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
189
- metadata: null,
190
135
  };
191
136
  mockDismissibleItem.update.mockResolvedValue(dbItem);
192
137
 
@@ -197,7 +142,6 @@ describe('PostgresStorageAdapter', () => {
197
142
  userId: 'user-123',
198
143
  createdAt: new Date('2024-01-15T10:30:00.000Z'),
199
144
  dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
200
- metadata: undefined,
201
145
  });
202
146
  expect(mockDismissibleItem.update).toHaveBeenCalledWith({
203
147
  where: {
@@ -208,7 +152,6 @@ describe('PostgresStorageAdapter', () => {
208
152
  },
209
153
  data: {
210
154
  dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
211
- metadata: Prisma.JsonNull,
212
155
  },
213
156
  });
214
157
  expect(mockLogger.debug).toHaveBeenCalledWith('PostgreSQL storage update', {
@@ -216,33 +159,5 @@ describe('PostgresStorageAdapter', () => {
216
159
  itemId: 'item-456',
217
160
  });
218
161
  });
219
-
220
- it('should update an item with metadata', async () => {
221
- const item: DismissibleItemDto = {
222
- id: 'item-456',
223
- userId: 'user-123',
224
- createdAt: new Date('2024-01-15T10:30:00.000Z'),
225
- dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
226
- metadata: { version: 3, updated: true },
227
- };
228
- const dbItem = {
229
- id: 'item-456',
230
- userId: 'user-123',
231
- createdAt: new Date('2024-01-15T10:30:00.000Z'),
232
- dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
233
- metadata: { version: 3, updated: true },
234
- };
235
- mockDismissibleItem.update.mockResolvedValue(dbItem);
236
-
237
- const result = await adapter.update(item);
238
-
239
- expect(result).toEqual({
240
- id: 'item-456',
241
- userId: 'user-123',
242
- createdAt: new Date('2024-01-15T10:30:00.000Z'),
243
- dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
244
- metadata: { version: 3, updated: true },
245
- });
246
- });
247
162
  });
248
163
  });
@@ -1,12 +1,7 @@
1
1
  import { Injectable, Inject } from '@nestjs/common';
2
2
  import { DISMISSIBLE_LOGGER, IDismissibleLogger } from '@dismissible/nestjs-logger';
3
3
  import { IDismissibleStorage } from '@dismissible/nestjs-storage';
4
- import {
5
- BaseMetadata,
6
- DismissibleItemDto,
7
- DismissibleItemFactory,
8
- } from '@dismissible/nestjs-dismissible-item';
9
- import { Prisma } from '../prisma/generated/prisma/client';
4
+ import { DismissibleItemDto, DismissibleItemFactory } from '@dismissible/nestjs-dismissible-item';
10
5
  import { PrismaService } from './prisma.service';
11
6
 
12
7
  /**
@@ -14,16 +9,14 @@ import { PrismaService } from './prisma.service';
14
9
  * Implements IDismissibleStorage for persistent database storage.
15
10
  */
16
11
  @Injectable()
17
- export class PostgresStorageAdapter<
18
- TMetadata extends BaseMetadata = BaseMetadata,
19
- > implements IDismissibleStorage<TMetadata> {
12
+ export class PostgresStorageAdapter implements IDismissibleStorage {
20
13
  constructor(
21
14
  private readonly prisma: PrismaService,
22
15
  @Inject(DISMISSIBLE_LOGGER) private readonly logger: IDismissibleLogger,
23
16
  private readonly itemFactory: DismissibleItemFactory,
24
17
  ) {}
25
18
 
26
- async get(userId: string, itemId: string): Promise<DismissibleItemDto<TMetadata> | null> {
19
+ async get(userId: string, itemId: string): Promise<DismissibleItemDto | null> {
27
20
  this.logger.debug('PostgreSQL storage get', { userId, itemId });
28
21
 
29
22
  const item = await this.prisma.dismissibleItem.findUnique({
@@ -45,7 +38,7 @@ export class PostgresStorageAdapter<
45
38
  return this.mapToDto(item);
46
39
  }
47
40
 
48
- async create(item: DismissibleItemDto<TMetadata>): Promise<DismissibleItemDto<TMetadata>> {
41
+ async create(item: DismissibleItemDto): Promise<DismissibleItemDto> {
49
42
  this.logger.debug('PostgreSQL storage create', { userId: item.userId, itemId: item.id });
50
43
 
51
44
  const created = await this.prisma.dismissibleItem.create({
@@ -54,14 +47,13 @@ export class PostgresStorageAdapter<
54
47
  userId: item.userId,
55
48
  createdAt: item.createdAt,
56
49
  dismissedAt: item.dismissedAt ?? null,
57
- metadata: (item.metadata as Prisma.InputJsonValue) ?? Prisma.JsonNull,
58
50
  },
59
51
  });
60
52
 
61
53
  return this.mapToDto(created);
62
54
  }
63
55
 
64
- async update(item: DismissibleItemDto<TMetadata>): Promise<DismissibleItemDto<TMetadata>> {
56
+ async update(item: DismissibleItemDto): Promise<DismissibleItemDto> {
65
57
  this.logger.debug('PostgreSQL storage update', { userId: item.userId, itemId: item.id });
66
58
 
67
59
  const updated = await this.prisma.dismissibleItem.update({
@@ -73,7 +65,6 @@ export class PostgresStorageAdapter<
73
65
  },
74
66
  data: {
75
67
  dismissedAt: item.dismissedAt ?? null,
76
- metadata: (item.metadata as Prisma.InputJsonValue) ?? Prisma.JsonNull,
77
68
  },
78
69
  });
79
70
 
@@ -88,14 +79,12 @@ export class PostgresStorageAdapter<
88
79
  userId: string;
89
80
  createdAt: Date;
90
81
  dismissedAt: Date | null;
91
- metadata: unknown;
92
- }): DismissibleItemDto<TMetadata> {
82
+ }): DismissibleItemDto {
93
83
  return this.itemFactory.create({
94
84
  id: item.id,
95
85
  userId: item.userId,
96
86
  createdAt: item.createdAt,
97
87
  dismissedAt: item.dismissedAt ?? undefined,
98
- metadata: (item.metadata as TMetadata) ?? undefined,
99
88
  });
100
89
  }
101
90
  }
@@ -46,7 +46,7 @@ export class PostgresStorageModule {
46
46
  useExisting: PostgresStorageAdapter,
47
47
  },
48
48
  ],
49
- exports: [DISMISSIBLE_STORAGE_ADAPTER],
49
+ exports: [DISMISSIBLE_STORAGE_ADAPTER, PrismaService],
50
50
  };
51
51
  }
52
52
 
@@ -73,7 +73,7 @@ export class PostgresStorageModule {
73
73
  useExisting: PostgresStorageAdapter,
74
74
  },
75
75
  ],
76
- exports: [DISMISSIBLE_STORAGE_ADAPTER],
76
+ exports: [DISMISSIBLE_STORAGE_ADAPTER, PrismaService],
77
77
  };
78
78
  }
79
79
  }
@@ -0,0 +1,93 @@
1
+ import { join } from 'path';
2
+
3
+ describe('prisma-config', () => {
4
+ const originalEnv = process.env;
5
+
6
+ beforeEach(() => {
7
+ jest.resetModules();
8
+ process.env = { ...originalEnv };
9
+ delete process.env.DATABASE_URL;
10
+ delete process.env.DISMISSIBLE_POSTGRES_STORAGE_CONNECTION_STRING;
11
+ });
12
+
13
+ afterAll(() => {
14
+ process.env = originalEnv;
15
+ });
16
+
17
+ describe('createPrismaConfig', () => {
18
+ it('should return config with schema path relative to package', async () => {
19
+ const { createPrismaConfig } = await import('./prisma-config');
20
+ const config = createPrismaConfig();
21
+
22
+ expect(config.schema).toContain('schema.prisma');
23
+ expect(config.schema).toMatch(/postgres-storage.*prisma.*schema\.prisma$/);
24
+ });
25
+
26
+ it('should return config with migrations path relative to package', async () => {
27
+ const { createPrismaConfig } = await import('./prisma-config');
28
+ const config = createPrismaConfig();
29
+
30
+ expect(config.migrations.path).toContain('migrations');
31
+ expect(config.migrations.path).toMatch(/postgres-storage.*prisma.*migrations$/);
32
+ });
33
+
34
+ it('should use DATABASE_URL when set', async () => {
35
+ process.env.DATABASE_URL = 'postgres://test:test@localhost/test';
36
+
37
+ const { createPrismaConfig } = await import('./prisma-config');
38
+ const config = createPrismaConfig();
39
+
40
+ expect(config.datasource.url).toBe('postgres://test:test@localhost/test');
41
+ });
42
+
43
+ it('should fall back to DISMISSIBLE_POSTGRES_STORAGE_CONNECTION_STRING when DATABASE_URL is not set', async () => {
44
+ process.env.DISMISSIBLE_POSTGRES_STORAGE_CONNECTION_STRING =
45
+ 'postgres://fallback:fallback@localhost/fallback';
46
+
47
+ const { createPrismaConfig } = await import('./prisma-config');
48
+ const config = createPrismaConfig();
49
+
50
+ expect(config.datasource.url).toBe('postgres://fallback:fallback@localhost/fallback');
51
+ });
52
+
53
+ it('should prefer DATABASE_URL over DISMISSIBLE_POSTGRES_STORAGE_CONNECTION_STRING', async () => {
54
+ process.env.DATABASE_URL = 'postgres://primary:primary@localhost/primary';
55
+ process.env.DISMISSIBLE_POSTGRES_STORAGE_CONNECTION_STRING =
56
+ 'postgres://fallback:fallback@localhost/fallback';
57
+
58
+ const { createPrismaConfig } = await import('./prisma-config');
59
+ const config = createPrismaConfig();
60
+
61
+ expect(config.datasource.url).toBe('postgres://primary:primary@localhost/primary');
62
+ });
63
+
64
+ it('should return empty string when no database URL is set', async () => {
65
+ const { createPrismaConfig } = await import('./prisma-config');
66
+ const config = createPrismaConfig();
67
+
68
+ expect(config.datasource.url).toBe('');
69
+ });
70
+ });
71
+
72
+ describe('basePrismaConfig', () => {
73
+ it('should be exported and have the expected structure', async () => {
74
+ const { basePrismaConfig } = await import('./prisma-config');
75
+
76
+ expect(basePrismaConfig).toBeDefined();
77
+ expect(basePrismaConfig).toHaveProperty('schema');
78
+ expect(basePrismaConfig).toHaveProperty('migrations');
79
+ expect(basePrismaConfig).toHaveProperty('datasource');
80
+ expect(basePrismaConfig.migrations).toHaveProperty('path');
81
+ expect(basePrismaConfig.datasource).toHaveProperty('url');
82
+ });
83
+
84
+ it('should have schema and migrations paths pointing to the same prisma directory', async () => {
85
+ const { basePrismaConfig } = await import('./prisma-config');
86
+
87
+ const schemaDir = join(basePrismaConfig.schema, '..');
88
+ const migrationsDir = join(basePrismaConfig.migrations.path, '..');
89
+
90
+ expect(schemaDir).toBe(migrationsDir);
91
+ });
92
+ });
93
+ });
@@ -0,0 +1,63 @@
1
+ import { join } from 'path';
2
+ import { getPrismaSchemaPath } from './schema-path';
3
+
4
+ /**
5
+ * Creates a Prisma configuration object with paths resolved relative to
6
+ * the @dismissible/nestjs-postgres-storage package.
7
+ *
8
+ * @returns Prisma configuration object suitable for use with defineConfig()
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // prisma.config.mjs
13
+ * import { defineConfig } from 'prisma/config';
14
+ * import { basePrismaConfig } from '@dismissible/nestjs-postgres-storage';
15
+ *
16
+ * export default defineConfig(basePrismaConfig);
17
+ * ```
18
+ */
19
+ export function createPrismaConfig() {
20
+ const prismaDir = join(getPrismaSchemaPath(), '..');
21
+ return {
22
+ schema: join(prismaDir, 'schema.prisma'),
23
+ migrations: {
24
+ path: join(prismaDir, 'migrations'),
25
+ },
26
+ datasource: {
27
+ url:
28
+ process.env.DATABASE_URL ??
29
+ process.env.DISMISSIBLE_POSTGRES_STORAGE_CONNECTION_STRING ??
30
+ '',
31
+ },
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Base Prisma configuration for @dismissible/nestjs-postgres-storage.
37
+ *
38
+ * Use this with Prisma's defineConfig() to create your prisma.config.mjs:
39
+ *
40
+ * @example
41
+ * ```javascript
42
+ * // prisma.config.mjs
43
+ * import { defineConfig } from 'prisma/config';
44
+ * import { basePrismaConfig } from '@dismissible/nestjs-postgres-storage';
45
+ *
46
+ * export default defineConfig(basePrismaConfig);
47
+ * ```
48
+ *
49
+ * @example Extending the config
50
+ * ```javascript
51
+ * import { defineConfig } from 'prisma/config';
52
+ * import { basePrismaConfig } from '@dismissible/nestjs-postgres-storage';
53
+ *
54
+ * export default defineConfig({
55
+ * ...basePrismaConfig,
56
+ * migrations: {
57
+ * ...basePrismaConfig.migrations,
58
+ * seed: 'tsx prisma/seed.ts',
59
+ * },
60
+ * });
61
+ * ```
62
+ */
63
+ export const basePrismaConfig = createPrismaConfig();
@@ -0,0 +1,131 @@
1
+ import { mock } from 'ts-jest-mocker';
2
+ import { PrismaService } from './prisma.service';
3
+ import { PostgresStorageConfig } from './postgres-storage.config';
4
+ import { IDismissibleLogger } from '@dismissible/nestjs-logger';
5
+
6
+ // Mock the modules before importing PrismaService
7
+ const mockPoolInstance = {};
8
+ const mockPrismaPgInstance = {};
9
+
10
+ jest.mock('pg', () => ({
11
+ Pool: jest.fn().mockImplementation(() => mockPoolInstance),
12
+ }));
13
+
14
+ jest.mock('@prisma/adapter-pg', () => ({
15
+ PrismaPg: jest.fn().mockImplementation(() => mockPrismaPgInstance),
16
+ }));
17
+
18
+ // Mock PrismaClient to avoid actual initialization
19
+ const mockPrismaClientMethods = {
20
+ $connect: jest.fn(),
21
+ $disconnect: jest.fn(),
22
+ $queryRaw: jest.fn(),
23
+ };
24
+
25
+ jest.mock('../prisma/generated/prisma/client', () => {
26
+ // Create a mock PrismaClient class inside the factory
27
+ class MockPrismaClient {
28
+ $connect = jest.fn();
29
+ $disconnect = jest.fn();
30
+ $queryRaw = jest.fn();
31
+ }
32
+ return {
33
+ PrismaClient: MockPrismaClient,
34
+ };
35
+ });
36
+
37
+ describe('PrismaService', () => {
38
+ let service: PrismaService;
39
+ let mockConfig: PostgresStorageConfig;
40
+ let mockLogger: jest.Mocked<IDismissibleLogger>;
41
+
42
+ beforeEach(() => {
43
+ mockConfig = {
44
+ connectionString: 'postgresql://user:password@localhost:5432/testdb',
45
+ };
46
+ mockLogger = mock<IDismissibleLogger>({ failIfMockNotProvided: false });
47
+
48
+ // Clear all mocks
49
+ jest.clearAllMocks();
50
+ mockPrismaClientMethods.$connect.mockClear();
51
+ mockPrismaClientMethods.$disconnect.mockClear();
52
+ mockPrismaClientMethods.$queryRaw.mockClear();
53
+ });
54
+
55
+ describe('constructor', () => {
56
+ it('should create PrismaService with pool and adapter', () => {
57
+ const { Pool } = require('pg');
58
+ const { PrismaPg } = require('@prisma/adapter-pg');
59
+
60
+ service = new PrismaService(mockConfig, mockLogger);
61
+
62
+ expect(service).toBeDefined();
63
+ expect(Pool).toHaveBeenCalledWith({
64
+ connectionString: mockConfig.connectionString,
65
+ });
66
+ expect(PrismaPg).toHaveBeenCalledWith(mockPoolInstance);
67
+ });
68
+ });
69
+
70
+ describe('onModuleInit', () => {
71
+ it('should connect to database and verify connection', async () => {
72
+ service = new PrismaService(mockConfig, mockLogger);
73
+ (service as any).$connect.mockResolvedValue(undefined);
74
+ (service as any).$queryRaw.mockResolvedValue([{ '?column?': 1 }]);
75
+
76
+ await service.onModuleInit();
77
+
78
+ expect(mockLogger.debug).toHaveBeenCalledWith('Connecting to PostgreSQL database');
79
+ expect((service as any).$connect).toHaveBeenCalled();
80
+ expect((service as any).$queryRaw).toHaveBeenCalled();
81
+ expect(mockLogger.debug).toHaveBeenCalledWith('Connected to PostgreSQL database');
82
+ });
83
+
84
+ it('should throw error when connection fails', async () => {
85
+ service = new PrismaService(mockConfig, mockLogger);
86
+ const connectError = new Error('Connection refused');
87
+ (service as any).$connect = jest.fn().mockRejectedValue(connectError);
88
+
89
+ // $connect() is called before the try-catch, so errors propagate directly
90
+ await expect(service.onModuleInit()).rejects.toThrow('Connection refused');
91
+ // Note: $connect errors are not logged because they're outside the try-catch
92
+ });
93
+
94
+ it('should throw error when query verification fails', async () => {
95
+ service = new PrismaService(mockConfig, mockLogger);
96
+ (service as any).$connect.mockResolvedValue(undefined);
97
+ (service as any).$queryRaw.mockRejectedValue(new Error('Query failed'));
98
+
99
+ await expect(service.onModuleInit()).rejects.toThrow(
100
+ 'Database connection failed: Query failed. Ensure PostgreSQL is running and DISMISSIBLE_POSTGRES_STORAGE_CONNECTION_STRING is configured correctly.',
101
+ );
102
+ expect(mockLogger.error).toHaveBeenCalledWith(
103
+ 'Failed to connect to PostgreSQL database',
104
+ expect.any(Error),
105
+ );
106
+ });
107
+
108
+ it('should handle non-Error objects in catch block', async () => {
109
+ service = new PrismaService(mockConfig, mockLogger);
110
+ (service as any).$connect.mockResolvedValue(undefined);
111
+ (service as any).$queryRaw.mockRejectedValue('String error');
112
+
113
+ await expect(service.onModuleInit()).rejects.toThrow(
114
+ 'Database connection failed: Unknown error. Ensure PostgreSQL is running and DISMISSIBLE_POSTGRES_STORAGE_CONNECTION_STRING is configured correctly.',
115
+ );
116
+ });
117
+ });
118
+
119
+ describe('onModuleDestroy', () => {
120
+ it('should disconnect from database', async () => {
121
+ service = new PrismaService(mockConfig, mockLogger);
122
+ (service as any).$disconnect.mockResolvedValue(undefined);
123
+
124
+ await service.onModuleDestroy();
125
+
126
+ expect(mockLogger.debug).toHaveBeenCalledWith('Disconnecting from PostgreSQL database');
127
+ expect((service as any).$disconnect).toHaveBeenCalled();
128
+ expect(mockLogger.debug).toHaveBeenCalledWith('Disconnected from PostgreSQL database');
129
+ });
130
+ });
131
+ });
@@ -0,0 +1,24 @@
1
+ import { getPrismaSchemaPath } from './schema-path';
2
+ import { join } from 'path';
3
+
4
+ describe('schema-path', () => {
5
+ describe('getPrismaSchemaPath', () => {
6
+ it('should return the absolute path to the Prisma schema file', () => {
7
+ const schemaPath = getPrismaSchemaPath();
8
+
9
+ expect(schemaPath).toBeDefined();
10
+ expect(typeof schemaPath).toBe('string');
11
+ expect(schemaPath).toContain('prisma');
12
+ expect(schemaPath).toContain('schema.prisma');
13
+ // Verify it uses join to construct the path
14
+ expect(schemaPath).toBe(join(__dirname, '..', 'prisma', 'schema.prisma'));
15
+ });
16
+
17
+ it('should return a valid path structure', () => {
18
+ const schemaPath = getPrismaSchemaPath();
19
+
20
+ // Path should be absolute (starts with / on Unix, or C:\ on Windows)
21
+ expect(schemaPath).toMatch(/^(\/|[A-Z]:\\)/);
22
+ });
23
+ });
24
+ });
@@ -6,12 +6,12 @@ import { join } from 'path';
6
6
  *
7
7
  * @example
8
8
  * ```typescript
9
- * import { getSchemaPath } from '@dismissible/nestjs-postgres-storage';
9
+ * import { getPrismaSchemaPath } from '@dismissible/nestjs-postgres-storage';
10
10
  * import { execSync } from 'child_process';
11
11
  *
12
- * execSync(`npx prisma generate --schema=${getSchemaPath()}`);
12
+ * execSync(`npx prisma generate --schema=${getPrismaSchemaPath()}`);
13
13
  * ```
14
14
  */
15
- export function getSchemaPath(): string {
15
+ export function getPrismaSchemaPath(): string {
16
16
  return join(__dirname, '..', 'prisma', 'schema.prisma');
17
17
  }
package/jest.config.ts DELETED
@@ -1,10 +0,0 @@
1
- export default {
2
- displayName: 'postgres-storage',
3
- preset: '../../jest.preset.js',
4
- testEnvironment: 'node',
5
- transform: {
6
- '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.json' }],
7
- },
8
- moduleFileExtensions: ['ts', 'js', 'html'],
9
- coverageDirectory: '../../coverage/libs/postgres-storage',
10
- };