...
This commit is contained in:
commit
54b51e0b60
|
@ -0,0 +1,3 @@
|
|||
[submodule "Dollar.swift"]
|
||||
path = Dollar.swift
|
||||
url = https://github.com/ankurp/Dollar.swift.git
|
|
@ -1,4 +1,5 @@
|
|||
github "krzyzanowskim/CryptoSwift" "0.1.1"
|
||||
github "ankurp/Dollar.swift" "4.0.1"
|
||||
github "Quick/Nimble" "v2.0.0-rc.3"
|
||||
github "Quick/Quick" "v0.6.0"
|
||||
github "tidwall/SwiftWebSocket" "v2.3.0"
|
||||
|
|
|
@ -19,6 +19,7 @@ Pod::Spec.new do |s|
|
|||
|
||||
s.dependency 'CryptoSwift'
|
||||
s.dependency 'SwiftWebSocket'
|
||||
s.dependency 'Dollar'
|
||||
s.dependency 'XCGLogger'
|
||||
|
||||
end
|
||||
|
|
|
@ -25,7 +25,11 @@
|
|||
D0C71B561BC172F40089B6CE /* Meteor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C71B551BC172F40089B6CE /* Meteor.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
D0C71B581BC173030089B6CE /* SwiftMeteor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C71B571BC173030089B6CE /* SwiftMeteor.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
D0C71B5B1BC174280089B6CE /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C71B5A1BC174280089B6CE /* Data.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
<<<<<<< HEAD
|
||||
D0F6C99D1BFFA04600A6CB70 /* EJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F6C99C1BFFA04600A6CB70 /* EJSON.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
=======
|
||||
D0F6C9221BFE97C800A6CB70 /* Dollar.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0F6C91F1BFE97BC00A6CB70 /* Dollar.framework */; };
|
||||
>>>>>>> 75ac27cd6b5f36231c0ad7b65baed7b0cf65f997
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -36,6 +40,20 @@
|
|||
remoteGlobalIDString = D02A71DB1BBEFBCA00940C17;
|
||||
remoteInfo = SwiftDDP;
|
||||
};
|
||||
D0F6C91E1BFE97BC00A6CB70 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D0F6C9191BFE97BC00A6CB70 /* Dollar.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 92E0D03C19467C67002ACC3D;
|
||||
remoteInfo = Dollar;
|
||||
};
|
||||
D0F6C9201BFE97BC00A6CB70 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D0F6C9191BFE97BC00A6CB70 /* Dollar.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 92E6686F19F09C6400BB4FB8;
|
||||
remoteInfo = DollarTests;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
@ -80,7 +98,11 @@
|
|||
D0C71B551BC172F40089B6CE /* Meteor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Meteor.swift; sourceTree = "<group>"; };
|
||||
D0C71B571BC173030089B6CE /* SwiftMeteor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftMeteor.swift; sourceTree = "<group>"; };
|
||||
D0C71B5A1BC174280089B6CE /* Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
|
||||
<<<<<<< HEAD
|
||||
D0F6C99C1BFFA04600A6CB70 /* EJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EJSON.swift; sourceTree = "<group>"; };
|
||||
=======
|
||||
D0F6C9191BFE97BC00A6CB70 /* Dollar.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Dollar.xcodeproj; path = Dollar.swift/Dollar/Dollar.xcodeproj; sourceTree = "<group>"; };
|
||||
>>>>>>> 75ac27cd6b5f36231c0ad7b65baed7b0cf65f997
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -88,6 +110,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D0F6C9221BFE97C800A6CB70 /* Dollar.framework in Frameworks */,
|
||||
D02A72281BBF01E900940C17 /* CryptoSwift.framework in Frameworks */,
|
||||
D02A722A1BBF01ED00940C17 /* SwiftWebSocket.framework in Frameworks */,
|
||||
D02A722C1BBF01EF00940C17 /* XCGLogger.framework in Frameworks */,
|
||||
|
@ -149,6 +172,7 @@
|
|||
D02A72341BBF02C200940C17 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0F6C9191BFE97BC00A6CB70 /* Dollar.xcodeproj */,
|
||||
D02A72321BBF02B900940C17 /* XCGLogger.framework.dSYM */,
|
||||
D02A72301BBF02B400940C17 /* SwiftWebSocket.framework.dSYM */,
|
||||
D02A722E1BBF02AA00940C17 /* CryptoSwift.framework.dSYM */,
|
||||
|
@ -173,6 +197,15 @@
|
|||
path = SwiftDDPTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D0F6C91A1BFE97BC00A6CB70 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0F6C91F1BFE97BC00A6CB70 /* Dollar.framework */,
|
||||
D0F6C9211BFE97BC00A6CB70 /* DollarTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
|
@ -252,6 +285,12 @@
|
|||
mainGroup = D02A71D21BBEFBCA00940C17;
|
||||
productRefGroup = D02A71DD1BBEFBCA00940C17 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = D0F6C91A1BFE97BC00A6CB70 /* Products */;
|
||||
ProjectRef = D0F6C9191BFE97BC00A6CB70 /* Dollar.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
D02A71DB1BBEFBCA00940C17 /* SwiftDDP */,
|
||||
|
@ -260,6 +299,23 @@
|
|||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
D0F6C91F1BFE97BC00A6CB70 /* Dollar.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = Dollar.framework;
|
||||
remoteRef = D0F6C91E1BFE97BC00A6CB70 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
D0F6C9211BFE97BC00A6CB70 /* DollarTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = DollarTests.xctest;
|
||||
remoteRef = D0F6C9201BFE97BC00A6CB70 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
D02A71DA1BBEFBCA00940C17 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
|
|
|
@ -32,16 +32,12 @@ case InternalServerError = "500"
|
|||
}
|
||||
*/
|
||||
|
||||
protocol MeteorCollectionType {
|
||||
public protocol MeteorCollectionType {
|
||||
func documentWasAdded(collection:String, id:String, fields:NSDictionary?)
|
||||
func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?)
|
||||
func documentWasRemoved(collection:String, id:String)
|
||||
}
|
||||
|
||||
protocol MeteorDocument {
|
||||
var id:String { get }
|
||||
}
|
||||
|
||||
/**
|
||||
Meteor is a class to simplify communicating with and consuming MeteorJS server services
|
||||
*/
|
||||
|
@ -270,31 +266,42 @@ public class Meteor {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
MeteorCollection is a class created to provide a base class and api for integrating SwiftDDP with persistence stores. MeteorCollection
|
||||
should generally be subclassed, with the methods documentWasAdded, documentWasChanged and documentWasRemoved facilitating communicating
|
||||
with the datastore.
|
||||
*/
|
||||
public class MeteorDocument: NSObject {
|
||||
|
||||
var id:String
|
||||
|
||||
required public init(id: String, fields: NSDictionary?) {
|
||||
self.id = id
|
||||
super.init()
|
||||
|
||||
if let properties = fields {
|
||||
for (key,value) in properties {
|
||||
self.setValue(value, forKey: key as! String)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func update(fields: NSDictionary?, cleared: [String]?) {
|
||||
if let properties = fields {
|
||||
for (key,value) in properties {
|
||||
self.setValue(value, forKey: key as! String)
|
||||
}
|
||||
}
|
||||
|
||||
if let deletions = cleared {
|
||||
for property in deletions {
|
||||
self.setNilValueForKey(property)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class MeteorCollection: NSObject, MeteorCollectionType {
|
||||
public class AbstractCollection: NSObject, MeteorCollectionType {
|
||||
|
||||
public var name:String
|
||||
public let client = Meteor.client
|
||||
|
||||
private var documents = [String:MeteorDocument]()
|
||||
|
||||
// Alternative API to subclassing
|
||||
// Can also set these closures to modify behavior on added, changed, removed
|
||||
internal var onAdded:((collection:String, id:String, fields:NSDictionary?) -> ())?
|
||||
internal var onChanged:((collection:String, id:String, fields:NSDictionary?, cleared:[String]?) -> ())?
|
||||
internal var onRemoved:((collection:String, id:String) -> ())?
|
||||
|
||||
/**
|
||||
Initializes a MeteorCollection object
|
||||
|
||||
- parameter name: The string name of the collection (must match the name of the collection on the server)
|
||||
*/
|
||||
|
||||
public init(name:String) {
|
||||
self.name = name
|
||||
super.init()
|
||||
|
@ -304,6 +311,75 @@ public class MeteorCollection: NSObject, MeteorCollectionType {
|
|||
deinit {
|
||||
Meteor.collections[name] = nil
|
||||
}
|
||||
|
||||
/**
|
||||
Invoked when a document has been sent from the server.
|
||||
|
||||
- parameter collection: the string name of the collection to which the document belongs
|
||||
- parameter id: the string unique id that identifies the document on the server
|
||||
- parameter fields: an optional NSDictionary with the documents properties
|
||||
*/
|
||||
|
||||
public func documentWasAdded(collection:String, id:String, fields:NSDictionary?) {}
|
||||
|
||||
/**
|
||||
Invoked when a document has been changed on the server.
|
||||
|
||||
- parameter collection: the string name of the collection to which the document belongs
|
||||
- parameter id: the string unique id that identifies the document on the server
|
||||
- parameter fields: an optional NSDictionary with the documents properties
|
||||
- parameter cleared: Optional array of strings (field names to delete)
|
||||
*/
|
||||
|
||||
public func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?) {}
|
||||
|
||||
/**
|
||||
Invoked when a document has been removed on the server.
|
||||
|
||||
- parameter collection: the string name of the collection to which the document belongs
|
||||
- parameter id: the string unique id that identifies the document on the server
|
||||
*/
|
||||
|
||||
public func documentWasRemoved(collection:String, id:String) {}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
MeteorCollection provides basic persistence as well as an api for integrating SwiftDDP with persistence stores. MeteorCollection
|
||||
should generally be subclassed, with the methods documentWasAdded, documentWasChanged and documentWasRemoved facilitating communicating
|
||||
with the datastore.
|
||||
*/
|
||||
|
||||
// MeteorCollectionType protocol declaration is necessary
|
||||
public class MeteorCollection<T:MeteorDocument>: AbstractCollection {
|
||||
|
||||
|
||||
var documents = [String:T]()
|
||||
|
||||
var sorted:[T] {
|
||||
return Array(documents.values).sort({ $0.id > $1.id })
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of documents in the collection
|
||||
*/
|
||||
|
||||
var count:Int {
|
||||
return documents.count
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes a MeteorCollection object
|
||||
|
||||
- parameter name: The string name of the collection (must match the name of the collection on the server)
|
||||
*/
|
||||
|
||||
private func sorted(property:String) -> [T] {
|
||||
let values = Array(documents.values)
|
||||
return values.sort({ $0.id > $1.id })
|
||||
}
|
||||
|
||||
/**
|
||||
Invoked when a document has been sent from the server.
|
||||
|
@ -313,8 +389,10 @@ public class MeteorCollection: NSObject, MeteorCollectionType {
|
|||
- parameter fields: an optional NSDictionary with the documents properties
|
||||
*/
|
||||
|
||||
public func documentWasAdded(collection:String, id:String, fields:NSDictionary?) {
|
||||
if let added = onAdded { added(collection: collection, id: id, fields:fields) }
|
||||
public override func documentWasAdded(collection:String, id:String, fields:NSDictionary?) {
|
||||
let document = T(id: id, fields: fields)
|
||||
documents[id] = document
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -326,8 +404,12 @@ public class MeteorCollection: NSObject, MeteorCollectionType {
|
|||
- parameter cleared: Optional array of strings (field names to delete)
|
||||
*/
|
||||
|
||||
public func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?) {
|
||||
if let changed = onChanged { changed(collection:collection, id:id, fields:fields, cleared:cleared) }
|
||||
public override func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?) {
|
||||
if let document = documents[id] {
|
||||
document.update(fields, cleared: cleared)
|
||||
documents[id] = document
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -337,8 +419,10 @@ public class MeteorCollection: NSObject, MeteorCollectionType {
|
|||
- parameter id: the string unique id that identifies the document on the server
|
||||
*/
|
||||
|
||||
public func documentWasRemoved(collection:String, id:String) {
|
||||
if let removed = onRemoved { removed(collection:collection, id:id) }
|
||||
public override func documentWasRemoved(collection:String, id:String) {
|
||||
if let _ = documents[id] {
|
||||
documents[id] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
import Foundation
|
||||
import SwiftDDP
|
||||
@testable import SwiftDDP
|
||||
|
||||
//
|
||||
//
|
||||
|
@ -8,6 +8,13 @@ import SwiftDDP
|
|||
//
|
||||
//
|
||||
|
||||
class Document: MeteorDocument {
|
||||
|
||||
var state:String?
|
||||
var city:String?
|
||||
|
||||
}
|
||||
|
||||
// *** methods that are tested against a server are tested against the url below ***
|
||||
|
||||
let url = "ws://swiftddp.meteor.com/websocket"
|
||||
|
|
|
@ -8,7 +8,7 @@ class MeteorTest: QuickSpec {
|
|||
override func spec() {
|
||||
|
||||
let client = Meteor.client
|
||||
let collection = MeteorCollection(name: "test-collection")
|
||||
let collection = MeteorCollection<Document>(name: "test-collection")
|
||||
|
||||
describe("Collections") {
|
||||
/*
|
||||
|
@ -24,40 +24,37 @@ class MeteorTest: QuickSpec {
|
|||
describe("Document methods send notifications") {
|
||||
|
||||
it("sends a message when a document is added") {
|
||||
var _id:String!
|
||||
|
||||
collection.onAdded = {collection, id, fields in
|
||||
if (id == "2gAMzqvE8K8kBWK8F") { _id = id }
|
||||
}
|
||||
|
||||
try! client.ddpMessageHandler(added[0])
|
||||
expect(_id).toEventuallyNot(beNil())
|
||||
expect(_id).toEventually(equal("2gAMzqvE8K8kBWK8F"))
|
||||
|
||||
print("Collection -> \(collection.documents)")
|
||||
|
||||
expect(collection.documents["2gAMzqvE8K8kBWK8F"]).toEventuallyNot(beNil())
|
||||
expect(collection.documents["2gAMzqvE8K8kBWK8F"]?.city).toEventually(equal("Boston"))
|
||||
}
|
||||
|
||||
it("sends a message when a document is removed") {
|
||||
var _id:String!
|
||||
|
||||
collection.onRemoved = {collection, id in
|
||||
if (id == "2gAMzqvE8K8kBWK8F") { _id = id }
|
||||
}
|
||||
try! client.ddpMessageHandler(added[1])
|
||||
expect(collection.documents["ByuwhKPGuLru8h4TT"]).toEventuallyNot(beNil())
|
||||
expect(collection.documents["ByuwhKPGuLru8h4TT"]!.city).toEventually(equal("Truro"))
|
||||
|
||||
try! client.ddpMessageHandler(removed[0])
|
||||
expect(_id).toEventuallyNot(beNil())
|
||||
expect(_id).toEventually(equal("2gAMzqvE8K8kBWK8F"))
|
||||
try! client.ddpMessageHandler(removed[1])
|
||||
expect(collection.documents["ByuwhKPGuLru8h4TT"]).toEventually(beNil())
|
||||
}
|
||||
|
||||
|
||||
it("sends a message when a document is updated") {
|
||||
var _id:String!
|
||||
|
||||
collection.onChanged = {collection, id, fields, cleared in
|
||||
if (id == "2gAMzqvE8K8kBWK8F") { _id = id }
|
||||
}
|
||||
try! client.ddpMessageHandler(added[2])
|
||||
expect(collection.documents["AGX6vyxCJtjqdxbFH"]).toEventuallyNot(beNil())
|
||||
expect(collection.documents["AGX6vyxCJtjqdxbFH"]!.city).toEventually(equal("Austin"))
|
||||
|
||||
try! client.ddpMessageHandler(changed[0])
|
||||
expect(_id).toEventuallyNot(beNil())
|
||||
expect(_id).toEventually(equal("2gAMzqvE8K8kBWK8F"))
|
||||
try! client.ddpMessageHandler(changed[2])
|
||||
expect(collection.documents["AGX6vyxCJtjqdxbFH"]!.city).toEventually(equal("Houston"))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue