-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from IanKeen/persistence
Persistence!
- Loading branch information
Showing
8 changed files
with
270 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,54 @@ | ||
//// | ||
//// PlistStorage.swift | ||
//// Chameleon | ||
//// | ||
//// Created by Ian Keen on 23/05/2016. | ||
//// Copyright © 2016 Mustard. All rights reserved. | ||
//// | ||
// | ||
//public final class PlistStorage: Storage { | ||
// //MARK: - Public | ||
// public init() { } | ||
// | ||
// public func set<T : StorableDataType>(_ in: StorageNamespace, key: String, value: T) { | ||
// var dataset = self.dataset() | ||
// var data = dataset[`in`.namespace] ?? [:] | ||
// | ||
// data[key] = value.anyObject | ||
// dataset[`in`.namespace] = data | ||
// | ||
// self.saveDataset(dataset) | ||
// } | ||
// public func get<T>(_ in: StorageNamespace, key: String) -> T? { | ||
// var dataset = self.dataset() | ||
// var data = dataset[`in`.namespace] ?? [:] | ||
// return data[key] as? T | ||
// } | ||
// | ||
// //MARK: - Private | ||
// private var fileName: String { | ||
// return "\(NSHomeDirectory())/storage.plist" | ||
// } | ||
// private func dataset() -> [String: [String: Any]] { | ||
// guard let dict = NSDictionary(contentsOfFile: self.fileName) as? [String: [String: Any]] else { | ||
// return self.defaultDataset() | ||
// } | ||
// return dict | ||
// } | ||
// private func defaultDataset() -> [String: [String: Any]] { return [:] } | ||
// private func saveDataset(_ dataset: [String: [String: Any]]) { | ||
// var result = [String: [String: Any]]() | ||
// for (namespace, data) in dataset { | ||
// var subset = [String: Any]() | ||
// for (key, value) in data { | ||
// subset[key] = value | ||
// } | ||
// result[namespace] = subset | ||
// } | ||
// | ||
// (result as NSDictionary).write(toFile: self.fileName, atomically: true) | ||
// } | ||
//} | ||
// PlistStorage.swift | ||
// Chameleon | ||
// | ||
// Created by Ian Keen on 23/05/2016. | ||
// Copyright © 2016 Mustard. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
// Provides Plist based storage of key/value pairs (OSX only) | ||
public final class PlistStorage: Storage { | ||
//MARK: - Public | ||
public init() { } | ||
|
||
//MARK: - Storage | ||
public func set<T: StorableType>(type: T.Type, in: StorageNamespace, key: String, value: T) throws { | ||
var dataset = self.dataset() | ||
var data = dataset[`in`.namespace] ?? [:] | ||
|
||
guard let anyObject = value.anyObject else { throw StorageError.invalidValue(value: value) } | ||
data[key] = anyObject | ||
dataset[`in`.namespace] = data | ||
|
||
self.saveDataset(dataset) | ||
} | ||
public func get<T : StorableType>(type: T.Type, in: StorageNamespace, key: String) -> T? { | ||
var dataset = self.dataset() | ||
var data = dataset[`in`.namespace] ?? [:] | ||
return data[key] as? T | ||
} | ||
|
||
//MARK: - Private | ||
private var fileName: String { | ||
return "\(NSHomeDirectory())/storage.plist" | ||
} | ||
private func dataset() -> [String: [String: AnyObject]] { | ||
guard let dict = NSDictionary(contentsOfFile: self.fileName) as? [String: [String: AnyObject]] else { | ||
return self.defaultDataset() | ||
} | ||
return dict | ||
} | ||
private func defaultDataset() -> [String: [String: AnyObject]] { return [:] } | ||
private func saveDataset(_ dataset: [String: [String: AnyObject]]) { | ||
(dataset as NSDictionary).write(toFile: self.fileName, atomically: true) | ||
} | ||
} | ||
|
||
//MARK: - Helper | ||
extension StorableType { | ||
var anyObject: AnyObject? { | ||
return self as? AnyObject | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// | ||
// RedisStorage.swift | ||
// Chameleon | ||
// | ||
// Created by Ian Keen on 15/06/2016. | ||
// | ||
// | ||
|
||
import Redbird | ||
|
||
/// Provides Redis based storage of key/value pairs | ||
public final class RedisStorage: Storage { | ||
//MARKL - Private | ||
private let client: Redbird | ||
|
||
//MARK: - Public | ||
public init(address: String, port: UInt16, password: String?) throws { | ||
let config = RedbirdConfig(address: address, port: port, password: password) | ||
self.client = try Redbird(config: config) | ||
} | ||
|
||
//MARK: - Storage | ||
public func set<T: StorableType>(type: T.Type, in: StorageNamespace, key: String, value: T) throws { | ||
guard let value = value as? RedisStorable else { throw StorageError.unsupportedType(value: T.self) } | ||
let key = "\(`in`.namespace):\(key)" | ||
do { | ||
try self.client.command("DEL", params: [key]) | ||
try self.client.command(value.redisStoreCommand, params: [key] + value.redisStoreParams) | ||
} | ||
catch let error { throw StorageError.internalError(error: error) } | ||
} | ||
public func get<T: StorableType>(type: T.Type, in: StorageNamespace, key: String) -> T? { | ||
guard let type = type as? RedisRetrievable.Type else { print("Unsupported data type: \(T.self)"); return nil } | ||
let key = "\(`in`.namespace):\(key)" | ||
do { | ||
let result = try self.client.command(type.redisRetrieveCommand, params: [key]) | ||
guard let stringValue = try result.toMaybeString() else { return nil } | ||
return type.redisValue(from: stringValue) as? T | ||
} | ||
catch let error { print("\(error)"); return nil } | ||
} | ||
} | ||
|
||
//MARK: - Redis Serialization | ||
protocol RedisStorable { | ||
var redisStoreCommand: String { get } | ||
var redisStoreParams: [String] { get } | ||
} | ||
extension RedisStorable { | ||
var redisStoreCommand: String { return "SET" } | ||
var redisStoreParams: [String] { return [String(self)] } | ||
} | ||
|
||
//MARK: - Redis Deserialization | ||
protocol RedisRetrievable { | ||
static var redisRetrieveCommand: String { get } | ||
static func redisValue(from: String) -> Self? | ||
} | ||
extension RedisRetrievable { | ||
static var redisRetrieveCommand: String { return "GET" } | ||
} | ||
|
||
//MARK: - RedisStorable/RedisRetrievable Implementations | ||
extension String: RedisStorable, RedisRetrievable { | ||
static func redisValue(from: String) -> String? { return from } | ||
} | ||
extension Int: RedisStorable, RedisRetrievable { | ||
var redisStoreParams: [String] { return [ String(self)] } | ||
static func redisValue(from: String) -> Int? { return Int(from) } | ||
} | ||
extension Bool: RedisStorable, RedisRetrievable { | ||
static func redisValue(from: String) -> Bool? { | ||
return (from == "true" ? true : false) | ||
} | ||
} | ||
|
||
//TOOD | ||
// I think these are wrong... need to test!! | ||
extension Sequence where Iterator.Element: RedisStorable { | ||
var redisStoreCommand: String { return "LPUSH" } | ||
var redisStoreParams: [String] { | ||
return [self | ||
.flatMap { $0.redisStoreParams } | ||
.joined(separator: ";")] | ||
} | ||
} | ||
extension Sequence where Iterator.Element: RedisRetrievable { | ||
var redisRetrieveCommand: String { return "MGET" } | ||
static func redisValue(from: String) -> Self? { | ||
return from.components(separatedBy: ";") as? Self | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.