Loading Kinetic/Commands/KeyRange.swift +116 −8 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ public enum Range<K : KeyType> : CustomStringConvertible{ case From(K, Bool) case To(K, Bool) case Prefix(K) case Empty internal func build(builder: Builder, device: KineticDevice) { switch self { Loading Loading @@ -54,6 +55,11 @@ public enum Range<K : KeyType> : CustomStringConvertible{ builder.range.endKey = NSData(bytes: bs, length: p.length) builder.range.endKeyInclusive = false } case Empty: builder.range.startKey = "".toData() builder.range.startKeyInclusive = false builder.range.endKey = "".toData() builder.range.endKeyInclusive = false } } Loading @@ -72,11 +78,11 @@ public enum Range<K : KeyType> : CustomStringConvertible{ case To(let key, true): return "Range [..'\(key)']" case To(let key, false): return "Range [..'\(key)')" case Prefix(let prefix): return "Prefix '\(prefix)'" case Empty: return "Empty" } } } public class GetKeyRangeCommand<K : KeyType> : ChannelCommand { public typealias ResponseType = KeyRangeResponse Loading @@ -91,7 +97,7 @@ public class GetKeyRangeCommand<K : KeyType> : ChannelCommand { self.maxReturned = maxReturned } public func build(builder: Builder, device: KineticDevice) -> Int { public func build(builder: Builder, device: KineticDevice) -> KeyRangeContext { builder.header.messageType = .Getkeyrange self.range.build(builder, device: device) builder.range.reverse = self.reverse Loading @@ -105,20 +111,47 @@ public class GetKeyRangeCommand<K : KeyType> : ChannelCommand { } builder.range.maxReturned = max return Int(max) return KeyRangeContext(maxReturned: Int(max), reverse: self.reverse, endKey: builder.range.endKey, endInclusive: builder.range.endKeyInclusive) } } public struct KeyRangeContext { internal let maxReturned: Int internal let reverse: Bool internal let endKey: NSData internal let endInclusive: Bool } public struct KeyRangeResponse: ChannelResponse { public typealias ContextType = Int public typealias ContextType = KeyRangeContext public let success: Bool public let error: KineticRemoteError? public let keys: [NSData] public let hasMore: Bool private let context: KeyRangeContext public var next: GetKeyRangeCommand<NSData> { guard self.hasMore else { return GetKeyRangeCommand(.Empty) } guard self.keys.count > 0 else { return GetKeyRangeCommand(.Empty) } // Even if there might be more, we know there isnt because we already got the last key guard self.keys[self.keys.count - 1] != self.context.endKey else { return GetKeyRangeCommand(.Empty) } public static func parse(raw: RawResponse, context: Int) -> KeyRangeResponse { return GetKeyRangeCommand(.FromTo(self.keys[self.keys.count-1], self.context.endKey, false, self.context.endInclusive), reverse: self.context.reverse, maxReturned: self.context.maxReturned) } public static func parse(raw: RawResponse, context: KeyRangeContext) -> KeyRangeResponse { switch raw.command.status.code { case .Success: var keys: [NSData] = [] Loading @@ -130,11 +163,79 @@ public struct KeyRangeResponse: ChannelResponse { } return KeyRangeResponse(success: true, error: nil, keys: keys, hasMore: keys.count == context) hasMore: keys.count == context.maxReturned, context: context ) default: return KeyRangeResponse(success: false, error: KineticRemoteError.fromStatus(raw.command.status), keys: [], hasMore: false) keys: [], hasMore: false, context: context) } } } public class KeySequence<K: KeyType>: SequenceType { public typealias Generator = KeyGenerator<K> private let session: KineticSession private let range: Range<K> private let reverse: Bool private let batch: Int? internal init(session: KineticSession, range: Range<K>, reverse:Bool = false, batch: Int? = nil) { self.session = session self.range = range self.reverse = reverse self.batch = batch } public func generate() -> KeyGenerator<K> { return KeyGenerator<K>(session: session, range: self.range, reverse: self.reverse, batch: self.batch) } } public class KeyGenerator<K: KeyType>: GeneratorType { public typealias Element = NSData // Params private let session: KineticSession private let range: Range<K> private let reverse: Bool private let batch: Int? // state private var lastResponse: KeyRangeResponse? private var index: Int internal init(session: KineticSession, range: Range<K>, reverse:Bool = false, batch: Int? = nil) { self.session = session self.range = range self.reverse = reverse self.batch = batch self.index = 0 let first = GetKeyRangeCommand(range, reverse: reverse, maxReturned: batch) do { self.lastResponse = try first.sendTo(self.session) } catch { /* TODO: log */ } } public func next() -> NSData? { if self.lastResponse == nil { return nil } else if self.index < self.lastResponse!.keys.count { return self.lastResponse!.keys[self.index++] } else if self.lastResponse!.hasMore { let cmd = self.lastResponse!.next do { self.lastResponse = try cmd.sendTo(self.session) } catch { // TODO: log self.lastResponse = nil } self.index = 0 return self.next() } else { return nil } } } Loading @@ -158,12 +259,19 @@ extension GetKeyRangeCommand: CustomStringConvertible { } public extension KineticSession { func getKeyRange<K>(range: Range<K>, reverse: Bool = false) throws -> GetKeyRangeCommand<K>.ResponseType { let cmd = GetKeyRangeCommand(range, reverse: reverse, maxReturned: nil) return try cmd.sendTo(self) } func getKeyRange<K>(range: Range<K>, reverse: Bool, maxReturned: Int) throws -> GetKeyRangeCommand<K>.ResponseType { let cmd = GetKeyRangeCommand(range, reverse: reverse, maxReturned: maxReturned) return try cmd.sendTo(self) } func traverse<K>(range: Range<K>, reverse: Bool = false, batch: Int) throws -> KeySequence<K> { return KeySequence(session: self, range: range, reverse: reverse, batch: batch) } } No newline at end of file Kinetic/Core.swift +7 −0 Original line number Diff line number Diff line Loading @@ -32,21 +32,28 @@ public protocol ValueType { } extension NSData: KeyType, ValueType { public func toData() -> NSData { return self } public func toBytes() -> Bytes { // TODO: figure out how to do this without copying! var buffer = Bytes(count: self.length, repeatedValue: 0) self.getBytes(&buffer, length: self.length) return buffer } } extension String: KeyType, ValueType { public var length: Int { return self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) } public func toData() -> NSData { return NSData(data: self.dataUsingEncoding(NSUTF8StringEncoding)!) } public func toBytes() -> Bytes { return self.toUtf8() } } public class Builder { Loading examples/Example 2 - Basics.playground/Contents.swift +5 −0 Original line number Diff line number Diff line Loading @@ -53,4 +53,9 @@ try c.getKeyRange(.Prefix("demo")) try c.getKeyRange(.Prefix("demo"), reverse: true) try c.getKeyRange(.Prefix("demo"), reverse: true, maxReturned: 42) //: If we wish to iterate through a range of keys that might span the entire //: contents of the device, we can use `KineticSession.traverse()` let ks = try c.traverse(.From("", true), reverse: false, batch: 64) for k in ks { print(k.toUtf8()) } c.close() examples/Example 2 - Basics.playground/contents.xcplayground +1 −1 Original line number Diff line number Diff line <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <playground version='5.0' target-platform='osx' requires-full-environment='true' display-mode='rendered'> <playground version='5.0' target-platform='osx' requires-full-environment='true' display-mode='raw'> <timeline fileName='timeline.xctimeline'/> </playground> No newline at end of file Loading
Kinetic/Commands/KeyRange.swift +116 −8 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ public enum Range<K : KeyType> : CustomStringConvertible{ case From(K, Bool) case To(K, Bool) case Prefix(K) case Empty internal func build(builder: Builder, device: KineticDevice) { switch self { Loading Loading @@ -54,6 +55,11 @@ public enum Range<K : KeyType> : CustomStringConvertible{ builder.range.endKey = NSData(bytes: bs, length: p.length) builder.range.endKeyInclusive = false } case Empty: builder.range.startKey = "".toData() builder.range.startKeyInclusive = false builder.range.endKey = "".toData() builder.range.endKeyInclusive = false } } Loading @@ -72,11 +78,11 @@ public enum Range<K : KeyType> : CustomStringConvertible{ case To(let key, true): return "Range [..'\(key)']" case To(let key, false): return "Range [..'\(key)')" case Prefix(let prefix): return "Prefix '\(prefix)'" case Empty: return "Empty" } } } public class GetKeyRangeCommand<K : KeyType> : ChannelCommand { public typealias ResponseType = KeyRangeResponse Loading @@ -91,7 +97,7 @@ public class GetKeyRangeCommand<K : KeyType> : ChannelCommand { self.maxReturned = maxReturned } public func build(builder: Builder, device: KineticDevice) -> Int { public func build(builder: Builder, device: KineticDevice) -> KeyRangeContext { builder.header.messageType = .Getkeyrange self.range.build(builder, device: device) builder.range.reverse = self.reverse Loading @@ -105,20 +111,47 @@ public class GetKeyRangeCommand<K : KeyType> : ChannelCommand { } builder.range.maxReturned = max return Int(max) return KeyRangeContext(maxReturned: Int(max), reverse: self.reverse, endKey: builder.range.endKey, endInclusive: builder.range.endKeyInclusive) } } public struct KeyRangeContext { internal let maxReturned: Int internal let reverse: Bool internal let endKey: NSData internal let endInclusive: Bool } public struct KeyRangeResponse: ChannelResponse { public typealias ContextType = Int public typealias ContextType = KeyRangeContext public let success: Bool public let error: KineticRemoteError? public let keys: [NSData] public let hasMore: Bool private let context: KeyRangeContext public var next: GetKeyRangeCommand<NSData> { guard self.hasMore else { return GetKeyRangeCommand(.Empty) } guard self.keys.count > 0 else { return GetKeyRangeCommand(.Empty) } // Even if there might be more, we know there isnt because we already got the last key guard self.keys[self.keys.count - 1] != self.context.endKey else { return GetKeyRangeCommand(.Empty) } public static func parse(raw: RawResponse, context: Int) -> KeyRangeResponse { return GetKeyRangeCommand(.FromTo(self.keys[self.keys.count-1], self.context.endKey, false, self.context.endInclusive), reverse: self.context.reverse, maxReturned: self.context.maxReturned) } public static func parse(raw: RawResponse, context: KeyRangeContext) -> KeyRangeResponse { switch raw.command.status.code { case .Success: var keys: [NSData] = [] Loading @@ -130,11 +163,79 @@ public struct KeyRangeResponse: ChannelResponse { } return KeyRangeResponse(success: true, error: nil, keys: keys, hasMore: keys.count == context) hasMore: keys.count == context.maxReturned, context: context ) default: return KeyRangeResponse(success: false, error: KineticRemoteError.fromStatus(raw.command.status), keys: [], hasMore: false) keys: [], hasMore: false, context: context) } } } public class KeySequence<K: KeyType>: SequenceType { public typealias Generator = KeyGenerator<K> private let session: KineticSession private let range: Range<K> private let reverse: Bool private let batch: Int? internal init(session: KineticSession, range: Range<K>, reverse:Bool = false, batch: Int? = nil) { self.session = session self.range = range self.reverse = reverse self.batch = batch } public func generate() -> KeyGenerator<K> { return KeyGenerator<K>(session: session, range: self.range, reverse: self.reverse, batch: self.batch) } } public class KeyGenerator<K: KeyType>: GeneratorType { public typealias Element = NSData // Params private let session: KineticSession private let range: Range<K> private let reverse: Bool private let batch: Int? // state private var lastResponse: KeyRangeResponse? private var index: Int internal init(session: KineticSession, range: Range<K>, reverse:Bool = false, batch: Int? = nil) { self.session = session self.range = range self.reverse = reverse self.batch = batch self.index = 0 let first = GetKeyRangeCommand(range, reverse: reverse, maxReturned: batch) do { self.lastResponse = try first.sendTo(self.session) } catch { /* TODO: log */ } } public func next() -> NSData? { if self.lastResponse == nil { return nil } else if self.index < self.lastResponse!.keys.count { return self.lastResponse!.keys[self.index++] } else if self.lastResponse!.hasMore { let cmd = self.lastResponse!.next do { self.lastResponse = try cmd.sendTo(self.session) } catch { // TODO: log self.lastResponse = nil } self.index = 0 return self.next() } else { return nil } } } Loading @@ -158,12 +259,19 @@ extension GetKeyRangeCommand: CustomStringConvertible { } public extension KineticSession { func getKeyRange<K>(range: Range<K>, reverse: Bool = false) throws -> GetKeyRangeCommand<K>.ResponseType { let cmd = GetKeyRangeCommand(range, reverse: reverse, maxReturned: nil) return try cmd.sendTo(self) } func getKeyRange<K>(range: Range<K>, reverse: Bool, maxReturned: Int) throws -> GetKeyRangeCommand<K>.ResponseType { let cmd = GetKeyRangeCommand(range, reverse: reverse, maxReturned: maxReturned) return try cmd.sendTo(self) } func traverse<K>(range: Range<K>, reverse: Bool = false, batch: Int) throws -> KeySequence<K> { return KeySequence(session: self, range: range, reverse: reverse, batch: batch) } } No newline at end of file
Kinetic/Core.swift +7 −0 Original line number Diff line number Diff line Loading @@ -32,21 +32,28 @@ public protocol ValueType { } extension NSData: KeyType, ValueType { public func toData() -> NSData { return self } public func toBytes() -> Bytes { // TODO: figure out how to do this without copying! var buffer = Bytes(count: self.length, repeatedValue: 0) self.getBytes(&buffer, length: self.length) return buffer } } extension String: KeyType, ValueType { public var length: Int { return self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) } public func toData() -> NSData { return NSData(data: self.dataUsingEncoding(NSUTF8StringEncoding)!) } public func toBytes() -> Bytes { return self.toUtf8() } } public class Builder { Loading
examples/Example 2 - Basics.playground/Contents.swift +5 −0 Original line number Diff line number Diff line Loading @@ -53,4 +53,9 @@ try c.getKeyRange(.Prefix("demo")) try c.getKeyRange(.Prefix("demo"), reverse: true) try c.getKeyRange(.Prefix("demo"), reverse: true, maxReturned: 42) //: If we wish to iterate through a range of keys that might span the entire //: contents of the device, we can use `KineticSession.traverse()` let ks = try c.traverse(.From("", true), reverse: false, batch: 64) for k in ks { print(k.toUtf8()) } c.close()
examples/Example 2 - Basics.playground/contents.xcplayground +1 −1 Original line number Diff line number Diff line <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <playground version='5.0' target-platform='osx' requires-full-environment='true' display-mode='rendered'> <playground version='5.0' target-platform='osx' requires-full-environment='true' display-mode='raw'> <timeline fileName='timeline.xctimeline'/> </playground> No newline at end of file