Overview
The QueryOperations class provides a lightweight, fluent API for building type-safe queries and mutations.
Creating QueryOperations
import { createQueryOperations } from '@codeleap/query'
const userOperations = createQueryOperations({ queryClient })
  .query('getUser', async (id: string) => {
    const response = await api.get(`/users/${id}`)
    return response.data
  })
  .query('getUsers', async (filters?: UserFilters) => {
    const response = await api.get('/users', { params: filters })
    return response.data
  })
  .mutation('createUser', async (data: Omit<User, 'id'>) => {
    const response = await api.post('/users', data)
    return response.data
  })
  .mutation('updateUser', async (data: Partial<User> & { id: string }) => {
    const response = await api.put(`/users/${data.id}`, data)
    return response.data
  })
  .mutation('deleteUser', async (id: string) => {
    await api.delete(`/users/${id}`)
    return id
  })
Using QueryOperations Hooks
Queries
function UserProfile({ userId }: { userId: string }) {
  // Type-safe query with automatic parameter and return type inference
  const userQuery = userOperations.useQuery('getUser', userId, {
    enabled: !!userId,
    staleTime: 5 * 60 * 1000
  })
  const usersQuery = userOperations.useQuery('getUsers', 
    { status: 'active' }, 
    {
      refetchInterval: 30 * 1000
    }
  )
  if (userQuery.isLoading) return <div>Loading...</div>
  if (userQuery.error) return <div>Error: {userQuery.error.message}</div>
  return (
    <div>
      <h1>{userQuery.data?.name}</h1>
      <p>Total active users: {usersQuery.data?.length}</p>
    </div>
  )
}
Mutations
function UserForm() {
  const createMutation = userOperations.useMutation('createUser', {
    onSuccess: (newUser) => {
      // 'newUser' is automatically typed
      toast.success(`Created user: ${newUser.name}`)
      
      // Invalidate related queries
      queryClient.invalidateQueries({ queryKey: ['getUsers'] })
    }
  })
  const updateMutation = userOperations.useMutation('updateUser')
  const deleteMutation = userOperations.useMutation('deleteUser')
  const handleCreate = (userData: Omit<User, 'id'>) => {
    // Parameters are type-checked
    createMutation.mutate(userData)
  }
  return (
    <form onSubmit={(e) => {
      e.preventDefault()
      handleCreate({
        name: 'John Doe',
        email: 'john@example.com',
        status: 'active',
        createdAt: new Date().toISOString()
      })
    }}>
      {/* Form fields */}
      <button 
        type="submit" 
        disabled={createMutation.isPending}
      >
        Create User
      </button>
    </form>
  )
}
Prefetching and Cache Access
// Prefetch data
await userOperations.prefetchQuery('getUser', 'user-123', {
  staleTime: 10 * 60 * 1000
})
// Get cached data
const cachedUser = await userOperations.getQueryData('getUser', 'user-123')
if (cachedUser) {
  console.log('User already in cache:', cachedUser.name)
}
// Access operations
const { queries, mutations } = userOperations
console.log('Available queries:', Object.keys(queries))
console.log('Available mutations:', Object.keys(mutations))