Skip to content

laptou/sqwery

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

sqwery

Sqwery is a Swift library that provides a powerful and flexible way to manage asynchronous data fetching and state management in SwiftUI applications. It offers a clean and declarative API for handling queries and mutations, inspired by TanStack Query.

Features

  • Declarative query and mutation definitions
  • Automatic caching and invalidation
  • Retry logic with customizable delays
  • SwiftUI integration with property wrappers
  • Support for HTTP requests with Alamofire

Usage

Defining a Query

First, define your query by conforming to the QueryKey protocol:

struct UserQuery: QueryKey {
    let userId: Int
    
    var resultLifetime: Duration { .seconds(60) }
    var retryDelay: Duration { .seconds(5) }
    var retryLimit: Int { 3 }
    
    func run() async throws -> User {
        // Fetch user data from an API
        let url = URL(string: "https://api.example.com/users/\(userId)")!
        let (data, _) = try await URLSession.shared.data(from: url)
        return try JSONDecoder().decode(User.self, from: data)
    }
}

Using Queries in SwiftUI

Use the @Query property wrapper to integrate your query with SwiftUI:

struct UserView: View {
    @Query(UserQuery(userId: 1), queryClient: queryClient)
    var userQuery

    var body: some View {
        switch userQuery {
        case .success(let user):
            Text(user.name)
        case .error(let error):
            Text("Error: \(error.localizedDescription)")
        case .pending:
            ProgressView()
        case .idle:
            Text("Idle")
        }
    }
}

Defining a Mutation

Define a mutation by conforming to the MutationKey protocol:

struct UpdateUserMutation: MutationKey {
    typealias Parameter = UpdateUserParams
    typealias Result = User

    var retryDelay: Duration { .seconds(5) }
    var retryLimit: Int { 3 }

    func run(parameter: UpdateUserParams) async throws -> User {
        // Update user data via API
        let url = URL(string: "https://api.example.com/users/\(parameter.userId)")!
        var request = URLRequest(url: url)
        request.httpMethod = "PUT"
        request.httpBody = try JSONEncoder().encode(parameter)
        let (data, _) = try await URLSession.shared.data(for: request)
        return try JSONDecoder().decode(User.self, from: data)
    }
}

Using Mutations in SwiftUI

Use the @Mutation property wrapper to integrate your mutation with SwiftUI:

struct UpdateUserView: View {
    @Mutation(UpdateUserMutation(), mutationClient: mutationClient)
    var updateUserMutation

    @State private var name = ""

    var body: some View {
        VStack {
            TextField("Name", text: $name)
            Button("Update User") {
                let params = UpdateUserParams(userId: 1, name: name)
                $updateUserMutation.mutate(parameter: params)
            }
            
            switch updateUserMutation {
            case .success(let user):
                Text("Updated: \(user.name)")
            case .error(let error):
                Text("Error: \(error.localizedDescription)")
            case .pending:
                ProgressView()
            case .idle:
                EmptyView()
            }
        }
    }
}

HTTP Queries and Mutations

Sqwery provides convenience protocols for HTTP queries and mutations using Alamofire:

struct FetchUserQuery: HttpQueryKey {
    let userId: Int
    
    var url: String { "https://api.example.com/users/\(userId)" }
    var method: HTTPMethod { .get }
    
    typealias Result = User
}

struct CreateUserMutation: HttpJsonMutationKey {
    typealias Body = CreateUserParams
    typealias Result = User
    
    var url: String { "https://api.example.com/users" }
    var method: HTTPMethod { .post }
    
    func bodyData(for parameter: CreateUserParams) throws -> CreateUserParams {
        parameter
    }
}

Advanced Usage

Query Invalidation

You can invalidate queries to force a refresh:

await queryClient.invalidate(key: UserQuery(userId: 1))

Custom Caching

Sqwery uses an internal cache to store query results. You can customize caching behavior by modifying the resultLifetime property of your queries.

About

React Query for Swift

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages