diff --git a/src/CaosDB.jl b/src/CaosDB.jl index 9d4d4abc4d0e6166c8c93741cac505dd30c5ee90..fb7a3d8b6eefc304af8c7ecbc76150f81c71d137 100644 --- a/src/CaosDB.jl +++ b/src/CaosDB.jl @@ -78,7 +78,16 @@ export append_parent, set_importance # Exports from module Transaction -export create_transaction, add_retrieve_by_id, add_query +export create_transaction, + add_retrieve_by_id, + add_query, + execute, + get_result_set, + get_count_result, + get_result_at, + get_results, + execute_query, + retrieve using Libdl diff --git a/src/Transaction.jl b/src/Transaction.jl index 990b9f0a59bc5d41a5ee5c06b74037d8475a6d0c..4f273b3e531692000297891f33b7c1344771cad5 100644 --- a/src/Transaction.jl +++ b/src/Transaction.jl @@ -23,7 +23,16 @@ module Transaction -export create_transaction, add_retrieve_by_id, add_query +export create_transaction, + add_retrieve_by_id, + add_query, + execute, + get_result_set, + get_count_result, + get_result_at, + get_results, + execute_query, + retrieve using CaosDB @@ -54,6 +63,23 @@ mutable struct _Transaction end end +""" +Struct containing a pointer to the wrapped cpp result set of a +transaction. The struct is meant for internal use only and shouldn't +be created directly by the user but is returned by, e.g., +`get_result_set`. +""" +mutable struct _ResultSet + wrapped_result_set::Ptr{Cvoid} + _deletable::Bool + + function _ResultSet() + rs = new() + rs._deletable = false + return rs + end +end + """ create_transaction(name::AbstractString = "default") @@ -170,4 +196,291 @@ function add_query(transaction::Ref{_Transaction}, query::AbstractString) CaosDB.Exceptions.evaluate_return_code(err_code) end +""" + function execute(transaction::Ref{_Transaction}) + +Send the given `transaction` to the CaosDB server for excecution and +wait for it to finish. +""" +function execute(transaction::Ref{_Transaction}) + + err_code = ccall( + (:caosdb_transaction_transaction_execute, CaosDB.library_name), + Cint, + (Ref{_Transaction},), + transaction, + ) + + CaosDB.Exceptions.evaluate_return_code(err_code) +end + +""" + function get_result_set(transaction::Ref{_Transaction}) + +Return the result set of the given `transaction`. +""" +function get_result_set(transaction::Ref{_Transaction}) + + results = Ref{_ResultSet}(_ResultSet()) + + err_code = ccall( + (:caosdb_transaction_transaction_get_result_set, CaosDB.library_name), + Cint, + (Ref{_Transaction}, Ref{_ResultSet}), + transaction, + results, + ) + + CaosDB.Exceptions.evaluate_return_code(err_code) + + return results +end + +""" + function get_count_result(transaction::Ref{_Transaction}) + +Return the number of results of the COUNT query in the given `transaction`. + +!!! info + + This is only a meaningful quantity if there actually was a COUNT + query in the `transaction`, and it already has been executed. In + all other cases the return value will be -1. +""" +function get_count_result(transaction::Ref{_Transaction}) + + out = Ref{Clong}(0) + + err_code = ccall( + (:caosdb_transaction_transaction_get_count_result, CaosDB.library_name), + Cint, + (Ref{_Transaction}, Ref{Clong}), + transaction, + out, + ) + + CaosDB.Exceptions.evaluate_return_code(err_code) + + return out[] +end + +""" + function get_result_size(results::Ref{_ResultSet}) + +Return the size of the given `results`, i.e., the number of entities +or other responses returned in this result set. +""" +function get_result_size(results::Ref{_ResultSet}) + + size = Ref{Cint}(0) + + err_code = ccall( + (:caosdb_transaction_result_set_size, CaosDB.library_name), + Cint, + (Ref{_ResultSet}, Ref{Cint}), + results, + size, + ) + + CaosDB.Exceptions.evaluate_return_code(err_code) + + return size[] +end + +""" + function get_result_at(results::Ref{_ResultSet}, index::Cint) + +Return the entity at position `index` of the given `results`. +""" +function get_result_at(results::Ref{_ResultSet}, index::Cint) + + size = get_result_size(results) + + if index > size + throw( + DomainError( + index, + "You tried to access the result at position $index but the result set only has $size results.", + ), + ) + end + + entity = Ref{CaosDB.Entity._Entity}(CaosDB.Entity._Entity()) + + err_code = ccall( + (:caosdb_transaction_result_set_at, CaosDB.library_name), + Cint, + (Ref{_ResultSet}, Ref{CaosDB.Entity._Entity}, Cint), + results, + entity, + index - Cint(1), + ) + + CaosDB.Exceptions.evaluate_return_code(err_code) + + return entity +end + +""" + function get_result_at(results::Ref{_ResultSet}, index::Integer) + +Convenience wrapper for `get_result_at(::Ref{_ResultSet}, +::Cint)`. Convert the given `index` to Int32 and return the result at +position `index` of `results`. +""" +function get_result_at(results::Ref{_ResultSet}, index::Integer) + + return get_result_at(results, Cint(index)) +end + +""" + function get_results(result_set::Ref{_ResultSet}) + +Return al results of the given `result_set`. +""" +function get_results(result_set::Ref{_ResultSet}) + + size = get_result_size(result_set) + + return [get_result_at(result_set, Cint(ii)) for ii = 1:size] +end + +""" + function get_results(transaction::Ref{_Transaction}) + +Return all results of the given `transaction`. +""" +function get_results(transaction::Ref{_Transaction}) + + result_set = get_result_set(transaction) + + return get_results(result_set) +end + +""" + function execute_query( + query::AbstractString, + name::AbstractString = "default" + ) + +Execute the given `query` and return its results. Use the connection +with the given `name`. If none is given, the default connection is +used. +""" +function execute_query(query::AbstractString, name::AbstractString = "default") + + transaction = create_transaction(name) + + add_query(transaction, query) + + execute(transaction) + + return get_results(transaction) +end + +""" + function execute_query( + query::AbstractString, + connection::Ref{CaosDB.Connection._Connection} + ) + +Execute the given `query` and return its results. Use the given +`connection`. +""" +function execute_query( + query::AbstractString, + connection::Ref{CaosDB.Connection._Connection}, +) + + transaction = create_transaction(connection) + + add_query(transaction, query) + + execute(transaction) + + return get_results(transaction) +end + +""" + function retrieve(id::AbstractString, name::AbstractString = "default") + +Retrieve and return the entity with the given `id`. Use the connection +with the given `name`. If none is provided, the default connection is +used. +""" +function retrieve(id::AbstractString, name::AbstractString = "default") + + transaction = create_transaction(name) + + add_retrieve_by_id(transaction, id) + + execute(transaction) + + return get_results(transaction)[0] +end + +""" + function retrieve(id::AbstractString, connection::Ref{CaosDB.Connection._Connection}) + +Retrieve and return the entity with the given `id`. Use the given +`connection`. +""" +function retrieve(id::AbstractString, connection::Ref{CaosDB.Connection._Connection}) + + transaction = create_transaction(connection) + + add_retrieve_by_id(transaction, id) + + execute(transaction) + + return get_results(transaction)[0] +end + +""" + function retrieve( + ids::Vector{T}, + name::AbstractString = "default", + ) where {T<:AbstractString} + +Retrieve and return the entities with the given `ids`. Use the +connection of the given `name`. If none is provided, the default +connection is used. +""" +function retrieve( + ids::Vector{T}, + name::AbstractString = "default", +) where {T<:AbstractString} + + transaction = create_transaction(name) + + add_retrieve_by_id(transaction, ids) + + execute(transaction) + + return get_results(transaction) +end + +""" + function retrieve( + ids::Vector{T}, + connection::Ref{CaosDB.Connection._Connection}, + ) where {T<:AbstractString} + +Retrieve and return the entities with the given `ids`. Use the given +`connection`. +""" +function retrieve( + ids::Vector{T}, + connection::Ref{CaosDB.Connection._Connection}, +) where {T<:AbstractString} + + transaction = create_transaction(connection) + + add_retrieve_by_id(transaction, ids) + + execute(transaction) + + return get_results(transaction) +end + end # Transaction