|
| 1 | +import Foundation |
| 2 | +import StructuredQueriesCore |
| 3 | + |
| 4 | +// MARK: - UUID Generation Functions |
| 5 | +// |
| 6 | +// PostgreSQL Chapter 9.14: UUID Functions |
| 7 | +// https://www.postgresql.org/docs/18/functions-uuid.html |
| 8 | +// |
| 9 | +// Functions for generating UUIDs server-side |
| 10 | + |
| 11 | +// MARK: - PostgreSQL.UUID Namespace Functions |
| 12 | + |
| 13 | +extension PostgreSQL.UUID { |
| 14 | + /// PostgreSQL's `gen_random_uuid()` - Version 4 (random) UUID |
| 15 | + /// |
| 16 | + /// Generates a cryptographically random UUID suitable for primary keys. |
| 17 | + /// |
| 18 | + /// ```swift |
| 19 | + /// User.insert { |
| 20 | + /// User.Draft(id: PostgreSQL.UUID.random(), name: "Alice") |
| 21 | + /// } |
| 22 | + /// // INSERT INTO "users" ("id", "name") VALUES (gen_random_uuid(), 'Alice') |
| 23 | + /// ``` |
| 24 | + /// |
| 25 | + /// - Returns: A random UUID expression suitable for use in queries |
| 26 | + /// |
| 27 | + /// > Note: Equivalent to PostgreSQL's `gen_random_uuid()` or `uuidv4()`. |
| 28 | + /// > This is the most commonly used UUID type for primary keys. |
| 29 | + /// |
| 30 | + /// > Tip: Use `.timeOrdered()` instead if you need time-ordered UUIDs for better index performance. |
| 31 | + public static func random() -> some QueryExpression<Foundation.UUID> { |
| 32 | + SQLQueryExpression("gen_random_uuid()", as: Foundation.UUID.self) |
| 33 | + } |
| 34 | + |
| 35 | + /// Alias for `.random()` - PostgreSQL's `uuidv4()` |
| 36 | + /// |
| 37 | + /// Generates a Version 4 (random) UUID. |
| 38 | + /// |
| 39 | + /// ```swift |
| 40 | + /// User.insert { |
| 41 | + /// User.Draft(id: PostgreSQL.UUID.v4(), name: "Bob") |
| 42 | + /// } |
| 43 | + /// // INSERT INTO "users" ("id", "name") VALUES (uuidv4(), 'Bob') |
| 44 | + /// ``` |
| 45 | + /// |
| 46 | + /// - Returns: A random UUID expression |
| 47 | + /// |
| 48 | + /// > Note: This is an alias for `.random()` and generates the same result. |
| 49 | + public static func v4() -> some QueryExpression<Foundation.UUID> { |
| 50 | + SQLQueryExpression("uuidv4()", as: Foundation.UUID.self) |
| 51 | + } |
| 52 | + |
| 53 | + /// PostgreSQL's `uuidv7()` - Version 7 (time-ordered) UUID |
| 54 | + /// |
| 55 | + /// Generates a time-ordered UUID with better index performance than v4. |
| 56 | + /// Version 7 UUIDs contain a timestamp component that can be extracted. |
| 57 | + /// |
| 58 | + /// ```swift |
| 59 | + /// Event.insert { |
| 60 | + /// Event.Draft(id: PostgreSQL.UUID.timeOrdered(), name: "Login") |
| 61 | + /// } |
| 62 | + /// // INSERT INTO "events" ("id", "name") VALUES (uuidv7(), 'Login') |
| 63 | + /// ``` |
| 64 | + /// |
| 65 | + /// - Returns: A time-ordered UUID expression |
| 66 | + /// |
| 67 | + /// > Note: Requires PostgreSQL 13+. UUIDs sort chronologically, improving index performance. |
| 68 | + /// |
| 69 | + /// > Tip: Extract creation time with `.extractTimestamp()`. |
| 70 | + /// |
| 71 | + /// **Why use v7 over v4?** |
| 72 | + /// - Better B-tree index performance (sequential inserts) |
| 73 | + /// - Natural chronological ordering |
| 74 | + /// - Embedded timestamp can be extracted without separate column |
| 75 | + /// - Reduces index fragmentation |
| 76 | + public static func timeOrdered() -> some QueryExpression<Foundation.UUID> { |
| 77 | + SQLQueryExpression("uuidv7()", as: Foundation.UUID.self) |
| 78 | + } |
| 79 | + |
| 80 | + /// Alias for `.timeOrdered()` - PostgreSQL's `uuidv7()` |
| 81 | + /// |
| 82 | + /// Generates a Version 7 (time-ordered) UUID. |
| 83 | + /// |
| 84 | + /// ```swift |
| 85 | + /// Event.insert { |
| 86 | + /// Event.Draft(id: PostgreSQL.UUID.v7(), name: "Logout") |
| 87 | + /// } |
| 88 | + /// // INSERT INTO "events" ("id", "name") VALUES (uuidv7(), 'Logout') |
| 89 | + /// ``` |
| 90 | + /// |
| 91 | + /// - Returns: A time-ordered UUID expression |
| 92 | + /// |
| 93 | + /// > Note: This is an alias for `.timeOrdered()` and generates the same result. |
| 94 | + public static func v7() -> some QueryExpression<Foundation.UUID> { |
| 95 | + SQLQueryExpression("uuidv7()", as: Foundation.UUID.self) |
| 96 | + } |
| 97 | + |
| 98 | + /// PostgreSQL's `uuidv7(interval)` - Time-ordered UUID with timestamp shift |
| 99 | + /// |
| 100 | + /// Generates a time-ordered UUID with an adjusted timestamp. |
| 101 | + /// Useful for backdating or future-dating events. |
| 102 | + /// |
| 103 | + /// ```swift |
| 104 | + /// Event.insert { |
| 105 | + /// Event.Draft(id: PostgreSQL.UUID.timeOrdered(shift: "-1 hour"), name: "Historical Event") |
| 106 | + /// } |
| 107 | + /// // INSERT INTO "events" ("id", "name") VALUES (uuidv7('-1 hour'::interval), 'Historical Event') |
| 108 | + /// |
| 109 | + /// Reminder.insert { |
| 110 | + /// Reminder.Draft(id: PostgreSQL.UUID.timeOrdered(shift: "30 minutes")) |
| 111 | + /// } |
| 112 | + /// // INSERT INTO "reminders" ("id") VALUES (uuidv7('30 minutes'::interval)) |
| 113 | + /// ``` |
| 114 | + /// |
| 115 | + /// - Parameter shift: PostgreSQL interval syntax for time adjustment |
| 116 | + /// - Returns: A time-ordered UUID with shifted timestamp |
| 117 | + /// |
| 118 | + /// > Warning: Invalid interval syntax causes runtime PostgreSQL error. |
| 119 | + /// |
| 120 | + /// **Valid interval examples:** |
| 121 | + /// - Negative shifts (past): `"-1 hour"`, `"-30 minutes"`, `"-2 days"` |
| 122 | + /// - Positive shifts (future): `"30 minutes"`, `"1 day"`, `"2 hours"` |
| 123 | + /// - Complex intervals: `"-1 hour 30 minutes"`, `"1 day 12 hours"` |
| 124 | + /// |
| 125 | + /// **Use cases:** |
| 126 | + /// - Backdating events: `.timeOrdered(shift: "-1 hour")` |
| 127 | + /// - Scheduling future events: `.timeOrdered(shift: "1 day")` |
| 128 | + /// - Testing time-based logic with controlled timestamps |
| 129 | + public static func timeOrdered(shift: String) -> some QueryExpression<Foundation.UUID> { |
| 130 | + SQLQueryExpression("uuidv7('\(raw: shift)'::interval)", as: Foundation.UUID.self) |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +// MARK: - Foundation.UUID Convenience Properties |
| 135 | +// |
| 136 | +// These provide ergonomic static properties for common usage patterns. |
| 137 | +// They delegate to PostgreSQL.UUID namespace functions. |
| 138 | + |
| 139 | +extension Foundation.UUID { |
| 140 | + /// Convenience property for PostgreSQL.UUID.random() |
| 141 | + /// |
| 142 | + /// ```swift |
| 143 | + /// User.insert { User.Draft(id: .random, name: "Alice") } |
| 144 | + /// // INSERT INTO "users" ("id", "name") VALUES (gen_random_uuid(), 'Alice') |
| 145 | + /// ``` |
| 146 | + /// |
| 147 | + /// > Note: Delegates to `PostgreSQL.UUID.random()` for implementation. |
| 148 | + public static var random: some QueryExpression<UUID> { |
| 149 | + PostgreSQL.UUID.random() |
| 150 | + } |
| 151 | + |
| 152 | + /// Convenience property for PostgreSQL.UUID.v4() |
| 153 | + /// |
| 154 | + /// ```swift |
| 155 | + /// User.insert { User.Draft(id: .v4, name: "Bob") } |
| 156 | + /// // INSERT INTO "users" ("id", "name") VALUES (uuidv4(), 'Bob') |
| 157 | + /// ``` |
| 158 | + /// |
| 159 | + /// > Note: Delegates to `PostgreSQL.UUID.v4()` for implementation. |
| 160 | + public static var v4: some QueryExpression<UUID> { |
| 161 | + PostgreSQL.UUID.v4() |
| 162 | + } |
| 163 | + |
| 164 | + /// Convenience property for PostgreSQL.UUID.timeOrdered() |
| 165 | + /// |
| 166 | + /// ```swift |
| 167 | + /// Event.insert { Event.Draft(id: .timeOrdered, name: "Login") } |
| 168 | + /// // INSERT INTO "events" ("id", "name") VALUES (uuidv7(), 'Login') |
| 169 | + /// ``` |
| 170 | + /// |
| 171 | + /// > Note: Delegates to `PostgreSQL.UUID.timeOrdered()` for implementation. |
| 172 | + public static var timeOrdered: some QueryExpression<UUID> { |
| 173 | + PostgreSQL.UUID.timeOrdered() |
| 174 | + } |
| 175 | + |
| 176 | + /// Convenience property for PostgreSQL.UUID.v7() |
| 177 | + /// |
| 178 | + /// ```swift |
| 179 | + /// Event.insert { Event.Draft(id: .v7, name: "Logout") } |
| 180 | + /// // INSERT INTO "events" ("id", "name") VALUES (uuidv7(), 'Logout') |
| 181 | + /// ``` |
| 182 | + /// |
| 183 | + /// > Note: Delegates to `PostgreSQL.UUID.v7()` for implementation. |
| 184 | + public static var v7: some QueryExpression<UUID> { |
| 185 | + PostgreSQL.UUID.v7() |
| 186 | + } |
| 187 | + |
| 188 | + /// Convenience function for PostgreSQL.UUID.timeOrdered(shift:) |
| 189 | + /// |
| 190 | + /// ```swift |
| 191 | + /// Event.insert { |
| 192 | + /// Event.Draft(id: .timeOrdered(shift: "-1 hour"), name: "Historical Event") |
| 193 | + /// } |
| 194 | + /// // INSERT INTO "events" ("id", "name") VALUES (uuidv7('-1 hour'::interval), 'Historical Event') |
| 195 | + /// ``` |
| 196 | + /// |
| 197 | + /// - Parameter shift: PostgreSQL interval syntax for time adjustment |
| 198 | + /// - Returns: A time-ordered UUID with shifted timestamp |
| 199 | + /// |
| 200 | + /// > Note: Delegates to `PostgreSQL.UUID.timeOrdered(shift:)` for implementation. |
| 201 | + public static func timeOrdered(shift: String) -> some QueryExpression<UUID> { |
| 202 | + PostgreSQL.UUID.timeOrdered(shift: shift) |
| 203 | + } |
| 204 | +} |
0 commit comments