Official Swift SDK for WowMySQL - 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/wowmysql/wowmysql-swift.git", from: "1.0.0")
]Or add it via Xcode:
- File β Add Packages...
- Enter:
https://github.com/wowmysql/wowmysql-swift.git - Select version:
1.0.0
import WowMySQL
let client = WowMySQLClient(
projectUrl: "https://your-project.wowmysql.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 = WowMySQLStorage(
projectUrl: "https://your-project.wowmysql.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 WowMySQLSchema client.
β οΈ IMPORTANT: Schema operations require a Service Role Key (service_*). Anonymous keys will return a 403 Forbidden error.
import WowMySQL
// Initialize schema client with SERVICE ROLE KEY
let schema = WowMySQLSchema(
projectURL: "https://your-project.wowmysql.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 WowMySQL
import Foundation
func runMigration() async throws {
let schema = WowMySQLSchema(
projectURL: ProcessInfo.processInfo.environment["WOWMYSQL_PROJECT_URL"]!,
serviceKey: ProcessInfo.processInfo.environment["WOWMYSQL_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 WowMySQL
do {
let schema = WowMySQLSchema(
projectURL: "https://your-project.wowmysql.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)")
}Full documentation available at: https://wowmysql.com/docs/swift
MIT License - see LICENSE file for details.
Made with β€οΈ by the WowMySQL Team