Commit a9d2ab03 authored by Ignacio Corderi's avatar Ignacio Corderi
Browse files

Added GetKeyRange

parent ec7f485c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

/* Begin PBXBuildFile section */
		3E07EA7F1B78E3B500DAB3F1 /* Kinetic.proto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E07EA7E1B78E3B500DAB3F1 /* Kinetic.proto.swift */; };
		3EA070371B846C3800E4821E /* KeyRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EA070361B846C3800E4821E /* KeyRange.swift */; };
		3ED681EB1B7CEA0600AFDF79 /* Encoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ED681EA1B7CEA0600AFDF79 /* Encoding.swift */; };
		3EDAAB411B66D32D00F30808 /* Kinetic.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EDAAB401B66D32D00F30808 /* Kinetic.h */; settings = {ATTRIBUTES = (Public, ); }; };
		3EDAAB481B66D32D00F30808 /* Kinetic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EDAAB3D1B66D32D00F30808 /* Kinetic.framework */; };
@@ -40,6 +41,7 @@
		382D1C00FC0EC4F1BF676411 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
		3E07EA7E1B78E3B500DAB3F1 /* Kinetic.proto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Kinetic.proto.swift; sourceTree = "<group>"; };
		3E386E6A1B7F85720040D363 /* Example 2 - Basics.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Example 2 - Basics.playground"; sourceTree = "<group>"; };
		3EA070361B846C3800E4821E /* KeyRange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyRange.swift; sourceTree = "<group>"; };
		3ED681EA1B7CEA0600AFDF79 /* Encoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Encoding.swift; sourceTree = "<group>"; };
		3ED681EE1B7D0EC600AFDF79 /* Example 3 - Async.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Example 3 - Async.playground"; sourceTree = "<group>"; };
		3EDAAB3D1B66D32D00F30808 /* Kinetic.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Kinetic.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -158,6 +160,7 @@
				3EFB7F1D1B7A6A9800988886 /* Put.swift */,
				3EFB7F261B7AA45A00988886 /* Get.swift */,
				3EFB7F281B7AB06800988886 /* Delete.swift */,
				3EA070361B846C3800E4821E /* KeyRange.swift */,
			);
			path = Commands;
			sourceTree = "<group>";
@@ -327,6 +330,7 @@
				3EFB7F221B7A7A8000988886 /* Utils.swift in Sources */,
				3EFB7F251B7A977500988886 /* Common.swift in Sources */,
				3EFB7F2F1B7BB4E700988886 /* Authentication.swift in Sources */,
				3EA070371B846C3800E4821E /* KeyRange.swift in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
+4 −2
Original line number Diff line number Diff line
@@ -21,23 +21,25 @@
// @author: Ignacio Corderi

public struct NoResponse : ChannelResponse {
    public typealias ContextType = Void
    public let success: Bool
    public let error: KineticRemoteError?
    
    public static func parse(raw: RawResponse) -> NoResponse {
    public static func parse(raw: RawResponse, context: Void) -> NoResponse {
        return NoResponse(success: raw.command.status.code == .Success,
            error: KineticRemoteError.fromStatus(raw.command.status))
    }
}

public struct ValueResponse : ChannelResponse {
    public typealias ContextType = Void
    public let success: Bool
    public let error: KineticRemoteError?
    public let value: Bytes?
    public let exists: Bool
    public var hasValue: Bool { return value != nil && value!.count > 0 }
    
    public static func parse(raw: RawResponse) -> ValueResponse {
    public static func parse(raw: RawResponse, context: Void) -> ValueResponse {
        switch raw.command.status.code {
        case .Success:
            return ValueResponse(success: true, error: nil, value: raw.value, exists: true)
+5 −4
Original line number Diff line number Diff line
@@ -31,23 +31,24 @@ public class DeleteCommand : ChannelCommand {
    }
    
    public convenience init(key: String) {
        self.init(key: key.toNSData())
        self.init(key: key.toData())
    }
    
    public func build(builder: Builder) -> Builder {
    public func build(builder: Builder, device: KineticDevice) {
        builder.header.messageType = .Delete
        builder.keyValue.key = self.key
        return builder
    }
    
}

public struct EmptyResponse : ChannelResponse {
    public typealias ContextType = Void
    
    public let success: Bool
    public let error: KineticRemoteError?
    public let exists: Bool
    
    public static func parse(raw: RawResponse) -> EmptyResponse {
    public static func parse(raw: RawResponse, context: Void) -> EmptyResponse {
        switch raw.command.status.code {
        case .Success:
            return EmptyResponse(success: true, error: nil, exists: true)
+5 −10
Original line number Diff line number Diff line
@@ -24,20 +24,15 @@ public class GetCommand : ChannelCommand {
    
    public typealias ResponseType = ValueResponse
    
    public let key: NSData
    public let key: KeyType
    
    public init(key: NSData) {
    public init(key: KeyType) {
        self.key = key
    }
    
    public convenience init(key: String) {
        self.init(key: key.toNSData())
    }
    
    public func build(builder: Builder) -> Builder {
    public func build(builder: Builder, device: KineticDevice) {
        builder.header.messageType = .Get
        builder.keyValue.key = self.key
        return builder
        builder.keyValue.key = self.key.toData()
    }
    
}
@@ -45,7 +40,7 @@ public class GetCommand : ChannelCommand {
extension GetCommand: CustomStringConvertible {
    public var description: String {
        get {
            return "Get (key: \(self.key.toUtf8()))"
            return "Get (key: \(self.key))"
        }
    }
}
+169 −0
Original line number Diff line number Diff line
// Copyright (c) 2015 Seagate Technology

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// @author: Ignacio Corderi

public enum Range<K : KeyType> : CustomStringConvertible{
    case FromTo(K, K, Bool, Bool)
    case From(K, Bool)
    case To(K, Bool)
    case Prefix(K)

    internal func build(builder: Builder, device: KineticDevice) {
        switch self {
        case FromTo(let from, let to, let fromInclusive, let toInclusive):
            builder.range.startKey = from.toData()
            builder.range.startKeyInclusive = fromInclusive
            builder.range.endKey = to.toData()
            builder.range.endKeyInclusive = toInclusive
        case From(let key, let inclusive):
            builder.range.startKey = key.toData()
            builder.range.startKeyInclusive = inclusive
            let bs = Bytes(count: Int(device.limits.maxKeySize), repeatedValue: UInt8(0xFF))
            builder.range.endKey = NSData(bytes: bs, length: bs.count)
            builder.range.endKeyInclusive = true
        case To(let key, let inclusive):
            builder.range.startKey = NSData(bytes: [], length: 0)
            builder.range.startKeyInclusive = true
            builder.range.endKey = key.toData()
            builder.range.endKeyInclusive = inclusive
        case Prefix(let prefix):
            let p = prefix.toData()
            builder.range.startKey = p
            builder.range.startKeyInclusive = true
            if p.length > 0 {
                var bs = p.arrayOfBytes()
                bs[bs.count-1] += 1
                builder.range.endKey = NSData(bytes: bs, length: p.length)
                builder.range.endKeyInclusive = false
            }
        }
    }
    
    public var description: String {
        switch self {
        case FromTo(let from, let to, true, true):
            return "Range ['\(from)'..'\(to)']"
        case FromTo(let from, let to, true, false):
            return "Range ['\(from)'..'\(to)')"
        case FromTo(let from, let to, false, true):
            return "Range ('\(from)'..'\(to)']"
        case FromTo(let from, let to, false, false):
            return "Range ('\(from)'..'\(to)')"
        case From(let key, true): return "Range ['\(key)'..)"
        case From(let key, false): return "Range ('\(key)'..)"
        case To(let key, true):  return "Range [..'\(key)']"
        case To(let key, false): return "Range [..'\(key)')"
        case Prefix(let prefix): return "Prefix '\(prefix)'"
        }
    }
}


public class GetKeyRangeCommand<K : KeyType> : ChannelCommand {
    
    public typealias ResponseType = KeyRangeResponse
    
    public let range: Range<K>
    public let reverse: Bool
    public let maxReturned: Int?
    
    public init(_ range: Range<K>, reverse: Bool=false, maxReturned: Int?=nil) {
        self.range = range
        self.reverse = reverse
        self.maxReturned = maxReturned
    }
    
    public func build(builder: Builder, device: KineticDevice) -> Int {
        builder.header.messageType = .Getkeyrange
        self.range.build(builder, device: device)
        builder.range.reverse = self.reverse
        
        var max: Int32 = 0
        if (self.maxReturned != nil) {
            // TODO: verify that it's <= than the limit
            max = Int32(self.maxReturned!)
        } else {
            max = Int32(device.limits.maxKeyRangeCount)
        }
         builder.range.maxReturned = max
        
        return Int(max)
    }
    
}

public struct KeyRangeResponse: ChannelResponse {
    public typealias ContextType = Int
    
    public let success: Bool
    public let error: KineticRemoteError?
    public let keys: [NSData]
    public let hasMore: Bool
    
    public static func parse(raw: RawResponse, context: Int) -> KeyRangeResponse {
        switch raw.command.status.code {
        case .Success:
            var keys: [NSData] = []
            /* It might be possible that some implementation of the device
               is not returning anyhting at all when the resulting range
               is empty. It might be considered an implementation flaw. */
            if raw.command.hasBody && raw.command.body.hasRange {
                keys = raw.command.body.range.keys
            }
            return KeyRangeResponse(success: true, error: nil,
                                    keys: keys,
                                    hasMore: keys.count == context)
        default:
            return KeyRangeResponse(success: false,
                error: KineticRemoteError.fromStatus(raw.command.status),
                keys: [], hasMore: false)
        }
    }
}

extension KeyRangeResponse: CustomStringConvertible {
    public var description: String {
        if self.success {
            return "Success (length: \(self.keys.count))"
        } else if self.error!.message.isEmpty {
            return "\(self.error!.code)"
        } else {
            return "\(self.error!.code): \(self.error!.message)"
        }
    }
}

extension GetKeyRangeCommand: CustomStringConvertible {
    public var description: String {
        return "GetKeyRange \(self.range)"
    }
}

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)
    }
}
 No newline at end of file
Loading