Add tests for FFI functions
Improve API
This commit is contained in:
parent
10e3d52902
commit
0dfb712ef7
9 changed files with 1001 additions and 121 deletions
|
@ -17,13 +17,13 @@
|
|||
7BDB96B32077C38E009D0651 /* RustObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB96AA2077C38E009D0651 /* RustObject.swift */; };
|
||||
7BDB96B42077C38E009D0651 /* OptionalRustObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB96AB2077C38E009D0651 /* OptionalRustObject.swift */; };
|
||||
7BDB96B52077C38E009D0651 /* TupleResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB96AC2077C38E009D0651 /* TupleResult.swift */; };
|
||||
7BDB96B62077C38E009D0651 /* TxReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB96AD2077C38E009D0651 /* TxReport.swift */; };
|
||||
7BDB96B72077C38E009D0651 /* TypedValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB96AE2077C38E009D0651 /* TypedValue.swift */; };
|
||||
7BDB96C02077CD7A009D0651 /* libmentat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BDB96BF2077CD7A009D0651 /* libmentat.a */; };
|
||||
7BDB96C22077CD98009D0651 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BDB96C12077CD98009D0651 /* libresolv.tbd */; };
|
||||
7BDB96C62077D347009D0651 /* Date+Int64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB96C52077D346009D0651 /* Date+Int64.swift */; };
|
||||
7BDB96C9207B735A009D0651 /* fixtures in Resources */ = {isa = PBXBuildFile; fileRef = 7BDB96C8207B735A009D0651 /* fixtures */; };
|
||||
7BDB96CC207B7684009D0651 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDB96CB207B7684009D0651 /* Errors.swift */; };
|
||||
7BEB7D25207BE3BF000369AD /* libtoodle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BEB7D21207BDDEF000369AD /* libtoodle.a */; };
|
||||
7BEB7D2C207D03DA000369AD /* TxReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEB7D2B207D03DA000369AD /* TxReport.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -50,7 +50,6 @@
|
|||
7BDB96AA2077C38E009D0651 /* RustObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RustObject.swift; sourceTree = "<group>"; };
|
||||
7BDB96AB2077C38E009D0651 /* OptionalRustObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionalRustObject.swift; sourceTree = "<group>"; };
|
||||
7BDB96AC2077C38E009D0651 /* TupleResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TupleResult.swift; sourceTree = "<group>"; };
|
||||
7BDB96AD2077C38E009D0651 /* TxReport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TxReport.swift; sourceTree = "<group>"; };
|
||||
7BDB96AE2077C38E009D0651 /* TypedValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypedValue.swift; sourceTree = "<group>"; };
|
||||
7BDB96BF2077CD7A009D0651 /* libmentat.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmentat.a; path = ../../../target/universal/release/libmentat.a; sourceTree = "<group>"; };
|
||||
7BDB96C12077CD98009D0651 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
|
||||
|
@ -58,6 +57,9 @@
|
|||
7BDB96C52077D346009D0651 /* Date+Int64.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Int64.swift"; sourceTree = "<group>"; };
|
||||
7BDB96C8207B735A009D0651 /* fixtures */ = {isa = PBXFileReference; lastKnownFileType = folder; name = fixtures; path = ../../../../fixtures; sourceTree = "<group>"; };
|
||||
7BDB96CB207B7684009D0651 /* Errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = "<group>"; };
|
||||
7BEB7D21207BDDEF000369AD /* libtoodle.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtoodle.a; path = ../../../target/universal/release/libtoodle.a; sourceTree = "<group>"; };
|
||||
7BEB7D23207BE2AF000369AD /* libmentat_ffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmentat_ffi.a; path = ../../../target/universal/release/libmentat_ffi.a; sourceTree = "<group>"; };
|
||||
7BEB7D2B207D03DA000369AD /* TxReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TxReport.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -66,7 +68,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7BDB96C22077CD98009D0651 /* libresolv.tbd in Frameworks */,
|
||||
7BDB96C02077CD7A009D0651 /* libmentat.a in Frameworks */,
|
||||
7BEB7D25207BE3BF000369AD /* libtoodle.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -106,11 +108,11 @@
|
|||
7BDB96CA207B7672009D0651 /* Errors */,
|
||||
7BDB96C42077D346009D0651 /* Extensions */,
|
||||
7BDB96BA2077C42B009D0651 /* Core */,
|
||||
7BDB96A42077C301009D0651 /* Query */,
|
||||
7BDB96B92077C403009D0651 /* Rust */,
|
||||
7BDB96A82077C38E009D0651 /* store.h */,
|
||||
7BDB96A72077C38D009D0651 /* Mentat.swift */,
|
||||
7BDB96A42077C301009D0651 /* Query */,
|
||||
7BDB96B82077C3B2009D0651 /* Transact */,
|
||||
7BEB7D26207BE5BB000369AD /* Transact */,
|
||||
7BDB968D2077C299009D0651 /* Mentat.h */,
|
||||
7BDB968E2077C299009D0651 /* Info.plist */,
|
||||
7BDB96C32077D090009D0651 /* module.map */,
|
||||
|
@ -138,14 +140,6 @@
|
|||
path = Query;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7BDB96B82077C3B2009D0651 /* Transact */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7BDB96AD2077C38E009D0651 /* TxReport.swift */,
|
||||
);
|
||||
path = Transact;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7BDB96B92077C403009D0651 /* Rust */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -166,6 +160,8 @@
|
|||
7BDB96BE2077CD7A009D0651 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7BEB7D23207BE2AF000369AD /* libmentat_ffi.a */,
|
||||
7BEB7D21207BDDEF000369AD /* libtoodle.a */,
|
||||
7BDB96C12077CD98009D0651 /* libresolv.tbd */,
|
||||
7BDB96BF2077CD7A009D0651 /* libmentat.a */,
|
||||
);
|
||||
|
@ -188,6 +184,14 @@
|
|||
path = Errors;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7BEB7D26207BE5BB000369AD /* Transact */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7BEB7D2B207D03DA000369AD /* TxReport.swift */,
|
||||
);
|
||||
path = Transact;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
|
@ -300,8 +304,8 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7BDB96B32077C38E009D0651 /* RustObject.swift in Sources */,
|
||||
7BDB96B62077C38E009D0651 /* TxReport.swift in Sources */,
|
||||
7BDB96C62077D347009D0651 /* Date+Int64.swift in Sources */,
|
||||
7BEB7D2C207D03DA000369AD /* TxReport.swift in Sources */,
|
||||
7BDB96B42077C38E009D0651 /* OptionalRustObject.swift in Sources */,
|
||||
7BDB96B22077C38E009D0651 /* RelResult.swift in Sources */,
|
||||
7BDB96AF2077C38E009D0651 /* Query.swift in Sources */,
|
||||
|
|
|
@ -7,6 +7,10 @@ import Mentatlib
|
|||
|
||||
class TypedValue: OptionalRustObject {
|
||||
|
||||
var valueType: ValueType {
|
||||
return typed_value_value_type(self.raw!)
|
||||
}
|
||||
|
||||
func asLong() -> Int64 {
|
||||
defer {
|
||||
self.raw = nil
|
||||
|
@ -32,7 +36,8 @@ class TypedValue: OptionalRustObject {
|
|||
defer {
|
||||
self.raw = nil
|
||||
}
|
||||
return typed_value_as_boolean(self.raw!) == 0 ? false : true
|
||||
let v = typed_value_as_boolean(self.raw!)
|
||||
return v > 0
|
||||
}
|
||||
|
||||
func asDouble() -> Double {
|
||||
|
|
|
@ -8,7 +8,7 @@ import Mentatlib
|
|||
|
||||
protocol Observing {
|
||||
// define functions for store observation
|
||||
func transactionDidOccur(key: String, reports: [TxReport])
|
||||
func transactionDidOccur(key: String, reports: [TransactionChange])
|
||||
}
|
||||
|
||||
protocol Observable {
|
||||
|
@ -27,16 +27,15 @@ class Mentat: RustObject {
|
|||
self.init(raw: store_open(storeURI))
|
||||
}
|
||||
|
||||
func transact(transaction: String) throws -> Bool {
|
||||
func transact(transaction: String) throws -> TxReport {
|
||||
let result = store_transact(self.raw, transaction).pointee
|
||||
guard let _ = result.ok else {
|
||||
guard let success = result.ok else {
|
||||
if let error = result.err {
|
||||
throw MentatError(message: String(cString: error))
|
||||
}
|
||||
throw MentatError(message: "Unspecified Error")
|
||||
}
|
||||
print("Successfull")
|
||||
return true
|
||||
return TxReport(raw: success)
|
||||
}
|
||||
|
||||
func entidForAttribute(attribute: String) -> Int64 {
|
||||
|
@ -70,6 +69,78 @@ class Mentat: RustObject {
|
|||
return TypedValue(raw: success)
|
||||
}
|
||||
|
||||
func set(date value: Date, forAttribute attribute: String, onEntity entid: Int64) throws {
|
||||
let result = store_set_timestamp_for_attribute_on_entid(self.intoRaw(), entid, attribute, value.toMicroseconds())
|
||||
guard let err = result.pointee.err else {
|
||||
return
|
||||
}
|
||||
|
||||
throw QueryError.executionFailed(message: String(cString: err))
|
||||
}
|
||||
|
||||
func set(long value: Int64, forAttribute attribute: String, onEntity entid: Int64) throws {
|
||||
let result = store_set_long_for_attribute_on_entid(self.intoRaw(), entid, attribute, value)
|
||||
guard let err = result.pointee.err else {
|
||||
return
|
||||
}
|
||||
|
||||
throw QueryError.executionFailed(message: String(cString: err))
|
||||
}
|
||||
|
||||
func set(reference value: Int64, forAttribute attribute: String, onEntity entid: Int64) throws {
|
||||
let result = store_set_entid_for_attribute_on_entid(self.intoRaw(), entid, attribute, value)
|
||||
guard let err = result.pointee.err else {
|
||||
return
|
||||
}
|
||||
|
||||
throw QueryError.executionFailed(message: String(cString: err))
|
||||
}
|
||||
|
||||
func setKeywordReference(value: String, forAttribute attribute: String, onEntity entid: Int64) throws {
|
||||
let result = store_set_kw_ref_for_attribute_on_entid(self.intoRaw(), entid, attribute, value)
|
||||
guard let err = result.pointee.err else {
|
||||
return
|
||||
}
|
||||
|
||||
throw QueryError.executionFailed(message: String(cString: err))
|
||||
}
|
||||
|
||||
func set(boolean value: Bool, forAttribute attribute: String, onEntity entid: Int64) throws {
|
||||
let result = store_set_boolean_for_attribute_on_entid(self.intoRaw(), entid, attribute, value ? 1 : 0)
|
||||
guard let err = result.pointee.err else {
|
||||
return
|
||||
}
|
||||
|
||||
throw QueryError.executionFailed(message: String(cString: err))
|
||||
}
|
||||
|
||||
func set(double value: Double, forAttribute attribute: String, onEntity entid: Int64) throws {
|
||||
let result = store_set_double_for_attribute_on_entid(self.intoRaw(), entid, attribute, value)
|
||||
guard let err = result.pointee.err else {
|
||||
return
|
||||
}
|
||||
|
||||
throw QueryError.executionFailed(message: String(cString: err))
|
||||
}
|
||||
|
||||
func set(string value: String, forAttribute attribute: String, onEntity entid: Int64) throws {
|
||||
let result = store_set_string_for_attribute_on_entid(self.intoRaw(), entid, attribute, value)
|
||||
guard let err = result.pointee.err else {
|
||||
return
|
||||
}
|
||||
|
||||
throw QueryError.executionFailed(message: String(cString: err))
|
||||
}
|
||||
|
||||
func set(uuid value: UUID, forAttribute attribute: String, onEntity entid: Int64) throws {
|
||||
let result = store_set_uuid_for_attribute_on_entid(self.intoRaw(), entid, attribute, value.uuidString)
|
||||
guard let err = result.pointee.err else {
|
||||
return
|
||||
}
|
||||
|
||||
throw QueryError.executionFailed(message: String(cString: err))
|
||||
}
|
||||
|
||||
override func cleanup(pointer: OpaquePointer) {
|
||||
store_destroy(pointer)
|
||||
}
|
||||
|
@ -99,20 +170,19 @@ extension Mentat: Observable {
|
|||
}
|
||||
}
|
||||
|
||||
private func transactionObserverCallback(key: UnsafePointer<CChar>, reports: UnsafePointer<TxReportList>) {
|
||||
private func transactionObserverCallback(key: UnsafePointer<CChar>, reports: UnsafePointer<TxChangeList>) {
|
||||
// needs to be done in the same thread as the calling thread otherwise the TxReportList might be released before
|
||||
// we can reference it.
|
||||
let key = String(cString: key)
|
||||
guard let observer = Mentat.observers[key] else { return }
|
||||
|
||||
let len = Int(reports.pointee.len)
|
||||
var txReports = [TxReport]()
|
||||
for i in 0..<len {
|
||||
let raw = tx_report_list_entry_at(reports, i)
|
||||
let report = TxReport(raw: raw!)
|
||||
txReports.append(report)
|
||||
}
|
||||
// let len = Int(reports.pointee.len)
|
||||
// var txReports = [TxReport]()
|
||||
// for i in 0..<len {
|
||||
// guard let report = tx_report_list_entry_at(reports, i)?.pointee else { continue }
|
||||
// txReports.append(TxReport(raw: report))
|
||||
// }
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
observer.transactionDidOccur(key: key, reports: txReports)
|
||||
observer.transactionDidOccur(key: key, reports: [TransactionChange]())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,84 +5,81 @@
|
|||
import Foundation
|
||||
import Mentatlib
|
||||
|
||||
enum QueryResult<T> {
|
||||
case error(Error)
|
||||
case success(T)
|
||||
}
|
||||
|
||||
class Query: OptionalRustObject {
|
||||
|
||||
func bind(varName: String, toInt value: Int32) throws {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
query_builder_bind_int(r, varName, value)
|
||||
}
|
||||
|
||||
func bind(varName: String, toLong value: Int64) throws {
|
||||
func bind(varName: String, toLong value: Int64) throws -> Query {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
query_builder_bind_long(r, varName, value)
|
||||
return self
|
||||
}
|
||||
|
||||
func bind(varName: String, toReference value: Int64) throws {
|
||||
func bind(varName: String, toReference value: Int64) throws -> Query {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
query_builder_bind_ref(r, varName, value)
|
||||
return self
|
||||
}
|
||||
|
||||
func bind(varName: String, toReference value: String) throws {
|
||||
func bind(varName: String, toReference value: String) throws -> Query {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
query_builder_bind_ref_kw(r, varName, value)
|
||||
return self
|
||||
}
|
||||
|
||||
func bind(varName: String, toKeyword value: String) throws {
|
||||
func bind(varName: String, toKeyword value: String) throws -> Query {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
query_builder_bind_kw(r, varName, value)
|
||||
return self
|
||||
}
|
||||
|
||||
func bind(varName: String, toBoolean value: Bool) throws {
|
||||
func bind(varName: String, toBoolean value: Bool) throws -> Query {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
query_builder_bind_boolean(r, varName, value ? 1 : 0)
|
||||
return self
|
||||
}
|
||||
|
||||
func bind(varName: String, toDouble value: Double) throws {
|
||||
func bind(varName: String, toDouble value: Double) throws -> Query {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
query_builder_bind_double(r, varName, value)
|
||||
return self
|
||||
}
|
||||
|
||||
func bind(varName: String, toDate value: Date) throws {
|
||||
func bind(varName: String, toDate value: Date) throws -> Query {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
query_builder_bind_timestamp(r, varName, value.toMicroseconds())
|
||||
return self
|
||||
}
|
||||
|
||||
func bind(varName: String, toString value: String) throws {
|
||||
func bind(varName: String, toString value: String) throws -> Query {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
query_builder_bind_string(r, varName, value)
|
||||
return self
|
||||
}
|
||||
|
||||
func bind(varName: String, toUuid value: UUID) throws {
|
||||
func bind(varName: String, toUuid value: UUID) throws -> Query {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
query_builder_bind_uuid(r, varName, value.uuidString)
|
||||
return self
|
||||
}
|
||||
|
||||
func executeMap(map: @escaping (QueryResult<TupleResult>) -> Void) throws {
|
||||
func executeMap(map: @escaping (TupleResult?, QueryError?) -> Void) throws {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
|
@ -93,7 +90,7 @@ class Query: OptionalRustObject {
|
|||
|
||||
if let err = result.pointee.err {
|
||||
let message = String(cString: err)
|
||||
map(QueryResult.error(QueryError.executionFailed(message: message)))
|
||||
map(nil, QueryError.executionFailed(message: message))
|
||||
return
|
||||
}
|
||||
guard let rowsPtr = result.pointee.ok else {
|
||||
|
@ -101,12 +98,12 @@ class Query: OptionalRustObject {
|
|||
}
|
||||
let rows = RelResult(raw: rowsPtr)
|
||||
for row in rows {
|
||||
map(QueryResult.success(row))
|
||||
map(row, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func execute(callback: @escaping (QueryResult<RelResult?>) -> Void) throws {
|
||||
func execute(callback: @escaping (RelResult?, QueryError?) -> Void) throws {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
|
@ -117,18 +114,18 @@ class Query: OptionalRustObject {
|
|||
|
||||
if let err = result.pointee.err {
|
||||
let message = String(cString: err)
|
||||
callback(QueryResult.error(QueryError.executionFailed(message: message)))
|
||||
callback(nil, QueryError.executionFailed(message: message))
|
||||
return
|
||||
}
|
||||
guard let results = result.pointee.ok else {
|
||||
callback(QueryResult.success(nil))
|
||||
callback(nil, nil)
|
||||
return
|
||||
}
|
||||
callback(QueryResult.success(RelResult(raw: results)))
|
||||
callback(RelResult(raw: results), nil)
|
||||
}
|
||||
}
|
||||
|
||||
func executeScalar(callback: @escaping (QueryResult<TypedValue?>) -> Void) throws {
|
||||
func executeScalar(callback: @escaping (TypedValue?, QueryError?) -> Void) throws {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
|
@ -139,17 +136,17 @@ class Query: OptionalRustObject {
|
|||
|
||||
if let err = result.pointee.err {
|
||||
let message = String(cString: err)
|
||||
callback(QueryResult.error(QueryError.executionFailed(message: message)))
|
||||
callback(nil, QueryError.executionFailed(message: message))
|
||||
}
|
||||
guard let results = result.pointee.ok else {
|
||||
callback(QueryResult.success(nil))
|
||||
callback(nil, nil)
|
||||
return
|
||||
}
|
||||
callback(QueryResult.success(TypedValue(raw: OpaquePointer(results))))
|
||||
callback(TypedValue(raw: OpaquePointer(results)), nil)
|
||||
}
|
||||
}
|
||||
|
||||
func executeColl(callback: @escaping (QueryResult<ColResult?>) -> Void) throws {
|
||||
func executeColl(callback: @escaping (ColResult?, QueryError?) -> Void) throws {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
|
@ -160,17 +157,17 @@ class Query: OptionalRustObject {
|
|||
|
||||
if let err = result.pointee.err {
|
||||
let message = String(cString: err)
|
||||
callback(QueryResult.error(QueryError.executionFailed(message: message)))
|
||||
callback(nil, QueryError.executionFailed(message: message))
|
||||
}
|
||||
guard let results = result.pointee.ok else {
|
||||
callback(QueryResult.success(nil))
|
||||
callback(nil, nil)
|
||||
return
|
||||
}
|
||||
callback(QueryResult.success(ColResult(raw: results)))
|
||||
callback(ColResult(raw: results), nil)
|
||||
}
|
||||
}
|
||||
|
||||
func executeCollMap(map: @escaping (QueryResult<TypedValue>) -> Void) throws {
|
||||
func executeCollMap(map: @escaping (TypedValue?, QueryError?) -> Void) throws {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
|
@ -181,7 +178,7 @@ class Query: OptionalRustObject {
|
|||
|
||||
if let err = result.pointee.err {
|
||||
let message = String(cString: err)
|
||||
map(QueryResult.error(QueryError.executionFailed(message: message)))
|
||||
map(nil, QueryError.executionFailed(message: message))
|
||||
return
|
||||
}
|
||||
guard let cols = result.pointee.ok else {
|
||||
|
@ -189,12 +186,12 @@ class Query: OptionalRustObject {
|
|||
}
|
||||
let rowList = ColResult(raw: cols)
|
||||
for row in rowList {
|
||||
map(QueryResult.success(row))
|
||||
map(row, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func executeTuple(callback: @escaping (QueryResult<TupleResult?>) -> Void) throws {
|
||||
func executeTuple(callback: @escaping (TupleResult?, QueryError?) -> Void) throws {
|
||||
guard let r = self.raw else {
|
||||
throw QueryError.builderConsumed
|
||||
}
|
||||
|
@ -205,13 +202,13 @@ class Query: OptionalRustObject {
|
|||
|
||||
if let err = result.pointee.err {
|
||||
let message = String(cString: err)
|
||||
callback(QueryResult.error(QueryError.executionFailed(message: message)))
|
||||
callback(nil, QueryError.executionFailed(message: message))
|
||||
}
|
||||
guard let results = result.pointee.ok else {
|
||||
callback(QueryResult.success(nil))
|
||||
callback(nil, nil)
|
||||
return
|
||||
}
|
||||
callback(QueryResult.success(TupleResult(raw: OpaquePointer(results))))
|
||||
callback(TupleResult(raw: OpaquePointer(results)), nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,40 +7,40 @@ import Mentatlib
|
|||
|
||||
class TupleResult: OptionalRustObject {
|
||||
|
||||
func get(index: Int32) -> TypedValue {
|
||||
return TypedValue(raw: value_at_index(self.raw!, index))
|
||||
func get(index: Int) -> TypedValue {
|
||||
return TypedValue(raw: value_at_index(self.raw!, Int32(index)))
|
||||
}
|
||||
|
||||
func asLong(index: Int32) -> Int64 {
|
||||
return value_at_index_as_long(self.raw!, index)
|
||||
func asLong(index: Int) -> Int64 {
|
||||
return value_at_index_as_long(self.raw!, Int32(index))
|
||||
}
|
||||
|
||||
func asEntid(index: Int32) -> Int64 {
|
||||
return value_at_index_as_entid(self.raw!, index)
|
||||
func asEntid(index: Int) -> Int64 {
|
||||
return value_at_index_as_entid(self.raw!, Int32(index))
|
||||
}
|
||||
|
||||
func asKeyword(index: Int32) -> String {
|
||||
return String(cString: value_at_index_as_kw(self.raw!, index))
|
||||
func asKeyword(index: Int) -> String {
|
||||
return String(cString: value_at_index_as_kw(self.raw!, Int32(index)))
|
||||
}
|
||||
|
||||
func asBool(index: Int32) -> Bool {
|
||||
return value_at_index_as_boolean(self.raw!, index) == 0 ? false : true
|
||||
func asBool(index: Int) -> Bool {
|
||||
return value_at_index_as_boolean(self.raw!, Int32(index)) == 0 ? false : true
|
||||
}
|
||||
|
||||
func asDouble(index: Int32) -> Double {
|
||||
return value_at_index_as_double(self.raw!, index)
|
||||
func asDouble(index: Int) -> Double {
|
||||
return value_at_index_as_double(self.raw!, Int32(index))
|
||||
}
|
||||
|
||||
func asDate(index: Int32) -> Date {
|
||||
return Date(timeIntervalSince1970: TimeInterval(value_at_index_as_timestamp(self.raw!, index)))
|
||||
func asDate(index: Int) -> Date {
|
||||
return Date(timeIntervalSince1970: TimeInterval(value_at_index_as_timestamp(self.raw!, Int32(index))))
|
||||
}
|
||||
|
||||
func asString(index: Int32) -> String {
|
||||
return String(cString: value_at_index_as_string(self.raw!, index))
|
||||
func asString(index: Int) -> String {
|
||||
return String(cString: value_at_index_as_string(self.raw!, Int32(index)))
|
||||
}
|
||||
|
||||
func asUUID(index: Int32) -> UUID? {
|
||||
return UUID(uuidString: String(cString: value_at_index_as_uuid(self.raw!, index)))
|
||||
func asUUID(index: Int) -> UUID? {
|
||||
return UUID(uuidString: String(cString: value_at_index_as_uuid(self.raw!, Int32(index))))
|
||||
}
|
||||
|
||||
override func cleanup(pointer: OpaquePointer) {
|
||||
|
@ -73,8 +73,10 @@ class ColResultIterator: OptionalRustObject, IteratorProtocol {
|
|||
|
||||
extension ColResult: Sequence {
|
||||
func makeIterator() -> ColResultIterator {
|
||||
defer {
|
||||
self.raw = nil
|
||||
}
|
||||
guard let raw = self.raw else {
|
||||
print("list pointer destroyed")
|
||||
return ColResultIterator(iter: nil)
|
||||
}
|
||||
let rowIter = values_iter(raw)
|
||||
|
|
|
@ -9,7 +9,7 @@ protocol Destroyable {
|
|||
func cleanup(pointer: OpaquePointer)
|
||||
}
|
||||
|
||||
class RustObject: Destroyable {
|
||||
public class RustObject: Destroyable {
|
||||
var raw: OpaquePointer
|
||||
|
||||
lazy var uniqueId: ObjectIdentifier = {
|
||||
|
|
|
@ -1,22 +1,30 @@
|
|||
//
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import Foundation
|
||||
|
||||
import Mentatlib
|
||||
|
||||
class TxReport {
|
||||
var raw: UnsafePointer<ExternTxReport>
|
||||
class TxReport: RustObject {
|
||||
|
||||
required init(raw: UnsafePointer<ExternTxReport>) {
|
||||
self.raw = raw
|
||||
public var txId: Int64 {
|
||||
return tx_report_get_entid(self.raw)
|
||||
}
|
||||
|
||||
func intoRaw() -> UnsafePointer<ExternTxReport> {
|
||||
return self.raw
|
||||
public var txInstant: Date {
|
||||
return Date(timeIntervalSince1970: TimeInterval(tx_report_get_tx_instant(self.raw)))
|
||||
}
|
||||
|
||||
deinit {
|
||||
destroy(UnsafeMutableRawPointer(mutating: raw))
|
||||
public func entidForTmpId(tmpId: String) -> Int64? {
|
||||
guard let entidPtr = tx_report_entity_for_temp_id(self.raw, tmpId) else {
|
||||
return nil
|
||||
}
|
||||
return entidPtr.pointee
|
||||
}
|
||||
|
||||
override func cleanup(pointer: OpaquePointer) {
|
||||
tx_report_destroy(pointer)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,20 @@
|
|||
#ifndef store_h
|
||||
#define store_h
|
||||
#include <stdint.h>
|
||||
#include <Foundation/NSObjCRuntime.h>
|
||||
|
||||
struct ExternTxReport {
|
||||
struct TransactionChange {
|
||||
int64_t txid;
|
||||
int64_t*_Nonnull* _Nonnull changes;
|
||||
uint64_t len;
|
||||
};
|
||||
|
||||
struct TxChangeList {
|
||||
struct TransactionChange*_Nonnull* _Nonnull reports;
|
||||
uint64_t len;
|
||||
};
|
||||
typedef struct TxChangeList TxChangeList;
|
||||
|
||||
struct Result {
|
||||
void* _Nullable ok;
|
||||
char* _Nullable err;
|
||||
|
@ -23,20 +30,25 @@ struct Option {
|
|||
};
|
||||
typedef struct Option Option;
|
||||
|
||||
struct Store;
|
||||
|
||||
struct TxReportList {
|
||||
struct ExternTxReport*_Nonnull* _Nonnull reports;
|
||||
uint64_t len;
|
||||
typedef NS_ENUM(NSInteger, ValueType) {
|
||||
ValueTypeRef = 1,
|
||||
ValueTypeBoolean,
|
||||
ValueTypeInstant,
|
||||
ValueTypeLong,
|
||||
ValueTypeDouble,
|
||||
ValueTypeString,
|
||||
ValueTypeKeyword,
|
||||
ValueTypeUuid
|
||||
};
|
||||
typedef struct TxReportList TxReportList;
|
||||
|
||||
struct Query;
|
||||
struct TypedValue;
|
||||
struct QueryResultRow;
|
||||
struct QueryResultRows;
|
||||
struct QueryRowsIterator;
|
||||
struct QueryRowIterator;
|
||||
struct Store;
|
||||
struct TxReport;
|
||||
struct TypedValue;
|
||||
|
||||
// Store
|
||||
struct Store*_Nonnull store_open(const char*_Nonnull uri);
|
||||
|
@ -44,6 +56,7 @@ struct Store*_Nonnull store_open(const char*_Nonnull uri);
|
|||
void destroy(void* _Nullable obj);
|
||||
void query_builder_destroy(struct Query* _Nullable obj);
|
||||
void store_destroy(struct Store* _Nonnull obj);
|
||||
void tx_report_destroy(struct TxReport* _Nonnull obj);
|
||||
void typed_value_destroy(struct TypedValue* _Nullable obj);
|
||||
void typed_value_list_destroy(struct QueryResultRow* _Nullable obj);
|
||||
void typed_value_list_iter_destroy(struct QueryRowIterator* _Nullable obj);
|
||||
|
@ -52,15 +65,18 @@ void typed_value_result_set_iter_destroy(struct QueryRowsIterator* _Nullable obj
|
|||
|
||||
// transact
|
||||
struct Result*_Nonnull store_transact(struct Store*_Nonnull store, const char* _Nonnull transaction);
|
||||
const int64_t* _Nullable tx_report_entity_for_temp_id(const struct TxReport* _Nonnull report, const char* _Nonnull tempid);
|
||||
int64_t tx_report_get_entid(const struct TxReport* _Nonnull report);
|
||||
int64_t tx_report_get_tx_instant(const struct TxReport* _Nonnull report);
|
||||
|
||||
// Sync
|
||||
struct Result*_Nonnull store_sync(struct Store*_Nonnull store, const char* _Nonnull user_uuid, const char* _Nonnull server_uri);
|
||||
|
||||
// Observers
|
||||
void store_register_observer(struct Store*_Nonnull store, const char* _Nonnull key, const int64_t* _Nonnull attributes, const int64_t len, void (*_Nonnull callback_fn)(const char* _Nonnull key, const struct TxReportList* _Nonnull reports));
|
||||
void store_register_observer(struct Store*_Nonnull store, const char* _Nonnull key, const int64_t* _Nonnull attributes, const int64_t len, void (*_Nonnull callback_fn)(const char* _Nonnull key, const struct TxChangeList* _Nonnull reports));
|
||||
void store_unregister_observer(struct Store*_Nonnull store, const char* _Nonnull key);
|
||||
int64_t store_entid_for_attribute(struct Store*_Nonnull store, const char*_Nonnull attr);
|
||||
const struct int64_t changelist_entry_at(const struct ExternTxReport* _Nonnull report, size_t index);
|
||||
int64_t changelist_entry_at(const struct TransactionChange* _Nonnull report, size_t index);
|
||||
|
||||
// Query
|
||||
struct Query*_Nonnull store_query(struct Store*_Nonnull store, const char* _Nonnull query);
|
||||
|
@ -93,6 +109,7 @@ double typed_value_as_double(struct TypedValue*_Nonnull value);
|
|||
int64_t typed_value_as_timestamp(struct TypedValue*_Nonnull value);
|
||||
const char* _Nonnull typed_value_as_string(struct TypedValue*_Nonnull value);
|
||||
const char* _Nonnull typed_value_as_uuid(struct TypedValue*_Nonnull value);
|
||||
enum ValueType typed_value_value_type(struct TypedValue*_Nonnull value);
|
||||
|
||||
struct QueryResultRow* _Nullable row_at_index(struct QueryResultRows* _Nonnull rows, const int32_t index);
|
||||
struct QueryRowsIterator* _Nonnull rows_iter(struct QueryResultRows* _Nonnull rows);
|
||||
|
@ -128,7 +145,7 @@ struct Result*_Nonnull store_set_timestamp_for_attribute_on_entid(struct Store*_
|
|||
struct Result*_Nonnull store_set_string_for_attribute_on_entid(struct Store*_Nonnull store, const int64_t entid, const char* _Nonnull attribute, const char* _Nonnull value);
|
||||
struct Result*_Nonnull store_set_uuid_for_attribute_on_entid(struct Store*_Nonnull store, const int64_t entid, const char* _Nonnull attribute, const char* _Nonnull value);
|
||||
|
||||
// TxReports
|
||||
const struct ExternTxReport* _Nullable tx_report_list_entry_at(const struct TxReportList* _Nonnull list, size_t index);
|
||||
// Transaction change lists
|
||||
const struct TransactionChange* _Nullable tx_change_list_entry_at(const struct TxChangeList* _Nonnull list, size_t index);
|
||||
|
||||
#endif /* store_h */
|
||||
|
|
|
@ -3,11 +3,14 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import XCTest
|
||||
|
||||
@testable import Mentat
|
||||
|
||||
class MentatTests: XCTestCase {
|
||||
|
||||
var schema: String?
|
||||
var edn: String?
|
||||
var store: Mentat?
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
@ -35,8 +38,8 @@ class MentatTests: XCTestCase {
|
|||
func readSchema() throws -> String {
|
||||
guard let schema = self.schema else {
|
||||
let bundle = Bundle(for: type(of: self))
|
||||
guard let schemaPath = bundle.path(forResource: "cities", ofType: "schema") else { return "" }
|
||||
let schema = try String(contentsOf: URL(fileURLWithPath: schemaPath))
|
||||
let schemaUrl = bundle.url(forResource: "cities", withExtension: "schema", subdirectory: "fixtures")!
|
||||
let schema = try String(contentsOf: schemaUrl)
|
||||
self.schema = schema
|
||||
return schema
|
||||
}
|
||||
|
@ -44,16 +47,790 @@ class MentatTests: XCTestCase {
|
|||
return schema
|
||||
}
|
||||
|
||||
func testTransactVocabulary() {
|
||||
do {
|
||||
let vocab = try readSchema()
|
||||
func readEdn() throws -> String {
|
||||
guard let edn = self.edn else {
|
||||
let bundle = Bundle(for: type(of: self))
|
||||
let ednUrl = bundle.url(forResource: "all_seattle", withExtension: "edn", subdirectory: "fixtures")!
|
||||
let edn = try String(contentsOf: ednUrl)
|
||||
self.edn = edn
|
||||
return edn
|
||||
}
|
||||
|
||||
return edn
|
||||
}
|
||||
|
||||
func transactSchema(mentat: Mentat) throws -> TxReport {
|
||||
let vocab = try readSchema()
|
||||
let report = try mentat.transact(transaction: vocab)
|
||||
return report
|
||||
}
|
||||
|
||||
func transactEdn(mentat: Mentat) throws -> TxReport {
|
||||
let edn = try readEdn()
|
||||
let report = try mentat.transact(transaction: edn)
|
||||
return report
|
||||
}
|
||||
|
||||
func newStore() -> Mentat {
|
||||
guard let mentat = self.store else {
|
||||
let mentat = Mentat()
|
||||
let success = try mentat.transact(transaction: vocab)
|
||||
assert( success )
|
||||
let _ = try! self.transactSchema(mentat: mentat)
|
||||
let _ = try! self.transactEdn(mentat: mentat)
|
||||
self.store = mentat
|
||||
return mentat
|
||||
}
|
||||
|
||||
return mentat
|
||||
}
|
||||
|
||||
func populateWithTypesSchema(mentat: Mentat) -> TxReport? {
|
||||
do {
|
||||
let schema = """
|
||||
[
|
||||
[:db/add "b" :db/ident :foo/boolean]
|
||||
[:db/add "b" :db/valueType :db.type/boolean]
|
||||
[:db/add "b" :db/cardinality :db.cardinality/one]
|
||||
[:db/add "l" :db/ident :foo/long]
|
||||
[:db/add "l" :db/valueType :db.type/long]
|
||||
[:db/add "l" :db/cardinality :db.cardinality/one]
|
||||
[:db/add "r" :db/ident :foo/ref]
|
||||
[:db/add "r" :db/valueType :db.type/ref]
|
||||
[:db/add "r" :db/cardinality :db.cardinality/one]
|
||||
[:db/add "i" :db/ident :foo/instant]
|
||||
[:db/add "i" :db/valueType :db.type/instant]
|
||||
[:db/add "i" :db/cardinality :db.cardinality/one]
|
||||
[:db/add "d" :db/ident :foo/double]
|
||||
[:db/add "d" :db/valueType :db.type/double]
|
||||
[:db/add "d" :db/cardinality :db.cardinality/one]
|
||||
[:db/add "s" :db/ident :foo/string]
|
||||
[:db/add "s" :db/valueType :db.type/string]
|
||||
[:db/add "s" :db/cardinality :db.cardinality/one]
|
||||
[:db/add "k" :db/ident :foo/keyword]
|
||||
[:db/add "k" :db/valueType :db.type/keyword]
|
||||
[:db/add "k" :db/cardinality :db.cardinality/one]
|
||||
[:db/add "u" :db/ident :foo/uuid]
|
||||
[:db/add "u" :db/valueType :db.type/uuid]
|
||||
[:db/add "u" :db/cardinality :db.cardinality/one]
|
||||
]
|
||||
"""
|
||||
let report = try mentat.transact(transaction: schema)
|
||||
let stringEntid = report.entidForTmpId(tmpId: "s")!
|
||||
|
||||
let data = """
|
||||
[
|
||||
[:db/add "a" :foo/boolean true]
|
||||
[:db/add "a" :foo/long 25]
|
||||
[:db/add "a" :foo/instant #inst "2017-01-01T11:00:00.000Z"]
|
||||
[:db/add "a" :foo/double 11.23]
|
||||
[:db/add "a" :foo/string "The higher we soar the smaller we appear to those who cannot fly."]
|
||||
[:db/add "a" :foo/keyword :foo/string]
|
||||
[:db/add "a" :foo/uuid #uuid "550e8400-e29b-41d4-a716-446655440000"]
|
||||
[:db/add "b" :foo/boolean false]
|
||||
[:db/add "b" :foo/ref \(stringEntid)]
|
||||
[:db/add "b" :foo/long 50]
|
||||
[:db/add "b" :foo/instant #inst "2018-01-01T11:00:00.000Z"]
|
||||
[:db/add "b" :foo/double 22.46]
|
||||
[:db/add "b" :foo/string "Silence is worse; all truths that are kept silent become poisonous."]
|
||||
[:db/add "b" :foo/uuid #uuid "4cb3f828-752d-497a-90c9-b1fd516d5644"]
|
||||
]
|
||||
"""
|
||||
return try mentat.transact(transaction: data)
|
||||
} catch {
|
||||
assertionFailure(error.localizedDescription)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func test1TransactVocabulary() {
|
||||
do {
|
||||
let mentat = Mentat()
|
||||
let report = try transactSchema(mentat: mentat)
|
||||
XCTAssertNotNil(report)
|
||||
assert(report.txId > 0)
|
||||
} catch {
|
||||
assertionFailure(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add more tests once we are able to add vocabulary and transact entities
|
||||
func test2TransactEntities() {
|
||||
do {
|
||||
let mentat = Mentat()
|
||||
let _ = try self.transactSchema(mentat: mentat)
|
||||
let report = try self.transactEdn(mentat: mentat)
|
||||
XCTAssertNotNil(report)
|
||||
assert(report.txId > 0)
|
||||
let entid = report.entidForTmpId(tmpId: "a17592186045438")
|
||||
assert(entid == 65566)
|
||||
} catch {
|
||||
assertionFailure(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
func testQueryScalar() {
|
||||
let mentat = newStore()
|
||||
let query = "[:find ?n . :in ?name :where [(fulltext $ :community/name ?name) [[?e ?n]]]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query).bind(varName: "?name", toString: "Wallingford").executeScalar(callback: { (scalarResult, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
guard let result = scalarResult?.asString() else {
|
||||
return assertionFailure("No String value received")
|
||||
}
|
||||
assert(result == "KOMO Communities - Wallingford")
|
||||
expect.fulfill()
|
||||
})
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testQueryColl() {
|
||||
let mentat = newStore()
|
||||
let query = "[:find [?when ...] :where [_ :db/txInstant ?when] :order (asc ?when)]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query).executeColl(callback: { (collResult, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
guard let rows = collResult else {
|
||||
return assertionFailure("No results received")
|
||||
}
|
||||
// we are expecting 3 results
|
||||
for i in 0..<3 {
|
||||
let _ = rows.asDate(index: i)
|
||||
assert(true)
|
||||
}
|
||||
expect.fulfill()
|
||||
})
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testQueryCollResultIterator() {
|
||||
let mentat = newStore()
|
||||
let query = "[:find [?when ...] :where [_ :db/txInstant ?when] :order (asc ?when)]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query).executeColl(callback: { (collResult, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
guard let rows = collResult else {
|
||||
return assertionFailure("No results received")
|
||||
}
|
||||
|
||||
rows.forEach({ (value) in
|
||||
assert(value.valueType.rawValue == 2)
|
||||
})
|
||||
expect.fulfill()
|
||||
})
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testQueryTuple() {
|
||||
let mentat = newStore()
|
||||
let query = """
|
||||
[:find [?name ?cat]
|
||||
:where
|
||||
[?c :community/name ?name]
|
||||
[?c :community/type :community.type/website]
|
||||
[(fulltext $ :community/category "food") [[?c ?cat]]]]
|
||||
"""
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query).executeTuple(callback: { (tupleResult, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
guard let tuple = tupleResult else {
|
||||
return assertionFailure("expecting a result")
|
||||
}
|
||||
let name = tuple.asString(index: 0)
|
||||
let category = tuple.asString(index: 1)
|
||||
assert(name == "Community Harvest of Southwest Seattle")
|
||||
assert(category == "sustainable food")
|
||||
expect.fulfill()
|
||||
})
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testQueryRel() {
|
||||
let mentat = newStore()
|
||||
let query = """
|
||||
[:find ?name ?cat
|
||||
:where
|
||||
[?c :community/name ?name]
|
||||
[?c :community/type :community.type/website]
|
||||
[(fulltext $ :community/category "food") [[?c ?cat]]]]
|
||||
"""
|
||||
let expect = expectation(description: "Query is executed")
|
||||
let expectedResults = [("InBallard", "food"),
|
||||
("Seattle Chinatown Guide", "food"),
|
||||
("Community Harvest of Southwest Seattle", "sustainable food"),
|
||||
("University District Food Bank", "food bank")]
|
||||
try! mentat.query(query: query).execute(callback: { (relResult, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
guard let rows = relResult else {
|
||||
return assertionFailure("No results received")
|
||||
}
|
||||
|
||||
for (i, row) in rows.enumerated() {
|
||||
let (name, category) = expectedResults[i]
|
||||
assert( row.asString(index: 0) == name)
|
||||
assert(row.asString(index: 1) == category)
|
||||
}
|
||||
expect.fulfill()
|
||||
})
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testQueryRelResultIterator() {
|
||||
let mentat = newStore()
|
||||
let query = """
|
||||
[:find ?name ?cat
|
||||
:where
|
||||
[?c :community/name ?name]
|
||||
[?c :community/type :community.type/website]
|
||||
[(fulltext $ :community/category "food") [[?c ?cat]]]]
|
||||
"""
|
||||
let expect = expectation(description: "Query is executed")
|
||||
let expectedResults = [("InBallard", "food"),
|
||||
("Seattle Chinatown Guide", "food"),
|
||||
("Community Harvest of Southwest Seattle", "sustainable food"),
|
||||
("University District Food Bank", "food bank")]
|
||||
try! mentat.query(query: query).execute(callback: { (relResult, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
guard let rows = relResult else {
|
||||
return assertionFailure("No results received")
|
||||
}
|
||||
|
||||
var i = 0
|
||||
rows.forEach({ (row) in
|
||||
let (name, category) = expectedResults[i]
|
||||
i += 1
|
||||
assert(row.asString(index: 0) == name)
|
||||
assert(row.asString(index: 1) == category)
|
||||
})
|
||||
assert(i == 4)
|
||||
expect.fulfill()
|
||||
})
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testBindLong() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")
|
||||
let query = "[:find ?e . :in ?bool :where [?e :foo/boolean ?bool]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?bool", toBoolean: true)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asEntid() == aEntid)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testBindRef() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let stringEntid = mentat.entidForAttribute(attribute: ":foo/string")
|
||||
let bEntid = report.entidForTmpId(tmpId: "b")
|
||||
let query = "[:find ?e . :in ?ref :where [?e :foo/ref ?ref]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?ref", toReference: stringEntid)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asEntid() == bEntid)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testBindKwRef() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let bEntid = report.entidForTmpId(tmpId: "b")
|
||||
let query = "[:find ?e . :in ?ref :where [?e :foo/ref ?ref]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?ref", toReference: ":foo/string")
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asEntid() == bEntid)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testBindKw() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")
|
||||
let query = "[:find ?e . :in ?kw :where [?e :foo/keyword ?kw]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?kw", toKeyword: ":foo/string")
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asEntid() == aEntid)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testBindDate() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")
|
||||
let query = "[:find [?e ?d] :in ?now :where [?e :foo/instant ?d] [(< ?d ?now)]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?now", toDate: Date())
|
||||
.executeTuple { (row, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(row)
|
||||
assert(row?.asEntid(index: 0) == aEntid)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testBindString() {
|
||||
let mentat = newStore()
|
||||
let query = "[:find ?n . :in ?name :where [(fulltext $ :community/name ?name) [[?e ?n]]]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?name", toString: "Wallingford")
|
||||
.executeScalar(callback: { (scalarResult, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
guard let result = scalarResult?.asString() else {
|
||||
return assertionFailure("No String value received")
|
||||
}
|
||||
assert(result == "KOMO Communities - Wallingford")
|
||||
expect.fulfill()
|
||||
})
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testBindUuid() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")
|
||||
let query = "[:find ?e . :in ?uuid :where [?e :foo/uuid ?uuid]]"
|
||||
let uuid = UUID(uuidString: "550e8400-e29b-41d4-a716-446655440000")!
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?uuid", toUuid: uuid)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asEntid() == aEntid)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testBindBoolean() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")
|
||||
let query = "[:find ?e . :in ?bool :where [?e :foo/boolean ?bool]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?bool", toBoolean: true)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asEntid() == aEntid)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testBindDouble() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")
|
||||
let query = "[:find ?e . :in ?double :where [?e :foo/double ?double]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?double", toDouble: 11.23)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asEntid() == aEntid)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testTypedValueAsLong() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let query = "[:find ?v . :in ?e :where [?e :foo/long ?v]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?e", toReference: aEntid)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asLong() == 25)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testTypedValueAsRef() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let query = "[:find ?e . :where [?e :foo/long 25]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asEntid() == aEntid)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testTypedValueAsKw() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let query = "[:find ?v . :in ?e :where [?e :foo/keyword ?v]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?e", toReference: aEntid)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asKeyword() == ":foo/string")
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testTypedValueAsBoolean() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let query = "[:find ?v . :in ?e :where [?e :foo/boolean ?v]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?e", toReference: aEntid)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asBool() == true)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testTypedValueAsDouble() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let query = "[:find ?v . :in ?e :where [?e :foo/double ?v]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?e", toReference: aEntid)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asDouble() == 11.23)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testTypedValueAsDate() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let query = "[:find ?v . :in ?e :where [?e :foo/instant ?v]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
|
||||
let expectedDate = formatter.date(from: "2017-01-01T11:00:00+00:00")
|
||||
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?e", toReference: aEntid)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asDate() == expectedDate)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testTypedValueAsString() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let query = "[:find ?v . :in ?e :where [?e :foo/string ?v]]"
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?e", toReference: aEntid)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asString() == "The higher we soar the smaller we appear to those who cannot fly.")
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testTypedValueAsUuid() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let query = "[:find ?v . :in ?e :where [?e :foo/uuid ?v]]"
|
||||
let expectedUuid = UUID(uuidString: "550e8400-e29b-41d4-a716-446655440000")!
|
||||
let expect = expectation(description: "Query is executed")
|
||||
try! mentat.query(query: query)
|
||||
.bind(varName: "?e", toReference: aEntid)
|
||||
.executeScalar { (value, error) in
|
||||
assert(error == nil, "Unexpected error: \(String(describing: error))")
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asUUID() == expectedUuid)
|
||||
expect.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1) { error in
|
||||
if let error = error {
|
||||
assertionFailure("waitForExpectationsWithTimeout errored: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testValueForAttributeOfEntity() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let value = mentat.value(forAttribute: ":foo/long", ofEntity: aEntid)
|
||||
XCTAssertNotNil(value)
|
||||
assert(value?.asLong() == 25)
|
||||
}
|
||||
|
||||
func testEntidForAttribute() {
|
||||
let mentat = Mentat()
|
||||
let _ = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let entid = mentat.entidForAttribute(attribute: ":foo/long")
|
||||
assert(entid == 65540)
|
||||
}
|
||||
|
||||
func testSetLongForAttributeOfEntity() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let attr = ":foo/long"
|
||||
let pre = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(pre)
|
||||
assert(pre?.asLong() == 25)
|
||||
XCTAssertNoThrow(try mentat.set(long: 100, forAttribute: attr, onEntity: aEntid))
|
||||
let post = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(post)
|
||||
assert(post?.asLong() == 100)
|
||||
}
|
||||
|
||||
func testSetBooleanForAttributeOfEntity() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let attr = ":foo/boolean"
|
||||
let pre = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(pre)
|
||||
assert(pre?.asBool() == true)
|
||||
XCTAssertNoThrow(try mentat.set(boolean: false, forAttribute: attr, onEntity: aEntid))
|
||||
let post = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(post)
|
||||
let p = post?.asBool()
|
||||
assert(p == false)
|
||||
}
|
||||
|
||||
func testSetRefForAttributeOfEntity() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let bEntid = report.entidForTmpId(tmpId: "b")!
|
||||
let attr = ":foo/ref"
|
||||
let pre = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNil(pre)
|
||||
XCTAssertNoThrow(try mentat.set(reference: bEntid, forAttribute: attr, onEntity: aEntid))
|
||||
let post = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(post)
|
||||
assert(post?.asEntid() == bEntid)
|
||||
}
|
||||
|
||||
func testSetRefKwForAttributeOfEntity() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let attr = ":foo/ref"
|
||||
let pre = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNil(pre)
|
||||
XCTAssertNoThrow(try mentat.setKeywordReference(value: ":foo/long", forAttribute: attr, onEntity: aEntid))
|
||||
let post = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(post)
|
||||
assert(post?.asEntid() == 65540)
|
||||
}
|
||||
|
||||
func testSetDateForAttributeOfEntity() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let attr = ":foo/instant"
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
|
||||
let previousDate = formatter.date(from: "2017-01-01T11:00:00+00:00")
|
||||
|
||||
let pre = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(pre)
|
||||
assert(pre?.asDate() == previousDate)
|
||||
|
||||
let now = Date()
|
||||
XCTAssertNoThrow(try mentat.set(date: now, forAttribute: attr, onEntity: aEntid))
|
||||
let post = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(post)
|
||||
let p = post?.asDate()
|
||||
|
||||
assert(formatter.string(from: p!) == formatter.string(from: now))
|
||||
}
|
||||
|
||||
func testSetDoubleForAttributeOfEntity() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let attr = ":foo/double"
|
||||
let pre = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(pre)
|
||||
assert(pre?.asDouble() == 11.23)
|
||||
XCTAssertNoThrow(try mentat.set(double: 22.0, forAttribute: attr, onEntity: aEntid))
|
||||
let post = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(post)
|
||||
assert(post?.asDouble() == 22.0)
|
||||
}
|
||||
|
||||
func testSetStringForAttributeOfEntity() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let attr = ":foo/string"
|
||||
let pre = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(pre)
|
||||
assert(pre?.asString() == "The higher we soar the smaller we appear to those who cannot fly.")
|
||||
XCTAssertNoThrow(try mentat.set(string: "Become who you are!", forAttribute: attr, onEntity: aEntid))
|
||||
let post = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(post)
|
||||
assert(post?.asString() == "Become who you are!")
|
||||
}
|
||||
|
||||
func testSetUuidForAttributeOfEntity() {
|
||||
let mentat = Mentat()
|
||||
let report = self.populateWithTypesSchema(mentat: mentat)!
|
||||
let aEntid = report.entidForTmpId(tmpId: "a")!
|
||||
let previousUuid = UUID(uuidString: "550e8400-e29b-41d4-a716-446655440000")!
|
||||
let attr = ":foo/uuid"
|
||||
let pre = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(pre)
|
||||
assert(pre?.asUUID() == previousUuid)
|
||||
|
||||
let newUuid = UUID()
|
||||
XCTAssertNoThrow(try mentat.set(uuid: newUuid, forAttribute: attr, onEntity: aEntid))
|
||||
let post = mentat.value(forAttribute: attr, ofEntity: aEntid)
|
||||
XCTAssertNotNil(post)
|
||||
assert(post?.asUUID() == newUuid)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue