suparisma 0.0.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.
Files changed (43) hide show
  1. package/.gitattributes +2 -0
  2. package/LICENSE +21 -0
  3. package/README.md +4 -0
  4. package/dist/config.js +7 -0
  5. package/dist/generated/supabase-client-generated.js +7 -0
  6. package/dist/generators/coreGenerator.js +1430 -0
  7. package/dist/generators/hookGenerator.js +108 -0
  8. package/dist/generators/indexGenerator.js +100 -0
  9. package/dist/generators/supabaseClientGenerator.js +29 -0
  10. package/dist/generators/typeGenerator.js +566 -0
  11. package/dist/hooks/generated/UserTypes.js +2 -0
  12. package/dist/hooks/generated/core.js +1089 -0
  13. package/dist/hooks/generated/index.js +33 -0
  14. package/dist/hooks/generated/useSuparismaUser.js +60 -0
  15. package/dist/index.js +259 -0
  16. package/dist/parser.js +117 -0
  17. package/dist/types.js +2 -0
  18. package/package.json +28 -0
  19. package/prisma/schema.prisma +22 -0
  20. package/src/config.ts +7 -0
  21. package/src/generated/hooks/useSuparismaUser.ts +77 -0
  22. package/src/generated/index.ts +50 -0
  23. package/src/generated/types/UserTypes.ts +400 -0
  24. package/src/generated/utils/core.ts +1413 -0
  25. package/src/generated/utils/supabase-client.ts +7 -0
  26. package/src/generators/coreGenerator.ts +1426 -0
  27. package/src/generators/hookGenerator.ts +110 -0
  28. package/src/generators/indexGenerator.ts +117 -0
  29. package/src/generators/supabaseClientGenerator.ts +24 -0
  30. package/src/generators/typeGenerator.ts +587 -0
  31. package/src/index.ts +339 -0
  32. package/src/parser.ts +134 -0
  33. package/src/suparisma/generated/UserTypes.ts +400 -0
  34. package/src/suparisma/generated/core.ts +1413 -0
  35. package/src/suparisma/generated/hooks/useSuparismaUser.ts +77 -0
  36. package/src/suparisma/generated/index.ts +50 -0
  37. package/src/suparisma/generated/supabase-client-generated.ts +9 -0
  38. package/src/suparisma/generated/types/UserTypes.ts +400 -0
  39. package/src/suparisma/generated/useSuparismaUser.ts +77 -0
  40. package/src/suparisma/generated/utils/core.ts +1413 -0
  41. package/src/suparisma/generated/utils/supabase-client.ts +7 -0
  42. package/src/types.ts +57 -0
  43. package/tsconfig.json +20 -0
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ // THIS FILE IS AUTO-GENERATED - DO NOT EDIT DIRECTLY
3
+ // Edit the generator script instead: scripts/generate-realtime-hooks.ts
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ const useSuparismaUser_1 = require("./useSuparismaUser");
6
+ /**
7
+ * Main Suparisma hook object with dot notation access to all model hooks.
8
+ *
9
+ * @example
10
+ * // Get hooks for different models
11
+ * import useSuparisma from './hooks/generated';
12
+ *
13
+ * // Access user model with all hook methods
14
+ * const users = useSuparisma.user();
15
+ * const { data, loading, error } = users;
16
+ *
17
+ * // Create a new record
18
+ * await users.create({ name: "John" });
19
+ *
20
+ * // Delete a record
21
+ * await users.delete({ id: "123" });
22
+ *
23
+ * @example
24
+ * // Use with filtering and options
25
+ * const admins = useSuparisma.user({
26
+ * where: { role: 'admin' },
27
+ * orderBy: { created_at: 'desc' }
28
+ * });
29
+ */
30
+ const useSuparisma = {
31
+ user: useSuparismaUser_1.useSuparismaUser,
32
+ };
33
+ exports.default = useSuparisma;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ // THIS FILE IS AUTO-GENERATED - DO NOT EDIT DIRECTLY
3
+ // Edit the generator script instead: scripts/generate-realtime-hooks.ts
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.useSuparismaUser = void 0;
6
+ const core_1 = require("./core");
7
+ /**
8
+ * A Prisma-like hook for interacting with User records with real-time capabilities.
9
+ *
10
+ * This hook provides CRUD operations, real-time updates, and search functionality.
11
+ *
12
+ * @param options - Optional configuration options for the hook
13
+ * @returns An object with data state and methods for interacting with User records
14
+ *
15
+ * @example
16
+ * // Basic usage - get all User records with realtime updates
17
+ * const user = useSuparismaUser();
18
+ * const { data, loading, error } = user;
19
+ *
20
+ * @example
21
+ * // With filtering and ordering
22
+ * const user = useSuparismaUser({
23
+ * where: { active: true },
24
+ * orderBy: { created_at: 'desc' },
25
+ * limit: 10
26
+ * });
27
+ *
28
+ * @example
29
+ * // Create a new record
30
+ * const result = await user.create({
31
+ * name: "Example Name",
32
+ * // other fields...
33
+ * });
34
+ *
35
+ * @example
36
+ * // Update a record
37
+ * const result = await user.update({
38
+ * where: { id: "123" },
39
+ * data: { name: "Updated Name" }
40
+ * });
41
+ *
42
+ * @example
43
+ * // Delete a record
44
+ * const result = await user.delete({ id: "123" });
45
+ *
46
+ * @example
47
+ * // Find records with specific criteria
48
+ * const result = await user.findMany({
49
+ * where: { // filters },
50
+ * orderBy: { // ordering },
51
+ * take: 20 // limit
52
+ * });
53
+ */
54
+ exports.useSuparismaUser = (0, core_1.createSuparismaHook)({
55
+ tableName: 'User',
56
+ hasCreatedAt: true,
57
+ hasUpdatedAt: true,
58
+ // Default values from schema
59
+ defaultValues: { "id": "uuid(", "createdAt": "now(" }
60
+ });
package/dist/index.js ADDED
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || function (mod) {
20
+ if (mod && mod.__esModule) return mod;
21
+ var result = {};
22
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
+ __setModuleDefault(result, mod);
24
+ return result;
25
+ };
26
+ var __importDefault = (this && this.__importDefault) || function (mod) {
27
+ return (mod && mod.__esModule) ? mod : { "default": mod };
28
+ };
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ const fs_1 = __importDefault(require("fs"));
31
+ const dotenv = __importStar(require("dotenv"));
32
+ dotenv.config();
33
+ // Import configuration
34
+ const config_1 = require("./config");
35
+ // Import parsers and generators
36
+ const parser_1 = require("./parser");
37
+ const coreGenerator_1 = require("./generators/coreGenerator");
38
+ const typeGenerator_1 = require("./generators/typeGenerator");
39
+ const hookGenerator_1 = require("./generators/hookGenerator");
40
+ const indexGenerator_1 = require("./generators/indexGenerator");
41
+ const supabaseClientGenerator_1 = require("./generators/supabaseClientGenerator");
42
+ function analyzePrismaSchema(schemaPath) {
43
+ try {
44
+ const schemaContent = fs_1.default.readFileSync(schemaPath, 'utf8');
45
+ const modelInfos = [];
46
+ // Regular expression to match model definitions with comments
47
+ const modelRegex = /(?:\/\/\s*@enableRealtime\s*)?\s*model\s+(\w+)\s*{([\s\S]*?)}/g;
48
+ let modelMatch;
49
+ while ((modelMatch = modelRegex.exec(schemaContent)) !== null) {
50
+ const modelName = modelMatch[1];
51
+ const modelBody = modelMatch[2];
52
+ if (!modelName || !modelBody) {
53
+ console.error('Model name or body not found');
54
+ continue;
55
+ }
56
+ const tableName = modelMatch[0].includes('@map')
57
+ ? modelMatch[0].match(/@map\s*\(\s*["'](.+?)["']\s*\)/)?.at(1) || modelName
58
+ : modelName;
59
+ // Check if model has @enableRealtime comment
60
+ const enableRealtime = modelMatch[0].includes('// @enableRealtime');
61
+ // Find fields with @enableSearch comment
62
+ const searchFields = [];
63
+ const fieldRegex = /(\w+)\s+(\w+)(?:\?.+?)?\s+(?:@.+?)?\s*(?:\/\/\s*@enableSearch)?/g;
64
+ let fieldMatch;
65
+ while ((fieldMatch = fieldRegex.exec(modelBody)) !== null) {
66
+ if (fieldMatch[0].includes('// @enableSearch')) {
67
+ searchFields.push({
68
+ name: fieldMatch[1] || '',
69
+ type: fieldMatch[2] || '',
70
+ });
71
+ }
72
+ }
73
+ modelInfos.push({
74
+ name: modelName,
75
+ tableName,
76
+ enableRealtime,
77
+ searchFields,
78
+ });
79
+ }
80
+ return modelInfos;
81
+ }
82
+ catch (error) {
83
+ console.error('Error analyzing Prisma schema:', error);
84
+ return [];
85
+ }
86
+ }
87
+ /**
88
+ * Configure database tables for proper realtime functionality and search
89
+ * 1. Sets REPLICA IDENTITY FULL and enables realtime for models with @enableRealtime
90
+ * 2. Creates search functions for fields with @enableSearch
91
+ */
92
+ async function configurePrismaTablesForSuparisma(schemaPath) {
93
+ try {
94
+ // COMPLETELY BYPASS NORMAL OPERATION FOR SIMPLICITY
95
+ console.log('🔧 Using direct SQL approach to avoid PostgreSQL case sensitivity issues...');
96
+ // Load environment variables
97
+ dotenv.config();
98
+ // Get direct PostgreSQL connection URL
99
+ const directUrl = process.env.DIRECT_URL;
100
+ if (!directUrl) {
101
+ console.warn('⚠️ DIRECT_URL environment variable not found. Skipping database configuration.');
102
+ return;
103
+ }
104
+ // Analyze Prisma schema for models, realtime and search annotations
105
+ const modelInfos = analyzePrismaSchema(schemaPath);
106
+ // Dynamically import pg package
107
+ const pg = await Promise.resolve().then(() => __importStar(require('pg')));
108
+ const { Pool } = pg.default || pg;
109
+ // Connect to PostgreSQL database
110
+ const pool = new Pool({ connectionString: directUrl });
111
+ console.log('🔌 Connected to PostgreSQL database');
112
+ // Get all tables from database directly
113
+ const { rows: allTables } = await pool.query(`
114
+ SELECT table_name
115
+ FROM information_schema.tables
116
+ WHERE table_schema = 'public'
117
+ `);
118
+ console.log(`📋 Found ${allTables.length} tables in the 'public' schema`);
119
+ allTables.forEach((t) => console.log(` - ${t.table_name}`));
120
+ // DIRECT APPROACH: Hardcode SQL for each known Prisma model type
121
+ for (const model of modelInfos) {
122
+ try {
123
+ // Find the matching table regardless of case
124
+ const matchingTable = allTables.find((t) => t.table_name.toLowerCase() === model.tableName.toLowerCase());
125
+ if (!matchingTable) {
126
+ console.warn(`⚠️ Could not find a table for model ${model.name}. Skipping.`);
127
+ continue;
128
+ }
129
+ // Use the exact case of the table as it exists in the database
130
+ const actualTableName = matchingTable.table_name;
131
+ console.log(`🔍 Model ${model.name} -> Actual table: ${actualTableName}`);
132
+ if (model.enableRealtime) {
133
+ // Explicitly use double quotes for mixed case identifiers
134
+ // try {
135
+ // await pool.query(`ALTER TABLE "${actualTableName}" REPLICA IDENTITY FULL;`);
136
+ // console.log(`✅ Set REPLICA IDENTITY FULL on "${actualTableName}"`);
137
+ // } catch (err: any ) {
138
+ // console.error(`❌ Failed to set REPLICA IDENTITY on "${actualTableName}": ${err.message}`);
139
+ // }
140
+ // Directly add the table to Supabase Realtime publication
141
+ try {
142
+ await pool.query(`
143
+ ALTER PUBLICATION supabase_realtime ADD TABLE "${actualTableName}";
144
+ `);
145
+ console.log(`✅ Added "${actualTableName}" to supabase_realtime publication`);
146
+ }
147
+ catch (err) {
148
+ // If error contains "already exists", this is fine
149
+ if (err.message.includes('already member')) {
150
+ console.log(`ℹ️ Table "${actualTableName}" was already in supabase_realtime publication`);
151
+ }
152
+ else {
153
+ console.error(`❌ Failed to add "${actualTableName}" to supabase_realtime: ${err.message}`);
154
+ }
155
+ }
156
+ }
157
+ // Handle search fields if any
158
+ if (model.searchFields.length > 0) {
159
+ // Get all columns for this table
160
+ const { rows: columns } = await pool.query(`
161
+ SELECT column_name
162
+ FROM information_schema.columns
163
+ WHERE table_schema = 'public' AND table_name = $1
164
+ `, [actualTableName]);
165
+ for (const searchField of model.searchFields) {
166
+ // Find matching column regardless of case
167
+ const matchingColumn = columns.find((c) => c.column_name.toLowerCase() === searchField.name.toLowerCase());
168
+ if (!matchingColumn) {
169
+ console.warn(`⚠️ Could not find column ${searchField.name} in table ${actualTableName}. Skipping search function.`);
170
+ continue;
171
+ }
172
+ const actualColumnName = matchingColumn.column_name;
173
+ const functionName = `search_${actualTableName.toLowerCase()}_by_${actualColumnName.toLowerCase()}_prefix`;
174
+ const indexName = `idx_search_${actualTableName.toLowerCase()}_${actualColumnName.toLowerCase()}`;
175
+ try {
176
+ // Create search function with exact column case
177
+ await pool.query(`
178
+ CREATE OR REPLACE FUNCTION "public"."${functionName}"(prefix text)
179
+ RETURNS SETOF "public"."${actualTableName}" AS $$
180
+ BEGIN
181
+ RETURN QUERY
182
+ SELECT * FROM "public"."${actualTableName}"
183
+ WHERE to_tsvector('english', "${actualColumnName}") @@ to_tsquery('english', prefix || ':*');
184
+ END;
185
+ $$ LANGUAGE plpgsql;
186
+ `);
187
+ console.log(`✅ Created search function for ${actualTableName}.${actualColumnName}`);
188
+ // FIXED: Properly quote identifiers in the index creation query
189
+ await pool.query(`
190
+ DO $$
191
+ BEGIN
192
+ IF NOT EXISTS (
193
+ SELECT 1 FROM pg_indexes
194
+ WHERE schemaname = 'public'
195
+ AND tablename = '${actualTableName}'
196
+ AND indexname = '${indexName}'
197
+ ) THEN
198
+ CREATE INDEX "${indexName}" ON "public"."${actualTableName}"
199
+ USING GIN (to_tsvector('english', "${actualColumnName}"));
200
+ END IF;
201
+ END;
202
+ $$;
203
+ `);
204
+ console.log(`✅ Created search index for ${actualTableName}.${actualColumnName}`);
205
+ }
206
+ catch (err) {
207
+ console.error(`❌ Failed to set up search for "${actualTableName}.${actualColumnName}": ${err.message}`);
208
+ }
209
+ }
210
+ }
211
+ }
212
+ catch (err) {
213
+ console.error(`❌ Error processing model ${model.name}: ${err.message}`);
214
+ }
215
+ }
216
+ await pool.end();
217
+ console.log('🎉 Database configuration complete');
218
+ }
219
+ catch (err) {
220
+ console.error('❌ Error configuring database:', err);
221
+ console.log('⚠️ Continuing with hook generation anyway...');
222
+ }
223
+ }
224
+ /**
225
+ * Main execution function
226
+ */
227
+ async function main() {
228
+ try {
229
+ console.log('Generating Supabase realtime hooks with improved architecture...');
230
+ // Ensure output directory exists
231
+ if (!fs_1.default.existsSync(config_1.OUTPUT_DIR)) {
232
+ fs_1.default.mkdirSync(config_1.OUTPUT_DIR, { recursive: true });
233
+ }
234
+ // Generate Supabase client file first
235
+ (0, supabaseClientGenerator_1.generateSupabaseClientFile)();
236
+ // First, generate the core hook factory
237
+ (0, coreGenerator_1.generateCoreFile)();
238
+ // Parse models from Prisma schema
239
+ const models = (0, parser_1.parsePrismaSchema)(config_1.PRISMA_SCHEMA_PATH);
240
+ // Configure database tables for real-time and search functionality
241
+ await configurePrismaTablesForSuparisma(config_1.PRISMA_SCHEMA_PATH);
242
+ // Generate type definitions and hooks for each model
243
+ const modelInfos = [];
244
+ for (const model of models) {
245
+ const modelInfo = (0, typeGenerator_1.generateModelTypesFile)(model);
246
+ (0, hookGenerator_1.generateModelHookFile)(modelInfo);
247
+ modelInfos.push(modelInfo);
248
+ }
249
+ // Generate the main module file
250
+ (0, indexGenerator_1.generateMainIndexFile)(modelInfos);
251
+ console.log('✅ Successfully generated all suparisma hooks!');
252
+ }
253
+ catch (error) {
254
+ console.error('❌ Error generating hooks:', error);
255
+ process.exit(1);
256
+ }
257
+ }
258
+ // Execute main function
259
+ main();
package/dist/parser.js ADDED
@@ -0,0 +1,117 @@
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
+ exports.parsePrismaSchema = parsePrismaSchema;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ /**
9
+ * Parse Prisma schema to extract model information including search annotations
10
+ */
11
+ function parsePrismaSchema(schemaPath) {
12
+ const schema = fs_1.default.readFileSync(schemaPath, 'utf-8');
13
+ const modelRegex = /model\s+(\w+)\s+{([^}]*)}/gs;
14
+ const models = [];
15
+ let match;
16
+ while ((match = modelRegex.exec(schema)) !== null) {
17
+ const modelName = match[1] || '';
18
+ const modelBody = match[2] || '';
19
+ // Extract custom table name if provided with @@map
20
+ const mapMatch = modelBody.match(/@@map\("([^"]+)"\)/);
21
+ const mappedName = mapMatch ? mapMatch[1] : modelName;
22
+ // Extract field info
23
+ const fields = [];
24
+ // Track fields with @enableSearch annotation
25
+ const searchFields = [];
26
+ const lines = modelBody.split('\n');
27
+ let lastFieldName = '';
28
+ let lastFieldType = '';
29
+ for (let i = 0; i < lines.length; i++) {
30
+ const line = lines[i]?.trim();
31
+ // Skip blank lines and non-field lines
32
+ if (!line || line.startsWith('@@')) {
33
+ continue;
34
+ }
35
+ // Check for standalone @enableSearch comment
36
+ if (line === '// @enableSearch' && lastFieldName) {
37
+ searchFields.push({
38
+ name: lastFieldName,
39
+ type: lastFieldType,
40
+ });
41
+ continue;
42
+ }
43
+ // Check if line is a comment
44
+ if (line.startsWith('//')) {
45
+ continue;
46
+ }
47
+ // Parse field definition
48
+ const fieldMatch = line.match(/\s*(\w+)\s+(\w+)(\?)?\s*(?:@[^)]+)?/);
49
+ if (fieldMatch) {
50
+ const fieldName = fieldMatch[1];
51
+ const fieldType = fieldMatch[2];
52
+ const isOptional = !!fieldMatch[3]; // ? makes it optional
53
+ // Store for potential standalone @enableSearch comment
54
+ lastFieldName = fieldName || '';
55
+ lastFieldType = fieldType || '';
56
+ // Detect special fields
57
+ const isId = line.includes('@id');
58
+ const isCreatedAt = fieldName === 'created_at' || fieldName === 'createdAt';
59
+ const isUpdatedAt = fieldName === 'updated_at' || fieldName === 'updatedAt';
60
+ const hasDefaultValue = line.includes('@default');
61
+ // Extract default value if present
62
+ let defaultValue;
63
+ if (hasDefaultValue) {
64
+ const defaultMatch = line.match(/@default\(\s*(.+?)\s*\)/);
65
+ if (defaultMatch) {
66
+ defaultValue = defaultMatch[1];
67
+ }
68
+ }
69
+ const isRelation = line.includes('@relation') ||
70
+ (!!fieldName &&
71
+ (fieldName.endsWith('_id') || fieldName === 'userId' || fieldName === 'user_id'));
72
+ // Check for inline @enableSearch comment
73
+ if (line.includes('// @enableSearch')) {
74
+ searchFields.push({
75
+ name: fieldName || '',
76
+ type: fieldType || '',
77
+ });
78
+ }
79
+ if (fieldName && fieldType) {
80
+ fields.push({
81
+ name: fieldName,
82
+ type: fieldType,
83
+ isRequired: false,
84
+ isOptional,
85
+ isId,
86
+ isUnique: false,
87
+ isUpdatedAt,
88
+ isCreatedAt,
89
+ hasDefaultValue,
90
+ defaultValue, // Add the extracted default value
91
+ isRelation,
92
+ });
93
+ }
94
+ }
95
+ }
96
+ // Check for model-level @enableSearch before the model definition
97
+ if (schema.includes(`// @enableSearch\nmodel ${modelName}`)) {
98
+ // Add all string fields as searchable
99
+ fields.forEach((field) => {
100
+ if (field.type.toLowerCase() === 'string' &&
101
+ !searchFields.some((sf) => sf.name === field.name)) {
102
+ searchFields.push({
103
+ name: field.name,
104
+ type: field.type,
105
+ });
106
+ }
107
+ });
108
+ }
109
+ models.push({
110
+ name: modelName,
111
+ mappedName: mappedName || '',
112
+ fields,
113
+ searchFields: searchFields.length > 0 ? searchFields : undefined,
114
+ });
115
+ }
116
+ return models;
117
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "suparisma",
3
+ "version": "0.0.1",
4
+ "description": "Opinionated typesafe React realtime CRUD hooks generator for all your Supabase tables, powered by Prisma.",
5
+ "main": "dist/index.js",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "start": "node dist/index.js",
9
+ "test": "jest",
10
+ "generate-prisma-types": "prisma generate",
11
+ "generate-hooks": "ts-node --transpile-only src/index.ts"
12
+ },
13
+ "dependencies": {
14
+ "@supabase/supabase-js": "^2.49.4",
15
+ "dotenv": "^16.5.0",
16
+ "fs": "0.0.1-security",
17
+ "path": "^0.12.7",
18
+ "pg": "^8.16.0",
19
+ "react": "^19.1.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^22.15.18",
23
+ "@types/pg": "^8.15.2",
24
+ "@types/react": "^19.1.4",
25
+ "prisma": "^6.8.2",
26
+ "supabase-js": "link:@types/@supabase/supabase-js"
27
+ }
28
+ }
@@ -0,0 +1,22 @@
1
+ // This is your Prisma schema file,
2
+ // learn more about it in the docs: https://pris.ly/d/prisma-schema
3
+
4
+ // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
5
+ // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
6
+
7
+ generator client {
8
+ provider = "prisma-client-js"
9
+ }
10
+
11
+ datasource db {
12
+ provider = "postgresql"
13
+ url = env("DATABASE_URL")
14
+ }
15
+
16
+ model User {
17
+ id String @id @default(uuid())
18
+ email String @unique
19
+ name String?
20
+ createdAt DateTime @default(now())
21
+ updatedAt DateTime @updatedAt
22
+ }
package/src/config.ts ADDED
@@ -0,0 +1,7 @@
1
+ // Configuration
2
+ export const PRISMA_SCHEMA_PATH = process.env.SUPARISMA_PRISMA_SCHEMA_PATH || 'prisma/schema.prisma';
3
+ export const OUTPUT_DIR = process.env.SUPARISMA_OUTPUT_DIR || 'src/suparisma/generated';
4
+ export const TYPES_DIR = `${OUTPUT_DIR}/types`;
5
+ export const HOOKS_DIR = `${OUTPUT_DIR}/hooks`;
6
+ export const UTILS_DIR = `${OUTPUT_DIR}/utils`;
7
+ export const HOOK_NAME_PREFIX = 'useSuparisma';
@@ -0,0 +1,77 @@
1
+ // THIS FILE IS AUTO-GENERATED - DO NOT EDIT DIRECTLY
2
+ // Edit the generator script instead: scripts/generate-realtime-hooks.ts
3
+
4
+ import { createSuparismaHook } from '../utils/core';
5
+ import type {
6
+ UserWithRelations,
7
+ UserCreateInput,
8
+ UserUpdateInput,
9
+ UserWhereInput,
10
+ UserWhereUniqueInput,
11
+ UserOrderByInput,
12
+ UserHookApi,
13
+ UseUserOptions
14
+ } from '../types/UserTypes';
15
+
16
+ /**
17
+ * A Prisma-like hook for interacting with User records with real-time capabilities.
18
+ *
19
+ * This hook provides CRUD operations, real-time updates, and search functionality.
20
+ *
21
+ * @param options - Optional configuration options for the hook
22
+ * @returns An object with data state and methods for interacting with User records
23
+ *
24
+ * @example
25
+ * // Basic usage - get all User records with realtime updates
26
+ * const user = useSuparismaUser();
27
+ * const { data, loading, error } = user;
28
+ *
29
+ * @example
30
+ * // With filtering and ordering
31
+ * const user = useSuparismaUser({
32
+ * where: { active: true },
33
+ * orderBy: { created_at: 'desc' },
34
+ * limit: 10
35
+ * });
36
+ *
37
+ * @example
38
+ * // Create a new record
39
+ * const result = await user.create({
40
+ * name: "Example Name",
41
+ * // other fields...
42
+ * });
43
+ *
44
+ * @example
45
+ * // Update a record
46
+ * const result = await user.update({
47
+ * where: { id: "123" },
48
+ * data: { name: "Updated Name" }
49
+ * });
50
+ *
51
+ * @example
52
+ * // Delete a record
53
+ * const result = await user.delete({ id: "123" });
54
+ *
55
+ * @example
56
+ * // Find records with specific criteria
57
+ * const result = await user.findMany({
58
+ * where: { // filters },
59
+ * orderBy: { // ordering },
60
+ * take: 20 // limit
61
+ * });
62
+ */
63
+ export const useSuparismaUser = createSuparismaHook<
64
+ UserWithRelations,
65
+ UserWithRelations,
66
+ UserCreateInput,
67
+ UserUpdateInput,
68
+ UserWhereInput,
69
+ UserWhereUniqueInput,
70
+ UserOrderByInput
71
+ >({
72
+ tableName: 'User',
73
+ hasCreatedAt: true,
74
+ hasUpdatedAt: true,
75
+ // Default values from schema
76
+ defaultValues: {"id":"uuid(","createdAt":"now("}
77
+ }) as (options?: UseUserOptions) => UserHookApi;
@@ -0,0 +1,50 @@
1
+ // THIS FILE IS AUTO-GENERATED - DO NOT EDIT DIRECTLY
2
+ // Edit the generator script instead: scripts/generate-realtime-hooks.ts
3
+
4
+ import { useSuparismaUser } from './hooks/useSuparismaUser';
5
+ import type { UseUserOptions, UserHookApi } from './types/UserTypes';
6
+ export type { SuparismaOptions, SearchQuery, SearchState, FilterOperators } from './utils/core';
7
+ export type { UserWithRelations, UserCreateInput, UserUpdateInput, UserWhereInput, UserWhereUniqueInput, UserOrderByInput, UserHookApi, UseUserOptions } from './types/UserTypes';
8
+
9
+ /**
10
+ * Interface for all Suparisma hooks with dot notation access.
11
+ * This provides IntelliSense for all available models.
12
+ *
13
+ * @example
14
+ * // Access hooks for different models
15
+ * const users = useSuparisma.user();
16
+ * const posts = useSuparisma.post();
17
+ */
18
+ export interface SuparismaHooks {
19
+ user: (options?: UseUserOptions) => UserHookApi;
20
+ }
21
+
22
+ /**
23
+ * Main Suparisma hook object with dot notation access to all model hooks.
24
+ *
25
+ * @example
26
+ * // Get hooks for different models
27
+ * import useSuparisma from './generated';
28
+ *
29
+ * // Access user model with all hook methods
30
+ * const users = useSuparisma.user();
31
+ * const { data, loading, error } = users;
32
+ *
33
+ * // Create a new record
34
+ * await users.create({ name: "John" });
35
+ *
36
+ * // Delete a record
37
+ * await users.delete({ id: "123" });
38
+ *
39
+ * @example
40
+ * // Use with filtering and options
41
+ * const admins = useSuparisma.user({
42
+ * where: { role: 'admin' },
43
+ * orderBy: { created_at: 'desc' }
44
+ * });
45
+ */
46
+ const useSuparisma: SuparismaHooks = {
47
+ user: useSuparismaUser,
48
+ };
49
+
50
+ export default useSuparisma;