Claude-skill-registry implement-crud
Implement complete CRUD (Create, Read, Update, Delete) operations for Supabase tables with proper error handling, validation, and RLS. Triggers when user requests data operations, API endpoints, or database interactions.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/implement-crud" ~/.claude/skills/majiayu000-claude-skill-registry-implement-crud && rm -rf "$T"
manifest:
skills/data/implement-crud/SKILL.mdsource content
CRUD Implementation Skill
Implement comprehensive CRUD operations for Supabase tables with best practices.
Purpose
Generate production-ready CRUD operations including queries, mutations, error handling, type safety, and RLS-aware implementations.
When to Use
- User requests CRUD functionality
- Needs API endpoints for data operations
- Asks for database interaction code
- Wants to implement data management features
- Requests type-safe database operations
Instructions
-
Analyze Requirements
- Identify target table and columns
- Understand relationships and foreign keys
- Check RLS policies on table
- Determine validation rules
- Identify required permissions
-
Implement Read Operations
- Single record fetch by ID
- List with filtering and pagination
- Search functionality
- Include related data with joins
- Handle not found cases
-
Implement Create Operations
- Input validation
- Required field checks
- Foreign key validation
- Return created record with ID
- Handle duplicate key errors
-
Implement Update Operations
- Partial update support
- Optimistic locking if needed
- Validate ownership via RLS
- Return updated record
- Handle not found cases
-
Implement Delete Operations
- Soft delete vs hard delete
- Cascade handling
- Validate ownership
- Return success confirmation
- Handle foreign key violations
-
Add Error Handling
- Wrap operations in try-catch
- Provide meaningful error messages
- Handle common Postgres errors
- Return structured error responses
- Log errors appropriately
Examples
TypeScript Implementation
import { createClient } from '@supabase/supabase-js' import type { Database } from './database.types' const supabase = createClient<Database>( process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY! ) // READ: Get single post by ID export async function getPost(id: string) { const { data, error } = await supabase .from('posts') .select(` *, author:profiles!author_id(*), comments(count) `) .eq('id', id) .single() if (error) { throw new Error(`Failed to fetch post: ${error.message}`) } return data } // READ: List posts with pagination export async function listPosts(options: { page?: number perPage?: number published?: boolean }) { const { page = 1, perPage = 20, published } = options const start = (page - 1) * perPage const end = start + perPage - 1 let query = supabase .from('posts') .select('*, author:profiles!author_id(username)', { count: 'exact' }) if (published !== undefined) { query = query.eq('published', published) } const { data, error, count } = await query .order('created_at', { ascending: false }) .range(start, end) if (error) { throw new Error(`Failed to list posts: ${error.message}`) } return { data, pagination: { page, perPage, total: count, totalPages: Math.ceil((count || 0) / perPage) } } } // CREATE: Insert new post export async function createPost(input: { title: string content: string authorId: string published?: boolean }) { const { data, error } = await supabase .from('posts') .insert({ title: input.title, content: input.content, author_id: input.authorId, published: input.published ?? false, slug: generateSlug(input.title) }) .select() .single() if (error) { if (error.code === '23505') { throw new Error('A post with this title already exists') } throw new Error(`Failed to create post: ${error.message}`) } return data } // UPDATE: Update existing post export async function updatePost( id: string, updates: { title?: string content?: string published?: boolean } ) { const { data, error } = await supabase .from('posts') .update(updates) .eq('id', id) .select() .single() if (error) { if (error.code === 'PGRST116') { throw new Error('Post not found or access denied') } throw new Error(`Failed to update post: ${error.message}`) } return data } // DELETE: Remove post export async function deletePost(id: string) { const { error } = await supabase .from('posts') .delete() .eq('id', id) if (error) { if (error.code === 'PGRST116') { throw new Error('Post not found or access denied') } throw new Error(`Failed to delete post: ${error.message}`) } return { success: true } } function generateSlug(title: string): string { return title .toLowerCase() .replace(/[^a-z0-9]+/g, '-') .replace(/^-|-$/g, '') }
Output Format
Provide:
- Complete CRUD function implementations
- Proper TypeScript types
- Error handling for all cases
- Usage examples
- Testing recommendations