suparisma 0.0.1 → 0.0.3

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.
Files changed (38) hide show
  1. package/README.md +156 -3
  2. package/dist/config.js +12 -3
  3. package/dist/generators/coreGenerator.js +122 -40
  4. package/dist/generators/hookGenerator.js +16 -7
  5. package/dist/generators/indexGenerator.js +12 -7
  6. package/dist/generators/supabaseClientGenerator.js +5 -5
  7. package/dist/generators/typeGenerator.js +22 -22
  8. package/dist/index.js +103 -25
  9. package/{src/suparisma/generated/useSuparismaUser.ts → dist/suparisma/generated/hooks/useSuparismaUser.js} +19 -35
  10. package/dist/suparisma/generated/index.js +33 -0
  11. package/dist/suparisma/generated/types/UserTypes.js +4 -0
  12. package/dist/suparisma/generated/utils/core.js +1090 -0
  13. package/dist/suparisma/generated/utils/supabase-client.js +8 -0
  14. package/package.json +12 -2
  15. package/prisma/schema.prisma +19 -3
  16. package/tsconfig.json +1 -1
  17. package/src/config.ts +0 -7
  18. package/src/generated/hooks/useSuparismaUser.ts +0 -77
  19. package/src/generated/index.ts +0 -50
  20. package/src/generated/types/UserTypes.ts +0 -400
  21. package/src/generated/utils/core.ts +0 -1413
  22. package/src/generated/utils/supabase-client.ts +0 -7
  23. package/src/generators/coreGenerator.ts +0 -1426
  24. package/src/generators/hookGenerator.ts +0 -110
  25. package/src/generators/indexGenerator.ts +0 -117
  26. package/src/generators/supabaseClientGenerator.ts +0 -24
  27. package/src/generators/typeGenerator.ts +0 -587
  28. package/src/index.ts +0 -339
  29. package/src/parser.ts +0 -134
  30. package/src/suparisma/generated/UserTypes.ts +0 -400
  31. package/src/suparisma/generated/core.ts +0 -1413
  32. package/src/suparisma/generated/hooks/useSuparismaUser.ts +0 -77
  33. package/src/suparisma/generated/index.ts +0 -50
  34. package/src/suparisma/generated/supabase-client-generated.ts +0 -9
  35. package/src/suparisma/generated/types/UserTypes.ts +0 -400
  36. package/src/suparisma/generated/utils/core.ts +0 -1413
  37. package/src/suparisma/generated/utils/supabase-client.ts +0 -7
  38. package/src/types.ts +0 -57
@@ -1,587 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { OUTPUT_DIR } from '../config';
4
- import { ModelInfo, ProcessedModelInfo, SearchQuery, SearchState } from '../types';
5
-
6
- /**
7
- * Generate model-specific types for a model
8
- */
9
- export function generateModelTypesFile(model: ModelInfo): ProcessedModelInfo {
10
- const modelName = model.name || '';
11
- const tableName = model.mappedName || modelName;
12
-
13
- // Identify foreign key fields (these end with _id)
14
- const foreignKeyFields = model.fields
15
- .filter((field) => field.name.endsWith('_id') || field.name === 'userId')
16
- .map((field) => field.name);
17
-
18
- // Identify relation object fields (these are relation fields but not foreign keys)
19
- const relationObjectFields = model.fields
20
- .filter((field) => field.isRelation && !foreignKeyFields.includes(field.name))
21
- .map((field) => field.name);
22
-
23
- // Fields that have default values (should be optional in CreateInput)
24
- const defaultValueFields = model.fields
25
- .filter((field) => field.hasDefaultValue)
26
- .map((field) => field.name);
27
-
28
- // Timestamps should be excluded completely
29
- const autoTimestampFields = model.fields
30
- .filter((field) => field.isCreatedAt || field.isUpdatedAt)
31
- .map((field) => field.name);
32
-
33
- // Collect default values into a map (will be passed to the hook)
34
- const defaultValues: Record<string, string> = {};
35
- model.fields
36
- .filter((field) => field.hasDefaultValue && field.defaultValue !== undefined)
37
- .forEach((field) => {
38
- defaultValues[field.name] = field.defaultValue!;
39
- });
40
-
41
- // Extract searchable fields from annotations
42
- const searchFields = model.searchFields?.map((field) => field.name) || [];
43
-
44
- // Create a manual property list for WithRelations interface
45
- const withRelationsProps = model.fields
46
- .filter(
47
- (field) =>
48
- !relationObjectFields.includes(field.name) && !foreignKeyFields.includes(field.name)
49
- )
50
- .map((field) => {
51
- const isOptional = field.isOptional;
52
- const type =
53
- field.type === 'Int'
54
- ? 'number'
55
- : field.type === 'Float'
56
- ? 'number'
57
- : field.type === 'Boolean'
58
- ? 'boolean'
59
- : 'string';
60
- return ` ${field.name}${isOptional ? '?' : ''}: ${type};`;
61
- });
62
-
63
- // Add foreign key fields
64
- foreignKeyFields.forEach((field) => {
65
- const fieldInfo = model.fields.find((f) => f.name === field);
66
- if (fieldInfo) {
67
- withRelationsProps.push(
68
- ` ${field}${fieldInfo.isOptional ? '?' : ''}: ${fieldInfo.type === 'Int' ? 'number' : 'string'};`
69
- );
70
- }
71
- });
72
-
73
- // Create a manual property list for CreateInput
74
- const createInputProps = model.fields
75
- .filter(
76
- (field) =>
77
- !relationObjectFields.includes(field.name) &&
78
- !autoTimestampFields.includes(field.name) &&
79
- !foreignKeyFields.includes(field.name)
80
- )
81
- .map((field) => {
82
- // Make fields with default values optional in CreateInput
83
- const isOptional = field.isOptional || defaultValueFields.includes(field.name);
84
- const type =
85
- field.type === 'Int'
86
- ? 'number'
87
- : field.type === 'Float'
88
- ? 'number'
89
- : field.type === 'Boolean'
90
- ? 'boolean'
91
- : 'string';
92
- return ` ${field.name}${isOptional ? '?' : ''}: ${type};`;
93
- });
94
-
95
- // Add foreign key fields to CreateInput
96
- foreignKeyFields.forEach((field) => {
97
- const fieldInfo = model.fields.find((f) => f.name === field);
98
- if (fieldInfo) {
99
- // Make foreign key fields with default values optional
100
- const isOptional = fieldInfo.isOptional || defaultValueFields.includes(field);
101
- createInputProps.push(
102
- ` ${field}${isOptional ? '?' : ''}: ${fieldInfo.type === 'Int' ? 'number' : 'string'};`
103
- );
104
- }
105
- });
106
-
107
- // Generate the type content with TSDoc comments
108
- const typeContent = `// THIS FILE IS AUTO-GENERATED - DO NOT EDIT DIRECTLY
109
- // Edit the generator script instead
110
-
111
- import type { ${modelName} } from '@prisma/client';
112
- import type { ModelResult, SuparismaOptions, SearchQuery, SearchState } from './core';
113
-
114
- /**
115
- * Extended ${modelName} type that includes relation fields.
116
- * This represents the complete shape of ${modelName} records returned from the database.
117
- */
118
- export interface ${modelName}WithRelations {
119
- ${withRelationsProps.join('\n')}
120
- }
121
-
122
- /**
123
- * Input type for creating a new ${modelName} record.
124
- * Fields with default values are optional and will be filled automatically if not provided.
125
- *
126
- * @example
127
- * // Create a minimal ${modelName.toLowerCase()}
128
- * ${modelName.toLowerCase()}.create({
129
- * // Required fields only
130
- ${createInputProps
131
- .filter((p) => !p.includes('?'))
132
- .slice(0, 2)
133
- .map((p) => ' * ' + p.trim().replace(';', ','))
134
- .join('\n')}
135
- * });
136
- *
137
- * @example
138
- * // Create with optional fields
139
- * ${modelName.toLowerCase()}.create({
140
- * // All fields including optional ones
141
- ${createInputProps
142
- .slice(0, 3)
143
- .map((p) => ' * ' + p.trim().replace(';', ','))
144
- .join('\n')}
145
- * });
146
- */
147
- export interface ${modelName}CreateInput {
148
- ${createInputProps.join('\n')}
149
- }
150
-
151
- /**
152
- * Input type for updating an existing ${modelName} record.
153
- * All fields are optional since you only need to specify the fields you want to change.
154
- *
155
- * @example
156
- * // Update a ${modelName.toLowerCase()}'s fields
157
- * ${modelName.toLowerCase()}.update({
158
- * where: { id: "123" },
159
- * data: {
160
- ${createInputProps
161
- .slice(0, 2)
162
- .map((p) => ' * ' + p.trim().replace(';', ','))
163
- .join('\n')}
164
- * }
165
- * });
166
- */
167
- export type ${modelName}UpdateInput = Partial<${modelName}CreateInput>;
168
-
169
- /**
170
- * Filter type for querying ${modelName} records.
171
- * You can filter by any field in the model using equality or advanced filter operators.
172
- *
173
- * @example
174
- * // Basic filtering
175
- * ${modelName.toLowerCase()}.findMany({
176
- * where: {
177
- ${withRelationsProps
178
- .slice(0, 2)
179
- .map((p) => {
180
- const field = p.trim().split(':')[0].trim();
181
- return ` * ${field}: "value"`;
182
- })
183
- .join(',\n')}
184
- * }
185
- * });
186
- *
187
- * @example
188
- * // Advanced filtering
189
- * ${modelName.toLowerCase()}.findMany({
190
- * where: {
191
- * // Use advanced operators
192
- ${withRelationsProps
193
- .slice(0, 1)
194
- .map((p) => {
195
- const field = p.trim().split(':')[0].trim();
196
- return ` * ${field}: { contains: "partial" }`;
197
- })
198
- .join(',\n')}
199
- * }
200
- * });
201
- */
202
- export type ${modelName}WhereInput = Partial<${modelName}WithRelations>;
203
-
204
- /**
205
- * Unique identifier for finding a specific ${modelName} record.
206
- * Usually uses the ID field but can be any field marked as @unique in the schema.
207
- *
208
- * @example
209
- * // Find by ID
210
- * ${modelName.toLowerCase()}.findUnique({ id: "123" });
211
- *
212
- * @example
213
- * // Delete by ID
214
- * ${modelName.toLowerCase()}.delete({ id: "123" });
215
- */
216
- export type ${modelName}WhereUniqueInput = {
217
- ${model.fields
218
- .filter((field) => field.isId)
219
- .map((field) => {
220
- return `${field.name}${field.isOptional ? '?' : ''}: ${field.type === 'Int' ? 'number' : 'string'};`;
221
- })
222
- .join('\n ')}
223
- };
224
-
225
- /**
226
- * Sort options for ${modelName} queries.
227
- * Specify the field to sort by and the direction ('asc' or 'desc').
228
- *
229
- * @example
230
- * // Sort by creation date, newest first
231
- * ${modelName.toLowerCase()}.findMany({
232
- * orderBy: { created_at: 'desc' }
233
- * });
234
- *
235
- * @example
236
- * // Sort alphabetically
237
- * ${modelName.toLowerCase()}.findMany({
238
- * orderBy: { name: 'asc' }
239
- * });
240
- */
241
- export type ${modelName}OrderByInput = {
242
- [key in keyof ${modelName}WithRelations]?: 'asc' | 'desc';
243
- };
244
-
245
- /**
246
- * Result type for operations that return a single ${modelName} record.
247
- */
248
- export type ${modelName}SingleResult = ModelResult<${modelName}WithRelations>;
249
-
250
- /**
251
- * Result type for operations that return multiple ${modelName} records.
252
- */
253
- export type ${modelName}ManyResult = ModelResult<${modelName}WithRelations[]>;
254
-
255
- /**
256
- * Configuration options for the ${modelName} hook.
257
- */
258
- export type Use${modelName}Options = SuparismaOptions<${modelName}WhereInput, ${modelName}OrderByInput>;
259
-
260
- /**
261
- * The complete API for interacting with ${modelName} records.
262
- * This interface defines all available operations and state properties.
263
- */
264
- export interface ${modelName}HookApi {
265
- /**
266
- * Current array of ${modelName} records.
267
- * This is automatically updated when:
268
- * - The initial data is loaded
269
- * - Mutations are performed (create, update, delete)
270
- * - Real-time updates are received from other clients
271
- * - The refresh method is called
272
- *
273
- * @example
274
- * // Render a list of ${modelName.toLowerCase()} records
275
- * const { data } = ${modelName.toLowerCase()};
276
- * return (
277
- * <ul>
278
- * {data.map(item => (
279
- * <li key={item.id}>{item.name}</li>
280
- * ))}
281
- * </ul>
282
- * );
283
- */
284
- data: ${modelName}WithRelations[];
285
-
286
- /**
287
- * Error object if the last operation failed, null otherwise.
288
- *
289
- * @example
290
- * // Handle potential errors
291
- * const { error } = ${modelName.toLowerCase()};
292
- * if (error) {
293
- * return <div>Error: {error.message}</div>;
294
- * }
295
- */
296
- error: Error | null;
297
-
298
- /**
299
- * Boolean indicating if an operation is in progress.
300
- *
301
- * @example
302
- * // Show loading state
303
- * const { loading } = ${modelName.toLowerCase()};
304
- * if (loading) {
305
- * return <div>Loading...</div>;
306
- * }
307
- */
308
- loading: boolean;
309
-
310
- ${
311
- searchFields.length > 0
312
- ? `/**
313
- * Search functionality for ${modelName} records.
314
- * Only available for models with @enableSearch fields.
315
- *
316
- * @example
317
- * // Search for records containing a term
318
- * ${modelName.toLowerCase()}.search.addQuery({ field: "name", value: "smith" });
319
- *
320
- * @example
321
- * // Clear search and return to normal data
322
- * ${modelName.toLowerCase()}.search.clearQueries();
323
- */
324
- search: SearchState;`
325
- : ''
326
- }
327
-
328
- /**
329
- * Find a single ${modelName} record by its unique identifier.
330
- *
331
- * @param where - The unique identifier to find the record by
332
- * @returns A promise with the found record or error
333
- *
334
- * @example
335
- * // Find ${modelName.toLowerCase()} by ID
336
- * const result = await ${modelName.toLowerCase()}.findUnique({ id: "123" });
337
- * if (result.data) {
338
- * console.log("Found ${modelName.toLowerCase()}:", result.data);
339
- * }
340
- */
341
- findUnique: (where: ${modelName}WhereUniqueInput) => ${modelName}SingleResult;
342
-
343
- /**
344
- * Find multiple ${modelName} records matching the filter criteria.
345
- * Supports filtering, sorting, and pagination.
346
- *
347
- * @param params - Optional query parameters
348
- * @returns A promise with the matching records or error
349
- *
350
- * @example
351
- * // Get all ${modelName.toLowerCase()} records
352
- * const result = await ${modelName.toLowerCase()}.findMany();
353
- *
354
- * @example
355
- * // Filter and sort records
356
- * const result = await ${modelName.toLowerCase()}.findMany({
357
- * where: { active: true },
358
- * orderBy: { created_at: 'desc' },
359
- * take: 10,
360
- * skip: 0
361
- * });
362
- */
363
- findMany: (params?: {
364
- where?: ${modelName}WhereInput;
365
- orderBy?: ${modelName}OrderByInput;
366
- take?: number;
367
- skip?: number;
368
- }) => ${modelName}ManyResult;
369
-
370
- /**
371
- * Find the first ${modelName} record matching the filter criteria.
372
- *
373
- * @param params - Optional query parameters
374
- * @returns A promise with the first matching record or error
375
- *
376
- * @example
377
- * // Find the first active ${modelName.toLowerCase()}
378
- * const result = await ${modelName.toLowerCase()}.findFirst({
379
- * where: { active: true }
380
- * });
381
- *
382
- * @example
383
- * // Find the oldest ${modelName.toLowerCase()}
384
- * const result = await ${modelName.toLowerCase()}.findFirst({
385
- * orderBy: { created_at: 'asc' }
386
- * });
387
- */
388
- findFirst: (params?: {
389
- where?: ${modelName}WhereInput;
390
- orderBy?: ${modelName}OrderByInput;
391
- }) => ${modelName}SingleResult;
392
-
393
- /**
394
- * Create a new ${modelName} record.
395
- * Fields with default values are optional and will use their defaults if not provided.
396
- *
397
- * @param data - The data for the new record
398
- * @returns A promise with the created record or error
399
- *
400
- * @example
401
- * // Create a new ${modelName.toLowerCase()}
402
- * const result = await ${modelName.toLowerCase()}.create({
403
- ${createInputProps
404
- .filter((p) => !p.includes('?'))
405
- .slice(0, 2)
406
- .map((p) => {
407
- const field = p.trim().split(':')[0].trim();
408
- const type = p.includes('number') ? 42 : p.includes('boolean') ? 'true' : '"value"';
409
- return ` * ${field}: ${type}`;
410
- })
411
- .join(',\n')}
412
- * });
413
- *
414
- * @example
415
- * // Create with custom ID (overriding default)
416
- * const result = await ${modelName.toLowerCase()}.create({
417
- * id: "custom-id",
418
- ${createInputProps
419
- .filter((p) => !p.includes('?'))
420
- .slice(0, 1)
421
- .map((p) => {
422
- const field = p.trim().split(':')[0].trim();
423
- if (field === 'id') return '';
424
- const type = p.includes('number') ? 42 : p.includes('boolean') ? 'true' : '"value"';
425
- return ` * ${field}: ${type}`;
426
- })
427
- .join(',\n')}
428
- * });
429
- */
430
- create: (data: ${modelName}CreateInput) => ${modelName}SingleResult;
431
-
432
- /**
433
- * Update an existing ${modelName} record.
434
- *
435
- * @param params - Object with the record identifier and fields to update
436
- * @returns A promise with the updated record or error
437
- *
438
- * @example
439
- * // Update a ${modelName.toLowerCase()}'s fields
440
- * const result = await ${modelName.toLowerCase()}.update({
441
- * where: { id: "123" },
442
- * data: {
443
- ${createInputProps
444
- .slice(0, 2)
445
- .map((p) => {
446
- const field = p.trim().split(':')[0].trim();
447
- if (field === 'id') return '';
448
- const type = p.includes('number') ? 42 : p.includes('boolean') ? 'true' : '"updated value"';
449
- return ` * ${field}: ${type}`;
450
- })
451
- .filter(Boolean)
452
- .join(',\n')}
453
- * }
454
- * });
455
- */
456
- update: (params: {
457
- where: ${modelName}WhereUniqueInput;
458
- data: ${modelName}UpdateInput;
459
- }) => ${modelName}SingleResult;
460
-
461
- /**
462
- * Delete a ${modelName} record by its unique identifier.
463
- *
464
- * @param where - The unique identifier of the record to delete
465
- * @returns A promise with the deleted record or error
466
- *
467
- * @example
468
- * // Delete a ${modelName.toLowerCase()} by ID
469
- * const result = await ${modelName.toLowerCase()}.delete({ id: "123" });
470
- * if (result.data) {
471
- * console.log("Deleted ${modelName.toLowerCase()}:", result.data);
472
- * }
473
- */
474
- delete: (where: ${modelName}WhereUniqueInput) => ${modelName}SingleResult;
475
-
476
- /**
477
- * Delete multiple ${modelName} records matching the filter criteria.
478
- *
479
- * @param params - Optional filter parameters
480
- * @returns A promise with the count of deleted records or error
481
- *
482
- * @example
483
- * // Delete all inactive ${modelName.toLowerCase()} records
484
- * const result = await ${modelName.toLowerCase()}.deleteMany({
485
- * where: { active: false }
486
- * });
487
- * console.log(\`Deleted \${result.count} records\`);
488
- *
489
- * @example
490
- * // Delete all ${modelName.toLowerCase()} records (use with caution!)
491
- * const result = await ${modelName.toLowerCase()}.deleteMany();
492
- */
493
- deleteMany: (params?: {
494
- where?: ${modelName}WhereInput;
495
- }) => Promise<{ count: number; error: Error | null }>;
496
-
497
- /**
498
- * Create a record if it doesn't exist, or update it if it does.
499
- *
500
- * @param params - Object with the identifier, update data, and create data
501
- * @returns A promise with the created or updated record or error
502
- *
503
- * @example
504
- * // Upsert a ${modelName.toLowerCase()} by ID
505
- * const result = await ${modelName.toLowerCase()}.upsert({
506
- * where: { id: "123" },
507
- * update: { name: "Updated Name" },
508
- * create: {
509
- * id: "123",
510
- * name: "New Name"${createInputProps.filter((p) => !p.includes('?') && !p.includes('id') && !p.includes('name')).length > 0 ? ',' : ''}
511
- ${createInputProps
512
- .filter((p) => !p.includes('?') && !p.includes('id') && !p.includes('name'))
513
- .slice(0, 1)
514
- .map((p) => {
515
- const field = p.trim().split(':')[0].trim();
516
- const type = p.includes('number') ? 42 : p.includes('boolean') ? 'true' : '"value"';
517
- return ` * ${field}: ${type}`;
518
- })
519
- .join(',\n')}
520
- * }
521
- * });
522
- */
523
- upsert: (params: {
524
- where: ${modelName}WhereUniqueInput;
525
- update: ${modelName}UpdateInput;
526
- create: ${modelName}CreateInput;
527
- }) => ${modelName}SingleResult;
528
-
529
- /**
530
- * Count the number of ${modelName} records matching the filter criteria.
531
- *
532
- * @param params - Optional filter parameters
533
- * @returns A promise with the count of matching records
534
- *
535
- * @example
536
- * // Count all ${modelName.toLowerCase()} records
537
- * const count = await ${modelName.toLowerCase()}.count();
538
- *
539
- * @example
540
- * // Count active ${modelName.toLowerCase()} records
541
- * const activeCount = await ${modelName.toLowerCase()}.count({
542
- * where: { active: true }
543
- * });
544
- */
545
- count: (params?: {
546
- where?: ${modelName}WhereInput;
547
- }) => Promise<number>;
548
-
549
- /**
550
- * Manually refresh the data with current filter settings.
551
- * Useful after external operations or when realtime is disabled.
552
- *
553
- * @param params - Optional override parameters for this specific refresh
554
- * @returns A promise with the refreshed data or error
555
- *
556
- * @example
557
- * // Refresh with current filter settings
558
- * await ${modelName.toLowerCase()}.refresh();
559
- *
560
- * @example
561
- * // Refresh with different filters for this call only
562
- * await ${modelName.toLowerCase()}.refresh({
563
- * where: { active: true },
564
- * orderBy: { name: 'asc' }
565
- * });
566
- */
567
- refresh: (params?: {
568
- where?: ${modelName}WhereInput;
569
- orderBy?: ${modelName}OrderByInput;
570
- take?: number;
571
- skip?: number;
572
- }) => ${modelName}ManyResult;
573
- }`;
574
-
575
- const outputPath = path.join(OUTPUT_DIR, `${modelName}Types.ts`);
576
- fs.writeFileSync(outputPath, typeContent);
577
- console.log(`Generated type definitions for ${modelName} at ${outputPath}`);
578
-
579
- return {
580
- modelName,
581
- tableName,
582
- hasCreatedAt: model.fields.some((field) => field.isCreatedAt),
583
- hasUpdatedAt: model.fields.some((field) => field.isUpdatedAt),
584
- searchFields,
585
- defaultValues: Object.keys(defaultValues).length > 0 ? defaultValues : undefined,
586
- };
587
- }