@dismissible/nestjs-postgres-storage 0.0.2-canary.738340d.0 → 0.0.2-canary.b0d8bfe.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 +108 -10
- package/bin/dismissible-prisma.js +4 -2
- package/package.json +23 -24
- package/prisma/generated/prisma/commonInputTypes.ts +0 -75
- package/prisma/generated/prisma/internal/class.ts +4 -4
- package/prisma/generated/prisma/internal/prismaNamespace.ts +5 -37
- package/prisma/generated/prisma/internal/prismaNamespaceBrowser.ts +1 -19
- package/prisma/generated/prisma/models/DismissibleItem.ts +1 -23
- package/prisma/migrations/20251219094936_init/migration.sql +12 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +0 -1
- package/prisma.config.mjs +33 -0
- package/src/index.ts +1 -0
- package/src/postgres-storage.adapter.spec.ts +0 -88
- package/src/postgres-storage.adapter.ts +6 -17
- package/src/postgres-storage.module.ts +2 -2
- package/src/prisma-config.spec.ts +93 -0
- package/src/prisma-config.ts +63 -0
- package/src/prisma.service.spec.ts +125 -0
- package/src/prisma.service.ts +11 -1
- package/src/schema-path.spec.ts +22 -0
- package/src/schema-path.ts +3 -3
- package/jest.config.ts +0 -10
- package/project.json +0 -73
- package/tsconfig.json +0 -13
- package/tsconfig.lib.json +0 -14
|
@@ -43,7 +43,6 @@ export type DismissibleItemCountAggregateOutputType = {
|
|
|
43
43
|
userId: number
|
|
44
44
|
createdAt: number
|
|
45
45
|
dismissedAt: number
|
|
46
|
-
metadata: number
|
|
47
46
|
_all: number
|
|
48
47
|
}
|
|
49
48
|
|
|
@@ -67,7 +66,6 @@ export type DismissibleItemCountAggregateInputType = {
|
|
|
67
66
|
userId?: true
|
|
68
67
|
createdAt?: true
|
|
69
68
|
dismissedAt?: true
|
|
70
|
-
metadata?: true
|
|
71
69
|
_all?: true
|
|
72
70
|
}
|
|
73
71
|
|
|
@@ -148,7 +146,6 @@ export type DismissibleItemGroupByOutputType = {
|
|
|
148
146
|
userId: string
|
|
149
147
|
createdAt: Date
|
|
150
148
|
dismissedAt: Date | null
|
|
151
|
-
metadata: runtime.JsonValue | null
|
|
152
149
|
_count: DismissibleItemCountAggregateOutputType | null
|
|
153
150
|
_min: DismissibleItemMinAggregateOutputType | null
|
|
154
151
|
_max: DismissibleItemMaxAggregateOutputType | null
|
|
@@ -177,7 +174,6 @@ export type DismissibleItemWhereInput = {
|
|
|
177
174
|
userId?: Prisma.StringFilter<"DismissibleItem"> | string
|
|
178
175
|
createdAt?: Prisma.DateTimeFilter<"DismissibleItem"> | Date | string
|
|
179
176
|
dismissedAt?: Prisma.DateTimeNullableFilter<"DismissibleItem"> | Date | string | null
|
|
180
|
-
metadata?: Prisma.JsonNullableFilter<"DismissibleItem">
|
|
181
177
|
}
|
|
182
178
|
|
|
183
179
|
export type DismissibleItemOrderByWithRelationInput = {
|
|
@@ -185,7 +181,6 @@ export type DismissibleItemOrderByWithRelationInput = {
|
|
|
185
181
|
userId?: Prisma.SortOrder
|
|
186
182
|
createdAt?: Prisma.SortOrder
|
|
187
183
|
dismissedAt?: Prisma.SortOrderInput | Prisma.SortOrder
|
|
188
|
-
metadata?: Prisma.SortOrderInput | Prisma.SortOrder
|
|
189
184
|
}
|
|
190
185
|
|
|
191
186
|
export type DismissibleItemWhereUniqueInput = Prisma.AtLeast<{
|
|
@@ -197,7 +192,6 @@ export type DismissibleItemWhereUniqueInput = Prisma.AtLeast<{
|
|
|
197
192
|
userId?: Prisma.StringFilter<"DismissibleItem"> | string
|
|
198
193
|
createdAt?: Prisma.DateTimeFilter<"DismissibleItem"> | Date | string
|
|
199
194
|
dismissedAt?: Prisma.DateTimeNullableFilter<"DismissibleItem"> | Date | string | null
|
|
200
|
-
metadata?: Prisma.JsonNullableFilter<"DismissibleItem">
|
|
201
195
|
}, "userId_id">
|
|
202
196
|
|
|
203
197
|
export type DismissibleItemOrderByWithAggregationInput = {
|
|
@@ -205,7 +199,6 @@ export type DismissibleItemOrderByWithAggregationInput = {
|
|
|
205
199
|
userId?: Prisma.SortOrder
|
|
206
200
|
createdAt?: Prisma.SortOrder
|
|
207
201
|
dismissedAt?: Prisma.SortOrderInput | Prisma.SortOrder
|
|
208
|
-
metadata?: Prisma.SortOrderInput | Prisma.SortOrder
|
|
209
202
|
_count?: Prisma.DismissibleItemCountOrderByAggregateInput
|
|
210
203
|
_max?: Prisma.DismissibleItemMaxOrderByAggregateInput
|
|
211
204
|
_min?: Prisma.DismissibleItemMinOrderByAggregateInput
|
|
@@ -219,7 +212,6 @@ export type DismissibleItemScalarWhereWithAggregatesInput = {
|
|
|
219
212
|
userId?: Prisma.StringWithAggregatesFilter<"DismissibleItem"> | string
|
|
220
213
|
createdAt?: Prisma.DateTimeWithAggregatesFilter<"DismissibleItem"> | Date | string
|
|
221
214
|
dismissedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"DismissibleItem"> | Date | string | null
|
|
222
|
-
metadata?: Prisma.JsonNullableWithAggregatesFilter<"DismissibleItem">
|
|
223
215
|
}
|
|
224
216
|
|
|
225
217
|
export type DismissibleItemCreateInput = {
|
|
@@ -227,7 +219,6 @@ export type DismissibleItemCreateInput = {
|
|
|
227
219
|
userId: string
|
|
228
220
|
createdAt?: Date | string
|
|
229
221
|
dismissedAt?: Date | string | null
|
|
230
|
-
metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue
|
|
231
222
|
}
|
|
232
223
|
|
|
233
224
|
export type DismissibleItemUncheckedCreateInput = {
|
|
@@ -235,7 +226,6 @@ export type DismissibleItemUncheckedCreateInput = {
|
|
|
235
226
|
userId: string
|
|
236
227
|
createdAt?: Date | string
|
|
237
228
|
dismissedAt?: Date | string | null
|
|
238
|
-
metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue
|
|
239
229
|
}
|
|
240
230
|
|
|
241
231
|
export type DismissibleItemUpdateInput = {
|
|
@@ -243,7 +233,6 @@ export type DismissibleItemUpdateInput = {
|
|
|
243
233
|
userId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
244
234
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
245
235
|
dismissedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
|
246
|
-
metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue
|
|
247
236
|
}
|
|
248
237
|
|
|
249
238
|
export type DismissibleItemUncheckedUpdateInput = {
|
|
@@ -251,7 +240,6 @@ export type DismissibleItemUncheckedUpdateInput = {
|
|
|
251
240
|
userId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
252
241
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
253
242
|
dismissedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
|
254
|
-
metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue
|
|
255
243
|
}
|
|
256
244
|
|
|
257
245
|
export type DismissibleItemCreateManyInput = {
|
|
@@ -259,7 +247,6 @@ export type DismissibleItemCreateManyInput = {
|
|
|
259
247
|
userId: string
|
|
260
248
|
createdAt?: Date | string
|
|
261
249
|
dismissedAt?: Date | string | null
|
|
262
|
-
metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue
|
|
263
250
|
}
|
|
264
251
|
|
|
265
252
|
export type DismissibleItemUpdateManyMutationInput = {
|
|
@@ -267,7 +254,6 @@ export type DismissibleItemUpdateManyMutationInput = {
|
|
|
267
254
|
userId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
268
255
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
269
256
|
dismissedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
|
270
|
-
metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue
|
|
271
257
|
}
|
|
272
258
|
|
|
273
259
|
export type DismissibleItemUncheckedUpdateManyInput = {
|
|
@@ -275,7 +261,6 @@ export type DismissibleItemUncheckedUpdateManyInput = {
|
|
|
275
261
|
userId?: Prisma.StringFieldUpdateOperationsInput | string
|
|
276
262
|
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
|
|
277
263
|
dismissedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
|
|
278
|
-
metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue
|
|
279
264
|
}
|
|
280
265
|
|
|
281
266
|
export type DismissibleItemUserIdIdCompoundUniqueInput = {
|
|
@@ -288,7 +273,6 @@ export type DismissibleItemCountOrderByAggregateInput = {
|
|
|
288
273
|
userId?: Prisma.SortOrder
|
|
289
274
|
createdAt?: Prisma.SortOrder
|
|
290
275
|
dismissedAt?: Prisma.SortOrder
|
|
291
|
-
metadata?: Prisma.SortOrder
|
|
292
276
|
}
|
|
293
277
|
|
|
294
278
|
export type DismissibleItemMaxOrderByAggregateInput = {
|
|
@@ -324,7 +308,6 @@ export type DismissibleItemSelect<ExtArgs extends runtime.Types.Extensions.Inter
|
|
|
324
308
|
userId?: boolean
|
|
325
309
|
createdAt?: boolean
|
|
326
310
|
dismissedAt?: boolean
|
|
327
|
-
metadata?: boolean
|
|
328
311
|
}, ExtArgs["result"]["dismissibleItem"]>
|
|
329
312
|
|
|
330
313
|
export type DismissibleItemSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
|
@@ -332,7 +315,6 @@ export type DismissibleItemSelectCreateManyAndReturn<ExtArgs extends runtime.Typ
|
|
|
332
315
|
userId?: boolean
|
|
333
316
|
createdAt?: boolean
|
|
334
317
|
dismissedAt?: boolean
|
|
335
|
-
metadata?: boolean
|
|
336
318
|
}, ExtArgs["result"]["dismissibleItem"]>
|
|
337
319
|
|
|
338
320
|
export type DismissibleItemSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
|
|
@@ -340,7 +322,6 @@ export type DismissibleItemSelectUpdateManyAndReturn<ExtArgs extends runtime.Typ
|
|
|
340
322
|
userId?: boolean
|
|
341
323
|
createdAt?: boolean
|
|
342
324
|
dismissedAt?: boolean
|
|
343
|
-
metadata?: boolean
|
|
344
325
|
}, ExtArgs["result"]["dismissibleItem"]>
|
|
345
326
|
|
|
346
327
|
export type DismissibleItemSelectScalar = {
|
|
@@ -348,10 +329,9 @@ export type DismissibleItemSelectScalar = {
|
|
|
348
329
|
userId?: boolean
|
|
349
330
|
createdAt?: boolean
|
|
350
331
|
dismissedAt?: boolean
|
|
351
|
-
metadata?: boolean
|
|
352
332
|
}
|
|
353
333
|
|
|
354
|
-
export type DismissibleItemOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "userId" | "createdAt" | "dismissedAt"
|
|
334
|
+
export type DismissibleItemOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "userId" | "createdAt" | "dismissedAt", ExtArgs["result"]["dismissibleItem"]>
|
|
355
335
|
|
|
356
336
|
export type $DismissibleItemPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
|
|
357
337
|
name: "DismissibleItem"
|
|
@@ -361,7 +341,6 @@ export type $DismissibleItemPayload<ExtArgs extends runtime.Types.Extensions.Int
|
|
|
361
341
|
userId: string
|
|
362
342
|
createdAt: Date
|
|
363
343
|
dismissedAt: Date | null
|
|
364
|
-
metadata: runtime.JsonValue | null
|
|
365
344
|
}, ExtArgs["result"]["dismissibleItem"]>
|
|
366
345
|
composites: {}
|
|
367
346
|
}
|
|
@@ -789,7 +768,6 @@ export interface DismissibleItemFieldRefs {
|
|
|
789
768
|
readonly userId: Prisma.FieldRef<"DismissibleItem", 'String'>
|
|
790
769
|
readonly createdAt: Prisma.FieldRef<"DismissibleItem", 'DateTime'>
|
|
791
770
|
readonly dismissedAt: Prisma.FieldRef<"DismissibleItem", 'DateTime'>
|
|
792
|
-
readonly metadata: Prisma.FieldRef<"DismissibleItem", 'Json'>
|
|
793
771
|
}
|
|
794
772
|
|
|
795
773
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
-- CreateTable
|
|
2
|
+
CREATE TABLE "dismissible_items" (
|
|
3
|
+
"id" TEXT NOT NULL,
|
|
4
|
+
"user_id" TEXT NOT NULL,
|
|
5
|
+
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
6
|
+
"dismissed_at" TIMESTAMP(3),
|
|
7
|
+
|
|
8
|
+
CONSTRAINT "dismissible_items_pkey" PRIMARY KEY ("user_id","id")
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
-- CreateIndex
|
|
12
|
+
CREATE INDEX "dismissible_items_user_id_idx" ON "dismissible_items"("user_id");
|
package/prisma/schema.prisma
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
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 ?? process.env.DISMISSIBLE_POSTGRES_STORAGE_CONNECTION_STRING ?? '',
|
|
32
|
+
},
|
|
33
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -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';
|
|
@@ -19,17 +18,14 @@ describe('PostgresStorageAdapter', () => {
|
|
|
19
18
|
beforeEach(() => {
|
|
20
19
|
mockLogger = mock<IDismissibleLogger>({ failIfMockNotProvided: false });
|
|
21
20
|
|
|
22
|
-
// Use real DismissibleItemFactory since it's a simple factory
|
|
23
21
|
mockItemFactory = new DismissibleItemFactory();
|
|
24
22
|
|
|
25
|
-
// Create a mock for the dismissibleItem delegate
|
|
26
23
|
mockDismissibleItem = {
|
|
27
24
|
findUnique: jest.fn(),
|
|
28
25
|
create: jest.fn(),
|
|
29
26
|
update: jest.fn(),
|
|
30
27
|
};
|
|
31
28
|
|
|
32
|
-
// Create a partial mock of PrismaService with the dismissibleItem property
|
|
33
29
|
mockPrismaService = {
|
|
34
30
|
dismissibleItem: mockDismissibleItem,
|
|
35
31
|
} as unknown as PrismaService;
|
|
@@ -64,7 +60,6 @@ describe('PostgresStorageAdapter', () => {
|
|
|
64
60
|
userId: 'user-123',
|
|
65
61
|
createdAt: new Date('2024-01-15T10:30:00.000Z'),
|
|
66
62
|
dismissedAt: null,
|
|
67
|
-
metadata: null,
|
|
68
63
|
};
|
|
69
64
|
mockDismissibleItem.findUnique.mockResolvedValue(dbItem);
|
|
70
65
|
|
|
@@ -75,34 +70,12 @@ describe('PostgresStorageAdapter', () => {
|
|
|
75
70
|
userId: 'user-123',
|
|
76
71
|
createdAt: new Date('2024-01-15T10:30:00.000Z'),
|
|
77
72
|
dismissedAt: undefined,
|
|
78
|
-
metadata: undefined,
|
|
79
73
|
});
|
|
80
74
|
expect(mockLogger.debug).toHaveBeenCalledWith('PostgreSQL storage hit', {
|
|
81
75
|
userId: 'user-123',
|
|
82
76
|
itemId: 'item-456',
|
|
83
77
|
});
|
|
84
78
|
});
|
|
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
79
|
});
|
|
107
80
|
|
|
108
81
|
describe('create', () => {
|
|
@@ -117,7 +90,6 @@ describe('PostgresStorageAdapter', () => {
|
|
|
117
90
|
userId: 'user-123',
|
|
118
91
|
createdAt: new Date('2024-01-15T10:30:00.000Z'),
|
|
119
92
|
dismissedAt: null,
|
|
120
|
-
metadata: null,
|
|
121
93
|
};
|
|
122
94
|
mockDismissibleItem.create.mockResolvedValue(dbItem);
|
|
123
95
|
|
|
@@ -128,7 +100,6 @@ describe('PostgresStorageAdapter', () => {
|
|
|
128
100
|
userId: 'user-123',
|
|
129
101
|
createdAt: new Date('2024-01-15T10:30:00.000Z'),
|
|
130
102
|
dismissedAt: undefined,
|
|
131
|
-
metadata: undefined,
|
|
132
103
|
});
|
|
133
104
|
expect(mockDismissibleItem.create).toHaveBeenCalledWith({
|
|
134
105
|
data: {
|
|
@@ -136,7 +107,6 @@ describe('PostgresStorageAdapter', () => {
|
|
|
136
107
|
userId: 'user-123',
|
|
137
108
|
createdAt: new Date('2024-01-15T10:30:00.000Z'),
|
|
138
109
|
dismissedAt: null,
|
|
139
|
-
metadata: Prisma.JsonNull,
|
|
140
110
|
},
|
|
141
111
|
});
|
|
142
112
|
expect(mockLogger.debug).toHaveBeenCalledWith('PostgreSQL storage create', {
|
|
@@ -144,33 +114,6 @@ describe('PostgresStorageAdapter', () => {
|
|
|
144
114
|
itemId: 'item-456',
|
|
145
115
|
});
|
|
146
116
|
});
|
|
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
117
|
});
|
|
175
118
|
|
|
176
119
|
describe('update', () => {
|
|
@@ -186,7 +129,6 @@ describe('PostgresStorageAdapter', () => {
|
|
|
186
129
|
userId: 'user-123',
|
|
187
130
|
createdAt: new Date('2024-01-15T10:30:00.000Z'),
|
|
188
131
|
dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
|
|
189
|
-
metadata: null,
|
|
190
132
|
};
|
|
191
133
|
mockDismissibleItem.update.mockResolvedValue(dbItem);
|
|
192
134
|
|
|
@@ -197,7 +139,6 @@ describe('PostgresStorageAdapter', () => {
|
|
|
197
139
|
userId: 'user-123',
|
|
198
140
|
createdAt: new Date('2024-01-15T10:30:00.000Z'),
|
|
199
141
|
dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
|
|
200
|
-
metadata: undefined,
|
|
201
142
|
});
|
|
202
143
|
expect(mockDismissibleItem.update).toHaveBeenCalledWith({
|
|
203
144
|
where: {
|
|
@@ -208,7 +149,6 @@ describe('PostgresStorageAdapter', () => {
|
|
|
208
149
|
},
|
|
209
150
|
data: {
|
|
210
151
|
dismissedAt: new Date('2024-01-15T12:00:00.000Z'),
|
|
211
|
-
metadata: Prisma.JsonNull,
|
|
212
152
|
},
|
|
213
153
|
});
|
|
214
154
|
expect(mockLogger.debug).toHaveBeenCalledWith('PostgreSQL storage update', {
|
|
@@ -216,33 +156,5 @@ describe('PostgresStorageAdapter', () => {
|
|
|
216
156
|
itemId: 'item-456',
|
|
217
157
|
});
|
|
218
158
|
});
|
|
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
159
|
});
|
|
248
160
|
});
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
-
|
|
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();
|