Defining Models
Models in SwiftDataServer are defined using the @Model macro, providing 100% API compatibility with Apple's SwiftData.
Basic Model
import SwiftDataServer
@Model
final class User {
var name: String = ""
@Attribute(.unique)
var email: String = ""
var age: Int = 0
var isActive: Bool = true
var createdAt: Date = Date()
init(name: String, email: String, age: Int) {
self.name = name
self.email = email
self.age = age
}
}
What @Model Generates
The @Model macro automatically generates:
- id property - A unique UUID identifier
- PersistentModel conformance - Required protocol for persistence
- Codable conformance - Automatic encoding/decoding
- Schema metadata - Maps properties to database columns
- Change tracking - Tracks modified properties for efficient updates
Supported Property Types
| Swift Type | Database Type |
|---|---|
String |
TEXT / VARCHAR |
Int, Int8, Int16, Int32, Int64 |
INTEGER / BIGINT |
Double, Float |
DOUBLE PRECISION / REAL |
Bool |
BOOLEAN |
Date |
TIMESTAMP |
UUID |
UUID |
Data |
BYTEA / BLOB |
Optional<T> |
NULLABLE column |
[T] (Codable arrays) |
JSON |
Default Values
All stored properties must have default values so SwiftDataServer can deserialize objects from the database:
@Model
final class Article {
var title: String = "" // Required - empty string default
var viewCount: Int = 0 // Required - zero default
var publishedAt: Date? = nil // Optional - nil default
var tags: [String] = [] // Array - empty array default
var createdAt: Date = Date() // Date - current date default
}
Custom Initializers
Define custom initializers to set properties at creation time:
@Model
final class User {
var name: String = ""
var email: String = ""
var createdAt: Date = Date()
// Custom initializer
init(name: String, email: String) {
self.name = name
self.email = email
// createdAt uses default value
}
// Multiple initializers are allowed
convenience init(email: String) {
self.init(name: "Unknown", email: email)
}
}
Computed Properties
Computed properties are not persisted but can be useful for derived values:
@Model
final class User {
var firstName: String = ""
var lastName: String = ""
var birthDate: Date = Date()
// Computed - not persisted
var fullName: String {
"\(firstName) \(lastName)"
}
var age: Int {
Calendar.current.dateComponents([.year], from: birthDate, to: Date()).year ?? 0
}
}
Transient Properties
Use @Transient to exclude stored properties from persistence:
@Model
final class User {
var name: String = ""
var email: String = ""
@Transient
var temporaryToken: String? // Not saved to database
@Transient
var cachedData: [String: Any]? // Not saved to database
}
Enums
Use raw value enums for type-safe status fields:
enum Status: String, Codable {
case pending
case active
case suspended
}
@Model
final class User {
var name: String = ""
var statusRawValue: String = Status.pending.rawValue
@Transient
var status: Status {
get { Status(rawValue: statusRawValue) ?? .pending }
set { statusRawValue = newValue.rawValue }
}
}
Next Steps
- Attributes - Customize property behavior with @Attribute
- Relationships - Define relationships between models
- Migrations - Handle schema changes