prisma-jotai-client
v0.0.1
Published
A fully dynamic Prisma client wrapper for Jotai with conditional typing and built-in pagination support
Maintainers
Readme
Prisma Jotai Client 🚀
A fully dynamic Prisma client wrapper for Jotai with conditional typing and built-in pagination support
Installation • Quick Start • API • Examples • Contributing
✨ Features
- 🔄 Fully Dynamic: All models and operations extracted automatically from generated Prisma types
- 🎯 Conditional Typing: Return types inferred based on parameters (
select,include,omit,paginated) - 📄 Built-in Pagination: Native pagination support with automatic metadata
- 🛡️ Type Safe: Complete TypeScript support with full autocompletion
- ⚡ Optimized: Intelligent caching with atom families and
isEqual - 🎪 Zero Config: No manual configuration required
- 🔧 Extensible: New models automatically supported
- 🌐 Universal: Works with any Prisma schema
🏗️ Architecture
This library creates a bridge between Prisma and Jotai by:
- Using dynamic proxies to intercept model access
- Leveraging generated Prisma types (
Prisma.TypeMap,Prisma.ModelName) - Creating cached atom families for optimal performance
- Providing advanced TypeScript inference for conditional return types
📦 Installation
npm install prisma-jotai-client
# or
yarn add prisma-jotai-client
# or
pnpm add prisma-jotai-client
# or
bun add prisma-jotai-clientPeer Dependencies
Make sure you have the required peer dependencies installed:
npm install @prisma/client jotai react🚀 Quick Start
- Generate your Prisma client (if not already done):
npx prisma generate- Import and use:
import { $ } from 'prisma-jotai-client';
import { useAtom } from 'jotai';
function UserProfile({ userId }: { userId: string }) {
// Automatically typed based on your Prisma schema
const [userAtom] = useAtom($.user.findUnique({
where: { id: userId },
include: { posts: true, profile: true }
}));
// userAtom type: Atom<Promise<User & { posts: Post[]; profile: Profile | null } | null>>
return (
<Suspense fallback="Loading...">
<UserDisplay userAtom={userAtom} />
</Suspense>
);
}🎯 Conditional Typing
The return type changes automatically based on the parameters you use:
// SELECT: Returns only selected fields
const userWithSelect = $.user.findUnique({
where: { id: 'user-123' },
select: { id: true, email: true }
});
// Type: Atom<Promise<{ id: string; email: string } | null>>
// INCLUDE: Returns full object + relations
const userWithInclude = $.user.findUnique({
where: { id: 'user-123' },
include: { posts: true, comments: true }
});
// Type: Atom<Promise<User & { posts: Post[]; comments: Comment[] } | null>>
// Default: Returns base object
const userBasic = $.user.findUnique({
where: { id: 'user-123' }
});
// Type: Atom<Promise<User | null>>📄 Pagination
Built-in pagination support with automatic metadata:
// Basic pagination
const paginatedUsers = $.user.findMany({
take: 10,
skip: 0,
paginated: true
});
// Returns: { data: User[], total: number, take: number, skip: number }
// Pagination with filters and sorting
const filteredPosts = $.post.findMany({
where: { published: true },
orderBy: { createdAt: 'desc' },
take: 25,
skip: 50,
paginated: true
});
// Pagination with SELECT
const paginatedWithSelect = $.user.findMany({
select: { id: true, email: true },
take: 20,
paginated: true
});
// Type: { data: { id: string; email: string }[], total: number, take: number, skip: number }Automatic metadata:
data: Query resultstotal: Total number of recordstake: Applied limitskip: Applied offset
📚 API Reference
Available Operations
All standard Prisma operations are supported automatically:
findUnique/findUniqueOrThrowfindFirst/findFirstOrThrowfindManycreate/createMany/createManyAndReturnupdate/updateMany/updateManyAndReturndelete/deleteManyupsertcountaggregategroupBy
Dynamic Model Access
Access any model from your Prisma schema:
$.user.findMany() // User operations
$.post.findMany() // Post operations
$.comment.findMany() // Comment operations
$.profile.findMany() // Profile operations
// ... any model from your schemaType-Safe Parameters
All parameters are fully typed based on your Prisma schema:
// TypeScript will provide autocompletion and validation
$.post.findMany({
where: {
title: { contains: 'prisma' },
author: { email: { endsWith: '@example.com' } }
},
orderBy: { createdAt: 'desc' },
include: { author: true, comments: true }
});💡 Examples
Real-World Usage Patterns
User Management with Search
function useUserList(search: string, page: number) {
return useAtom($.user.findMany({
where: search ? {
OR: [
{ email: { contains: search, mode: 'insensitive' } },
{ name: { contains: search, mode: 'insensitive' } }
]
} : undefined,
orderBy: { createdAt: 'desc' },
take: 20,
skip: (page - 1) * 20,
select: {
id: true,
email: true,
name: true,
createdAt: true
},
paginated: true
}));
}Blog Posts with Analytics
function useBlogPosts(authorId?: string) {
return useAtom($.post.findMany({
where: authorId ? { authorId } : { published: true },
include: {
author: { select: { name: true, email: true } },
_count: { comments: true }
},
orderBy: { createdAt: 'desc' }
}));
}Advanced Filtering
function usePostsWithFilters(filters: {
authorId?: string;
dateFrom?: Date;
dateTo?: Date;
hasComments?: boolean;
}) {
return useAtom($.post.findMany({
where: {
...(filters.authorId && { authorId: filters.authorId }),
...(filters.dateFrom && { createdAt: { gte: filters.dateFrom } }),
...(filters.dateTo && { createdAt: { lte: filters.dateTo } }),
...(filters.hasComments !== undefined && {
comments: filters.hasComments ? { some: {} } : { none: {} }
})
},
include: { author: true, comments: true }
}));
}🧪 Testing
Run the included examples:
# See full demonstration
npm run demo
# Test pagination examples
npm run demo:pagination🏗️ Development
Setup
# Clone the repository
git clone https://github.com/yourusername/prisma-jotai-client.git
cd prisma-jotai-client
# Install dependencies
npm install
# Run development build
npm run devBuild
# Build for production
npm run build
# Type check
npm run type-check
# Lint
npm run lint🌟 Benefits
- Conditional Typing: Return types inferred based on
select/include/omit/paginated - Native Pagination: Automatic metadata (
total,take,skip) - Zero Maintenance: New models automatically supported
- Type Safety: TypeScript errors for invalid models/fields
- Performance: Intelligent atom caching
- Developer Experience: Full IDE autocompletion
- Flexibility: Complete Prisma feature support
🔧 Configuration
TypeScript
Ensure your tsconfig.json includes:
{
"compilerOptions": {
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true
}
}Prisma
Works with any Prisma schema. Just run prisma generate and you're ready to go!
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Workflow
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Run
npm run buildandnpm run type-check - Submit a pull request
📄 License
MIT © Your Name
🙏 Acknowledgments
- Prisma for the amazing ORM and type generation
- Jotai for the excellent atomic state management
- The React and TypeScript communities
📞 Support
Made with ❤️ by the community
