Implement InProgress transactions and InProgress and Entity builders on iOS
This commit is contained in:
parent
d8bde6ed97
commit
3865803981
10 changed files with 1462 additions and 15 deletions
|
@ -7,6 +7,9 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
7B64E44D209094520063909F /* InProgressBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B64E44A209094510063909F /* InProgressBuilder.swift */; };
|
||||
7B64E44E209094520063909F /* EntityBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B64E44B209094510063909F /* EntityBuilder.swift */; };
|
||||
7B64E44F209094520063909F /* InProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B64E44C209094520063909F /* InProgress.swift */; };
|
||||
7B74483D208DF667006CFFB0 /* Result+Unwrap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B74483C208DF667006CFFB0 /* Result+Unwrap.swift */; };
|
||||
7BAE75A22089020E00895D37 /* libmentat_ffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BEB7D23207BE2AF000369AD /* libmentat_ffi.a */; };
|
||||
7BAE75A42089022B00895D37 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BAE75A32089022B00895D37 /* libsqlite3.tbd */; };
|
||||
|
@ -39,6 +42,9 @@
|
|||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
7B64E44A209094510063909F /* InProgressBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InProgressBuilder.swift; sourceTree = "<group>"; };
|
||||
7B64E44B209094510063909F /* EntityBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntityBuilder.swift; sourceTree = "<group>"; };
|
||||
7B64E44C209094520063909F /* InProgress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InProgress.swift; sourceTree = "<group>"; };
|
||||
7B74483C208DF667006CFFB0 /* Result+Unwrap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Result+Unwrap.swift"; path = "Mentat/Extensions/Result+Unwrap.swift"; sourceTree = SOURCE_ROOT; };
|
||||
7B911E1A2085081D000998CB /* libtoodle.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtoodle.a; path = "../../../../sync-storage-prototype/rust/target/universal/release/libtoodle.a"; sourceTree = "<group>"; };
|
||||
7BAE75A32089022B00895D37 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
|
||||
|
@ -196,6 +202,9 @@
|
|||
7BEB7D26207BE5BB000369AD /* Transact */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7B64E44B209094510063909F /* EntityBuilder.swift */,
|
||||
7B64E44C209094520063909F /* InProgress.swift */,
|
||||
7B64E44A209094510063909F /* InProgressBuilder.swift */,
|
||||
7BEB7D2B207D03DA000369AD /* TxReport.swift */,
|
||||
);
|
||||
path = Transact;
|
||||
|
@ -321,8 +330,11 @@
|
|||
7BDB96CC207B7684009D0651 /* Errors.swift in Sources */,
|
||||
7BDB96B02077C38E009D0651 /* Mentat.swift in Sources */,
|
||||
7BDB96B72077C38E009D0651 /* TypedValue.swift in Sources */,
|
||||
7B64E44E209094520063909F /* EntityBuilder.swift in Sources */,
|
||||
7B64E44D209094520063909F /* InProgressBuilder.swift in Sources */,
|
||||
7BDB96B52077C38E009D0651 /* TupleResult.swift in Sources */,
|
||||
7B74483D208DF667006CFFB0 /* Result+Unwrap.swift in Sources */,
|
||||
7B64E44F209094520063909F /* InProgress.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -37,14 +37,6 @@
|
|||
BlueprintName = "MentatTests"
|
||||
ReferencedContainer = "container:Mentat.xcodeproj">
|
||||
</BuildableReference>
|
||||
<SkippedTests>
|
||||
<Test
|
||||
Identifier = "MentatTests/testBindBoolean()">
|
||||
</Test>
|
||||
<Test
|
||||
Identifier = "MentatTests/testBindDate()">
|
||||
</Test>
|
||||
</SkippedTests>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
//
|
||||
/* Copyright 2018 Mozilla
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
|
|
|
@ -69,8 +69,63 @@ class Mentat: RustObject {
|
|||
return TxReport(raw: try result.unwrap())
|
||||
}
|
||||
|
||||
/**
|
||||
Start a new transaction.
|
||||
|
||||
- Throws: `ResultError.error` if the creation of the transaction fails.
|
||||
- Throws: `ResultError.empty` if no `InProgress` is created.
|
||||
|
||||
- Returns: The `InProgress` used to manage the transaction
|
||||
*/
|
||||
func beginTransaction() throws -> InProgress {
|
||||
let result = store_begin_transaction(self.raw).pointee;
|
||||
return InProgress(raw: try result.unwrap())
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new transaction (`InProgress`) and returns an `InProgressBuilder` for that transaction.
|
||||
|
||||
- Throws: `ResultError.error` if the creation of the transaction fails.
|
||||
- Throws: `ResultError.empty` if no `InProgressBuilder` is created.
|
||||
|
||||
- Returns: an `InProgressBuilder` for this `InProgress`
|
||||
*/
|
||||
func entityBuilder() throws -> InProgressBuilder {
|
||||
let result = store_in_progress_builder(self.raw).pointee
|
||||
return InProgressBuilder(raw: try result.unwrap())
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new transaction (`InProgress`) and returns an `EntityBuilder` for the entity with `entid`
|
||||
for that transaction.
|
||||
|
||||
- Throws: `ResultError.error` if the creation of the transaction fails.
|
||||
- Throws: `ResultError.empty` if no `EntityBuilder` is created.
|
||||
|
||||
- Returns: an `EntityBuilder` for this `InProgress`
|
||||
*/
|
||||
func entityBuilder(forEntid entid: Entid) throws -> EntityBuilder {
|
||||
let result = store_entity_builder_from_entid(self.raw, entid).pointee
|
||||
return EntityBuilder(raw: try result.unwrap())
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new transaction (`InProgress`) and returns an `EntityBuilder` for a new entity with `tempId`
|
||||
for that transaction.
|
||||
|
||||
- Throws: `ResultError.error` if the creation of the transaction fails.
|
||||
- Throws: `ResultError.empty` if no `EntityBuilder` is created.
|
||||
|
||||
- Returns: an `EntityBuilder` for this `InProgress`
|
||||
*/
|
||||
func entityBuilder(forTempId tempId: String) throws -> EntityBuilder {
|
||||
let result = store_entity_builder_from_temp_id(self.raw, tempId).pointee
|
||||
return EntityBuilder(raw: try result.unwrap())
|
||||
}
|
||||
|
||||
/**
|
||||
Get the the `Entid` of the attribute.
|
||||
|
||||
- Parameter attribute: The string represeting the attribute whose `Entid` we are after.
|
||||
The string is represented as `:namespace/name`.
|
||||
|
||||
|
|
355
sdks/swift/Mentat/Mentat/Transact/EntityBuilder.swift
Normal file
355
sdks/swift/Mentat/Mentat/Transact/EntityBuilder.swift
Normal file
|
@ -0,0 +1,355 @@
|
|||
/* Copyright 2018 Mozilla
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of the
|
||||
* License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License. */
|
||||
|
||||
import Foundation
|
||||
import MentatStore
|
||||
|
||||
/**
|
||||
This class wraps a raw pointer that points to a Rust `EntityBuilder<InProgressBuilder>` object.
|
||||
|
||||
`EntityBuilder` provides a programmatic interface to performing assertions on a specific entity.
|
||||
It provides functions for adding and retracting values for attributes for an entity within
|
||||
an in progress transaction.
|
||||
|
||||
The `transact` function will transact the assertions that have been added to the `EntityBuilder`
|
||||
and pass back the `TxReport` that was generated by this transact and the `InProgress` that was
|
||||
used to perform the transact. This enables you to perform further transacts on the same `InProgress`
|
||||
before committing.
|
||||
|
||||
```
|
||||
let aEntid = txReport.entid(forTempId: "a")
|
||||
let bEntid = txReport.entid(forTempId: "b")
|
||||
do {
|
||||
let builder = try mentat.entityBuilder(forEntid: bEntid)
|
||||
try builder.add(keyword: ":foo/boolean", boolean: true)
|
||||
try builder.add(keyword: ":foo/instant", date: newDate)
|
||||
let (inProgress, report) = try builder.transact()
|
||||
try inProgress.transact(transaction: "[[:db/add \(aEntid) :foo/long 22]]")
|
||||
try inProgress.commit()
|
||||
} catch {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The `commit` function will transact and commit the assertions that have been added to the `EntityBuilder`.
|
||||
It will consume the `InProgress` used to perform the transact. It returns the `TxReport` generated by
|
||||
the transact. After calling `commit`, a new transaction must be started by calling `Mentat.beginTransaction()`
|
||||
in order to perform further actions.
|
||||
|
||||
```
|
||||
let aEntid = txReport.entid(forTempId: "a")
|
||||
do {
|
||||
let builder = try mentat.entityBuilder(forEntid: aEntid)
|
||||
try builder.add(keyword: ":foo/boolean", boolean: true)
|
||||
try builder.add(keyword: ":foo/instant", date: newDate)
|
||||
let report = try builder.commit()
|
||||
...
|
||||
} catch {
|
||||
...
|
||||
}
|
||||
```
|
||||
*/
|
||||
class EntityBuilder: OptionalRustObject {
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/long`.
|
||||
*/
|
||||
func add(keyword: String, long value: Int64) throws {
|
||||
try entity_builder_add_long(try self.validPointer(), keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/ref`.
|
||||
*/
|
||||
func add(keyword: String, reference value: Int64) throws {
|
||||
try entity_builder_add_ref(try self.validPointer(), keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/keyword`.
|
||||
*/
|
||||
func add(keyword: String, keyword value: String) throws {
|
||||
try entity_builder_add_keyword(try self.validPointer(), keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/boolean`.
|
||||
*/
|
||||
func add(keyword: String, boolean value: Bool) throws {
|
||||
try entity_builder_add_boolean(try self.validPointer(), keyword, value ? 1 : 0).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/double`.
|
||||
*/
|
||||
func add(keyword: String, double value: Double) throws {
|
||||
try entity_builder_add_double(try self.validPointer(), keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/instant`.
|
||||
*/
|
||||
func add(keyword: String, date value: Date) throws {
|
||||
try entity_builder_add_timestamp(try self.validPointer(), keyword, value.toMicroseconds()).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/string`.
|
||||
*/
|
||||
func add(keyword: String, string value: String) throws {
|
||||
try entity_builder_add_string(try self.validPointer(), keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/uuid`.
|
||||
*/
|
||||
func add(keyword: String, uuid value: UUID) throws {
|
||||
var rawUuid = value.uuid
|
||||
let _ = try withUnsafePointer(to: &rawUuid) { uuidPtr in
|
||||
try entity_builder_add_uuid(try self.validPointer(), keyword, uuidPtr).pointee.tryUnwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/long`.
|
||||
*/
|
||||
func retract(keyword: String, long value: Int64) throws {
|
||||
try entity_builder_retract_long(try self.validPointer(), keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/ref`.
|
||||
*/
|
||||
func retract(keyword: String, reference value: Int64) throws {
|
||||
try entity_builder_retract_ref(try self.validPointer(), keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/keyword`.
|
||||
*/
|
||||
func retract(keyword: String, keyword value: String) throws {
|
||||
try entity_builder_retract_keyword(try self.validPointer(), keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/boolean`.
|
||||
*/
|
||||
func retract(keyword: String, boolean value: Bool) throws {
|
||||
try entity_builder_retract_boolean(try self.validPointer(), keyword, value ? 1 : 0).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/double`.
|
||||
*/
|
||||
func retract(keyword: String, double value: Double) throws {
|
||||
try entity_builder_retract_double(try self.validPointer(), keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/instant`.
|
||||
*/
|
||||
func retract(keyword: String, date value: Date) throws {
|
||||
try entity_builder_retract_timestamp(try self.validPointer(), keyword, value.toMicroseconds()).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/string`.
|
||||
*/
|
||||
func retract(keyword: String, string value: String) throws {
|
||||
try entity_builder_retract_string(try self.validPointer(), keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value`.
|
||||
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/uuid`.
|
||||
*/
|
||||
func retract(keyword: String, uuid value: UUID) throws {
|
||||
var rawUuid = value.uuid
|
||||
let _ = try withUnsafePointer(to: &rawUuid) { uuidPtr in
|
||||
try entity_builder_retract_uuid(try self.validPointer(), keyword, uuidPtr).pointee.tryUnwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Transacts the added assertions. This consumes the pointer associated with this `EntityBuilder`
|
||||
such that no further assertions can be added after the `transact` has completed. To perform
|
||||
further assertions, use the `InProgress` returned from this function.
|
||||
|
||||
This does not commit the transaction. In order to do so, `commit` can be called on the `InProgress` returned
|
||||
from this function.
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if an error occured during the execution of the transact.
|
||||
|
||||
- Returns: The current `InProgress` and the `TxReport` generated by the transact.
|
||||
*/
|
||||
func transact() throws -> (InProgress, TxReport?) {
|
||||
defer {
|
||||
self.raw = nil
|
||||
}
|
||||
let result = entity_builder_transact(try self.validPointer()).pointee
|
||||
let inProgress = InProgress(raw: result.inProgress)
|
||||
guard let report = try result.result.pointee.tryUnwrap() else {
|
||||
return (inProgress, nil)
|
||||
}
|
||||
return (inProgress, TxReport(raw: report))
|
||||
}
|
||||
|
||||
/**
|
||||
Transacts the added assertions and commits. This consumes the pointer associated with this `EntityBuilder`
|
||||
and the associated `InProgress` such that no further assertions can be added after the `commit` has completed.
|
||||
To perform further assertions, a new `InProgress` or `EntityBuilder` should be created.
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if an error occured during the execution of the transact.
|
||||
|
||||
- Returns: The `TxReport` generated by the transact.
|
||||
*/
|
||||
func commit() throws -> TxReport {
|
||||
defer {
|
||||
self.raw = nil
|
||||
}
|
||||
return TxReport(raw: try entity_builder_commit(try self.validPointer()).pointee.unwrap())
|
||||
}
|
||||
|
||||
override func cleanup(pointer: OpaquePointer) {
|
||||
entity_builder_destroy(pointer)
|
||||
}
|
||||
}
|
184
sdks/swift/Mentat/Mentat/Transact/InProgress.swift
Normal file
184
sdks/swift/Mentat/Mentat/Transact/InProgress.swift
Normal file
|
@ -0,0 +1,184 @@
|
|||
/* Copyright 2018 Mozilla
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of the
|
||||
* License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License. */
|
||||
|
||||
import Foundation
|
||||
import MentatStore
|
||||
|
||||
/**
|
||||
This class wraps a raw pointer that points to a Rust `InProgress` object.
|
||||
|
||||
`InProgress` allows for multiple transacts to be performed in a single transaction.
|
||||
Each transact performed results in a `TxReport` that can be used to gather information
|
||||
to be used in subsequent transacts.
|
||||
|
||||
Committing an `InProgress` commits all the transacts that have been performed using
|
||||
that `InProgress`.
|
||||
|
||||
Rolling back and `InProgress` rolls back all the transacts that have been performed
|
||||
using that `InProgress`.
|
||||
|
||||
```
|
||||
do {
|
||||
let inProgress = try mentat.beginTransaction()
|
||||
let txReport = try inProgress.transact(transaction: "[[:db/add "a" :foo/long 22]]")
|
||||
let aEntid = txReport.entid(forTempId: "a")
|
||||
let report = try inProgress.transact(transaction: "[[:db/add "b" :foo/ref \(aEntid)] [:db/add "b" :foo/boolean true]]")
|
||||
try inProgress.commit()
|
||||
} catch {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
`InProgress` also provides a number of functions to generating an builder to assert datoms programatically.
|
||||
The two types of builder are `InProgressBuilder` and `EntityBuilder`.
|
||||
|
||||
`InProgressBuilder` takes the current `InProgress` and provides a programmatic interface to add
|
||||
and retract values from entities for which there exists an `Entid`. The provided `InProgress`
|
||||
is used to perform the transacts.
|
||||
|
||||
```
|
||||
let aEntid = txReport.entid(forTempId: "a")
|
||||
let bEntid = txReport.entid(forTempId: "b")
|
||||
do {
|
||||
let inProgress = try mentat.beginTransaction()
|
||||
let builder = try inProgress.builder()
|
||||
try builder.add(entid: bEntid, keyword: ":foo/boolean", boolean: true)
|
||||
try builder.add(entid: aEntid, keyword: ":foo/instant", date: newDate)
|
||||
let (inProgress, report) = try builder.transact()
|
||||
try inProgress.transact(transaction: "[[:db/add \(aEntid) :foo/long 22]]")
|
||||
try inProgress.commit()
|
||||
} catch {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
`EntityBuilder` takes the current `InProgress` and either an `Entid` or a `tempid` to provide
|
||||
a programmatic interface to add and retract values from a specific entity. The provided `InProgress`
|
||||
is used to perform the transacts.
|
||||
|
||||
```
|
||||
do {
|
||||
let transaction = try mentat.beginTransaction()
|
||||
let builder = try transaction.builder(forTempId: "b")
|
||||
try builder.add(keyword: ":foo/boolean", boolean: true)
|
||||
try builder.add(keyword: ":foo/instant", date: newDate)
|
||||
let (inProgress, report) = try builder.transact()
|
||||
let bEntid = report.entid(forTempId: "b")
|
||||
try inProgress.transact(transaction: "[[:db/add \(bEntid) :foo/long 22]]")
|
||||
try inProgress.commit()
|
||||
} catch {
|
||||
...
|
||||
}
|
||||
```
|
||||
*/
|
||||
class InProgress: OptionalRustObject {
|
||||
|
||||
/**
|
||||
Creates an `InProgressBuilder` using this `InProgress`.
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the `InProgress`
|
||||
has already been committed, or converted into a Builder.
|
||||
|
||||
- Returns: an `InProgressBuilder` for this `InProgress`
|
||||
*/
|
||||
func builder() throws -> InProgressBuilder {
|
||||
defer {
|
||||
self.raw = nil
|
||||
}
|
||||
return InProgressBuilder(raw: in_progress_builder(try self.validPointer()))
|
||||
}
|
||||
|
||||
/**
|
||||
Creates an `EntityBuilder` using this `InProgress` for the entity with `entid`.
|
||||
|
||||
- Parameter tempId: The `Entid` for this entity.
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the `InProgress`
|
||||
has already been committed, or converted into a Builder.
|
||||
|
||||
- Returns: an `EntityBuilder` for this `InProgress`
|
||||
*/
|
||||
func builder(forEntid entid: Int64) throws -> EntityBuilder {
|
||||
defer {
|
||||
self.raw = nil
|
||||
}
|
||||
return EntityBuilder(raw: in_progress_entity_builder_from_entid(try self.validPointer(), entid))
|
||||
}
|
||||
|
||||
/**
|
||||
Creates an `EntityBuilder` using this `InProgress` for a new entity with `tempId`.
|
||||
|
||||
- Parameter tempId: The temporary identifier for this entity.
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the `InProgress`
|
||||
has already been committed, or converted into a Builder.
|
||||
|
||||
- Returns: an `EntityBuilder` for this `InProgress`
|
||||
*/
|
||||
func builder(forTempId tempId: String) throws -> EntityBuilder {
|
||||
defer {
|
||||
self.raw = nil
|
||||
}
|
||||
return EntityBuilder(raw: in_progress_entity_builder_from_temp_id(try self.validPointer(), tempId))
|
||||
}
|
||||
|
||||
/**
|
||||
Transacts the `transaction`
|
||||
|
||||
This does not commit the transaction. In order to do so, `commit` can be called.
|
||||
|
||||
- Parameter transaction: The EDN string to be transacted.
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the transaction failed.
|
||||
- Throws: `ResultError.empty` if no `TxReport` is returned from the transact.
|
||||
|
||||
- Returns: The `TxReport` generated by the transact.
|
||||
*/
|
||||
func transact(transaction: String) throws -> TxReport {
|
||||
let result = in_progress_transact(try self.validPointer(), transaction).pointee
|
||||
return TxReport(raw: try result.unwrap())
|
||||
}
|
||||
|
||||
/**
|
||||
Commits all the transacts that have been performed on this `InProgress`, either directly
|
||||
or through a Builder.
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the commit failed.
|
||||
*/
|
||||
func commit() throws {
|
||||
defer {
|
||||
self.raw = nil
|
||||
}
|
||||
try in_progress_commit(try self.validPointer()).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Rolls back all the transacts that have been performed on this `InProgress`, either directly
|
||||
or through a Builder.
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the rollback failed.
|
||||
*/
|
||||
func rollback() throws {
|
||||
defer {
|
||||
self.raw = nil
|
||||
}
|
||||
try in_progress_rollback(try self.validPointer()).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
override func cleanup(pointer: OpaquePointer) {
|
||||
in_progress_destroy(pointer)
|
||||
}
|
||||
}
|
372
sdks/swift/Mentat/Mentat/Transact/InProgressBuilder.swift
Normal file
372
sdks/swift/Mentat/Mentat/Transact/InProgressBuilder.swift
Normal file
|
@ -0,0 +1,372 @@
|
|||
/* Copyright 2018 Mozilla
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
* this file except in compliance with the License. You may obtain a copy of the
|
||||
* License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software distributed
|
||||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License. */
|
||||
|
||||
import Foundation
|
||||
import MentatStore
|
||||
|
||||
/**
|
||||
This class wraps a raw pointer that points to a Rust `InProgressBuilder` object.
|
||||
|
||||
`InProgressBuilder` provides a programmatic interface to performing assertions for entities.
|
||||
It provides functions for adding and retracting values for attributes for an entity within
|
||||
an in progress transaction.
|
||||
|
||||
The `transact` function will transact the assertions that have been added to the `InProgressBuilder`
|
||||
and pass back the `TxReport` that was generated by this transact and the `InProgress` that was
|
||||
used to perform the transact. This enables you to perform further transacts on the same `InProgress`
|
||||
before committing.
|
||||
|
||||
```
|
||||
let aEntid = txReport.entid(forTempId: "a")
|
||||
let bEntid = txReport.entid(forTempId: "b")
|
||||
do {
|
||||
let builder = try mentat.entityBuilder()
|
||||
try builder.add(entid: bEntid, keyword: ":foo/boolean", boolean: true)
|
||||
try builder.add(entid: aEntid, keyword: ":foo/instant", date: newDate)
|
||||
let (inProgress, report) = try builder.transact()
|
||||
try inProgress.transact(transaction: "[[:db/add \(aEntid) :foo/long 22]]")
|
||||
try inProgress.commit()
|
||||
...
|
||||
} catch {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The `commit` function will transact and commit the assertions that have been added to the `EntityBuilder`.
|
||||
It will consume the `InProgress` used to perform the transact. It returns the `TxReport` generated by
|
||||
the transact. After calling `commit`, a new transaction must be started by calling `Mentat.beginTransaction()`
|
||||
in order to perform further actions.
|
||||
|
||||
```
|
||||
let aEntid = txReport.entid(forTempId: "a")
|
||||
let bEntid = txReport.entid(forTempId: "b")
|
||||
do {
|
||||
let builder = try mentat.entityBuilder(forEntid: aEntid)
|
||||
try builder.add(entid: bEntid, keyword: ":foo/boolean", boolean: true)
|
||||
try builder.add(entid: aEntid, keyword: ":foo/instant", date: newDate)
|
||||
let report = try builder.commit()
|
||||
...
|
||||
} catch {
|
||||
...
|
||||
}
|
||||
```
|
||||
*/
|
||||
class InProgressBuilder: OptionalRustObject {
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/long`.
|
||||
*/
|
||||
func add(entid: Entid, keyword: String, long value: Int64) throws {
|
||||
try in_progress_builder_add_long(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/ref`.
|
||||
*/
|
||||
func add(entid: Entid, keyword: String, reference value: Entid) throws {
|
||||
try in_progress_builder_add_ref(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/keyword`.
|
||||
*/
|
||||
func add(entid: Entid, keyword: String, keyword value: String) throws {
|
||||
try in_progress_builder_add_keyword(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/boolean`.
|
||||
*/
|
||||
func add(entid: Entid, keyword: String, boolean value: Bool) throws {
|
||||
try in_progress_builder_add_boolean(try self.validPointer(), entid, keyword, value ? 1 : 0).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/double`.
|
||||
*/
|
||||
func add(entid: Entid, keyword: String, double value: Double) throws {
|
||||
try in_progress_builder_add_double(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/instant`.
|
||||
*/
|
||||
func add(entid: Entid, keyword: String, date value: Date) throws {
|
||||
try in_progress_builder_add_timestamp(try self.validPointer(), entid, keyword, value.toMicroseconds()).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/string`.
|
||||
*/
|
||||
func add(entid: Entid, keyword: String, string value: String) throws {
|
||||
try in_progress_builder_add_string(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts the value of attribute `keyword` to be the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be asserted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/uuid`.
|
||||
*/
|
||||
func add(entid: Entid, keyword: String, uuid value: UUID) throws {
|
||||
var rawUuid = value.uuid
|
||||
let _ = try withUnsafePointer(to: &rawUuid) { uuidPtr in
|
||||
try in_progress_builder_add_uuid(try self.validPointer(), entid, keyword, uuidPtr).pointee.tryUnwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/long`.
|
||||
*/
|
||||
func retract(entid: Entid, keyword: String, long value: Int64) throws {
|
||||
try in_progress_builder_retract_long(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/ref`.
|
||||
*/
|
||||
func retract(entid: Entid, keyword: String, reference value: Entid) throws {
|
||||
try in_progress_builder_retract_ref(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/keyword`.
|
||||
*/
|
||||
func retract(entid: Entid, keyword: String, keyword value: String) throws {
|
||||
try in_progress_builder_retract_keyword(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/boolean`.
|
||||
*/
|
||||
func retract(entid: Entid, keyword: String, boolean value: Bool) throws {
|
||||
try in_progress_builder_retract_boolean(try self.validPointer(), entid, keyword, value ? 1 : 0).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/double`.
|
||||
*/
|
||||
func retract(entid: Entid, keyword: String, double value: Double) throws {
|
||||
try in_progress_builder_retract_double(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/instant`.
|
||||
*/
|
||||
func retract(entid: Entid, keyword: String, date value: Date) throws {
|
||||
try in_progress_builder_retract_timestamp(try self.validPointer(), entid, keyword, value.toMicroseconds()).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/string`.
|
||||
*/
|
||||
func retract(entid: Entid, keyword: String, string value: String) throws {
|
||||
try in_progress_builder_retract_string(try self.validPointer(), entid, keyword, value).pointee.tryUnwrap()
|
||||
}
|
||||
|
||||
/**
|
||||
Retracts the value of attribute `keyword` from the provided `value` for entity `entid`.
|
||||
|
||||
- Parameter entid: The `Entid` of the entity to be touched.
|
||||
- Parameter keyword: The name of the attribute in the format `:namespace/name`.
|
||||
- Parameter value: The value to be retracted
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if the attribute is not present in the schema or the attribute value type
|
||||
is not `:db.type/uuid`.
|
||||
*/
|
||||
func retract(entid: Entid, keyword: String, uuid value: UUID) throws {
|
||||
var rawUuid = value.uuid
|
||||
let _ = try withUnsafePointer(to: &rawUuid) { uuidPtr in
|
||||
try in_progress_builder_retract_uuid(try self.validPointer(), entid, keyword, uuidPtr).pointee.tryUnwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Transacts the added assertions. This consumes the pointer associated with this `InProgressBuilder`
|
||||
such that no further assertions can be added after the `transact` has completed. To perform
|
||||
further assertions, use the `InProgress` returned from this function.
|
||||
|
||||
This does not commit the transaction. In order to do so, `commit` can be called on the `InProgress` returned
|
||||
from this function.
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if an error occured during the execution of the transact.
|
||||
|
||||
- Returns: The current `InProgress` and the `TxReport` generated by the transact.
|
||||
*/
|
||||
func transact() throws -> (InProgress, TxReport?) {
|
||||
defer {
|
||||
self.raw = nil
|
||||
}
|
||||
let result = in_progress_builder_transact(try self.validPointer()).pointee
|
||||
let inProgress = InProgress(raw: result.inProgress)
|
||||
guard let report = try result.result.pointee.tryUnwrap() else {
|
||||
return (inProgress, nil)
|
||||
}
|
||||
return (inProgress, TxReport(raw: report))
|
||||
}
|
||||
|
||||
/**
|
||||
Transacts the added assertions and commits. This consumes the pointer associated with this `InProgressBuilder`
|
||||
and the associated `InProgress` such that no further assertions can be added after the `commit` has completed.
|
||||
To perform further assertions, a new `InProgress` or `InProgressBuilder` should be created.
|
||||
|
||||
- Throws: `PointerError.pointerConsumed` if the underlying raw pointer has already consumed, which will occur if the builder
|
||||
has already been transacted or committed.
|
||||
- Throws: `ResultError.error` if an error occured during the execution of the transact.
|
||||
|
||||
- Returns: The `TxReport` generated by the transact.
|
||||
*/
|
||||
func commit() throws -> TxReport {
|
||||
defer {
|
||||
self.raw = nil
|
||||
}
|
||||
return TxReport(raw: try in_progress_builder_commit(try self.validPointer()).pointee.unwrap())
|
||||
}
|
||||
|
||||
override func cleanup(pointer: OpaquePointer) {
|
||||
in_progress_builder_destroy(pointer)
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ import Foundation
|
|||
import MentatStore
|
||||
|
||||
/**
|
||||
This class wraps a raw pointer than points to a Rust `TxReport` object.
|
||||
This class wraps a raw pointer that points to a Rust `TxReport` object.
|
||||
|
||||
The `TxReport` contains information about a successful Mentat transaction.
|
||||
|
||||
|
|
|
@ -60,6 +60,16 @@ struct Option {
|
|||
};
|
||||
typedef struct Option Option;
|
||||
|
||||
/*
|
||||
A mapping of the InProgressTransactResult repr(C) Rust object.
|
||||
The memory for this is managed by Swift.
|
||||
*/
|
||||
struct InProgressTransactResult {
|
||||
struct InProgress*_Nonnull inProgress;
|
||||
struct Result*_Nonnull result;
|
||||
};
|
||||
typedef struct InProgressTransactResult InProgressTransactResult;
|
||||
|
||||
/*
|
||||
A Mapping for the ValueType Rust object.
|
||||
*/
|
||||
|
@ -100,13 +110,67 @@ void typed_value_list_destroy(struct QueryResultRow* _Nullable obj);
|
|||
void typed_value_list_iter_destroy(struct QueryRowIterator* _Nullable obj);
|
||||
void typed_value_result_set_destroy(struct QueryResultRows* _Nullable obj);
|
||||
void typed_value_result_set_iter_destroy(struct QueryRowsIterator* _Nullable obj);
|
||||
void in_progress_destroy(struct InProgress* _Nullable obj);
|
||||
void in_progress_builder_destroy(struct InProgressBuilder* _Nullable obj);
|
||||
void entity_builder_destroy(struct EntityBuilder* _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);
|
||||
struct Result*_Nonnull store_begin_transaction(struct Store*_Nonnull store);
|
||||
|
||||
// in progress
|
||||
struct Result*_Nonnull in_progress_transact(struct InProgress*_Nonnull in_progress, const char* _Nonnull transaction);
|
||||
struct Result*_Nonnull in_progress_commit(struct InProgress*_Nonnull in_progress);
|
||||
struct Result*_Nonnull in_progress_rollback(struct InProgress*_Nonnull in_progress);
|
||||
|
||||
// in_progress entity building
|
||||
struct Result*_Nonnull store_in_progress_builder(struct Store*_Nonnull store);
|
||||
struct InProgressBuilder*_Nonnull in_progress_builder(struct InProgress*_Nonnull in_progress);
|
||||
struct EntityBuilder*_Nonnull in_progress_entity_builder_from_temp_id(struct InProgress*_Nonnull in_progress, const char*_Nonnull temp_id);
|
||||
struct EntityBuilder*_Nonnull in_progress_entity_builder_from_entid(struct InProgress*_Nonnull in_progress, const int64_t entid);
|
||||
struct Result*_Nonnull in_progress_builder_add_string(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value);
|
||||
struct Result*_Nonnull in_progress_builder_add_long(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull in_progress_builder_add_ref(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull in_progress_builder_add_keyword(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value);
|
||||
struct Result*_Nonnull in_progress_builder_add_timestamp(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull in_progress_builder_add_boolean(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int32_t value);
|
||||
struct Result*_Nonnull in_progress_builder_add_double(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const double value);
|
||||
struct Result*_Nonnull in_progress_builder_add_uuid(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const uuid_t* _Nonnull value);
|
||||
struct Result*_Nonnull in_progress_builder_retract_string(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value);
|
||||
struct Result*_Nonnull in_progress_builder_retract_long(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull in_progress_builder_retract_ref(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull in_progress_builder_retract_keyword(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const char*_Nonnull value);
|
||||
struct Result*_Nonnull in_progress_builder_retract_timestamp(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull in_progress_builder_retract_boolean(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const int32_t value);
|
||||
struct Result*_Nonnull in_progress_builder_retract_double(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const double value);
|
||||
struct Result*_Nonnull in_progress_builder_retract_uuid(struct InProgressBuilder*_Nonnull builder, const int64_t entid, const char*_Nonnull kw, const uuid_t* _Nonnull value);
|
||||
struct InProgressTransactResult*_Nonnull in_progress_builder_transact(struct InProgressBuilder*_Nonnull builder);
|
||||
struct Result*_Nonnull in_progress_builder_commit(struct InProgressBuilder*_Nonnull builder);
|
||||
|
||||
// entity building
|
||||
struct Result*_Nonnull store_entity_builder_from_temp_id(struct Store*_Nonnull store, const char*_Nonnull temp_id);
|
||||
struct Result*_Nonnull store_entity_builder_from_entid(struct Store*_Nonnull store, const int64_t entid);
|
||||
struct Result*_Nonnull entity_builder_add_string(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value);
|
||||
struct Result*_Nonnull entity_builder_add_long(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull entity_builder_add_ref(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull entity_builder_add_keyword(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value);
|
||||
struct Result*_Nonnull entity_builder_add_boolean(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int32_t value);
|
||||
struct Result*_Nonnull entity_builder_add_double(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const double value);
|
||||
struct Result*_Nonnull entity_builder_add_timestamp(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull entity_builder_add_uuid(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const uuid_t* _Nonnull value);
|
||||
struct Result*_Nonnull entity_builder_retract_string(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value);
|
||||
struct Result*_Nonnull entity_builder_retract_long(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull entity_builder_retract_ref(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull entity_builder_retract_keyword(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const char*_Nonnull value);
|
||||
struct Result*_Nonnull entity_builder_retract_boolean(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int32_t value);
|
||||
struct Result*_Nonnull entity_builder_retract_double(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const double value);
|
||||
struct Result*_Nonnull entity_builder_retract_timestamp(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const int64_t value);
|
||||
struct Result*_Nonnull entity_builder_retract_uuid(struct EntityBuilder*_Nonnull builder, const char*_Nonnull kw, const uuid_t* _Nonnull value);
|
||||
struct InProgressTransactResult*_Nonnull entity_builder_transact(struct InProgressBuilder*_Nonnull builder);
|
||||
struct Result*_Nonnull entity_builder_commit(struct EntityBuilder*_Nonnull builder);
|
||||
|
||||
// Sync
|
||||
struct Result*_Nonnull store_sync(struct Store*_Nonnull store, const char* _Nonnull user_uuid, const char* _Nonnull server_uri);
|
||||
|
|
|
@ -17,12 +17,12 @@ class MentatTests: XCTestCase {
|
|||
var citiesSchema: String?
|
||||
var seattleData: String?
|
||||
var store: Mentat?
|
||||
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
|
@ -120,7 +120,8 @@ class MentatTests: XCTestCase {
|
|||
[:db/add "u" :db/cardinality :db.cardinality/one]
|
||||
]
|
||||
"""
|
||||
let report = try mentat.transact(transaction: schema)
|
||||
let transaction = try mentat.beginTransaction();
|
||||
let report = try transaction.transact(transaction: schema)
|
||||
let stringEntid = report.entid(forTempId: "s")!
|
||||
|
||||
let data = """
|
||||
|
@ -142,7 +143,8 @@ class MentatTests: XCTestCase {
|
|||
[:db/add "b" :foo/uuid #uuid "4cb3f828-752d-497a-90c9-b1fd516d5644"]
|
||||
]
|
||||
"""
|
||||
let dataReport = try mentat.transact(transaction: data)
|
||||
let dataReport = try transaction.transact(transaction: data)
|
||||
try transaction.commit();
|
||||
return (report, dataReport)
|
||||
} catch {
|
||||
assertionFailure(error.localizedDescription)
|
||||
|
@ -317,7 +319,7 @@ class MentatTests: XCTestCase {
|
|||
guard let rows = relResult else {
|
||||
return assertionFailure("No results received")
|
||||
}
|
||||
|
||||
|
||||
var i = 0
|
||||
rows.forEach({ (row) in
|
||||
let (name, category) = expectedResults[i]
|
||||
|
@ -760,6 +762,418 @@ class MentatTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
func test3InProgressTransact() {
|
||||
let mentat = Mentat()
|
||||
let (_, report) = self.populateWithTypesSchema(mentat: mentat)
|
||||
XCTAssertNotNil(report)
|
||||
}
|
||||
|
||||
func testInProgressRollback() {
|
||||
let mentat = Mentat()
|
||||
let (_, report) = self.populateWithTypesSchema(mentat: mentat)
|
||||
XCTAssertNotNil(report)
|
||||
let aEntid = report!.entid(forTempId: "a")!
|
||||
|
||||
let preLongValue = try! mentat.value(forAttribute: ":foo/long", ofEntity: aEntid)
|
||||
XCTAssertEqual(25, preLongValue?.asLong())
|
||||
|
||||
let inProgress = try! mentat.beginTransaction()
|
||||
XCTAssertNoThrow(try inProgress.transact(transaction: "[[:db/add \(aEntid) :foo/long 22]]"))
|
||||
XCTAssertNoThrow(try inProgress.rollback())
|
||||
|
||||
let postLongValue = try! mentat.value(forAttribute: ":foo/long", ofEntity: aEntid)
|
||||
XCTAssertEqual(25, postLongValue?.asLong())
|
||||
|
||||
}
|
||||
|
||||
func testInProgressEntityBuilder() {
|
||||
let mentat = Mentat()
|
||||
let (schemaReport, dataReport) = self.populateWithTypesSchema(mentat: mentat)
|
||||
let bEntid = dataReport!.entid(forTempId: "b")!
|
||||
let longEntid = schemaReport!.entid(forTempId: "l")!
|
||||
let stringEntid = schemaReport!.entid(forTempId: "s")!
|
||||
// test that the values are as expected
|
||||
let query = """
|
||||
[:find [?b ?i ?u ?l ?d ?s ?k ?r]
|
||||
:in ?e
|
||||
:where [?e :foo/boolean ?b]
|
||||
[?e :foo/instant ?i]
|
||||
[?e :foo/uuid ?u]
|
||||
[?e :foo/long ?l]
|
||||
[?e :foo/double ?d]
|
||||
[?e :foo/string ?s]
|
||||
[?e :foo/keyword ?k]
|
||||
[?e :foo/ref ?r]]
|
||||
"""
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
|
||||
XCTAssertNoThrow(try mentat.query(query: query).bind(varName: "?e", toReference: bEntid).runTuple { (result) in
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertEqual(false, result?.asBool(index: 0))
|
||||
|
||||
let previousDate = formatter.date(from: "2018-01-01T11:00:00+00:00")
|
||||
XCTAssertEqual(previousDate, result?.asDate(index: 1))
|
||||
|
||||
let previousUuid = UUID(uuidString: "4cb3f828-752d-497a-90c9-b1fd516d5644")!
|
||||
XCTAssertEqual(previousUuid, result?.asUUID(index: 2))
|
||||
|
||||
XCTAssertEqual(50, result?.asLong(index: 3))
|
||||
XCTAssertEqual(22.46, result?.asDouble(index: 4))
|
||||
XCTAssertEqual("Silence is worse; all truths that are kept silent become poisonous.", result?.asString(index: 5))
|
||||
XCTAssertEqual(":foo/string", result?.asKeyword(index: 6))
|
||||
XCTAssertEqual(stringEntid, result?.asEntid(index: 7))
|
||||
})
|
||||
|
||||
let builder = try! mentat.entityBuilder()
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/boolean", boolean: true))
|
||||
let newDate = Date()
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/instant", date: newDate))
|
||||
let newUUID = UUID()
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/uuid", uuid: newUUID))
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/long", long: 75))
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/double", double: 81.3))
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/string", string: "Become who you are!"))
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/keyword", keyword: ":foo/long"))
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/ref", reference: longEntid))
|
||||
XCTAssertNoThrow(try builder.commit())
|
||||
|
||||
// test that the values have changed
|
||||
XCTAssertNoThrow(try mentat.query(query: query).bind(varName: "?e", toReference: bEntid).runTuple { (result) in
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertEqual(true, result?.asBool(index: 0))
|
||||
XCTAssertEqual(formatter.string(from: newDate), formatter.string(from: result!.asDate(index: 1)))
|
||||
XCTAssertEqual(newUUID, result?.asUUID(index: 2))
|
||||
XCTAssertEqual(75, result?.asLong(index: 3))
|
||||
XCTAssertEqual(81.3, result?.asDouble(index: 4))
|
||||
XCTAssertEqual("Become who you are!", result?.asString(index: 5))
|
||||
XCTAssertEqual(":foo/long", result?.asKeyword(index: 6))
|
||||
XCTAssertEqual(longEntid, result?.asEntid(index: 7))
|
||||
})
|
||||
}
|
||||
|
||||
func testEntityBuilderForEntid() {
|
||||
let mentat = Mentat()
|
||||
let (schemaReport, dataReport) = self.populateWithTypesSchema(mentat: mentat)
|
||||
let bEntid = dataReport!.entid(forTempId: "b")!
|
||||
let longEntid = schemaReport!.entid(forTempId: "l")!
|
||||
let stringEntid = schemaReport!.entid(forTempId: "s")!
|
||||
// test that the values are as expected
|
||||
let query = """
|
||||
[:find [?b ?i ?u ?l ?d ?s ?k ?r]
|
||||
:in ?e
|
||||
:where [?e :foo/boolean ?b]
|
||||
[?e :foo/instant ?i]
|
||||
[?e :foo/uuid ?u]
|
||||
[?e :foo/long ?l]
|
||||
[?e :foo/double ?d]
|
||||
[?e :foo/string ?s]
|
||||
[?e :foo/keyword ?k]
|
||||
[?e :foo/ref ?r]]
|
||||
"""
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
|
||||
XCTAssertNoThrow(try mentat.query(query: query).bind(varName: "?e", toReference: bEntid).runTuple { (result) in
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertEqual(false, result?.asBool(index: 0))
|
||||
|
||||
let previousDate = formatter.date(from: "2018-01-01T11:00:00+00:00")
|
||||
XCTAssertEqual(previousDate, result?.asDate(index: 1))
|
||||
|
||||
let previousUuid = UUID(uuidString: "4cb3f828-752d-497a-90c9-b1fd516d5644")!
|
||||
XCTAssertEqual(previousUuid, result?.asUUID(index: 2))
|
||||
|
||||
XCTAssertEqual(50, result?.asLong(index: 3))
|
||||
XCTAssertEqual(22.46, result?.asDouble(index: 4))
|
||||
XCTAssertEqual("Silence is worse; all truths that are kept silent become poisonous.", result?.asString(index: 5))
|
||||
XCTAssertEqual(":foo/string", result?.asKeyword(index: 6))
|
||||
XCTAssertEqual(stringEntid, result?.asEntid(index: 7))
|
||||
})
|
||||
|
||||
let builder = try! mentat.entityBuilder(forEntid: bEntid)
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/boolean", boolean: true))
|
||||
let newDate = Date()
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/instant", date: newDate))
|
||||
let newUUID = UUID()
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/uuid", uuid: newUUID))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/long", long: 75))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/double", double: 81.3))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/string", string: "Become who you are!"))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/keyword", keyword: ":foo/long"))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/ref", reference: longEntid))
|
||||
XCTAssertNoThrow(try builder.commit())
|
||||
|
||||
// test that the values have changed
|
||||
XCTAssertNoThrow(try mentat.query(query: query).bind(varName: "?e", toReference: bEntid).runTuple { (result) in
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertEqual(true, result?.asBool(index: 0))
|
||||
XCTAssertEqual(formatter.string(from: newDate), formatter.string(from: result!.asDate(index: 1)))
|
||||
XCTAssertEqual(newUUID, result?.asUUID(index: 2))
|
||||
XCTAssertEqual(75, result?.asLong(index: 3))
|
||||
XCTAssertEqual(81.3, result?.asDouble(index: 4))
|
||||
XCTAssertEqual("Become who you are!", result?.asString(index: 5))
|
||||
XCTAssertEqual(":foo/long", result?.asKeyword(index: 6))
|
||||
XCTAssertEqual(longEntid, result?.asEntid(index: 7))
|
||||
})
|
||||
}
|
||||
|
||||
func testEntityBuilderForTempid() {
|
||||
let mentat = Mentat()
|
||||
let (schemaReport, _) = self.populateWithTypesSchema(mentat: mentat)
|
||||
let longEntid = schemaReport!.entid(forTempId: "l")!
|
||||
// test that the values are as expected
|
||||
let query = """
|
||||
[:find [?b ?i ?u ?l ?d ?s ?k ?r]
|
||||
:in ?e
|
||||
:where [?e :foo/boolean ?b]
|
||||
[?e :foo/instant ?i]
|
||||
[?e :foo/uuid ?u]
|
||||
[?e :foo/long ?l]
|
||||
[?e :foo/double ?d]
|
||||
[?e :foo/string ?s]
|
||||
[?e :foo/keyword ?k]
|
||||
[?e :foo/ref ?r]]
|
||||
"""
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
|
||||
|
||||
let builder = try! mentat.entityBuilder(forTempId: "c")
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/boolean", boolean: true))
|
||||
let newDate = Date()
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/instant", date: newDate))
|
||||
let newUUID = UUID()
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/uuid", uuid: newUUID))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/long", long: 75))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/double", double: 81.3))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/string", string: "Become who you are!"))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/keyword", keyword: ":foo/long"))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/ref", reference: longEntid))
|
||||
let report = try! builder.commit()
|
||||
let cEntid = report.entid(forTempId: "c")!
|
||||
// test that the values have changed
|
||||
XCTAssertNoThrow(try mentat.query(query: query).bind(varName: "?e", toReference: cEntid).runTuple { (result) in
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertEqual(true, result?.asBool(index: 0))
|
||||
XCTAssertEqual(formatter.string(from: newDate), formatter.string(from: result!.asDate(index: 1)))
|
||||
XCTAssertEqual(newUUID, result?.asUUID(index: 2))
|
||||
XCTAssertEqual(75, result?.asLong(index: 3))
|
||||
XCTAssertEqual(81.3, result?.asDouble(index: 4))
|
||||
XCTAssertEqual("Become who you are!", result?.asString(index: 5))
|
||||
XCTAssertEqual(":foo/long", result?.asKeyword(index: 6))
|
||||
XCTAssertEqual(longEntid, result?.asEntid(index: 7))
|
||||
})
|
||||
}
|
||||
|
||||
func testInProgressBuilderTransact() {
|
||||
let mentat = Mentat()
|
||||
let (schemaReport, dataReport) = self.populateWithTypesSchema(mentat: mentat)
|
||||
let aEntid = dataReport!.entid(forTempId: "a")!
|
||||
let bEntid = dataReport!.entid(forTempId: "b")!
|
||||
let longEntid = schemaReport!.entid(forTempId: "l")!
|
||||
// test that the values are as expected
|
||||
let query = """
|
||||
[:find [?b ?i ?u ?l ?d ?s ?k ?r]
|
||||
:in ?e
|
||||
:where [?e :foo/boolean ?b]
|
||||
[?e :foo/instant ?i]
|
||||
[?e :foo/uuid ?u]
|
||||
[?e :foo/long ?l]
|
||||
[?e :foo/double ?d]
|
||||
[?e :foo/string ?s]
|
||||
[?e :foo/keyword ?k]
|
||||
[?e :foo/ref ?r]]
|
||||
"""
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
|
||||
|
||||
let builder = try! mentat.entityBuilder()
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/boolean", boolean: true))
|
||||
let newDate = Date()
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/instant", date: newDate))
|
||||
let newUUID = UUID()
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/uuid", uuid: newUUID))
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/long", long: 75))
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/double", double: 81.3))
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/string", string: "Become who you are!"))
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/keyword", keyword: ":foo/long"))
|
||||
XCTAssertNoThrow(try builder.add(entid: bEntid, keyword: ":foo/ref", reference: longEntid))
|
||||
let (inProgress, report) = try! builder.transact()
|
||||
XCTAssertNotNil(inProgress)
|
||||
XCTAssertNotNil(report)
|
||||
XCTAssertNoThrow(try inProgress.transact(transaction: "[[:db/add \(aEntid) :foo/long 22]]"))
|
||||
XCTAssertNoThrow(try inProgress.commit())
|
||||
|
||||
// test that the values have changed
|
||||
XCTAssertNoThrow(try mentat.query(query: query).bind(varName: "?e", toReference: bEntid).runTuple { (result) in
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertEqual(true, result?.asBool(index: 0))
|
||||
XCTAssertEqual(formatter.string(from: newDate), formatter.string(from: result!.asDate(index: 1)))
|
||||
XCTAssertEqual(newUUID, result?.asUUID(index: 2))
|
||||
XCTAssertEqual(75, result?.asLong(index: 3))
|
||||
XCTAssertEqual(81.3, result?.asDouble(index: 4))
|
||||
XCTAssertEqual("Become who you are!", result?.asString(index: 5))
|
||||
XCTAssertEqual(":foo/long", result?.asKeyword(index: 6))
|
||||
XCTAssertEqual(longEntid, result?.asEntid(index: 7))
|
||||
})
|
||||
|
||||
let longValue = try! mentat.value(forAttribute: ":foo/long", ofEntity: aEntid)
|
||||
XCTAssertEqual(22, longValue?.asLong())
|
||||
}
|
||||
|
||||
func testEntityBuilderTransact() {
|
||||
let mentat = Mentat()
|
||||
let (schemaReport, dataReport) = self.populateWithTypesSchema(mentat: mentat)
|
||||
let aEntid = dataReport!.entid(forTempId: "a")!
|
||||
let bEntid = dataReport!.entid(forTempId: "b")!
|
||||
let longEntid = schemaReport!.entid(forTempId: "l")!
|
||||
// test that the values are as expected
|
||||
let query = """
|
||||
[:find [?b ?i ?u ?l ?d ?s ?k ?r]
|
||||
:in ?e
|
||||
:where [?e :foo/boolean ?b]
|
||||
[?e :foo/instant ?i]
|
||||
[?e :foo/uuid ?u]
|
||||
[?e :foo/long ?l]
|
||||
[?e :foo/double ?d]
|
||||
[?e :foo/string ?s]
|
||||
[?e :foo/keyword ?k]
|
||||
[?e :foo/ref ?r]]
|
||||
"""
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
|
||||
|
||||
let builder = try! mentat.entityBuilder(forEntid: bEntid)
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/boolean", boolean: true))
|
||||
let newDate = Date()
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/instant", date: newDate))
|
||||
let newUUID = UUID()
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/uuid", uuid: newUUID))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/long", long: 75))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/double", double: 81.3))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/string", string: "Become who you are!"))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/keyword", keyword: ":foo/long"))
|
||||
XCTAssertNoThrow(try builder.add(keyword: ":foo/ref", reference: longEntid))
|
||||
let (inProgress, report) = try! builder.transact()
|
||||
XCTAssertNotNil(inProgress)
|
||||
XCTAssertNotNil(report)
|
||||
XCTAssertNoThrow(try inProgress.transact(transaction: "[[:db/add \(aEntid) :foo/long 22]]"))
|
||||
XCTAssertNoThrow(try inProgress.commit())
|
||||
|
||||
// test that the values have changed
|
||||
XCTAssertNoThrow(try mentat.query(query: query).bind(varName: "?e", toReference: bEntid).runTuple { (result) in
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertEqual(true, result?.asBool(index: 0))
|
||||
XCTAssertEqual(formatter.string(from: newDate), formatter.string(from: result!.asDate(index: 1)))
|
||||
XCTAssertEqual(newUUID, result?.asUUID(index: 2))
|
||||
XCTAssertEqual(75, result?.asLong(index: 3))
|
||||
XCTAssertEqual(81.3, result?.asDouble(index: 4))
|
||||
XCTAssertEqual("Become who you are!", result?.asString(index: 5))
|
||||
XCTAssertEqual(":foo/long", result?.asKeyword(index: 6))
|
||||
XCTAssertEqual(longEntid, result?.asEntid(index: 7))
|
||||
})
|
||||
|
||||
let longValue = try! mentat.value(forAttribute: ":foo/long", ofEntity: aEntid)
|
||||
XCTAssertEqual(22, longValue?.asLong())
|
||||
}
|
||||
|
||||
func testEntityBuilderRetract() {
|
||||
let mentat = Mentat()
|
||||
let (schemaReport, dataReport) = self.populateWithTypesSchema(mentat: mentat)
|
||||
let bEntid = dataReport!.entid(forTempId: "b")!
|
||||
let stringEntid = schemaReport!.entid(forTempId: "s")!
|
||||
// test that the values are as expected
|
||||
let query = """
|
||||
[:find [?b ?i ?u ?l ?d ?s ?k ?r]
|
||||
:in ?e
|
||||
:where [?e :foo/boolean ?b]
|
||||
[?e :foo/instant ?i]
|
||||
[?e :foo/uuid ?u]
|
||||
[?e :foo/long ?l]
|
||||
[?e :foo/double ?d]
|
||||
[?e :foo/string ?s]
|
||||
[?e :foo/keyword ?k]
|
||||
[?e :foo/ref ?r]]
|
||||
"""
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
|
||||
let previousDate = formatter.date(from: "2018-01-01T11:00:00+00:00")!
|
||||
let previousUuid = UUID(uuidString: "4cb3f828-752d-497a-90c9-b1fd516d5644")!
|
||||
XCTAssertNoThrow(try mentat.query(query: query).bind(varName: "?e", toReference: bEntid).runTuple { (result) in
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertEqual(false, result?.asBool(index: 0))
|
||||
XCTAssertEqual(previousDate, result?.asDate(index: 1))
|
||||
XCTAssertEqual(previousUuid, result?.asUUID(index: 2))
|
||||
XCTAssertEqual(50, result?.asLong(index: 3))
|
||||
XCTAssertEqual(22.46, result?.asDouble(index: 4))
|
||||
XCTAssertEqual("Silence is worse; all truths that are kept silent become poisonous.", result?.asString(index: 5))
|
||||
XCTAssertEqual(":foo/string", result?.asKeyword(index: 6))
|
||||
XCTAssertEqual(stringEntid, result?.asEntid(index: 7))
|
||||
})
|
||||
|
||||
let builder = try! mentat.entityBuilder(forEntid: bEntid)
|
||||
XCTAssertNoThrow(try builder.retract(keyword: ":foo/boolean", boolean: false))
|
||||
XCTAssertNoThrow(try builder.retract(keyword: ":foo/instant", date: previousDate))
|
||||
XCTAssertNoThrow(try builder.retract(keyword: ":foo/uuid", uuid: previousUuid))
|
||||
XCTAssertNoThrow(try builder.retract(keyword: ":foo/long", long: 50))
|
||||
XCTAssertNoThrow(try builder.retract(keyword: ":foo/double", double: 22.46))
|
||||
XCTAssertNoThrow(try builder.retract(keyword: ":foo/string", string: "Silence is worse; all truths that are kept silent become poisonous."))
|
||||
XCTAssertNoThrow(try builder.retract(keyword: ":foo/keyword", keyword: ":foo/string"))
|
||||
XCTAssertNoThrow(try builder.retract(keyword: ":foo/ref", reference: stringEntid))
|
||||
XCTAssertNoThrow(try builder.commit())
|
||||
|
||||
XCTAssertNoThrow(try mentat.query(query: query).bind(varName: "?e", toReference: bEntid).runTuple { (result) in
|
||||
XCTAssertNil(result)
|
||||
})
|
||||
}
|
||||
|
||||
func testInProgressEntityBuilderRetract() {
|
||||
let mentat = Mentat()
|
||||
let (schemaReport, dataReport) = self.populateWithTypesSchema(mentat: mentat)
|
||||
let bEntid = dataReport!.entid(forTempId: "b")!
|
||||
let stringEntid = schemaReport!.entid(forTempId: "s")!
|
||||
// test that the values are as expected
|
||||
let query = """
|
||||
[:find [?b ?i ?u ?l ?d ?s ?k ?r]
|
||||
:in ?e
|
||||
:where [?e :foo/boolean ?b]
|
||||
[?e :foo/instant ?i]
|
||||
[?e :foo/uuid ?u]
|
||||
[?e :foo/long ?l]
|
||||
[?e :foo/double ?d]
|
||||
[?e :foo/string ?s]
|
||||
[?e :foo/keyword ?k]
|
||||
[?e :foo/ref ?r]]
|
||||
"""
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
|
||||
let previousDate = formatter.date(from: "2018-01-01T11:00:00+00:00")!
|
||||
let previousUuid = UUID(uuidString: "4cb3f828-752d-497a-90c9-b1fd516d5644")!
|
||||
XCTAssertNoThrow(try mentat.query(query: query).bind(varName: "?e", toReference: bEntid).runTuple { (result) in
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertEqual(false, result?.asBool(index: 0))
|
||||
XCTAssertEqual(previousDate, result?.asDate(index: 1))
|
||||
XCTAssertEqual(previousUuid, result?.asUUID(index: 2))
|
||||
XCTAssertEqual(50, result?.asLong(index: 3))
|
||||
XCTAssertEqual(22.46, result?.asDouble(index: 4))
|
||||
XCTAssertEqual("Silence is worse; all truths that are kept silent become poisonous.", result?.asString(index: 5))
|
||||
XCTAssertEqual(":foo/string", result?.asKeyword(index: 6))
|
||||
XCTAssertEqual(stringEntid, result?.asEntid(index: 7))
|
||||
})
|
||||
|
||||
let builder = try! mentat.entityBuilder()
|
||||
XCTAssertNoThrow(try builder.retract(entid: bEntid, keyword: ":foo/boolean", boolean: false))
|
||||
XCTAssertNoThrow(try builder.retract(entid: bEntid, keyword: ":foo/instant", date: previousDate))
|
||||
XCTAssertNoThrow(try builder.retract(entid: bEntid, keyword: ":foo/uuid", uuid: previousUuid))
|
||||
XCTAssertNoThrow(try builder.retract(entid: bEntid, keyword: ":foo/long", long: 50))
|
||||
XCTAssertNoThrow(try builder.retract(entid: bEntid, keyword: ":foo/double", double: 22.46))
|
||||
XCTAssertNoThrow(try builder.retract(entid: bEntid, keyword: ":foo/string", string: "Silence is worse; all truths that are kept silent become poisonous."))
|
||||
XCTAssertNoThrow(try builder.retract(entid: bEntid, keyword: ":foo/keyword", keyword: ":foo/string"))
|
||||
XCTAssertNoThrow(try builder.retract(entid: bEntid, keyword: ":foo/ref", reference: stringEntid))
|
||||
XCTAssertNoThrow(try builder.commit())
|
||||
|
||||
XCTAssertNoThrow(try mentat.query(query: query).bind(varName: "?e", toReference: bEntid).runTuple { (result) in
|
||||
XCTAssertNil(result)
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: Add tests for transaction observation
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue