Commit 0ec7848b authored by Ruben Daniels's avatar Ruben Daniels
Browse files

Temp reverted realm and removed ThreadSafeRefs that werent so safe afterall

parent ccc741c6
Showing with 139 additions and 140 deletions
+139 -140
......@@ -2258,7 +2258,7 @@
repositoryURL = "https://github.com/realm/realm-cocoa";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 5.0.0;
minimumVersion = 4.0.0;
};
};
B8FB4994249F21A6007A05C4 /* XCRemoteSwiftPackageReference "ascollectionview" */ = {
......
......@@ -42,8 +42,8 @@
"repositoryURL": "https://github.com/realm/realm-cocoa",
"state": {
"branch": null,
"revision": "ef337f0991255d19e3a14f6c0d718a9f53a55d9a",
"version": "5.3.1"
"revision": "fa43b8e2909334c79f233ce472332c136ca108da",
"version": "4.4.1"
}
},
{
......@@ -51,8 +51,8 @@
"repositoryURL": "https://github.com/realm/realm-core",
"state": {
"branch": null,
"revision": "430bc95a34dd0a72a5ebbdc87d4035f0b43096ae",
"version": "6.0.11"
"revision": "35662ff940e340bf630ad1d1d88acfc7af18bee6",
"version": "5.23.8"
}
}
]
......
......@@ -14,26 +14,25 @@ protocol UniqueString {
var uniqueString: String { get }
}
public class Datasource: SchemaItem, UniqueString {
/// Primary key used in the realm database of this Item
override public static func primaryKey() -> String? {
"uid"
}
public class Datasource: Equatable, UniqueString {
public static func == (lhs: Datasource, rhs: Datasource) -> Bool {
lhs.uniqueString == rhs.uniqueString
}
/// Retrieves the query which is used to load data from the pod
@objc dynamic var query: String?
var query: String?
/// Retrieves the property that is used to sort on
@objc dynamic var sortProperty: String?
var sortProperty: String?
/// Retrieves whether the sort direction
/// - false sort descending
/// - true sort ascending
let sortAscending = RealmOptional<Bool>()
var sortAscending: Bool? = nil
/// Retrieves the number of items per page
let pageCount = RealmOptional<Int>() // Todo move to ResultSet
var pageCount: Int? = nil
let pageIndex = RealmOptional<Int>() // Todo move to ResultSet
var pageIndex: Int? = nil
/// Returns a string representation of the data in QueryOptions that is unique for that data
/// Each QueryOptions object with the same data will return the same uniqueString
var uniqueString: String {
......@@ -42,46 +41,16 @@ public class Datasource: SchemaItem, UniqueString {
result.append((query ?? "").sha256())
result.append(sortProperty ?? "")
let sortAsc = sortAscending.value ?? true
let sortAsc = sortAscending ?? true
result.append(String(sortAsc))
return result.joined(separator: ":")
}
convenience init(query: String) {
self.init()
init(query: String?, sortProperty: String? = nil, sortAscending: Bool? = nil) {
self.query = query
}
required init() {
super.init()
}
required init(from decoder: Decoder) throws {
fatalError("init(from:) has not been implemented")
}
public class func fromCVUDefinition(_ def: CVUParsedDatasourceDefinition,
_ viewArguments: ViewArguments? = nil) throws -> Datasource {
func getValue<T>(_ name: String) throws -> T? {
if let expr = def[name] as? Expression {
do {
let x = try expr.execForReturnType(T.self, args: viewArguments)
return x
} catch {
debugHistory.warn("\(error)")
return nil
}
}
return def[name] as? T
}
return try Cache.createItem(Datasource.self, values: [
"selector": def.selector ?? "[datasource]",
"query": try getValue("query") ?? "",
"sortProperty": try getValue("sortProperty") ?? "",
"sortAscending": try getValue("sortAscending") ?? true,
])
self.sortProperty = sortProperty
self.sortAscending = sortAscending
}
}
......@@ -121,11 +90,11 @@ public class CascadingDatasource: Cascadable, UniqueString, Subscriptable {
}
func flattened() -> Datasource {
Datasource(value: [
"query": query as Any,
"sortProperty": sortProperty as Any,
"sortAscending": sortAscending as Any,
])
Datasource(
query: query,
sortProperty: sortProperty,
sortAscending: sortAscending
)
}
//
// init(_ cascadeStack: [CVUParsedDatasourceDefinition],
......
......@@ -8,20 +8,6 @@ import Foundation
import SwiftUI
import RealmSwift
class ItemReference {
let uid:Int
let type:Item.Type
init (to: Item) {
uid = to.uid.value ?? -1
type = to.getType() ?? Item.self
}
func resolve() -> Item? {
DatabaseController.read { $0.object(ofType: type, forPrimaryKey: uid) }
}
}
public class CascadableDict: Cascadable, CustomStringConvertible, Subscriptable {
func get<T>(_ name:String, type:T.Type = T.self) -> T? {
guard let value = cascadeProperty(name, type: Any?.self) else {
......
......@@ -85,8 +85,10 @@ class MapHelper {
lookup.sink { [weak self] location in
if let location = location {
// Update the address with the location (avoid future lookups)
let addressReference = ThreadSafeReference(to: address)
DatabaseController.writeAsync(withResolvedReferenceTo: addressReference) { _, address in
let safeRef = ItemReference(to: address)
DatabaseController.writeAsync { _ in
guard let address = safeRef.resolve() as? Address else { return }
let newLocation = try Cache.createItem(Location.self, values: [
"latitude": location.coordinate.latitude,
"longitude": location.coordinate.longitude
......
......@@ -202,7 +202,7 @@ public class Cache {
if let sortProperty = datasource.sortProperty, sortProperty != "" {
result = result.sorted(
byKeyPath: sortProperty,
ascending: datasource.sortAscending.value ?? true
ascending: datasource.sortAscending ?? true
)
}
......@@ -254,7 +254,7 @@ public class Cache {
// Make sure the new resultset has the right query properties
resultSet.datasource.query = datasource.query
resultSet.datasource.sortProperty = datasource.sortProperty
resultSet.datasource.sortAscending.value = datasource.sortAscending.value
resultSet.datasource.sortAscending = datasource.sortAscending
// Make sure the UI updates when the resultset updates
cancellables.append(resultSet.objectWillChange.sink { _ in
......@@ -324,7 +324,7 @@ public class Cache {
private func bindChangeListeners(_ item: Item) {
// Update the sync state when the item changes
rlmTokens.append(item.observe { objectChange in
if case let .change(_, propChanges) = objectChange {
if case let .change(propChanges) = objectChange {
if item._action == nil {
func doAction() {
// Mark item for updating
......@@ -522,7 +522,7 @@ public class Cache {
dict["uid"] = try Cache.incrementUID()
}
print("\(type) - \(dict["uid"])")
// print("\(type) - \(dict["uid"])")
item = realm.create(type, value: dict)
......
......@@ -9,6 +9,40 @@
import Foundation
import RealmSwift
class ItemReference {
let uid:Int
let type:Item.Type
init (to: Item) {
uid = to.uid.value ?? -1
type = to.getType() ?? Item.self
}
func resolve() -> Item? {
DatabaseController.read { $0.object(ofType: type, forPrimaryKey: uid) }
}
}
class EdgeReference {
let type:String
let sourceItemID:Int
let targetItemID:Int
init (to: Edge) {
type = to.type ?? ""
sourceItemID = to.sourceItemID.value ?? -1
targetItemID = to.targetItemID.value ?? -1
}
func resolve() -> Edge? {
DatabaseController.read {
$0.objects(Edge.self)
.filter("type = '\(type)' AND sourceItemID = \(sourceItemID) AND targetItemID = \(targetItemID)")
.first
}
}
}
class DatabaseController {
private init() {}
......@@ -30,7 +64,7 @@ class DatabaseController {
// Realm will automatically detect new properties and removed properties
// And will update the schema on disk automatically
}
}
}
)
}
......@@ -99,7 +133,6 @@ class DatabaseController {
}
}
static func read<T>(_ doRead: ((Realm) throws -> T?) ) -> T? {
do {
return try tryRead(doRead)
......@@ -177,7 +210,8 @@ class DatabaseController {
}
/// Use this for writing to Realm in the background. It will run on a background thread.
static func writeAsync<T>(withResolvedReferenceTo objectReference: ThreadSafeReference<T>, _ doWrite: @escaping (Realm, T) throws -> Void) {
static func writeAsync<T>(withResolvedReferenceTo objectReference: ThreadSafeReference<T>,
_ doWrite: @escaping (Realm, T) throws -> Void) {
realmQueue.async {
autoreleasepool {
do {
......
......@@ -78,7 +78,7 @@ class Sync {
let data = try MemriJSONEncoder.encode([ // TODO: move this to Datasource
"query": datasource.query,
"sortProperty": datasource.sortProperty,
"sortAscending": datasource.sortAscending.value ?? false ? "true" : "false",
"sortAscending": datasource.sortAscending ?? false ? "true" : "false",
] as? [String: String])
// Add to realm
......@@ -134,7 +134,7 @@ class Sync {
debugHistory.info("Syncing from pod with query: \(datasource.query ?? "")")
let wrappedObject = ThreadSafeReference(to: audititem)
let safeRef = ItemReference(to: audititem)
// Call out to the pod with the query
podAPI.query(datasource) { error, items in
......@@ -163,8 +163,8 @@ class Sync {
}
// We no longer need to process this log item
DatabaseController.writeAsync(withResolvedReferenceTo: wrappedObject) { _, audititem in
audititem._action = nil
DatabaseController.writeAsync { _ in
safeRef.resolve()?._action = nil
}
}
} else {
......@@ -205,7 +205,10 @@ class Sync {
DatabaseController.writeAsync { realm in
for (_, sublist) in list {
for item in sublist as? [Any] ?? [] {
if let item = item as? ThreadSafeReference<SchemaItem>, let resolvedItem = realm.resolve(item) {
if
let item = item as? ItemReference,
let resolvedItem = item.resolve()
{
if resolvedItem._action == "delete" {
realm.delete(resolvedItem)
}
......@@ -213,7 +216,10 @@ class Sync {
resolvedItem._action = ""
resolvedItem._updated.removeAll()
}
} else if let item = item as? ThreadSafeReference<Edge>, let resolvedItem = realm.resolve(item) {
} else if
let item = item as? EdgeReference,
let resolvedItem = item.resolve()
{
if resolvedItem._action == "delete" {
realm.delete(resolvedItem)
}
......@@ -232,14 +238,14 @@ class Sync {
DatabaseController.read { realm in
var found = 0
var itemQueue: [String: [SchemaItem]] = ["create": [], "update": [], "delete": []]
var itemQueue: [String: [Item]] = ["create": [], "update": [], "delete": []]
var edgeQueue: [String: [Edge]] = ["create": [], "update": [], "delete": []]
// Items
for itemType in ItemFamily.allCases {
if itemType == .typeUserState { continue }
if let type = itemType.getType() as? SchemaItem.Type {
if let type = itemType.getType() as? Item.Type {
let items = realm.objects(type).filter("_action != nil")
for item in items {
if let action = item._action, itemQueue[action] != nil {
......@@ -260,11 +266,11 @@ class Sync {
}
let safeItemQueue = itemQueue.mapValues {
$0.map { ThreadSafeReference(to: $0) }
$0.map { ItemReference(to: $0) }
}
let safeEdgeQueue = edgeQueue.mapValues {
$0.map { ThreadSafeReference(to: $0) }
$0.map { EdgeReference(to: $0) }
}
if found > 0 {
......
......@@ -616,62 +616,64 @@ public class Item: SchemaItem {
/// update the dateAccessed property to the current date
public func accessed() {
#warning("REPLACE ME with ItemReference - we don't know what thread this Item was made on... so even `self` may not be safe")
// let safeSelf = ThreadSafeReference(to: self)
// DatabaseController.writeAsync(withResolvedReferenceTo: safeSelf) { realm, item in
// item.dateAccessed = Date()
//
// let auditItem = try Cache.createItem(AuditItem.self, values: ["action": "read"])
// _ = try item.link(auditItem, type: "changelog")
// }
let safeSelf = ItemReference(to: self)
DatabaseController.writeAsync { realm in
guard let item = safeSelf.resolve() else { return }
item.dateAccessed = Date()
let auditItem = try Cache.createItem(AuditItem.self, values: ["action": "read"])
_ = try item.link(auditItem, type: "changelog")
}
}
/// update the dateAccessed property to the current date
public func modified(_ updatedFields:[String]) {
#warning("REPLACE ME with ItemReference - we don't know what thread this Item was made on... so even `self` may not be safe")
// let safeSelf = ThreadSafeReference(to: self)
// DatabaseController.writeAsync(withResolvedReferenceTo: safeSelf) { realm, item in
// let previousModified = item.dateModified
// item.dateModified = Date()
//
// for field in updatedFields {
// if !item._updated.contains(field) {
// item._updated.append(field)
// }
// }
//
// if previousModified?.distance(to: Date()) ?? 0 < 300 /* 5 minutes */ {
// #warning("Test that .last gives the last added audit item")
// if
// let auditItem = item.edges("changelog")?.last?.item(type: AuditItem.self),
// let content = auditItem.content,
// var dict = try unserialize(content, type: [String:AnyCodable?].self)
// {
// for field in updatedFields {
// guard item.objectSchema[field] != nil else { throw "Invalid update call" }
// dict[field] = AnyCodable(item[field])
// }
// auditItem.content = String(data: try MemriJSONEncoder.encode(dict), encoding: .utf8) ?? ""
// return
// }
// }
//
// var dict = [String:AnyCodable?]()
// for field in updatedFields {
// guard item.objectSchema[field] != nil else { throw "Invalid update call" }
// dict[field] = AnyCodable(item[field])
// }
//
// let content = String(data: try MemriJSONEncoder.encode(dict), encoding: .utf8) ?? ""
// let auditItem = try Cache.createItem(
// AuditItem.self,
// values: [
// "action": "update",
// "content": content
// ]
// )
// _ = try item.link(auditItem, type: "changelog")
// }
let safeSelf = ItemReference(to: self)
DatabaseController.writeAsync { realm in
guard let item = safeSelf.resolve() else { return }
let previousModified = item.dateModified
item.dateModified = Date()
for field in updatedFields {
if !item._updated.contains(field) {
item._updated.append(field)
}
}
if previousModified?.distance(to: Date()) ?? 0 < 300 /* 5 minutes */ {
#warning("Test that .last gives the last added audit item")
if
let auditItem = item.edges("changelog")?.last?.item(type: AuditItem.self),
let content = auditItem.content,
var dict = try unserialize(content, type: [String:AnyCodable?].self)
{
for field in updatedFields {
guard item.objectSchema[field] != nil else { throw "Invalid update call" }
dict[field] = AnyCodable(item[field])
}
auditItem.content = String(data: try MemriJSONEncoder.encode(dict), encoding: .utf8) ?? ""
return
}
}
var dict = [String:AnyCodable?]()
for field in updatedFields {
guard item.objectSchema[field] != nil else { throw "Invalid update call" }
dict[field] = AnyCodable(item[field])
}
let content = String(data: try MemriJSONEncoder.encode(dict), encoding: .utf8) ?? ""
let auditItem = try Cache.createItem(
AuditItem.self,
values: [
"action": "update",
"content": content
]
)
_ = try item.link(auditItem, type: "changelog")
}
}
/// compare two dataItems
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment