forked from PerfectlySoft/Perfect
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPerfectObject.swift
232 lines (196 loc) · 6.03 KB
/
PerfectObject.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
//
// PerfectObject.swift
// PerfectLib
//
// Created by Kyle Jessup on 2015-08-04.
// Copyright (C) 2015 PerfectlySoft, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version, as supplemented by the
// Perfect Additional Terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License, as supplemented by the
// Perfect Additional Terms, for more details.
//
// You should have received a copy of the GNU Affero General Public License
// and the Perfect Additional Terms that immediately follow the terms and
// conditions of the GNU Affero General Public License along with this
// program. If not, see <http://www.perfect.org/AGPL_3_0_With_Perfect_Additional_Terms.txt>.
//
import Foundation
public enum HandlerAction {
case None
case Load
case Create
case Delete
case Commit
case List
}
extension HandlerAction {
public func asString() -> String {
switch self {
case .None:
return "none"
case .Load:
return "load"
case .Create:
return "create"
case .Delete:
return "delete"
case .Commit:
return "commit"
case .List:
return "list"
}
}
public static func fromString(s:String) -> HandlerAction {
switch s {
case HandlerAction.Load.asString():
return .Load
case HandlerAction.Create.asString():
return .Create
case HandlerAction.Delete.asString():
return .Delete
case HandlerAction.Commit.asString():
return .Commit
case HandlerAction.List.asString():
return .List
default:
return .None
}
}
}
public protocol PerfectObjectDriver : Closeable {
func load<T : PerfectObject>(type: T, withId: uuid_t) -> T
func load<T : PerfectObject>(type: T, withUniqueField: (String,String)) -> T
func delete(type: PerfectObject) -> (Int, String)
func commitChanges(type: PerfectObject) -> (Int, String)
func commitChanges(types: [PerfectObject]) -> [(Int, String)]
func create<T : PerfectObject>(withFields: [(String,String)]) -> T
func joinTable<T : PerfectObject>(type: PerfectObject, name: String) -> [T]
func list<T : PerfectObject>() -> [T]
func list<T : PerfectObject>(withCriterion: (String,String)) -> [T]
}
extension PerfectObjectDriver {
public func generateUUID() -> uuid_t {
return random_uuid()
}
}
public class PerfectObject {
// Caching on joined tables
var joinCache = [String:[PerfectObject]]()
let driver: PerfectObjectDriver
var id: uuid_t = empty_uuid()
var pkName = "id"
var simpleNameStr = ""
var _orderBy: String?
var _orderDesc: Bool = false
/// The driver must be passed down to any newly loaded objects.
/// It is assumed that the children of a PerfectObject will have the same driver *instance* as the parent.
public required init(driver: PerfectObjectDriver) {
self.driver = driver
}
/// Objects will have valid ids if they have been successfully loaded or created
public func hasValidID() -> Bool {
let empty = empty_uuid()
let id = self.id
if id.0 != empty.0 { return true }
if id.1 != empty.1 { return true }
if id.2 != empty.2 { return true }
if id.3 != empty.3 { return true }
if id.4 != empty.4 { return true }
if id.5 != empty.5 { return true }
if id.6 != empty.6 { return true }
if id.7 != empty.7 { return true }
if id.8 != empty.8 { return true }
if id.9 != empty.9 { return true }
if id.10 != empty.10 { return true }
if id.11 != empty.11 { return true }
if id.12 != empty.12 { return true }
if id.13 != empty.13 { return true }
if id.14 != empty.14 { return true }
if id.15 != empty.15 { return true }
return false
}
/// Provides access to the object driver for this instance
public func objectDriver() -> PerfectObjectDriver {
return self.driver
}
/// Sets the name of hte primary key
/// Should be called by sub-classes only
public func setPrimaryKeyName(to: String) {
self.pkName = to
}
/// Provides access to the object's primary key field name
public func primaryKeyName() -> String {
return self.pkName
}
public func setOrderBy(to: String) {
self._orderBy = to
}
public func orderBy() -> String? {
return self._orderBy
}
public func setOrderDesc(to: Bool) {
self._orderDesc = to
}
public func orderDesc() -> Bool {
return self._orderDesc
}
public func setSimpleName(to: String) {
self.simpleNameStr = to
}
public func simpleName() -> String {
return self.simpleNameStr
}
/// The unique id for this object, within its table.
public func objectId() -> uuid_t {
return self.id
}
public func setObjectId(id: uuid_t) {
self.id = id
}
/// Read the values from a table to populate the object.
/// Sub-classes will override this method to load their own custom properties.
public func load(dict: [String:String], markClean: Bool = true) {
if let findId = dict[primaryKeyName()] {
let uuid = findId.asUUID()
self.id = uuid
}
}
/// Returns only the properties of the type which have been modified since loading
public func unloadDirty() -> [String:String] {
return [String:String]()
}
/// Returns the values from this object which would be written to the table.
/// Sub-classes will overrride this to introduce their own custom properties
public func unload() -> [String:String] {
return [primaryKeyName():String.fromUUID(self.id)]
}
public func fieldList() -> [String] {
return [primaryKeyName()]
}
public func tableName() -> String {
return "Not overridden"
}
public func joinTable<T : PerfectObject>(name: String) -> [T] {
if let found = self.joinCache[name] as! [T]? {
return found
}
let fnd: [T] = self.driver.joinTable(self, name: name)
if fnd.count > 0 {
self.joinCache[name] = fnd
}
return fnd
}
public func clearJoins(named: String) {
self.joinCache.removeValueForKey(named)
}
public func created(withFields: [(String,String)]) {
}
}