Official Swift SDK for WOWSQL - MySQL Backend-as-a-Service with S3 Storage.
- ποΈ Full CRUD operations (Create, Read, Update, Delete)
- π Advanced filtering (eq, neq, gt, gte, lt, lte, like, isNull)
- π Pagination (limit, offset)
- π Sorting (orderBy)
- π― Fluent query builder API
- π Type-safe queries with Codable
- β‘ async/await support
- π Raw SQL queries
- π Table schema introspection
- π¦ S3-compatible storage for file management
- β¬οΈ File upload with automatic quota validation
- β¬οΈ File download (presigned URLs)
- π File listing with metadata
- ποΈ File deletion (single and batch)
- π Storage quota management
Add the following to your Package.swift:
dependencies: [
.package(url: "https://github.com/wowsql/wowsql-swift.git", from: "1.0.0")
]Or add it via Xcode:
- File β Add Packages...
- Enter:
https://github.com/wowsql/wowsql-swift.git - Select version:
1.0.0
import WOWSQL
let client = WOWSQLClient(
projectUrl: "https://your-project.wowsql.com",
apiKey: "your-api-key"
)
// Query data
let response = try await client.table("users")
.select("id", "name", "email")
.eq("status", AnyCodable("active"))
.limit(10)
.execute() as QueryResponse<[String: AnyCodable]>
print("Found \(response.count) users")
for user in response.data {
print("\(user["name"]?.value ?? "Unknown") - \(user["email"]?.value ?? "")")
}let storage = WOWSQLStorage(
projectUrl: "https://your-project.wowsql.com",
apiKey: "your-api-key"
)
// Upload file
let fileData = try Data(contentsOf: URL(fileURLWithPath: "document.pdf"))
let result = try await storage.uploadBytes(
fileData,
key: "uploads/document.pdf",
contentType: "application/pdf"
)
print("Uploaded: \(result.url)")
// Check quota
let quota = try await storage.getQuota()
print("Storage used: \(quota.storageUsedGb)GB / \(quota.storageQuotaGb)GB")Programmatically manage your database schema with the WOWSQLSchema client.
β οΈ IMPORTANT: Schema operations require a Service Role Key (service_*). Anonymous keys will return a 403 Forbidden error.
import WOWSQL
// Initialize schema client with SERVICE ROLE KEY
let schema = WOWSQLSchema(
projectURL: "https://your-project.wowsql.com",
serviceKey: "service_xyz789..." // β οΈ Backend only! Never expose!
)// Create a new table
try await schema.createTable(CreateTableRequest(
tableName: "products",
columns: [
ColumnDefinition(name: "id", type: "INT", autoIncrement: true),
ColumnDefinition(name: "name", type: "VARCHAR(255)", notNull: true),
ColumnDefinition(name: "price", type: "DECIMAL(10,2)", notNull: true),
ColumnDefinition(name: "category", type: "VARCHAR(100)"),
ColumnDefinition(name: "created_at", type: "TIMESTAMP", defaultValue: "CURRENT_TIMESTAMP")
],
primaryKey: "id",
indexes: [
IndexDefinition(name: "idx_category", columns: ["category"]),
IndexDefinition(name: "idx_price", columns: ["price"])
]
))
print("Table created successfully!")// Add a new column
try await schema.alterTable(AlterTableRequest(
tableName: "products",
addColumns: [
ColumnDefinition(name: "stock_quantity", type: "INT", defaultValue: "0")
]
))
// Modify an existing column
try await schema.alterTable(AlterTableRequest(
tableName: "products",
modifyColumns: [
ColumnDefinition(name: "price", type: "DECIMAL(12,2)") // Increase precision
]
))
// Drop a column
try await schema.alterTable(AlterTableRequest(
tableName: "products",
dropColumns: ["category"]
))
// Rename a column
try await schema.alterTable(AlterTableRequest(
tableName: "products",
renameColumns: [
RenameColumn(oldName: "name", newName: "product_name")
]
))// Drop a table
try await schema.dropTable("old_table")
// Drop with CASCADE (removes dependent objects)
try await schema.dropTable("products", cascade: true)// Execute custom schema SQL
try await schema.executeSQL("""
CREATE INDEX idx_product_name
ON products(product_name);
""")
// Add a foreign key constraint
try await schema.executeSQL("""
ALTER TABLE orders
ADD CONSTRAINT fk_product
FOREIGN KEY (product_id)
REFERENCES products(id);
""")- Use service role keys only in backend/server code (never in iOS/macOS apps)
- Store service keys in environment variables or secure configuration
- Use anonymous keys for client-side data operations
- Test schema changes in development first
- Never expose service role keys in iOS/macOS app code
- Never commit service keys to version control
- Don't use anonymous keys for schema operations (will fail)
import WOWSQL
import Foundation
func runMigration() async throws {
let schema = WOWSQLSchema(
projectURL: ProcessInfo.processInfo.environment["WOWSQL_PROJECT_URL"]!,
serviceKey: ProcessInfo.processInfo.environment["WOWSQL_SERVICE_KEY"]! // From env var
)
// Create users table
try await schema.createTable(CreateTableRequest(
tableName: "users",
columns: [
ColumnDefinition(name: "id", type: "INT", autoIncrement: true),
ColumnDefinition(name: "email", type: "VARCHAR(255)", unique: true, notNull: true),
ColumnDefinition(name: "name", type: "VARCHAR(255)", notNull: true),
ColumnDefinition(name: "created_at", type: "TIMESTAMP", defaultValue: "CURRENT_TIMESTAMP")
],
primaryKey: "id",
indexes: [
IndexDefinition(name: "idx_email", columns: ["email"])
]
))
print("Migration completed!")
}
// Run migration
Task {
try await runMigration()
}import WOWSQL
do {
let schema = WOWSQLSchema(
projectURL: "https://your-project.wowsql.com",
serviceKey: "service_xyz..."
)
try await schema.createTable(CreateTableRequest(
tableName: "test",
columns: [ColumnDefinition(name: "id", type: "INT")]
))
} catch let error as PermissionError {
print("Permission denied: \(error.message)")
print("Make sure you're using a SERVICE ROLE KEY, not an anonymous key!")
} catch {
print("Error: \(error)")
}β¨ One Project = One Set of Keys for ALL Operations
WOWSQL uses unified authentication - the same API keys work for both database operations AND authentication operations.
-
Anonymous Key (
wowsql_anon_...) β¨ Unified Key- Used for:
- β Client-side auth operations (signup, login, OAuth)
- β Public/client-side database operations with limited permissions
- Safe to expose in frontend code (browser, mobile apps)
- Used for:
-
Service Role Key (
wowsql_service_...) β¨ Unified Key- Used for:
- β Server-side auth operations (admin, full access)
- β Server-side database operations (full access, bypass RLS)
- NEVER expose in frontend code - server-side only!
- Used for:
import WOWSQL
// Database operations
let dbClient = WOWSQLClient(
projectUrl: "https://your-project.wowsql.com",
apiKey: "wowsql_anon_..." // Anonymous Key
)
// Authentication operations - SAME KEY!
let authConfig = ProjectAuthConfig(
projectUrl: "https://your-project.wowsql.com",
apiKey: "wowsql_anon_..." // Same Anonymous Key
)
let authClient = ProjectAuthClient(config: authConfig)Note: The publicApiKey parameter is deprecated but still works for backward compatibility. Use apiKey instead.
Full documentation available at: https://wowsql.com/docs/swift
MIT License - see LICENSE file for details.
Made with β€οΈ by the WOWSQL Team