create-syncular-app 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -27
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +131 -179
- package/dist/constants.d.ts +40 -0
- package/dist/constants.js +46 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/scaffold.d.ts +44 -0
- package/dist/scaffold.js +106 -0
- package/package.json +22 -15
- package/src/cli.ts +174 -0
- package/src/constants.ts +53 -0
- package/src/index.ts +3 -0
- package/src/scaffold.ts +161 -0
- package/template/minimal/README.md +45 -0
- package/template/minimal/gitignore +5 -0
- package/template/minimal/migrations/0001_initial/up.sql +9 -0
- package/template/minimal/package.json +22 -0
- package/template/minimal/src/clients.ts +54 -0
- package/template/minimal/src/make-client.ts +26 -0
- package/template/minimal/src/server.ts +39 -0
- package/template/minimal/src/smoke.test.ts +70 -0
- package/template/minimal/src/syncular.generated.ts +66 -0
- package/template/minimal/syncular.ir.json +66 -0
- package/template/minimal/syncular.json +17 -0
- package/template/minimal/tsconfig.json +16 -0
- package/template/web/README.md +63 -0
- package/template/web/gitignore +5 -0
- package/template/web/migrations/0001_initial/up.sql +11 -0
- package/template/web/package.json +22 -0
- package/template/web/src/frontend/index.html +37 -0
- package/template/web/src/frontend/main.ts +191 -0
- package/template/web/src/frontend/worker.ts +9 -0
- package/template/web/src/server.ts +183 -0
- package/template/web/src/smoke.test.ts +91 -0
- package/template/web/src/syncular.generated.ts +74 -0
- package/template/web/syncular.ir.json +76 -0
- package/template/web/syncular.json +17 -0
- package/template/web/tsconfig.json +16 -0
- package/template/README.md +0 -122
- package/template/_gitignore +0 -5
- package/template/generated/kotlin/SyncularApp.kt +0 -1005
- package/template/generated/rust/diesel_tables.rs +0 -142
- package/template/generated/rust/migrations.rs +0 -32
- package/template/generated/rust/schema.rs +0 -15
- package/template/generated/rust/syncular.rs +0 -926
- package/template/generated/swift/SyncularApp.swift +0 -1191
- package/template/generated/syncular.codegen.json +0 -19
- package/template/index.html +0 -13
- package/template/migrations/0001_initial/down.sql +0 -1
- package/template/migrations/0001_initial/up.sql +0 -8
- package/template/package.json +0 -33
- package/template/scripts/dev.ts +0 -42
- package/template/src/app.tsx +0 -231
- package/template/src/client/syncular.ts +0 -61
- package/template/src/generated/syncular.generated.ts +0 -769
- package/template/src/generated/syncular.server.generated.ts +0 -512
- package/template/src/main.tsx +0 -5
- package/template/src/server/sync-server.ts +0 -129
- package/template/src/styles.css +0 -233
- package/template/syncular.app.ts +0 -23
- package/template/syncular.schema.json +0 -145
- package/template/tsconfig.json +0 -18
- package/template/vite.config.ts +0 -9
|
@@ -1,1191 +0,0 @@
|
|
|
1
|
-
// @generated by `cargo run --manifest-path rust/Cargo.toml -p syncular-codegen --`
|
|
2
|
-
// Source: migrations/*.sql and generated Syncular codegen handoff
|
|
3
|
-
|
|
4
|
-
import Foundation
|
|
5
|
-
|
|
6
|
-
public let syncularNativeExpectedFfiAbiVersion = 2
|
|
7
|
-
public let syncularNativeExpectedCrateVersion = "0.1.0"
|
|
8
|
-
public let syncularNativeGeneratedSchemaVersion = 1
|
|
9
|
-
|
|
10
|
-
public let syncularNativeGeneratedAppSchemaJson = "{\"clientSchemaSupport\":{\"current\":1,\"minSupported\":1,\"supported\":[1]},\"localBaseSchema\":{\"tableSetupSql\":[\"CREATE TABLE IF NOT EXISTS \\\"tasks\\\" (\\n \\\"id\\\" TEXT PRIMARY KEY,\\n \\\"title\\\" TEXT NOT NULL,\\n \\\"completed\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"user_id\\\" TEXT NOT NULL,\\n \\\"created_at\\\" INTEGER NOT NULL DEFAULT 0,\\n \\\"server_version\\\" INTEGER NOT NULL DEFAULT 0\\n) WITHOUT ROWID\"]},\"migrations\":[{\"name\":\"initial\",\"schemaVersion\":1,\"upSql\":\"CREATE TABLE IF NOT EXISTS tasks (\\n id TEXT PRIMARY KEY,\\n title TEXT NOT NULL,\\n completed INTEGER NOT NULL DEFAULT 0,\\n user_id TEXT NOT NULL,\\n created_at BIGINT NOT NULL DEFAULT 0,\\n server_version BIGINT NOT NULL DEFAULT 0\\n) WITHOUT ROWID;\",\"version\":\"0001\"}],\"schemaVersion\":1,\"tables\":[{\"blobColumns\":[],\"columns\":[{\"name\":\"id\",\"notnullRequired\":false,\"primaryKey\":true,\"typeFamily\":\"text\"},{\"name\":\"title\",\"notnullRequired\":true,\"primaryKey\":false,\"typeFamily\":\"text\"},{\"name\":\"completed\",\"notnullRequired\":true,\"primaryKey\":false,\"typeFamily\":\"integer\"},{\"name\":\"user_id\",\"notnullRequired\":true,\"primaryKey\":false,\"typeFamily\":\"text\"},{\"name\":\"created_at\",\"notnullRequired\":true,\"primaryKey\":false,\"typeFamily\":\"integer\"},{\"name\":\"server_version\",\"notnullRequired\":true,\"primaryKey\":false,\"typeFamily\":\"integer\"}],\"crdtYjsFields\":[],\"encryptedFields\":[],\"name\":\"tasks\",\"primaryKeyColumn\":\"id\",\"scopes\":[{\"column\":\"user_id\",\"name\":\"user_id\",\"required\":true,\"source\":\"actorId\"}],\"serverVersionColumn\":\"server_version\",\"softDeleteColumn\":null,\"subscriptionId\":\"sub-tasks\"}]}"
|
|
11
|
-
|
|
12
|
-
public enum SyncularNativeGeneratedError: Error, Equatable {
|
|
13
|
-
case runtimeManifestMismatch(String)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
public struct SyncularNativeRuntimeManifest: Decodable, Equatable {
|
|
17
|
-
public let ffiAbiVersion: Int
|
|
18
|
-
public let crateName: String
|
|
19
|
-
public let crateVersion: String
|
|
20
|
-
public let schemaVersion: Int
|
|
21
|
-
public let storageBackend: String
|
|
22
|
-
public let transportBackends: [String]
|
|
23
|
-
public let capabilities: [String]
|
|
24
|
-
|
|
25
|
-
private enum CodingKeys: String, CodingKey {
|
|
26
|
-
case ffiAbiVersion = "ffi_abi_version"
|
|
27
|
-
case crateName = "crate_name"
|
|
28
|
-
case crateVersion = "crate_version"
|
|
29
|
-
case schemaVersion = "schema_version"
|
|
30
|
-
case storageBackend = "storage_backend"
|
|
31
|
-
case transportBackends = "transport_backends"
|
|
32
|
-
case capabilities
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public func assertSyncularNativeRuntimeManifestJson(_ manifestJson: String) throws {
|
|
37
|
-
let data = Data(manifestJson.utf8)
|
|
38
|
-
let manifest = try JSONDecoder().decode(SyncularNativeRuntimeManifest.self, from: data)
|
|
39
|
-
try assertSyncularNativeRuntimeManifest(manifest)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
public func assertSyncularNativeRuntimeManifest(_ manifest: SyncularNativeRuntimeManifest) throws {
|
|
43
|
-
guard manifest.ffiAbiVersion == syncularNativeExpectedFfiAbiVersion else {
|
|
44
|
-
throw SyncularNativeGeneratedError.runtimeManifestMismatch("FFI ABI version \(manifest.ffiAbiVersion) does not match generated expectation \(syncularNativeExpectedFfiAbiVersion)")
|
|
45
|
-
}
|
|
46
|
-
guard manifest.crateVersion == syncularNativeExpectedCrateVersion else {
|
|
47
|
-
throw SyncularNativeGeneratedError.runtimeManifestMismatch("Rust crate version \(manifest.crateVersion) does not match generated expectation \(syncularNativeExpectedCrateVersion)")
|
|
48
|
-
}
|
|
49
|
-
guard manifest.storageBackend == "diesel-sqlite" else {
|
|
50
|
-
throw SyncularNativeGeneratedError.runtimeManifestMismatch("Rust storage backend \(manifest.storageBackend) is not diesel-sqlite")
|
|
51
|
-
}
|
|
52
|
-
guard manifest.capabilities.contains("generated-json-local-operations") else {
|
|
53
|
-
throw SyncularNativeGeneratedError.runtimeManifestMismatch("Rust native runtime is missing generated-json-local-operations")
|
|
54
|
-
}
|
|
55
|
-
guard manifest.capabilities.contains("generated-json-mutations") else {
|
|
56
|
-
throw SyncularNativeGeneratedError.runtimeManifestMismatch("Rust native runtime is missing generated-json-mutations")
|
|
57
|
-
}
|
|
58
|
-
guard manifest.capabilities.contains("generated-json-leased-mutations") else {
|
|
59
|
-
throw SyncularNativeGeneratedError.runtimeManifestMismatch("Rust native runtime is missing generated-json-leased-mutations")
|
|
60
|
-
}
|
|
61
|
-
guard manifest.capabilities.contains("queued-json-leased-mutations") else {
|
|
62
|
-
throw SyncularNativeGeneratedError.runtimeManifestMismatch("Rust native runtime is missing queued-json-leased-mutations")
|
|
63
|
-
}
|
|
64
|
-
guard manifest.capabilities.contains("auth-lease-issue") else {
|
|
65
|
-
throw SyncularNativeGeneratedError.runtimeManifestMismatch("Rust native runtime is missing auth-lease-issue")
|
|
66
|
-
}
|
|
67
|
-
guard manifest.capabilities.contains("read-only-query-json") else {
|
|
68
|
-
throw SyncularNativeGeneratedError.runtimeManifestMismatch("Rust native runtime is missing read-only-query-json")
|
|
69
|
-
}
|
|
70
|
-
guard manifest.capabilities.contains("query-observer-events") else {
|
|
71
|
-
throw SyncularNativeGeneratedError.runtimeManifestMismatch("Rust native runtime is missing query-observer-events")
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
public enum SyncularGeneratedOperationKind: String, Codable, Equatable {
|
|
76
|
-
case upsert
|
|
77
|
-
case delete
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
public indirect enum SyncularJsonValue: Codable, Equatable {
|
|
81
|
-
case string(String)
|
|
82
|
-
case int(Int64)
|
|
83
|
-
case double(Double)
|
|
84
|
-
case bool(Bool)
|
|
85
|
-
case object([String: SyncularJsonValue])
|
|
86
|
-
case array([SyncularJsonValue])
|
|
87
|
-
case null
|
|
88
|
-
|
|
89
|
-
public init(from decoder: Decoder) throws {
|
|
90
|
-
let container = try decoder.singleValueContainer()
|
|
91
|
-
if container.decodeNil() { self = .null }
|
|
92
|
-
else if let value = try? container.decode(Bool.self) { self = .bool(value) }
|
|
93
|
-
else if let value = try? container.decode(Int64.self) { self = .int(value) }
|
|
94
|
-
else if let value = try? container.decode(Double.self) { self = .double(value) }
|
|
95
|
-
else if let value = try? container.decode([String: SyncularJsonValue].self) { self = .object(value) }
|
|
96
|
-
else if let value = try? container.decode([SyncularJsonValue].self) { self = .array(value) }
|
|
97
|
-
else { self = .string(try container.decode(String.self)) }
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public func encode(to encoder: Encoder) throws {
|
|
101
|
-
var container = encoder.singleValueContainer()
|
|
102
|
-
switch self {
|
|
103
|
-
case .string(let value): try container.encode(value)
|
|
104
|
-
case .int(let value): try container.encode(value)
|
|
105
|
-
case .double(let value): try container.encode(value)
|
|
106
|
-
case .bool(let value): try container.encode(value)
|
|
107
|
-
case .object(let value): try container.encode(value)
|
|
108
|
-
case .array(let value): try container.encode(value)
|
|
109
|
-
case .null: try container.encodeNil()
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
public struct SyncularBlobRef: Codable, Equatable {
|
|
115
|
-
public let hash: String
|
|
116
|
-
public let size: Int64
|
|
117
|
-
public let mimeType: String
|
|
118
|
-
public let encrypted: Bool?
|
|
119
|
-
public let keyId: String?
|
|
120
|
-
|
|
121
|
-
public init(hash: String, size: Int64, mimeType: String, encrypted: Bool? = nil, keyId: String? = nil) {
|
|
122
|
-
self.hash = hash
|
|
123
|
-
self.size = size
|
|
124
|
-
self.mimeType = mimeType
|
|
125
|
-
self.encrypted = encrypted
|
|
126
|
-
self.keyId = keyId
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
private enum CodingKeys: String, CodingKey {
|
|
130
|
-
case hash
|
|
131
|
-
case size
|
|
132
|
-
case mimeType
|
|
133
|
-
case encrypted
|
|
134
|
-
case keyId
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
public init(from decoder: Decoder) throws {
|
|
138
|
-
let single = try decoder.singleValueContainer()
|
|
139
|
-
if let encoded = try? single.decode(String.self) {
|
|
140
|
-
self = try JSONDecoder().decode(SyncularBlobRef.self, from: Data(encoded.utf8))
|
|
141
|
-
return
|
|
142
|
-
}
|
|
143
|
-
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
144
|
-
hash = try container.decode(String.self, forKey: .hash)
|
|
145
|
-
size = try container.decode(Int64.self, forKey: .size)
|
|
146
|
-
mimeType = try container.decode(String.self, forKey: .mimeType)
|
|
147
|
-
encrypted = try container.decodeIfPresent(Bool.self, forKey: .encrypted)
|
|
148
|
-
keyId = try container.decodeIfPresent(String.self, forKey: .keyId)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
public func encode(to encoder: Encoder) throws {
|
|
152
|
-
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
153
|
-
try container.encode(hash, forKey: .hash)
|
|
154
|
-
try container.encode(size, forKey: .size)
|
|
155
|
-
try container.encode(mimeType, forKey: .mimeType)
|
|
156
|
-
try container.encodeIfPresent(encrypted, forKey: .encrypted)
|
|
157
|
-
try container.encodeIfPresent(keyId, forKey: .keyId)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
public var syncularPayloadValue: SyncularJsonValue {
|
|
161
|
-
var value: [String: SyncularJsonValue] = [
|
|
162
|
-
"hash": .string(hash),
|
|
163
|
-
"size": .int(size),
|
|
164
|
-
"mimeType": .string(mimeType),
|
|
165
|
-
]
|
|
166
|
-
if let encrypted { value["encrypted"] = .bool(encrypted) }
|
|
167
|
-
if let keyId { value["keyId"] = .string(keyId) }
|
|
168
|
-
return .object(value)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
public func jsonString() throws -> String {
|
|
172
|
-
let encoder = JSONEncoder()
|
|
173
|
-
encoder.outputFormatting = [.sortedKeys]
|
|
174
|
-
return String(data: try encoder.encode(self), encoding: .utf8)!
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
public struct SyncularSubscriptionArgs: Equatable {
|
|
179
|
-
public let actorId: String
|
|
180
|
-
public let projectId: String?
|
|
181
|
-
|
|
182
|
-
public let bootstrapPhases: [String: Int64]
|
|
183
|
-
|
|
184
|
-
public init(actorId: String, projectId: String? = nil, bootstrapPhases: [String: Int64] = [:]) {
|
|
185
|
-
self.actorId = actorId
|
|
186
|
-
self.projectId = projectId
|
|
187
|
-
self.bootstrapPhases = bootstrapPhases
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
private func syncularBootstrapPhase(args: SyncularSubscriptionArgs, table: String, subscriptionId: String) -> Int64 {
|
|
192
|
-
args.bootstrapPhases[subscriptionId] ?? args.bootstrapPhases[table] ?? 0
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
public struct SyncularSubscriptionSpec: Codable, Equatable {
|
|
196
|
-
public let id: String
|
|
197
|
-
public let table: String
|
|
198
|
-
public let scopes: [String: SyncularJsonValue]
|
|
199
|
-
public let params: [String: SyncularJsonValue]
|
|
200
|
-
public let bootstrapPhase: Int64
|
|
201
|
-
|
|
202
|
-
public init(id: String, table: String, scopes: [String: SyncularJsonValue], params: [String: SyncularJsonValue] = [:], bootstrapPhase: Int64 = 0) {
|
|
203
|
-
self.id = id
|
|
204
|
-
self.table = table
|
|
205
|
-
self.scopes = scopes
|
|
206
|
-
self.params = params
|
|
207
|
-
self.bootstrapPhase = bootstrapPhase
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
public func jsonString() throws -> String {
|
|
211
|
-
let encoder = JSONEncoder()
|
|
212
|
-
encoder.outputFormatting = [.sortedKeys]
|
|
213
|
-
return String(data: try encoder.encode(self), encoding: .utf8)!
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
public struct SyncularAuthLeaseScope: Codable, Equatable {
|
|
218
|
-
public let subscriptionId: String
|
|
219
|
-
public let table: String
|
|
220
|
-
public let values: [String: SyncularJsonValue]
|
|
221
|
-
public let operations: [String]
|
|
222
|
-
|
|
223
|
-
public init(subscriptionId: String, table: String, values: [String: SyncularJsonValue], operations: [String]) {
|
|
224
|
-
self.subscriptionId = subscriptionId
|
|
225
|
-
self.table = table
|
|
226
|
-
self.values = values
|
|
227
|
-
self.operations = operations
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
public struct SyncularAuthLeaseIssueRequest: Codable, Equatable {
|
|
232
|
-
public let schemaVersion: Int
|
|
233
|
-
public let ttlMs: Int64?
|
|
234
|
-
public let scopes: [SyncularAuthLeaseScope]
|
|
235
|
-
|
|
236
|
-
public init(schemaVersion: Int = syncularNativeGeneratedSchemaVersion, ttlMs: Int64? = nil, scopes: [SyncularAuthLeaseScope]) {
|
|
237
|
-
self.schemaVersion = schemaVersion
|
|
238
|
-
self.ttlMs = ttlMs
|
|
239
|
-
self.scopes = scopes
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
public func jsonString() throws -> String {
|
|
243
|
-
let encoder = JSONEncoder()
|
|
244
|
-
encoder.outputFormatting = [.sortedKeys]
|
|
245
|
-
return String(data: try encoder.encode(self), encoding: .utf8)!
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
public struct SyncularAuthLeaseRecord: Codable, Equatable {
|
|
250
|
-
public let leaseId: String
|
|
251
|
-
public let kid: String
|
|
252
|
-
public let actorId: String
|
|
253
|
-
public let issuedAtMs: Int64
|
|
254
|
-
public let notBeforeMs: Int64
|
|
255
|
-
public let expiresAtMs: Int64
|
|
256
|
-
public let schemaVersion: Int
|
|
257
|
-
public let payloadJson: String
|
|
258
|
-
public let token: String
|
|
259
|
-
public let status: String
|
|
260
|
-
public let lastValidationError: String?
|
|
261
|
-
public let createdAtMs: Int64
|
|
262
|
-
public let updatedAtMs: Int64
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
public func syncularSubscriptionsJson(_ subscriptions: [SyncularSubscriptionSpec]) throws -> String {
|
|
266
|
-
let encoder = JSONEncoder()
|
|
267
|
-
encoder.outputFormatting = [.sortedKeys]
|
|
268
|
-
return String(data: try encoder.encode(subscriptions), encoding: .utf8)!
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
public func syncularDefaultSubscriptionsJson(actorId: String, projectId: String? = nil, bootstrapPhases: [String: Int64] = [:]) throws -> String {
|
|
272
|
-
try syncularSubscriptionsJson(syncularDefaultSubscriptions(args: SyncularSubscriptionArgs(actorId: actorId, projectId: projectId, bootstrapPhases: bootstrapPhases)))
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
public func syncularDefaultSubscriptions(args: SyncularSubscriptionArgs) -> [SyncularSubscriptionSpec] {
|
|
276
|
-
[
|
|
277
|
-
taskSubscription(args: args),
|
|
278
|
-
]
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
public func taskSubscription(args: SyncularSubscriptionArgs) -> SyncularSubscriptionSpec {
|
|
282
|
-
var scopes: [String: SyncularJsonValue] = [:]
|
|
283
|
-
scopes["user_id"] = .string(args.actorId)
|
|
284
|
-
return SyncularSubscriptionSpec(id: "sub-tasks", table: "tasks", scopes: scopes, params: [:], bootstrapPhase: syncularBootstrapPhase(args: args, table: "tasks", subscriptionId: "sub-tasks"))
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
public struct SyncularReadonlyQuery: Codable, Equatable {
|
|
288
|
-
public let sql: String
|
|
289
|
-
public let params: [SyncularJsonValue]
|
|
290
|
-
public let tables: [String]
|
|
291
|
-
|
|
292
|
-
public init(sql: String, params: [SyncularJsonValue] = [], tables: [String]) {
|
|
293
|
-
self.sql = sql
|
|
294
|
-
self.params = params
|
|
295
|
-
self.tables = tables
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
public func jsonString() throws -> String {
|
|
299
|
-
let encoder = JSONEncoder()
|
|
300
|
-
encoder.outputFormatting = [.sortedKeys]
|
|
301
|
-
return String(data: try encoder.encode(self), encoding: .utf8)!
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
public struct SyncularLiveQueryRegistration: Codable, Equatable {
|
|
306
|
-
public let id: String
|
|
307
|
-
public let tables: [String]
|
|
308
|
-
public let label: String?
|
|
309
|
-
|
|
310
|
-
public init(id: String, tables: [String], label: String? = nil) {
|
|
311
|
-
self.id = id
|
|
312
|
-
self.tables = tables
|
|
313
|
-
self.label = label
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
public func jsonString() throws -> String {
|
|
317
|
-
let encoder = JSONEncoder()
|
|
318
|
-
encoder.outputFormatting = [.sortedKeys]
|
|
319
|
-
return String(data: try encoder.encode(self), encoding: .utf8)!
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
public struct SyncularChangedCrdtField: Decodable, Equatable {
|
|
324
|
-
public let field: String
|
|
325
|
-
public let stateColumn: String
|
|
326
|
-
public let containerKey: String
|
|
327
|
-
public let rowIdField: String
|
|
328
|
-
public let kind: String
|
|
329
|
-
public let syncMode: String
|
|
330
|
-
|
|
331
|
-
public init(field: String, stateColumn: String, containerKey: String, rowIdField: String, kind: String, syncMode: String) {
|
|
332
|
-
self.field = field
|
|
333
|
-
self.stateColumn = stateColumn
|
|
334
|
-
self.containerKey = containerKey
|
|
335
|
-
self.rowIdField = rowIdField
|
|
336
|
-
self.kind = kind
|
|
337
|
-
self.syncMode = syncMode
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
public struct SyncularChangedRow: Decodable, Equatable {
|
|
342
|
-
public let table: String
|
|
343
|
-
public let rowId: String?
|
|
344
|
-
public let operation: String
|
|
345
|
-
public let changedFields: [String]
|
|
346
|
-
public let crdtFields: [String]
|
|
347
|
-
public let crdtFieldChanges: [SyncularChangedCrdtField]
|
|
348
|
-
public let commitId: String?
|
|
349
|
-
public let commitSeq: Int64?
|
|
350
|
-
public let subscriptionId: String?
|
|
351
|
-
public let serverVersion: Int64?
|
|
352
|
-
|
|
353
|
-
public init(table: String, rowId: String? = nil, operation: String, changedFields: [String] = [], crdtFields: [String] = [], crdtFieldChanges: [SyncularChangedCrdtField] = [], commitId: String? = nil, commitSeq: Int64? = nil, subscriptionId: String? = nil, serverVersion: Int64? = nil) {
|
|
354
|
-
self.table = table
|
|
355
|
-
self.rowId = rowId
|
|
356
|
-
self.operation = operation
|
|
357
|
-
self.changedFields = changedFields
|
|
358
|
-
self.crdtFields = crdtFields
|
|
359
|
-
self.crdtFieldChanges = crdtFieldChanges
|
|
360
|
-
self.commitId = commitId
|
|
361
|
-
self.commitSeq = commitSeq
|
|
362
|
-
self.subscriptionId = subscriptionId
|
|
363
|
-
self.serverVersion = serverVersion
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
public init(from decoder: Decoder) throws {
|
|
367
|
-
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
368
|
-
table = try container.decode(String.self, forKey: .table)
|
|
369
|
-
rowId = try container.decodeIfPresent(String.self, forKey: .rowId)
|
|
370
|
-
operation = try container.decode(String.self, forKey: .operation)
|
|
371
|
-
changedFields = try container.decodeIfPresent([String].self, forKey: .changedFields) ?? []
|
|
372
|
-
crdtFields = try container.decodeIfPresent([String].self, forKey: .crdtFields) ?? []
|
|
373
|
-
crdtFieldChanges = try container.decodeIfPresent([SyncularChangedCrdtField].self, forKey: .crdtFieldChanges) ?? []
|
|
374
|
-
commitId = try container.decodeIfPresent(String.self, forKey: .commitId)
|
|
375
|
-
commitSeq = try container.decodeIfPresent(Int64.self, forKey: .commitSeq)
|
|
376
|
-
subscriptionId = try container.decodeIfPresent(String.self, forKey: .subscriptionId)
|
|
377
|
-
serverVersion = try container.decodeIfPresent(Int64.self, forKey: .serverVersion)
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
private enum CodingKeys: String, CodingKey {
|
|
381
|
-
case table
|
|
382
|
-
case rowId
|
|
383
|
-
case operation
|
|
384
|
-
case changedFields
|
|
385
|
-
case crdtFields
|
|
386
|
-
case crdtFieldChanges
|
|
387
|
-
case commitId
|
|
388
|
-
case commitSeq
|
|
389
|
-
case subscriptionId
|
|
390
|
-
case serverVersion
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
public struct SyncularBootstrapState: Decodable, Equatable {
|
|
395
|
-
public let asOfCommitSeq: Int64
|
|
396
|
-
public let tables: [String]
|
|
397
|
-
public let tableIndex: Int64
|
|
398
|
-
public let rowCursor: String?
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
public struct SyncularBootstrapSubscriptionStatus: Decodable, Equatable {
|
|
402
|
-
public let id: String
|
|
403
|
-
public let table: String
|
|
404
|
-
public let expected: Bool
|
|
405
|
-
public let ready: Bool
|
|
406
|
-
public let status: String?
|
|
407
|
-
public let phase: String
|
|
408
|
-
public let progressPercent: Int64
|
|
409
|
-
public let cursor: Int64?
|
|
410
|
-
public let bootstrapState: SyncularBootstrapState?
|
|
411
|
-
public let bootstrapPhase: Int64
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
public struct SyncularBootstrapPhaseStatus: Decodable, Equatable {
|
|
415
|
-
public let phase: Int64
|
|
416
|
-
public let expectedSubscriptionIds: [String]
|
|
417
|
-
public let readySubscriptionIds: [String]
|
|
418
|
-
public let pendingSubscriptionIds: [String]
|
|
419
|
-
public let isReady: Bool
|
|
420
|
-
public let progressPercent: Int64
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
public struct SyncularBootstrapStatus: Decodable, Equatable {
|
|
424
|
-
public let channelPhase: String
|
|
425
|
-
public let progressPercent: Int64
|
|
426
|
-
public let isBootstrapping: Bool
|
|
427
|
-
public let criticalReady: Bool
|
|
428
|
-
public let interactiveReady: Bool
|
|
429
|
-
public let complete: Bool
|
|
430
|
-
public let activePhase: Int64?
|
|
431
|
-
public let expectedSubscriptionIds: [String]
|
|
432
|
-
public let readySubscriptionIds: [String]
|
|
433
|
-
public let pendingSubscriptionIds: [String]
|
|
434
|
-
public let subscriptions: [SyncularBootstrapSubscriptionStatus]
|
|
435
|
-
public let phases: [SyncularBootstrapPhaseStatus]
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
public struct SyncularNativeErrorInfo: Decodable, Equatable {
|
|
439
|
-
public let kind: String
|
|
440
|
-
public let code: String
|
|
441
|
-
public let category: String
|
|
442
|
-
public let retryable: Bool
|
|
443
|
-
public let recommendedAction: String
|
|
444
|
-
public let message: String
|
|
445
|
-
public let debug: String?
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
public struct SyncularNativeLifecycleBootstrap: Decodable, Equatable {
|
|
449
|
-
public let complete: Bool
|
|
450
|
-
public let criticalReady: Bool
|
|
451
|
-
public let interactiveReady: Bool
|
|
452
|
-
public let isBootstrapping: Bool
|
|
453
|
-
public let progressPercent: Int64
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
public struct SyncularNativeLifecycleOutbox: Decodable, Equatable {
|
|
457
|
-
public let pending: UInt64
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
public struct SyncularNativeLifecycleConflicts: Decodable, Equatable {
|
|
461
|
-
public let unresolved: UInt64
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
public struct SyncularNativeLifecycleBlobUploads: Decodable, Equatable {
|
|
465
|
-
public let pending: Int64
|
|
466
|
-
public let uploading: Int64
|
|
467
|
-
public let failed: Int64
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
public struct SyncularNativeLifecycleState: Decodable, Equatable {
|
|
471
|
-
public let phase: String
|
|
472
|
-
public let online: Bool
|
|
473
|
-
public let requiresAction: Bool
|
|
474
|
-
public let pendingRequests: UInt64
|
|
475
|
-
public let bootstrap: SyncularNativeLifecycleBootstrap?
|
|
476
|
-
public let outbox: SyncularNativeLifecycleOutbox?
|
|
477
|
-
public let conflicts: SyncularNativeLifecycleConflicts?
|
|
478
|
-
public let blobUploads: SyncularNativeLifecycleBlobUploads?
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
public struct SyncularNativeEvent: Decodable, Equatable {
|
|
482
|
-
public let eventSeq: UInt64
|
|
483
|
-
public let kind: String
|
|
484
|
-
public let error: SyncularNativeErrorInfo?
|
|
485
|
-
public let tables: [String]
|
|
486
|
-
public let queries: [String]
|
|
487
|
-
public let changedRows: [SyncularChangedRow]
|
|
488
|
-
public let commandId: String?
|
|
489
|
-
public let clientCommitId: String?
|
|
490
|
-
public let durationMs: UInt64?
|
|
491
|
-
public let droppedCount: UInt64?
|
|
492
|
-
public let bootstrap: SyncularBootstrapStatus?
|
|
493
|
-
public let lifecycle: SyncularNativeLifecycleState?
|
|
494
|
-
public let resyncRequired: Bool
|
|
495
|
-
|
|
496
|
-
public init(eventSeq: UInt64 = 0, kind: String, error: SyncularNativeErrorInfo? = nil, tables: [String] = [], queries: [String] = [], changedRows: [SyncularChangedRow] = [], commandId: String? = nil, clientCommitId: String? = nil, durationMs: UInt64? = nil, droppedCount: UInt64? = nil, bootstrap: SyncularBootstrapStatus? = nil, lifecycle: SyncularNativeLifecycleState? = nil, resyncRequired: Bool = false) {
|
|
497
|
-
self.eventSeq = eventSeq
|
|
498
|
-
self.kind = kind
|
|
499
|
-
self.error = error
|
|
500
|
-
self.tables = tables
|
|
501
|
-
self.queries = queries
|
|
502
|
-
self.changedRows = changedRows
|
|
503
|
-
self.commandId = commandId
|
|
504
|
-
self.clientCommitId = clientCommitId
|
|
505
|
-
self.durationMs = durationMs
|
|
506
|
-
self.droppedCount = droppedCount
|
|
507
|
-
self.bootstrap = bootstrap
|
|
508
|
-
self.lifecycle = lifecycle
|
|
509
|
-
self.resyncRequired = resyncRequired
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
private enum CodingKeys: String, CodingKey {
|
|
513
|
-
case eventSeq = "event_seq"
|
|
514
|
-
case kind
|
|
515
|
-
case error
|
|
516
|
-
case tables
|
|
517
|
-
case queries
|
|
518
|
-
case changedRows
|
|
519
|
-
case commandId = "command_id"
|
|
520
|
-
case clientCommitId = "client_commit_id"
|
|
521
|
-
case durationMs = "duration_ms"
|
|
522
|
-
case droppedCount
|
|
523
|
-
case bootstrap
|
|
524
|
-
case lifecycle
|
|
525
|
-
case resyncRequired
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
public init(from decoder: Decoder) throws {
|
|
529
|
-
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
530
|
-
eventSeq = try container.decodeIfPresent(UInt64.self, forKey: .eventSeq) ?? 0
|
|
531
|
-
kind = try container.decode(String.self, forKey: .kind)
|
|
532
|
-
error = try container.decodeIfPresent(SyncularNativeErrorInfo.self, forKey: .error)
|
|
533
|
-
tables = try container.decodeIfPresent([String].self, forKey: .tables) ?? []
|
|
534
|
-
queries = try container.decodeIfPresent([String].self, forKey: .queries) ?? []
|
|
535
|
-
changedRows = try container.decodeIfPresent([SyncularChangedRow].self, forKey: .changedRows) ?? []
|
|
536
|
-
commandId = try container.decodeIfPresent(String.self, forKey: .commandId)
|
|
537
|
-
clientCommitId = try container.decodeIfPresent(String.self, forKey: .clientCommitId)
|
|
538
|
-
durationMs = try container.decodeIfPresent(UInt64.self, forKey: .durationMs)
|
|
539
|
-
droppedCount = try container.decodeIfPresent(UInt64.self, forKey: .droppedCount)
|
|
540
|
-
bootstrap = try container.decodeIfPresent(SyncularBootstrapStatus.self, forKey: .bootstrap)
|
|
541
|
-
lifecycle = try container.decodeIfPresent(SyncularNativeLifecycleState.self, forKey: .lifecycle)
|
|
542
|
-
resyncRequired = (try container.decodeIfPresent(Bool.self, forKey: .resyncRequired)) ?? (kind == "EventsOverflowed")
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
public var eventStreamLost: Bool {
|
|
546
|
-
kind == "EventsOverflowed" || resyncRequired
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
public func syncularDecodeNativeEvent(_ eventJson: String) throws -> SyncularNativeEvent {
|
|
551
|
-
try JSONDecoder().decode(SyncularNativeEvent.self, from: Data(eventJson.utf8))
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
public func syncularNativeEventRequiresFullRefresh(_ event: SyncularNativeEvent) -> Bool {
|
|
555
|
-
event.eventStreamLost
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
public protocol SyncularNativeEventJsonSource {
|
|
559
|
-
func eventJsonStream(capacity: UInt64) -> AsyncThrowingStream<String, Error>
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
public func syncularNativeEventStream(from source: SyncularNativeEventJsonSource, capacity: UInt64 = 256) -> AsyncThrowingStream<SyncularNativeEvent, Error> {
|
|
563
|
-
AsyncThrowingStream { continuation in
|
|
564
|
-
let task = Task {
|
|
565
|
-
do {
|
|
566
|
-
for try await eventJson in source.eventJsonStream(capacity: capacity) {
|
|
567
|
-
continuation.yield(try syncularDecodeNativeEvent(eventJson))
|
|
568
|
-
}
|
|
569
|
-
continuation.finish()
|
|
570
|
-
} catch {
|
|
571
|
-
continuation.finish(throwing: error)
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
continuation.onTermination = { _ in task.cancel() }
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
public struct TaskChangedFields: Equatable {
|
|
579
|
-
public let raw: Set<String>
|
|
580
|
-
public let id: Bool
|
|
581
|
-
public let title: Bool
|
|
582
|
-
public let completed: Bool
|
|
583
|
-
public let userId: Bool
|
|
584
|
-
public let createdAt: Bool
|
|
585
|
-
public let serverVersion: Bool
|
|
586
|
-
|
|
587
|
-
public init(_ fields: [String]) {
|
|
588
|
-
let raw = Set(fields)
|
|
589
|
-
self.raw = raw
|
|
590
|
-
self.id = raw.contains("id")
|
|
591
|
-
self.title = raw.contains("title")
|
|
592
|
-
self.completed = raw.contains("completed")
|
|
593
|
-
self.userId = raw.contains("user_id")
|
|
594
|
-
self.createdAt = raw.contains("created_at")
|
|
595
|
-
self.serverVersion = raw.contains("server_version")
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
public func contains(_ column: String) -> Bool {
|
|
599
|
-
switch column {
|
|
600
|
-
case "id": id
|
|
601
|
-
case "title": title
|
|
602
|
-
case "completed": completed
|
|
603
|
-
case "user_id": userId
|
|
604
|
-
case "created_at": createdAt
|
|
605
|
-
case "server_version": serverVersion
|
|
606
|
-
default: false
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
public struct TaskChangedRow: Equatable {
|
|
612
|
-
public let raw: SyncularChangedRow
|
|
613
|
-
public let changed: TaskChangedFields
|
|
614
|
-
public let crdt: TaskChangedFields
|
|
615
|
-
|
|
616
|
-
public var rowId: String? { raw.rowId }
|
|
617
|
-
public var operation: String { raw.operation }
|
|
618
|
-
public var isInsert: Bool { raw.operation == "insert" }
|
|
619
|
-
public var isUpdate: Bool { raw.operation == "update" }
|
|
620
|
-
public var isDelete: Bool { raw.operation == "delete" }
|
|
621
|
-
|
|
622
|
-
public init?(_ row: SyncularChangedRow) {
|
|
623
|
-
guard row.table == "tasks" else { return nil }
|
|
624
|
-
self.raw = row
|
|
625
|
-
self.changed = TaskChangedFields(row.changedFields)
|
|
626
|
-
self.crdt = TaskChangedFields(row.crdtFields)
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
public func taskChangedRows(_ rows: [SyncularChangedRow]) -> [TaskChangedRow] {
|
|
631
|
-
rows.compactMap(TaskChangedRow.init)
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
public func taskChangedRows(in event: SyncularNativeEvent) -> [TaskChangedRow] {
|
|
635
|
-
taskChangedRows(event.changedRows)
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
public struct SyncularGeneratedOperation: Codable, Equatable {
|
|
639
|
-
public let table: String
|
|
640
|
-
public let rowId: String
|
|
641
|
-
public let op: SyncularGeneratedOperationKind
|
|
642
|
-
public let payload: [String: SyncularJsonValue]?
|
|
643
|
-
public let baseVersion: Int64?
|
|
644
|
-
|
|
645
|
-
public init(table: String, rowId: String, op: SyncularGeneratedOperationKind, payload: [String: SyncularJsonValue]?, baseVersion: Int64?) {
|
|
646
|
-
self.table = table
|
|
647
|
-
self.rowId = rowId
|
|
648
|
-
self.op = op
|
|
649
|
-
self.payload = payload
|
|
650
|
-
self.baseVersion = baseVersion
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
private enum CodingKeys: String, CodingKey {
|
|
654
|
-
case table
|
|
655
|
-
case rowId = "row_id"
|
|
656
|
-
case op
|
|
657
|
-
case payload
|
|
658
|
-
case baseVersion = "base_version"
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
public func jsonString() throws -> String {
|
|
662
|
-
let encoder = JSONEncoder()
|
|
663
|
-
encoder.outputFormatting = [.sortedKeys]
|
|
664
|
-
return String(data: try encoder.encode(self), encoding: .utf8)!
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
public func encode(to encoder: Encoder) throws {
|
|
668
|
-
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
669
|
-
try container.encode(table, forKey: .table)
|
|
670
|
-
try container.encode(rowId, forKey: .rowId)
|
|
671
|
-
try container.encode(op, forKey: .op)
|
|
672
|
-
if let payload {
|
|
673
|
-
try container.encode(payload, forKey: .payload)
|
|
674
|
-
} else {
|
|
675
|
-
try container.encodeNil(forKey: .payload)
|
|
676
|
-
}
|
|
677
|
-
if let baseVersion {
|
|
678
|
-
try container.encode(baseVersion, forKey: .baseVersion)
|
|
679
|
-
} else {
|
|
680
|
-
try container.encodeNil(forKey: .baseVersion)
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
public struct SyncularFieldEncryptionRule: Codable, Equatable {
|
|
686
|
-
public let scope: String
|
|
687
|
-
public let table: String?
|
|
688
|
-
public let fields: [String]
|
|
689
|
-
public let rowIdField: String?
|
|
690
|
-
|
|
691
|
-
public init(scope: String, table: String?, fields: [String], rowIdField: String?) {
|
|
692
|
-
self.scope = scope
|
|
693
|
-
self.table = table
|
|
694
|
-
self.fields = fields
|
|
695
|
-
self.rowIdField = rowIdField
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
public struct SyncularFieldEncryptionConfig: Codable, Equatable {
|
|
700
|
-
public let rules: [SyncularFieldEncryptionRule]
|
|
701
|
-
public let keys: [String: String]
|
|
702
|
-
public let encryptionKid: String?
|
|
703
|
-
public let decryptionErrorMode: String?
|
|
704
|
-
public let envelopePrefix: String?
|
|
705
|
-
|
|
706
|
-
public init(keys: [String: String], rules: [SyncularFieldEncryptionRule] = syncularGeneratedFieldEncryptionRules, encryptionKid: String? = nil, decryptionErrorMode: String? = nil, envelopePrefix: String? = nil) {
|
|
707
|
-
self.rules = rules
|
|
708
|
-
self.keys = keys
|
|
709
|
-
self.encryptionKid = encryptionKid
|
|
710
|
-
self.decryptionErrorMode = decryptionErrorMode
|
|
711
|
-
self.envelopePrefix = envelopePrefix
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
public func jsonString() throws -> String {
|
|
715
|
-
let encoder = JSONEncoder()
|
|
716
|
-
encoder.outputFormatting = [.sortedKeys]
|
|
717
|
-
return String(data: try encoder.encode(self), encoding: .utf8)!
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
public let syncularGeneratedFieldEncryptionRules: [SyncularFieldEncryptionRule] = [
|
|
722
|
-
]
|
|
723
|
-
|
|
724
|
-
public func syncularGeneratedFieldEncryptionConfigJson(keys: [String: String], encryptionKid: String? = nil, decryptionErrorMode: String? = nil, envelopePrefix: String? = nil) throws -> String {
|
|
725
|
-
try SyncularFieldEncryptionConfig(keys: keys, rules: syncularGeneratedFieldEncryptionRules, encryptionKid: encryptionKid, decryptionErrorMode: decryptionErrorMode, envelopePrefix: envelopePrefix).jsonString()
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
public protocol SyncularNativeJsonClient {
|
|
729
|
-
func applyMutationJson(mutationJson: String, localRowJson: String?) throws -> String
|
|
730
|
-
func applyLeasedMutationJson(mutationJson: String, localRowJson: String?) throws -> String
|
|
731
|
-
func enqueueMutationJson(mutationJson: String, localRowJson: String?) throws -> String
|
|
732
|
-
func enqueueLeasedMutationJson(mutationJson: String, localRowJson: String?) throws -> String
|
|
733
|
-
func issueAuthLeaseJson(requestJson: String) throws -> String
|
|
734
|
-
func queryJson(requestJson: String) throws -> String
|
|
735
|
-
func registerQueryJson(queryJson: String) throws -> String
|
|
736
|
-
func unregisterQuery(id: String) throws -> Bool
|
|
737
|
-
func diagnosticSnapshotJson() throws -> String
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
public extension SyncularNativeJsonClient {
|
|
741
|
-
func apply(_ operation: SyncularGeneratedOperation, localRowJson: String? = nil) throws -> String {
|
|
742
|
-
try applyMutationJson(mutationJson: operation.jsonString(), localRowJson: localRowJson)
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
func applyLeased(_ operation: SyncularGeneratedOperation, localRowJson: String? = nil) throws -> String {
|
|
746
|
-
try applyLeasedMutationJson(mutationJson: operation.jsonString(), localRowJson: localRowJson)
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
func enqueue(_ operation: SyncularGeneratedOperation, localRowJson: String? = nil) throws -> String {
|
|
750
|
-
try enqueueMutationJson(mutationJson: operation.jsonString(), localRowJson: localRowJson)
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
func enqueueLeased(_ operation: SyncularGeneratedOperation, localRowJson: String? = nil) throws -> String {
|
|
754
|
-
try enqueueLeasedMutationJson(mutationJson: operation.jsonString(), localRowJson: localRowJson)
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
func issueAuthLease(_ request: SyncularAuthLeaseIssueRequest) throws -> SyncularAuthLeaseRecord {
|
|
758
|
-
try syncularDecodeJson(issueAuthLeaseJson(requestJson: request.jsonString()), as: SyncularAuthLeaseRecord.self)
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
func diagnosticSnapshot() throws -> SyncularJsonValue {
|
|
762
|
-
try syncularDecodeJson(diagnosticSnapshotJson(), as: SyncularJsonValue.self)
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
func query<Row: Decodable>(_ query: SyncularReadonlyQuery, as type: Row.Type) throws -> [Row] {
|
|
766
|
-
try syncularDecodeQueryRows(queryJson(requestJson: query.jsonString()), as: Row.self)
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
func registerLiveQuery(_ registration: SyncularLiveQueryRegistration) throws -> String {
|
|
770
|
-
try registerQueryJson(queryJson: registration.jsonString())
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
public final class SyncularNativeLiveQuery<Row: Decodable> {
|
|
775
|
-
public let id: String
|
|
776
|
-
public let query: SyncularReadonlyQuery
|
|
777
|
-
public let label: String?
|
|
778
|
-
public private(set) var rows: [Row] = []
|
|
779
|
-
private let rowType: Row.Type
|
|
780
|
-
|
|
781
|
-
public init(id: String, query: SyncularReadonlyQuery, as rowType: Row.Type, label: String? = nil) {
|
|
782
|
-
self.id = id
|
|
783
|
-
self.query = query
|
|
784
|
-
self.label = label
|
|
785
|
-
self.rowType = rowType
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
@discardableResult
|
|
789
|
-
public func start(on client: SyncularNativeJsonClient) throws -> [Row] {
|
|
790
|
-
_ = try client.registerLiveQuery(SyncularLiveQueryRegistration(id: id, tables: query.tables, label: label))
|
|
791
|
-
return try refresh(on: client)
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
@discardableResult
|
|
795
|
-
public func refresh(on client: SyncularNativeJsonClient) throws -> [Row] {
|
|
796
|
-
rows = try client.query(query, as: rowType)
|
|
797
|
-
return rows
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
@discardableResult
|
|
801
|
-
public func stop(on client: SyncularNativeJsonClient) throws -> Bool {
|
|
802
|
-
try client.unregisterQuery(id: id)
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
public func matches(queryIds: [String]) -> Bool {
|
|
806
|
-
queryIds.contains(id)
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
@discardableResult
|
|
810
|
-
public func refreshIfChanged(event: SyncularNativeEvent, on client: SyncularNativeJsonClient) throws -> [Row]? {
|
|
811
|
-
if syncularNativeEventRequiresFullRefresh(event) {
|
|
812
|
-
return try refresh(on: client)
|
|
813
|
-
}
|
|
814
|
-
guard event.kind == "QueriesChanged", matches(queryIds: event.queries) else {
|
|
815
|
-
return nil
|
|
816
|
-
}
|
|
817
|
-
return try refresh(on: client)
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
@discardableResult
|
|
821
|
-
public func refreshIfChanged(eventJson: String, on client: SyncularNativeJsonClient) throws -> [Row]? {
|
|
822
|
-
try refreshIfChanged(event: syncularDecodeNativeEvent(eventJson), on: client)
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
private func syncularDecodeJson<T: Decodable>(_ json: String, as type: T.Type) throws -> T {
|
|
827
|
-
try JSONDecoder().decode(T.self, from: Data(json.utf8))
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
private struct SyncularQueryResult<Row: Decodable>: Decodable {
|
|
831
|
-
let rows: [Row]
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
private func syncularDecodeQueryRows<Row: Decodable>(_ json: String, as type: Row.Type) throws -> [Row] {
|
|
835
|
-
try JSONDecoder().decode(SyncularQueryResult<Row>.self, from: Data(json.utf8)).rows
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
public protocol SyncularQueryValue {
|
|
839
|
-
var syncularJsonValue: SyncularJsonValue { get }
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
extension String: SyncularQueryValue { public var syncularJsonValue: SyncularJsonValue { .string(self) } }
|
|
843
|
-
extension Int: SyncularQueryValue { public var syncularJsonValue: SyncularJsonValue { .int(Int64(self)) } }
|
|
844
|
-
extension Int64: SyncularQueryValue { public var syncularJsonValue: SyncularJsonValue { .int(self) } }
|
|
845
|
-
extension Double: SyncularQueryValue { public var syncularJsonValue: SyncularJsonValue { .double(self) } }
|
|
846
|
-
extension Bool: SyncularQueryValue { public var syncularJsonValue: SyncularJsonValue { .bool(self) } }
|
|
847
|
-
|
|
848
|
-
extension SyncularBlobRef: SyncularQueryValue { public var syncularJsonValue: SyncularJsonValue { .string((try? jsonString()) ?? "{}") } }
|
|
849
|
-
|
|
850
|
-
public struct SyncularQueryPredicate: Equatable {
|
|
851
|
-
public let sql: String
|
|
852
|
-
public let params: [SyncularJsonValue]
|
|
853
|
-
|
|
854
|
-
public init(sql: String, params: [SyncularJsonValue] = []) {
|
|
855
|
-
self.sql = sql
|
|
856
|
-
self.params = params
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
public func and(_ other: SyncularQueryPredicate) -> SyncularQueryPredicate {
|
|
860
|
-
SyncularQueryPredicate(sql: "((\(sql)) and (\(other.sql)))", params: params + other.params)
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
public func or(_ other: SyncularQueryPredicate) -> SyncularQueryPredicate {
|
|
864
|
-
SyncularQueryPredicate(sql: "((\(sql)) or (\(other.sql)))", params: params + other.params)
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
public struct SyncularQueryOrder: Equatable {
|
|
869
|
-
public let sql: String
|
|
870
|
-
|
|
871
|
-
public init(sql: String) {
|
|
872
|
-
self.sql = sql
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
public struct SyncularQueryColumn<Value>: Equatable {
|
|
877
|
-
public let table: String
|
|
878
|
-
public let name: String
|
|
879
|
-
|
|
880
|
-
public init(table: String, name: String) {
|
|
881
|
-
self.table = table
|
|
882
|
-
self.name = name
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
public func eq(_ value: Value) -> SyncularQueryPredicate where Value: SyncularQueryValue {
|
|
886
|
-
SyncularQueryPredicate(sql: "\(syncularQuoteIdentifier(name)) = ?", params: [value.syncularJsonValue])
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
public func notEq(_ value: Value) -> SyncularQueryPredicate where Value: SyncularQueryValue {
|
|
890
|
-
SyncularQueryPredicate(sql: "\(syncularQuoteIdentifier(name)) != ?", params: [value.syncularJsonValue])
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
public func gt(_ value: Value) -> SyncularQueryPredicate where Value: SyncularQueryValue {
|
|
894
|
-
SyncularQueryPredicate(sql: "\(syncularQuoteIdentifier(name)) > ?", params: [value.syncularJsonValue])
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
public func gte(_ value: Value) -> SyncularQueryPredicate where Value: SyncularQueryValue {
|
|
898
|
-
SyncularQueryPredicate(sql: "\(syncularQuoteIdentifier(name)) >= ?", params: [value.syncularJsonValue])
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
public func lt(_ value: Value) -> SyncularQueryPredicate where Value: SyncularQueryValue {
|
|
902
|
-
SyncularQueryPredicate(sql: "\(syncularQuoteIdentifier(name)) < ?", params: [value.syncularJsonValue])
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
public func lte(_ value: Value) -> SyncularQueryPredicate where Value: SyncularQueryValue {
|
|
906
|
-
SyncularQueryPredicate(sql: "\(syncularQuoteIdentifier(name)) <= ?", params: [value.syncularJsonValue])
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
public func isNull() -> SyncularQueryPredicate {
|
|
910
|
-
SyncularQueryPredicate(sql: "\(syncularQuoteIdentifier(name)) is null", params: [])
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
public func isNotNull() -> SyncularQueryPredicate {
|
|
914
|
-
SyncularQueryPredicate(sql: "\(syncularQuoteIdentifier(name)) is not null", params: [])
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
public func isIn(_ values: [Value]) -> SyncularQueryPredicate where Value: SyncularQueryValue {
|
|
918
|
-
guard !values.isEmpty else { return SyncularQueryPredicate(sql: "0 = 1") }
|
|
919
|
-
let placeholders = Array(repeating: "?", count: values.count).joined(separator: ", ")
|
|
920
|
-
return SyncularQueryPredicate(sql: "\(syncularQuoteIdentifier(name)) in (\(placeholders))", params: values.map(\.syncularJsonValue))
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
public func notIn(_ values: [Value]) -> SyncularQueryPredicate where Value: SyncularQueryValue {
|
|
924
|
-
guard !values.isEmpty else { return SyncularQueryPredicate(sql: "1 = 1") }
|
|
925
|
-
let placeholders = Array(repeating: "?", count: values.count).joined(separator: ", ")
|
|
926
|
-
return SyncularQueryPredicate(sql: "\(syncularQuoteIdentifier(name)) not in (\(placeholders))", params: values.map(\.syncularJsonValue))
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
public func asc() -> SyncularQueryOrder {
|
|
930
|
-
SyncularQueryOrder(sql: "\(syncularQuoteIdentifier(name)) asc")
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
public func desc() -> SyncularQueryOrder {
|
|
934
|
-
SyncularQueryOrder(sql: "\(syncularQuoteIdentifier(name)) desc")
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
public struct SyncularQueryTable<Row: Decodable>: Equatable {
|
|
939
|
-
public let name: String
|
|
940
|
-
public let columns: [String]
|
|
941
|
-
|
|
942
|
-
public init(name: String, columns: [String]) {
|
|
943
|
-
self.name = name
|
|
944
|
-
self.columns = columns
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
public func select() -> SyncularSelectQuery<Row> {
|
|
948
|
-
SyncularSelectQuery(table: self)
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
public struct SyncularSelectQuery<Row: Decodable>: Equatable {
|
|
953
|
-
public let table: SyncularQueryTable<Row>
|
|
954
|
-
public let predicates: [SyncularQueryPredicate]
|
|
955
|
-
public let orders: [SyncularQueryOrder]
|
|
956
|
-
public let limitValue: Int?
|
|
957
|
-
|
|
958
|
-
public init(table: SyncularQueryTable<Row>, predicates: [SyncularQueryPredicate] = [], orders: [SyncularQueryOrder] = [], limitValue: Int? = nil) {
|
|
959
|
-
self.table = table
|
|
960
|
-
self.predicates = predicates
|
|
961
|
-
self.orders = orders
|
|
962
|
-
self.limitValue = limitValue
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
public func filter(_ predicate: SyncularQueryPredicate) -> Self {
|
|
966
|
-
Self(table: table, predicates: predicates + [predicate], orders: orders, limitValue: limitValue)
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
public func orderBy(_ order: SyncularQueryOrder) -> Self {
|
|
970
|
-
Self(table: table, predicates: predicates, orders: orders + [order], limitValue: limitValue)
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
public func limit(_ value: Int) -> Self {
|
|
974
|
-
Self(table: table, predicates: predicates, orders: orders, limitValue: value)
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
public func readonlyQuery() -> SyncularReadonlyQuery {
|
|
978
|
-
let columnSql = table.columns.map(syncularQuoteIdentifier).joined(separator: ", ")
|
|
979
|
-
var sql = "select \(columnSql) from \(syncularQuoteIdentifier(table.name))"
|
|
980
|
-
var params: [SyncularJsonValue] = []
|
|
981
|
-
if !predicates.isEmpty {
|
|
982
|
-
sql += " where " + predicates.map(\.sql).joined(separator: " and ")
|
|
983
|
-
params = predicates.flatMap(\.params)
|
|
984
|
-
}
|
|
985
|
-
if !orders.isEmpty {
|
|
986
|
-
sql += " order by " + orders.map(\.sql).joined(separator: ", ")
|
|
987
|
-
}
|
|
988
|
-
if let limitValue {
|
|
989
|
-
sql += " limit \(limitValue)"
|
|
990
|
-
}
|
|
991
|
-
return SyncularReadonlyQuery(sql: sql, params: params, tables: [table.name])
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
public func fetch(on client: SyncularNativeJsonClient) throws -> [Row] {
|
|
995
|
-
try client.query(readonlyQuery(), as: Row.self)
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
public func liveQuery(id: String, label: String? = nil) -> SyncularNativeLiveQuery<Row> {
|
|
999
|
-
SyncularNativeLiveQuery(id: id, query: readonlyQuery(), as: Row.self, label: label)
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
private func syncularQuoteIdentifier(_ identifier: String) -> String {
|
|
1004
|
-
"\"" + identifier.replacingOccurrences(of: "\"", with: "\"\"") + "\""
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
public struct TaskRow: Codable, Equatable {
|
|
1008
|
-
public let id: String
|
|
1009
|
-
public let title: String
|
|
1010
|
-
public let completed: Int64
|
|
1011
|
-
public let userId: String
|
|
1012
|
-
public let createdAt: Int64
|
|
1013
|
-
public let serverVersion: Int64
|
|
1014
|
-
|
|
1015
|
-
private enum CodingKeys: String, CodingKey {
|
|
1016
|
-
case id
|
|
1017
|
-
case title
|
|
1018
|
-
case completed
|
|
1019
|
-
case userId = "user_id"
|
|
1020
|
-
case createdAt = "created_at"
|
|
1021
|
-
case serverVersion = "server_version"
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
public struct NewTask: Codable, Equatable {
|
|
1026
|
-
public let id: String
|
|
1027
|
-
public let title: String
|
|
1028
|
-
public let completed: Int64?
|
|
1029
|
-
public let userId: String
|
|
1030
|
-
public let createdAt: Int64?
|
|
1031
|
-
|
|
1032
|
-
public init(id: String, title: String, completed: Int64? = nil, userId: String, createdAt: Int64? = nil) {
|
|
1033
|
-
self.id = id
|
|
1034
|
-
self.title = title
|
|
1035
|
-
self.completed = completed
|
|
1036
|
-
self.userId = userId
|
|
1037
|
-
self.createdAt = createdAt
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
private enum CodingKeys: String, CodingKey {
|
|
1041
|
-
case id
|
|
1042
|
-
case title
|
|
1043
|
-
case completed
|
|
1044
|
-
case userId = "user_id"
|
|
1045
|
-
case createdAt = "created_at"
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
public struct TaskPatch: Codable, Equatable {
|
|
1050
|
-
public let title: String?
|
|
1051
|
-
public let completed: Int64?
|
|
1052
|
-
public let userId: String?
|
|
1053
|
-
public let createdAt: Int64?
|
|
1054
|
-
|
|
1055
|
-
public init(title: String? = nil, completed: Int64? = nil, userId: String? = nil, createdAt: Int64? = nil) {
|
|
1056
|
-
self.title = title
|
|
1057
|
-
self.completed = completed
|
|
1058
|
-
self.userId = userId
|
|
1059
|
-
self.createdAt = createdAt
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
private enum CodingKeys: String, CodingKey {
|
|
1063
|
-
case title
|
|
1064
|
-
case completed
|
|
1065
|
-
case userId = "user_id"
|
|
1066
|
-
case createdAt = "created_at"
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
public enum TaskQuery {
|
|
1071
|
-
public static let table = SyncularQueryTable<TaskRow>(name: "tasks", columns: ["id", "title", "completed", "user_id", "created_at", "server_version"])
|
|
1072
|
-
public static let id = SyncularQueryColumn<String>(table: "tasks", name: "id")
|
|
1073
|
-
public static let title = SyncularQueryColumn<String>(table: "tasks", name: "title")
|
|
1074
|
-
public static let completed = SyncularQueryColumn<Int64>(table: "tasks", name: "completed")
|
|
1075
|
-
public static let userId = SyncularQueryColumn<String>(table: "tasks", name: "user_id")
|
|
1076
|
-
public static let createdAt = SyncularQueryColumn<Int64>(table: "tasks", name: "created_at")
|
|
1077
|
-
public static let serverVersion = SyncularQueryColumn<Int64>(table: "tasks", name: "server_version")
|
|
1078
|
-
public static func select() -> SyncularSelectQuery<TaskRow> { table.select() }
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
public enum SyncularAppOperations {
|
|
1082
|
-
public static func newTask(_ input: NewTask, baseVersion: Int64? = 0) -> SyncularGeneratedOperation {
|
|
1083
|
-
var payload: [String: SyncularJsonValue] = [:]
|
|
1084
|
-
payload["title"] = .string(input.title)
|
|
1085
|
-
payload["completed"] = .int(input.completed ?? 0)
|
|
1086
|
-
payload["user_id"] = .string(input.userId)
|
|
1087
|
-
payload["created_at"] = .int(input.createdAt ?? 0)
|
|
1088
|
-
return SyncularGeneratedOperation(
|
|
1089
|
-
table: "tasks",
|
|
1090
|
-
rowId: input.id,
|
|
1091
|
-
op: .upsert,
|
|
1092
|
-
payload: payload,
|
|
1093
|
-
baseVersion: baseVersion
|
|
1094
|
-
)
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
public static func patchTask(rowId: String, patch: TaskPatch, baseVersion: Int64? = nil) -> SyncularGeneratedOperation {
|
|
1098
|
-
var payload: [String: SyncularJsonValue] = [:]
|
|
1099
|
-
if let value = patch.title {
|
|
1100
|
-
payload["title"] = .string(value)
|
|
1101
|
-
}
|
|
1102
|
-
if let value = patch.completed {
|
|
1103
|
-
payload["completed"] = .int(value)
|
|
1104
|
-
}
|
|
1105
|
-
if let value = patch.userId {
|
|
1106
|
-
payload["user_id"] = .string(value)
|
|
1107
|
-
}
|
|
1108
|
-
if let value = patch.createdAt {
|
|
1109
|
-
payload["created_at"] = .int(value)
|
|
1110
|
-
}
|
|
1111
|
-
return SyncularGeneratedOperation(
|
|
1112
|
-
table: "tasks",
|
|
1113
|
-
rowId: rowId,
|
|
1114
|
-
op: .upsert,
|
|
1115
|
-
payload: payload,
|
|
1116
|
-
baseVersion: baseVersion
|
|
1117
|
-
)
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
public static func deleteTask(rowId: String, baseVersion: Int64? = nil) -> SyncularGeneratedOperation {
|
|
1121
|
-
SyncularGeneratedOperation(
|
|
1122
|
-
table: "tasks",
|
|
1123
|
-
rowId: rowId,
|
|
1124
|
-
op: .delete,
|
|
1125
|
-
payload: nil,
|
|
1126
|
-
baseVersion: baseVersion
|
|
1127
|
-
)
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
public struct SyncularAppMutations {
|
|
1133
|
-
private let client: SyncularNativeJsonClient
|
|
1134
|
-
private let queued: Bool
|
|
1135
|
-
private let leased: Bool
|
|
1136
|
-
|
|
1137
|
-
init(client: SyncularNativeJsonClient, queued: Bool = false, leased: Bool = false) {
|
|
1138
|
-
self.client = client
|
|
1139
|
-
self.queued = queued
|
|
1140
|
-
self.leased = leased
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
public var tasks: TaskMutations { TaskMutations(client: client, queued: queued, leased: leased) }
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
public extension SyncularNativeJsonClient {
|
|
1147
|
-
var mutations: SyncularAppMutations { SyncularAppMutations(client: self) }
|
|
1148
|
-
var queuedMutations: SyncularAppMutations { SyncularAppMutations(client: self, queued: true) }
|
|
1149
|
-
var leasedMutations: SyncularAppMutations { SyncularAppMutations(client: self, leased: true) }
|
|
1150
|
-
var queuedLeasedMutations: SyncularAppMutations { SyncularAppMutations(client: self, queued: true, leased: true) }
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
public struct TaskMutations {
|
|
1154
|
-
private let client: SyncularNativeJsonClient
|
|
1155
|
-
private let queued: Bool
|
|
1156
|
-
private let leased: Bool
|
|
1157
|
-
|
|
1158
|
-
init(client: SyncularNativeJsonClient, queued: Bool, leased: Bool) {
|
|
1159
|
-
self.client = client
|
|
1160
|
-
self.queued = queued
|
|
1161
|
-
self.leased = leased
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
public func insert(_ input: NewTask, baseVersion: Int64? = 0, localRowJson: String? = nil) throws -> String {
|
|
1165
|
-
let operation = SyncularAppOperations.newTask(input, baseVersion: baseVersion)
|
|
1166
|
-
if queued {
|
|
1167
|
-
return leased ? try client.enqueueLeased(operation, localRowJson: localRowJson) : try client.enqueue(operation, localRowJson: localRowJson)
|
|
1168
|
-
}
|
|
1169
|
-
return leased ? try client.applyLeased(operation, localRowJson: localRowJson) : try client.apply(operation, localRowJson: localRowJson)
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
public func update(rowId: String, patch: TaskPatch, baseVersion: Int64? = nil, localRowJson: String? = nil) throws -> String {
|
|
1173
|
-
let operation = SyncularAppOperations.patchTask(rowId: rowId, patch: patch, baseVersion: baseVersion)
|
|
1174
|
-
if queued {
|
|
1175
|
-
return leased ? try client.enqueueLeased(operation, localRowJson: localRowJson) : try client.enqueue(operation, localRowJson: localRowJson)
|
|
1176
|
-
}
|
|
1177
|
-
return leased ? try client.applyLeased(operation, localRowJson: localRowJson) : try client.apply(operation, localRowJson: localRowJson)
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
public func delete(rowId: String, baseVersion: Int64? = nil) throws -> String {
|
|
1181
|
-
let operation = SyncularAppOperations.deleteTask(rowId: rowId, baseVersion: baseVersion)
|
|
1182
|
-
if queued {
|
|
1183
|
-
return leased ? try client.enqueueLeased(operation) : try client.enqueue(operation)
|
|
1184
|
-
}
|
|
1185
|
-
return leased ? try client.applyLeased(operation) : try client.apply(operation)
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
}
|
|
1189
|
-
|
|
1190
|
-
public extension SyncularNativeJsonClient {
|
|
1191
|
-
}
|