Skip to main content

Installation

Add InsForge to your Swift Package Manager dependencies:
dependencies: [
    .package(url: "https://github.com/insforge/insforge-swift.git", from: "0.0.7")
]
import InsForge

let insforge = InsForgeClient(
    baseURL: URL(string: "https://your-app.insforge.app")!,
    anonKey: "your-anon-key"
)

Enable Logging (Optional)

For debugging, you can configure the SDK log level and destination:
let options = InsForgeClientOptions(
    global: .init(
        logLevel: .debug,
        logDestination: .osLog,
        logSubsystem: "com.example.MyApp"
    )
)

let insforge = InsForgeClient(
    baseURL: URL(string: "https://your-app.insforge.app")!,
    anonKey: "your-anon-key",
    options: options
)
Log Levels:
LevelDescription
.traceMost verbose, includes all internal details
.debugDetailed information for debugging
.infoGeneral operational information (default)
.warningWarnings that don’t prevent operation
.errorErrors that affect functionality
.criticalCritical failures
Log Destinations:
DestinationDescription
.consoleStandard output (print)
.osLogApple’s unified logging system (recommended for iOS/macOS)
.noneDisable logging
.customProvide your own LogHandler factory
Use .info or .error in production to avoid exposing sensitive data in logs.

Define Models

Define your data models using Swift’s Codable protocol:
struct Post: Codable {
    let id: String?
    let title: String
    let content: String
    let userId: String
    let createdAt: Date?
}

insert()

Insert new records into a table.

Parameters

  • values - Single Codable object or array of objects to insert

Examples

// Single insert
let post = Post(
    id: nil,
    title: "Hello World",
    content: "My first post!",
    userId: currentUserId,
    createdAt: nil
)
let inserted = try await insforge.database
    .from("posts")
    .insert(post)

// Bulk insert
let posts = [
    Post(id: nil, title: "First Post", content: "Hello everyone!", userId: currentUserId, createdAt: nil),
    Post(id: nil, title: "Second Post", content: "Another update.", userId: currentUserId, createdAt: nil)
]
let inserted = try await insforge.database
    .from("posts")
    .insert(posts)

update()

Update existing records in a table.

Examples

// Define update model
struct PostUpdate: Codable {
    let title: String
}

// Update by ID
let updated: [Post] = try await insforge.database
    .from("posts")
    .eq("id", value: postId)
    .update(PostUpdate(title: "Updated Title"))

// Update multiple records
struct TaskUpdate: Codable {
    let status: String
}

let updated: [Task] = try await insforge.database
    .from("tasks")
    .in("id", values: ["task-1", "task-2"])
    .update(TaskUpdate(status: "completed"))

delete()

Delete records from a table.

Examples

// Delete by ID
try await insforge.database
    .from("posts")
    .eq("id", value: postId)
    .delete()

// Delete with filter
try await insforge.database
    .from("sessions")
    .lt("expires_at", value: Date())
    .delete()

select()

Query records from a table.

Examples

// Get all posts
let posts: [Post] = try await insforge.database
    .from("posts")
    .select()
    .execute()

// Filter and sort
let recentPosts: [Post] = try await insforge.database
    .from("posts")
    .select()
    .eq("userId", value: currentUserId)
    .order("createdAt", ascending: false)
    .limit(20)
    .execute()

// Multiple filters
let activePosts: [Post] = try await insforge.database
    .from("posts")
    .select()
    .eq("userId", value: currentUserId)
    .eq("status", value: "published")
    .execute()

// Specific columns
let posts = try await insforge.database
    .from("posts")
    .select("id, title, content")
    .execute()

// With relationships
let posts = try await insforge.database
    .from("posts")
    .select("*, comments(id, content)")
    .execute()

rpc()

Call PostgreSQL stored functions (RPC - Remote Procedure Call). This method allows you to directly invoke SQL functions defined in your database.

Parameters

  • functionName (String) - Name of the PostgreSQL function to call
  • args ([String: Any]?, optional) - Arguments to pass to the function

Examples

// Define response models
struct UserStats: Decodable {
    let totalPosts: Int
    let totalComments: Int
}

struct User: Decodable {
    let id: String
    let name: String
    let email: String
}

// Call function with parameters, returning array
let stats: [UserStats] = try await insforge.database
    .rpc("get_user_stats", args: ["user_id": "123"])
    .execute()

// Call function with parameters, returning single result
let stat: UserStats = try await insforge.database
    .rpc("get_user_stats", args: ["user_id": "123"])
    .executeSingle()

// Call function without parameters
let users: [User] = try await insforge.database
    .rpc("get_all_active_users")
    .execute()

// Call function with multiple parameters
let results: [Post] = try await insforge.database
    .rpc("search_posts", args: [
        "search_term": "swift",
        "limit": 10,
        "offset": 0
    ])
    .execute()

// Call function with no return value (void function)
try await insforge.database
    .rpc("cleanup_old_records", args: ["days": 30])
    .execute()

// Call function returning a single primitive value
let count: Int = try await insforge.database
    .rpc("count_active_posts")
    .executeSingle()

Implementation Details

  • No arguments: Uses GET request to /api/database/rpc/{functionName}
  • With arguments: Uses POST request with JSON body to /api/database/rpc/{functionName}
  • Use execute() for functions returning arrays or void
  • Use executeSingle() for functions returning a single object or value

Filters

FilterDescriptionExample
.eq(column, value:)Equals.eq("status", value: "active")
.neq(column, value:)Not equals.neq("status", value: "banned")
.gt(column, value:)Greater than.gt("age", value: 18)
.gte(column, value:)Greater than or equal.gte("price", value: 100)
.lt(column, value:)Less than.lt("stock", value: 10)
.lte(column, value:)Less than or equal.lte("priority", value: 3)
.like(column, pattern:)Case-sensitive pattern.like("name", pattern: "%Widget%")
.ilike(column, pattern:)Case-insensitive pattern.ilike("email", pattern: "%@gmail.com")
.in(column, values:)Value in array.in("status", values: ["pending", "active"])
.is(column, value:)Exactly equals (for nil/bool).is("deleted_at", value: nil)
// Chain multiple filters
let products: [Product] = try await insforge.database
    .from("products")
    .select()
    .eq("category", value: "electronics")
    .gte("price", value: 50)
    .lte("price", value: 500)
    .execute()

// Pattern matching
let posts: [Post] = try await insforge.database
    .from("posts")
    .select()
    .ilike("title", pattern: "%swift%")
    .execute()

// Filter by multiple values
let tasks: [Task] = try await insforge.database
    .from("tasks")
    .select()
    .in("status", values: ["pending", "in_progress"])
    .execute()

// Check for null or boolean
let activePosts: [Post] = try await insforge.database
    .from("posts")
    .select()
    .is("deleted_at", value: nil)
    .is("published", value: true)
    .execute()

Modifiers

ModifierDescriptionExample
.order(column, ascending:)Sort results.order("createdAt", ascending: false)
.limit(count)Limit rows.limit(10)
.offset(count)Skip rows.offset(20)
.range(from:, to:)Range pagination.range(from: 0, to: 9)
// Pagination with sorting
let posts: [Post] = try await insforge.database
    .from("posts")
    .select()
    .order("createdAt", ascending: false)
    .limit(10)
    .offset(20)
    .execute()

// Range pagination (get items 10-19)
let posts: [Post] = try await insforge.database
    .from("posts")
    .select()
    .range(from: 10, to: 19)
    .execute()

SwiftUI Integration

import SwiftUI
import InsForge

struct PostListView: View {
    @State private var posts: [Post] = []
    @State private var isLoading = true

    var body: some View {
        List(posts) { post in
            VStack(alignment: .leading) {
                Text(post.title)
                    .font(.headline)
                Text(post.content)
                    .font(.subheadline)
            }
        }
        .task {
            await loadPosts()
        }
    }

    func loadPosts() async {
        do {
            posts = try await insforge.database
                .from("posts")
                .select()
                .order("createdAt", ascending: false)
                .execute()
            isLoading = false
        } catch {
            print("Error loading posts: \(error)")
        }
    }
}