suparisma 1.0.8 → 1.0.12
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 +0 -211
- package/dist/generators/coreGenerator.js +115 -323
- package/dist/generators/typeGenerator.js +33 -65
- package/dist/index.js +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,6 @@ A powerful, typesafe React hook generator for Supabase, driven by your Prisma sc
|
|
|
23
23
|
- [Filtering Data](#filtering-data)
|
|
24
24
|
- [⚠️ IMPORTANT: Using Dynamic Filters with React](#️-important-using-dynamic-filters-with-react)
|
|
25
25
|
- [Array Filtering](#array-filtering)
|
|
26
|
-
- [OR/AND Conditions](#orand-conditions)
|
|
27
26
|
- [Sorting Data](#sorting-data)
|
|
28
27
|
- [Pagination](#pagination)
|
|
29
28
|
- [Search Functionality](#search-functionality)
|
|
@@ -62,7 +61,6 @@ Suparisma bridges this gap by:
|
|
|
62
61
|
- 🔄 **Real-time updates by default** for all tables (with opt-out capability)
|
|
63
62
|
- 🔒 **Type-safe interfaces** for all database operations
|
|
64
63
|
- 🔍 **Full-text search** with configurable annotations *(currently under maintenance)*
|
|
65
|
-
- ⚡ **Advanced filtering** with OR/AND conditions for complex queries
|
|
66
64
|
- 🔢 **Pagination and sorting** built into every hook
|
|
67
65
|
- 🧩 **Prisma-like API** that feels familiar if you already use Prisma
|
|
68
66
|
- 📱 **Works with any React framework** including Next.js, Remix, etc.
|
|
@@ -582,215 +580,6 @@ function ProductFilter() {
|
|
|
582
580
|
}
|
|
583
581
|
```
|
|
584
582
|
|
|
585
|
-
### OR/AND Conditions
|
|
586
|
-
|
|
587
|
-
Suparisma supports powerful logical operations to combine multiple filter conditions:
|
|
588
|
-
|
|
589
|
-
#### OR Conditions - Match ANY condition
|
|
590
|
-
|
|
591
|
-
Use `OR` to find records that match **any** of the provided conditions:
|
|
592
|
-
|
|
593
|
-
```tsx
|
|
594
|
-
// Find users with name "John" OR email containing "@admin"
|
|
595
|
-
const { data: users } = useSuparisma.user({
|
|
596
|
-
where: {
|
|
597
|
-
OR: [
|
|
598
|
-
{ name: "John" },
|
|
599
|
-
{ email: { contains: "@admin" } }
|
|
600
|
-
]
|
|
601
|
-
}
|
|
602
|
-
});
|
|
603
|
-
|
|
604
|
-
// Complex OR with multiple field types
|
|
605
|
-
const { data: posts } = useSuparisma.post({
|
|
606
|
-
where: {
|
|
607
|
-
OR: [
|
|
608
|
-
{ title: { contains: "react" } },
|
|
609
|
-
{ tags: { has: ["typescript"] } },
|
|
610
|
-
{ author: { name: "John Doe" } },
|
|
611
|
-
{ publishedAt: { gte: new Date('2024-01-01') } }
|
|
612
|
-
]
|
|
613
|
-
}
|
|
614
|
-
});
|
|
615
|
-
|
|
616
|
-
// OR with array operators
|
|
617
|
-
const { data: products } = useSuparisma.product({
|
|
618
|
-
where: {
|
|
619
|
-
OR: [
|
|
620
|
-
{ categories: { has: ["electronics"] } },
|
|
621
|
-
{ categories: { has: ["gaming"] } },
|
|
622
|
-
{ price: { lt: 100 } }
|
|
623
|
-
]
|
|
624
|
-
}
|
|
625
|
-
});
|
|
626
|
-
```
|
|
627
|
-
|
|
628
|
-
#### AND Conditions - Match ALL conditions
|
|
629
|
-
|
|
630
|
-
Use `AND` for explicit conjunction (though regular object properties are ANDed by default):
|
|
631
|
-
|
|
632
|
-
```tsx
|
|
633
|
-
// Explicit AND conditions
|
|
634
|
-
const { data: premiumUsers } = useSuparisma.user({
|
|
635
|
-
where: {
|
|
636
|
-
AND: [
|
|
637
|
-
{ active: true },
|
|
638
|
-
{ subscriptionTier: "premium" },
|
|
639
|
-
{ lastLoginAt: { gte: new Date('2024-01-01') } }
|
|
640
|
-
]
|
|
641
|
-
}
|
|
642
|
-
});
|
|
643
|
-
|
|
644
|
-
// Mix AND with other conditions
|
|
645
|
-
const { data: qualifiedPosts } = useSuparisma.post({
|
|
646
|
-
where: {
|
|
647
|
-
published: true, // Regular condition (implicit AND)
|
|
648
|
-
AND: [
|
|
649
|
-
{ views: { gte: 1000 } },
|
|
650
|
-
{ likes: { gte: 100 } }
|
|
651
|
-
]
|
|
652
|
-
}
|
|
653
|
-
});
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
#### Combining OR and AND
|
|
657
|
-
|
|
658
|
-
Create complex nested logic by combining OR and AND:
|
|
659
|
-
|
|
660
|
-
```tsx
|
|
661
|
-
// Advanced search: (Premium users OR moderators) AND active
|
|
662
|
-
const { data: privilegedUsers } = useSuparisma.user({
|
|
663
|
-
where: {
|
|
664
|
-
active: true, // Must be active
|
|
665
|
-
OR: [
|
|
666
|
-
{ role: "premium" },
|
|
667
|
-
{ role: "moderator" }
|
|
668
|
-
]
|
|
669
|
-
}
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
// Content filtering: (Recent posts OR popular posts) AND published
|
|
673
|
-
const { data: featuredPosts } = useSuparisma.post({
|
|
674
|
-
where: {
|
|
675
|
-
published: true,
|
|
676
|
-
OR: [
|
|
677
|
-
{ createdAt: { gte: new Date('2024-01-01') } }, // Recent
|
|
678
|
-
{ views: { gte: 10000 } } // Popular
|
|
679
|
-
]
|
|
680
|
-
}
|
|
681
|
-
});
|
|
682
|
-
|
|
683
|
-
// Complex search across multiple fields and conditions
|
|
684
|
-
const { data: searchResults } = useSuparisma.product({
|
|
685
|
-
where: {
|
|
686
|
-
active: true,
|
|
687
|
-
AND: [
|
|
688
|
-
{
|
|
689
|
-
OR: [
|
|
690
|
-
{ name: { contains: searchTerm } },
|
|
691
|
-
{ description: { contains: searchTerm } },
|
|
692
|
-
{ tags: { has: [searchTerm] } }
|
|
693
|
-
]
|
|
694
|
-
},
|
|
695
|
-
{
|
|
696
|
-
OR: [
|
|
697
|
-
{ price: { between: [minPrice, maxPrice] } },
|
|
698
|
-
{ onSale: true }
|
|
699
|
-
]
|
|
700
|
-
}
|
|
701
|
-
]
|
|
702
|
-
}
|
|
703
|
-
});
|
|
704
|
-
```
|
|
705
|
-
|
|
706
|
-
#### Real-World Examples
|
|
707
|
-
|
|
708
|
-
**Multi-field search for e-commerce:**
|
|
709
|
-
```tsx
|
|
710
|
-
const { data: products } = useSuparisma.product({
|
|
711
|
-
where: {
|
|
712
|
-
OR: [
|
|
713
|
-
{ name: { contains: "laptop" } },
|
|
714
|
-
{ description: { contains: "laptop" } },
|
|
715
|
-
{ categories: { has: ["computers", "electronics"] } },
|
|
716
|
-
{ brand: { in: ["Apple", "Dell", "HP"] } }
|
|
717
|
-
]
|
|
718
|
-
}
|
|
719
|
-
});
|
|
720
|
-
```
|
|
721
|
-
|
|
722
|
-
**User permission filtering:**
|
|
723
|
-
```tsx
|
|
724
|
-
const { data: accessiblePosts } = useSuparisma.post({
|
|
725
|
-
where: {
|
|
726
|
-
OR: [
|
|
727
|
-
{ public: true },
|
|
728
|
-
{ authorId: currentUserId },
|
|
729
|
-
{
|
|
730
|
-
AND: [
|
|
731
|
-
{ published: true },
|
|
732
|
-
{ collaborators: { has: [currentUserId] } }
|
|
733
|
-
]
|
|
734
|
-
}
|
|
735
|
-
]
|
|
736
|
-
}
|
|
737
|
-
});
|
|
738
|
-
```
|
|
739
|
-
|
|
740
|
-
**Dynamic search with React state:**
|
|
741
|
-
```tsx
|
|
742
|
-
import { useMemo } from 'react';
|
|
743
|
-
|
|
744
|
-
function SearchComponent() {
|
|
745
|
-
const [searchTerm, setSearchTerm] = useState("");
|
|
746
|
-
const [category, setCategory] = useState("");
|
|
747
|
-
const [priceRange, setPriceRange] = useState({ min: 0, max: 1000 });
|
|
748
|
-
|
|
749
|
-
// ✅ Use useMemo for stable object reference
|
|
750
|
-
const searchFilter = useMemo(() => {
|
|
751
|
-
const conditions = [];
|
|
752
|
-
|
|
753
|
-
// Add search term condition
|
|
754
|
-
if (searchTerm) {
|
|
755
|
-
conditions.push({
|
|
756
|
-
OR: [
|
|
757
|
-
{ name: { contains: searchTerm } },
|
|
758
|
-
{ description: { contains: searchTerm } },
|
|
759
|
-
{ tags: { has: [searchTerm] } }
|
|
760
|
-
]
|
|
761
|
-
});
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
// Add category condition
|
|
765
|
-
if (category) {
|
|
766
|
-
conditions.push({
|
|
767
|
-
categories: { has: [category] }
|
|
768
|
-
});
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
// Add price range condition
|
|
772
|
-
conditions.push({
|
|
773
|
-
price: { gte: priceRange.min, lte: priceRange.max }
|
|
774
|
-
});
|
|
775
|
-
|
|
776
|
-
return conditions.length > 0 ? { AND: conditions } : undefined;
|
|
777
|
-
}, [searchTerm, category, priceRange]);
|
|
778
|
-
|
|
779
|
-
const { data: products } = useSuparisma.product({
|
|
780
|
-
where: searchFilter
|
|
781
|
-
});
|
|
782
|
-
|
|
783
|
-
// ... rest of component
|
|
784
|
-
}
|
|
785
|
-
```
|
|
786
|
-
|
|
787
|
-
#### Important Notes
|
|
788
|
-
|
|
789
|
-
1. **Performance**: OR conditions may require client-side filtering for realtime updates
|
|
790
|
-
2. **Realtime**: Complex OR/AND combinations automatically enable client-side filtering mode
|
|
791
|
-
3. **Memory**: Use `useMemo` for dynamic OR/AND filters to maintain stable object references
|
|
792
|
-
4. **Nesting**: You can nest OR within AND and vice versa for complex logic
|
|
793
|
-
|
|
794
583
|
### Sorting Data
|
|
795
584
|
|
|
796
585
|
Sort data using Prisma-like ordering:
|
|
@@ -94,21 +94,6 @@ export type FilterOperators<T> = {
|
|
|
94
94
|
// Type for a single field in an advanced where filter
|
|
95
95
|
export type AdvancedWhereInput<T> = {
|
|
96
96
|
[K in keyof T]?: T[K] | FilterOperators<T[K]>;
|
|
97
|
-
} & {
|
|
98
|
-
/**
|
|
99
|
-
* OR condition - match records that satisfy ANY of the provided conditions
|
|
100
|
-
* @example
|
|
101
|
-
* // Find users where name is "John" OR email contains "@admin"
|
|
102
|
-
* { OR: [{ name: "John" }, { email: { contains: "@admin" } }] }
|
|
103
|
-
*/
|
|
104
|
-
OR?: AdvancedWhereInput<T>[];
|
|
105
|
-
/**
|
|
106
|
-
* AND condition - match records that satisfy ALL of the provided conditions (default behavior)
|
|
107
|
-
* @example
|
|
108
|
-
* // Find users where name is "John" AND age > 18
|
|
109
|
-
* { AND: [{ name: "John" }, { age: { gt: 18 } }] }
|
|
110
|
-
*/
|
|
111
|
-
AND?: AdvancedWhereInput<T>[];
|
|
112
97
|
};
|
|
113
98
|
|
|
114
99
|
/**
|
|
@@ -192,19 +177,6 @@ export type SearchState = {
|
|
|
192
177
|
clearQueries: () => void;
|
|
193
178
|
};
|
|
194
179
|
|
|
195
|
-
/**
|
|
196
|
-
* Escape values for Supabase filter strings
|
|
197
|
-
*/
|
|
198
|
-
function escapeFilterValue(value: any): string {
|
|
199
|
-
if (typeof value === 'string') {
|
|
200
|
-
// If the string contains spaces or special characters, wrap it in quotes
|
|
201
|
-
if (value.includes(' ') || value.includes(',') || value.includes('(') || value.includes(')')) {
|
|
202
|
-
return \`"\${value.replace(/"/g, '\\\\"')}"\`;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
return String(value);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
180
|
/**
|
|
209
181
|
* Compare two values for sorting with proper type handling
|
|
210
182
|
*/
|
|
@@ -243,73 +215,9 @@ export function buildFilterString<T>(where?: T): string | undefined {
|
|
|
243
215
|
if (!where) return undefined;
|
|
244
216
|
|
|
245
217
|
const filters: string[] = [];
|
|
246
|
-
const orConditions: string[] = [];
|
|
247
218
|
|
|
248
219
|
for (const [key, value] of Object.entries(where)) {
|
|
249
220
|
if (value !== undefined) {
|
|
250
|
-
// Handle OR conditions
|
|
251
|
-
if (key === 'OR' && Array.isArray(value)) {
|
|
252
|
-
const orParts: string[] = [];
|
|
253
|
-
for (const orCondition of value) {
|
|
254
|
-
// Build individual OR condition parts using proper dot notation
|
|
255
|
-
for (const [orKey, orValue] of Object.entries(orCondition)) {
|
|
256
|
-
if (orValue !== undefined) {
|
|
257
|
-
if (typeof orValue === 'object' && orValue !== null) {
|
|
258
|
-
// Handle advanced operators in OR conditions
|
|
259
|
-
const advancedOps = orValue as unknown as FilterOperators<any>;
|
|
260
|
-
|
|
261
|
-
if ('equals' in advancedOps && advancedOps.equals !== undefined) {
|
|
262
|
-
orParts.push(\`\${orKey}.eq.\${advancedOps.equals}\`);
|
|
263
|
-
} else if ('contains' in advancedOps && advancedOps.contains !== undefined) {
|
|
264
|
-
orParts.push(\`\${orKey}.ilike.*\${advancedOps.contains}*\`);
|
|
265
|
-
} else if ('has' in advancedOps && advancedOps.has !== undefined) {
|
|
266
|
-
// Use PostgreSQL array syntax: {item1,item2} not ["item1","item2"]
|
|
267
|
-
const arrayValue = \`{\${advancedOps.has.map((item: any) => escapeFilterValue(item)).join(',')}}\`;
|
|
268
|
-
orParts.push(\`\${orKey}.ov.\${arrayValue}\`);
|
|
269
|
-
} else if ('hasEvery' in advancedOps && advancedOps.hasEvery !== undefined) {
|
|
270
|
-
// Use PostgreSQL array syntax: {item1,item2} not ["item1","item2"]
|
|
271
|
-
const arrayValue = \`{\${advancedOps.hasEvery.map((item: any) => escapeFilterValue(item)).join(',')}}\`;
|
|
272
|
-
orParts.push(\`\${orKey}.cs.\${arrayValue}\`);
|
|
273
|
-
} else if ('hasSome' in advancedOps && advancedOps.hasSome !== undefined) {
|
|
274
|
-
// Use PostgreSQL array syntax: {item1,item2} not ["item1","item2"]
|
|
275
|
-
const arrayValue = \`{\${advancedOps.hasSome.map((item: any) => escapeFilterValue(item)).join(',')}}\`;
|
|
276
|
-
orParts.push(\`\${orKey}.ov.\${arrayValue}\`);
|
|
277
|
-
} else if ('gt' in advancedOps && advancedOps.gt !== undefined) {
|
|
278
|
-
orParts.push(\`\${orKey}.gt.\${advancedOps.gt}\`);
|
|
279
|
-
} else if ('gte' in advancedOps && advancedOps.gte !== undefined) {
|
|
280
|
-
orParts.push(\`\${orKey}.gte.\${advancedOps.gte}\`);
|
|
281
|
-
} else if ('lt' in advancedOps && advancedOps.lt !== undefined) {
|
|
282
|
-
orParts.push(\`\${orKey}.lt.\${advancedOps.lt}\`);
|
|
283
|
-
} else if ('lte' in advancedOps && advancedOps.lte !== undefined) {
|
|
284
|
-
orParts.push(\`\${orKey}.lte.\${advancedOps.lte}\`);
|
|
285
|
-
} else if ('in' in advancedOps && advancedOps.in?.length) {
|
|
286
|
-
orParts.push(\`\${orKey}.in.(\${advancedOps.in.join(',')})\`);
|
|
287
|
-
}
|
|
288
|
-
} else {
|
|
289
|
-
// Simple equality in OR condition
|
|
290
|
-
orParts.push(\`\${orKey}.eq.\${escapeFilterValue(orValue)}\`);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (orParts.length > 0) {
|
|
297
|
-
orConditions.push(\`or(\${orParts.join(',')})\`);
|
|
298
|
-
}
|
|
299
|
-
continue;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Handle AND conditions (explicit)
|
|
303
|
-
if (key === 'AND' && Array.isArray(value)) {
|
|
304
|
-
for (const andCondition of value) {
|
|
305
|
-
const andFilter = buildFilterString(andCondition);
|
|
306
|
-
if (andFilter) {
|
|
307
|
-
filters.push(andFilter);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
continue;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
221
|
if (typeof value === 'object' && value !== null) {
|
|
314
222
|
// Handle advanced operators
|
|
315
223
|
const advancedOps = value as unknown as FilterOperators<any>;
|
|
@@ -357,22 +265,19 @@ export function buildFilterString<T>(where?: T): string | undefined {
|
|
|
357
265
|
// Array-specific operators
|
|
358
266
|
if ('has' in advancedOps && advancedOps.has !== undefined) {
|
|
359
267
|
// Array contains ANY of the specified items (overlaps)
|
|
360
|
-
|
|
361
|
-
const arrayValue = \`{\${advancedOps.has.map((item: any) => escapeFilterValue(item)).join(',')}}\`;
|
|
268
|
+
const arrayValue = JSON.stringify(advancedOps.has);
|
|
362
269
|
filters.push(\`\${key}=ov.\${arrayValue}\`);
|
|
363
270
|
}
|
|
364
271
|
|
|
365
272
|
if ('hasEvery' in advancedOps && advancedOps.hasEvery !== undefined) {
|
|
366
273
|
// Array contains ALL of the specified items (contains)
|
|
367
|
-
|
|
368
|
-
const arrayValue = \`{\${advancedOps.hasEvery.map((item: any) => escapeFilterValue(item)).join(',')}}\`;
|
|
274
|
+
const arrayValue = JSON.stringify(advancedOps.hasEvery);
|
|
369
275
|
filters.push(\`\${key}=cs.\${arrayValue}\`);
|
|
370
276
|
}
|
|
371
277
|
|
|
372
278
|
if ('hasSome' in advancedOps && advancedOps.hasSome !== undefined) {
|
|
373
279
|
// Array contains ANY of the specified items (overlaps)
|
|
374
|
-
|
|
375
|
-
const arrayValue = \`{\${advancedOps.hasSome.map((item: any) => escapeFilterValue(item)).join(',')}}\`;
|
|
280
|
+
const arrayValue = JSON.stringify(advancedOps.hasSome);
|
|
376
281
|
filters.push(\`\${key}=ov.\${arrayValue}\`);
|
|
377
282
|
}
|
|
378
283
|
|
|
@@ -392,18 +297,7 @@ export function buildFilterString<T>(where?: T): string | undefined {
|
|
|
392
297
|
}
|
|
393
298
|
}
|
|
394
299
|
|
|
395
|
-
|
|
396
|
-
const allConditions: string[] = [];
|
|
397
|
-
|
|
398
|
-
if (filters.length > 0) {
|
|
399
|
-
allConditions.push(filters.join(','));
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (orConditions.length > 0) {
|
|
403
|
-
allConditions.push(\`or(\${orConditions.join(',')})\`);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
return allConditions.length > 0 ? allConditions.join(',') : undefined;
|
|
300
|
+
return filters.length > 0 ? filters.join(',') : undefined;
|
|
407
301
|
}
|
|
408
302
|
|
|
409
303
|
/**
|
|
@@ -420,69 +314,6 @@ export function applyFilter<T>(
|
|
|
420
314
|
// Apply each filter condition
|
|
421
315
|
for (const [key, value] of Object.entries(where)) {
|
|
422
316
|
if (value !== undefined) {
|
|
423
|
-
// Handle OR conditions
|
|
424
|
-
if (key === 'OR' && Array.isArray(value)) {
|
|
425
|
-
// For OR conditions, build the proper dot notation filter string
|
|
426
|
-
const orParts: string[] = [];
|
|
427
|
-
|
|
428
|
-
for (const orCondition of value) {
|
|
429
|
-
for (const [orKey, orValue] of Object.entries(orCondition)) {
|
|
430
|
-
if (orValue !== undefined) {
|
|
431
|
-
if (typeof orValue === 'object' && orValue !== null) {
|
|
432
|
-
// Handle advanced operators in OR conditions
|
|
433
|
-
const advancedOps = orValue as unknown as FilterOperators<any>;
|
|
434
|
-
|
|
435
|
-
if ('equals' in advancedOps && advancedOps.equals !== undefined) {
|
|
436
|
-
orParts.push(\`\${orKey}.eq.\${advancedOps.equals}\`);
|
|
437
|
-
} else if ('contains' in advancedOps && advancedOps.contains !== undefined) {
|
|
438
|
-
orParts.push(\`\${orKey}.ilike.*\${advancedOps.contains}*\`);
|
|
439
|
-
} else if ('has' in advancedOps && advancedOps.has !== undefined) {
|
|
440
|
-
// Use PostgreSQL array syntax: {item1,item2} not ["item1","item2"]
|
|
441
|
-
const arrayValue = \`{\${advancedOps.has.map((item: any) => escapeFilterValue(item)).join(',')}}\`;
|
|
442
|
-
orParts.push(\`\${orKey}.ov.\${arrayValue}\`);
|
|
443
|
-
} else if ('hasEvery' in advancedOps && advancedOps.hasEvery !== undefined) {
|
|
444
|
-
// Use PostgreSQL array syntax: {item1,item2} not ["item1","item2"]
|
|
445
|
-
const arrayValue = \`{\${advancedOps.hasEvery.map((item: any) => escapeFilterValue(item)).join(',')}}\`;
|
|
446
|
-
orParts.push(\`\${orKey}.cs.\${arrayValue}\`);
|
|
447
|
-
} else if ('hasSome' in advancedOps && advancedOps.hasSome !== undefined) {
|
|
448
|
-
// Use PostgreSQL array syntax: {item1,item2} not ["item1","item2"]
|
|
449
|
-
const arrayValue = \`{\${advancedOps.hasSome.map((item: any) => escapeFilterValue(item)).join(',')}}\`;
|
|
450
|
-
orParts.push(\`\${orKey}.ov.\${arrayValue}\`);
|
|
451
|
-
} else if ('gt' in advancedOps && advancedOps.gt !== undefined) {
|
|
452
|
-
orParts.push(\`\${orKey}.gt.\${advancedOps.gt}\`);
|
|
453
|
-
} else if ('gte' in advancedOps && advancedOps.gte !== undefined) {
|
|
454
|
-
orParts.push(\`\${orKey}.gte.\${advancedOps.gte}\`);
|
|
455
|
-
} else if ('lt' in advancedOps && advancedOps.lt !== undefined) {
|
|
456
|
-
orParts.push(\`\${orKey}.lt.\${advancedOps.lt}\`);
|
|
457
|
-
} else if ('lte' in advancedOps && advancedOps.lte !== undefined) {
|
|
458
|
-
orParts.push(\`\${orKey}.lte.\${advancedOps.lte}\`);
|
|
459
|
-
} else if ('in' in advancedOps && advancedOps.in?.length) {
|
|
460
|
-
orParts.push(\`\${orKey}.in.(\${advancedOps.in.join(',')})\`);
|
|
461
|
-
}
|
|
462
|
-
} else {
|
|
463
|
-
// Simple equality in OR condition
|
|
464
|
-
orParts.push(\`\${orKey}.eq.\${escapeFilterValue(orValue)}\`);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
if (orParts.length > 0) {
|
|
471
|
-
// @ts-ignore: Supabase typing issue
|
|
472
|
-
filteredQuery = filteredQuery.or(orParts.join(','));
|
|
473
|
-
}
|
|
474
|
-
continue;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// Handle AND conditions (explicit)
|
|
478
|
-
if (key === 'AND' && Array.isArray(value)) {
|
|
479
|
-
// For explicit AND conditions, apply each condition normally
|
|
480
|
-
for (const andCondition of value) {
|
|
481
|
-
filteredQuery = applyFilter(filteredQuery, andCondition);
|
|
482
|
-
}
|
|
483
|
-
continue;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
317
|
if (typeof value === 'object' && value !== null) {
|
|
487
318
|
// Handle advanced operators
|
|
488
319
|
const advancedOps = value as unknown as FilterOperators<any>;
|
|
@@ -614,112 +445,6 @@ export function applyOrderBy<T>(
|
|
|
614
445
|
return orderedQuery;
|
|
615
446
|
}
|
|
616
447
|
|
|
617
|
-
/**
|
|
618
|
-
* Client-side filter validation for realtime events
|
|
619
|
-
*/
|
|
620
|
-
function clientSideFilterCheck<T>(record: any, where: T): boolean {
|
|
621
|
-
if (!where) return true;
|
|
622
|
-
|
|
623
|
-
for (const [key, value] of Object.entries(where)) {
|
|
624
|
-
if (value !== undefined) {
|
|
625
|
-
// Handle OR conditions
|
|
626
|
-
if (key === 'OR' && Array.isArray(value)) {
|
|
627
|
-
// For OR, at least one condition must match
|
|
628
|
-
const orMatches = value.some(orCondition => clientSideFilterCheck(record, orCondition));
|
|
629
|
-
if (!orMatches) {
|
|
630
|
-
return false;
|
|
631
|
-
}
|
|
632
|
-
continue;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
// Handle AND conditions (explicit)
|
|
636
|
-
if (key === 'AND' && Array.isArray(value)) {
|
|
637
|
-
// For AND, all conditions must match
|
|
638
|
-
const andMatches = value.every(andCondition => clientSideFilterCheck(record, andCondition));
|
|
639
|
-
if (!andMatches) {
|
|
640
|
-
return false;
|
|
641
|
-
}
|
|
642
|
-
continue;
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
if (typeof value === 'object' && value !== null) {
|
|
646
|
-
// Handle complex array filters client-side
|
|
647
|
-
const advancedOps = value as any;
|
|
648
|
-
const recordValue = record[key as keyof typeof record] as any;
|
|
649
|
-
|
|
650
|
-
// Array-specific operators validation
|
|
651
|
-
if ('has' in advancedOps && advancedOps.has !== undefined) {
|
|
652
|
-
// Array contains ANY of the specified items
|
|
653
|
-
if (!Array.isArray(recordValue) || !advancedOps.has.some((item: any) => recordValue.includes(item))) {
|
|
654
|
-
return false;
|
|
655
|
-
}
|
|
656
|
-
} else if ('hasEvery' in advancedOps && advancedOps.hasEvery !== undefined) {
|
|
657
|
-
// Array contains ALL of the specified items
|
|
658
|
-
if (!Array.isArray(recordValue) || !advancedOps.hasEvery.every((item: any) => recordValue.includes(item))) {
|
|
659
|
-
return false;
|
|
660
|
-
}
|
|
661
|
-
} else if ('hasSome' in advancedOps && advancedOps.hasSome !== undefined) {
|
|
662
|
-
// Array contains ANY of the specified items
|
|
663
|
-
if (!Array.isArray(recordValue) || !advancedOps.hasSome.some((item: any) => recordValue.includes(item))) {
|
|
664
|
-
return false;
|
|
665
|
-
}
|
|
666
|
-
} else if ('isEmpty' in advancedOps && advancedOps.isEmpty !== undefined) {
|
|
667
|
-
// Array is empty or not empty
|
|
668
|
-
const isEmpty = !Array.isArray(recordValue) || recordValue.length === 0;
|
|
669
|
-
if (isEmpty !== advancedOps.isEmpty) {
|
|
670
|
-
return false;
|
|
671
|
-
}
|
|
672
|
-
} else if ('equals' in advancedOps && advancedOps.equals !== undefined) {
|
|
673
|
-
if (recordValue !== advancedOps.equals) {
|
|
674
|
-
return false;
|
|
675
|
-
}
|
|
676
|
-
} else if ('not' in advancedOps && advancedOps.not !== undefined) {
|
|
677
|
-
if (recordValue === advancedOps.not) {
|
|
678
|
-
return false;
|
|
679
|
-
}
|
|
680
|
-
} else if ('gt' in advancedOps && advancedOps.gt !== undefined) {
|
|
681
|
-
if (!(recordValue > advancedOps.gt)) {
|
|
682
|
-
return false;
|
|
683
|
-
}
|
|
684
|
-
} else if ('gte' in advancedOps && advancedOps.gte !== undefined) {
|
|
685
|
-
if (!(recordValue >= advancedOps.gte)) {
|
|
686
|
-
return false;
|
|
687
|
-
}
|
|
688
|
-
} else if ('lt' in advancedOps && advancedOps.lt !== undefined) {
|
|
689
|
-
if (!(recordValue < advancedOps.lt)) {
|
|
690
|
-
return false;
|
|
691
|
-
}
|
|
692
|
-
} else if ('lte' in advancedOps && advancedOps.lte !== undefined) {
|
|
693
|
-
if (!(recordValue <= advancedOps.lte)) {
|
|
694
|
-
return false;
|
|
695
|
-
}
|
|
696
|
-
} else if ('in' in advancedOps && advancedOps.in !== undefined) {
|
|
697
|
-
if (!advancedOps.in.includes(recordValue)) {
|
|
698
|
-
return false;
|
|
699
|
-
}
|
|
700
|
-
} else if ('contains' in advancedOps && advancedOps.contains !== undefined) {
|
|
701
|
-
if (!String(recordValue).toLowerCase().includes(String(advancedOps.contains).toLowerCase())) {
|
|
702
|
-
return false;
|
|
703
|
-
}
|
|
704
|
-
} else if ('startsWith' in advancedOps && advancedOps.startsWith !== undefined) {
|
|
705
|
-
if (!String(recordValue).toLowerCase().startsWith(String(advancedOps.startsWith).toLowerCase())) {
|
|
706
|
-
return false;
|
|
707
|
-
}
|
|
708
|
-
} else if ('endsWith' in advancedOps && advancedOps.endsWith !== undefined) {
|
|
709
|
-
if (!String(recordValue).toLowerCase().endsWith(String(advancedOps.endsWith).toLowerCase())) {
|
|
710
|
-
return false;
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
} else if (record[key as keyof typeof record] !== value) {
|
|
714
|
-
console.log(\`Filter mismatch on \${key}\`, { expected: value, actual: record[key as keyof typeof record] });
|
|
715
|
-
return false;
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
return true;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
448
|
/**
|
|
724
449
|
* Core hook factory function that creates a type-safe realtime hook for a specific model.
|
|
725
450
|
* This is the foundation for all Suparisma hooks.
|
|
@@ -763,23 +488,12 @@ export function createSuparismaHook<
|
|
|
763
488
|
* const users = useSuparismaUser();
|
|
764
489
|
* const { data, loading, error } = users;
|
|
765
490
|
*
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
*
|
|
773
|
-
* @example
|
|
774
|
-
* // With OR conditions for search
|
|
775
|
-
* const users = useSuparismaUser({
|
|
776
|
-
* where: {
|
|
777
|
-
* OR: [
|
|
778
|
-
* { name: { contains: "john" } },
|
|
779
|
-
* { email: { contains: "john" } }
|
|
780
|
-
* ]
|
|
781
|
-
* }
|
|
782
|
-
* });
|
|
491
|
+
* @example
|
|
492
|
+
* // With filtering
|
|
493
|
+
* const users = useSuparismaUser({
|
|
494
|
+
* where: { role: 'admin' },
|
|
495
|
+
* orderBy: { created_at: 'desc' }
|
|
496
|
+
* });
|
|
783
497
|
*/
|
|
784
498
|
return function useSuparismaHook(options: SuparismaOptions<TWhereInput, TOrderByInput> = {}) {
|
|
785
499
|
const {
|
|
@@ -990,7 +704,19 @@ export function createSuparismaHook<
|
|
|
990
704
|
|
|
991
705
|
// Apply any where conditions client-side
|
|
992
706
|
if (where) {
|
|
993
|
-
results = results.filter((item) =>
|
|
707
|
+
results = results.filter((item) => {
|
|
708
|
+
for (const [key, value] of Object.entries(where)) {
|
|
709
|
+
if (typeof value === 'object' && value !== null) {
|
|
710
|
+
// Skip complex filters for now
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
if (item[key as keyof typeof item] !== value) {
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return true;
|
|
719
|
+
});
|
|
994
720
|
}
|
|
995
721
|
|
|
996
722
|
// Set count directly for search results
|
|
@@ -1186,33 +912,19 @@ export function createSuparismaHook<
|
|
|
1186
912
|
|
|
1187
913
|
const channelId = channelName || \`changes_to_\${tableName}_\${Math.random().toString(36).substring(2, 15)}\`;
|
|
1188
914
|
|
|
1189
|
-
// Check if we have complex array filters
|
|
915
|
+
// Check if we have complex array filters that should be handled client-side only
|
|
1190
916
|
let hasComplexArrayFilters = false;
|
|
1191
917
|
if (where) {
|
|
1192
|
-
const
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
if (typeof value === 'object' && value !== null) {
|
|
1200
|
-
// Check if it's an array of conditions (nested OR/AND)
|
|
1201
|
-
if (Array.isArray(value)) {
|
|
1202
|
-
return true;
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
const advancedOps = value as any;
|
|
1206
|
-
// Check for complex array operators
|
|
1207
|
-
if ('has' in advancedOps || 'hasEvery' in advancedOps || 'hasSome' in advancedOps || 'isEmpty' in advancedOps) {
|
|
1208
|
-
return true;
|
|
1209
|
-
}
|
|
918
|
+
for (const [key, value] of Object.entries(where)) {
|
|
919
|
+
if (typeof value === 'object' && value !== null) {
|
|
920
|
+
const advancedOps = value as any;
|
|
921
|
+
// Check for complex array operators
|
|
922
|
+
if ('has' in advancedOps || 'hasEvery' in advancedOps || 'hasSome' in advancedOps || 'isEmpty' in advancedOps) {
|
|
923
|
+
hasComplexArrayFilters = true;
|
|
924
|
+
break;
|
|
1210
925
|
}
|
|
1211
926
|
}
|
|
1212
|
-
|
|
1213
|
-
};
|
|
1214
|
-
|
|
1215
|
-
hasComplexArrayFilters = checkForComplexFilters(where);
|
|
927
|
+
}
|
|
1216
928
|
}
|
|
1217
929
|
|
|
1218
930
|
// For complex array filters, use no database filter and rely on client-side filtering
|
|
@@ -1269,7 +981,49 @@ export function createSuparismaHook<
|
|
|
1269
981
|
// ALWAYS check if this record matches our filter client-side
|
|
1270
982
|
// This is especially important for complex array filters
|
|
1271
983
|
if (currentWhere) { // Use ref value
|
|
1272
|
-
|
|
984
|
+
let matchesFilter = true;
|
|
985
|
+
|
|
986
|
+
// Check each filter condition client-side for complex filters
|
|
987
|
+
for (const [key, value] of Object.entries(currentWhere)) {
|
|
988
|
+
if (typeof value === 'object' && value !== null) {
|
|
989
|
+
// Handle complex array filters client-side
|
|
990
|
+
const advancedOps = value as any;
|
|
991
|
+
const recordValue = newRecord[key as keyof typeof newRecord] as any;
|
|
992
|
+
|
|
993
|
+
// Array-specific operators validation
|
|
994
|
+
if ('has' in advancedOps && advancedOps.has !== undefined) {
|
|
995
|
+
// Array contains ANY of the specified items
|
|
996
|
+
if (!Array.isArray(recordValue) || !advancedOps.has.some((item: any) => recordValue.includes(item))) {
|
|
997
|
+
matchesFilter = false;
|
|
998
|
+
break;
|
|
999
|
+
}
|
|
1000
|
+
} else if ('hasEvery' in advancedOps && advancedOps.hasEvery !== undefined) {
|
|
1001
|
+
// Array contains ALL of the specified items
|
|
1002
|
+
if (!Array.isArray(recordValue) || !advancedOps.hasEvery.every((item: any) => recordValue.includes(item))) {
|
|
1003
|
+
matchesFilter = false;
|
|
1004
|
+
break;
|
|
1005
|
+
}
|
|
1006
|
+
} else if ('hasSome' in advancedOps && advancedOps.hasSome !== undefined) {
|
|
1007
|
+
// Array contains ANY of the specified items
|
|
1008
|
+
if (!Array.isArray(recordValue) || !advancedOps.hasSome.some((item: any) => recordValue.includes(item))) {
|
|
1009
|
+
matchesFilter = false;
|
|
1010
|
+
break;
|
|
1011
|
+
}
|
|
1012
|
+
} else if ('isEmpty' in advancedOps && advancedOps.isEmpty !== undefined) {
|
|
1013
|
+
// Array is empty or not empty
|
|
1014
|
+
const isEmpty = !Array.isArray(recordValue) || recordValue.length === 0;
|
|
1015
|
+
if (isEmpty !== advancedOps.isEmpty) {
|
|
1016
|
+
matchesFilter = false;
|
|
1017
|
+
break;
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
// Add other complex filter validations as needed
|
|
1021
|
+
} else if (newRecord[key as keyof typeof newRecord] !== value) {
|
|
1022
|
+
matchesFilter = false;
|
|
1023
|
+
console.log(\`Filter mismatch on \${key}\`, { expected: value, actual: newRecord[key as keyof typeof newRecord] });
|
|
1024
|
+
break;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1273
1027
|
|
|
1274
1028
|
if (!matchesFilter) {
|
|
1275
1029
|
console.log('New record does not match filter criteria, skipping');
|
|
@@ -1355,7 +1109,46 @@ export function createSuparismaHook<
|
|
|
1355
1109
|
|
|
1356
1110
|
// Check if the updated record still matches our current filter
|
|
1357
1111
|
if (currentWhere) {
|
|
1358
|
-
|
|
1112
|
+
let matchesFilter = true;
|
|
1113
|
+
|
|
1114
|
+
for (const [key, value] of Object.entries(currentWhere)) {
|
|
1115
|
+
if (typeof value === 'object' && value !== null) {
|
|
1116
|
+
// Handle complex array filters client-side
|
|
1117
|
+
const advancedOps = value as any;
|
|
1118
|
+
const recordValue = updatedRecord[key as keyof typeof updatedRecord] as any;
|
|
1119
|
+
|
|
1120
|
+
// Array-specific operators validation
|
|
1121
|
+
if ('has' in advancedOps && advancedOps.has !== undefined) {
|
|
1122
|
+
// Array contains ANY of the specified items
|
|
1123
|
+
if (!Array.isArray(recordValue) || !advancedOps.has.some((item: any) => recordValue.includes(item))) {
|
|
1124
|
+
matchesFilter = false;
|
|
1125
|
+
break;
|
|
1126
|
+
}
|
|
1127
|
+
} else if ('hasEvery' in advancedOps && advancedOps.hasEvery !== undefined) {
|
|
1128
|
+
// Array contains ALL of the specified items
|
|
1129
|
+
if (!Array.isArray(recordValue) || !advancedOps.hasEvery.every((item: any) => recordValue.includes(item))) {
|
|
1130
|
+
matchesFilter = false;
|
|
1131
|
+
break;
|
|
1132
|
+
}
|
|
1133
|
+
} else if ('hasSome' in advancedOps && advancedOps.hasSome !== undefined) {
|
|
1134
|
+
// Array contains ANY of the specified items
|
|
1135
|
+
if (!Array.isArray(recordValue) || !advancedOps.hasSome.some((item: any) => recordValue.includes(item))) {
|
|
1136
|
+
matchesFilter = false;
|
|
1137
|
+
break;
|
|
1138
|
+
}
|
|
1139
|
+
} else if ('isEmpty' in advancedOps && advancedOps.isEmpty !== undefined) {
|
|
1140
|
+
// Array is empty or not empty
|
|
1141
|
+
const isEmpty = !Array.isArray(recordValue) || recordValue.length === 0;
|
|
1142
|
+
if (isEmpty !== advancedOps.isEmpty) {
|
|
1143
|
+
matchesFilter = false;
|
|
1144
|
+
break;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
} else if (updatedRecord[key as keyof typeof updatedRecord] !== value) {
|
|
1148
|
+
matchesFilter = false;
|
|
1149
|
+
break;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1359
1152
|
|
|
1360
1153
|
// If the updated record doesn't match the filter, remove it from the list
|
|
1361
1154
|
if (!matchesFilter) {
|
|
@@ -2081,7 +1874,6 @@ export function createSuparismaHook<
|
|
|
2081
1874
|
: api;
|
|
2082
1875
|
};
|
|
2083
1876
|
}
|
|
2084
|
-
|
|
2085
1877
|
`; // Ensure template literal is closed
|
|
2086
1878
|
// Output to the UTILS_DIR
|
|
2087
1879
|
const outputPath = path_1.default.join(config_1.UTILS_DIR, 'core.ts');
|
|
@@ -118,44 +118,40 @@ function generateModelTypesFile(model) {
|
|
|
118
118
|
// Generate imports section for zod custom types
|
|
119
119
|
let customImports = '';
|
|
120
120
|
if (model.zodImports && model.zodImports.length > 0) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
return `// ${zodImport.importStatement}`;
|
|
134
|
-
})
|
|
135
|
-
.join('\n') + '\n\n';
|
|
136
|
-
customImports += importStatements;
|
|
137
|
-
// Add type definitions for imported zod schemas as simple types
|
|
138
|
-
const customTypeDefinitions = model.zodImports
|
|
139
|
-
.flatMap(zodImport => zodImport.types)
|
|
140
|
-
.filter((type, index, array) => array.indexOf(type) === index) // Remove duplicates
|
|
141
|
-
.map(type => {
|
|
142
|
-
// If it ends with 'Schema', create a corresponding type as any for now
|
|
143
|
-
if (type.endsWith('Schema')) {
|
|
144
|
-
const typeName = type.replace('Schema', '');
|
|
145
|
-
return `// Fallback type - replace with actual type if you implement zod schemas\nexport type ${typeName} = any;`;
|
|
146
|
-
}
|
|
147
|
-
return '';
|
|
148
|
-
})
|
|
149
|
-
.filter(Boolean)
|
|
150
|
-
.join('\n');
|
|
151
|
-
if (customTypeDefinitions) {
|
|
152
|
-
customImports += customTypeDefinitions + '\n\n';
|
|
121
|
+
// Add zod import for type inference
|
|
122
|
+
customImports = 'import { z } from \'zod\';\n';
|
|
123
|
+
// Get the zod schemas file path from environment variable
|
|
124
|
+
const zodSchemasPath = process.env.ZOD_SCHEMAS_FILE_PATH || '../commonTypes';
|
|
125
|
+
// Add custom imports with environment variable path
|
|
126
|
+
customImports += model.zodImports
|
|
127
|
+
.map(zodImport => {
|
|
128
|
+
// Extract the types from the original import statement
|
|
129
|
+
const typeMatch = zodImport.importStatement.match(/import\s+{\s*([^}]+)\s*}\s+from/);
|
|
130
|
+
if (typeMatch) {
|
|
131
|
+
const types = typeMatch[1].trim();
|
|
132
|
+
return `import { ${types} } from '${zodSchemasPath}'`;
|
|
153
133
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
134
|
+
// Fallback to original import if parsing fails
|
|
135
|
+
return zodImport.importStatement;
|
|
136
|
+
})
|
|
137
|
+
.join('\n') + '\n\n';
|
|
138
|
+
// Add type definitions for imported zod schemas if needed
|
|
139
|
+
// This is a simplified approach - you might want to make this more sophisticated
|
|
140
|
+
const customTypeDefinitions = model.zodImports
|
|
141
|
+
.flatMap(zodImport => zodImport.types)
|
|
142
|
+
.filter((type, index, array) => array.indexOf(type) === index) // Remove duplicates
|
|
143
|
+
.map(type => {
|
|
144
|
+
// If it ends with 'Schema', create a corresponding type
|
|
145
|
+
if (type.endsWith('Schema')) {
|
|
146
|
+
const typeName = type.replace('Schema', '');
|
|
147
|
+
return `export type ${typeName} = z.infer<typeof ${type}>;`;
|
|
148
|
+
}
|
|
149
|
+
return '';
|
|
150
|
+
})
|
|
151
|
+
.filter(Boolean)
|
|
152
|
+
.join('\n');
|
|
153
|
+
if (customTypeDefinitions) {
|
|
154
|
+
customImports += customTypeDefinitions + '\n\n';
|
|
159
155
|
}
|
|
160
156
|
}
|
|
161
157
|
// Generate the type content with TSDoc comments
|
|
@@ -268,28 +264,6 @@ ${withRelationsProps
|
|
|
268
264
|
.join(',\n')}
|
|
269
265
|
* }
|
|
270
266
|
* });
|
|
271
|
-
*
|
|
272
|
-
* @example
|
|
273
|
-
* // OR conditions - find records matching ANY condition
|
|
274
|
-
* ${modelName.toLowerCase()}.findMany({
|
|
275
|
-
* where: {
|
|
276
|
-
* OR: [
|
|
277
|
-
* { name: "John" },
|
|
278
|
-
* { email: { contains: "@admin" } }
|
|
279
|
-
* ]
|
|
280
|
-
* }
|
|
281
|
-
* });
|
|
282
|
-
*
|
|
283
|
-
* @example
|
|
284
|
-
* // AND conditions - find records matching ALL conditions
|
|
285
|
-
* ${modelName.toLowerCase()}.findMany({
|
|
286
|
-
* where: {
|
|
287
|
-
* AND: [
|
|
288
|
-
* { active: true },
|
|
289
|
-
* { age: { gte: 18 } }
|
|
290
|
-
* ]
|
|
291
|
-
* }
|
|
292
|
-
* });
|
|
293
267
|
*/
|
|
294
268
|
export type ${modelName}WhereInput = {
|
|
295
269
|
${model.fields
|
|
@@ -311,12 +285,6 @@ ${model.fields
|
|
|
311
285
|
}
|
|
312
286
|
return '';
|
|
313
287
|
}).filter(Boolean))
|
|
314
|
-
.concat([
|
|
315
|
-
' /** OR condition - match records that satisfy ANY of the provided conditions */',
|
|
316
|
-
` OR?: ${modelName}WhereInput[];`,
|
|
317
|
-
' /** AND condition - match records that satisfy ALL of the provided conditions */',
|
|
318
|
-
` AND?: ${modelName}WhereInput[];`
|
|
319
|
-
])
|
|
320
288
|
.join('\n')}
|
|
321
289
|
};
|
|
322
290
|
|
package/dist/index.js
CHANGED
|
File without changes
|
package/package.json
CHANGED