diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 992a6a0a..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.github/workflows/.env b/.github/workflows/.env index 5ded5a76..e69de29b 100644 --- a/.github/workflows/.env +++ b/.github/workflows/.env @@ -1,3 +0,0 @@ -ENV["PYTHON"] = "${{ env.pythonLocation }}" >> $GITHUB_ENV -ENV["PYCALL_JL_RUNTIME_PYTHONHOME"] = "${{ env.pythonLocation }}" >> $GITHUB_ENV -ENV["PYCALL_JL_RUNTIME"] = "${{ env.pythonLocation }}" >> $GITHUB_ENV \ No newline at end of file diff --git a/.github/workflows/grakn-bdd.yml b/.github/workflows/grakn-bdd.yml new file mode 100644 index 00000000..2da211a5 --- /dev/null +++ b/.github/workflows/grakn-bdd.yml @@ -0,0 +1,16 @@ +name: Grakn BDD runner +on: [push] + +jobs: + hello_world_job: + runs-on: ubuntu-latest + name: A job to pull feature files, install Grakn, and execute the tests + steps: + - uses: actions/checkout@v2 + - id: foo + uses: Humans-of-Julia/GraknRunner@0.1.2 + with: + who-to-greet: 'Mark Schulze' + - run: echo random-number ${{ steps.foo.outputs.random-number }} + shell: bash + diff --git a/.gitignore b/.gitignore index ca97352b..50c13c31 100644 --- a/.gitignore +++ b/.gitignore @@ -25,9 +25,11 @@ docs/site/ # ignore local user specific files .git .vscode -# Manifest.toml -# test/Manifest.toml -# docs/Manifest.toml +Manifest.toml +test/Manifest.toml +docs/Manifest.toml +.DS_Store +src/.DS_Store # ignore julia internal git files in the dev folder _git2_* @@ -37,3 +39,5 @@ src/generated/protoc/ src/generated/protobuf/ protocol client-python + +test/graql_defines/ diff --git a/Manifest.toml b/Manifest.toml deleted file mode 100644 index b6a75171..00000000 --- a/Manifest.toml +++ /dev/null @@ -1,239 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -[[ArgTools]] -uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" - -[[Artifacts]] -uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" - -[[Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[CodeTracking]] -deps = ["InteractiveUtils", "UUIDs"] -git-tree-sha1 = "8ad457cfeb0bca98732c97958ef81000a543e73e" -uuid = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" -version = "1.0.5" - -[[Compat]] -deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] -git-tree-sha1 = "919c7f3151e79ff196add81d7f4e45d91bbf420b" -uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "3.25.0" - -[[DataStructures]] -deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "4437b64df1e0adccc3e5d1adbc3ac741095e4677" -uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.9" - -[[Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" - -[[DelimitedFiles]] -deps = ["Mmap"] -uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" - -[[Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" - -[[Downloads]] -deps = ["ArgTools", "LibCURL", "NetworkOptions"] -uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" - -[[FileWatching]] -uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" - -[[HPack]] -git-tree-sha1 = "2d0879ccdda8938cf70f92e1e1097ffba33ed639" -repo-rev = "master" -repo-url = "https://github.com/tanmaykm/HPack.jl" -uuid = "28024e5f-9f70-4280-80a2-4be20479eed3" -version = "0.3.0" - -[[HTTP2]] -deps = ["HPack", "MbedTLS"] -git-tree-sha1 = "05b7259ad9964d3d52669ce300fda62e4d36a921" -repo-rev = "master" -repo-url = "https://github.com/tanmaykm/HTTP2.jl" -uuid = "0ee529b6-85a9-4020-94aa-d5b2735f286b" -version = "0.3.0" - -[[InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "81690084b6198a2e1da36fcfda16eeca9f9f24e4" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.1" - -[[JuliaInterpreter]] -deps = ["CodeTracking", "InteractiveUtils", "Random", "UUIDs"] -git-tree-sha1 = "86439cef50a24fa981583476f48b197b7dea691e" -uuid = "aa1ae85d-cabe-5617-a682-6adf51b2e16a" -version = "0.8.9" - -[[LibCURL]] -deps = ["LibCURL_jll", "MozillaCACerts_jll"] -uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" - -[[LibCURL_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] -uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" - -[[LibGit2]] -deps = ["Base64", "NetworkOptions", "Printf", "SHA"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" - -[[LibSSH2_jll]] -deps = ["Artifacts", "Libdl", "MbedTLS_jll"] -uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" - -[[Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" - -[[LinearAlgebra]] -deps = ["Libdl"] -uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" - -[[Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[LoweredCodeUtils]] -deps = ["JuliaInterpreter"] -git-tree-sha1 = "8c96709706ce27471655247ad9a931447d16dd62" -uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b" -version = "1.2.9" - -[[Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[MbedTLS]] -deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] -git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe" -uuid = "739be429-bea8-5141-9913-cc70e7f3736d" -version = "1.0.3" - -[[MbedTLS_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" - -[[Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" - -[[MozillaCACerts_jll]] -uuid = "14a3606d-f60d-562e-9121-12d972cd8159" - -[[NetworkOptions]] -uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" - -[[OrderedCollections]] -git-tree-sha1 = "4fa2ba51070ec13fcc7517db714445b4ab986bdf" -uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.4.0" - -[[Parsers]] -deps = ["Dates"] -git-tree-sha1 = "223a825cccef2228f3fdbf2ecc7ca93363059073" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "1.0.16" - -[[Pkg]] -deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs"] -uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" - -[[Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" - -[[ProtoBuf]] -deps = ["Compat", "Logging"] -git-tree-sha1 = "9ecf92287404ebe5666a1c0488c3aaf90bbb5ff4" -uuid = "3349acd9-ac6a-5e09-bcdb-63829b23a429" -version = "0.10.0" - -[[REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[Random]] -deps = ["Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[Requires]] -deps = ["UUIDs"] -git-tree-sha1 = "cfbac6c1ed70c002ec6361e7fd334f02820d6419" -uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.1.2" - -[[Revise]] -deps = ["CodeTracking", "Distributed", "FileWatching", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "Pkg", "REPL", "Requires", "UUIDs", "Unicode"] -git-tree-sha1 = "b72fa706920b1421d581525de9f4e442b95ba254" -uuid = "295af30f-e4ad-537b-8983-00126c2a3abe" -version = "3.1.14" - -[[SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" - -[[Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[SharedArrays]] -deps = ["Distributed", "Mmap", "Random", "Serialization"] -uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" - -[[Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[SparseArrays]] -deps = ["LinearAlgebra", "Random"] -uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - -[[Statistics]] -deps = ["LinearAlgebra", "SparseArrays"] -uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" - -[[TOML]] -deps = ["Dates"] -uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" - -[[Tar]] -deps = ["ArgTools", "SHA"] -uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" - -[[Test]] -deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" - -[[Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" - -[[VersionParsing]] -git-tree-sha1 = "80229be1f670524750d905f8fc8148e5a8c4537f" -uuid = "81def892-9a0e-5fdd-b105-ffc91e053289" -version = "1.2.0" - -[[Zlib_jll]] -deps = ["Libdl"] -uuid = "83775a58-1f1d-513f-b197-d71354ab007a" - -[[gRPC]] -deps = ["HTTP2", "ProtoBuf", "Sockets"] -git-tree-sha1 = "a402360d2e7713e308a8bb8c7351f18f4114f0eb" -repo-rev = "master" -repo-url = "https://github.com/tanmaykm/gRPC.jl" -uuid = "afc8a647-7d08-4745-b7bc-49733df17e1a" -version = "0.1.0" - -[[nghttp2_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" diff --git a/Project.toml b/Project.toml index 6e43ebf4..3efdad5c 100644 --- a/Project.toml +++ b/Project.toml @@ -5,11 +5,13 @@ version = "0.1.0" [deps] DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" HPack = "28024e5f-9f70-4280-80a2-4be20479eed3" HTTP2 = "0ee529b6-85a9-4020-94aa-d5b2735f286b" ProtoBuf = "3349acd9-ac6a-5e09-bcdb-63829b23a429" Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Sockets = "6462fe0b-24de-5631-8697-dd941f90decc" +UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" gRPC = "afc8a647-7d08-4745-b7bc-49733df17e1a" [compat] diff --git a/docs/Manifest.toml b/docs/Manifest.toml deleted file mode 100644 index 2507db7e..00000000 --- a/docs/Manifest.toml +++ /dev/null @@ -1,106 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -[[Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" - -[[Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" - -[[DocStringExtensions]] -deps = ["LibGit2", "Markdown", "Pkg", "Test"] -git-tree-sha1 = "50ddf44c53698f5e784bbebb3f4b21c5807401b1" -uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.3" - -[[Documenter]] -deps = ["Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "a4875e0763112d6d017126f3944f4133abb342ae" -uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.25.5" - -[[GraknClient]] -git-tree-sha1 = "a2d3a02c9a42ef0d3b94a0ce031da9811aeb3ba6" -repo-rev = "main" -repo-url = "https://github.com/Humans-of-Julia/GraknClient.jl" -uuid = "7ffdda62-db04-4838-9798-febd00f3125c" -version = "0.1.0" - -[[IOCapture]] -deps = ["Logging"] -git-tree-sha1 = "377252859f740c217b936cebcd918a44f9b53b59" -uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" -version = "0.1.1" - -[[InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "81690084b6198a2e1da36fcfda16eeca9f9f24e4" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.1" - -[[LibGit2]] -deps = ["Printf"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" - -[[Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" - -[[Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" - -[[Parsers]] -deps = ["Dates"] -git-tree-sha1 = "50c9a9ed8c714945e01cd53a21007ed3865ed714" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "1.0.15" - -[[Pkg]] -deps = ["Dates", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"] -uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" - -[[Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" - -[[REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[Random]] -deps = ["Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" - -[[Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[Test]] -deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" - -[[Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" diff --git a/src/.DS_Store b/src/.DS_Store deleted file mode 100644 index 780cb5c2..00000000 Binary files a/src/.DS_Store and /dev/null differ diff --git a/src/GraknClient.jl b/src/GraknClient.jl index 1705cbd9..923725a7 100644 --- a/src/GraknClient.jl +++ b/src/GraknClient.jl @@ -13,10 +13,9 @@ then install the packages from GitHub module GraknClient # following this example here: https://github.com/tanmaykm/DexClient.jl/blob/master/src/DexClient.jl -using gRPC -using Sockets +using gRPC, Sockets, UUIDs, Dates -import Base: show, close +import Base: show, close, == ###### abstract types ################## # # @@ -26,6 +25,8 @@ abstract type AbstractTransaction end abstract type AbstractConceptManager end abstract type AbstractLogicManager end abstract type AbstractQueryManager end +abstract type AbstractConcept end +abstract type AbstractThing <: AbstractConcept end ###### inlcudes ######################## # # @@ -39,10 +40,11 @@ include(joinpath(@__DIR__,"rpc","database_manager.jl")) include(joinpath(@__DIR__,"client.jl")) include(joinpath(@__DIR__,"concept","ConceptManager.jl")) include(joinpath(@__DIR__,"query","query_manager.jl")) +include(joinpath(@__DIR__,"logic","logic_manager.jl")) include(joinpath(@__DIR__,"rpc","session.jl")) include(joinpath(@__DIR__,"rpc","transaction.jl")) -export GraknBlockingClient, GraknClientException, Session +export GraknBlockingClient, GraknClientException, Session, Transaction end #module diff --git a/src/GraknOptions.jl b/src/GraknOptions.jl index 156c1a95..171e8bfd 100644 --- a/src/GraknOptions.jl +++ b/src/GraknOptions.jl @@ -8,6 +8,7 @@ mutable struct GraknOptions <: AbstractGraknOptions trace_inference::Union{Bool,Nothing} explain::Union{Bool,Nothing} batch_size::Union{Int,Nothing} + session_idle_timeout_millis::Union{Int,Nothing} end mutable struct GraknClusterOptions <: AbstractGraknClusterOptions @@ -15,17 +16,22 @@ mutable struct GraknClusterOptions <: AbstractGraknClusterOptions trace_inference::Union{Bool,Nothing} explain::Union{Bool,Nothing} batch_size::Union{Int,Nothing} + session_idle_timeout_millis::Union{Int,Nothing} read_any_replica::Union{Bool,Nothing} end -function grakn_options_init(graknoption::Type{T},infer=nothing,trace_inference=nothing ,explain=nothing,batch_size=nothing,read_any_replica=nothing) where {T<:AbstractGraknOptions} - result = graknoption(infer,trace_inference,explain,batch_size) - isdefined(result, :read_any_replica) ? result.read_any_replica = read_any_replica : nothing +function grakn_options_init(graknoption::Type{T},infer=nothing,trace_inference=nothing ,explain=nothing,batch_size=nothing,read_any_replica=nothing,session_idle_timeout_millis=0) where {T<:AbstractGraknOptions} + if graknoption == GraknOptions + result = graknoption(infer,trace_inference,explain,batch_size,session_idle_timeout_millis) + else + result = graknoption(infer,trace_inference,explain,batch_size,session_idle_timeout_millis, read_any_replica) + end result end GraknOptions() = grakn_options_init(GraknOptions) +GraknOptions(session_idle_timeout_millis::Int) = grakn_options_init(GraknOptions,nothing,nothing ,nothing,nothing,nothing,session_idle_timeout_millis) GraknClusterOptions() = grakn_options_init(GraknClusterOptions) function core() @@ -42,4 +48,16 @@ end function is_cluster(m::GraknClusterOptions) true +end + +############ Helper functions ########## + +function copyFrom(fromOption::R, toOption::Type{T}) where {T<:grakn.protocol.Options} where {R<:AbstractGraknOptions} + result_option = toOption() + for fname in fieldnames(typeof(fromOption)) + if !hasproperty(result_option, Symbol(fname)) && getfield(fromOption,Symbol(fname)) !== nothing + setproperty!(result_option,Symbol(fname),getfield(fromOption,Symbol(fname))) + end + end + result_option end \ No newline at end of file diff --git a/src/client.jl b/src/client.jl index 2ee149ad..2ceb7023 100644 --- a/src/client.jl +++ b/src/client.jl @@ -1,7 +1,5 @@ # This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE -using .grakn.protocol - const DEFAULT_GRAKN_GRPC_PORT = 1729 struct GraknBlockingClient diff --git a/src/concept/Concept.jl b/src/concept/Concept.jl index d34175e9..9d2213ba 100644 --- a/src/concept/Concept.jl +++ b/src/concept/Concept.jl @@ -1 +1,34 @@ -# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE \ No newline at end of file +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + +struct Concept <:AbstractConcept +end + +is_type(m::Concept) = false +is_thing_type(m::Concept)= false +is_entity_type(m::Concept)= false +is_attribute_type(m::Concept) = false +is_relation_type(m::Concept)= false +is_role_type(m::Concept)= false +is_thing(m::Concept)= false +is_entity(m::Concept)= false +is_attribute(m::Concept)= false +is_relation(m::Concept)= false +is_remote(m::Concept)= false + + +struct RemoteConcept <:AbstractConcept +end + +is_remote(m::RemoteConcept)= true +delete(m::RemoteConcept)= nothing +is_deleted(m::RemoteConcept)= false +is_type(m::RemoteConcept)= false +is_thing_type(m::RemoteConcept)= false +is_entity_type(m::RemoteConcept)= false +is_attribute_type(m::RemoteConcept)= false +is_relation_type(m::RemoteConcept)= false +is_role_type(m::RemoteConcept)= false +is_thing(m::RemoteConcept)= false +is_entity(m::RemoteConcept)= false +is_attribute(m::RemoteConcept)= false +is_relation(m::RemoteConcept)= false diff --git a/src/concept/ConceptManager.jl b/src/concept/ConceptManager.jl index b21a126c..8dd4ade6 100644 --- a/src/concept/ConceptManager.jl +++ b/src/concept/ConceptManager.jl @@ -1,10 +1,13 @@ # This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE -mutable struct ConceptManager +include(joinpath(@__DIR__,"Concept.jl")) + +mutable struct ConceptManager <:AbstractConceptManager _transaction::Union{T,Nothing} where {T<:AbstractTransaction} end ConceptManager() = ConceptManager(nothing) + # def get_root_thing_type(self): # return self.get_thing_type("thing") diff --git a/src/concept/answer/Answer.jl b/src/concept/answer/Answer.jl index d34175e9..e07c4282 100644 --- a/src/concept/answer/Answer.jl +++ b/src/concept/answer/Answer.jl @@ -1 +1,2 @@ -# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE \ No newline at end of file +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + diff --git a/src/concept/answer/concept_map.jl b/src/concept/answer/concept_map.jl index d34175e9..aade9356 100644 --- a/src/concept/answer/concept_map.jl +++ b/src/concept/answer/concept_map.jl @@ -1 +1,70 @@ -# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE \ No newline at end of file +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + +# from typing import Mapping + +# import grakn_protocol.protobuf.answer_pb2 as answer_proto + +# from grakn.common.exception import GraknClientException +# from grakn.concept.proto import concept_proto_reader +# from grakn.concept.concept import Concept + +import Base.== + +mutable struct ConceptMap + _map::Dict{String,Concept} +end + +_THING = "thing" + +function ConceptMap(mapping::Dict{String,Concept}) + ConceptMap(mapping) +end + +function ConceptMap() + ConceptMap(Dict{String,Concept}()) +end + +function map(conc_map::ConceptMap) + conc_map._map +end + +function concepts(conc_map::ConceptMap) + values(conc_map._map) +end + +function get(conc_map::ConceptMap, variable::String) + !haskey(conc_map._map, variable) && throw(GraknClientException("The variable " * variable * " does not exist.")) + conc_map._map[variable] +end + +function Base.print(iO::IO, conc_map::ConceptMap) + # return "".join(map(lambda var: "[" + var + "/" + str(self._map[var]) + "]", sorted(self._map.keys()))) + str = join(["[$x / $(conc_map._map[x])]" for x in keys(conc_map._map)],"\n","\n") + Base.print(iO,str) +end + +Base.show(io::IO, conc_map::ConceptMap) = Base.print(io,conc_map) + +function Base.==(conc_map_one::ConceptMap, conc_map_two::ConceptMap) + if conc_map_one === conc_map_two + return true + end + conc_map_one._map == conc_map_two._map +end + +function hash(conc_map::ConceptMap) + hash(conc_map._map) +end + + +function _of(concept_map_proto::grakn.protocol.ConceptMap) + variable_map = Dict{String,Concept}() + throw(GraknClientException("concept_proto_reader is not implemented yet")) + for res_var in concept_map_proto.map + # TODO: implement the concept_proto_reader + concept = concept_proto_reader.concept (concept_map_proto.map[res_var]) + variable_map[res_var] = concept + end + ConceptMap(variable_map) +end diff --git a/src/concept/proto/concept_proto_builder.jl b/src/concept/proto/concept_proto_builder.jl index 334ae5a4..80413dea 100644 --- a/src/concept/proto/concept_proto_builder.jl +++ b/src/concept/proto/concept_proto_builder.jl @@ -1 +1,178 @@ # This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + +# from datetime import datetime +# from typing import List + +# import grakn_protocol.protobuf.concept_pb2 as concept_proto + +# from grakn.common.exception import GraknClientException +# from grakn.concept.type.value_type import ValueType + +function iid(iid_::String) + bytes = hex2bytes(lstrip(iid_,['0','x'])) +end + +function thing(thing_) + proto_thing = grakn.protocol.Thing() + proto_thing.iid = iid(get_iid(thing_)) + + proto_thing +end + +function type_(_type) + proto_type = grakn.protocol.Type() + proto_type.label = get_label(_type) + proto_type.encoding = encoding(_type) + + if _type.is_role_type() + proto_type.scope = get_scope(_type) + end + + proto_type +end + +function types(types_) + map(_type -> type_(_type), types_) +end + +function boolean_attribute_value(value::Bool) + value_proto = grakn.protocol.Attribute_Value() + value_proto.boolean = value + return value_proto +end + +function long_attribute_value(value::Int) + value_proto = grakn.protocol.Attribute_Value() + value_proto.long = value + return value_proto +end + +function double_attribute_value(value::T) where {T<:AbstractFloat} + value_proto = grakn.protocol.Attribute_Value() + value_proto.double = value + return value_proto +end + +function string_attribute_value(value::String) + value_proto = grakn.protocol.Attribute_Value() + value_proto.string = value + return value_proto +end + +function datetime_attribute_value(value::DateTime) + value_proto = grakn.protocol.Attribute_Value() + value_proto.date_time = Second(value - DateTime(1970, 1, 1)) + return value_proto + + +function value_type(value_type_::ValueType) + if findfirst(x-> x == value_type_, instances(ValueType)) === nothing + throw(GraknClientException("Unrecognised value type: " + string(value_type_))) + else + findfirst(x-> x == value_type_, instances(ValueType)) + end +end + +function encoding(_type) + if is_entity_type(_type) + return Int("ENTITY_TYPE") + elseif is_relation_type(_type) + return Int("RELATION_TYPE") + elseif is_attribute_type(_type) + return Int("ATTRIBUTE_TYPE") + elseif is_role_type(_type) + return Int("ROLE_TYPE") + elseif is_thing_type(_type) + return Int("THING_TYPE") + elseif true + raise GraknClientException("Unrecognised type encoding: " + str(_type)) + end +end + + +# def iid(iid_: str): erl. +# return bytes.fromhex(iid_.lstrip("0x")) + + +# def thing(thing_): erl. +# proto_thing = concept_proto.Thing() +# proto_thing.iid = iid(thing_.get_iid()) +# return proto_thing + + +# def type_(_type): erl. +# proto_type = concept_proto.Type() +# proto_type.label = _type.get_label() +# proto_type.encoding = encoding(_type) + +# if _type.is_role_type(): +# proto_type.scope = _type.get_scope() + +# return proto_type + + +# def types(types_: List): erl. +# return map(lambda _type: type_(_type), types_) + + +# def boolean_attribute_value(value: bool): erl. +# value_proto = concept_proto.Attribute.Value() +# value_proto.boolean = value +# return value_proto + + +# def long_attribute_value(value: int): erl. +# value_proto = concept_proto.Attribute.Value() +# value_proto.long = value +# return value_proto + + +# def double_attribute_value(value: float): erl. +# value_proto = concept_proto.Attribute.Value() +# value_proto.double = value +# return value_proto + + +# def string_attribute_value(value: str): erl. +# value_proto = concept_proto.Attribute.Value() +# value_proto.string = value +# return value_proto + + +# def datetime_attribute_value(value: datetime): erl. +# value_proto = concept_proto.Attribute.Value() +# value_proto.date_time = int((value - datetime(1970, 1, 1)).total_seconds() * 1000) +# return value_proto + + +# def value_type(value_type_: ValueType): erl. +# if value_type_ == ValueType.BOOLEAN: +# return concept_proto.AttributeType.ValueType.Value("BOOLEAN") +# elif value_type_ == ValueType.LONG: +# return concept_proto.AttributeType.ValueType.Value("LONG") +# elif value_type_ == ValueType.DOUBLE: +# return concept_proto.AttributeType.ValueType.Value("DOUBLE") +# elif value_type_ == ValueType.STRING: +# return concept_proto.AttributeType.ValueType.Value("STRING") +# elif value_type_ == ValueType.DATETIME: +# return concept_proto.AttributeType.ValueType.Value("DATETIME") +# elif value_type_ == ValueType.OBJECT: +# return concept_proto.AttributeType.ValueType.Value("OBJECT") +# else: +# raise GraknClientException("Unrecognised value type: " + str(value_type_)) + + +# def encoding(_type): +# if _type.is_entity_type(): +# return concept_proto.Type.Encoding.Value("ENTITY_TYPE") +# elif _type.is_relation_type(): +# return concept_proto.Type.Encoding.Value("RELATION_TYPE") +# elif _type.is_attribute_type(): +# return concept_proto.Type.Encoding.Value("ATTRIBUTE_TYPE") +# elif _type.is_role_type(): +# return concept_proto.Type.Encoding.Value("ROLE_TYPE") +# elif _type.is_thing_type(): +# return concept_proto.Type.Encoding.Value("THING_TYPE") +# else: +# raise GraknClientException("Unrecognised type encoding: " + str(_type)) diff --git a/src/concept/proto/concept_proto_reader.jl b/src/concept/proto/concept_proto_reader.jl index d34175e9..5357fa3b 100644 --- a/src/concept/proto/concept_proto_reader.jl +++ b/src/concept/proto/concept_proto_reader.jl @@ -1 +1,110 @@ -# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE \ No newline at end of file +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# import grakn_protocol.protobuf.concept_pb2 as concept_proto + +# from grakn.common.exception import GraknClientException +# from grakn.concept.answer.concept_map import ConceptMap erl. +# from grakn.concept.thing.attribute import BooleanAttribute, LongAttribute, DoubleAttribute, StringAttribute, \ +# DateTimeAttribute +# from grakn.concept.thing.entity import Entity +# from grakn.concept.thing.relation import Relation +# from grakn.concept.type.attribute_type import BooleanAttributeType, LongAttributeType, DoubleAttributeType, \ +# StringAttributeType, DateTimeAttributeType, AttributeType +# from grakn.concept.type.entity_type import EntityType +# from grakn.concept.type.relation_type import RelationType +# from grakn.concept.type.role_type import RoleType +# from grakn.concept.type.thing_type import ThingType + + +# def iid(iid_proto: bytes): +# return "0x" + iid_proto.hex() + + +# def concept(con_proto: concept_proto.Concept): +# if con_proto.HasField(ConceptMap._THING): +# concept = thing(con_proto.thing) +# else: +# concept = type_(con_proto.type) +# return concept + + +# def thing(thing_proto: concept_proto.Thing): +# if thing_proto.type.encoding == concept_proto.Type.Encoding.Value("ENTITY_TYPE"): +# return Entity._of(thing_proto) +# elif thing_proto.type.encoding == concept_proto.Type.Encoding.Value("RELATION_TYPE"): +# return Relation._of(thing_proto) +# elif thing_proto.type.encoding == concept_proto.Type.Encoding.Value("ATTRIBUTE_TYPE"): +# return attribute(thing_proto) +# else: +# raise GraknClientException("The encoding " + thing_proto.type.encoding + " was not recognised.") + + +# def attribute(thing_proto: concept_proto.Thing): +# if thing_proto.type.value_type == concept_proto.AttributeType.ValueType.Value("BOOLEAN"): +# return BooleanAttribute._of(thing_proto) +# elif thing_proto.type.value_type == concept_proto.AttributeType.ValueType.Value("LONG"): +# return LongAttribute._of(thing_proto) +# elif thing_proto.type.value_type == concept_proto.AttributeType.ValueType.Value("DOUBLE"): +# return DoubleAttribute._of(thing_proto) +# elif thing_proto.type.value_type == concept_proto.AttributeType.ValueType.Value("STRING"): +# return StringAttribute._of(thing_proto) +# elif thing_proto.type.value_type == concept_proto.AttributeType.ValueType.Value("DATETIME"): +# return DateTimeAttribute._of(thing_proto) +# else: +# raise GraknClientException("The value type " + str(thing_proto.type.value_type) + " was not recognised.") + + +# def type_(type_proto: concept_proto.Type): +# if type_proto.encoding == concept_proto.Type.Encoding.Value("ROLE_TYPE"): +# return RoleType._of(type_proto) +# else: +# return thing_type(type_proto) + + +# def thing_type(type_proto: concept_proto.Type): +# if type_proto.encoding == concept_proto.Type.Encoding.Value("ENTITY_TYPE"): +# return EntityType._of(type_proto) +# elif type_proto.encoding == concept_proto.Type.Encoding.Value("RELATION_TYPE"): +# return RelationType._of(type_proto) +# elif type_proto.encoding == concept_proto.Type.Encoding.Value("ATTRIBUTE_TYPE"): +# return attribute_type(type_proto) +# elif type_proto.encoding == concept_proto.Type.Encoding.Value("THING_TYPE"): +# return ThingType(type_proto.label, type_proto.root) +# else: +# raise GraknClientException("The encoding " + str(type_proto.encoding) + " was not recognised.") + + +# def attribute_type(type_proto: concept_proto.Type): +# if type_proto.value_type == concept_proto.AttributeType.ValueType.Value("BOOLEAN"): +# return BooleanAttributeType._of(type_proto) +# elif type_proto.value_type == concept_proto.AttributeType.ValueType.Value("LONG"): +# return LongAttributeType._of(type_proto) +# elif type_proto.value_type == concept_proto.AttributeType.ValueType.Value("DOUBLE"): +# return DoubleAttributeType._of(type_proto) +# elif type_proto.value_type == concept_proto.AttributeType.ValueType.Value("STRING"): +# return StringAttributeType._of(type_proto) +# elif type_proto.value_type == concept_proto.AttributeType.ValueType.Value("DATETIME"): +# return DateTimeAttributeType._of(type_proto) +# elif type_proto.value_type == concept_proto.AttributeType.ValueType.Value("OBJECT"): +# return AttributeType(type_proto.label, type_proto.root) +# else: +# raise GraknClientException("The value type " + str(type_proto.value_type) + " was not recognised.") diff --git a/src/concept/thing/Attribute.jl b/src/concept/thing/Attribute.jl index d34175e9..1b32b459 100644 --- a/src/concept/thing/Attribute.jl +++ b/src/concept/thing/Attribute.jl @@ -1 +1,238 @@ -# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE \ No newline at end of file +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + +# from datetime import datetime + +# import grakn_protocol.protobuf.concept_pb2 as concept_proto + +# from grakn.concept.proto import concept_proto_builder, concept_proto_reader +# from grakn.concept.thing.thing import Thing, RemoteThing + + +# class Attribute(Thing): + +# def is_attribute(self): +# return True + +# def is_boolean(self): +# return False + +# def is_long(self): +# return False + +# def is_double(self): +# return False + +# def is_string(self): +# return False + +# def is_datetime(self): +# return False + + +# class RemoteAttribute(RemoteThing): + +# def get_owners(self, owner_type=None): +# method = concept_proto.Thing.Req() +# get_owners_req = concept_proto.Attribute.GetOwners.Req() +# if owner_type: +# get_owners_req.thing_type = concept_proto_builder.type_(owner_type) +# method.attribute_get_owners_req.CopyFrom(get_owners_req) +# return self._thing_stream(method, lambda res: res.attribute_get_owners_res.things) + +# def is_attribute(self): +# return True + +# def is_boolean(self): +# return False + +# def is_long(self): +# return False + +# def is_double(self): +# return False + +# def is_string(self): +# return False + +# def is_datetime(self): +# return False + + +# class BooleanAttribute(Attribute): + +# def __init__(self, iid: str, type_, value: bool): +# super(BooleanAttribute, self).__init__(iid, type_) +# self._value = value + +# @staticmethod +# def _of(thing_proto: concept_proto.Thing): +# return BooleanAttribute(concept_proto_reader.iid(thing_proto.iid), concept_proto_reader.attribute_type(thing_proto.type), thing_proto.value.boolean) + +# def get_value(self): +# return self._value + +# def is_boolean(self): +# return True + +# def as_remote(self, transaction): +# return RemoteBooleanAttribute(transaction, self.get_iid(), self.get_type(), self.get_value()) + + +# class RemoteBooleanAttribute(RemoteAttribute): + +# def __init__(self, transaction, iid: str, type_, value: bool): +# super(RemoteBooleanAttribute, self).__init__(transaction, iid, type_) +# self._value = value + +# def get_value(self): +# return self._value + +# def is_boolean(self): +# return True + +# def as_remote(self, transaction): +# return RemoteBooleanAttribute(transaction, self.get_iid(), self.get_type(), self.get_value()) + + +# class LongAttribute(Attribute): + +# def __init__(self, iid: str, type_, value: int): +# super(LongAttribute, self).__init__(iid, type_) +# self._value = value + +# @staticmethod +# def _of(thing_proto: concept_proto.Thing): +# return LongAttribute(concept_proto_reader.iid(thing_proto.iid), concept_proto_reader.attribute_type(thing_proto.type), thing_proto.value.long) + +# def get_value(self): +# return self._value + +# def is_long(self): +# return True + +# def as_remote(self, transaction): +# return RemoteLongAttribute(transaction, self.get_iid(), self.get_type(), self.get_value()) + + +# class RemoteLongAttribute(RemoteAttribute): + +# def __init__(self, transaction, iid: str, type_, value: int): +# super(RemoteLongAttribute, self).__init__(transaction, iid, type_) +# self._value = value + +# def get_value(self): +# return self._value + +# def is_long(self): +# return True + +# def as_remote(self, transaction): +# return RemoteLongAttribute(transaction, self.get_iid(), self.get_type(), self.get_value()) + + +# class DoubleAttribute(Attribute): + +# def __init__(self, iid: str, type_, value: float): +# super(DoubleAttribute, self).__init__(iid, type_) +# self._value = value + +# @staticmethod +# def _of(thing_proto: concept_proto.Thing): +# return DoubleAttribute(concept_proto_reader.iid(thing_proto.iid), concept_proto_reader.attribute_type(thing_proto.type), thing_proto.value.double) + +# def get_value(self): +# return self._value + +# def is_double(self): +# return True + +# def as_remote(self, transaction): +# return RemoteDoubleAttribute(transaction, self.get_iid(), self.get_type(), self.get_value()) + + +# class RemoteDoubleAttribute(RemoteAttribute): + +# def __init__(self, transaction, iid: str, type_, value: float): +# super(RemoteDoubleAttribute, self).__init__(transaction, iid, type_) +# self._value = value + +# def get_value(self): +# return self._value + +# def is_double(self): +# return True + +# def as_remote(self, transaction): +# return RemoteDoubleAttribute(transaction, self.get_iid(), self.get_type(), self.get_value()) + + +# class StringAttribute(Attribute): + +# def __init__(self, iid: str, type_, value: str): +# super(StringAttribute, self).__init__(iid, type_) +# self._value = value + +# @staticmethod +# def _of(thing_proto: concept_proto.Thing): +# return StringAttribute(concept_proto_reader.iid(thing_proto.iid), concept_proto_reader.attribute_type(thing_proto.type), thing_proto.value.string) + +# def get_value(self): +# return self._value + +# def is_string(self): +# return True + +# def as_remote(self, transaction): +# return RemoteStringAttribute(transaction, self.get_iid(), self.get_type(), self.get_value()) + + +# class RemoteStringAttribute(RemoteAttribute): + +# def __init__(self, transaction, iid: str, type_, value: str): +# super(RemoteStringAttribute, self).__init__(transaction, iid, type_) +# self._value = value + +# def get_value(self): +# return self._value + +# def is_string(self): +# return True + +# def as_remote(self, transaction): +# return RemoteStringAttribute(transaction, self.get_iid(), self.get_type(), self.get_value()) + + +# class DateTimeAttribute(Attribute): + +# def __init__(self, iid: str, type_, value: datetime): +# super(DateTimeAttribute, self).__init__(iid, type_) +# self._value = value + +# @staticmethod +# def _of(thing_proto: concept_proto.Thing): +# return DateTimeAttribute(concept_proto_reader.iid(thing_proto.iid), concept_proto_reader.attribute_type(thing_proto.type), datetime.fromtimestamp(float(thing_proto.value.date_time) / 1000.0)) + +# def get_value(self): +# return self._value + +# def is_datetime(self): +# return True + +# def as_remote(self, transaction): +# return RemoteDateTimeAttribute(transaction, self.get_iid(), self.get_type(), self.get_value()) + + +# class RemoteDateTimeAttribute(RemoteAttribute): + +# def __init__(self, transaction, iid: str, type_, value: datetime): +# super(RemoteDateTimeAttribute, self).__init__(transaction, iid, type_) +# self._value = value + +# def get_value(self): +# return self._value + +# def is_datetime(self): +# return True + +# def as_remote(self, transaction): +# return RemoteDateTimeAttribute(transaction, self.get_iid(), self.get_type(), self.get_value()) diff --git a/src/concept/thing/Thing.jl b/src/concept/thing/Thing.jl index d34175e9..033efd5f 100644 --- a/src/concept/thing/Thing.jl +++ b/src/concept/thing/Thing.jl @@ -1 +1,207 @@ -# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE \ No newline at end of file +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + +# from typing import Callable, List + +# import grakn_protocol.protobuf.concept_pb2 as concept_proto +# import grakn_protocol.protobuf.transaction_pb2 as transaction_proto + +# from grakn.common.exception import GraknClientException +# from grakn.concept.proto import concept_proto_reader, concept_proto_builder +# from grakn.concept.concept import Concept, RemoteConcept + +mutable struct Thing <: AbstractThing + _iid::String + _type + _hash +end + +Base.print(io::IO, thing::Thing) = Base.print(io, string(typeof(thing)) + "[iid: $(thing._iid)]") +Base.show(io::IO, thing::Thing) = Base.print(io,thing) + +function Thing(iid::String, type_) + isempty(iid) && throw(GraknClientException("IID must be a non-empty string.")) + hash_iid = hash(iid) + Thing(iid,type_, hash_iid) +end + +get_iid(thing::T) where {T<: AbstractThing} = thing._iid + +get_type(thing::T) where {T<: AbstractThing} = thing._type + +is_thing(thing::T) where {T<: AbstractThing} = true + +function Base.==(thing1::Thing, thing2::Thing) + thing1 === thing2 && return true + get_iid(thing1) == get_iid(thing2) +end + +hash(thing::Thing) = thing._hash + + +# def __init__(self, iid: str, type_): erl. +# if not iid: +# raise GraknClientException("IID must be a non-empty string.") +# self._iid = iid +# self._type = type_ +# self._hash = hash(iid) + +# def get_iid(self): erl. +# return self._iid + +# def get_type(self): erl. +# return self._type + +# def is_thing(self): +# return True + +# def __str__(self): erl. +# return type(self).__name__ + "[iid:" + self.get_iid() + "]" + +# def __eq__(self, other): erl. +# if other is self: +# return True +# if not other or type(self) != type(other): +# return False +# return self.get_iid() == other.get_iid() + +# def __hash__(self): erl. +# return self._hash + + +mutable struct RemoteThing <: AbstractThing + _transaction::AbstractTransaction + _iid::String + _type + _hash +end + +function RemoteThing(transaction::AbstractTransaction, iid::String, type_) + isempty(iid) && throw(GraknClientException("IID must be set.")) + _transaction = transaction + _iid = iid + _type = type_ + _hash = hash(iid) + RemoteThing(_transaction,_iid,_type,_hash) +end + +function is_inferred(thing::RemoteThing) + req = grakn.protocol.Thing_Req() + req.thing_is_inferred_req = grakn.protocol.Thing_IsInferred_Req() + return self._execute(req).thing_is_inferred_res.inferred +end + +#TODO concept_proto_builder must be implemented +function _execute(self, method::grakn.protocol.Thing_Req) + throw(GraknClientException("concept_proto_builder must be implemented")) + method.iid = concept_proto_builder.iid(self.get_iid()) + request = transaction_proto.Transaction.Req() + request.thing_req.CopyFrom(method) + return self._transaction._execute(request).thing_res + +end + +# def __init__(self, transaction, iid: str, type_): erl. +# if not transaction: +# raise GraknClientException("Transaction must be set.") +# if not iid: +# raise GraknClientException("IID must be set.") +# self._transaction = transaction +# self._iid = iid +# self._type = type_ +# self._hash = hash(iid) + +# def get_iid(self): erl +# return self._iid + +# def get_type(self): erl. +# return self._type + +# def is_inferred(self): +# req = concept_proto.Thing.Req() +# req.thing_is_inferred_req.CopyFrom(concept_proto.Thing.IsInferred.Req()) +# return self._execute(req).thing_is_inferred_res.inferred + +# def get_has(self, attribute_type=None, attribute_types: List = None, only_key=False): +# if [bool(attribute_type), bool(attribute_types), only_key].count(True) > 1: +# raise GraknClientException("Only one filter can be applied at a time to get_has." +# "The possible filters are: [attribute_type, attribute_types, only_key]") +# if attribute_type: +# attribute_types = [attribute_type] +# method = concept_proto.Thing.Req() +# get_has_req = concept_proto.Thing.GetHas.Req() +# if only_key: +# get_has_req.keys_only = only_key +# elif attribute_types: +# get_has_req.attribute_types.extend(concept_proto_builder.types(attribute_types)) +# method.thing_get_has_req.CopyFrom(get_has_req) +# return self._thing_stream(method, lambda res: res.thing_get_has_res.attributes) + +# def get_plays(self): +# req = concept_proto.Thing.Req() +# req.thing_get_plays_req.CopyFrom(concept_proto.Thing.GetPlays.Req()) +# return self._type_stream(req, lambda res: res.thing_get_plays_res.role_types) + +# def get_relations(self, role_types: list = None): +# if not role_types: +# role_types = [] +# method = concept_proto.Thing.Req() +# get_relations_req = concept_proto.Thing.GetRelations.Req() +# get_relations_req.role_types.extend(concept_proto_builder.types(role_types)) +# method.thing_get_relations_req.CopyFrom(get_relations_req) +# return self._thing_stream(method, lambda res: res.thing_get_relations_res.relations) + +# def set_has(self, attribute): +# method = concept_proto.Thing.Req() +# set_has_req = concept_proto.Thing.SetHas.Req() +# set_has_req.attribute.CopyFrom(concept_proto_builder.thing(attribute)) +# method.thing_set_has_req.CopyFrom(set_has_req) +# self._execute(method) + +# def unset_has(self, attribute): +# method = concept_proto.Thing.Req() +# unset_has_req = concept_proto.Thing.UnsetHas.Req() +# unset_has_req.attribute.CopyFrom(concept_proto_builder.thing(attribute)) +# method.thing_unset_has_req.CopyFrom(unset_has_req) +# self._execute(method) + +# def delete(self): +# method = concept_proto.Thing.Req() +# method.thing_delete_req.CopyFrom(concept_proto.Thing.Delete.Req()) +# self._execute(method) + +# def is_deleted(self): +# return not self._transaction.concepts().get_thing(self.get_iid()) + +# def is_thing(self): +# return True + +# def _thing_stream(self, method: concept_proto.Thing.Req, thing_list_getter: Callable[[concept_proto.Thing.Res], List[concept_proto.Thing]]): +# method.iid = concept_proto_builder.iid(self.get_iid()) +# request = transaction_proto.Transaction.Req() +# request.thing_req.CopyFrom(method) +# return map(lambda thing_proto: concept_proto_reader.thing(thing_proto), self._transaction._stream(request, lambda res: thing_list_getter(res.thing_res))) + +# def _type_stream(self, method: concept_proto.Thing.Req, type_list_getter: Callable[[concept_proto.Thing.Res], List[concept_proto.Type]]): +# method.iid = concept_proto_builder.iid(self.get_iid()) +# request = transaction_proto.Transaction.Req() +# request.thing_req.CopyFrom(method) +# return map(lambda type_proto: concept_proto_reader.type_(type_proto), self._transaction._stream(request, lambda res: type_list_getter(res.thing_res))) + +# def _execute(self, method: concept_proto.Thing.Req): +# method.iid = concept_proto_builder.iid(self.get_iid()) +# request = transaction_proto.Transaction.Req() +# request.thing_req.CopyFrom(method) +# return self._transaction._execute(request).thing_res + +# def __str__(self): +# return type(self).__name__ + "[iid:" + str(self._iid) + "]" + +# def __eq__(self, other): +# if other is self: +# return True +# if not other or type(self) != type(other): +# return False +# return self._transaction is other._transaction and self._iid == other._iid + +# def __hash__(self): +# return self._hash diff --git a/src/concept/type/value_type.jl b/src/concept/type/value_type.jl index d34175e9..653170d4 100644 --- a/src/concept/type/value_type.jl +++ b/src/concept/type/value_type.jl @@ -1 +1,20 @@ -# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE \ No newline at end of file +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + +import enum + +from datetime import datetime +from typing import Union + + +@enum ValueType begin + # This lives here to avoid circular imports. + OBJECT = 0 + BOOLEAN = 1 + LONG = 2 + DOUBLE = 3 + STRING = 4 + DATETIME = 5 +end + + +ValueClass = Union{Bool, Int, T , String, DateTime} where {T<:AbstractFloat} \ No newline at end of file diff --git a/src/generated/grakn_pb.jl b/src/generated/grakn_pb.jl index 90a4dbdd..a5d93f25 100644 --- a/src/generated/grakn_pb.jl +++ b/src/generated/grakn_pb.jl @@ -13,7 +13,7 @@ const _Grakn_methods = MethodDescriptor[ MethodDescriptor("session_open", 5, grakn.protocol.Session_Open_Req, grakn.protocol.Session_Open_Res), MethodDescriptor("session_close", 6, grakn.protocol.Session_Close_Req, grakn.protocol.Session_Close_Res), MethodDescriptor("session_pulse", 7, grakn.protocol.Session_Pulse_Req, grakn.protocol.Session_Pulse_Res), - MethodDescriptor("transaction", 8, Channel{grakn.protocol.Transaction_Req}, Channel{grakn.protocol.Transaction_Res}) + MethodDescriptor("transaction", 8, grakn.protocol.Transaction_Req, grakn.protocol.Transaction_Res), ] # const _Grakn_methods const _Grakn_desc = ServiceDescriptor("grakn.protocol.Grakn", 1, _Grakn_methods) @@ -50,7 +50,7 @@ session_close(stub::GraknBlockingStub, controller::ProtoRpcController, inp::grak session_pulse(stub::GraknStub, controller::ProtoRpcController, inp::grakn.protocol.Session_Pulse_Req, done::Function) = call_method(stub.impl, _Grakn_methods[7], controller, inp, done) session_pulse(stub::GraknBlockingStub, controller::ProtoRpcController, inp::grakn.protocol.Session_Pulse_Req) = call_method(stub.impl, _Grakn_methods[7], controller, inp) -transaction(stub::GraknStub, controller::ProtoRpcController, inp::Channel{grakn.protocol.Transaction_Req}, done::Function) = call_method(stub.impl, _Grakn_methods[8], controller, inp, done) -transaction(stub::GraknBlockingStub, controller::ProtoRpcController, inp::Channel{grakn.protocol.Transaction_Req}) = call_method(stub.impl, _Grakn_methods[8], controller, inp) +transaction(stub::GraknStub, controller::ProtoRpcController, inp::grakn.protocol.Transaction_Req, done::Function) = call_method(stub.impl, _Grakn_methods[8], controller, inp, done) +transaction(stub::GraknBlockingStub, controller::ProtoRpcController, inp::grakn.protocol.Transaction_Req) = call_method(stub.impl, _Grakn_methods[8], controller, inp) export Grakn, GraknStub, GraknBlockingStub, database_contains, database_create, database_all, database_delete, session_open, session_close, session_pulse, transaction diff --git a/src/query/query_manager.jl b/src/query/query_manager.jl index 19a9e2ad..b22dadd8 100644 --- a/src/query/query_manager.jl +++ b/src/query/query_manager.jl @@ -6,14 +6,18 @@ end QueryManager() = QueryManager(nothing) -# def match(self, query: str, options: GraknOptions = None): -# if not options: -# options = GraknOptions.core() -# request = query_proto.Query.Req() -# match_req = query_proto.Query.Match.Req() -# match_req.query = query -# request.match_req.CopyFrom(match_req) -# return map(lambda answer_proto: concept_map._of(answer_proto), self._iterate_query(request, lambda res: res.query_res.match_res.answers, options)) + +# function match(querMan::T, query::String, options::GraknOptions = nothing) where {T<:AbstractQueryManager} +# if !options +# options = core() +# end +# request = grakn.protocol.Query_Req() +# match_req =grakn.protocol.Query_Match_Req() +# match_req.query = query +# request.match_req = match_req +# return map(lambda answer_proto: concept_map._of(answer_proto), self._iterate_query(request, lambda res: res.query_res.match_res.answers, options)) +# end + # def match_aggregate(self, query: str, options: GraknOptions = None): # if not options: diff --git a/src/rpc/database_manager.jl b/src/rpc/database_manager.jl index 47fba69c..a15ead60 100644 --- a/src/rpc/database_manager.jl +++ b/src/rpc/database_manager.jl @@ -2,8 +2,7 @@ using ProtoBuf using gRPC - -using .grakn.protocol +using .grakn export DatabaseManager export contains, create, delete, all @@ -37,7 +36,7 @@ function create(db_manager::DatabaseManager, name::String) request.name = name if !contains(db_manager,name) try - result = database_create(stub_local, gRPCController(), request) + result = database_create(db_manager.stub_local, gRPCController(), request) catch ex throw(GraknClientException(ex)) finally @@ -55,7 +54,7 @@ function delete(db_manager::DatabaseManager, name::String) request.name = name if contains(db_manager,name) try - result = database_delete(stub_local, gRPCController(), request) + result = database_delete(db_manager.stub_local, gRPCController(), request) catch ex throw(GraknClientException(ex)) finally @@ -73,7 +72,7 @@ function all(db_manager::DatabaseManager) try result = database_all(stub_local, gRPCController(), request).names catch ex - throw(GraknClientException(e)) + throw(GraknClientException(ex)) finally end diff --git a/src/rpc/session.jl b/src/rpc/session.jl index cefffc83..0cb41e59 100644 --- a/src/rpc/session.jl +++ b/src/rpc/session.jl @@ -1,5 +1,5 @@ # This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE - + using gRPC using .grakn @@ -11,52 +11,38 @@ function _session_type_proto(session_type) return Int(session_type) end -# @abstractmethod -# def transaction(self, transaction_type: TransactionType, options=None) -> Transaction: -# pass - -# @abstractmethod -# def session_type(self) -> SessionType: -# pass - -# @abstractmethod -# def is_open(self) -> bool: -# pass - -# @abstractmethod -# def close(self) -> None: -# pass - -# @abstractmethod -# def database(self) -> str: -# pass - -# @abstractmethod -# def __enter__(self): -# pass - -# @abstractmethod -# def __exit__(self, exc_type, exc_val, exc_tb): -# pass - - -struct _SessionRPC <: AbstractSession +mutable struct _SessionRPC <: AbstractSession _pulse_frequency_seconds::Number _options _address _port _channel - #_scheduler _database _session_type _session_id _grpc_stub _is_open + _scheduler +end + +mutable struct Scheduler + session_run::Bool + session_id::Array{UInt8,1} + pulse_interval::Int + grpc_stub::GraknBlockingStub end -Session(client::GraknBlockingClient, database::String, options::GraknOptions, session_type) = init_Session(client, database, options, session_type) -Session(client::GraknBlockingClient, database::String) = init_Session(client, database, GraknOptions(), Session_Type[:DATA]) -_SessionRPC(client::GraknBlockingClient, database::String, options::GraknOptions, session_type) = init_Session(client, database, options, session_type) +function Session(client::GraknBlockingClient, database::String, options::GraknOptions, session_type) + init_Session(client, database, options, session_type) +end + +function Session(client::GraknBlockingClient, database::String) + init_Session(client, database, GraknOptions(), grakn.protocol.Session_Type[:DATA]) +end + +function _SessionRPC(client::GraknBlockingClient, database::String, options::GraknOptions, session_type) + init_Session(client, database, options, session_type) +end Base.show(io::IO, session::T) where {T<:AbstractSession} = print(io,"Session - database: $(session._database) server: $(session._address)") @@ -75,15 +61,17 @@ function init_Session(client::GraknBlockingClient, database::String, options::Un open_req.database = database open_req._type = _session_type_proto(session_type) open_req.options = copyFrom(options ,grakn.protocol.Options) - _session_id = session_open(_grpc_stub, gRPCController(), open_req).session_id + _is_open = true -# self._pulse = self._scheduler.enter(delay=self._PULSE_FREQUENCY_SECONDS, priority=1, action=self._transmit_pulse, argument=()) -# Thread(target=self._scheduler.run, name="session_pulse_{}".format(self._session_id.hex()), daemon=True).start() - _SessionRPC(_pulse_frequency_seconds, _options, _address, _port, _channel, _database , _session_type , _session_id,_grpc_stub, _is_open) + + _scheduler = Scheduler(true, _session_id, _pulse_frequency_seconds, _grpc_stub) + @async _transmit_pulse(_scheduler) + + _SessionRPC(_pulse_frequency_seconds, _options, _address, _port, _channel, _database , _session_type , _session_id,_grpc_stub, _is_open,_scheduler) end -function transaction(session::T, transaction_type, options=nothing) where {T<:AbstractSession} +function transaction(session::T, transaction_type, options=GraknOptions()) where {T<:AbstractSession} _options = options === nothing && core() return Transaction(session, transaction_type, options) end @@ -92,54 +80,40 @@ function session_type(session::T) where {T<:AbstractSession} session._session_type end +function database(session::T) where {T<:AbstractSession} + session._database +end + function is_open(session::T) where {T<:AbstractSession} session._is_open end -# def close(self) -> None: -# if self._is_open: -# self._is_open = False -# self._scheduler.cancel(self._pulse) -# self._scheduler.empty() -# req = session_proto.Session.Close.Req() -# req.session_id = self._session_id -# try: -# self._grpc_stub.session_close(req) -# except RpcError as e: -# raise GraknClientException(e) -# finally: -# self._channel.close() - -# def database(self) -> str: return self._database - -# def _transmit_pulse(self) -> None: -# if not self._is_open: -# return -# pulse_req = session_proto.Session.Pulse.Req() -# pulse_req.session_id = self._session_id -# res = self._grpc_stub.session_pulse(pulse_req) -# if res.alive: -# self._pulse = self._scheduler.enter(delay=self._PULSE_FREQUENCY_SECONDS, priority=1, action=self._transmit_pulse, argument=()) -# Thread(target=self._scheduler.run, name="session_pulse_{}".format(self._session_id.hex()), daemon=True).start() - -# def __enter__(self): -# return self - -# def __exit__(self, exc_type, exc_val, exc_tb): -# self.close() -# if exc_tb is None: -# pass -# else: -# return False - -#### helper functions ############ - -function copyFrom(fromOption::R, toOption::Type{T}) where {T<:Options} where {R<:AbstractGraknOptions} - result_option = toOption() - for fname in fieldnames(typeof(fromOption)) - if hasproperty(result_option, Symbol(fname)) - setproperty!(result_option,Symbol(fname),getfield(fromOption,Symbol(fname))) +function close(session::T) where {T<:AbstractSession} + if session._is_open + session._is_open = false + session._scheduler.session_run = false + req = grakn.protocol.Session_Close_Req() + req.session_id = session._session_id + try + result = session_close(session._grpc_stub,gRPCController(),req) + catch ex + rethrow(ex) + finally + close(session._channel) end end - result_option +end + +""" + function _transmit_pulse(scheduler::Scheduler) used to keep the session alive. + The function meant to be called as @async +""" +function _transmit_pulse(scheduler::Scheduler) + while scheduler.session_run + sleep(scheduler.pulse_interval -1) + pulse_req = grakn.protocol.Session_Pulse_Req() + pulse_req.session_id = scheduler.session_id + is_alive = session_pulse(scheduler.grpc_stub, gRPCController(), pulse_req).alive + end + @info "Session $(scheduler.session_id) no longer alive" end diff --git a/src/rpc/transaction.jl b/src/rpc/transaction.jl index ccf43494..852450fd 100644 --- a/src/rpc/transaction.jl +++ b/src/rpc/transaction.jl @@ -1,4 +1,5 @@ # This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE +using UUIDs CLOSE_STREAM = "CLOSE_STREAM" @@ -11,17 +12,18 @@ RequestIterator() = RequestIterator(nothing) mutable struct Transaction <: AbstractTransaction _options _transaction_type::Union{Any,Nothing} - _concept_manager::Union{T,Nothing} where {T<:AbstractConceptManager} - _query_manager::Union{T,Nothing} where {T<:AbstractQueryManager} - _logic_manager::Union{T,Nothing} where {T<:AbstractLogicManager} - _response_queues - _grpc_stub::Union{GraknStub,Nothing} - _request_iterator::Union{RequestIterator,Nothing} - _response_iterator + _concept_manager::T where {T<:Union{<:AbstractConceptManager, Nothing}} + _query_manager::T where {T<:Union{<:AbstractQueryManager, Nothing}} + _logic_manager::T where {T<:Union{<:AbstractLogicManager, Nothing}} + _response_queues::Dict{String,Any} + _grpc_stub::Union{GraknBlockingStub,Nothing} + _request_iterator::Union{Channel{grakn.protocol.Transaction_Req},Nothing} + _response_iterator::Union{Channel{grakn.protocol.Transaction_Res},Nothing} _transaction_was_closed::Bool + _network_latency_millis::Number end -Base.show(io::IO, transaction::T) where {T<:AbstractTransaction} = print(io,"Transaction - session-id: $(transaction._session_id)") +Base.show(io::IO, transaction::T) where {T<:AbstractTransaction} = print(io,"Transaction - first attempt") function Transaction(session::T, transaction_type::W, options::R) where {T<:AbstractSession} where {W<:Number} where {R<:AbstractGraknOptions} @@ -32,70 +34,100 @@ function Transaction(session::T, transaction_type::W, options::R) where {T<:Abst _logic_manager = LogicManager() _response_queues = Dict{String,Any}() - _channel = grpc_channel(GraknBlockingClient(session._address,session._port)) - _grpc_stub = GraknBlockingStub(_channel) - _request_iterator = Channel{grakn.protocol.Transaction_Req}(4) - _response_iterator = transaction(_grpc_stub, gRPCController(), _request_iterator) + channel = grpc_channel(GraknBlockingClient(session._address,session._port)) + _grpc_stub = GraknBlockingStub(channel) + _request_iterator = Channel{grakn.protocol.Transaction_Req}(20) + _response_iterator = Channel{grakn.protocol.Transaction_Res}(20) _transaction_was_closed = false - # open_req = Transaction_Open_Req() - # open_req.session_id = session._session_id - # open_req.type = _transaction_type_proto(transaction_type) - # open_req.options = copyFrom(options ,grakn.protocol.Options) - # req = Transaction_Req() - # req.open_req.CopyFrom(open_req) + open_req = grakn.protocol.Transaction_Open_Req() + open_req.session_id = session._session_id + open_req._type = _transaction_type_proto(transaction_type) + open_req.options = copyFrom(options ,grakn.protocol.Options) + req = grakn.protocol.Transaction_Req() + req.id = string(UUIDs.uuid4()) + req.open_req = open_req + res = @timed transaction(_grpc_stub, gRPCController(), req) + _network_latency_millis = (res.time * 1000) - res.value.open_res.processing_time_millis + + Transaction(options, _transaction_type, _concept_manager, _query_manager, _logic_manager, _response_queues, _grpc_stub, _request_iterator, _response_iterator, _transaction_was_closed, _network_latency_millis ) +end -# start_time = time.time() * 1000.0 -# res = self._execute(req) -# end_time = time.time() * 1000.0 -# self._network_latency_millis = end_time - start_time - res.open_res.processing_time_millis +const __meta_Channel_Transaction_Req = Ref{ProtoMeta}() +function meta(::Type{Channel{grakn.protocol.Transaction_Req}}) + ProtoBuf.metalock() do + if !isassigned(__meta_Channel_Transaction_Req) + __meta_Channel_Transaction_Req[] = target = ProtoMeta(Channel{grakn.protocol.Transaction_Req}) + allflds = Pair{Symbol,Union{Type,String}}[] + meta(target, Channel{grakn.protocol.Transaction_Req}, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES) + end + __meta_Channel_Transaction_Req[] + end +end - Transaction(options, _transaction_type, nothing, nothing, nothing, nothing, nothing, nothing, nothing, false) +function _transaction_type_proto(transaction_type) + Int32(transaction_type) end -# def transaction_type(self): -# return self._transaction_type -# def is_open(self): -# return not self._transaction_was_closed +function transaction_type(trans::T) where {T<:AbstractTransaction} + findfirst(x-> x == trans._transaction_type, grakn.protocol.Transaction_Type) +end -# def concepts(self): -# return self._concept_manager +function is_open(trans::T) where {T<:AbstractTransaction} + !trans._transaction_was_closed +end -# def query(self): -# return self._query_manager +function concepts(trans::T) where {T<:AbstractTransaction} + trans._concept_manager +end -# def logic(self): -# return self._logic_manager +function query(trans::T) where {T<:AbstractTransaction} + trans._query_manager +end + +function logic(trans::T) where {T<:AbstractTransaction} + trans._logic_manager +end + +function _execute(trans::T, request::grakn.protocol.Transaction_Req) where {T<:AbstractTransaction} + request_id = string(UUIDs.uuid4()) + request.id = request_id + if trans._transaction_was_closed + throw(GraknClientException("The transaction has been closed and no further operation is allowed.")) + end + res = transaction(trans._grpc_stub, gRPCController(), request) +end + +function commit(trans::T) where {T<:AbstractTransaction} + req = grakn.protocol.Transaction_Req() + commit_req = grakn.protocol.Transaction_Commit_Req() + req.commit_req = commit_req + try + _execute(trans,req) + catch ex + throw(GraknClientException("Transaction commit failed \n reason: $ex")) + finally + close(trans) + end +end + +function close(trans::T) where {T<:AbstractTransaction} + trans_transaction_was_closed = true + close(trans._request_iterator) + close(trans._response_iterator) +end + +function rollback(trans::T) where {T<:AbstractTransaction} + req = grakn.protocol.Transaction_Req() + rollback_req = grakn.protocol.Transaction_Rollback_Req() + req.rollback_req = rollback_req + _execute(trans, req) +end -# def commit(self): -# req = transaction_proto.Transaction.Req() -# commit_req = transaction_proto.Transaction.Commit.Req() -# req.commit_req.CopyFrom(commit_req) -# try: -# self._execute(req) -# finally: -# self.close() -# def rollback(self): -# req = transaction_proto.Transaction.Req() -# rollback_req = transaction_proto.Transaction.Rollback.Req() -# req.rollback_req.CopyFrom(rollback_req) -# self._execute(req) -# def close(self): -# self._transaction_was_closed = True -# self._request_iterator.close() -# def _execute(self, request: transaction_proto.Transaction.Req): -# response_queue = queue.Queue() -# request_id = str(uuid.uuid4()) -# request.id = request_id -# if self._transaction_was_closed: -# raise GraknClientException("The transaction has been closed and no further operation is allowed.") -# self._response_queues[request_id] = response_queue -# self._request_iterator.put(request) -# return self._fetch(request_id) # def _stream(self, request: transaction_proto.Transaction.Req, transform_response: Callable[[transaction_proto.Transaction.Res], List] = None): # response_queue = queue.Queue() @@ -147,14 +179,6 @@ end # else: # return False -# @staticmethod -# def _transaction_type_proto(transaction_type): -# if transaction_type == TransactionType.READ: -# return transaction_proto.Transaction.Type.Value("READ") -# if transaction_type == TransactionType.WRITE: -# return transaction_proto.Transaction.Type.Value("WRITE") - - # Essentially the gRPC stream is constantly polling this iterator. When we issue a new request, it gets put into # the back of the queue and gRPC will pick it up when it gets round to it (this is usually instantaneous) # def __next__(self): diff --git a/src/specific_transaction_experiment.jl b/src/specific_transaction_experiment.jl new file mode 100644 index 00000000..900acc7f --- /dev/null +++ b/src/specific_transaction_experiment.jl @@ -0,0 +1,28 @@ +using GraknClient +using gRPC +using Sockets + +DefaultAdress = ip"127.0.0.1" +DefaultPort = 1729 + +cli = GraknBlockingClient(DefaultAdress,DefaultPort) + +opt = GraknClient.GraknOptions(5000) + +ses = GraknClient.Session(cli, "test", opt, GraknClient.grakn.protocol.Session_Type[:DATA]) + +# sleep(15) + +# close(ses) +tra = GraknClient.Transaction(ses, GraknClient.grakn.protocol.Transaction_Type[:READ], opt) + + +type = GraknClient.transaction_type(tra) + +is_open = GraknClient.is_open(tra) + +concepts = GraknClient.concepts(tra) + +query = GraknClient.query(tra) + +logic = GraknClient.logic(tra) \ No newline at end of file diff --git a/test/behaviour/background/core/environment.jl b/test/behaviour/background/core/environment.jl new file mode 100644 index 00000000..2b09a5de --- /dev/null +++ b/test/behaviour/background/core/environment.jl @@ -0,0 +1,33 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + + +#= +from tests.behaviour.background import environment_base +from grakn.client import GraknClient +from tests.behaviour.context import Context + + +IGNORE_TAGS = ["ignore", "ignore-client-python", "ignore-core"] + + +def before_all(context: Context): + environment_base.before_all(context) + context.client = GraknClient.core(address="localhost:%d" % int(context.config.userdata["port"])) + + +def before_scenario(context: Context, scenario): + for tag in IGNORE_TAGS: + if tag in scenario.effective_tags: + scenario.skip("tagged with @" + tag) + return + environment_base.before_scenario(context, scenario) + + +def after_scenario(context: Context, scenario): + environment_base.after_scenario(context, scenario) + + +def after_all(context: Context): + environment_base.after_all(context) +=# \ No newline at end of file diff --git a/test/behaviour/background/environment_base.jl b/test/behaviour/background/environment_base.jl new file mode 100644 index 00000000..3b2040c8 --- /dev/null +++ b/test/behaviour/background/environment_base.jl @@ -0,0 +1,77 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + +#= +from behave import * +from behave.model_core import Status + +from tests.behaviour.config.parameters import RootLabel +from tests.behaviour.context import Context, ThingSubtype + +import time + + +def before_all(context: Context): + context.THREAD_POOL_SIZE = 32 + + +def before_scenario(context: Context, scenario): + for database in context.client.databases().all(): + database.delete() + context.sessions = [] + context.sessions_to_transactions = {} + context.sessions_parallel = [] + context.sessions_to_transactions_parallel = {} + context.sessions_parallel_to_transactions_parallel = {} + context.tx = lambda: context.sessions_to_transactions[context.sessions[0]][0] + context.things = {} + context.get = lambda var: context.things[var] + context.put = lambda var, thing: _put_impl(context, var, thing) + context.get_thing_type = lambda root_label, type_label: _get_thing_type_impl(context, root_label, type_label) + context.clear_answers = lambda: _clear_answers_impl(context) + + +def _put_impl(context: Context, variable: str, thing: ThingSubtype): + context.things[variable] = thing + + +def _get_thing_type_impl(context: Context, root_label: RootLabel, type_label: str): + if root_label == RootLabel.ENTITY: + return context.tx().concepts().get_entity_type(type_label) + elif root_label == RootLabel.ATTRIBUTE: + return context.tx().concepts().get_attribute_type(type_label) + elif root_label == RootLabel.RELATION: + return context.tx().concepts().get_relation_type(type_label) + else: + raise ValueError("Unrecognised value") + + +def _clear_answers_impl(context: Context): + context.answers = None + context.numeric_answer = None + context.answer_groups = None + context.numeric_answer_groups = None + + +def after_scenario(context: Context, scenario): + if scenario.status == Status.skipped: + return + + #TODO: REMOVE THIS ONCE THE CRASHES ARE FIXED + time.sleep(0.01) + + for session in context.sessions: + session.close() + for future_session in context.sessions_parallel: + future_session.result().close() + for database in context.client.databases().all(): + database.delete() + + +def after_all(context: Context): + #TODO: REMOVE THIS ONCE THE CRASHES ARE FIXED + time.sleep(0.01) + + context.client.close() + +=# \ No newline at end of file diff --git a/test/behaviour/concept/thing/attribute/attribute_steps.jl b/test/behaviour/concept/thing/attribute/attribute_steps.jl new file mode 100644 index 00000000..f8317d87 --- /dev/null +++ b/test/behaviour/concept/thing/attribute/attribute_steps.jl @@ -0,0 +1,139 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + + +#= +from datetime import datetime + +from behave import * +from hamcrest import * + +from grakn.common.exception import GraknClientException +from grakn.concept.type.value_type import ValueType +from tests.behaviour.context import Context + + +@step("attribute({type_label}) get instances contain: {var:Var}") +def step_impl(context: Context, type_label: str, var: str): + assert_that(context.get(var), is_in(context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).get_instances())) + + +@step("attribute({type_label}) get instances is empty") +def step_impl(context: Context, type_label: str): + assert_that(calling(next).with_args(context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).get_instances()), raises(StopIteration)) + + +@step("attribute {var1:Var} get owners contain: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + assert_that(context.get(var2), is_in(context.get(var1).as_remote(context.tx()).get_owners())) + + +@step("attribute {var1:Var} get owners do not contain: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + assert_that(context.get(var2), not_(is_in(context.get(var1).as_remote(context.tx()).get_owners()))) + + +@step("attribute {var:Var} has value type: {value_type:ValueType}") +def step_impl(context: Context, var: str, value_type: ValueType): + assert_that(context.get(var).get_type().get_value_type(), is_(value_type)) + + +@step("attribute({type_label}) as(boolean) put: {value:Bool}; throws exception") +def step_impl(context: Context, type_label: str, value: bool): + assert_that(calling(context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).put).with_args(value), raises(GraknClientException)) + + +@step("{var:Var} = attribute({type_label}) as(boolean) put: {value:Bool}") +def step_impl(context: Context, var: str, type_label: str, value: bool): + context.put(var, context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).put(value)) + + +@step("attribute({type_label}) as(long) put: {value:Int}; throws exception") +def step_impl(context: Context, type_label: str, value: int): + assert_that(calling(context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).put).with_args(value), raises(GraknClientException)) + + +@step("{var:Var} = attribute({type_label}) as(long) put: {value:Int}") +def step_impl(context: Context, var: str, type_label: str, value: int): + context.put(var, context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).put(value)) + + +@step("attribute({type_label}) as(double) put: {value:Float}; throws exception") +def step_impl(context: Context, type_label: str, value: float): + assert_that(calling(context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).put).with_args(value), raises(GraknClientException)) + + +@step("{var:Var} = attribute({type_label}) as(double) put: {value:Float}") +def step_impl(context: Context, var: str, type_label: str, value: float): + context.put(var, context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).put(value)) + + +@step("attribute({type_label}) as(string) put: {value}; throws exception") +def step_impl(context: Context, type_label: str, value: str): + assert_that(calling(context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).put).with_args(value), raises(GraknClientException)) + + +@step("{var:Var} = attribute({type_label}) as(string) put: {value}") +def step_impl(context: Context, var: str, type_label: str, value: str): + context.put(var, context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).put(value)) + + +@step("attribute({type_label}) as(datetime) put: {value:DateTime}; throws exception") +def step_impl(context: Context, type_label: str, value: datetime): + assert_that(calling(context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).put).with_args(value), raises(GraknClientException)) + + +@step("{var:Var} = attribute({type_label}) as(datetime) put: {value:DateTime}") +def step_impl(context: Context, var: str, type_label: str, value: datetime): + context.put(var, context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).put(value)) + + +@step("{var:Var} = attribute({type_label}) as(boolean) get: {value:Bool}") +def step_impl(context: Context, var: str, type_label: str, value: bool): + context.put(var, context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).get(value)) + + +@step("{var:Var} = attribute({type_label}) as(long) get: {value:Int}") +def step_impl(context: Context, var: str, type_label: str, value: int): + context.put(var, context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).get(value)) + + +@step("{var:Var} = attribute({type_label}) as(double) get: {value:Float}") +def step_impl(context: Context, var: str, type_label: str, value: float): + context.put(var, context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).get(value)) + + +@step("{var:Var} = attribute({type_label}) as(string) get: {value}") +def step_impl(context: Context, var: str, type_label: str, value: str): + context.put(var, context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).get(value)) + + +@step("{var:Var} = attribute({type_label}) as(datetime) get: {value:DateTime}") +def step_impl(context: Context, var: str, type_label: str, value: datetime): + context.put(var, context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).get(value)) + + +@step("attribute {var:Var} has boolean value: {value:Bool}") +def step_impl(context: Context, var: str, value: bool): + assert_that(context.get(var).get_value(), is_(value)) + + +@step("attribute {var:Var} has long value: {value:Int}") +def step_impl(context: Context, var: str, value: int): + assert_that(context.get(var).get_value(), is_(value)) + + +@step("attribute {var:Var} has double value: {value:Float}") +def step_impl(context: Context, var: str, value: float): + assert_that(context.get(var).get_value(), is_(value)) + + +@step("attribute {var:Var} has string value: {value}") +def step_impl(context: Context, var: str, value: str): + assert_that(context.get(var).get_value(), is_(value)) + + +@step("attribute {var:Var} has datetime value: {value:DateTime}") +def step_impl(context: Context, var: str, value: datetime): + assert_that(context.get(var).get_value(), is_(value)) +=# \ No newline at end of file diff --git a/test/behaviour/concept/thing/entity/entity_steps.jl b/test/behaviour/concept/thing/entity/entity_steps.jl new file mode 100644 index 00000000..88fa4f48 --- /dev/null +++ b/test/behaviour/concept/thing/entity/entity_steps.jl @@ -0,0 +1,46 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + + +#= +from behave import * +from hamcrest import * + +from grakn.common.exception import GraknClientException +from tests.behaviour.context import Context + + +@step("entity({type_label}) create new instance; throws exception") +def step_impl(context: Context, type_label: str): + assert_that(calling(context.tx().concepts().get_entity_type(type_label).as_remote(context.tx()).create), raises(GraknClientException)) + + +@step("{var:Var} = entity({type_label}) create new instance") +def step_impl(context: Context, var: str, type_label: str): + context.put(var, context.tx().concepts().get_entity_type(type_label).as_remote(context.tx()).create()) + + +@step("{var:Var} = entity({type_label}) create new instance with key({key_type}): {key_value}") +def step_impl(context: Context, var: str, type_label: str, key_type: str, key_value: str): + key = context.tx().concepts().get_attribute_type(key_type).as_string().as_remote(context.tx()).put(key_value) + entity = context.tx().concepts().get_entity_type(type_label).as_remote(context.tx()).create() + entity.as_remote(context.tx()).set_has(key) + context.put(var, entity) + + +@step("{var:Var} = entity({type_label}) get instance with key({key_type}): {key_value}") +def step_impl(context: Context, var: str, type_label: str, key_type: str, key_value: str): + context.put(var, next((owner for owner in context.tx().concepts().get_attribute_type(key_type).as_string() + .as_remote(context.tx()).get(key_value).as_remote(context.tx()).get_owners() + if owner.get_type().get_label() == type_label), None)) + + +@step("entity({type_label}) get instances contain: {var:Var}") +def step_impl(context: Context, type_label: str, var: str): + assert_that(context.tx().concepts().get_entity_type(type_label).as_remote(context.tx()).get_instances(), has_item(context.get(var))) + + +@step("entity({type_label}) get instances is empty") +def step_impl(context: Context, type_label: str): + assert_that(calling(next).with_args(context.tx().concepts().get_entity_type(type_label).as_remote(context.tx()).get_instances()), raises(StopIteration)) +=# \ No newline at end of file diff --git a/test/behaviour/concept/thing/relation/relation_steps.jl b/test/behaviour/concept/thing/relation/relation_steps.jl new file mode 100644 index 00000000..c8667e22 --- /dev/null +++ b/test/behaviour/concept/thing/relation/relation_steps.jl @@ -0,0 +1,123 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + + +#= +from datetime import datetime + +from behave import * +from hamcrest import * + +from grakn.common.exception import GraknClientException +from grakn.concept.type.value_type import ValueType +from tests.behaviour.config.parameters import parse_dict, parse_var +from tests.behaviour.context import Context + + +@step("relation({type_label}) create new instance; throws exception") +def step_impl(context: Context, type_label: str): + assert_that(calling(context.tx().concepts().get_relation_type(type_label).as_remote(context.tx()).create), raises(GraknClientException)) + + +@step("{var:Var} = relation({type_label}) create new instance") +def step_impl(context: Context, var: str, type_label: str): + context.put(var, context.tx().concepts().get_relation_type(type_label).as_remote(context.tx()).create()) + + +@step("{var:Var} = relation({type_label}) create new instance with key({key_type}): {key_value}") +def step_impl(context: Context, var: str, type_label: str, key_type: str, key_value: str): + key = context.tx().concepts().get_attribute_type(key_type).as_string().as_remote(context.tx()).put(key_value) + relation = context.tx().concepts().get_relation_type(type_label).as_remote(context.tx()).create() + relation.as_remote(context.tx()).set_has(key) + context.put(var, relation) + + +@step("{var:Var} = relation({type_label}) get instance with key({key_type}): {key_value}") +def step_impl(context: Context, var: str, type_label: str, key_type: str, key_value: str): + context.put(var, next((owner for owner in context.tx().concepts().get_attribute_type(key_type).as_string() + .as_remote(context.tx()).get(key_value).as_remote(context.tx()).get_owners() + if owner.get_type().get_label() == type_label), None)) + + +@step("relation({type_label}) get instances contain: {var:Var}") +def step_impl(context: Context, type_label: str, var: str): + assert_that(context.tx().concepts().get_relation_type(type_label).as_remote(context.tx()).get_instances(), has_item(context.get(var))) + + +@step("relation({type_label}) get instances do not contain: {var:Var}") +def step_impl(context: Context, type_label: str, var: str): + assert_that(context.tx().concepts().get_relation_type(type_label).as_remote(context.tx()).get_instances(), not_(has_item(context.get(var)))) + + +@step("relation({type_label}) get instances is empty") +def step_impl(context: Context, type_label: str): + assert_that(calling(next).with_args(context.tx().concepts().get_relation_type(type_label).as_remote(context.tx()).get_instances()), raises(StopIteration)) + + +@step("relation {var1:Var} add player for role({role_label}): {var2:Var}") +def step_impl(context: Context, var1: str, role_label: str, var2: str): + context.get(var1).as_remote(context.tx()).add_player(context.get(var1).get_type().as_remote(context.tx()).get_relates(role_label), context.get(var2)) + + +@step("relation {var1:Var} remove player for role({role_label}): {var2:Var}") +def step_impl(context: Context, var1: str, role_label: str, var2: str): + context.get(var1).as_remote(context.tx()).remove_player(context.get(var1).get_type().as_remote(context.tx()).get_relates(role_label), context.get(var2)) + + +@step("relation {var1:Var} add player for role({role_label}): {var2:Var}; throws exception") +def step_impl(context: Context, var1: str, role_label: str, var2: str): + adding_player_throws_exception(context, var1, role_label, var2) + + +def adding_player_throws_exception(context: Context, var1: str, role_label: str, var2: str): + try: + context.get(var1).as_remote(context.tx()).add_player( + context.get(var1).get_type().as_remote(context.tx()).get_relates(role_label), + context.get(var2)) + assert False; + except GraknClientException: + pass + + +@step("relation {var:Var} get players contain") +def step_impl(context: Context, var: str): + players = parse_dict(context.table) + relation = context.get(var) + players_by_role_type = relation.as_remote(context.tx()).get_players_by_role_type() + print(players) + for (role_label, var2) in players.items(): + assert_that(players_by_role_type.get(relation.get_type().as_remote(context.tx()).get_relates(role_label)), has_item(context.get(parse_var(var2)))) + + +@step("relation {var:Var} get players do not contain") +def step_impl(context: Context, var: str): + players = parse_dict(context.table) + relation = context.get(var) + players_by_role_type = relation.as_remote(context.tx()).get_players_by_role_type() + for (role_label, var2) in players.items(): + assert_that(players_by_role_type.get(relation.get_type().as_remote(context.tx()).get_relates(role_label)), not_(has_item(context.get(parse_var(var2))))) + + +@step("relation {var1:Var} get players contain: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_players(), has_item(context.get(var2))) + + +@step("relation {var1:Var} get players do not contain: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_players(), not_(has_item(context.get(var2)))) + + +@step("relation {var1:Var} get players for role({role_label}) contain: {var2:Var}") +def step_impl(context: Context, var1: str, role_label: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_players( + role_types=[context.get(var1).get_type().as_remote(context.tx()).get_relates(role_label)]), + has_item(context.get(var2))) + + +@step("relation {var1:Var} get players for role({role_label}) do not contain: {var2:Var}") +def step_impl(context: Context, var1: str, role_label: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_players( + role_types=[context.get(var1).get_type().as_remote(context.tx()).get_relates(role_label)]), + not_(has_item(context.get(var2)))) +0' \ No newline at end of file diff --git a/test/behaviour/concept/thing/thing_steps.jl b/test/behaviour/concept/thing/thing_steps.jl new file mode 100644 index 00000000..65006d88 --- /dev/null +++ b/test/behaviour/concept/thing/thing_steps.jl @@ -0,0 +1,184 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + +#= +from behave import * +from hamcrest import * + +from grakn.common.exception import GraknClientException +from tests.behaviour.config.parameters import parse_bool, RootLabel +from tests.behaviour.context import Context + + +@step("entity {var:Var} is null: {is_null}") +@step("attribute {var:Var} is null: {is_null}") +@step("relation {var:Var} is null: {is_null}") +def step_impl(context: Context, var: str, is_null): + is_null = parse_bool(is_null) + assert_that(context.get(var) is None, is_(is_null)) + + +@step("entity {var:Var} is deleted: {is_deleted}") +@step("attribute {var:Var} is deleted: {is_deleted}") +@step("relation {var:Var} is deleted: {is_deleted}") +def step_impl(context: Context, var: str, is_deleted): + is_deleted = parse_bool(is_deleted) + assert_that(context.get(var).as_remote(context.tx()).is_deleted(), is_(is_deleted)) + + +@step("{root_label:RootLabel} {var:Var} has type: {type_label}") +def step_impl(context: Context, root_label: RootLabel, var: str, type_label: str): + thing_type = context.get_thing_type(root_label, type_label) + assert_that(context.get(var).get_type(), is_(thing_type)) + + +@step("delete entity: {var:Var}") +@step("delete attribute: {var:Var}") +@step("delete relation: {var:Var}") +def step_impl(context: Context, var: str): + context.get(var).as_remote(context.tx()).delete() + + +@step("entity {var1:Var} set has: {var2:Var}; throws exception") +@step("attribute {var1:Var} set has: {var2:Var}; throws exception") +@step("relation {var1:Var} set has: {var2:Var}; throws exception") +def step_impl(context: Context, var1: str, var2: str): + try: + context.get(var1).as_remote(context.tx()).set_has(context.get(var2)) + assert False + except GraknClientException: + pass + + +@step("entity {var1:Var} set has: {var2:Var}") +@step("attribute {var1:Var} set has: {var2:Var}") +@step("relation {var1:Var} set has: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + context.get(var1).as_remote(context.tx()).set_has(context.get(var2)) + + +@step("entity {var1:Var} unset has: {var2:Var}") +@step("attribute {var1:Var} unset has: {var2:Var}") +@step("relation {var1:Var} unset has: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + context.get(var1).as_remote(context.tx()).unset_has(context.get(var2)) + + +@step("entity {var1:Var} get keys contain: {var2:Var}") +@step("attribute {var1:Var} get keys contain: {var2:Var}") +@step("relation {var1:Var} get keys contain: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_has(only_key=True), has_item(context.get(var2))) + + +@step("entity {var1:Var} get keys do not contain: {var2:Var}") +@step("attribute {var1:Var} get keys do not contain: {var2:Var}") +@step("relation {var1:Var} get keys do not contain: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_has(only_key=True), not_(has_item(context.get(var2)))) + + +@step("entity {var1:Var} get attributes contain: {var2:Var}") +@step("attribute {var1:Var} get attributes contain: {var2:Var}") +@step("relation {var1:Var} get attributes contain: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_has(), has_item(context.get(var2))) + + +@step("entity {var1:Var} get attributes({type_label}) contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) contain: {var2:Var}") +@step("entity {var1:Var} get attributes({type_label}) as(boolean) contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) as(boolean) contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) as(boolean) contain: {var2:Var}") +@step("entity {var1:Var} get attributes({type_label}) as(long) contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) as(long) contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) as(long) contain: {var2:Var}") +@step("entity {var1:Var} get attributes({type_label}) as(double) contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) as(double) contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) as(double) contain: {var2:Var}") +@step("entity {var1:Var} get attributes({type_label}) as(string) contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) as(string) contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) as(string) contain: {var2:Var}") +@step("entity {var1:Var} get attributes({type_label}) as(datetime) contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) as(datetime) contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) as(datetime) contain: {var2:Var}") +def step_impl(context: Context, var1: str, type_label: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_has(attribute_type=context.tx().concepts().get_attribute_type(type_label)), has_item(context.get(var2))) + + +@step("entity {var1:Var} get attributes do not contain: {var2:Var}") +@step("attribute {var1:Var} get attributes do not contain: {var2:Var}") +@step("relation {var1:Var} get attributes do not contain: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_has(), not_(has_item(context.get(var2)))) + + +@step("entity {var1:Var} get attributes({type_label}) do not contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) do not contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) do not contain: {var2:Var}") +@step("entity {var1:Var} get attributes({type_label}) as(boolean) do not contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) as(boolean) do not contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) as(boolean) do not contain: {var2:Var}") +@step("entity {var1:Var} get attributes({type_label}) as(long) do not contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) as(long) do not contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) as(long) do not contain: {var2:Var}") +@step("entity {var1:Var} get attributes({type_label}) as(double) do not contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) as(double) do not contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) as(double) do not contain: {var2:Var}") +@step("entity {var1:Var} get attributes({type_label}) as(string) do not contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) as(string) do not contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) as(string) do not contain: {var2:Var}") +@step("entity {var1:Var} get attributes({type_label}) as(datetime) do not contain: {var2:Var}") +@step("attribute {var1:Var} get attributes({type_label}) as(datetime) do not contain: {var2:Var}") +@step("relation {var1:Var} get attributes({type_label}) as(datetime) do not contain: {var2:Var}") +def step_impl(context: Context, var1: str, type_label: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_has(attribute_type=context.tx().concepts().get_attribute_type(type_label)), not_(has_item(context.get(var2)))) + + +@step("entity {var1:Var} get relations({scope}:{label}) contain: {var2:Var}") +@step("attribute {var1:Var} get relations({scope}:{label}) contain: {var2:Var}") +@step("relation {var1:Var} get relations({scope}:{label}) contain: {var2:Var}") +def step_impl(context: Context, var1: str, scope: str, label: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_relations( + role_types=[context.tx().concepts().get_relation_type(scope).as_remote(context.tx()).get_relates(label)]), + has_item(context.get(var2))) + + +@step("entity {var1:Var} get relations contain: {var2:Var}") +@step("attribute {var1:Var} get relations contain: {var2:Var}") +@step("relation {var1:Var} get relations contain: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_relations(), has_item(context.get(var2))) + + +@step("entity {var1:Var} get relations({scope}:{label}) do not contain: {var2:Var}") +@step("attribute {var1:Var} get relations({scope}:{label}) do not contain: {var2:Var}") +@step("relation {var1:Var} get relations({scope}:{label}) do not contain: {var2:Var}") +def step_impl(context: Context, var1: str, scope: str, label: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_relations( + role_types=[context.tx().concepts().get_relation_type(scope).as_remote(context.tx()).get_relates(label)]), + not_(has_item(context.get(var2)))) + + +@step("entity {var1:Var} get relations do not contain: {var2:Var}") +@step("attribute {var1:Var} get relations do not contain: {var2:Var}") +@step("relation {var1:Var} get relations do not contain: {var2:Var}") +def step_impl(context: Context, var1: str, var2: str): + assert_that(context.get(var1).as_remote(context.tx()).get_relations(), not_(has_item(context.get(var2)))) + + +@step("root(thing) get instances count: {count:Int}") +def step_impl(context: Context, count: int): + assert_that(list(context.tx().concepts().get_root_thing_type().as_remote(context.tx()).get_instances()), has_length(count)) + + +@step("root(thing) get instances contain: {var:Var}") +def step_impl(context: Context, var: str): + assert_that(context.tx().concepts().get_root_thing_type().as_remote(context.tx()).get_instances(), has_item(context.get(var))) + + +@step("root(thing) get instances is empty") +def step_impl(context: Context): + assert_that(list(context.tx().concepts().get_root_thing_type().as_remote(context.tx()).get_instances()), has_length(0)) + diff --git a/test/behaviour/concept/type/attributetype/attribute_type_steps.jl b/test/behaviour/concept/type/attributetype/attribute_type_steps.jl new file mode 100644 index 00000000..2e89366c --- /dev/null +++ b/test/behaviour/concept/type/attributetype/attribute_type_steps.jl @@ -0,0 +1,135 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + + +#= +from behave import * +from hamcrest import * + +from grakn.concept.type.value_type import ValueType +from tests.behaviour.config.parameters import parse_value_type, parse_list +from tests.behaviour.context import Context + + +@step("put attribute type: {type_label}, with value type: {value_type}") +def step_impl(context: Context, type_label: str, value_type: str): + context.tx().concepts().put_attribute_type(type_label, parse_value_type(value_type)) + + +@step("attribute({type_label}) get value type: {value_type}") +def step_impl(context: Context, type_label: str, value_type: str): + assert_that(context.tx().concepts().get_attribute_type(type_label).get_value_type(), is_(parse_value_type(value_type))) + + +@step("attribute({type_label}) get supertype value type: {value_type}") +def step_impl(context: Context, type_label: str, value_type: str): + supertype = context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).get_supertype() + assert_that(supertype.get_value_type(), is_(parse_value_type(value_type))) + + +def attribute_type_as_value_type(context: Context, type_label: str, value_type: ValueType): + attribute_type = context.tx().concepts().get_attribute_type(type_label) + if value_type is ValueType.OBJECT: + return attribute_type + elif value_type is ValueType.BOOLEAN: + return attribute_type.as_boolean() + elif value_type is ValueType.LONG: + return attribute_type.as_long() + elif value_type is ValueType.DOUBLE: + return attribute_type.as_double() + elif value_type is ValueType.STRING: + return attribute_type.as_string() + elif value_type is ValueType.DATETIME: + return attribute_type.as_datetime() + else: + raise ValueError("Unrecognised value type: " + str(value_type)) + + +@step("attribute({type_label}) as({value_type}) get subtypes contain") +def step_impl(context: Context, type_label: str, value_type: str): + sub_labels = parse_list(context.table) + attribute_type = attribute_type_as_value_type(context, type_label, parse_value_type(value_type)) + actuals = list(map(lambda tt: tt.get_label(), attribute_type.as_remote(context.tx()).get_subtypes())) + for sub_label in sub_labels: + assert_that(sub_label, is_in(actuals)) + + +@step("attribute({type_label}) as({value_type}) get subtypes do not contain") +def step_impl(context: Context, type_label: str, value_type: str): + sub_labels = parse_list(context.table) + attribute_type = attribute_type_as_value_type(context, type_label, parse_value_type(value_type)) + actuals = list(map(lambda tt: tt.get_label(), attribute_type.as_remote(context.tx()).get_subtypes())) + print(parse_value_type(value_type)) + print(attribute_type) + print(actuals) + for sub_label in sub_labels: + assert_that(sub_label, not_(is_in(actuals))) + + +@step("attribute({type_label}) as({value_type}) set regex: {regex}") +def step_impl(context: Context, type_label: str, value_type, regex: str): + value_type = parse_value_type(value_type) + assert_that(value_type, is_(ValueType.STRING)) + attribute_type = attribute_type_as_value_type(context, type_label, value_type) + attribute_type.as_remote(context.tx()).set_regex(regex) + + +@step("attribute({type_label}) as({value_type}) unset regex") +def step_impl(context: Context, type_label: str, value_type): + value_type = parse_value_type(value_type) + assert_that(value_type, is_(ValueType.STRING)) + attribute_type = attribute_type_as_value_type(context, type_label, value_type) + attribute_type.as_remote(context.tx()).set_regex(None) + + +@step("attribute({type_label}) as({value_type}) get regex: {regex}") +def step_impl(context: Context, type_label: str, value_type, regex: str): + value_type = parse_value_type(value_type) + assert_that(value_type, is_(ValueType.STRING)) + attribute_type = attribute_type_as_value_type(context, type_label, value_type) + assert_that(attribute_type.as_remote(context.tx()).get_regex(), is_(regex)) + + +@step("attribute({type_label}) as({value_type}) does not have any regex") +def step_impl(context: Context, type_label: str, value_type): + value_type = parse_value_type(value_type) + assert_that(value_type, is_(ValueType.STRING)) + attribute_type = attribute_type_as_value_type(context, type_label, value_type) + assert_that(attribute_type.as_remote(context.tx()).get_regex(), is_(None)) + + +@step("attribute({type_label}) get key owners contain") +def step_impl(context: Context, type_label: str): + owner_labels = parse_list(context.table) + attribute_type = context.tx().concepts().get_attribute_type(type_label) + actuals = list(map(lambda tt: tt.get_label(), attribute_type.as_remote(context.tx()).get_owners(only_key=True))) + for owner_label in owner_labels: + assert_that(actuals, has_item(owner_label)) + + +@step("attribute({type_label}) get key owners do not contain") +def step_impl(context: Context, type_label: str): + owner_labels = parse_list(context.table) + attribute_type = context.tx().concepts().get_attribute_type(type_label) + actuals = list(map(lambda tt: tt.get_label(), attribute_type.as_remote(context.tx()).get_owners(only_key=True))) + for owner_label in owner_labels: + assert_that(actuals, not_(has_item(owner_label))) + + +@step("attribute({type_label}) get attribute owners contain") +def step_impl(context: Context, type_label: str): + owner_labels = parse_list(context.table) + attribute_type = context.tx().concepts().get_attribute_type(type_label) + actuals = list(map(lambda tt: tt.get_label(), attribute_type.as_remote(context.tx()).get_owners(only_key=False))) + for owner_label in owner_labels: + assert_that(actuals, has_item(owner_label)) + + +@step("attribute({type_label}) get attribute owners do not contain") +def step_impl(context: Context, type_label: str): + owner_labels = parse_list(context.table) + attribute_type = context.tx().concepts().get_attribute_type(type_label) + actuals = list(map(lambda tt: tt.get_label(), attribute_type.as_remote(context.tx()).get_owners(only_key=False))) + for owner_label in owner_labels: + assert_that(actuals, not_(has_item(owner_label))) +=# \ No newline at end of file diff --git a/test/behaviour/concept/type/relationtype/relation_type_steps.jl b/test/behaviour/concept/type/relationtype/relation_type_steps.jl new file mode 100644 index 00000000..c0270cee --- /dev/null +++ b/test/behaviour/concept/type/relationtype/relation_type_steps.jl @@ -0,0 +1,168 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + +#= +from behave import * +from hamcrest import * + +from grakn.common.exception import GraknClientException +from grakn.concept.type.value_type import ValueType +from tests.behaviour.config.parameters import parse_value_type, parse_list, parse_bool +from tests.behaviour.context import Context + + +@step("relation({relation_label}) set relates role: {role_label} as {super_role}; throws exception") +def step_impl(context: Context, relation_label: str, role_label: str, super_role: str): + try: + context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).set_relates(role_label, overridden_label=super_role) + assert False + except GraknClientException: + pass + + +@step("relation({relation_label}) set relates role: {role_label} as {super_role}") +def step_impl(context: Context, relation_label: str, role_label: str, super_role: str): + context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).set_relates(role_label, overridden_label=super_role) + + +@step("relation({relation_label}) set relates role: {role_label}; throws exception") +def step_impl(context: Context, relation_label: str, role_label: str): + try: + context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).set_relates(role_label) + assert False + except GraknClientException: + pass + + +@step("relation({relation_label}) set relates role: {role_label}") +def step_impl(context: Context, relation_label: str, role_label: str): + context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).set_relates(role_label) + + +@step("relation({relation_label}) unset related role: {role_label}; throws exception") +def step_impl(context: Context, relation_label: str, role_label: str): + try: + context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).unset_relates(role_label) + assert False + except GraknClientException: + pass + + +@step("relation({relation_label}) unset related role: {role_label}") +def step_impl(context: Context, relation_label: str, role_label: str): + context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).unset_relates(role_label) + + +@step("relation({relation_label}) remove related role: {role_label}") +def step_impl(context: Context, relation_label: str, role_label: str): + context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).get_relates(role_label).as_remote(context.tx()).delete() + + +@step("relation({relation_label}) get role({role_label}) is null: {is_null}") +def step_impl(context: Context, relation_label: str, role_label: str, is_null): + is_null = parse_bool(is_null) + assert_that(context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).get_relates(role_label) is None, is_(is_null)) + + +@step("relation({relation_label}) get role({role_label}) set label: {new_label}") +def step_impl(context: Context, relation_label: str, role_label: str, new_label: str): + context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).get_relates(role_label).as_remote(context.tx()).set_label(new_label) + + +@step("relation({relation_label}) get role({role_label}) get label: {get_label}") +def step_impl(context: Context, relation_label: str, role_label: str, get_label: str): + assert_that(context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).get_relates(role_label).as_remote(context.tx()).get_label(), is_(get_label)) + + +@step("relation({relation_label}) get role({role_label}) is abstract: {is_abstract}") +def step_impl(context: Context, relation_label: str, role_label: str, is_abstract): + is_abstract = parse_bool(is_abstract) + assert_that(context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).get_relates(role_label).as_remote(context.tx()).is_abstract(), is_(is_abstract)) + + +def get_actual_related_role_scoped_labels(context: Context, relation_label: str): + return [r.get_scoped_label() for r in context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).get_relates()] + + +@step("relation({relation_label}) get related roles contain") +def step_impl(context: Context, relation_label: str): + role_labels = parse_list(context.table) + actuals = get_actual_related_role_scoped_labels(context, relation_label) + for role_label in role_labels: + assert_that(actuals, has_item(role_label)) + + +@step("relation({relation_label}) get related roles do not contain") +def step_impl(context: Context, relation_label: str): + role_labels = parse_list(context.table) + actuals = get_actual_related_role_scoped_labels(context, relation_label) + for role_label in role_labels: + assert_that(actuals, not_(has_item(role_label))) + + +@step("relation({relation_label}) get role({role_label}) get supertype: {super_scope}:{super_label}") +def step_impl(context: Context, relation_label: str, role_label: str, super_scope: str, super_label: str): + supertype = context.tx().concepts().get_relation_type(super_scope).as_remote(context.tx()).get_relates(super_label) + assert_that(supertype, is_(context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).get_relates(role_label).as_remote(context.tx()).get_supertype())) + + +def get_actual_related_role_supertypes_scoped_labels(context: Context, relation_label: str, role_label: str): + return [r.get_scoped_label() for r in context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).get_relates(role_label).as_remote(context.tx()).get_supertypes()] + + +@step("relation({relation_label}) get role({role_label}) get supertypes contain") +def step_impl(context: Context, relation_label: str, role_label: str): + super_labels = parse_list(context.table) + actuals = get_actual_related_role_supertypes_scoped_labels(context, relation_label, role_label) + for super_label in super_labels: + assert_that(actuals, has_item(super_label)) + + +@step("relation({relation_label}) get role({role_label}) get supertypes do not contain") +def step_impl(context: Context, relation_label: str, role_label: str): + super_labels = parse_list(context.table) + actuals = get_actual_related_role_supertypes_scoped_labels(context, relation_label, role_label) + for super_label in super_labels: + assert_that(actuals, not_(has_item(super_label))) + + +def get_actual_related_role_players_scoped_labels(context: Context, relation_label: str, role_label: str): + return [r.get_label() for r in context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).get_relates(role_label).as_remote(context.tx()).get_players()] + + +@step("relation({relation_label}) get role({role_label}) get players contain") +def step_impl(context: Context, relation_label: str, role_label: str): + player_labels = parse_list(context.table) + actuals = get_actual_related_role_players_scoped_labels(context, relation_label, role_label) + for player_label in player_labels: + assert_that(actuals, has_item(player_label)) + + +@step("relation({relation_label}) get role({role_label}) get players do not contain") +def step_impl(context: Context, relation_label: str, role_label: str): + player_labels = parse_list(context.table) + actuals = get_actual_related_role_players_scoped_labels(context, relation_label, role_label) + for player_label in player_labels: + assert_that(actuals, not_(has_item(player_label))) + + +def get_actual_related_role_subtypes_scoped_labels(context: Context, relation_label: str, role_label: str): + return [r.get_scoped_label() for r in context.tx().concepts().get_relation_type(relation_label).as_remote(context.tx()).get_relates(role_label).as_remote(context.tx()).get_subtypes()] + + +@step("relation({relation_label}) get role({role_label}) get subtypes contain") +def step_impl(context: Context, relation_label: str, role_label: str): + sub_labels = parse_list(context.table) + actuals = get_actual_related_role_subtypes_scoped_labels(context, relation_label, role_label) + for sub_label in sub_labels: + assert_that(actuals, has_item(sub_label)) + + +@step("relation({relation_label}) get role({role_label}) get subtypes do not contain") +def step_impl(context: Context, relation_label: str, role_label: str): + sub_labels = parse_list(context.table) + actuals = get_actual_related_role_subtypes_scoped_labels(context, relation_label, role_label) + for sub_label in sub_labels: + assert_that(actuals, not_(has_item(sub_label))) + +=# \ No newline at end of file diff --git a/test/behaviour/concept/type/thingtype/thing_type_steps.jl b/test/behaviour/concept/type/thingtype/thing_type_steps.jl new file mode 100644 index 00000000..1f4792fe --- /dev/null +++ b/test/behaviour/concept/type/thingtype/thing_type_steps.jl @@ -0,0 +1,366 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + + +#= +from behave import * +from hamcrest import * + +from grakn.common.exception import GraknClientException +from grakn.concept.thing.thing import Thing +from tests.behaviour.config.parameters import parse_bool, parse_list, RootLabel +from tests.behaviour.context import Context + + +@step("put {root_label:RootLabel} type: {type_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + if root_label == RootLabel.ENTITY: + context.tx().concepts().put_entity_type(type_label) + elif root_label == RootLabel.RELATION: + context.tx().concepts().put_relation_type(type_label) + else: + raise ValueError("Unrecognised value") + + +@step("delete {root_label:RootLabel} type: {type_label}; throws exception") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + try: + context.get_thing_type(root_label, type_label).as_remote(context.tx()).delete() + assert False + except GraknClientException: + pass + + +@step("delete {root_label:RootLabel} type: {type_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + context.get_thing_type(root_label, type_label).as_remote(context.tx()).delete() + + +@step("{root_label:RootLabel}({type_label}) is null: {is_null}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, is_null): + is_null = parse_bool(is_null) + assert_that(context.get_thing_type(root_label, type_label) is None, is_(is_null)) + + +@step("{root_label:RootLabel}({type_label}) set label: {new_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, new_label: str): + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_label(new_label) + + +@step("{root_label:RootLabel}({type_label}) get label: {get_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, get_label: str): + assert_that(context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_label(), is_(get_label)) + + +@step("{root_label:RootLabel}({type_label}) set abstract: {is_abstract}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, is_abstract): + is_abstract = parse_bool(is_abstract) + thing_type = context.get_thing_type(root_label, type_label) + if is_abstract: + thing_type.as_remote(context.tx()).set_abstract() + else: + thing_type.as_remote(context.tx()).unset_abstract() + + +@step("{root_label:RootLabel}({type_label}) is abstract: {is_abstract}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, is_abstract): + is_abstract = parse_bool(is_abstract) + assert_that(context.get_thing_type(root_label, type_label).as_remote(context.tx()).is_abstract(), is_(is_abstract)) + + +@step("{root_label:RootLabel}({type_label}) set supertype: {super_label}; throws exception") +def step_impl(context: Context, root_label: RootLabel, type_label: str, super_label: str): + if root_label == RootLabel.ENTITY: + entity_supertype = context.tx().concepts().get_entity_type(super_label) + try: + context.tx().concepts().get_entity_type(type_label).as_remote(context.tx()).set_supertype(entity_supertype) + assert False + except GraknClientException: + pass + elif root_label == RootLabel.ATTRIBUTE: + attribute_supertype = context.tx().concepts().get_attribute_type(super_label) + try: + context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).set_supertype(attribute_supertype) + assert False + except GraknClientException: + pass + elif root_label == RootLabel.RELATION: + relation_supertype = context.tx().concepts().get_relation_type(super_label) + try: + context.tx().concepts().get_relation_type(type_label).as_remote(context.tx()).set_supertype(relation_supertype) + assert False + except GraknClientException: + pass + else: + raise ValueError("Unrecognised value") + + +@step("{root_label:RootLabel}({type_label}) set supertype: {super_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, super_label: str): + if root_label == RootLabel.ENTITY: + entity_supertype = context.tx().concepts().get_entity_type(super_label) + context.tx().concepts().get_entity_type(type_label).as_remote(context.tx()).set_supertype(entity_supertype) + elif root_label == RootLabel.ATTRIBUTE: + attribute_supertype = context.tx().concepts().get_attribute_type(super_label) + context.tx().concepts().get_attribute_type(type_label).as_remote(context.tx()).set_supertype(attribute_supertype) + elif root_label == RootLabel.RELATION: + relation_supertype = context.tx().concepts().get_relation_type(super_label) + context.tx().concepts().get_relation_type(type_label).as_remote(context.tx()).set_supertype(relation_supertype) + else: + raise ValueError("Unrecognised value") + + +@step("{root_label:RootLabel}({type_label}) get supertype: {super_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, super_label: str): + supertype = context.get_thing_type(root_label, super_label) + assert_that(context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_supertype(), is_(supertype)) + + +@step("{root_label:RootLabel}({type_label}) get supertypes contain") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + super_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_supertypes())) + for super_label in super_labels: + assert_that(super_label, is_in(actuals)) + + +@step("{root_label:RootLabel}({type_label}) get supertypes do not contain") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + super_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_supertypes())) + for super_label in super_labels: + assert_that(super_label, not_(is_in(actuals))) + + +@step("{root_label:RootLabel}({type_label}) get subtypes contain") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + sub_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_subtypes())) + for sub_label in sub_labels: + assert_that(sub_label, is_in(actuals)) + + +@step("{root_label:RootLabel}({type_label}) get subtypes do not contain") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + sub_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_subtypes())) + for sub_label in sub_labels: + assert_that(sub_label, not_(is_in(actuals))) + + +@step("{root_label:RootLabel}({type_label}) set owns key type: {att_type_label} as {overridden_label}; throws exception") +def step_impl(context: Context, root_label: RootLabel, type_label: str, att_type_label: str, overridden_label: str): + attribute_type = context.tx().concepts().get_attribute_type(att_type_label) + overridden_type = context.tx().concepts().get_attribute_type(overridden_label) + try: + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_owns(attribute_type, overridden_type, is_key=True) + assert False + except GraknClientException: + pass + + +@step("{root_label:RootLabel}({type_label}) set owns key type: {att_type_label}; throws exception") +def step_impl(context: Context, root_label: RootLabel, type_label: str, att_type_label: str): + attribute_type = context.tx().concepts().get_attribute_type(att_type_label) + try: + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_owns(attribute_type, is_key=True) + assert False + except GraknClientException: + pass + + +@step("{root_label:RootLabel}({type_label}) set owns key type: {att_type_label} as {overridden_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, att_type_label: str, overridden_label: str): + attribute_type = context.tx().concepts().get_attribute_type(att_type_label) + overridden_type = context.tx().concepts().get_attribute_type(overridden_label) + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_owns(attribute_type, overridden_type, is_key=True) + + +@step("{root_label:RootLabel}({type_label}) set owns key type: {att_type_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, att_type_label: str): + attribute_type = context.tx().concepts().get_attribute_type(att_type_label) + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_owns(attribute_type, is_key=True) + + +@step("{root_label:RootLabel}({type_label}) unset owns attribute type: {att_type_label}; throws exception") +@step("{root_label:RootLabel}({type_label}) unset owns key type: {att_type_label}; throws exception") +def step_impl(context: Context, root_label: RootLabel, type_label: str, att_type_label: str): + attribute_type = context.tx().concepts().get_attribute_type(att_type_label) + try: + context.get_thing_type(root_label, type_label).as_remote(context.tx()).unset_owns(attribute_type) + assert False + except GraknClientException: + pass + + +@step("{root_label:RootLabel}({type_label}) unset owns attribute type: {att_type_label}") +@step("{root_label:RootLabel}({type_label}) unset owns key type: {att_type_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, att_type_label: str): + attribute_type = context.tx().concepts().get_attribute_type(att_type_label) + context.get_thing_type(root_label, type_label).as_remote(context.tx()).unset_owns(attribute_type) + + +@step("{root_label:RootLabel}({type_label}) get owns key types contain") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + attribute_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_owns(keys_only=True))) + for attribute_label in attribute_labels: + assert_that(attribute_label, is_in(actuals)) + + +@step("{root_label:RootLabel}({type_label}) get owns key types do not contain") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + attribute_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_owns(keys_only=True))) + for attribute_label in attribute_labels: + assert_that(attribute_label, not_(is_in(actuals))) + + +@step("{root_label:RootLabel}({type_label}) set owns attribute type: {att_type_label} as {overridden_label}; throws exception") +def step_impl(context: Context, root_label: RootLabel, type_label: str, att_type_label: str, overridden_label: str): + attribute_type = context.tx().concepts().get_attribute_type(att_type_label) + overridden_type = context.tx().concepts().get_attribute_type(overridden_label) + try: + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_owns(attribute_type, overridden_type) + assert False + except GraknClientException: + pass + + +@step("{root_label:RootLabel}({type_label}) set owns attribute type: {att_type_label}; throws exception") +def step_impl(context: Context, root_label: RootLabel, type_label: str, att_type_label: str): + attribute_type = context.tx().concepts().get_attribute_type(att_type_label) + try: + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_owns(attribute_type) + assert False + except GraknClientException: + pass + + +@step("{root_label:RootLabel}({type_label}) set owns attribute type: {att_type_label} as {overridden_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, att_type_label: str, overridden_label: str): + attribute_type = context.tx().concepts().get_attribute_type(att_type_label) + overridden_type = context.tx().concepts().get_attribute_type(overridden_label) + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_owns(attribute_type, overridden_type) + + +@step("{root_label:RootLabel}({type_label}) set owns attribute type: {att_type_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, att_type_label: str): + attribute_type = context.tx().concepts().get_attribute_type(att_type_label) + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_owns(attribute_type) + + +@step("{root_label:RootLabel}({type_label}) get owns attribute types contain") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + attribute_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_owns())) + for attribute_label in attribute_labels: + assert_that(attribute_label, is_in(actuals)) + + +@step("{root_label:RootLabel}({type_label}) get owns attribute types do not contain") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + attribute_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_owns())) + for attribute_label in attribute_labels: + assert_that(attribute_label, not_(is_in(actuals))) + + +@step("{root_label:RootLabel}({type_label}) set plays role: {scope}:{role_label} as {overridden_scope}:{overridden_label}; throws exception") +def step_impl(context: Context, root_label: RootLabel, type_label: str, scope: str, role_label: str, overridden_scope: str, overridden_label: str): + role_type = context.tx().concepts().get_relation_type(scope).as_remote(context.tx()).get_relates(role_label) + overridden_type = context.tx().concepts().get_relation_type(overridden_scope).as_remote(context.tx()).get_relates(overridden_label) + try: + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_plays(role_type, overridden_type) + assert False + except GraknClientException: + pass + + +@step("{root_label:RootLabel}({type_label}) set plays role: {scope}:{role_label} as {overridden_scope}:{overridden_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, scope: str, role_label: str, overridden_scope: str, overridden_label: str): + role_type = context.tx().concepts().get_relation_type(scope).as_remote(context.tx()).get_relates(role_label) + overridden_type = context.tx().concepts().get_relation_type(overridden_scope).as_remote(context.tx()).get_relates(overridden_label) + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_plays(role_type, overridden_type) + + +@step("{root_label:RootLabel}({type_label}) set plays role: {scope}:{role_label}; throws exception") +def step_impl(context: Context, root_label: RootLabel, type_label: str, scope: str, role_label: str): + role_type = context.tx().concepts().get_relation_type(scope).as_remote(context.tx()).get_relates(role_label) + try: + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_plays(role_type) + assert False + except GraknClientException: + pass + + +@step("{root_label:RootLabel}({type_label}) set plays role: {scope}:{role_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, scope: str, role_label: str): + role_type = context.tx().concepts().get_relation_type(scope).as_remote(context.tx()).get_relates(role_label) + context.get_thing_type(root_label, type_label).as_remote(context.tx()).set_plays(role_type) + + +@step("{root_label:RootLabel}({type_label}) unset plays role: {scope}:{role_label}; throws exception") +def step_impl(context: Context, root_label: RootLabel, type_label: str, scope: str, role_label: str): + role_type = context.tx().concepts().get_relation_type(scope).as_remote(context.tx()).get_relates(role_label) + try: + context.get_thing_type(root_label, type_label).as_remote(context.tx()).unset_plays(role_type) + assert False + except GraknClientException: + pass + + +@step("{root_label:RootLabel}({type_label}) unset plays role: {scope}:{role_label}") +def step_impl(context: Context, root_label: RootLabel, type_label: str, scope: str, role_label: str): + role_type = context.tx().concepts().get_relation_type(scope).as_remote(context.tx()).get_relates(role_label) + context.get_thing_type(root_label, type_label).as_remote(context.tx()).unset_plays(role_type) + + +@step("{root_label:RootLabel}({type_label}) get playing roles contain") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + role_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_scoped_label(), context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_plays())) + for role_label in role_labels: + assert_that(role_label, is_in(actuals)) + + +@step("{root_label:RootLabel}({type_label}) get playing roles do not contain") +def step_impl(context: Context, root_label: RootLabel, type_label: str): + role_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_scoped_label(), context.get_thing_type(root_label, type_label).as_remote(context.tx()).get_plays())) + for role_label in role_labels: + assert_that(role_label, not_(is_in(actuals))) + + +@step("thing type root get supertypes contain") +def step_impl(context: Context): + super_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.tx().concepts().get_root_thing_type().as_remote(context.tx()).get_supertypes())) + for super_label in super_labels: + assert_that(super_label, is_in(actuals)) + + +@step("thing type root get supertypes do not contain") +def step_impl(context: Context): + super_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.tx().concepts().get_root_thing_type().as_remote(context.tx()).get_supertypes())) + for super_label in super_labels: + assert_that(super_label, not_(is_in(actuals))) + + +@step("thing type root get subtypes contain") +def step_impl(context: Context): + super_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.tx().concepts().get_root_thing_type().as_remote(context.tx()).get_subtypes())) + for super_label in super_labels: + assert_that(super_label, is_in(actuals)) + + +@step("thing type root get subtypes do not contain") +def step_impl(context: Context): + super_labels = parse_list(context.table) + actuals = list(map(lambda t: t.get_label(), context.tx().concepts().get_root_thing_type().as_remote(context.tx()).get_subtypes())) + for super_label in super_labels: + assert_that(super_label, not_(is_in(actuals))) + +=# \ No newline at end of file diff --git a/test/behaviour/config/parameters.jl b/test/behaviour/config/parameters.jl new file mode 100644 index 00000000..7cb6bafb --- /dev/null +++ b/test/behaviour/config/parameters.jl @@ -0,0 +1,134 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + + +#= +from datetime import datetime +from enum import Enum +from typing import List, Dict, Tuple + +import parse +from behave import register_type +from behave.model import Table + +from grakn.concept.type.value_type import ValueType +from grakn.rpc.transaction import TransactionType + +# TODO: We aren't consistently using typed parameters in step implementations - we should be. + +@parse.with_pattern(r"true|false") +def parse_bool(value: str) -> bool: + return value == "true" + + +register_type(Bool=parse_bool) + + +def parse_int(text: str) -> int: + return int(text) + + +register_type(Int=parse_int) + + +def parse_float(text: str) -> float: + return float(text) + + +register_type(Float=parse_float) + + +@parse.with_pattern(r"\d\d\d\d-\d\d-\d\d(?: \d\d:\d\d:\d\d)?") +def parse_datetime(text: str) -> datetime: + try: + return datetime.strptime(text, "%Y-%m-%d %H:%M:%S") + except ValueError: + return datetime.strptime(text, "%Y-%m-%d") + + +register_type(DateTime=parse_datetime) + + +class RootLabel(Enum): + ENTITY = 0, + ATTRIBUTE = 1, + RELATION = 2 + + +@parse.with_pattern(r"entity|attribute|relation") +def parse_root_label(text: str) -> RootLabel: + if text == "entity": + return RootLabel.ENTITY + elif text == "attribute": + return RootLabel.ATTRIBUTE + elif text == "relation": + return RootLabel.RELATION + else: + raise ValueError("Unrecognised root label: " + text) + + +register_type(RootLabel=parse_root_label) + + +@parse.with_pattern(r"\$([a-zA-Z0-9]+)") +def parse_var(text: str): + return text + + +register_type(Var=parse_var) + + +@parse.with_pattern(r"long|double|string|boolean|datetime") +def parse_value_type(value: str) -> ValueType: + mapping = { + "long": ValueType.LONG, + "double": ValueType.DOUBLE, + "string": ValueType.STRING, + "boolean": ValueType.BOOLEAN, + "datetime": ValueType.DATETIME + } + return mapping[value] + + +register_type(ValueType=parse_value_type) + + +@parse.with_pattern("read|write") +def parse_transaction_type(value: str) -> TransactionType: + return TransactionType.READ if value == "read" else TransactionType.WRITE + + +register_type(TransactionType=parse_transaction_type) + + +def parse_list(table: Table) -> List[str]: + return [table.headings[0]] + list(map(lambda row: row[0], table.rows)) + + +def parse_dict(table: Table) -> Dict[str, str]: + result = {table.headings[0]: table.headings[1]} + for row in table.rows: + result[row[0]] = row[1] + return result + + +def parse_table(table: Table) -> List[List[Tuple[str, str]]]: + """ + Extracts the rows of a Table as lists of Tuples, where each Tuple contains the column header and the cell value. + + For example, the table:: + + | x | type | + | key:ref:0 | label:person | + | key:ref:2 | label:dog | + + is converted to:: + + [ + [('x', 'key:ref:0'), ('type', 'label:person')], + [('x', 'key:ref:2'), ('type', 'label:dog')] + ] + """ + return [[(table.headings[idx], row[idx]) for idx in range(len(row))] for row in table.rows] + + =# \ No newline at end of file diff --git a/test/behaviour/connection/connection_steps.jl b/test/behaviour/connection/connection_steps.jl new file mode 100644 index 00000000..cc436b5e --- /dev/null +++ b/test/behaviour/connection/connection_steps.jl @@ -0,0 +1,29 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + +using ExecutableSpecifications + +@then "connection has been opened" do context + @expect context[:cllient] !== nothing && is_open(context[:client]) +end + +@then "connection does not have any database" do context + @expect length(get_all(databases(context[:client]))) == 0 +end + + +#= +from behave import * + +from tests.behaviour.context import Context + + +@step("connection has been opened") +def step_impl(context: Context): + assert context.client and context.client.is_open() + + +@step("connection does not have any database") +def step_impl(context: Context): + assert len(context.client.databases().all()) == 0 + +=# \ No newline at end of file diff --git a/test/behaviour/connection/database/database_steps.jl b/test/behaviour/connection/database/database_steps.jl new file mode 100644 index 00000000..a22a55cc --- /dev/null +++ b/test/behaviour/connection/database/database_steps.jl @@ -0,0 +1,119 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + + + + +#= +from concurrent.futures.thread import ThreadPoolExecutor +from functools import partial +from typing import List + +from behave import * +from hamcrest import * + +from grakn.common.exception import GraknClientException +from tests.behaviour.config.parameters import parse_list +from tests.behaviour.context import Context +from tests.behaviour.util import assert_collections_equal + + +def create_databases(context: Context, names: List[str]): + for name in names: + context.client.databases().create(name) + + +@step("connection create database: {database_name}") +def step_impl(context: Context, database_name: str): + create_databases(context, [database_name]) + + +# TODO: connection create database(s) in other implementations, simplify +@step("connection create databases") +def step_impl(context: Context): + names = parse_list(context.table) + create_databases(context, names) + + +@step("connection create databases in parallel") +def step_impl(context: Context): + names = parse_list(context.table) + assert_that(len(names), is_(less_than_or_equal_to(context.THREAD_POOL_SIZE))) + with ThreadPoolExecutor(max_workers=context.THREAD_POOL_SIZE) as executor: + for name in names: + executor.submit(partial(context.client.databases().create, name)) + + +def delete_databases(context: Context, names: List[str]): + for name in names: + context.client.databases().get(name).delete() + + +@step("connection delete database: {name}") +def step_impl(context: Context, name: str): + delete_databases(context, [name]) + + +@step("connection delete databases") +def step_impl(context: Context): + delete_databases(context, names=parse_list(context.table)) + + +def delete_databases_throws_exception(context: Context, names: List[str]): + for name in names: + try: + context.client.databases().get(name).delete() + assert False + except GraknClientException as e: + pass + + +@step("connection delete database; throws exception: {name}") +def step_impl(context: Context, name: str): + delete_databases_throws_exception(context, [name]) + + +@step("connection delete databases; throws exception") +def step_impl(context: Context): + delete_databases_throws_exception(context, names=parse_list(context.table)) + + +@step("connection delete databases in parallel") +def step_impl(context: Context): + names = parse_list(context.table) + assert_that(len(names), is_(less_than_or_equal_to(context.THREAD_POOL_SIZE))) + with ThreadPoolExecutor(max_workers=context.THREAD_POOL_SIZE) as executor: + for name in names: + executor.submit(partial(context.client.databases().get(name).delete)) + + +def has_databases(context: Context, names: List[str]): + assert_collections_equal([db.name() for db in context.client.databases().all()], names) + + +@step("connection has database: {name}") +def step_impl(context: Context, name: str): + has_databases(context, [name]) + + +@step("connection has databases") +def step_impl(context: Context): + has_databases(context, names=parse_list(context.table)) + + +def does_not_have_databases(context: Context, names: List[str]): + databases = [db.name() for db in context.client.databases().all()] + for name in names: + assert_that(name, not_(is_in(databases))) + + +@step("connection does not have database: {name}") +def step_impl(context: Context, name: str): + does_not_have_databases(context, [name]) + + +@step("connection does not have databases") +def step_impl(context: Context): + does_not_have_databases(context, names=parse_list(context.table)) + +=# \ No newline at end of file diff --git a/test/behaviour/connection/session/session_steps.jl b/test/behaviour/connection/session/session_steps.jl new file mode 100644 index 00000000..8f43a445 --- /dev/null +++ b/test/behaviour/connection/session/session_steps.jl @@ -0,0 +1,131 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + + +#= +from concurrent.futures.thread import ThreadPoolExecutor +from functools import partial +from typing import List + +from behave import * +from hamcrest import * + +from grakn.rpc.session import SessionType +from tests.behaviour.config.parameters import parse_bool, parse_list +from tests.behaviour.context import Context + + +def open_sessions_for_databases(context: Context, names: list, session_type=SessionType.DATA): + for name in names: + context.sessions.append(context.client.session(name, session_type)) + + +@step("connection open schema session for database: {database_name}") +def step_impl(context: Context, database_name): + open_sessions_for_databases(context, [database_name], SessionType.SCHEMA) + + +@step("connection open data session for database: {database_name}") +@step("connection open session for database: {database_name}") +def step_impl(context: Context, database_name: str): + open_sessions_for_databases(context, [database_name], SessionType.DATA) + + +@step("connection open schema session for database") +@step("connection open schema session for databases") +@step("connection open schema sessions for database") +@step("connection open schema sessions for databases") +def step_impl(context: Context): + names = parse_list(context.table) + open_sessions_for_databases(context, names, SessionType.SCHEMA) + + +@step("connection open data session for database") +@step("connection open data session for databases") +@step("connection open data sessions for database") +@step("connection open data sessions for databases") +@step("connection open session for database") +@step("connection open session for databases") +@step("connection open sessions for database") +@step("connection open sessions for databases") +def step_impl(context: Context): + names = parse_list(context.table) + open_sessions_for_databases(context, names, SessionType.DATA) + + +@step("connection open data sessions in parallel for databases") +@step("connection open sessions in parallel for databases") +def step_impl(context: Context): + names = parse_list(context.table) + assert_that(len(names), is_(less_than_or_equal_to(context.THREAD_POOL_SIZE))) + with ThreadPoolExecutor(max_workers=context.THREAD_POOL_SIZE) as executor: + for name in names: + context.sessions_parallel.append(executor.submit(partial(context.client.session, name, SessionType.DATA))) + + +@step("connection close all sessions") +def step_impl(context: Context): + for session in context.sessions: + session.close() + context.sessions = [] + + +@step("session is null: {is_null}") +@step("sessions are null: {is_null}") +def step_impl(context: Context, is_null): + is_null = parse_bool(is_null) + for session in context.sessions: + assert_that(session is None, is_(is_null)) + + +@step("session is open: {is_open}") +@step("sessions are open: {is_open}") +def step_impl(context: Context, is_open): + is_open = parse_bool(is_open) + for session in context.sessions: + assert_that(session.is_open(), is_(is_open)) + + +@step("sessions in parallel are null: {is_null}") +def step_impl(context: Context, is_null): + is_null = parse_bool(is_null) + for future_session in context.sessions_parallel: + assert_that(future_session.result() is None, is_(is_null)) + + +@step("sessions in parallel are open: {is_open}") +def step_impl(context: Context, is_open): + is_open = parse_bool(is_open) + for future_session in context.sessions_parallel: + assert_that(future_session.result().is_open(), is_(is_open)) + + +def sessions_have_databases(context: Context, names: List[str]): + assert_that(context.sessions, has_length(equal_to(len(names)))) + session_iter = iter(context.sessions) + for name in names: + assert_that(next(session_iter).database().name(), is_(name)) + + +@step("session has database: {database_name}") +@step("sessions have database: {database_name}") +def step_impl(context: Context, database_name: str): + sessions_have_databases(context, [database_name]) + + +# TODO: session(s) has/have databases in other implementations, simplify +@step("sessions have databases") +def step_impl(context: Context): + database_names = parse_list(context.table) + sessions_have_databases(context, database_names) + + +@step("sessions in parallel have databases") +def step_impl(context: Context): + database_names = parse_list(context.table) + assert_that(context.sessions_parallel, has_length(equal_to(len(database_names)))) + future_session_iter = iter(context.sessions_parallel) + for name in database_names: + assert_that(next(future_session_iter).result().database().name(), is_(name)) + +=# \ No newline at end of file diff --git a/test/behaviour/connection/transaction/transaction_steps.jl b/test/behaviour/connection/transaction/transaction_steps.jl new file mode 100644 index 00000000..f76cd220 --- /dev/null +++ b/test/behaviour/connection/transaction/transaction_steps.jl @@ -0,0 +1,251 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + +#= +from concurrent.futures.thread import ThreadPoolExecutor +from functools import partial +from typing import Callable, List + +from behave import * +from hamcrest import * + +from grakn.common.exception import GraknClientException +from grakn.rpc.transaction import TransactionType, Transaction +from tests.behaviour.config.parameters import parse_transaction_type, parse_list, parse_bool +from tests.behaviour.context import Context + + +def for_each_session_open_transaction_of_type(context: Context, transaction_types: List[TransactionType]): + for session in context.sessions: + transactions = [] + for transaction_type in transaction_types: + transaction = session.transaction(transaction_type) + transactions.append(transaction) + context.sessions_to_transactions[session] = transactions + + +# TODO: this is implemented as open(s) in some clients - get rid of that, simplify them +@step("session opens transaction of type: {transaction_type}") +@step("for each session, open transaction of type: {transaction_type}") +def step_impl(context: Context, transaction_type: str): + transaction_type = parse_transaction_type(transaction_type) + for_each_session_open_transaction_of_type(context, [transaction_type]) + + +@step("for each session, open transaction of type") +@step("for each session, open transactions of type") +def step_impl(context: Context): + transaction_types = list(map(parse_transaction_type, parse_list(context.table))) + for_each_session_open_transaction_of_type(context, transaction_types) + + +def open_transactions_of_type_throws_exception(context: Context, transaction_types: List[TransactionType]): + for session in context.sessions: + for transaction_type in transaction_types: + try: + session.transaction(transaction_type) + assert False + except GraknClientException: + pass + + +@step("session open transaction of type; throws exception: {transaction_type}") +def step_impl(context: Context, transaction_type): + print("Running step: session open transaction of type; throws exception") + transaction_type = parse_transaction_type(transaction_type) + open_transactions_of_type_throws_exception(context, [transaction_type]) + + +# TODO: transaction(s) in other implementations, simplify +@step("for each session, open transactions of type; throws exception") +def step_impl(context: Context): + open_transactions_of_type_throws_exception(context, list(map(lambda raw_type: parse_transaction_type(raw_type), parse_list(context.table)))) + + +def for_each_session_transactions_are(context: Context, assertion: Callable[[Transaction], None]): + for session in context.sessions: + for transaction in context.sessions_to_transactions[session]: + assertion(transaction) + + +def assert_transaction_null(transaction: Transaction, is_null: bool): + assert_that(transaction is None, is_(is_null)) + + +@step("session transaction is null: {is_null}") +@step("for each session, transaction is null: {is_null}") +@step("for each session, transactions are null: {is_null}") +def step_impl(context: Context, is_null): + is_null = parse_bool(is_null) + for_each_session_transactions_are(context, lambda tx: assert_transaction_null(tx, is_null)) + + +def assert_transaction_open(transaction: Transaction, is_open: bool): + assert_that(transaction.is_open(), is_(is_open)) + + +@step("session transaction is open: {is_open}") +@step("for each session, transaction is open: {is_open}") +@step("for each session, transactions are open: {is_open}") +def step_impl(context: Context, is_open): + is_open = parse_bool(is_open) + for_each_session_transactions_are(context, lambda tx: assert_transaction_open(tx, is_open)) + + +@step("session transaction commits") +@step("transaction commits") +def step_impl(context: Context): + context.tx().commit() + + +@step("session transaction commits; throws exception") +@step("transaction commits; throws exception") +def step_impl(context: Context): + try: + context.tx().commit() + assert False + except GraknClientException: + pass + + +@step("transaction commits; throws exception containing \"{exception}\"") +def step_impl(context: Context, exception: str): + assert_that(calling(context.tx().commit), raises(GraknClientException, exception)) + + +@step("for each session, transaction commits") +@step("for each session, transactions commit") +def step_impl(context: Context): + for session in context.sessions: + for transaction in context.sessions_to_transactions[session]: + transaction.commit() + + +@step("for each session, transaction commits; throws exception") +@step("for each session, transactions commit; throws exception") +def step_impl(context: Context): + for session in context.sessions: + for transaction in context.sessions_to_transactions[session]: + try: + transaction.commit() + assert False + except GraknClientException: + pass + + +# TODO: close(s) in other implementations - simplify +@step("for each session, transaction closes") +def step_impl(context: Context): + for session in context.sessions: + for transaction in context.sessions_to_transactions[session]: + transaction.close() + + +def for_each_session_transaction_has_type(context: Context, transaction_types: list): + for session in context.sessions: + transactions = context.sessions_to_transactions[session] + assert_that(transactions, has_length(len(transaction_types))) + transactions_iterator = iter(transactions) + for transaction_type in transaction_types: + assert_that(next(transactions_iterator).transaction_type(), is_(transaction_type)) + + +# NOTE: behave ignores trailing colons in feature files +@step("for each session, transaction has type") +@step("for each session, transactions have type") +def step_impl(context: Context): + transaction_types = list(map(parse_transaction_type, parse_list(context.table))) + for_each_session_transaction_has_type(context, transaction_types) + + +# TODO: this is overcomplicated in some clients (has/have, transaction(s)) +@step("for each session, transaction has type: {transaction_type}") +@step("session transaction has type: {transaction_type}") +def step_impl(context: Context, transaction_type): + transaction_type = parse_transaction_type(transaction_type) + for_each_session_transaction_has_type(context, [transaction_type]) + + +############################################## +# sequential sessions, parallel transactions # +############################################## + +# TODO: transaction(s) in other implementations - simplify +@step("for each session, open transactions in parallel of type") +def step_impl(context: Context): + types = list(map(parse_transaction_type, parse_list(context.table))) + assert_that(len(types), is_(less_than_or_equal_to(context.THREAD_POOL_SIZE))) + with ThreadPoolExecutor(max_workers=context.THREAD_POOL_SIZE) as executor: + for session in context.sessions: + context.sessions_to_transactions_parallel[session] = [] + for type_ in types: + context.sessions_to_transactions_parallel[session].append(executor.submit(partial(session.transaction, type_))) + + +def for_each_session_transactions_in_parallel_are(context: Context, assertion: Callable[[Transaction], None]): + for session in context.sessions: + for future_transaction in context.sessions_to_transactions_parallel[session]: + assertion(future_transaction.result()) + + +@step("for each session, transactions in parallel are null: {is_null}") +def step_impl(context: Context, is_null): + is_null = parse_bool(is_null) + for_each_session_transactions_in_parallel_are(context, lambda tx: assert_transaction_null(tx, is_null)) + + +@step("for each session, transactions in parallel are open: {is_open}") +def step_impl(context: Context, is_open): + is_open = parse_bool(is_open) + for_each_session_transactions_in_parallel_are(context, lambda tx: assert_transaction_open(tx, is_open)) + + +@step("for each session, transactions in parallel have type") +def step_impl(context: Context): + types = list(map(parse_transaction_type, parse_list(context.table))) + for session in context.sessions: + future_transactions = context.sessions_to_transactions_parallel[session] + assert_that(future_transactions, has_length(len(types))) + future_transactions_iter = iter(future_transactions) + for type_ in types: + assert_that(next(future_transactions_iter).result().transaction_type(), is_(type_)) + + +############################################ +# parallel sessions, parallel transactions # +############################################ + +def for_each_session_in_parallel_transactions_in_parallel_are(context: Context, assertion): + for future_session in context.sessions_parallel: + for future_transaction in context.sessions_parallel_to_transactions_parallel[future_session]: + assertion(future_transaction.result()) + + +@step("for each session in parallel, transactions in parallel are null: {is_null}") +def step_impl(context: Context, is_null): + is_null = parse_bool(is_null) + for_each_session_in_parallel_transactions_in_parallel_are(context, lambda tx: assert_transaction_null(tx, is_null)) + + +@step("for each session in parallel, transactions in parallel are open: {is_open}") +def step_impl(context: Context, is_open): + is_open = parse_bool(is_open) + for_each_session_in_parallel_transactions_in_parallel_are(context, lambda tx: assert_transaction_open(tx, is_open)) + + +###################################### +# transaction behaviour with queries # +###################################### + +@step("for each transaction, define query; throws exception containing \"{exception}\"") +def step_impl(context: Context, exception: str): + for session in context.sessions: + for transaction in context.sessions_to_transactions[session]: + try: + next(transaction.query().define(context.text), default=None) + assert False + except GraknClientException as e: + assert_that(exception, is_in(str(e))) + + +=# \ No newline at end of file diff --git a/test/behaviour/context.jl b/test/behaviour/context.jl new file mode 100644 index 00000000..92988c24 --- /dev/null +++ b/test/behaviour/context.jl @@ -0,0 +1,103 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + +using GraknClient +using ConceptMap +using ConceptMapGroup +using Numeric +using NumericGroup +using Concept +using Attribute, BooleanAttribute, LongAttribute, DoubleAttribute, StringAttribute, \ + DateTimeAttribute +using EntityType +using RelationType +using RoleType +using ThingType +using Type +using Session +using Transaction + +using Test + + + + +#= +from concurrent.futures._base import Future +from typing import List, Union, Optional + +import behave.runner +from behave.model import Table + +from grakn.client import GraknClient +from grakn.concept.answer.concept_map import ConceptMap +from grakn.concept.answer.concept_map_group import ConceptMapGroup +from grakn.concept.answer.numeric import Numeric +from grakn.concept.answer.numeric_group import NumericGroup +from grakn.concept.concept import Concept +from grakn.concept.thing.attribute import Attribute, BooleanAttribute, LongAttribute, DoubleAttribute, StringAttribute, \ + DateTimeAttribute +from grakn.concept.thing.entity import Entity +from grakn.concept.thing.relation import Relation +from grakn.concept.thing.thing import Thing +from grakn.concept.type.attribute_type import AttributeType, BooleanAttributeType, LongAttributeType, \ + DoubleAttributeType, StringAttributeType, DateTimeAttributeType +from grakn.concept.type.entity_type import EntityType +from grakn.concept.type.relation_type import RelationType +from grakn.concept.type.role_type import RoleType +from grakn.concept.type.thing_type import ThingType +from grakn.concept.type.type import Type +from grakn.rpc.session import Session +from grakn.rpc.transaction import Transaction + + +AttributeSubtype: Attribute = Union[BooleanAttribute, LongAttribute, DoubleAttribute, StringAttribute, DateTimeAttribute] +ThingSubtype: Thing = Union[Entity, Relation, AttributeSubtype] +TypeSubtype: Type = Union[ThingType, EntityType, RelationType, RoleType, AttributeType, BooleanAttributeType, LongAttributeType, DoubleAttributeType, StringAttributeType, DateTimeAttributeType] +ConceptSubtype: Concept = Union[ThingSubtype, TypeSubtype] + + +class Config: + """ + Type definitions for Config. + + This class should not be instantiated. The initialisation of the actual Config object occurs in environment.py. + """ + def __init__(self): + self.userdata = {} + + +class Context(behave.runner.Context): + """ + Type definitions for Context. + + This class should not be instantiated. The initialisation of the actual Context object occurs in environment.py. + """ + def __init__(self): + self.table: Optional[Table] = None + self.THREAD_POOL_SIZE = 0 + self.client: Optional[GraknClient] = None + self.sessions: List[Session] = [] + self.sessions_to_transactions: dict[Session, List[Transaction]] = {} + self.sessions_parallel: List[Future[Session]] = [] + self.sessions_parallel_to_transactions_parallel: dict[Future[Session], List[Transaction]] = {} + self.things: dict[str, ThingSubtype] = {} + self.answers: Optional[List[ConceptMap]] = None + self.numeric_answer: Optional[Numeric] = None + self.answer_groups: Optional[List[ConceptMapGroup]] = None + self.numeric_answer_groups: Optional[List[NumericGroup]] = None + self.config = Config() + + def tx(self) -> Transaction: + return self.sessions_to_transactions[self.sessions[0]][0] + + def put(self, var: str, thing: ThingSubtype) -> None: + pass + + def get(self, var: str) -> ThingSubtype: + pass + + def clear_answers(self) -> None: + pass + +=# \ No newline at end of file diff --git a/test/behaviour/graql/graql_steps.jl b/test/behaviour/graql/graql_steps.jl new file mode 100644 index 00000000..447abfec --- /dev/null +++ b/test/behaviour/graql/graql_steps.jl @@ -0,0 +1,394 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + + +#= +import re +from collections import defaultdict +from typing import Dict, List, Tuple, Union, Optional + +from behave import * +from hamcrest import * + +from grakn.common.exception import GraknClientException +from grakn.concept.answer.concept_map import ConceptMap +from grakn.concept.answer.numeric import Numeric +from tests.behaviour.config.parameters import parse_bool, parse_int, parse_float, parse_datetime, parse_table +from tests.behaviour.context import Context, ConceptSubtype, AttributeSubtype + + +@step("the integrity is validated") +def step_impl(context: Context): + # TODO + pass + + +@step("graql define") +def step_impl(context: Context): + context.tx().query().define(query=context.text) + + +@step("graql define; throws exception") +def step_impl(context: Context): + assert_that(calling(next).with_args(context.tx().query().define(query=context.text)), raises(GraknClientException)) + + +@step("graql define; throws exception containing \"{exception}\"") +def step_impl(context: Context, exception: str): + assert_that(calling(next).with_args(context.tx().query().define(query=context.text)), raises(GraknClientException, exception)) + + +@step("graql undefine") +def step_impl(context: Context): + context.tx().query().undefine(query=context.text) + + +@step("graql undefine; throws exception") +def step_impl(context: Context): + assert_that(calling(next).with_args(context.tx().query().undefine(query=context.text)), raises(GraknClientException)) + + +@step("graql undefine; throws exception containing \"{exception}\"") +def step_impl(context: Context, exception: str): + assert_that(calling(next).with_args(context.tx().query().undefine(query=context.text)), raises(GraknClientException, exception)) + + +@step("graql insert") +def step_impl(context: Context): + context.tx().query().insert(query=context.text) + + +@step("graql insert; throws exception") +def step_impl(context: Context): + assert_that(calling(next).with_args(context.tx().query().insert(query=context.text)), raises(GraknClientException)) + + +@step("graql insert; throws exception containing \"{exception}\"") +def step_impl(context: Context, exception: str): + assert_that(calling(next).with_args(context.tx().query().insert(query=context.text)), raises(GraknClientException, exception)) + + +@step("graql delete") +def step_impl(context: Context): + context.tx().query().delete(query=context.text) + + +@step("graql delete; throws exception") +def step_impl(context: Context): + assert_that(calling(next).with_args(context.tx().query().delete(query=context.text)), raises(GraknClientException)) + + +@step("graql delete; throws exception containing \"{exception}\"") +def step_impl(context: Context, exception: str): + assert_that(calling(next).with_args(context.tx().query().insert(query=context.text)), raises(GraknClientException, exception)) + + +@step("graql update") +def step_impl(context: Context): + context.tx().query().update(query=context.text) + + +@step("graql update; throws exception") +def step_impl(context: Context): + assert_that(calling(next).with_args(context.tx().query().update(query=context.text)), raises(GraknClientException)) + + +@step("graql update; throws exception containing \"{exception}\"") +def step_impl(context: Context, exception: str): + assert_that(calling(next).with_args(context.tx().query().update(query=context.text)), raises(GraknClientException, exception)) + +@step("get answers of graql insert") +def step_impl(context: Context): + context.clear_answers() + context.answers = [answer for answer in context.tx().query().insert(query=context.text)] + + +@step("get answers of graql match") +def step_impl(context: Context): + context.clear_answers() + context.answers = [answer for answer in context.tx().query().match(query=context.text)] + + +@step("graql match; throws exception") +def step_impl(context: Context): + assert_that(calling(next).with_args(context.tx().query().match(query=context.text)), raises(GraknClientException)) + + +@step("get answer of graql match aggregate") +def step_impl(context: Context): + context.clear_answers() + context.numeric_answer = next(context.tx().query().match_aggregate(query=context.text)) + + +@step("get answers of graql match group") +def step_impl(context: Context): + context.clear_answers() + context.answer_groups = [group for group in context.tx().query().match_group(query=context.text)] + + +@step("get answers of graql match group aggregate") +def step_impl(context: Context): + context.clear_answers() + context.numeric_answer_groups = [group for group in context.tx().query().match_group_aggregate(query=context.text)] + + +@step("answer size is: {expected_size:Int}") +def step_impl(context: Context, expected_size: int): + assert_that(context.answers, has_length(expected_size), "Expected [%d] answers, but got [%d]" % (expected_size, len(context.answers))) + + +@step("rules contain: {rule_label}") +def step_impl(context: Context, rule_label: str): + return rule_label in [rule.get_label() for rule in context.tx().logic().get_rules()] + +@step("rules do not contain: {rule_label}") +def step_impl(context: Context, rule_label: str): + return not (rule_label in [rule.get_label() for rule in context.tx().logic().get_rules()]) + + +class ConceptMatcher: + + def matches(self, context: Context, concept: ConceptSubtype): + return False + + +class TypeLabelMatcher(ConceptMatcher): + + def __init__(self, label: str): + self.label = label + + def matches(self, context: Context, concept: ConceptSubtype): + if concept.is_role_type(): + return self.label == concept.get_scoped_label() + elif concept.is_type(): + return self.label == concept.get_label() + else: + raise TypeError("A Concept was matched by label, but it is not a Type.") + + +class AttributeMatcher(ConceptMatcher): + + def __init__(self, type_and_value: str): + s = type_and_value.split(":") + assert_that(s, has_length(2), "[%s] is not a valid attribute identifier. It should have format \"type_label:value\"." % type_and_value) + self.type_label, self.value = s + + def check(self, attribute: AttributeSubtype): + if attribute.is_boolean(): + return attribute.get_value() == parse_bool(self.value) + elif attribute.is_long(): + return attribute.get_value() == parse_int(self.value) + elif attribute.is_double(): + return attribute.get_value() == parse_float(self.value) + elif attribute.is_string(): + return attribute.get_value() == self.value + elif attribute.is_datetime(): + return attribute.get_value() == parse_datetime(self.value) + else: + raise ValueError("Unrecognised value type " + str(type(attribute))) + + +class AttributeValueMatcher(AttributeMatcher): + + def matches(self, context: Context, concept: ConceptSubtype): + if not concept.is_attribute(): + return False + + attribute = concept + + if self.type_label != attribute.get_type().get_label(): + return False + + return self.check(attribute) + + +class ThingKeyMatcher(AttributeMatcher): + + def matches(self, context: Context, concept: ConceptSubtype): + if not concept.is_thing(): + return False + + keys = [key for key in concept.as_remote(context.tx()).get_has(only_key=True)] + + for key in keys: + if key.get_type().get_label() == self.type_label: + return self.check(key) + + return False + + +def parse_concept_identifier(value: str): + identifier_type, identifier_body = value.split(":", 1) + if identifier_type == "label": + return TypeLabelMatcher(label=identifier_body) + elif identifier_type == "key": + return ThingKeyMatcher(type_and_value=identifier_body) + elif identifier_type == "value": + return AttributeValueMatcher(type_and_value=identifier_body) + else: + raise ValueError("Failed to parse concept identifier: " + value) + + +def answer_concepts_match(context: Context, answer_identifier: List[Tuple[str, str]], answer: ConceptMap) -> bool: + for var, concept_identifier in answer_identifier: + matcher = parse_concept_identifier(concept_identifier) + if not matcher.matches(context, answer.get(var)): + return False + + return True + + +@step("uniquely identify answer concepts") +def step_impl(context: Context): + answer_identifiers = parse_table(context.table) + assert_that(context.answers, has_length(len(answer_identifiers)), + "The number of answers [%d] should match the number of answer identifiers [%d]." % (len(context.answers), len(answer_identifiers))) + + result_set = [(ai, []) for ai in answer_identifiers] + for answer in context.answers: + for answer_identifier, matched_answers in result_set: + if answer_concepts_match(context, answer_identifier, answer): + matched_answers.append(answer) + + for answer_identifier, answers in result_set: + assert_that(answers, has_length(1), "Each answer identifier should match precisely 1 answer, but [%d] answers " + "matched the identifier [%s]." % (len(answers), answer_identifier)) + + +@step("order of answer concepts is") +def step_impl(context: Context): + answer_identifiers = parse_table(context.table) + assert_that(context.answers, has_length(len(answer_identifiers)), + "The number of answers [%d] should match the number of answer identifiers [%d]." % (len(context.answers), len(answer_identifiers))) + for i in range(len(context.answers)): + answer = context.answers[i] + answer_identifier = answer_identifiers[i] + assert_that(answer_concepts_match(context, answer_identifier, answer), + reason="The answer at index [%d] does not match the identifier [%s]." % (i, answer_identifier)) + + +def get_numeric_value(numeric: Numeric): + if numeric.is_int(): + return numeric.as_int() + elif numeric.is_float(): + return numeric.as_float() + else: + return None + + +def assert_numeric_value(numeric: Numeric, expected_answer: Union[int, float], reason: Optional[str] = None): + if numeric.is_int(): + assert_that(numeric.as_int(), is_(expected_answer), reason) + elif numeric.is_float(): + assert_that(numeric.as_float(), is_(close_to(expected_answer, delta=0.001)), reason) + else: + assert False + + +@step("aggregate value is: {expected_answer:Float}") +def step_impl(context: Context, expected_answer: float): + assert_that(context.numeric_answer is not None, reason="The last query executed was not an aggregate query.") + assert_numeric_value(context.numeric_answer, expected_answer) + + +@step("aggregate answer is not a number") +def step_impl(context: Context): + assert_that(context.numeric_answer.is_nan()) + + +class AnswerIdentifierGroup: + + GROUP_COLUMN_NAME = "owner" + + def __init__(self, raw_answer_identifiers: List[List[Tuple[str, str]]]): + self.owner_identifier = next(entry[1] for entry in raw_answer_identifiers[0] if entry[0] == self.GROUP_COLUMN_NAME) + self.answer_identifiers = [[(var, concept_identifier) for (var, concept_identifier) in raw_answer_identifier if var != self.GROUP_COLUMN_NAME] + for raw_answer_identifier in raw_answer_identifiers] + + +@step("answer groups are") +def step_impl(context: Context): + raw_answer_identifiers = parse_table(context.table) + grouped_answer_identifiers = defaultdict(list) + for raw_answer_identifier in raw_answer_identifiers: + owner = next(entry[1] for entry in raw_answer_identifier if entry[0] == AnswerIdentifierGroup.GROUP_COLUMN_NAME) + grouped_answer_identifiers[owner].append(raw_answer_identifier) + answer_identifier_groups = [AnswerIdentifierGroup(raw_identifiers) for raw_identifiers in grouped_answer_identifiers.values()] + + assert_that(context.answer_groups, has_length(len(answer_identifier_groups)), + "Expected [%d] answer groups, but found [%d]." % (len(answer_identifier_groups), len(context.answer_groups))) + + for answer_identifier_group in answer_identifier_groups: + identifier = parse_concept_identifier(answer_identifier_group.owner_identifier) + answer_group = next((group for group in context.answer_groups if identifier.matches(context, group.owner())), None) + assert_that(answer_group is not None, + reason="The group identifier [%s] does not match any of the answer group owners." % answer_identifier_group.owner_identifier) + + result_set = [(ai, []) for ai in answer_identifier_group.answer_identifiers] + for answer in answer_group.concept_maps(): + for (answer_identifier, matched_answers) in result_set: + if answer_concepts_match(context, answer_identifier, answer): + matched_answers.append(answer) + + for (answer_identifier, answers) in result_set: + assert_that(answers, has_length(1), "Each answer identifier should match precisely 1 answer, but [%d] answers " + "matched the identifier [%s]." % (len(answers), answer_identifier)) + + +@step("group aggregate values are") +def step_impl(context: Context): + raw_answer_identifiers = parse_table(context.table) + expectations = {} + for raw_answer_identifier in raw_answer_identifiers: + owner = next(entry[1] for entry in raw_answer_identifier if entry[0] == AnswerIdentifierGroup.GROUP_COLUMN_NAME) + expected_answer = parse_float(next(entry[1] for entry in raw_answer_identifier if entry[0] == "value")) + expectations[owner] = expected_answer + + assert_that(context.numeric_answer_groups, has_length(len(expectations)), + reason="Expected [%d] answer groups, but found [%d]." % (len(expectations), len(context.numeric_answer_groups))) + + for (owner_identifier, expected_answer) in expectations.items(): + identifier = parse_concept_identifier(owner_identifier) + numeric_group = next((group for group in context.numeric_answer_groups if identifier.matches(context, group.owner())), None) + assert_that(numeric_group is not None, + reason="The group identifier [%s] does not match any of the answer group owners." % owner_identifier) + + actual_answer = get_numeric_value(numeric_group.numeric()) + assert_numeric_value(numeric_group.numeric(), expected_answer, + reason="Expected answer [%f] for group [%s], but got [%f]" % (expected_answer, owner_identifier, actual_answer)) + + +def variable_from_template_placeholder(placeholder: str): + if placeholder.endswith(".iid"): + return placeholder.replace(".iid", "").replace("answer.", "") + else: + raise ValueError("Cannot replace template not based on IID.") + + +def apply_query_template(template: str, answer: ConceptMap): + query = "" + matches = re.finditer(r"<(.+?)>", template) + i = 0 + for match in matches: + required_variable = variable_from_template_placeholder(match.group(1)) + query += template[i:match.span()[0]] + if required_variable in answer.map().keys(): + concept = answer.get(required_variable) + if not concept.is_thing(): + raise TypeError("Cannot apply IID templating to Types") + query += concept.get_iid() + else: + raise ValueError("No IID available for template placeholder: [%s]" % match.group()) + i = match.span()[1] + query += template[i:] + return query + + +# TODO: This step seems needlessly complex for what it's actually used for +@step("each answer satisfies") +def step_impl(context: Context): + for answer in context.answers: + query = apply_query_template(template=context.text, answer=answer) + assert_that(list(context.tx().query().match(query)), has_length(1)) + +=# \ No newline at end of file diff --git a/test/behaviour/graql/language/define/BUILD b/test/behaviour/graql/language/define/BUILD new file mode 100644 index 00000000..08228a8c --- /dev/null +++ b/test/behaviour/graql/language/define/BUILD @@ -0,0 +1,53 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +package(default_visibility = ["//tests/behaviour:__subpackages__"]) +load("//tools:behave_rule.bzl", "grakn_behaviour_py_test") +load("@graknlabs_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") + +grakn_behaviour_py_test( + name = "test", + feats = ["@graknlabs_behaviour//graql/language:define.feature"], + background_core = ["//tests/behaviour/background:core"], + background_cluster = ["//tests/behaviour/background:cluster"], + steps = [ + "//tests/behaviour/connection:steps", + "//tests/behaviour/connection/database:steps", + "//tests/behaviour/connection/session:steps", + "//tests/behaviour/connection/transaction:steps", + "//tests/behaviour/graql:steps", + ], + deps = [ + "//:client_python", + "//tests/behaviour:context", + "//tests/behaviour:util", + "//tests/behaviour/config:parameters", + "//tests/behaviour/background", + ], + native_grakn_artifact_core = "//tests:native-grakn-core-artifact", + native_grakn_artifact_cluster = "//tests:native-grakn-cluster-artifact", + size = "medium", +) + +checkstyle_test( + name = "checkstyle", + include = glob(["*"]), + license_type = "apache", + size = "small", +) diff --git a/test/behaviour/graql/language/delete/BUILD b/test/behaviour/graql/language/delete/BUILD new file mode 100644 index 00000000..adb9ea7a --- /dev/null +++ b/test/behaviour/graql/language/delete/BUILD @@ -0,0 +1,53 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +package(default_visibility = ["//tests/behaviour:__subpackages__"]) +load("//tools:behave_rule.bzl", "grakn_behaviour_py_test") +load("@graknlabs_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") + +grakn_behaviour_py_test( + name = "test", + feats = ["@graknlabs_behaviour//graql/language:delete.feature"], + background_core = ["//tests/behaviour/background:core"], + background_cluster = ["//tests/behaviour/background:cluster"], + steps = [ + "//tests/behaviour/connection:steps", + "//tests/behaviour/connection/database:steps", + "//tests/behaviour/connection/session:steps", + "//tests/behaviour/connection/transaction:steps", + "//tests/behaviour/graql:steps", + ], + deps = [ + "//:client_python", + "//tests/behaviour:context", + "//tests/behaviour:util", + "//tests/behaviour/config:parameters", + "//tests/behaviour/background", + ], + native_grakn_artifact_core = "//tests:native-grakn-core-artifact", + native_grakn_artifact_cluster = "//tests:native-grakn-cluster-artifact", + size = "medium", +) + +checkstyle_test( + name = "checkstyle", + include = glob(["*"]), + license_type = "apache", + size = "small", +) diff --git a/test/behaviour/graql/language/get/BUILD b/test/behaviour/graql/language/get/BUILD new file mode 100644 index 00000000..0f7aa7a4 --- /dev/null +++ b/test/behaviour/graql/language/get/BUILD @@ -0,0 +1,53 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +package(default_visibility = ["//tests/behaviour:__subpackages__"]) +load("//tools:behave_rule.bzl", "grakn_behaviour_py_test") +load("@graknlabs_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") + +grakn_behaviour_py_test( + name = "test", + feats = ["@graknlabs_behaviour//graql/language:get.feature"], + background_core = ["//tests/behaviour/background:core"], + background_cluster = ["//tests/behaviour/background:cluster"], + steps = [ + "//tests/behaviour/connection:steps", + "//tests/behaviour/connection/database:steps", + "//tests/behaviour/connection/session:steps", + "//tests/behaviour/connection/transaction:steps", + "//tests/behaviour/graql:steps", + ], + deps = [ + "//:client_python", + "//tests/behaviour:context", + "//tests/behaviour:util", + "//tests/behaviour/config:parameters", + "//tests/behaviour/background", + ], + native_grakn_artifact_core = "//tests:native-grakn-core-artifact", + native_grakn_artifact_cluster = "//tests:native-grakn-cluster-artifact", + size = "medium", +) + +checkstyle_test( + name = "checkstyle", + include = glob(["*"]), + license_type = "apache", + size = "small", +) diff --git a/test/behaviour/graql/language/insert/BUILD b/test/behaviour/graql/language/insert/BUILD new file mode 100644 index 00000000..94d1d572 --- /dev/null +++ b/test/behaviour/graql/language/insert/BUILD @@ -0,0 +1,53 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +package(default_visibility = ["//tests/behaviour:__subpackages__"]) +load("//tools:behave_rule.bzl", "grakn_behaviour_py_test") +load("@graknlabs_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") + +grakn_behaviour_py_test( + name = "test", + feats = ["@graknlabs_behaviour//graql/language:insert.feature"], + background_core = ["//tests/behaviour/background:core"], + background_cluster = ["//tests/behaviour/background:cluster"], + steps = [ + "//tests/behaviour/connection:steps", + "//tests/behaviour/connection/database:steps", + "//tests/behaviour/connection/session:steps", + "//tests/behaviour/connection/transaction:steps", + "//tests/behaviour/graql:steps", + ], + deps = [ + "//:client_python", + "//tests/behaviour:context", + "//tests/behaviour:util", + "//tests/behaviour/config:parameters", + "//tests/behaviour/background", + ], + native_grakn_artifact_core = "//tests:native-grakn-core-artifact", + native_grakn_artifact_cluster = "//tests:native-grakn-cluster-artifact", + size = "medium", +) + +checkstyle_test( + name = "checkstyle", + include = glob(["*"]), + license_type = "apache", + size = "small", +) diff --git a/test/behaviour/graql/language/match/BUILD b/test/behaviour/graql/language/match/BUILD new file mode 100644 index 00000000..47f2a2ef --- /dev/null +++ b/test/behaviour/graql/language/match/BUILD @@ -0,0 +1,53 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +package(default_visibility = ["//tests/behaviour:__subpackages__"]) +load("//tools:behave_rule.bzl", "grakn_behaviour_py_test") +load("@graknlabs_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") + +grakn_behaviour_py_test( + name = "test", + feats = ["@graknlabs_behaviour//graql/language:match.feature"], + background_core = ["//tests/behaviour/background:core"], + background_cluster = ["//tests/behaviour/background:cluster"], + steps = [ + "//tests/behaviour/connection:steps", + "//tests/behaviour/connection/database:steps", + "//tests/behaviour/connection/session:steps", + "//tests/behaviour/connection/transaction:steps", + "//tests/behaviour/graql:steps", + ], + deps = [ + "//:client_python", + "//tests/behaviour:context", + "//tests/behaviour:util", + "//tests/behaviour/config:parameters", + "//tests/behaviour/background", + ], + native_grakn_artifact_core = "//tests:native-grakn-core-artifact", + native_grakn_artifact_cluster = "//tests:native-grakn-cluster-artifact", + size = "medium", +) + +checkstyle_test( + name = "checkstyle", + include = glob(["*"]), + license_type = "apache", + size = "small", +) diff --git a/test/behaviour/graql/language/undefine/BUILD b/test/behaviour/graql/language/undefine/BUILD new file mode 100644 index 00000000..5109f18c --- /dev/null +++ b/test/behaviour/graql/language/undefine/BUILD @@ -0,0 +1,53 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +package(default_visibility = ["//tests/behaviour:__subpackages__"]) +load("//tools:behave_rule.bzl", "grakn_behaviour_py_test") +load("@graknlabs_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") + +grakn_behaviour_py_test( + name = "test", + feats = ["@graknlabs_behaviour//graql/language:undefine.feature"], + background_core = ["//tests/behaviour/background:core"], + background_cluster = ["//tests/behaviour/background:cluster"], + steps = [ + "//tests/behaviour/connection:steps", + "//tests/behaviour/connection/database:steps", + "//tests/behaviour/connection/session:steps", + "//tests/behaviour/connection/transaction:steps", + "//tests/behaviour/graql:steps", + ], + deps = [ + "//:client_python", + "//tests/behaviour:context", + "//tests/behaviour:util", + "//tests/behaviour/config:parameters", + "//tests/behaviour/background", + ], + native_grakn_artifact_core = "//tests:native-grakn-core-artifact", + native_grakn_artifact_cluster = "//tests:native-grakn-cluster-artifact", + size = "medium", +) + +checkstyle_test( + name = "checkstyle", + include = glob(["*"]), + license_type = "apache", + size = "small", +) diff --git a/test/behaviour/graql/language/update/BUILD b/test/behaviour/graql/language/update/BUILD new file mode 100644 index 00000000..fec3c7c2 --- /dev/null +++ b/test/behaviour/graql/language/update/BUILD @@ -0,0 +1,53 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +package(default_visibility = ["//tests/behaviour:__subpackages__"]) +load("//tools:behave_rule.bzl", "grakn_behaviour_py_test") +load("@graknlabs_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") + +grakn_behaviour_py_test( + name = "test", + feats = ["@graknlabs_behaviour//graql/language:update.feature"], + background_core = ["//tests/behaviour/background:core"], + background_cluster = ["//tests/behaviour/background:cluster"], + steps = [ + "//tests/behaviour/connection:steps", + "//tests/behaviour/connection/database:steps", + "//tests/behaviour/connection/session:steps", + "//tests/behaviour/connection/transaction:steps", + "//tests/behaviour/graql:steps", + ], + deps = [ + "//:client_python", + "//tests/behaviour:context", + "//tests/behaviour:util", + "//tests/behaviour/config:parameters", + "//tests/behaviour/background", + ], + native_grakn_artifact_core = "//tests:native-grakn-core-artifact", + native_grakn_artifact_cluster = "//tests:native-grakn-cluster-artifact", + size = "medium", +) + +checkstyle_test( + name = "checkstyle", + include = glob(["*"]), + license_type = "apache", + size = "small", +) diff --git a/test/behaviour/util.jl b/test/behaviour/util.jl new file mode 100644 index 00000000..5e4e2d26 --- /dev/null +++ b/test/behaviour/util.jl @@ -0,0 +1,12 @@ +# This file is a part of GraknClient. License is MIT: https://github.com/Humans-of-Julia/GraknClient.jl/blob/main/LICENSE + + +#= +from collections import Counter + +from hamcrest import * + + +def assert_collections_equal(collection1: list, collection2: list): + assert_that(Counter(collection1), is_(equal_to(Counter(collection2)))) +=# \ No newline at end of file diff --git a/test/pytojulexample.jl b/test/pytojulexample.jl new file mode 100644 index 00000000..cd2de13b --- /dev/null +++ b/test/pytojulexample.jl @@ -0,0 +1,34 @@ +class MyClass(object): + + def __init__(self, foo, bar): + self.foo = foo + self.bar = bar + + def do_something(self): + return self.foo + self.bar + + def do_something_else(self, num): + return num * self.bar + +my_class = MyClass(1, 10) +my_class.do_something() # returns 11 +my_class.do_something_else(10) # returns 100 + + + +struct State + foo::Int + bar::Float64 +end + +function dosomething(s::State) + s.foo + s.bar +end + +function dosomethingelse(s::State, n::Int) + n * s.bar +end + +s = State(1, 10) +dosomething(s) # returns 11 +dosomethingelse(s, 10) # returns 100 \ No newline at end of file