From 5b7d8cf4e97be4caebc5ffc77aa5b6ff0b2320e6 Mon Sep 17 00:00:00 2001 From: Frank Urbach <33724682+FrankUrbach@users.noreply.github.com> Date: Wed, 20 Oct 2021 20:30:07 +0200 Subject: [PATCH] Merge the speed improvements to the main branch (#122) * more documentation * changed lock usage and yield behavior * Sligth changes to get more speed * more functions documented * try to remove the conflict closing the input channel during transaction single request * removed a typo * more changes * Simplified getting and processing data from channels. * speedup completed * investigation of some fault using in multi processing * changed some minor issues * Added more documentation and changed some minor glitches. * enhanced the change log * small layout tweak in change log * up * Some changes to fullfill all BDD test * changed the close method when a query fails * Corrected the Version of the Documenter * Problems solved in BDD tests * little changes * Changed type declaration ::String to ::AbstractString Divided working through the BDD tests in smaller parts * added the relation_type test in runner.jl deleted some unnessecary code inside preparing the environment. * thing_type as test added * added tests for database, session and transaction * next attempt to go green * Normal runner trial * Next attempt to go green * minor change in steps.jl definition * minor change in close of Bidirectional Stream * Merge branch 'main' of https://github.com/Humans-of-Julia/TypeDBClient.jl * worked trough the review of Tom * changed the date in documentation to iso format. * debug the only failing function so far * First part of changes from comments * changed documentation and some functions * little Change to trigger the documentation * Next round of improvements suggested by Scott * remove a little typo and changed some forgotten places regarding RemoteConcept * Next Changes according Scott advices. Co-authored-by: = <=> Co-authored-by: Scott P. Jones --- .gitignore | 1 + docs/Project.toml | 3 + docs/src/changelog.md | 8 +- docs/src/contributing.md | 6 +- docs/src/examples.md | 2 +- docs/src/guide.md | 123 +++++++------ src/common/exception/TypeDBClientException.jl | 2 +- src/common/rpc/RequestBuilder.jl | 74 ++++---- src/concept/Concept.jl | 10 +- src/concept/ConceptManager.jl | 20 +-- src/concept/answer/ConceptMap.jl | 2 +- src/concept/thing/Attribute.jl | 7 + src/concept/thing/Thing.jl | 21 +++ src/concept/type/AttributeType.jl | 53 ++++-- src/concept/type/RelationType.jl | 6 +- src/concept/type/ThingType.jl | 169 +++++++++++++----- src/contribution/contribution.jl | 10 +- src/core/CoreClient.jl | 4 +- src/core/CoreDatabaseManager.jl | 15 +- src/core/CoreSession.jl | 115 +++++++----- src/core/CoreTransaction.jl | 35 ++-- src/logic/LogicManager.jl | 19 +- src/logic/Rule.jl | 2 +- src/query/QueryManager.jl | 4 +- src/standard/frontend.jl | 1 - src/standard/utils.jl | 19 +- src/stream/BidirectionalStream.jl | 44 +++-- src/stream/RequestTransmitter.jl | 36 ++-- src/stream/ResponseCollector.jl | 35 ++-- .../type/attributetype/AttributeTypeSteps.jl | 13 +- .../type/entitytype/EntityTypeSteps.jl | 2 +- .../concept/type/thingtype/ThingTypeSteps.jl | 29 ++- .../connection/database/DatabaseSteps.jl | 12 +- .../connection/session/SessionSteps.jl | 6 +- .../transaction/TransactionSteps.jl | 41 +++-- .../features/concept/thing/attribute.feature | 2 +- .../features/concept/thing/entity.feature | 1 + .../features/concept/thing/relation.feature | 1 + .../concept/type/attributetype.feature | 1 + .../features/concept/type/entitytype.feature | 1 + .../concept/type/relationtype.feature | 9 +- .../features/concept/type/thingtype.feature | 1 + .../features/connection/database.feature | 1 + .../features/connection/session.feature | 1 + .../features/connection/transaction.feature | 1 + test/behaviour/features/steps/steps.jl | 30 ++-- test/notes.jl | 3 +- test/runner.jl | 18 +- 48 files changed, 651 insertions(+), 368 deletions(-) diff --git a/.gitignore b/.gitignore index 8bb8cdf2..a966c23f 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,5 @@ docs/src/.DS_Store docs/src/assets/.DS_Store .DS_Store +map.mm.md diff --git a/docs/Project.toml b/docs/Project.toml index f9528499..3139d4bb 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,3 +1,6 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" TypeDBClient = "7ffdda62-db04-4838-9798-febd00f3125c" + +[compat] +Documenter = "0.27.0" diff --git a/docs/src/changelog.md b/docs/src/changelog.md index 9ce7e059..49fbe29c 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -6,25 +6,25 @@ CurrentModule = TypeDBClient ## lets list em here *** -03.10.2021 +2021-10-03 - more work on docs - release preparations *** -27.09.2021 +2021-09-27 - changed the client to use threading where it is suitable - extended the docs *** -25.06.2021 +2021-06-25 - updated docs - trigger CI *** -08.11.2020 +2020-11-08 - created project logo - set up initial docs and guidelines diff --git a/docs/src/contributing.md b/docs/src/contributing.md index f5ca8a79..27f69506 100644 --- a/docs/src/contributing.md +++ b/docs/src/contributing.md @@ -12,16 +12,16 @@ There is the [Workbase] (https://docs.vaticle.com/docs/workbase/overview) the [T There are clients for the following languages: Java, Node.js and Python. -This is the new community driven Julia client. +This is the community driven Julia client. ## Workflow guidance & roadmap Our reference client is the [Java version](https://docs.vaticle.com/docs/client-api/java). -The roadmap for TypeDBClient.jl (01.10.2021): +The roadmap for TypeDBClient.jl (2021-10-01): - completing the client with the cluster functionality (commercial product by Vaticle) -- improving speed +- improving speed - making multithreading possible and threadsafe The roadmap for TypeDBClient.jl (24.01.2021): diff --git a/docs/src/examples.md b/docs/src/examples.md index b58fd675..ba1109ca 100644 --- a/docs/src/examples.md +++ b/docs/src/examples.md @@ -2,7 +2,7 @@ For a quick example based introduction, you can refer to the folder examples and check out the files there. -However, if you like to watch a Video, showing how to work with the client in a Notebook, you can watch this recording: +However, if you would like to watch a video, showing how to work with the client in a Notebook, you can watch this recording: [A TypeDB Client Interface in Julia | TypeDBClient.jl](https://youtu.be/liNnm1nShCg?t=1262) diff --git a/docs/src/guide.md b/docs/src/guide.md index e437e7ed..a62e7f4f 100644 --- a/docs/src/guide.md +++ b/docs/src/guide.md @@ -20,31 +20,31 @@ Inside the Julia REPL, type ] to enter the Pkg REPL mode then run ## Quickstart -First make sure, the TypeDB server is running. +First make sure the TypeDB server is running. See [Start the TypeDB Server](https://docs.vaticle.com/docs/running-typedb/install-and-run#start-the-typedb-server) section. -In the Julia REPL or in your source code run: +In the Julia REPL or in your source code: `using TypeDBClient` You have two choices: -* If you are only interested in working interactivly, you can use the more simplified API. An example for this is: +* If you are only interested in working interactively, you can use the more simplified API. An example for this is: ```julia using TypeDBClient: dbconnect, open, read, write, match, insert, commit, create_database # Connecting the client to TypeDB dbconnect("127.0.0.1") do client - # Creation of a database + # Create a database create_database(client, "my-typedb") - # Opening the session + # Opening a session open(client, "my-typedb") do session # Open a write transaction write(session) do transaction - # Make a insert with a TypeQL string + # Insert a record using TypeQL insert(transaction, raw"insert $_ isa person;") - # Committing the transaction. + # Commit the transaction commit(transaction) end # Open a read session @@ -63,28 +63,32 @@ For working with data using TypeQL, please refer to the syntax on [TypeQL Docume ```julia using TypeDBClient -# Only for convencience reasons, you can write the full name if you want +# Only for convenience reasons, you can write the full name if you want g = TypeDBClient # Create a client client = g.CoreClient("127.0.0.1",1729) -# Create a database called typedb if the database isn't already created by you previously. +# Create a database called typedb if the database wasn't already created by you previously. g.create_database(client, "typedb") -#= Open a session to write in the schema section of the database. -Be careful if you work with a schema session. No more sessions are allowed -until you close this session. Closing a session is mandatory. Don't forget this -at the end of your work.=# +#= + Open a session to write in the schema section of the database. + Be careful if you work with a schema session. No more sessions are allowed + until you close this session. Closing a session is mandatory. Don't forget this + at the end of your work. +=# session = g.CoreSession(client, "typedb" , g.Proto.Session_Type.SCHEMA, request_timeout=Inf) # Open a write transaction transaction = g.transaction(session, g.Proto.Transaction_Type.WRITE) -#= Make a query in the database -The result of this query will be a vector of ConceptMap. -From there you can access the data as you want.=# -results = g.match(transaction, raw"""match $x sub thing;""") +#= + Make a query in the database + The result of this query will be a vector of ConceptMap. + From there you can access the data as you want. +=# +results = g.match(transaction, "match \$x sub thing;") # If you want to work further in the session, go ahead, else close the session. close(session) @@ -102,13 +106,14 @@ Modules = [TypeDBClient] * delete There are some delete functions: + * database - [`delete_database(client::CoreClient, database_name::String)`](@ref) + [`delete_database(client::AbstractCoreClient, name::AbstractString)`](@ref) * type - [`delete(r::RemoteConcept{C,T}) where {C <:AbstractThingType, T <: AbstractCoreTransaction}`](@ref) + [`unset_has(transaction::AbstractCoreTransaction, thing::AbstractThing, attribute::Attribute)`](@ref) Any type can be deleted with this function. Be aware that only types which have no instances in the database can be deleted. @@ -116,22 +121,24 @@ Modules = [TypeDBClient] * get_has - [`get_owns(r::RemoteConcept{C,T}, value_type::Optional{EnumType}=nothing,keys_only::Bool=false) where {C <: AbstractThingType,T <: AbstractCoreTransaction}`](@ref) + [`get_has(transaction::AbstractCoreTransaction, + thing::AbstractThing, + attribute_type::Optional{AttributeType} = nothing, + attribute_types::Optional{Vector{<:AbstractAttributeType}} = nothing, + keys_only = false)`](@ref) * get_instances - [`get_instances(r::RemoteConcept{C,T}) where - {C <: AbstractThingType,T <: AbstractCoreTransaction}`](@ref) + [`get_instances(r::RemoteConcept{<:AbstractThingType})`](@ref) * get_owns [`get_owns( - r::RemoteConcept{C,T}, + r::RemoteConcept{<:AbstractThingType}, value_type::Optional{EnumType}=nothing, keys_only::Bool=false - ) where {C <: AbstractThingType,T <: AbstractCoreTransaction}`](@ref) - + )`](@ref) * get_owners @@ -143,25 +150,22 @@ Modules = [TypeDBClient] * AttributeType - [`get_owners(r::RemoteConcept{C,T}, only_key = false) where { - C <: AbstractAttributeType, T <: AbstractCoreTransaction}`](@ref) + [`get_owners(r::RemoteConcept{<: AbstractAttributeType}, only_key = false)`](@ref) * get_plays - [`get_plays(r::RemoteConcept{C,T}) where - {C <: AbstractThingType,T <: AbstractCoreTransaction}`](@ref) + [`get_plays(r::RemoteConcept{<: AbstractThingType})`](@ref) -* get_regex - [`get_regex(r::RemoteConcept{C,T}) where { - C <: AbstractAttributeType, T <: AbstractCoreTransaction}`](@ref) +* get_regex + [`get_regex(r::RemoteConcept{<:AbstractAttributeType})`](@ref) * get_rule - [`get_rule(log_mgr::AbstractLogicManager, label::String)`](@ref) + [`get_rule(log_mgr::AbstractLogicManager, label::AbstractString)`](@ref) * get_rules @@ -171,65 +175,68 @@ Modules = [TypeDBClient] * get_subtypes - [`get_subtypes(r::RemoteConcept{C,T}) where - {C <: AbstractType,T <: AbstractCoreTransaction}`](@ref) + [`get_subtypes(r::RemoteConcept{<:AbstractType})`](@ref) + * get_supertype - [`get_supertype( - r::RemoteConcept{C,T}) where {C <: AbstractType,T <: AbstractCoreTransaction}`](@ref) + [`get_supertype(r::RemoteConcept{<:AbstractType})`](@ref) + * get_supertypes - [`get_supertypes(r::RemoteConcept{C,T}) where - {C <: AbstractType,T <: AbstractCoreTransaction}`](@ref) + [` get_supertypes(r::RemoteConcept{<:AbstractType})`](@ref) + * set_abstract - [`set_abstract(r::RemoteConcept{C,T}) where - {C <: AbstractThingType,T <: AbstractCoreTransaction}`](@ref) + [`set_abstract(r::RemoteConcept{<:AbstractThingType})`](@ref) * set_has [`set_has(transaction::AbstractCoreTransaction, thing::AbstractThing, attribute::Attribute)`](@ref) + * set_label - [`set_label(r::RemoteConcept{C,T}, new_label_name::String) where - {C <: AbstractType,T <: AbstractCoreTransaction}`](@ref) + [`set_label(r::RemoteConcept{<:AbstractType}, + new_label_name::AbstractString)`](@ref) * set_owns [`set_owns( - r::RemoteConcept{C,T}, - attribute_type::AbstractType, - is_key::Bool=false, - overriden_type::Optional{AbstractType}=nothing - ) where {C <: AbstractType,T <: AbstractCoreTransaction}`](@ref) + r::RemoteConcept{<:AbstractType}, + attribute_type::AbstractType, + is_key::Bool=false, + overriden_type::Optional{AbstractType}=nothing + )`](@ref) + * set_plays - [`function set_plays( - r::RemoteConcept{C,T}, + [`set_plays( + r::RemoteConcept{<:AbstractThingType}, role_type::AbstractRoleType, overridden_role_type::Optional{AbstractRoleType}=nothing - ) where {C <: AbstractThingType,T <: AbstractCoreTransaction}`](@ref) + )`](@ref) + * set_regex - [``set_regex(r::RemoteConcept{C,T}, regex::Optional{AbstractString}) where { - C <: AbstractAttributeType, T <: AbstractCoreTransaction}](@ref) + [`set_regex(r::RemoteConcept{<:AbstractAttributeType}, + regex::Optional{AbstractString})`](@ref) + * set_supertype - [`set_supertype(r::RemoteConcept{C,T}, - super_type::AbstractThingType) where - {C <: AbstractThingType,T <: AbstractCoreTransaction}`](@ref) + [`set_supertype(r::RemoteConcept{<: AbstractThingType,<: AbstractCoreTransaction}, + super_type::AbstractThingType)`](@ref) + * unset_abstract - [`unset_abstract(r::RemoteConcept{C,T}) where - {C <: AbstractThingType,T <: AbstractCoreTransaction}`](@ref) + [`unset_abstract(r::RemoteConcept{<:AbstractThingType})`](@ref) + * unset_has diff --git a/src/common/exception/TypeDBClientException.jl b/src/common/exception/TypeDBClientException.jl index cc8ccad2..c6e1f950 100644 --- a/src/common/exception/TypeDBClientException.jl +++ b/src/common/exception/TypeDBClientException.jl @@ -55,7 +55,7 @@ function TypeDBClientException(err::gRPCServiceCallException, parameters...) return TypeDBClientException(def_err, isempty(parameters) ? Tuple{}() : parameters, nothing, nothing) end -function TypeDBClientException(message::String, cause::T) where {T<:Exception} +function TypeDBClientException(message::AbstractString, cause::Exception) err = _build_error_messages(GENERAL_UNKOWN_ERROR) return TypeDBClientException(err,nothing,message,cause) end diff --git a/src/common/rpc/RequestBuilder.jl b/src/common/rpc/RequestBuilder.jl index 0494b497..9e8a6848 100644 --- a/src/common/rpc/RequestBuilder.jl +++ b/src/common/rpc/RequestBuilder.jl @@ -5,9 +5,9 @@ module DatabaseManagerRequestBuilder using ..TypeDBClient: Proto -create_req(name::String) = Proto.CoreDatabaseManager_Create_Req(; name) +create_req(name::AbstractString) = Proto.CoreDatabaseManager_Create_Req(; name) -contains_req(name::String) = Proto.CoreDatabaseManager_Contains_Req(; name) +contains_req(name::AbstractString) = Proto.CoreDatabaseManager_Contains_Req(; name) all_req() = Proto.CoreDatabaseManager_All_Req() @@ -18,9 +18,9 @@ module DatabaseRequestBuilder using ..TypeDBClient: Proto -schema_req(name::String) = Proto.CoreDatabase_Schema_Req(; name) +schema_req(name::AbstractString) = Proto.CoreDatabase_Schema_Req(; name) -delete_req(name::String) = Proto.CoreDatabase_Delete_Req(; name) +delete_req(name::AbstractString) = Proto.CoreDatabase_Delete_Req(; name) end @@ -29,7 +29,7 @@ module SessionRequestBuilder using ..TypeDBClient: Proto, EnumType, Bytes -function open_req(database::String, _type::EnumType, options::Proto.Options) +function open_req(database::AbstractString, _type::EnumType, options::Proto.Options) return Proto.Session_Open_Req(; database, _type, options) end @@ -93,7 +93,7 @@ for (f, t) in ( func = Symbol("$f") type = Symbol("QueryManager_$t") @eval begin - function $func(query::String, options::Proto.Options = Proto.Options()) + function $func(query::AbstractString, options::Proto.Options = Proto.Options()) $f = Proto.$type(; query) query_manager_req = Proto.QueryManager_Req(; $f, options) return Proto.Transaction_Req(; query_manager_req) @@ -114,32 +114,32 @@ function _treq(; kwargs...) ) end -function put_entity_type_req(label::String) +function put_entity_type_req(label::AbstractString) return _treq( put_entity_type_req = Proto.ConceptManager_PutEntityType_Req(; label) ) end -function put_relation_type_req(label::String) +function put_relation_type_req(label::AbstractString) return _treq( put_relation_type_req = Proto.ConceptManager_PutRelationType_Req(; label) ) end -function put_attribute_type_req(label::String, value_type::EnumType) +function put_attribute_type_req(label::AbstractString, value_type::EnumType) return _treq( put_attribute_type_req = Proto.ConceptManager_PutAttributeType_Req(; label, value_type) ) end -function get_thing_type_req(label::String) +function get_thing_type_req(label::AbstractString) return _treq( get_thing_type_req = Proto.ConceptManager_GetThingType_Req(; label) ) end -function get_thing_req(iid::String) +function get_thing_req(iid::AbstractString) return _treq( get_thing_req = Proto.ConceptManager_GetThing_Req(; iid = bytes(iid)) ) @@ -160,13 +160,13 @@ function _treq(; kwargs...) ) end -function put_rule_req(label::String, when::String, then::String) +function put_rule_req(label::AbstractString, when::AbstractString, then::AbstractString) return _treq( put_rule_req = Proto.LogicManager_PutRule_Req(; label, when, then) ) end -function get_rule_req(label::String) +function get_rule_req(label::AbstractString) return _treq( get_rule_req = Proto.LogicManager_GetRule_Req(; label) ) @@ -198,7 +198,7 @@ function is_abstract_req(label::Label) ) end -function set_label_req(label::Label, new_label::String) +function set_label_req(label::Label, new_label::AbstractString) return _treq(label.name, label.scope; type_set_label_req = Proto.Type_SetLabel_Req( label = new_label @@ -399,7 +399,7 @@ function get_relates_req(label::Label) end function set_relates_req( - label::Label, role_label::String, overridden_label::Optional{String}) + label::Label, role_label::AbstractString, overridden_label::Optional{<:AbstractString}) relation_type_set_relates_req = overridden_label !== nothing ? Proto.RelationType_SetRelates_Req(; @@ -419,7 +419,7 @@ function unset_relates_req(label::Label, role_label::Optional{String}) ) end -function relation_type_get_relates_for_role_label_req(label::Label, role_label::String) +function relation_type_get_relates_for_role_label_req(label::Label, role_label::AbstractString) return _treq(label.name, label.scope; relation_type_get_relates_for_role_label_req = Proto.RelationType_GetRelatesForRoleLabel_Req(; label = role_label @@ -473,9 +473,9 @@ module ThingRequestBuilder using ..TypeDBClient: Proto, Label, Bytes, bytes, Optional proto_thing(iid::Bytes) = Proto.Thing(; iid) -proto_thing(iid::String) = proto_thing(bytes(iid)) +proto_thing(iid::AbstractString) = proto_thing(bytes(iid)) -function _thing_req(iid::String; kwargs...) +function _thing_req(iid::AbstractString; kwargs...) return Proto.Transaction_Req( thing_req = Proto.Thing_Req( ; iid = bytes(iid), kwargs... @@ -483,43 +483,43 @@ function _thing_req(iid::String; kwargs...) ) end -function is_inferred_req(iid::String) +function is_inferred_req(iid::AbstractString) return _thing_req(iid; thing_is_inferred_req = Proto.Thing_IsInferred_Req() ) end -function get_has_req(iid::String, attribute_types::AbstractVector{Proto._Type}) +function get_has_req(iid::AbstractString, attribute_types::AbstractVector{Proto._Type}) return _thing_req(iid; thing_get_has_req = Proto.Thing_GetHas_Req(; attribute_types) ) end -function get_has_req(iid::String, keys_only::Bool) +function get_has_req(iid::AbstractString, keys_only::Bool) return _thing_req(iid; thing_get_has_req = Proto.Thing_GetHas_Req(; keys_only) ) end -function set_has_req(iid::String, attribute::Proto.Thing) +function set_has_req(iid::AbstractString, attribute::Proto.Thing) return _thing_req(iid; thing_set_has_req = Proto.Thing_SetHas_Req(; attribute) ) end -function unset_has_req(iid::String, attribute::Proto.Thing) +function unset_has_req(iid::AbstractString, attribute::Proto.Thing) return _thing_req(iid; thing_unset_has_req = Proto.Thing_UnsetHas_Req(; attribute) ) end -function get_playing_req(iid::String) +function get_playing_req(iid::AbstractString) return _thing_req(iid; thing_get_playing_req = Proto.Thing_GetPlaying_Req() ) end -function get_relations_req(iid::String, role_types::Optional{AbstractVector{Proto._Type}}) +function get_relations_req(iid::AbstractString, role_types::Optional{<:AbstractVector{Proto._Type}}) thing_get_relations_req = Proto.Thing_GetRelations_Req() if role_types !== nothing thing_get_relations_req.role_types = role_types @@ -529,19 +529,19 @@ function get_relations_req(iid::String, role_types::Optional{AbstractVector{Prot ) end -function delete_req(iid::String) +function delete_req(iid::AbstractString) return _thing_req(iid; thing_delete_req = Proto.Thing_Delete_Req() ) end -function attribute_get_owners_req(iid::String, thing_type::Proto._Type) +function attribute_get_owners_req(iid::AbstractString, thing_type::Proto._Type) return _thing_req(iid; attribute_get_owners_req = Proto.Attribute_GetOwners_Req(; thing_type) ) end -function attribute_get_owners_req(iid::String) +function attribute_get_owners_req(iid::AbstractString) return _thing_req(iid; attribute_get_owners_req = Proto.Attribute_GetOwners_Req() ) @@ -555,7 +555,7 @@ module RelationRequestBuilder using ..TypeDBClient: Proto, Optional using ..ThingRequestBuilder: _thing_req -function add_player_req(iid::String, role_type::Proto._Type, player::Proto.Thing) +function add_player_req(iid::AbstractString, role_type::Proto._Type, player::Proto.Thing) return _thing_req(iid; relation_add_player_req = Proto.Relation_AddPlayer_Req(; role_type, @@ -564,7 +564,7 @@ function add_player_req(iid::String, role_type::Proto._Type, player::Proto.Thing ) end -function remove_player_req(iid::String, role_type::Proto._Type, player::Proto.Thing) +function remove_player_req(iid::AbstractString, role_type::Proto._Type, player::Proto.Thing) return _thing_req(iid; relation_remove_player_req = Proto.Relation_RemovePlayer_Req(; role_type, @@ -573,7 +573,7 @@ function remove_player_req(iid::String, role_type::Proto._Type, player::Proto.Th ) end -function get_players_req(iid::String, role_types::Optional{AbstractVector{Proto._Type}} = nothing) +function get_players_req(iid::AbstractString, role_types::Optional{AbstractVector{Proto._Type}} = nothing) relation_get_players_req = Proto.Relation_GetPlayers_Req() if role_types !== nothing @@ -584,13 +584,13 @@ function get_players_req(iid::String, role_types::Optional{AbstractVector{Proto. ) end -function get_players_by_role_type_req(iid::String) +function get_players_by_role_type_req(iid::AbstractString) return _thing_req(iid; relation_get_players_by_role_type_req = Proto.Relation_GetPlayersByRoleType_Req() ) end -function get_relating_req(iid::String) +function get_relating_req(iid::AbstractString) return _thing_req(iid; relation_get_players_req = Proto.Relation_GetRelating_Req() ) @@ -605,7 +605,7 @@ using ..TypeDBClient: Proto, Optional using ..ThingRequestBuilder: _thing_req using TimeZones: ZonedDateTime -function get_owners_req(iid::String, owner_type::Optional{Proto._Type}) +function get_owners_req(iid::AbstractString, owner_type::Optional{Proto._Type}) return _thing_req(iid; relation_get_owners_req = Proto.Relation_GetOwners_Req(), thing_type = owner_type @@ -615,7 +615,7 @@ end proto_boolean_attribute_value(value::Bool) = Proto.Attribute_Value(; boolean = value) proto_long_attribute_value(value::Int64) = Proto.Attribute_Value(; long = value) proto_double_attribute_value(value::Float64) = Proto.Attribute_Value(; double = value) -proto_string_attribute_value(value::String) = Proto.Attribute_Value(; string = value) +proto_string_attribute_value(value::AbstractString) = Proto.Attribute_Value(; string = value) function proto_date_time_attribute_value(value::ZonedDateTime) epoch_millis = value.utc_datetime.instant @@ -629,7 +629,7 @@ module RuleRequestBuilder using ..TypeDBClient: Proto -function set_label_req(current_label::String, new_label::String) +function set_label_req(current_label::AbstractString, new_label::AbstractString) return Proto.Transaction_Req( rule_req = Proto.Rule_Req( label = current_label, @@ -640,7 +640,7 @@ function set_label_req(current_label::String, new_label::String) ) end -function delete_req(label::String) +function delete_req(label::AbstractString) return Proto.Transaction_Req( rule_req = Proto.Rule_Req( rule_delete_req = Proto.Rule_Delete_Req() diff --git a/src/concept/Concept.jl b/src/concept/Concept.jl index a8552baf..250c4665 100644 --- a/src/concept/Concept.jl +++ b/src/concept/Concept.jl @@ -48,9 +48,9 @@ end Wrapper type that encapsulates a concept and transaction. """ -struct RemoteConcept{D <: AbstractConcept, T <: AbstractCoreTransaction} +struct RemoteConcept{D <: AbstractConcept} concept::D - transaction::T + transaction::AbstractCoreTransaction end """ @@ -59,8 +59,8 @@ end Create a `Remote`(@ref) object for a concept `x` with a transaction `t`. """ -function as_remote(x::D, t::T) where { - D<: AbstractConcept, T <: AbstractCoreTransaction +function as_remote(x::D, t::AbstractCoreTransaction) where { + D<: AbstractConcept } - return RemoteConcept{D, T}(x, t) + return RemoteConcept{D}(x, t) end diff --git a/src/concept/ConceptManager.jl b/src/concept/ConceptManager.jl index f60dd528..8d8c652e 100644 --- a/src/concept/ConceptManager.jl +++ b/src/concept/ConceptManager.jl @@ -13,13 +13,13 @@ Base.get(cm::ConceptManager, ::Type{RelationType}, ::Root) = get(cm, ThingType, Base.get(cm::ConceptManager, ::Type{AttributeType}, ::Root) = get(cm, ThingType, "attribute") Base.get(cm::ConceptManager, ::Type{ThingType}, ::Root) = get(cm, ThingType, "thing") -function Base.get(cm::ConceptManager, ::Type{EntityType}, label::String) +function Base.get(cm::ConceptManager, ::Type{EntityType}, label::AbstractString) t = get(cm, ThingType, label) t !== nothing && t isa EntityType && return t return nothing end -function put(cm::ConceptManager, ::Type{EntityType}, label::String) +function put(cm::ConceptManager, ::Type{EntityType}, label::AbstractString) res = execute(cm, ConceptManagerRequestBuilder.put_entity_type_req(label)) if which_oneof(res, :res) == :put_entity_type_res return instantiate(res.put_entity_type_res.entity_type) @@ -27,13 +27,13 @@ function put(cm::ConceptManager, ::Type{EntityType}, label::String) return nothing end -function Base.get(cm::ConceptManager, ::Type{RelationType}, label::String) +function Base.get(cm::ConceptManager, ::Type{RelationType}, label::AbstractString) t = get(cm, ThingType, label) t !== nothing && t isa RelationType && return t return nothing end -function put(cm::ConceptManager, ::Type{RelationType}, label::String) +function put(cm::ConceptManager, ::Type{RelationType}, label::AbstractString) res = execute(cm, ConceptManagerRequestBuilder.put_relation_type_req(label)) if which_oneof(res, :res) == :put_relation_type_res return instantiate(res.put_relation_type_res.relation_type) @@ -41,13 +41,13 @@ function put(cm::ConceptManager, ::Type{RelationType}, label::String) return nothing end -function Base.get(cm::ConceptManager, ::Type{AttributeType}, label::String) +function Base.get(cm::ConceptManager, ::Type{AttributeType}, label::AbstractString) t = get(cm, ThingType, label) t !== nothing && t isa AttributeType && return t return nothing end -function put(cm::ConceptManager, ::Type{AttributeType}, label::String, value_type::EnumType) +function put(cm::ConceptManager, ::Type{AttributeType}, label::AbstractString, value_type::EnumType) res = execute(cm, ConceptManagerRequestBuilder.put_attribute_type_req(label, value_type)) if which_oneof(res, :res) == :put_attribute_type_res return instantiate(res.put_attribute_type_res.attribute_type) @@ -55,7 +55,7 @@ function put(cm::ConceptManager, ::Type{AttributeType}, label::String, value_typ return nothing end -function Base.get(cm::ConceptManager, ::Type{ThingType}, label::String) +function Base.get(cm::ConceptManager, ::Type{ThingType}, label::AbstractString) req = ConceptManagerRequestBuilder.get_thing_type_req(label) res = execute(cm, req) if which_oneof(res, :res) == :get_thing_type_res @@ -68,7 +68,7 @@ function Base.get(cm::ConceptManager, ::Type{ThingType}, label::String) return nothing end -function Base.get(cm::ConceptManager, iid::String) +function Base.get(cm::ConceptManager, iid::AbstractString) res = get_proto_thing(cm, iid) res !== nothing && return instantiate(res) return nothing @@ -80,12 +80,12 @@ end function execute(cm::ConceptManager, req::Proto.Transaction_Req) result = execute(cm.transaction, req) - return result.concept_manager_res + return result !== nothing ? result.concept_manager_res : result end # get_proto_thing is supposed to be a vehicle to get things in its proto form to get # a result for setting up set_has etc. -function get_proto_thing(cm::ConceptManager, iid::String) +function get_proto_thing(cm::ConceptManager, iid::AbstractString) req = ConceptManagerRequestBuilder.get_thing_req(iid) res = execute(cm, req) if which_oneof(res, :res) == :get_thing_res diff --git a/src/concept/answer/ConceptMap.jl b/src/concept/answer/ConceptMap.jl index 6c2baaa8..aec5b3e5 100644 --- a/src/concept/answer/ConceptMap.jl +++ b/src/concept/answer/ConceptMap.jl @@ -41,7 +41,7 @@ end concepts(cm::ConceptMap) = values(cm.data) -Base.getindex(cm::ConceptMap, key::String) = cm.data[key] +Base.getindex(cm::ConceptMap, key::AbstractString) = cm.data[key] function Base.show(io::IO, cm::ConceptMap) num_entries = length(cm.data) diff --git a/src/concept/thing/Attribute.jl b/src/concept/thing/Attribute.jl index 6e87aff9..fca95313 100644 --- a/src/concept/thing/Attribute.jl +++ b/src/concept/thing/Attribute.jl @@ -28,6 +28,13 @@ function Attribute(t::Proto.Thing) end end +""" + get_owners(transaction::AbstractCoreTransaction, + attribute::AbstractAttribute, + thing_type::Optional{AbstractThingType} = nothing) + +gives back all things has this attribute +""" function get_owners( transaction::AbstractCoreTransaction, attribute::AbstractAttribute, diff --git a/src/concept/thing/Thing.jl b/src/concept/thing/Thing.jl index 00e3980b..2d39e7ed 100644 --- a/src/concept/thing/Thing.jl +++ b/src/concept/thing/Thing.jl @@ -16,6 +16,11 @@ function instantiate(t::Proto.Thing) end end +""" + set_has(transaction::AbstractCoreTransaction, thing::AbstractThing, attribute::Attribute) + +For a given Thing the attribute will set as associated. +""" function set_has(transaction::AbstractCoreTransaction, thing::AbstractThing, attribute::Attribute) res_proto_attribute = get_proto_thing(ConceptManager(transaction), attribute.iid) has_req = ThingRequestBuilder.set_has_req(thing.iid, res_proto_attribute) @@ -24,6 +29,11 @@ function set_has(transaction::AbstractCoreTransaction, thing::AbstractThing, att return nothing end +""" + unset_has(transaction::AbstractCoreTransaction, thing::AbstractThing, attribute::Attribute) + +Here an given attribute will be detached from a given thing +""" function unset_has(transaction::AbstractCoreTransaction, thing::AbstractThing, attribute::Attribute) res_proto_attribute = get_proto_thing(ConceptManager(transaction), attribute.iid) unset_has_req = ThingRequestBuilder.unset_has_req(thing.iid, res_proto_attribute) @@ -32,6 +42,17 @@ function unset_has(transaction::AbstractCoreTransaction, thing::AbstractThing, a return nothing end +""" + get_has(transaction::AbstractCoreTransaction, + thing::AbstractThing, + attribute_type::Optional{AttributeType} = nothing, + attribute_types::Optional{Vector{<:AbstractAttributeType}} = nothing, + keys_only = false) + +With this function it is possible to get attributes of an entity or a relation. +Optional it is possible to restrict the type(s) of attributes which will retrieved from +the database. You can decide between only one ore more than one type. +""" function get_has(transaction::AbstractCoreTransaction, thing::AbstractThing, attribute_type::Optional{AttributeType} = nothing, diff --git a/src/concept/type/AttributeType.jl b/src/concept/type/AttributeType.jl index 2d43c1bf..ee6bd81d 100644 --- a/src/concept/type/AttributeType.jl +++ b/src/concept/type/AttributeType.jl @@ -72,9 +72,8 @@ is_keyable(::AttributeType{VALUE_TYPE.LONG}) = true # get_instances # Technically, we can reuse the logic from ThingType. Maybe refactor soon. -function get_subtypes(r::RemoteConcept{C,T}) where { - C <: AbstractAttributeType, T <: AbstractCoreTransaction -} +function get_subtypes(r::RemoteConcept{<: AbstractAttributeType}) + concept = r.concept req = TypeRequestBuilder.get_subtypes_req(label(concept)) res = execute(r.transaction, req) @@ -88,30 +87,50 @@ function get_subtypes(r::RemoteConcept{C,T}) where { end end -function get_owners(r::RemoteConcept{C,T}, only_key = false) where { - C <: AbstractAttributeType, T <: AbstractCoreTransaction -} +""" + get_owners(r::RemoteConcept{<: AbstractAttributeType}, only_key = false) + +Returns all ThingTypes which owns the given AttributeType +""" +function get_owners(r::RemoteConcept{<: AbstractAttributeType}, only_key = false) + req = AttributeTypeRequestBuilder.get_owners_req(r.concept.label, only_key) res = stream(r.transaction, req) return instantiate.(collect(Iterators.flatten( r.type_res_part.attribute_type_get_owners_res_part.owners for r in res))) end -function get_regex(r::RemoteConcept{C,T}) where { - C <: AbstractAttributeType, T <: AbstractCoreTransaction -} +""" + get_regex(r::RemoteConcept{<:AbstractAttributeType}) + +For AttributeTypes with the value type String it is possible to set a regex pattern +to proof the incoming string to fulfill the pattern. Otherwise the insert will fail. +The function wil give back a regex string if set. The regex string follows the conventions +of the Java programming language. +""" +function get_regex(r::RemoteConcept{<:AbstractAttributeType}) + req = AttributeTypeRequestBuilder.get_regex_req(r.concept.label) res = execute(r.transaction, req) regex = res.type_res.attribute_type_get_regex_res.regex return isempty(regex) ? nothing : regex end -function set_regex(r::RemoteConcept{C,T}, regex::Optional{AbstractString}) where { - C <: AbstractAttributeType, T <: AbstractCoreTransaction -} + +""" + set_regex(r::RemoteConcept{<:AbstractAttributeType}, + regex::Optional{AbstractString}) + +For AttributeTypes with the value type String it is possible to set a regex pattern +to check the incoming string matches the pattern, otherwise the insert will fail. +The function will set a regex string to a given attribute. The regex string follows the +conventions of the Java programming language. +""" +function set_regex(r::RemoteConcept{<:AbstractAttributeType}, regex::Optional{AbstractString}) + regex_str = regex === nothing ? "" : regex req = AttributeTypeRequestBuilder.set_regex_req(r.concept.label, regex_str) - res = execute(r.transaction, req) + return execute(r.transaction, req) end proto_attribute_value(value::Bool) = Proto.Attribute_Value(; boolean = value) @@ -126,9 +145,7 @@ function proto_attribute_value(value::DateTime) return Proto.Attribute_Value(; date_time = milliseconds_since_1970) end -function Base.get(r::RemoteConcept{C,T}, value) where { - C <: AbstractAttributeType, T <: AbstractCoreTransaction -} +function Base.get(r::RemoteConcept{<:AbstractAttributeType}, value) req = AttributeTypeRequestBuilder.get_req(r.concept.label, proto_attribute_value(value)) res = execute(r.transaction, req) if hasproperty(res.type_res.attribute_type_get_res, :attribute) @@ -138,9 +155,7 @@ function Base.get(r::RemoteConcept{C,T}, value) where { end end -function put(r::RemoteConcept{C,T}, value) where { - C <: AbstractAttributeType, T <: AbstractCoreTransaction -} +function put(r::RemoteConcept{<: AbstractAttributeType}, value) req = AttributeTypeRequestBuilder.put_req(r.concept.label, proto_attribute_value(value)) res = execute(r.transaction, req) return Attribute(res.type_res.attribute_type_put_res.attribute) diff --git a/src/concept/type/RelationType.jl b/src/concept/type/RelationType.jl index cb1450eb..80d978c5 100644 --- a/src/concept/type/RelationType.jl +++ b/src/concept/type/RelationType.jl @@ -12,8 +12,8 @@ end function set_relates(transaction::AbstractCoreTransaction, label::Label, - role_label::String, - overridden_label::Optional{String} = nothing) + role_label::AbstractString, + overridden_label::Optional{<:AbstractString} = nothing) relates_req = RelationTypeRequestBuilder.set_relates_req(label, role_label, @@ -30,7 +30,7 @@ function get_relates(r::RemoteConcept{RelationType}) r.type_res_part.relation_type_get_relates_res_part.roles for r in res))) end -function relation_type_get_relates_for_role_label(r::RemoteConcept{RelationType}, for_role::String) +function relation_type_get_relates_for_role_label(r::RemoteConcept{RelationType}, for_role::AbstractString) role_req = RelationTypeRequestBuilder.relation_type_get_relates_for_role_label_req(r.concept.label,for_role) res = execute(r.transaction, role_req) diff --git a/src/concept/type/ThingType.jl b/src/concept/type/ThingType.jl index 25c7435e..8eaa930a 100644 --- a/src/concept/type/ThingType.jl +++ b/src/concept/type/ThingType.jl @@ -5,6 +5,14 @@ struct ThingType <: AbstractThingType is_root::Bool end +Instanciate_Types = Union{<:AbstractAttribute, + <:AbstractRelation, + <:AbstractEntity, + <:AbstractThingType, + <:AbstractEntityType, + <:AbstractAttributeType, + <:AbstractRelationType} + # Porting note: Java client calls into RequestBuilder but it really # has nothing to to with requests... I think it's probably better # migrating the function here. @@ -27,43 +35,74 @@ label(t::AbstractThingType) = t.label # Remote functions # ------------------------------------------------------------------------ -function set_supertype(r::RemoteConcept{C,T}, - super_type::AbstractThingType) where - {C <: AbstractThingType,T <: AbstractCoreTransaction} +""" + set_supertype(r::RemoteConcept{<: AbstractThingType,<: AbstractCoreTransaction}, + super_type::AbstractThingType) + +Here we have the chance to set a given ThingType as the supertype of an other Thingtype. +Mixing of diffent root types eg. AttributeType with EntityType is not allowed. +""" +function set_supertype(r::RemoteConcept{<:AbstractThingType}, + super_type::AbstractThingType) req = ThingTypeRequestBuilder.set_supertype_req(r.concept.label, proto(super_type)) execute(r.transaction, req) end -function get_supertype( - r::RemoteConcept{C,T}) where {C <: AbstractType,T <: AbstractCoreTransaction} +""" + get_supertype(r::RemoteConcept{<:AbstractType}) +Returns one step upwards in the chain of types and returns the direct supertype of a +given type. +""" +function get_supertype(r::RemoteConcept{<:AbstractType}) req = TypeRequestBuilder.get_supertype_req(r.concept.label) res = execute(r.transaction, req) typ = res.type_res.type_get_supertype_res._type return instantiate(typ) end -function get_supertypes(r::RemoteConcept{C,T}) where - {C <: AbstractType,T <: AbstractCoreTransaction} +""" + get_supertypes(r::RemoteConcept{<:AbstractType}) + +Here all supertypes in the chain upwards from the given type will be returned. +""" +function get_supertypes(r::RemoteConcept{<:AbstractType}) req = TypeRequestBuilder.get_supertypes_req(r.concept.label) res = execute(r.transaction, req) - typs = res.type_res_part.type_get_supertypes_res_part.types - return instantiate.(typs) + if res !== nothing + typs = res.type_res_part.type_get_supertypes_res_part.types + return instantiate.(typs) + else + return Instanciate_Types[] + end end -function get_subtypes(r::RemoteConcept{C,T}) where - {C <: AbstractType,T <: AbstractCoreTransaction} +""" + get_subtypes(r::RemoteConcept{<:AbstractType}) + +get_subtypes returns all subtypes for a given type. A specialzation of this function +is made for AttributeType. +""" +function get_subtypes(r::RemoteConcept{<:AbstractType}) req = TypeRequestBuilder.get_subtypes_req(r.concept.label) res = execute(r.transaction, req) - typs = res.type_res_part.type_get_subtypes_res_part.types - return instantiate.(typs) + if res !== nothing + typs = res.type_res_part.type_get_subtypes_res_part.types + return instantiate.(typs) + else + return [] + end end -function get_instances(r::RemoteConcept{C,T}) where - {C <: AbstractThingType,T <: AbstractCoreTransaction} +""" + get_instances(r::RemoteConcept{<:AbstractThingType}) + +Here you can get all instances for a given Type. The has to be given as a RemoteConcept +""" +function get_instances(r::RemoteConcept{<:AbstractThingType}) req = ThingTypeRequestBuilder.get_instances_req(r.concept.label) res = stream(r.transaction, req) @@ -71,33 +110,52 @@ function get_instances(r::RemoteConcept{C,T}) where r.type_res_part.thing_type_get_instances_res_part.things for r in res))) end -function set_abstract(r::RemoteConcept{C,T}) where - {C <: AbstractThingType,T <: AbstractCoreTransaction} +""" + set_abstract(r::RemoteConcept{<:AbstractThingType}) +In the chain of fine grained functions in the concept section here we can determine +a given ThingType is abstract. +""" +function set_abstract(r::RemoteConcept{<:AbstractThingType}) req = ThingTypeRequestBuilder.set_abstract_req(r.concept.label) execute(r.transaction, req) end -function unset_abstract(r::RemoteConcept{C,T}) where - {C <: AbstractThingType,T <: AbstractCoreTransaction} +""" + unset_abstract(r::RemoteConcept{<:AbstractThingType}) + +With this function it is possible to change an ThingType from abstact to normal behavior +which means that the given ThingType can be instanceated. +""" +function unset_abstract(r::RemoteConcept{<:AbstractThingType}) req = ThingTypeRequestBuilder.unset_abstract_req(r.concept.label) execute(r.transaction, req) end -function is_abstract(r::RemoteConcept{C,T}) where - {C <: AbstractType,T <: AbstractCoreTransaction} +function is_abstract(r::RemoteConcept{<:AbstractType}) req = TypeRequestBuilder.is_abstract_req(r.concept.label) res = execute(r.transaction, req) return res.type_res.type_is_abstract_res._abstract end +""" + set_plays( + r::RemoteConcept{<:AbstractThingType}, + role_type::AbstractRoleType, + overridden_role_type::Optional{AbstractRoleType}=nothing + ) + +With set_play we are able to set a roletype to an ThingType and it is possible to +set a new RoleType instead of the old. Be cautious, this is only allowed for not instantiated +types. +""" function set_plays( - r::RemoteConcept{C,T}, + r::RemoteConcept{<:AbstractThingType}, role_type::AbstractRoleType, overridden_role_type::Optional{AbstractRoleType}=nothing -) where {C <: AbstractThingType,T <: AbstractCoreTransaction} +) req = ThingTypeRequestBuilder.set_plays_req( r.concept.label, proto(role_type), @@ -106,19 +164,31 @@ function set_plays( execute(r.transaction, req) end -function unset_plays(r::RemoteConcept{C,T}, - role_type::AbstractRoleType -) where {C <: AbstractThingType,T <: AbstractCoreTransaction} +function unset_plays(r::RemoteConcept{<:AbstractThingType}, role_type::AbstractRoleType) unset_req = ThingTypeRequestBuilder.unset_plays_req(r.concept.label, proto(role_type)) execute(r.transaction, unset_req) end +""" + set_owns( + r::RemoteConcept{<:AbstractType}, + attribute_type::AbstractType, + is_key::Bool=false, + overriden_type::Optional{AbstractType}=nothing + ) + +With set_owns it is possible to assign an attribute to a type. If it is needed it is +possible to set the attribute as unique. This means for the type where the attribute is set +as key only one instance of the type can have a specific attribute: +E.g. person entity has a unique email as an attribute. So it is not possible to have two +entities with the same email address. +""" function set_owns( - r::RemoteConcept{C,T}, + r::RemoteConcept{<:AbstractType}, attribute_type::AbstractType, is_key::Bool=false, overriden_type::Optional{AbstractType}=nothing -) where {C <: AbstractType,T <: AbstractCoreTransaction} +) req = ThingTypeRequestBuilder.set_owns_req( r.concept.label, is_key, @@ -129,9 +199,8 @@ function set_owns( end function unset_owns( - r::RemoteConcept{C,T}, - attribute_type::AbstractType -) where {C <: AbstractType,T <: AbstractCoreTransaction} + r::RemoteConcept{<: AbstractType}, + attribute_type::AbstractType) req = ThingTypeRequestBuilder.unset_owns_req( r.concept.label, proto(attribute_type) @@ -139,28 +208,48 @@ function unset_owns( execute(r.transaction, req) end +""" + get_owns( + r::RemoteConcept{<:AbstractThingType}, + value_type::Optional{EnumType}=nothing, + keys_only::Bool=false + ) + +get_owns will give back all thingtypes which owns a given AttributeType +""" function get_owns( - r::RemoteConcept{C,T}, + r::RemoteConcept{<:AbstractThingType}, value_type::Optional{EnumType}=nothing, keys_only::Bool=false -) where {C <: AbstractThingType,T <: AbstractCoreTransaction} +) req = ThingTypeRequestBuilder.get_owns_req(r.concept.label, value_type, keys_only) res = stream(r.transaction, req) return instantiate.(collect(Iterators.flatten( r.type_res_part.thing_type_get_owns_res_part.attribute_types for r in res))) end -function get_plays(r::RemoteConcept{C,T}) where - {C <: AbstractThingType,T <: AbstractCoreTransaction} +""" + get_plays(r::RemoteConcept{<: AbstractThingType}) +Returns which roles are played by the given ThingType +""" +function get_plays(r::RemoteConcept{<:AbstractThingType}) req = ThingTypeRequestBuilder.get_plays_req(r.concept.label) res = stream(r.transaction, req) return instantiate.(collect(Iterators.flatten( r.type_res_part.thing_type_get_plays_res_part.roles for r in res))) end -function set_label(r::RemoteConcept{C,T}, new_label_name::String) where - {C <: AbstractType,T <: AbstractCoreTransaction} +""" + set_label(r::RemoteConcept{<:AbstractType}, + new_label_name::AbstractString) + +With this function we are able to set the label for a given Type. This gives us the +chance to rename a given type. But be prepared, this is only allowed if the type is +not instantiated by inserted data. +""" +function set_label(r::RemoteConcept{<:AbstractType}, + new_label_name::AbstractString) set_label_req = TypeRequestBuilder.set_label_req(r.concept.label, new_label_name) execute(r.transaction, set_label_req) @@ -169,14 +258,12 @@ function set_label(r::RemoteConcept{C,T}, new_label_name::String) where end """ - delete(r::RemoteConcept{C,T}) where {C <: AbstractThingType,T <: AbstractCoreTransaction} + delete(r::RemoteConcept{<:AbstractThingType}) To delete a type in the database pack the type with the transaction to a RemoteConcept. Be aware that a type can only be deleted if no Entity, Attribute or Relation is in the database which is based on this type. """ -function delete(r::RemoteConcept{C,T}) where - {C <: AbstractThingType,T <: AbstractCoreTransaction} - +function delete(r::RemoteConcept{<:AbstractThingType}) del_req = TypeRequestBuilder.delete_req(r.concept.label) execute(r.transaction, del_req) end diff --git a/src/contribution/contribution.jl b/src/contribution/contribution.jl index 59ed4073..1bc3d418 100644 --- a/src/contribution/contribution.jl +++ b/src/contribution/contribution.jl @@ -7,11 +7,11 @@ const g = TypeDBClient export entity_set_owns function entity_set_owns(thing_type::Type{<:g.AbstractThingType}, - entity::String, - attribute_type::String, + entity::AbstractString, + attribute_type::AbstractString, transaction::g.AbstractCoreTransaction, is_key = false, - overriden::g.Optional{String} = nothing) + overriden::g.Optional{<:AbstractString} = nothing) cm = ConceptManager(transaction) loc_entity = nothing @@ -49,8 +49,8 @@ function entity_set_owns(thing_type::Type{<:g.AbstractThingType}, return nothing end - function entity_set_owns(entity::String, - attribute_type::String, + function entity_set_owns(entity::AbstractString, + attribute_type::AbstractString, transaction, is_key = false, overriden::g.Optional{String} = nothing) diff --git a/src/core/CoreClient.jl b/src/core/CoreClient.jl index b47f3d57..011f3c41 100644 --- a/src/core/CoreClient.jl +++ b/src/core/CoreClient.jl @@ -2,7 +2,7 @@ mutable struct CoreClient <: AbstractCoreClient channel::gRPCClient.gRPCChannel - address::String + address::AbstractString port::Int core_stub::Core_TypeDBStub databaseMgr::CoreDatabaseManager @@ -13,7 +13,7 @@ function Base.show(io::IO, core_client::CoreClient) print(io, "CoreClient(address: $(core_client.address):$(core_client.port))") end -function CoreClient(address::String, port::Int = 1729) +function CoreClient(address::AbstractString, port::Int = 1729) channel = gRPCChannel(address * ":" * string(port)) stub = Core_TypeDBStub(channel) databaseMgr = CoreDatabaseManager() diff --git a/src/core/CoreDatabaseManager.jl b/src/core/CoreDatabaseManager.jl index 550ba30d..7f76d9ec 100644 --- a/src/core/CoreDatabaseManager.jl +++ b/src/core/CoreDatabaseManager.jl @@ -4,7 +4,7 @@ mutable struct CoreDatabaseManager <: AbstractCoreDatabaseManager end -function get_database(client::AbstractCoreClient, name::String)::CoreDatabase +function get_database(client::AbstractCoreClient, name::AbstractString)::CoreDatabase isempty(name) && throw(TypeDBClientException(CLIENT_MISSING_DB_NAME)) if contains_database(client, name) return CoreDatabase(name) @@ -13,7 +13,7 @@ function get_database(client::AbstractCoreClient, name::String)::CoreDatabase end end -function contains_database(client::AbstractCoreClient, name::String) +function contains_database(client::AbstractCoreClient, name::AbstractString) isempty(name) && throw(TypeDBClientException(CLIENT_MISSING_DB_NAME)) db = DatabaseManagerRequestBuilder req_result, status = Proto.databases_contains(client.core_stub.blockingStub, gRPCController() , db.contains_req(name)) @@ -26,14 +26,21 @@ function get_all_databases(client::AbstractCoreClient)::Vector{CoreDatabase} return grpc_result_or_error(req_result, status, result -> [CoreDatabase(db_name) for db_name in result.names]) end -function create_database(client::AbstractCoreClient, name::String) +function create_database(client::AbstractCoreClient, name::AbstractString) isempty(name) && throw(TypeDBClientException(CLIENT_MISSING_DB_NAME)) db = DatabaseManagerRequestBuilder req_result, status = Proto.databases_create(client.core_stub.blockingStub, gRPCController(), db.create_req(name)) return grpc_result_or_error(req_result, status, result->true) end -function delete_database(client::AbstractCoreClient, name::String) + +""" + delete_database(client::AbstractCoreClient, name::AbstractString) + +Delete the database for the given name without any question. Be carful. There is no +recovery function within this call. +""" +function delete_database(client::AbstractCoreClient, name::AbstractString) database = get_database(client, name) db = DatabaseRequestBuilder req_result, status = Proto.database_delete(client.core_stub.blockingStub, gRPCController(), db.delete_req(database.name)) diff --git a/src/core/CoreSession.jl b/src/core/CoreSession.jl index 3bec6b2b..edb0e111 100644 --- a/src/core/CoreSession.jl +++ b/src/core/CoreSession.jl @@ -6,23 +6,25 @@ mutable struct CoreSession <: AbstractCoreSession client::CoreClient database::CoreDatabase sessionID::Bytes - transactions::Dict{UUID,T} where {T<:Union{Nothing,<:AbstractCoreTransaction}} + transactions::Dict{UUID,T} where {T<:Optional{<:AbstractCoreTransaction}} type::EnumType accessLock::ReentrantLock options::TypeDBOptions isOpen::Bool networkLatencyMillis::Int timer::Optional{Controller} - request_timeout::Real + request_timeout::Float64 + error_break_time::Float64 end -Base.show(io::IO, session::T) where {T<:AbstractCoreSession} = print(io, "Session(ID: $(bytes2hex(session.sessionID)))") +Base.show(io::IO, session::AbstractCoreSession) = print(io, "Session(ID: $(bytes2hex(session.sessionID)))") -function CoreSession(client::T, - database::String, +function CoreSession(client::AbstractCoreClient, + database::AbstractString, type::Int32, options::TypeDBOptions = TypeDBOptions(); - request_timout::Real=6) where {T<:AbstractCoreClient} + request_timeout::Float64=Inf, + error_time::Float64 = 5.0) try #building open_request open_req = SessionRequestBuilder.open_req( @@ -43,7 +45,18 @@ function CoreSession(client::T, t = Controller(true, 0.5) - result = CoreSession(client, database, session_id, transactions, type, ReentrantLock() ,options, is_open, networkLatencyMillis, t, request_timout) + result = CoreSession(client, + database, + session_id, + transactions, + type, + ReentrantLock(), + options, + is_open, + networkLatencyMillis, + t, + request_timeout, + error_time) # initialize the ongoing pulse request make_pulse_request(result, t) @@ -99,60 +112,76 @@ function make_pulse_request(session::AbstractCoreSession, controller::Controller end end -transaction(session::AbstractCoreSession, type::EnumType) = transaction(session, type, typedb_options_core()) -function transaction(session::AbstractCoreSession, type::EnumType, options::TypeDBOptions) - try - lock(session.accessLock) + +transaction(session::AbstractCoreSession, + type::EnumType; + error_break_time::Real = session.error_break_time) = + transaction(session, + type, + typedb_options_core(), + true, + error_break_time = error_break_time) + +transaction(session::AbstractCoreSession, + type::EnumType, + blocking::Bool) = transaction(session, + type, + typedb_options_core(), + blocking) + +function transaction(session::AbstractCoreSession, + type::EnumType, + options::TypeDBOptions, + blocking::Bool = true; + error_break_time::Real = session.error_break_time) + + lock(session.accessLock) do if !session.isOpen throw(TypeDBClientException(CLIENT_SESSION_CLOSED, bytes2hex(session.sessionID))) end - transactionRPC = CoreTransaction(session, session.sessionID, type, options) + transactionRPC = CoreTransaction(session, + session.sessionID, + type, + options, + use_blocking_stub = blocking, + error_break_time = error_break_time) + session.transactions[transactionRPC.transaction_id] = transactionRPC return transactionRPC - finally - unlock(session.accessLock) end end function close(session::AbstractCoreSession, session_alive::Bool=true) - try - lock(session.accessLock) - if session.isOpen - for (_,trans) in session.transactions - safe_close(trans) - end - remove_session(session.client, session) - safe_close(session.timer) - if session_alive - req = SessionRequestBuilder.close_req(session.sessionID) - stub = session.client.core_stub.blockingStub - Proto.session_close(stub, gRPCController(), req ) - end + lock(session.accessLock) do + if session.isOpen + for (_,trans) in session.transactions + safe_close(trans) + end + remove_session(session.client, session) + safe_close(session.timer) - session.isOpen = false - end - catch ex - if ex isa gRPCServiceCallException - @info "Session with id: $(session.sessionID) isn't open on the server" - else - @error TypeDBClientException("Unexpected error while closing session ID: $(session.sessionID)",ex) + if session_alive + req = SessionRequestBuilder.close_req(session.sessionID) + stub = session.client.core_stub.blockingStub + Proto.session_close(stub, gRPCController(), req ) + end + + session.isOpen = false + end end - finally - unlock(session.accessLock) - end + return true end function Base.delete!(session::AbstractCoreSession, trans_id::UUID) - try - lock(session.accessLock) - delete!(session.transactions, trans_id) - finally - unlock(session.accessLock) - end + + lock(session.accessLock) do + delete!(session.transactions, trans_id) + end + end function is_open(session::AbstractCoreSession) diff --git a/src/core/CoreTransaction.jl b/src/core/CoreTransaction.jl index c617ab6d..ab8231f3 100644 --- a/src/core/CoreTransaction.jl +++ b/src/core/CoreTransaction.jl @@ -6,8 +6,9 @@ struct CoreTransaction <: AbstractCoreTransaction bidirectional_stream::BidirectionalStream transaction_id::Optional{UUID} session_id::Bytes - request_timout::Real + request_timeout::Real session::AbstractCoreSession + error_break_time::Real end function Base.show(io::IO, transaction::AbstractCoreTransaction) @@ -20,26 +21,38 @@ function CoreTransaction(session::CoreSession , sessionId::Bytes, type::EnumType, options::TypeDBOptions; - request_timout::Real=session.request_timeout) + request_timeout::Real=session.request_timeout, + use_blocking_stub::Bool = true, + error_break_time::Real = session.error_break_time) + + function trans_return(res) + return res + end + type = type options = options - input_channel = Channel{Proto.Transaction_Client}(10) + input_channel = Channel{Proto.Transaction_Client}() proto_options = copy_to_proto(options, Proto.Options) - grpc_controller = gRPCController(request_timeout=request_timout) + grpc_controller = gRPCController(request_timeout = request_timeout) - req_result, status = Proto.transaction(session.client.core_stub.blockingStub, grpc_controller, input_channel) + if use_blocking_stub + req_result, status = Proto.transaction(session.client.core_stub.blockingStub, grpc_controller, input_channel) + else + res = Proto.transaction(session.client.core_stub.asyncStub, grpc_controller, input_channel, trans_return) + wait(res) + req_result, status = fetch(res) + end output_channel = grpc_result_or_error(req_result, status, result->result) - open_req = TransactionRequestBuilder.open_req(session.sessionID, type, proto_options,session.networkLatencyMillis) + open_req = TransactionRequestBuilder.open_req(session.sessionID, type, proto_options, session.networkLatencyMillis) - bidirectionalStream = BidirectionalStream(input_channel, output_channel, status) + bidirectionalStream = BidirectionalStream(input_channel, output_channel, status, error_break_time = error_break_time) trans_id = uuid4() - result = CoreTransaction(type, options, bidirectionalStream, trans_id, sessionId, request_timout, session) + result = CoreTransaction(type, options, bidirectionalStream, trans_id, sessionId, request_timeout, session, error_break_time) # The following is only for warming up Transaction. If we didn't do this # it could happen that a transaction reach a timeout. - req_result = execute(result, open_req, false) kind_of_result = Proto.which_oneof(req_result, :res) getproperty(req_result, kind_of_result) @@ -66,7 +79,7 @@ function query(transaction::T, request::R, batch::Bool) where {T<:AbstractCoreTr try result = single_request(transaction.bidirectional_stream, request, batch) catch ex - safe_close(transaction) + close(transaction) rethrow(ex) end @@ -80,7 +93,7 @@ function stream(transaction::T, request::R, batch::Bool = true) where {T<:Abstra try result = stream_request(transaction.bidirectional_stream, request, batch) catch ex - safe_close(transaction) + close(transaction) rethrow(ex) end diff --git a/src/logic/LogicManager.jl b/src/logic/LogicManager.jl index 2fc2fb37..4c8c3b3c 100644 --- a/src/logic/LogicManager.jl +++ b/src/logic/LogicManager.jl @@ -4,7 +4,12 @@ mutable struct LogicManager <: AbstractLogicManager transaction::AbstractCoreTransaction end -function get_rule(log_mgr::AbstractLogicManager, label::String) +""" + get_rule(log_mgr::AbstractLogicManager, label::AbstractString) + +The get_rule function will return the rule for the given label +""" +function get_rule(log_mgr::AbstractLogicManager, label::AbstractString) res = execute(log_mgr.transaction, LogicManagerRequestBuilder.get_rule_req(label)) result = if which_oneof(res.logic_manager_res.get_rule_res, :res) == :rule Rule(res.logic_manager_res.get_rule_res.rule) @@ -13,7 +18,11 @@ function get_rule(log_mgr::AbstractLogicManager, label::String) end return result end +""" + get_rules(log_mgr::AbstractLogicManager) +Here we get all rules in the schema exposed by the session. +""" function get_rules(log_mgr::AbstractLogicManager) dbResult = stream(log_mgr.transaction, LogicManagerRequestBuilder.get_rules_req()) answers = [res.logic_manager_res_part.get_rules_res_part.rules for res in dbResult] @@ -22,7 +31,13 @@ function get_rules(log_mgr::AbstractLogicManager) return result end -function put_rule(log_mgr::AbstractLogicManager, label::String, when::String, then::String) +""" + put_rule(log_mgr::AbstractLogicManager, label::AbstractString, when::AbstractString, then::AbstractString) + +The function gives the possibility to formulate a rule and put it in the database. The when +and then clauses will be written in TypeQL terms. +""" +function put_rule(log_mgr::AbstractLogicManager, label::AbstractString, when::AbstractString, then::AbstractString) res = execute(log_mgr.transaction, LogicManagerRequestBuilder.put_rule_req(label, when, then)) result = Rule(res.logic_manager_res.get_rule_res.rule) return result diff --git a/src/logic/Rule.jl b/src/logic/Rule.jl index 5e811f82..1a0f5411 100644 --- a/src/logic/Rule.jl +++ b/src/logic/Rule.jl @@ -53,7 +53,7 @@ is_remote(rule::Rule) = false is_remote(rule::RemoteRule) = true -function set_label(remote::RemoteRule, new_label::String) +function set_label(remote::RemoteRule, new_label::AbstractString) dbResult = execute(remote.rule.transaction, RuleRequestBuilder.rule_set_label_req(remote.label, new_label)) remote.rule.label = new_label return remote diff --git a/src/query/QueryManager.jl b/src/query/QueryManager.jl index 50d030bd..f3e6b979 100644 --- a/src/query/QueryManager.jl +++ b/src/query/QueryManager.jl @@ -23,7 +23,7 @@ function match_group_aggregate(transaction::AbstractCoreTransaction, query::Abst db_result = stream(transaction, QueryManagerRequestBuilder.match_group_aggregate_req(query, options)) isempty(db_result) && return [] - return reduce(vcat, [NumericGroup(item.match_group_aggregate_res_part.answers) for item in db_result]) + return reduce(vcat, [NumericGroup(item.query_manager_res_part.match_group_aggregate_res_part.answers) for item in db_result]) end function insert(transaction::AbstractCoreTransaction, query::AbstractString, options = Proto.Options()) @@ -72,7 +72,7 @@ function commit(transaction::AbstractCoreTransaction) safe_close(transaction) catch ex @info ex - return false + rethrow(ex) end return true diff --git a/src/standard/frontend.jl b/src/standard/frontend.jl index 60dcf688..fb08cc4e 100644 --- a/src/standard/frontend.jl +++ b/src/standard/frontend.jl @@ -53,4 +53,3 @@ function Base.write( ) readwrite(f, session, typedb.protocol.Transaction_Type.WRITE, options) end - diff --git a/src/standard/utils.jl b/src/standard/utils.jl index e1368994..07b068b8 100644 --- a/src/standard/utils.jl +++ b/src/standard/utils.jl @@ -20,7 +20,7 @@ Convert `x` to `Vector{UInt8}`. """ bytes(x::UUID) = collect(reinterpret(UInt8, [hton(x.value)])) -function bytes(s::String) +function bytes(s::AbstractString) chunks = (s[i:i+1] for i in 1:2:length(s)-1) # 2-char chunks return parse.(UInt8, chunks; base = 16) end @@ -62,3 +62,20 @@ function safe_close(source_to_close) reason: $ex" end end + +function safe_close(channel::Channel) + if isready(channel) + @info "There is something wrong with the channel management. \n + Here an example what's in it:" + last_item = fetch(channel) + @info last_item + func_id = which_oneof(last_item, :res) + res = getproperty(last_item, func_id) + @info "kind of item: $res" + end + close(channel) +end + +function Base.close(inp::Vector{Timer}) + close.(inp) +end diff --git a/src/stream/BidirectionalStream.jl b/src/stream/BidirectionalStream.jl index 5864be6e..68aeab31 100644 --- a/src/stream/BidirectionalStream.jl +++ b/src/stream/BidirectionalStream.jl @@ -7,16 +7,18 @@ mutable struct BidirectionalStream input_channel::Channel{Proto.Transaction_Client} output_channel::Channel{Proto.Transaction_Server} status::Task + error_break_time::Real end function BidirectionalStream(input_channel::Channel{Proto.Transaction_Client}, output_channel::Channel{Proto.Transaction_Server}, - status::Task) + status::Task; + error_break_time::Real) dispatcher = Dispatcher(input_channel) res_collector = ResponseCollector(output_channel) - return BidirectionalStream(res_collector, dispatcher, Threads.Atomic{Bool}(true),input_channel, output_channel, status) + return BidirectionalStream(res_collector, dispatcher, Threads.Atomic{Bool}(true),input_channel, output_channel, status, error_break_time) end function single_request(bidirect_stream::BidirectionalStream, request::Proto.ProtoType) @@ -30,7 +32,7 @@ function single_request(bidirect_stream::BidirectionalStream, request::T, batch: """ function single_request(bidirect_stream::BidirectionalStream, request::Proto.Transaction_Req, batch::Bool) answer = _process_request(bidirect_stream, request, batch) - return answer[1] + return isempty(answer) ? nothing : answer[1] end """ @@ -42,16 +44,17 @@ function stream_request(bidirect_stream::BidirectionalStream, request::Proto.Tra return answer end +# ToDo: Make the request timout determined by user at session level as a default and in the transaction level function _process_request(bidirect_stream::BidirectionalStream, request::Proto.Transaction_Req, batch::Bool) res_channel = _open_result_channel(bidirect_stream, request, batch) # start a task to collect the results asynchronusly - result_task = @async collect_result(res_channel, bidirect_stream) + result_task = Threads.@spawn collect_result(res_channel, bidirect_stream, request.req_id) # until solving the absent possibility to detect grpc errors in the gRPCClient a pure time # dependent solutionresult = nothing - answer = nothing - contr = Controller(true,5) + answer = Vector{Transaction_Res_All}() + contr = Controller(true, bidirect_stream.error_break_time) @async sleeper(contr) while contr.running yield() @@ -97,16 +100,14 @@ function collect_result(res_channel::Channel{T}) where {T<:ProtoProtoType} The function will be called for each single request. She works until the whole result set will be collected. """ -function collect_result(res_channel::Channel{Transaction_Res_All}, bidirect_stream::BidirectionalStream) +function collect_result(res_channel::Channel{Transaction_Res_All}, bidirect_stream::BidirectionalStream, request_id::Bytes) answers = Vector{Transaction_Res_All}() - while isopen(res_channel) - yield() - if isready(res_channel) - tmp_result = take!(res_channel) - req_push, loop_break = _is_stream_respart_done(tmp_result, bidirect_stream) - - req_push && push!(answers, tmp_result) - loop_break && break + for tmp_result in res_channel + req_push, loop_break = _is_stream_respart_done(tmp_result, bidirect_stream) + req_push && push!(answers, tmp_result) + if loop_break + delete!(bidirect_stream.resCollector, request_id) + break end end return answers @@ -152,10 +153,17 @@ end function close(stream::BidirectionalStream) - - safe_close(stream.input_channel) - safe_close(stream.output_channel) safe_close(stream.dispatcher) + task_to_close = @async begin + while true + yield() + isempty(stream.resCollector.collectors) && break + for (k,_) in stream.resCollector.collectors + delete!(stream.resCollector.collectors, k) + end + end + end + wait(task_to_close) safe_close(stream.resCollector) return true end diff --git a/src/stream/RequestTransmitter.jl b/src/stream/RequestTransmitter.jl index 2bdba512..1eaae370 100644 --- a/src/stream/RequestTransmitter.jl +++ b/src/stream/RequestTransmitter.jl @@ -3,19 +3,26 @@ const BATCH_WINDOW_SMALL_MILLIS = 1 const BATCH_WINDOW_LARGE_MILLIS = 3 +const DISPATCHER_THREADS = 3 + mutable struct Dispatcher input_channel::Channel{Proto.Transaction_Client} direct_dispatch_channel::Channel{Proto.ProtoType} dispatch_channel::Channel{Proto.ProtoType} - dispatch_timer::Optional{Timer} + dispatch_timer::Optional{Vector{Timer}} end function Dispatcher(input_channel::Channel{Proto.Transaction_Client}) direct_dispatch_channel = Channel{Proto.ProtoType}(10) dispatch_channel = Channel{Proto.ProtoType}(10) - disp_timer = batch_requests(dispatch_channel,input_channel) - process_direct_requests(direct_dispatch_channel, input_channel) + + disp_timer = Vector{Timer}() + for _ in 1:DISPATCHER_THREADS + push!(disp_timer, batch_requests(dispatch_channel,input_channel)) + end + + Threads.@spawn process_direct_requests(direct_dispatch_channel, input_channel) return Dispatcher(input_channel, direct_dispatch_channel, dispatch_channel,disp_timer) end @@ -25,24 +32,11 @@ function process_direct_requests(in_channel::Channel{Proto.ProtoType}, out_chann This function process the incoming request directly to the server """ function process_direct_requests(in_channel::Channel{Proto.ProtoType}, out_channel::Channel{Proto.Transaction_Client}) - @async begin - while isopen(in_channel) - yield() - # if the grpc connection shows an error or is terminated for the channel - # the loop will exited - try - if isready(in_channel) - tmp_res = take!(in_channel) - client_res = TransactionRequestBuilder.client_msg([tmp_res]) - Threads.@spawn put!(out_channel,client_res) - end - catch ex - @info "process_direct_requests shows an error" - finally - end - end - @debug "process_direct_requests was closed" + for tmp_res in in_channel + client_res = TransactionRequestBuilder.client_msg([tmp_res]) + put!(out_channel, client_res) end + @debug "process_direct_requests was closed" end """ @@ -65,7 +59,7 @@ function batch_requests(in_channel::Channel{Proto.ProtoType}, out_channel::Chann end end if length(answers) > 0 - put!(out_channel, TransactionRequestBuilder.client_msg(answers)) + @async put!(out_channel, TransactionRequestBuilder.client_msg(answers)) end catch ex throw(TypeDBClientException("batch_requests runner failure",ex)) diff --git a/src/stream/ResponseCollector.jl b/src/stream/ResponseCollector.jl index d14e0e76..4c220f89 100644 --- a/src/stream/ResponseCollector.jl +++ b/src/stream/ResponseCollector.jl @@ -11,7 +11,10 @@ function ResponseCollector(transact_result_channel::Channel{Proto.Transaction_Se collectors = Dict{Bytes,Channel{Transaction_Res_All}}() access_lock = ReentrantLock() resp_col = ResponseCollector(collectors, transact_result_channel, access_lock) - @async response_worker(resp_col) + for _ in 1:3 + Threads.@spawn response_worker(resp_col) + end + return resp_col end @@ -22,13 +25,12 @@ will be collected. Attention! Don't put a new Id manually on the ResponsCollector. It wouldn't be thread safe """ function Base.push!(resp_collector::ResponseCollector, req_id::Bytes) - res_channel = Channel{Transaction_Res_All}(10) - try - lock(resp_collector.access_lock) + res_channel = Channel{Transaction_Res_All}() + + lock(resp_collector.access_lock) do resp_collector.collectors[req_id] = res_channel - finally - unlock(resp_collector.access_lock) end + return res_channel end @@ -40,30 +42,19 @@ Attention! Don't remove a result_channel manually from the Dictionary. This will not be thread safe. """ function Base.delete!(resp_collector::ResponseCollector, id::Bytes) - try - lock(resp_collector.access_lock) + + lock(resp_collector.access_lock) do close(resp_collector.collectors[id]) delete!(resp_collector.collectors, id) - finally - unlock(resp_collector.access_lock) end end function response_worker(response_collector::ResponseCollector) resp_chan = response_collector.transact_result_channel collectors = response_collector.collectors - while isopen(resp_chan) - yield() - try - if isready(resp_chan) - req_result = take!(resp_chan) - tmp_result = _process_Transaction_Server(req_result) - put!(collectors[tmp_result.req_id], tmp_result) - end - catch ex - @info "response_worker shows an error \n - $ex" - end + for req_result in resp_chan + tmp_result = _process_Transaction_Server(req_result) + put!(collectors[tmp_result.req_id], tmp_result) end @debug "response_collector is Done" end diff --git a/test/behaviour/concept/type/attributetype/AttributeTypeSteps.jl b/test/behaviour/concept/type/attributetype/AttributeTypeSteps.jl index ef9a610f..0f3ab7ba 100644 --- a/test/behaviour/concept/type/attributetype/AttributeTypeSteps.jl +++ b/test/behaviour/concept/type/attributetype/AttributeTypeSteps.jl @@ -10,12 +10,21 @@ using Dates g = TypeDBClient # Utility functions -function _attribute_subtypes(context, attribute_label_name, value_type::g.EnumType, contain::Bool) +function _attribute_subtypes(context, attribute_label_name, value_type::g.EnumType, contain::Bool; debug::Bool= false) types_inp = [db[1] for db in context.datatable] result_bools = Bool[] attr = g.get(ConceptManager(context[:transaction]), AttributeType, attribute_label_name) sub_types = g.get_subtypes(g.as_remote(attr, context[:transaction])) + + # Print out subtypes if needed + if debug + @info "Subtypes:" + println.(sub_types) + @info "should be:" + println.(types_inp) + end + res = filter(x->g.proto_value_type(x) == value_type || g.proto_value_type(x) == VALUE_TYPE.OBJECT, sub_types) @@ -678,7 +687,7 @@ end # Scenario: Attribute type root can get attribute types of a specific value class @then("attribute(attribute) as(boolean) get subtypes contain:") do context - res = _attribute_subtypes(context, "attribute", VALUE_TYPE.BOOLEAN, true) + res = _attribute_subtypes(context, "attribute", VALUE_TYPE.BOOLEAN, true, debug = true) @expect length(context.datatable) == length(res) @expect all(res) end diff --git a/test/behaviour/concept/type/entitytype/EntityTypeSteps.jl b/test/behaviour/concept/type/entitytype/EntityTypeSteps.jl index 76b9f673..113e747b 100644 --- a/test/behaviour/concept/type/entitytype/EntityTypeSteps.jl +++ b/test/behaviour/concept/type/entitytype/EntityTypeSteps.jl @@ -830,7 +830,7 @@ end end @then("relation(marriage) get role(husband) get players do not contain:") do context - res = _get_players_contain("marriage","husband", context) + res = _get_players_contain("marriage","husband", context, should_contain = false) @expect all(res) === false end diff --git a/test/behaviour/concept/type/thingtype/ThingTypeSteps.jl b/test/behaviour/concept/type/thingtype/ThingTypeSteps.jl index 58da3436..239a3112 100644 --- a/test/behaviour/concept/type/thingtype/ThingTypeSteps.jl +++ b/test/behaviour/concept/type/thingtype/ThingTypeSteps.jl @@ -27,16 +27,29 @@ function _supertypes_contain(context, abstract_type::Type{<:g.AbstractThingType} return res_array end -function _supertypes_contain(context, ::Type{g.RoleType}, relation_name::String, role_name::String) +function _supertypes_contain(context, ::Type{g.RoleType}, + relation_name::String, + role_name::String; + debug::Bool = false) + db_roles = [_split_role(db[1])[1]=>_split_role(db[1])[2] for db in context.datatable] res = g.get(ConceptManager(context[:transaction]), RelationType, relation_name) role_play = g.relation_type_get_relates_for_role_label(g.as_remote(res, context[:transaction]), role_name) res_supertypes = g.get_supertypes(g.as_remote(role_play, context[:transaction])) + + isempty(res_supertypes) && println("Supertypes of $relation_name - $role_name aren't there") + res_array = Bool[] + + debug && @info "Supertypes:" + debug && println.(res_supertypes) + + debug && @info "Table should be there" for i in 1:length(db_roles) super_role = RoleType(g.Label(db_roles[i].first, db_roles[i].second), false) + debug && println(super_role) push!(res_array, in(super_role, res_supertypes)) end return res_array @@ -46,6 +59,9 @@ function _subtypes_contain(context, abstract_type::Type{<:g.AbstractThingType}, sub_types = [db[1] for db in context.datatable] attr = g.get(ConceptManager(context[:transaction]), abstract_type, attr_name) res_types = g.get_subtypes(g.as_remote(attr, context[:transaction])) + + isempty(res_types) && println("Subtypes of $attr_name isn't there") + res_array = Bool[] for i in 1:length(sub_types) sub_type = g.get(context[:cm], abstract_type, sub_types[i]) @@ -75,6 +91,9 @@ function _get_owns_contain(context, abstract_type::Type{<:g.AbstractThingType}, types_owns = g.get_owns(g.as_remote(attr, context[:transaction]), nothing, is_key) + + isempty(types_owns) && println("Owner $owner owns no attribute as it should be") + res_array = Bool[] for i in 1:length(key_types) key_type = g.get(ConceptManager(context[:transaction]), @@ -87,9 +106,12 @@ function _get_owns_contain(context, abstract_type::Type{<:g.AbstractThingType}, end -function _get_players_contain(relation_name::String, role_name::String, context) +function _get_players_contain(relation_name::String, role_name::String, context; should_contain::Bool = true) db = [db[1] for db in context.datatable] res = g.get_players(context[:transaction], g.Label(relation_name,role_name)) + + isempty(res) && should_contain && println("Relation $relation_name with Role $role_name haven't players") + res_array = Bool[] for i in 1:length(db) entity = g.get(ConceptManager(context[:transaction]), @@ -107,6 +129,9 @@ function _get_playing_roles_contain(player::String, player_type::Type{<:g.Abstra player) res_array = Bool[] play_roles = g.get_plays(g.as_remote(attr, context[:transaction])) + + isempty(play_roles) && println("played_roles of $player isn't there") + for i in 1:length(db) role = RoleType(g.Label(db[i].first, db[i].second), false) push!(res_array, in(role, play_roles)) diff --git a/test/behaviour/connection/database/DatabaseSteps.jl b/test/behaviour/connection/database/DatabaseSteps.jl index 623d5f34..61bdd1a9 100644 --- a/test/behaviour/connection/database/DatabaseSteps.jl +++ b/test/behaviour/connection/database/DatabaseSteps.jl @@ -77,25 +77,26 @@ end # Scenario: delete a database causes open sessions to fail @when("connection create database: typedb") do context g.create_database(context[:client], "typedb") + context[:db_name] = "typedb" end @when("connection open session for database: typedb") do context - context[:session] = g.CoreSession(context[:client], "typedb" , g.Proto.Session_Type.DATA, request_timout=Inf) + context[:session] = g.CoreSession(context[:client], context[:db_name] , g.Proto.Session_Type.DATA, request_timeout=Inf) end @when("connection delete database: typedb") do context - g.delete_database(context[:client], "typedb") + g.delete_database(context[:client], context[:db_name]) end @then("connection does not have database: typedb") do context - @expect g.contains_database(context[:client], "typedb") === false + @expect g.contains_database(context[:client], context[:db_name]) === false end @then("session open transaction of type; throws exception: write") do context try transaction(context[:session], g.Proto.Transaction_Type.WRITE) catch ex - @info "if a database isn't there a transaction can't be open" + @expect ex !== nothing end end @@ -104,8 +105,7 @@ end try g.define(context[:transaction], define_string) catch ex - # @expect occursin("transaction has been closed", ex.message) - @info ex + @expect ex !== nothing end end diff --git a/test/behaviour/connection/session/SessionSteps.jl b/test/behaviour/connection/session/SessionSteps.jl index f2520633..461ab481 100644 --- a/test/behaviour/connection/session/SessionSteps.jl +++ b/test/behaviour/connection/session/SessionSteps.jl @@ -9,14 +9,14 @@ end end @then("session has database: typedb") do context - @expect context[:session].database.name == "typedb" + @expect context[:session].database.name == context[:db_name] end @when("connection open sessions for databases:") do context dbnames = [item[1] for item in context.datatable] sessions = g.CoreSession[] for name in dbnames - push!(sessions, g.CoreSession(context[:client], name, g.Proto.Session_Type.DATA, request_timout=Inf)) + push!(sessions, g.CoreSession(context[:client], name, g.Proto.Session_Type.DATA, request_timeout=Inf)) end context[:sessions] = sessions @expect length(dbnames) == length(sessions) @@ -43,7 +43,7 @@ end sessions = g.CoreSession[] lock_add = ReentrantLock() @sync @async for db in dbnames - sess = g.CoreSession(context[:client], db, g.Proto.Session_Type.DATA, request_timout=Inf) + sess = g.CoreSession(context[:client], db, g.Proto.Session_Type.DATA, request_timeout=Inf) try lock(lock_add) push!(sessions, sess) diff --git a/test/behaviour/connection/transaction/TransactionSteps.jl b/test/behaviour/connection/transaction/TransactionSteps.jl index d5107b26..d7f77b81 100644 --- a/test/behaviour/connection/transaction/TransactionSteps.jl +++ b/test/behaviour/connection/transaction/TransactionSteps.jl @@ -5,24 +5,43 @@ # end g = TypeDBClient -@when("session opens transaction of type: read") do context - transaction = g.transaction(context[:session], trans_read) - @expect transaction !== nothing - context[:transaction] = transaction - context[:cm] = ConceptManager(context[:transaction]) -end +function transaction_read_write(context; write = false) -@when("session opens transaction of type: write") do context + if write + read_write = g.Proto.Transaction_Type.WRITE + else + read_write = g.Proto.Transaction_Type.READ + end + + if haskey(context, :transaction) && context[:transaction] !== nothing + g.close(context[:transaction]) + context[:transaction] = nothing + end - if haskey(context, :transaction) - context[:transaction] !== nothing && g.close(context[:transaction]) + if context[:session].type == g.Proto.Session_Type.SCHEMA + close(context[:session]) + context[:session] = nothing + context[:session] = g.CoreSession(context[:client], context[:db_name], + g.Proto.Session_Type.SCHEMA, + request_timeout = Inf) end - transaction = g.transaction(context[:session], g.Proto.Transaction_Type.WRITE) + transaction = g.transaction(context[:session], read_write , error_break_time = 6) @expect transaction !== nothing context[:transaction] = transaction # only a convinience method to prevent paperwork context[:cm] = ConceptManager(context[:transaction]) + + return nothing +end + +@when("session opens transaction of type: read") do context + transaction_read_write(context, write = false) +end + +# When session opens transaction of type: write +@when("session opens transaction of type: write") do context + transaction_read_write(context, write = true) end @then("session transaction is null: false") do context @@ -181,7 +200,7 @@ end @given("connection open sessions for database:") do context dbs = [row[1] for row in context.datatable] for db in dbs - g.CoreSession(context[:client], db , g.Proto.Session_Type.DATA, request_timout=Inf) + g.CoreSession(context[:client], db , g.Proto.Session_Type.DATA, request_timeout=Inf) end count_result = length(context[:client].sessions) == length(dbs) @expect count_result diff --git a/test/behaviour/features/concept/thing/attribute.feature b/test/behaviour/features/concept/thing/attribute.feature index 501fc0d0..8f0bd53f 100644 --- a/test/behaviour/features/concept/thing/attribute.feature +++ b/test/behaviour/features/concept/thing/attribute.feature @@ -16,7 +16,7 @@ # #noinspection CucumberUndefinedStep - +@attribute Feature: Concept Attribute Background: Given connection has been opened diff --git a/test/behaviour/features/concept/thing/entity.feature b/test/behaviour/features/concept/thing/entity.feature index 47b979f5..6073caae 100644 --- a/test/behaviour/features/concept/thing/entity.feature +++ b/test/behaviour/features/concept/thing/entity.feature @@ -16,6 +16,7 @@ # #noinspection CucumberUndefinedStep +@entity Feature: Concept Entity Background: diff --git a/test/behaviour/features/concept/thing/relation.feature b/test/behaviour/features/concept/thing/relation.feature index c14dc43e..2fc31626 100644 --- a/test/behaviour/features/concept/thing/relation.feature +++ b/test/behaviour/features/concept/thing/relation.feature @@ -16,6 +16,7 @@ # #noinspection CucumberUndefinedStep +@relation Feature: Concept Relation Background: diff --git a/test/behaviour/features/concept/type/attributetype.feature b/test/behaviour/features/concept/type/attributetype.feature index 55103b7c..481c975c 100644 --- a/test/behaviour/features/concept/type/attributetype.feature +++ b/test/behaviour/features/concept/type/attributetype.feature @@ -16,6 +16,7 @@ # #noinspection CucumberUndefinedStep +@attribute_type Feature: Concept Attribute Type Background: diff --git a/test/behaviour/features/concept/type/entitytype.feature b/test/behaviour/features/concept/type/entitytype.feature index 620d44d2..bf09daed 100644 --- a/test/behaviour/features/concept/type/entitytype.feature +++ b/test/behaviour/features/concept/type/entitytype.feature @@ -16,6 +16,7 @@ # #noinspection CucumberUndefinedStep +@entity_type @actual Feature: Concept Entity Type Background: diff --git a/test/behaviour/features/concept/type/relationtype.feature b/test/behaviour/features/concept/type/relationtype.feature index 089d1691..ef402ef3 100644 --- a/test/behaviour/features/concept/type/relationtype.feature +++ b/test/behaviour/features/concept/type/relationtype.feature @@ -16,7 +16,7 @@ # #noinspection CucumberUndefinedStep -@actual +@relation_type Feature: Concept Relation Type and Role Type Background: @@ -141,8 +141,6 @@ Feature: Concept Relation Type and Role Type Then relation(marriage) unset related role: husband Then transaction commits - - Scenario: Relation and role types can change labels When put relation type: parentship When relation(parentship) set relates role: parent @@ -182,8 +180,6 @@ Feature: Concept Relation Type and Role Type Then relation(employment) get role(employee) get label: employee Then relation(employment) get role(employer) get label: employer - - Scenario: Relation and role types can be set to abstract When put relation type: marriage When relation(marriage) set relates role: husband @@ -234,7 +230,7 @@ Feature: Concept Relation Type and Role Type When put relation type: connection When relation(connection) set abstract: true Then transaction commits - +@failure Scenario: Relation and role types can be subtypes of other relation and role types When put relation type: parentship When relation(parentship) set relates role: parent @@ -772,7 +768,6 @@ Feature: Concept Relation Type and Role Type | parttime-hours | - Scenario: Relation types can override inherited keys and attributes When put attribute type: employment-reference, with value type: string When attribute(employment-reference) set abstract: true diff --git a/test/behaviour/features/concept/type/thingtype.feature b/test/behaviour/features/concept/type/thingtype.feature index 37fc6000..320466ff 100644 --- a/test/behaviour/features/concept/type/thingtype.feature +++ b/test/behaviour/features/concept/type/thingtype.feature @@ -16,6 +16,7 @@ # #noinspection CucumberUndefinedStep +@thing_type @failure Feature: Concept Thing Type Background: diff --git a/test/behaviour/features/connection/database.feature b/test/behaviour/features/connection/database.feature index 828bb0f5..7e79da15 100644 --- a/test/behaviour/features/connection/database.feature +++ b/test/behaviour/features/connection/database.feature @@ -16,6 +16,7 @@ # #noinspection CucumberUndefinedStep +@database Feature: Connection Database Background: diff --git a/test/behaviour/features/connection/session.feature b/test/behaviour/features/connection/session.feature index 248db756..dcd806c4 100644 --- a/test/behaviour/features/connection/session.feature +++ b/test/behaviour/features/connection/session.feature @@ -16,6 +16,7 @@ # #noinspection CucumberUndefinedStep +@session Feature: Connection Session Background: diff --git a/test/behaviour/features/connection/transaction.feature b/test/behaviour/features/connection/transaction.feature index 0c38c6ab..6beef6df 100644 --- a/test/behaviour/features/connection/transaction.feature +++ b/test/behaviour/features/connection/transaction.feature @@ -16,6 +16,7 @@ # #noinspection CucumberUndefinedStep +@transaction Feature: Connection Transaction Background: diff --git a/test/behaviour/features/steps/steps.jl b/test/behaviour/features/steps/steps.jl index 0c09ea7e..e492422d 100644 --- a/test/behaviour/features/steps/steps.jl +++ b/test/behaviour/features/steps/steps.jl @@ -1,25 +1,18 @@ @given("connection open schema session for database: typedb") do context - typedb_session = TypeDBClient.CoreSession(client, "typedb" , TypeDBClient.typedb.protocol.Session_Type[:SCHEMA] , TypeDBClient.TypeDBOptions(), request_timout = Inf) + typedb_session = TypeDBClient.CoreSession(client, "typedb" , g.Proto.Session_Type.SCHEMA , request_timeout = Inf) context[:session] = typedb_session - # Menat to proof open sessions. During tests it shows sometimes that sessions wasn't closed properly - haskey(context, :sessions) ? push!(context[:sessions], typedb_session) : context[:sessions] = [typedb_session] + @expect context[:session] !== nothing end @given("connection open data session for database: typedb") do context - sess = g.CoreSession(context[:client], "typedb", g.Proto.Session_Type.DATA, request_timout=Inf) + sess = g.CoreSession(context[:client], context[:db_name], g.Proto.Session_Type.DATA, request_timeout=Inf) context[:session] = sess - # Menat to proof open sessions. During tests it shows sometimes that sessions wasn't closed properly - haskey(context, :sessions) ? push!(context[:sessions], sess) : context[:sessions] = [sess] @expect context[:session] !== nothing end @given("transaction commits") do context if g.is_open(context[:session]) === true g.is_open(context[:transaction]) && g.commit(context[:transaction]) - for (_,transaction) in context[:session].transactions - all([context[:transaction].transaction_id != transaction.transaction_id, - g.is_open(transaction)]) && g.commit(transaction) - end end end @@ -28,13 +21,30 @@ end g.safe_close.(collect(values(context[:client].sessions))) end +@beforescenario() do context, scenario + client = g.CoreClient("127.0.0.1",1729) + delete_all_databases(client) +end + @afterscenario() do context, scenario + if haskey(context, :session) + close(context[:session]) + context[:session] = nothing + end + + if haskey(context, :transaction) + context[:transaction] = nothing + end + delete_all_databases(context[:client]) + close(context[:client]) + context[:client] = nothing end @afterall() do client = g.CoreClient("127.0.0.1",1729) delete_all_databases(client) + close(client) end @beforeall() do diff --git a/test/notes.jl b/test/notes.jl index 501665da..8560041f 100644 --- a/test/notes.jl +++ b/test/notes.jl @@ -2,8 +2,7 @@ using TypeDBClient g = TypeDBClient client = g.CoreClient("127.0.0.1",1729) -# g.create_database(client, "typedb") -sess = g.CoreSession(client, "typedb", g.Proto.Session_Type.SCHEMA, request_timout = Inf) +sess = g.CoreSession(client, context[:db_name], g.Proto.Session_Type.SCHEMA, request_timeout = Inf) trans = g.transaction(sess, g.Proto.Transaction_Type.WRITE) g.put(g.ConceptManager(trans), AttributeType, "is-alive", VALUE_TYPE.BOOLEAN ) diff --git a/test/runner.jl b/test/runner.jl index 8af7eff3..c203a8c6 100644 --- a/test/runner.jl +++ b/test/runner.jl @@ -1,3 +1,8 @@ +using Pkg +cd(@__DIR__) +cd("..") +Pkg.activate(".") + using Base: runtests using Behavior @@ -14,17 +19,16 @@ configpath = joinpath(@__DIR__,"behaviour/config/ConfigEnvironment.jl") p = ParseOptions(allow_any_step_order = true) -# runspec(rootpath; featurepath = featurepath, stepspath = stepspath, parseoptions=p, execenvpath = configpath, tags="not @ignore-typedb-core") - function run_tests(tag::String = "") runspec(rootpath; featurepath = featurepath, stepspath = stepspath, parseoptions=p, execenvpath = configpath, tags=tag) end +results = run_tests("not @ignore-typedb-core") +# results = run_tests("@failure") +# results = run_tests("@actual") -result = run_tests("not @ignore-typedb-core") - -if !result - throw("TestSuite failed. Please proof the results") +if !all(values(results)) + throw("TestSuite failed. Please review the results") else - @info "Well done!" + @info "All tests passed. Well done! 😄 " end