From f167abc1d8b5d1c081ee5751bbbfd36cf412a335 Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Wed, 17 Dec 2025 16:56:56 +0000 Subject: [PATCH 01/10] Add TypeDB Cluster support and failover (#765) Introduce TypeDB Cluster support. Including: Drivers can be created using a single address, multiple addresses, or address translation (mapping between public user-facing addresses and internal cluster addresses for special needs). Address translation can be updated after the driver is created. Server version and distribution, as well as the list of active replicas, can be retrieved using TypeDB Driver. Read operations can be executed using one of three strategies: * Strong consistency level -- Strongest consistency, always up-to-date due to the guarantee of the primary replica usage. * Eventual consistency level -- Allow stale reads from any replica. May not reflect latest writes (will not be supported in the first Cluster release on the server side, so will probably return errors) * Replica dependent consistency level -- The operation is executed against the provided replica address only. Can be especially useful for testing. By default, all operations are executed using the strongest consistency level. However, all read operations now support consistency level specification. Read transactions can be configured through transaction options. Driver options can be used to configure the failover strategies used with strong and eventual consistency levels. `primary_failover_retries` -- Limits the number of attempts to redirect a strongly consistent request to another primary replica in case of a failure due to the change of replica roles. Defaults to 1. `replica_discovery_attempts` -- Limits the number of driver attempts to discover a single working replica to perform an operation in case of a replica unavailability. Every replica is tested once, which means that at most: - {limit} operations are performed if the limit <= the number of replicas. - {number of replicas} operations are performed if the limit > the number of replicas. - {number of replicas} operations are performed if the limit is None. Affects every eventually consistent operation, including redirect failover, when the new primary replica is unknown. Defaults to None. **Missing parts**: * Address translation runtime update is not fully implemented, it probably requires more updates, or can be removed for the first release. * Testing cannot be automated without Cluster snapshots. Instead, for local testing, use `temp-cluster-server` (instructions below). * The driver works itself, the tests for Core pass. However, its replication features are untested. There is a new `clustering` integration test, which successfully boots up servers, but there are some missing functionalities of the server that prevent the testing progress. Once the PR referenced below is completed and merged, it can be completed, as well. More BDD tests should be added here https://github.com/typedb/typedb-behaviour/pull/373 This driver can be tested using the server from https://github.com/typedb/typedb-cluster/pull/608. To do so, run `cargo build` in `typedb-cluster`, and then copy the resulting binary to `typedb-driver` like: ``` cp path-to-typedb/typedb-cluster/target/debug/typedb_server_bin path-to-typedb/typedb-driver/tool/test/temp-cluster-server/typedb ``` Then, test scripts like `./tool/test/temp-cluster-server/start-cluster-servers.sh 3` can be used. Note that it is a temporary directory, created to use the server while we are not able to use Cluster snapshots from Bazel. Remove server_manager prints Rustfmt and C impl cleanup Update deps after rebase Fix build Fix encryption and C tests Expose consistency too all the needed interfaces in Rust and C Uncomment linux archives Configure cluster tests better and introduce driver fields retrieval Remove unready factory jobs and fix options interfaces Add Java and Python BDD cluster init. Update artifacts Temporarily make https/tls validation more friendly (#832) Allow using `http` and `https` schemes in connection URLs, introducing a temporary comparison of the specified scheme and the TLS driver option. This is a temporary resolution until we decide how to make the GRPC endpoint safe and easy to understand, yet comfortable for Cloud and Cluster. Additionally, introduce more Java interfaces as a part of its build fix. Update TypeDB ref Fix Java and Python build. Uncomment Java and Python CI. Update docs Clean up build Update version to 3.7.0-alpha-2. Fix test and update release notes Fix python and windows c tests Fix invalid test sizes Fix python test rules Fix tests Update dependencies Refactor DriverOptions tls configuration and preapre for 3.7.0-alpha-3 Fix build Update dependencies Update cluster artifact Update cluster artifact Rename community to core in internals and fix windows builds Fix Rust doc generation Update TypeDB artifact Fix windows test job Add GRPC requests timeouts (#840) Add request timeouts for operations outside of transactions (connections, users, databases, transaction opening). Now, instead of hanging forever if the server does not respond, the operation fails with an explicit error message on timeout. These timeouts can be configured through driver options and are defaulted to 2 hours. They do not affect transaction lifetimes, queries, and commits (thus, commits can still be running forever -- an explicit TODO is left for consideration). This change replaces https://github.com/typedb/typedb-driver/pull/710 Use `tokio::time::timeout`. Add request timeout todo Rustfmt Fix Java bdd tests Remove large tests to limit the time given to the tests to 5 mins Try stabilizing bdd tests in java Remove bind address from connection addresses of clustering internal addresses Rustfmt Fix Javas consistency level constructors Add cluster support BDD tests (#845) Add cluster support BDD and fix uncovered bugs. Affected drivers: * rust * java * python * ... Extend cluster tests retries --- .circleci/config.yml | 82 +- .circleci/windows/clib/test_assembly.bat | 2 +- .circleci/windows/cpp/test_assembly.bat | 2 +- .../windows/csharp/test_deploy_snapshot.bat | 10 +- .../windows/java/test_deploy_snapshot.bat | 10 +- .../windows/python/test_deploy_snapshot.bat | 10 +- .factory/automation.yml | 314 +++--- .factory/{test-community.sh => test-core.sh} | 2 +- .gitignore | 6 + Cargo.lock | 895 ++++++++++-------- RELEASE_NOTES_LATEST.md | 159 ++-- RELEASE_TEMPLATE.md | 11 + VERSION | 2 +- WORKSPACE | 8 +- c/Cargo.toml | 13 +- c/README.md | 7 +- c/src/analyze.rs | 28 +- c/src/answer.rs | 24 +- c/src/{ => common}/error.rs | 16 +- c/src/{ => common}/iterator.rs | 11 +- c/src/{ => common}/memory.rs | 30 +- c/src/{common.rs => common/mod.rs} | 23 +- c/src/{ => common}/promise.rs | 2 +- c/src/concept/concept.rs | 32 +- c/src/concept/instance.rs | 2 +- c/src/concept/mod.rs | 7 +- c/src/connection.rs | 121 --- c/src/credentials.rs | 39 + c/src/database.rs | 144 --- c/src/database/database.rs | 116 +++ c/src/database/database_manager.rs | 144 +++ c/src/database/mod.rs | 21 + c/src/database_manager.rs | 91 -- c/src/driver.rs | 292 ++++++ c/src/driver_options.rs | 144 +++ c/src/driver_tls_config.rs | 71 ++ c/src/lib.rs | 12 +- c/src/query_options.rs | 6 +- c/src/server/consistency_level.rs | 127 +++ c/src/server/mod.rs | 22 + c/src/server/server_replica.rs | 91 ++ c/src/server/server_version.rs | 55 ++ c/src/transaction.rs | 12 +- c/src/transaction_options.rs | 38 +- c/src/user.rs | 63 -- c/src/user/mod.rs | 21 + c/src/user/user.rs | 78 ++ c/src/user/user_manager.rs | 142 +++ c/src/user_manager.rs | 74 -- c/swig/typedb_driver_java.swg | 59 +- c/tests/assembly/test.c | 22 +- c/tests/integration/common.c | 15 +- c/tests/integration/common.h | 7 +- c/tests/integration/test_driver.c | 19 +- c/typedb_driver.i | 52 +- cpp/include/typedb/user/user_manager.hpp | 2 +- csharp/Api/User/IUserManager.cs | 2 +- dependencies/typedb/artifacts.bzl | 25 +- dependencies/typedb/repositories.bzl | 17 +- .../ROOT/partials/c/connection/database.adoc | 253 ++++- .../ROOT/partials/c/session/options.adoc | 533 +++++++++++ .../partials/cpp/connection/Database.adoc | 2 +- .../ROOT/partials/cpp/session/Options.adoc | 2 +- .../partials/csharp/connection/IDatabase.adoc | 2 +- .../csharp/session/TypeDBOptions.adoc | 2 +- .../partials/http-ts/connection/Server.adoc | 16 + .../http-ts/connection/TypeDBHttpDriver.adoc | 14 + .../http-ts/response/ServersListResponse.adoc | 14 + .../connection/ConsistencyLevel.Eventual.adoc | 80 ++ .../ConsistencyLevel.ReplicaDependent.adoc | 94 ++ .../connection/ConsistencyLevel.Strong.adoc | 80 ++ .../java/connection/ConsistencyLevel.adoc | 66 ++ .../partials/java/connection/Database.adoc | 160 +++- .../java/connection/DatabaseManager.adoc | 159 +++- .../ROOT/partials/java/connection/Driver.adoc | 274 +++++- .../java/connection/DriverOptions.adoc | 275 +++++- .../java/connection/DriverTlsConfig.adoc | 149 +++ .../partials/java/connection/ReplicaRole.adoc | 152 +++ .../java/connection/ServerReplica.adoc | 85 ++ .../java/connection/ServerVersion.adoc | 62 ++ .../ROOT/partials/java/connection/TypeDB.adoc | 74 +- .../ROOT/partials/java/connection/User.adoc | 85 +- .../partials/java/connection/UserManager.adoc | 210 +++- .../java/transaction/QueryOptions.adoc | 4 +- .../java/transaction/TransactionOptions.adoc | 55 +- .../partials/nodejs/connection/Database.adoc | 6 +- .../partials/python/answer/ConceptRow.adoc | 2 - .../partials/python/answer/QueryAnswer.adoc | 2 - .../python/connection/ConsistencyLevel.adoc | 80 ++ .../partials/python/connection/Database.adoc | 61 +- .../python/connection/DatabaseManager.adoc | 53 +- .../partials/python/connection/Driver.adoc | 186 +++- .../python/connection/DriverOptions.adoc | 22 +- .../python/connection/DriverTlsConfig.adoc | 98 ++ .../partials/python/connection/Eventual.adoc | 11 + .../python/connection/ReplicaDependent.adoc | 22 + .../python/connection/ReplicaRole.adoc | 72 ++ .../python/connection/ServerReplica.adoc | 45 + .../python/connection/ServerVersion.adoc | 26 + .../partials/python/connection/Strong.adoc | 11 + .../partials/python/connection/TypeDB.adoc | 15 +- .../ROOT/partials/python/connection/User.adoc | 36 +- .../python/connection/UserManager.adoc | 71 +- .../python/transaction/QueryOptions.adoc | 2 +- .../transaction/TransactionOptions.adoc | 1 + .../ROOT/partials/python/value/Datetime.adoc | 32 +- .../partials/rust/answer/ConceptDocument.adoc | 2 +- .../ROOT/partials/rust/answer/ConceptRow.adoc | 4 +- .../partials/rust/answer/QueryAnswer.adoc | 8 +- .../ROOT/partials/rust/concept/Concept.adoc | 40 +- .../partials/rust/connection/Address.adoc | 15 + .../partials/rust/connection/Addresses.adoc | 231 +++++ .../connection/AvailableServerReplica.adoc | 103 ++ .../rust/connection/ConsistencyLevel.adoc | 18 + .../partials/rust/connection/Database.adoc | 319 ++++++- .../rust/connection/DatabaseManager.adoc | 325 ++++++- .../rust/connection/DriverOptions.adoc | 117 ++- .../rust/connection/DriverTlsConfig.adoc | 164 ++++ .../partials/rust/connection/ReplicaRole.adoc | 18 + .../rust/connection/ServerReplica.adoc | 37 + .../rust/connection/ServerVersion.adoc | 48 + .../rust/connection/Trait_Replica.adoc | 78 ++ .../rust/connection/TypeDBDriver.adoc | 849 ++++++++++++++++- .../ROOT/partials/rust/connection/User.adoc | 220 ++++- .../partials/rust/connection/UserManager.adoc | 529 ++++++++++- .../partials/rust/errors/ConnectionError.adoc | 23 +- .../partials/rust/errors/InternalError.adoc | 3 +- .../rust/transaction/Transaction.adoc | 11 +- .../rust/transaction/TransactionOptions.adoc | 21 +- .../ROOT/partials/rust/value/Decimal.adoc | 45 +- http-ts/docs_structure.bzl | 2 + http-ts/src/index.ts | 5 + http-ts/src/response.ts | 10 + http-ts/tests/behaviour/feature/BUILD | 13 +- http-ts/tests/behaviour/rules.bzl | 31 +- http-ts/tests/behaviour/steps/connection.ts | 57 +- http-ts/tests/behaviour/steps/context.ts | 101 +- java/README.md | 3 +- java/TypeDB.java | 39 +- java/TypeDBExample.java | 3 +- java/analyze/ConstraintImpl.java | 5 +- java/api/ConsistencyLevel.java | 137 +++ java/api/Driver.java | 146 ++- java/api/DriverOptions.java | 214 ++++- java/api/DriverTlsConfig.java | 126 +++ java/api/QueryOptions.java | 4 +- java/api/TransactionOptions.java | 39 +- java/api/analyze/NamedRole.java | 4 +- java/api/answer/ConceptRow.java | 2 +- java/api/database/Database.java | 152 +-- java/api/database/DatabaseManager.java | 104 +- java/api/server/ReplicaRole.java | 76 ++ java/api/server/ServerReplica.java | 62 ++ java/api/server/ServerVersion.java | 65 ++ java/api/user/User.java | 53 +- java/api/user/UserManager.java | 109 ++- java/connection/DatabaseImpl.java | 65 +- java/connection/DatabaseManagerImpl.java | 27 +- java/connection/DriverImpl.java | 125 ++- java/connection/ServerReplicaImpl.java | 76 ++ java/docs_structure.bzl | 9 +- java/test/behaviour/config/Parameters.java | 65 +- java/test/behaviour/connection/BUILD | 5 +- .../connection/ConnectionStepsBase.java | 104 +- .../connection/ConnectionStepsCluster.java | 133 ++- ...ommunity.java => ConnectionStepsCore.java} | 65 +- java/test/behaviour/connection/database/BUILD | 3 - .../connection/database/DatabaseSteps.java | 20 +- .../connection/database/DatabaseTest.java | 2 +- .../behaviour/connection/transaction/BUILD | 3 - .../transaction/TransactionSteps.java | 6 + .../transaction/TransactionTest.java | 2 +- .../behaviour/connection/user/UserSteps.java | 4 +- java/test/behaviour/debug/BUILD | 4 +- java/test/behaviour/driver/cluster/BUILD | 52 + .../behaviour/driver/cluster/ClusterTest.java | 58 ++ java/test/behaviour/driver/concept/BUILD | 3 - .../behaviour/driver/concept/ConceptTest.java | 2 +- java/test/behaviour/driver/connection/BUILD | 3 - .../driver/connection/ConnectionTest.java | 2 +- java/test/behaviour/driver/migration/BUILD | 3 - .../driver/migration/MigrationTest.java | 2 +- java/test/behaviour/driver/query/BUILD | 3 - .../behaviour/driver/query/QueryTest.java | 2 +- java/test/behaviour/driver/user/BUILD | 3 - java/test/behaviour/driver/user/UserTest.java | 2 +- java/test/behaviour/query/AnalyzeSteps.java | 5 +- java/test/behaviour/rules.bzl | 46 +- .../application/MavenApplicationTest.java | 3 +- java/test/integration/BUILD | 4 +- java/test/integration/DriverTest.java | 5 +- java/test/integration/ExampleTest.java | 5 +- java/test/integration/ValueTest.java | 5 +- java/test/integration/cluster/BUILD | 2 +- java/user/UserImpl.java | 23 +- java/user/UserManagerImpl.java | 33 +- nodejs/api/connection/user/UserManager.ts | 2 +- python/README.md | 6 +- python/docs_structure.bzl | 11 +- python/example.py | 3 +- python/rules.bzl | 2 +- python/tests/behaviour/background/BUILD | 4 +- .../background/cluster/environment.py | 64 +- .../background/community/environment.py | 71 -- .../behaviour/background/core/environment.py | 58 ++ .../behaviour/background/environment_base.py | 36 +- python/tests/behaviour/behave_rule.bzl | 17 +- python/tests/behaviour/config/parameters.py | 56 +- .../behaviour/connection/connection_steps.py | 130 ++- .../tests/behaviour/connection/database/BUILD | 2 +- .../connection/database/database_steps.py | 23 +- .../transaction/transaction_steps.py | 8 +- .../behaviour/connection/user/user_steps.py | 2 +- python/tests/behaviour/driver/cluster/BUILD | 47 + python/tests/behaviour/driver/concept/BUILD | 1 - python/tests/behaviour/driver/user/BUILD | 2 +- python/tests/behaviour/query/query_steps.py | 10 +- .../tests/behaviour/util/functor_encoder.py | 2 +- python/tests/deployment/test.py | 3 +- python/tests/integration/cluster/BUILD | 4 +- .../integration/cluster/cluster_test_rule.bzl | 8 +- python/tests/integration/test_debug.py | 3 +- python/tests/integration/test_driver.py | 9 +- python/tests/integration/test_example.py | 6 +- python/tests/integration/test_values.py | 12 +- python/typedb/analyze/__init__.py | 4 +- python/typedb/analyze/function.py | 6 +- python/typedb/analyze/pipeline.py | 2 +- python/typedb/analyze/pipeline_stage.py | 1 + python/typedb/api/analyze/constraint.py | 1 + python/typedb/api/analyze/named_role.py | 1 + .../api/answer/concept_document_iterator.py | 4 - python/typedb/api/answer/concept_row.py | 12 - .../typedb/api/answer/concept_row_iterator.py | 4 - python/typedb/api/answer/ok_query_answer.py | 4 - python/typedb/api/answer/query_answer.py | 14 - python/typedb/api/concept/concept.py | 90 -- .../typedb/api/concept/instance/attribute.py | 30 - python/typedb/api/concept/instance/entity.py | 8 - .../typedb/api/concept/instance/instance.py | 6 - .../typedb/api/concept/instance/relation.py | 8 - .../typedb/api/concept/type/attribute_type.py | 4 - python/typedb/api/concept/type/entity_type.py | 4 - .../typedb/api/concept/type/relation_type.py | 4 - python/typedb/api/concept/type/role_type.py | 4 - python/typedb/api/concept/type/type.py | 2 - python/typedb/api/concept/value/value.py | 28 - .../api/connection/consistency_level.py | 129 +++ python/typedb/api/connection/database.py | 286 ------ python/typedb/api/connection/driver.py | 125 ++- .../typedb/api/connection/driver_options.py | 148 ++- .../api/connection/driver_tls_config.py | 118 +++ python/typedb/api/connection/query_options.py | 2 +- python/typedb/api/connection/transaction.py | 10 - .../api/connection/transaction_options.py | 22 +- python/typedb/api/database/database.py | 101 ++ .../typedb/api/database/database_manager.py | 114 +++ python/typedb/api/server/replica_role.py | 54 ++ python/typedb/api/server/server_replica.py | 100 ++ python/typedb/api/server/server_version.py | 71 ++ python/typedb/api/user/user.py | 116 +-- python/typedb/api/user/user_manager.py | 112 +++ python/typedb/common/datetime.py | 32 +- python/typedb/common/enums.py | 1 + python/typedb/common/exception.py | 10 +- python/typedb/common/promise.py | 2 - python/typedb/connection/driver.py | 118 ++- python/typedb/connection/server_replica.py | 68 ++ python/typedb/connection/transaction.py | 2 +- .../{connection => database}/database.py | 60 +- .../database_manager.py | 32 +- python/typedb/driver.py | 27 +- python/typedb/user/user.py | 18 +- python/typedb/user/user_manager.py | 36 +- rust/Cargo.toml | 35 +- rust/README.md | 9 +- rust/docs_structure.bzl | 17 +- rust/example.rs | 9 +- rust/src/analyze/pipeline.rs | 2 +- rust/src/answer/concept_document.rs | 2 +- rust/src/answer/concept_row.rs | 4 +- rust/src/answer/mod.rs | 8 +- rust/src/common/{ => address}/address.rs | 19 +- .../src/common/address/address_translation.rs | 44 + rust/src/common/address/addresses.rs | 232 +++++ .../src/common/address/mod.rs | 10 +- rust/src/common/consistency_level.rs | 54 ++ rust/src/common/error.rs | 190 ++-- rust/src/common/info.rs | 17 - rust/src/common/mod.rs | 2 + rust/src/common/transaction_options.rs | 15 +- rust/src/concept/mod.rs | 40 +- rust/src/concept/value.rs | 34 +- rust/src/connection/database/import_stream.rs | 2 +- rust/src/connection/driver_options.rs | 134 ++- rust/src/connection/driver_tls_config.rs | 121 +++ rust/src/connection/message.rs | 19 +- rust/src/connection/mod.rs | 10 +- rust/src/connection/network/channel.rs | 24 +- rust/src/connection/network/proto/concept.rs | 1 - rust/src/connection/network/proto/database.rs | 24 +- rust/src/connection/network/proto/message.rs | 107 ++- rust/src/connection/network/proto/mod.rs | 1 + rust/src/connection/network/proto/server.rs | 73 ++ rust/src/connection/network/stub.rs | 47 +- .../src/connection/network/transmitter/rpc.rs | 77 +- .../network/transmitter/transaction.rs | 4 +- rust/src/connection/server/mod.rs | 23 + .../{ => server}/server_connection.rs | 146 +-- rust/src/connection/server/server_manager.rs | 553 +++++++++++ rust/src/connection/server/server_replica.rs | 183 ++++ rust/src/connection/server/server_version.rs | 44 + rust/src/connection/transaction_stream.rs | 4 +- rust/src/database/database.rs | 488 +++------- rust/src/database/database_manager.rs | 312 +++--- rust/src/database/migration.rs | 8 +- rust/src/driver.rs | 415 +++++--- rust/src/lib.rs | 10 +- rust/src/transaction.rs | 16 +- rust/src/user/user.rs | 118 ++- rust/src/user/user_manager.rs | 255 +++-- rust/tests/BUILD | 1 + rust/tests/behaviour/config/BUILD | 8 +- rust/tests/behaviour/driver/BUILD | 6 + rust/tests/behaviour/driver/cluster.rs | 42 + rust/tests/behaviour/steps/Cargo.toml | 12 +- rust/tests/behaviour/steps/analyze.rs | 4 +- .../behaviour/steps/connection/database.rs | 50 +- rust/tests/behaviour/steps/connection/mod.rs | 142 ++- .../behaviour/steps/connection/transaction.rs | 30 +- rust/tests/behaviour/steps/connection/user.rs | 23 +- rust/tests/behaviour/steps/lib.rs | 129 ++- rust/tests/behaviour/steps/params.rs | 68 +- rust/tests/behaviour/steps/query.rs | 16 +- rust/tests/behaviour/steps/util.rs | 20 +- rust/tests/integration/BUILD | 5 - rust/tests/integration/cluster/BUILD | 38 +- rust/tests/integration/cluster/clustering.rs | 338 +++++++ rust/tests/integration/cluster/mod.rs | 3 + rust/tests/integration/cluster/playground.rs | 106 +++ rust/tests/integration/driver.rs | 10 +- rust/tests/integration/example.rs | 13 +- tool/docs/rust/RustDocsParser.kt | 14 +- tool/test/BUILD | 38 +- tool/test/resources/BUILD | 7 +- tool/test/resources/config.yml | 32 + .../encryption/ext-grpc-certificate.pem | 64 +- .../encryption/ext-grpc-private-key.pem | 52 +- .../resources/encryption/ext-grpc-root-ca.pem | 47 +- .../encryption/int-grpc-certificate.pem | 64 +- .../encryption/int-grpc-private-key.pem | 52 +- .../resources/encryption/int-grpc-root-ca.pem | 47 +- .../resources/encryption/int-zmq-private-key | 1 - .../resources/encryption/int-zmq-public-key | 1 - .../test/resources/encryption/keystore.pkcs12 | Bin 9373 -> 4363 bytes tool/test/start-cluster-servers.sh | 86 +- ...mmunity-server.sh => start-core-server.sh} | 6 +- tool/test/stop-cluster-servers.sh | 12 +- ...ommunity-server.sh => stop-core-server.sh} | 0 359 files changed, 17063 insertions(+), 4625 deletions(-) rename .factory/{test-community.sh => test-core.sh} (90%) rename c/src/{ => common}/error.rs (85%) rename c/src/{ => common}/iterator.rs (77%) rename c/src/{ => common}/memory.rs (79%) rename c/src/{common.rs => common/mod.rs} (75%) rename c/src/{ => common}/promise.rs (99%) delete mode 100644 c/src/connection.rs create mode 100644 c/src/credentials.rs delete mode 100644 c/src/database.rs create mode 100644 c/src/database/database.rs create mode 100644 c/src/database/database_manager.rs create mode 100644 c/src/database/mod.rs delete mode 100644 c/src/database_manager.rs create mode 100644 c/src/driver.rs create mode 100644 c/src/driver_options.rs create mode 100644 c/src/driver_tls_config.rs create mode 100644 c/src/server/consistency_level.rs create mode 100644 c/src/server/mod.rs create mode 100644 c/src/server/server_replica.rs create mode 100644 c/src/server/server_version.rs delete mode 100644 c/src/user.rs create mode 100644 c/src/user/mod.rs create mode 100644 c/src/user/user.rs create mode 100644 c/src/user/user_manager.rs delete mode 100644 c/src/user_manager.rs create mode 100644 docs/modules/ROOT/partials/c/session/options.adoc create mode 100644 docs/modules/ROOT/partials/http-ts/connection/Server.adoc create mode 100644 docs/modules/ROOT/partials/http-ts/response/ServersListResponse.adoc create mode 100644 docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Eventual.adoc create mode 100644 docs/modules/ROOT/partials/java/connection/ConsistencyLevel.ReplicaDependent.adoc create mode 100644 docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Strong.adoc create mode 100644 docs/modules/ROOT/partials/java/connection/ConsistencyLevel.adoc create mode 100644 docs/modules/ROOT/partials/java/connection/DriverTlsConfig.adoc create mode 100644 docs/modules/ROOT/partials/java/connection/ReplicaRole.adoc create mode 100644 docs/modules/ROOT/partials/java/connection/ServerReplica.adoc create mode 100644 docs/modules/ROOT/partials/java/connection/ServerVersion.adoc create mode 100644 docs/modules/ROOT/partials/python/connection/ConsistencyLevel.adoc create mode 100644 docs/modules/ROOT/partials/python/connection/DriverTlsConfig.adoc create mode 100644 docs/modules/ROOT/partials/python/connection/Eventual.adoc create mode 100644 docs/modules/ROOT/partials/python/connection/ReplicaDependent.adoc create mode 100644 docs/modules/ROOT/partials/python/connection/ReplicaRole.adoc create mode 100644 docs/modules/ROOT/partials/python/connection/ServerReplica.adoc create mode 100644 docs/modules/ROOT/partials/python/connection/ServerVersion.adoc create mode 100644 docs/modules/ROOT/partials/python/connection/Strong.adoc create mode 100644 docs/modules/ROOT/partials/rust/connection/Address.adoc create mode 100644 docs/modules/ROOT/partials/rust/connection/Addresses.adoc create mode 100644 docs/modules/ROOT/partials/rust/connection/AvailableServerReplica.adoc create mode 100644 docs/modules/ROOT/partials/rust/connection/ConsistencyLevel.adoc create mode 100644 docs/modules/ROOT/partials/rust/connection/DriverTlsConfig.adoc create mode 100644 docs/modules/ROOT/partials/rust/connection/ReplicaRole.adoc create mode 100644 docs/modules/ROOT/partials/rust/connection/ServerReplica.adoc create mode 100644 docs/modules/ROOT/partials/rust/connection/ServerVersion.adoc create mode 100644 docs/modules/ROOT/partials/rust/connection/Trait_Replica.adoc create mode 100644 java/api/ConsistencyLevel.java create mode 100644 java/api/DriverTlsConfig.java create mode 100644 java/api/server/ReplicaRole.java create mode 100644 java/api/server/ServerReplica.java create mode 100644 java/api/server/ServerVersion.java create mode 100644 java/connection/ServerReplicaImpl.java rename java/test/behaviour/connection/{ConnectionStepsCommunity.java => ConnectionStepsCore.java} (63%) create mode 100644 java/test/behaviour/driver/cluster/BUILD create mode 100644 java/test/behaviour/driver/cluster/ClusterTest.java delete mode 100644 python/tests/behaviour/background/community/environment.py create mode 100644 python/tests/behaviour/background/core/environment.py create mode 100644 python/tests/behaviour/driver/cluster/BUILD create mode 100644 python/typedb/api/connection/consistency_level.py delete mode 100644 python/typedb/api/connection/database.py create mode 100644 python/typedb/api/connection/driver_tls_config.py create mode 100644 python/typedb/api/database/database.py create mode 100644 python/typedb/api/database/database_manager.py create mode 100644 python/typedb/api/server/replica_role.py create mode 100644 python/typedb/api/server/server_replica.py create mode 100644 python/typedb/api/server/server_version.py create mode 100644 python/typedb/api/user/user_manager.py create mode 100644 python/typedb/connection/server_replica.py rename python/typedb/{connection => database}/database.py (60%) rename python/typedb/{connection => database}/database_manager.py (71%) rename rust/src/common/{ => address}/address.rs (77%) create mode 100644 rust/src/common/address/address_translation.rs create mode 100644 rust/src/common/address/addresses.rs rename tool/test/EchoJavaHome.java => rust/src/common/address/mod.rs (81%) create mode 100644 rust/src/common/consistency_level.rs create mode 100644 rust/src/connection/driver_tls_config.rs create mode 100644 rust/src/connection/network/proto/server.rs create mode 100644 rust/src/connection/server/mod.rs rename rust/src/connection/{ => server}/server_connection.rs (80%) create mode 100644 rust/src/connection/server/server_manager.rs create mode 100644 rust/src/connection/server/server_replica.rs create mode 100644 rust/src/connection/server/server_version.rs create mode 100644 rust/tests/behaviour/driver/cluster.rs create mode 100644 rust/tests/integration/cluster/clustering.rs create mode 100644 rust/tests/integration/cluster/playground.rs create mode 100644 tool/test/resources/config.yml delete mode 100644 tool/test/resources/encryption/int-zmq-private-key delete mode 100644 tool/test/resources/encryption/int-zmq-public-key rename tool/test/{start-community-server.sh => start-core-server.sh} (82%) rename tool/test/{stop-community-server.sh => stop-core-server.sh} (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2c39b7ce47..113f3e59c2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -134,21 +134,21 @@ commands: steps: - install-pip-requirements - run: | - tool/test/start-community-server.sh + tool/test/start-core-server.sh python3 -m pip install wheel python3 -m pip install --extra-index-url https://repo.typedb.com/public/public-snapshot/python/simple typedb-driver==0.0.0+$(git rev-parse HEAD) sleep 5 pushd python/tests/deployment/ python3 -m unittest test && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 popd - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh exit $TEST_SUCCESS test-pip-snapshot-mac-rosetta: steps: - install-brew-rosetta - run: | - tool/test/start-community-server.sh + tool/test/start-core-server.sh python3 -m pip install wheel python3 -m pip install pip python3 -m pip install -r python/requirements_dev.txt @@ -157,7 +157,7 @@ commands: pushd python/tests/deployment/ python3 -m unittest test && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 popd - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh exit $TEST_SUCCESS deploy-pip-release-unix: @@ -207,20 +207,20 @@ commands: test-maven-snapshot-unix: steps: - run: | - tool/test/start-community-server.sh + tool/test/start-core-server.sh sed -i -e "s/DRIVER_JAVA_VERSION_MARKER/0.0.0-$CIRCLE_SHA1/g" java/test/deployment/pom.xml cat java/test/deployment/pom.xml (cd java/test/deployment && mvn test) - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh test-maven-snapshot-mac-rosetta: steps: - run: | - tool/test/start-community-server.sh + tool/test/start-core-server.sh sed -i -e "s/DRIVER_JAVA_VERSION_MARKER/0.0.0-$CIRCLE_SHA1/g" java/test/deployment/pom.xml cat java/test/deployment/pom.xml (cd java/test/deployment && /usr/local/bin/mvn test) - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh deploy-maven-jni-release-unix: steps: @@ -262,12 +262,12 @@ commands: cmake3 ../c/tests/assembly -DTYPEDB_ASSEMBLY=$(pwd)/$ASSEMBLY && cmake3 --build . --config release popd - tool/test/start-community-server.sh + tool/test/start-core-server.sh sleep 5 pushd test_assembly_clib LD_LIBRARY_PATH=$ASSEMBLY/lib ./test_assembly && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 popd - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh exit $TEST_SUCCESS test-clib-assembly-mac: @@ -285,12 +285,12 @@ commands: cmake ../c/tests/assembly -DTYPEDB_ASSEMBLY=$(pwd)/$ASSEMBLY -DCMAKE_OSX_ARCHITECTURES=<> && cmake --build . --config release popd - tool/test/start-community-server.sh + tool/test/start-core-server.sh sleep 5 pushd test_assembly_clib DYLD_LIBRARY_PATH=$ASSEMBLY/lib ./test_assembly && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 popd - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh exit $TEST_SUCCESS deploy-clib-release-unix: @@ -326,12 +326,12 @@ commands: cmake3 ../cpp/test/assembly -DTYPEDB_ASSEMBLY=$(pwd)/$ASSEMBLY && cmake3 --build . --config release popd - tool/test/start-community-server.sh + tool/test/start-core-server.sh sleep 5 pushd test_assembly_cpp LD_LIBRARY_PATH=$ASSEMBLY/lib ./test_assembly && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 popd - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh exit $TEST_SUCCESS test-cpp-assembly-mac: @@ -349,12 +349,12 @@ commands: cmake ../cpp/test/assembly -DTYPEDB_ASSEMBLY=$(pwd)/$ASSEMBLY -DCMAKE_OSX_ARCHITECTURES=<> && cmake --build . --config release popd - tool/test/start-community-server.sh + tool/test/start-core-server.sh sleep 5 pushd test_assembly_cpp DYLD_LIBRARY_PATH=$ASSEMBLY/lib ./test_assembly && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 popd - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh exit $TEST_SUCCESS deploy-cpp-release-unix: @@ -410,22 +410,22 @@ commands: test-dotnet-snapshot-unix: steps: - run: | - tool/test/start-community-server.sh + tool/test/start-core-server.sh sleep 5 sed -i -e "s/DRIVER_CSHARP_VERSION_MARKER/0.0.0-$CIRCLE_SHA1/g" csharp/Test/Deployment/NugetApplicationTest.csproj cat csharp/Test/Deployment/NugetApplicationTest.csproj (cd csharp/Test/Deployment && dotnet run NugetApplicationTest.csproj) - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh test-dotnet-snapshot-mac-rosetta: steps: - run: | - tool/test/start-community-server.sh + tool/test/start-core-server.sh sleep 5 sed -i -e "s/DRIVER_CSHARP_VERSION_MARKER/0.0.0-$CIRCLE_SHA1/g" csharp/Test/Deployment/NugetApplicationTest.csproj cat csharp/Test/Deployment/NugetApplicationTest.csproj (cd csharp/Test/Deployment && /usr/local/bin/dotnet run NugetApplicationTest.csproj) - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh deploy-dotnet-runtime-release-unix: steps: @@ -486,13 +486,13 @@ commands: test-npm-snapshot-unix: steps: - run: | - tool/test/start-community-server.sh + tool/test/start-core-server.sh cd nodejs/test/deployment/ npm install --registry https://npm.cloudsmith.io/typedb/public-snapshot/ "typedb-driver@0.0.0-$CIRCLE_SHA1" npm install jest --global jest --detectOpenHandles application.test.js && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 cd - - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh exit $TEST_SUCCESS deploy-npm-release-unix: @@ -793,7 +793,8 @@ jobs: bazel-arch: amd64 - deploy-crate-release-unix - deploy-maven-release-unix - - deploy-http-ts-npm-release-unix +# TODO: http-ts is disabled in the clustering branch +# - deploy-http-ts-npm-release-unix # - deploy-npm-release-unix deploy-release-dotnet-any: @@ -845,32 +846,32 @@ workflows: - deploy-snapshot-linux-arm64: filters: branches: - only: [master] + only: [master, cluster-support-feature-branch] - deploy-snapshot-linux-x86_64: filters: branches: - only: [master] + only: [master, cluster-support-feature-branch] - deploy-snapshot-mac-arm64: filters: branches: - only: [master] + only: [master, cluster-support-feature-branch] - deploy-snapshot-mac-x86_64: filters: branches: - only: [master] + only: [master, cluster-support-feature-branch] - deploy-snapshot-windows-x86_64: filters: branches: - only: [master] + only: [master, cluster-support-feature-branch] - deploy-snapshot-any: filters: branches: - only: [master] + only: [master, cluster-support-feature-branch] requires: - deploy-snapshot-linux-arm64 - deploy-snapshot-linux-x86_64 @@ -892,7 +893,7 @@ workflows: - test-snapshot-linux-arm64: filters: branches: - only: [master] + only: [master, cluster-support-feature-branch] requires: - deploy-snapshot-linux-arm64 - deploy-snapshot-any @@ -901,7 +902,7 @@ workflows: - test-snapshot-linux-x86_64: filters: branches: - only: [master] + only: [master, cluster-support-feature-branch] requires: - deploy-snapshot-linux-x86_64 - deploy-snapshot-any @@ -910,7 +911,7 @@ workflows: - test-snapshot-mac-arm64: filters: branches: - only: [master] + only: [master, cluster-support-feature-branch] requires: - deploy-snapshot-mac-arm64 - deploy-snapshot-any @@ -919,20 +920,19 @@ workflows: - test-snapshot-mac-x86_64: filters: branches: - only: [master] + only: [master, cluster-support-feature-branch] requires: - deploy-snapshot-mac-x86_64 - deploy-snapshot-any # - deploy-snapshot-dotnet-any -# TODO: Windows typedb artifact is not ready -# - test-snapshot-windows-x86_64: -# filters: -# branches: -# only: [master] -# requires: -# - deploy-snapshot-windows-x86_64 -# - deploy-snapshot-any + - test-snapshot-windows-x86_64: + filters: + branches: + only: [master, cluster-support-feature-branch] + requires: + - deploy-snapshot-windows-x86_64 + - deploy-snapshot-any # - deploy-snapshot-dotnet-any # TODO: npm is not ready diff --git a/.circleci/windows/clib/test_assembly.bat b/.circleci/windows/clib/test_assembly.bat index eb2ea6b81f..d74fed9fa9 100644 --- a/.circleci/windows/clib/test_assembly.bat +++ b/.circleci/windows/clib/test_assembly.bat @@ -35,7 +35,7 @@ cmake --build . --config release popd set PATH=%cd%\test_assembly_clib\typedb-driver-clib-windows-x86_64\lib;%PATH%; -START /B "" typedb-all-windows\typedb server --development-mode.enabled=true +START /B "" typedb-all-windows\typedb server --development-mode.enabled=true --server.http.enabled=false powershell -Command "Start-Sleep -Seconds 10" test_assembly_clib\Release\test_assembly.exe diff --git a/.circleci/windows/cpp/test_assembly.bat b/.circleci/windows/cpp/test_assembly.bat index 2d0982293f..2e3639bb33 100644 --- a/.circleci/windows/cpp/test_assembly.bat +++ b/.circleci/windows/cpp/test_assembly.bat @@ -35,7 +35,7 @@ cmake --build . --config release popd set PATH=%cd%\test_assembly_cpp\typedb-driver-cpp-windows-x86_64\lib;%PATH%; -START /B "" typedb-all-windows\typedb server --development-mode.enabled=true +START /B "" typedb-all-windows\typedb server --development-mode.enabled=true --server.http.enabled=false powershell -Command "Start-Sleep -Seconds 10" test_assembly_cpp\Release\test_assembly.exe diff --git a/.circleci/windows/csharp/test_deploy_snapshot.bat b/.circleci/windows/csharp/test_deploy_snapshot.bat index 27895e2d17..08d18b7446 100644 --- a/.circleci/windows/csharp/test_deploy_snapshot.bat +++ b/.circleci/windows/csharp/test_deploy_snapshot.bat @@ -21,11 +21,11 @@ choco install 7zip.portable --limit-output --yes --no-progress CALL refreshenv bazel --output_user_root=C:\b build --config=ci @typedb_artifact_windows-x86_64//file -powershell -Command "Move-Item -Path bazel-typedb-driver\external\typedb_artifact_windows-x86_64\file\typedb-server-windows* -Destination typedb-server-windows.zip" -7z x typedb-server-windows.zip -RD /S /Q typedb-server-windows -powershell -Command "Move-Item -Path typedb-server-windows-* -Destination typedb-server-windows" -START /B "" typedb-server-windows\typedb server --development-mode.enable=true +powershell -Command "Move-Item -Path bazel-typedb-driver\external\typedb_artifact_windows-x86_64\file\typedb-all-windows* -Destination typedb-all-windows.zip" +7z x typedb-all-windows.zip +RD /S /Q typedb-all-windows +powershell -Command "Move-Item -Path typedb-all-windows-* -Destination typedb-all-windows" +START /B "" typedb-all-windows\typedb server --development-mode.enabled=true --server.http.enabled=false powershell -Command "(gc csharp\Test\Deployment\NugetApplicationTest.csproj) -replace 'DRIVER_CSHARP_VERSION_MARKER', '0.0.0-%CIRCLE_SHA1%' | Out-File -encoding ASCII csharp\Test\Deployment\NugetApplicationTest.csproj" type csharp\Test\Deployment\NugetApplicationTest.csproj diff --git a/.circleci/windows/java/test_deploy_snapshot.bat b/.circleci/windows/java/test_deploy_snapshot.bat index af3a757fb3..80ee47cd6a 100644 --- a/.circleci/windows/java/test_deploy_snapshot.bat +++ b/.circleci/windows/java/test_deploy_snapshot.bat @@ -21,11 +21,11 @@ choco install 7zip.portable --limit-output --yes --no-progress CALL refreshenv bazel --output_user_root=C:\b build --config=ci @typedb_artifact_windows-x86_64//file -powershell -Command "Move-Item -Path bazel-typedb-driver\external\typedb_artifact_windows-x86_64\file\typedb-server-windows* -Destination typedb-server-windows.zip" -7z x typedb-server-windows.zip -RD /S /Q typedb-server-windows -powershell -Command "Move-Item -Path typedb-server-windows-* -Destination typedb-server-windows" -START /B "" typedb-server-windows\typedb server --development-mode.enable=true +powershell -Command "Move-Item -Path bazel-typedb-driver\external\typedb_artifact_windows-x86_64\file\typedb-all-windows* -Destination typedb-all-windows.zip" +7z x typedb-all-windows.zip +RD /S /Q typedb-all-windows +powershell -Command "Move-Item -Path typedb-all-windows-* -Destination typedb-all-windows" +START /B "" typedb-all-windows\typedb server --development-mode.enabled=true --server.http.enabled=false powershell -Command "(gc java\test\deployment\pom.xml) -replace 'DRIVER_JAVA_VERSION_MARKER', '0.0.0-%CIRCLE_SHA1%' | Out-File -encoding ASCII java\test\deployment\pom.xml" type java\test\deployment\pom.xml diff --git a/.circleci/windows/python/test_deploy_snapshot.bat b/.circleci/windows/python/test_deploy_snapshot.bat index 4061ce9a10..14bbe420cf 100644 --- a/.circleci/windows/python/test_deploy_snapshot.bat +++ b/.circleci/windows/python/test_deploy_snapshot.bat @@ -23,11 +23,11 @@ git rev-parse HEAD > version_temp.txt set /p VER= /var/tmp/doxygen && sudo mv /var/tmp/doxygen /usr/local/bin/ && sudo chmod +x /usr/local/bin/doxygen bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh - + # TODO: Temporarily update only 3.0 drivers - DOCS_DIRS=("docs/modules/ROOT/partials/rust" "docs/modules/ROOT/partials/java" "docs/modules/ROOT/partials/python" "docs/modules/ROOT/partials/http-ts" "docs/modules/ROOT/partials/c") + DOCS_DIRS=("docs/modules/ROOT/partials/rust" "docs/modules/ROOT/partials/java" "docs/modules/ROOT/partials/python" "docs/modules/ROOT/partials/http-ts") find "${DOCS_DIRS[@]}" -type f ! -name 'api-reference.adoc' -exec rm -f {} \; tool/docs/update.sh git add "${DOCS_DIRS[@]}" - git diff --exit-code HEAD "${DOCS_DIRS[@]}" || { + git diff --exit-code HEAD "${DOCS_DIRS[@]}" || { echo "Failed to verify docs files: please update it manually and verify the changes" exit 1 } - + tool/docs/update_readme.sh git add . - git diff --exit-code || { - echo "Failed to verify README files: plese update it manually and verify the changes" + git diff --exit-code || { + echo "Failed to verify README files: please update it manually and verify the changes" exit 1 } @@ -102,20 +102,20 @@ build: bazel test --config=ci //rust:typedb_driver_unit_tests --test_output=streamed || exit 1 - tool/test/start-community-server.sh && + tool/test/start-core-server.sh && bazel test --config=ci //rust/tests/integration:all --test_output=streamed --test_arg=--nocapture && - export COMMUNITY_FAILED= || export COMMUNITY_FAILED=1 - tool/test/stop-community-server.sh - if [[ -n "$COMMUNITY_FAILED" ]]; then exit 1; fi + export CORE_FAILED= || export CORE_FAILED=1 + tool/test/stop-core-server.sh + if [[ -n "$CORE_FAILED" ]]; then exit 1; fi # TODO: Use cluster server artifact with 3 nodes for the same common tests when available - # tool/test/start-cluster-servers.sh 3 && + # source tool/test/start-cluster-servers.sh 3 && # bazel test --config=ci //rust/tests/integration:all --test_output=streamed --test_arg=--nocapture && # export CLUSTER_FAILED= || export CLUSTER_FAILED=1 # tool/test/stop-cluster-servers.sh # if [[ -n "$CLUSTER_FAILED" ]]; then exit 1; fi - test-rust-behaviour-community: + test-rust-behaviour-core: image: typedb-ubuntu-20.04 # Ubuntu 20.04 has GLIBC version 2.31 (2020) which we should verify to compile against command: | export ARTIFACT_USERNAME=$REPO_TYPEDB_USERNAME @@ -123,28 +123,31 @@ build: bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc - tool/test/start-community-server.sh && + tool/test/start-core-server.sh && bazel test --config=ci //rust/tests/behaviour/... --test_output=streamed --jobs=1 && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh exit $TEST_SUCCESS - # TODO: Use cluster server artifact with 3 nodes when available (it would do the same thing as community now) - # test-rust-behaviour-cluster: - # image: typedb-ubuntu-20.04 # Ubuntu 20.04 has GLIBC version 2.31 (2020) which we should verify to compile against - # dependencies: - # - build - # command: | - # export ARTIFACT_USERNAME=$REPO_TYPEDB_USERNAME - # export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD - # bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh - # bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc - # - # tool/test/start-cluster-servers.sh 3 && - # bazel test --config=ci //rust/tests/behaviour/... --//rust/tests/behaviour/config:mode=cluster --test_output=streamed --jobs=1 && - # export TEST_SUCCESS=0 || export TEST_SUCCESS=1 - # tool/test/stop-cluster-servers.sh - # exit $TEST_SUCCESS + test-rust-behaviour-cluster: + image: typedb-ubuntu-20.04 # Ubuntu 20.04 has GLIBC version 2.31 (2020) which we should verify to compile against + command: | + export ARTIFACT_USERNAME=$REPO_TYPEDB_USERNAME + export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD + bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh + bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc + + # TODO: run `bazel test --config=ci //rust/tests/behaviour/...` instead of multiple tests (cannot do Clustered migration now) + source tool/test/start-cluster-servers.sh 3 && + bazel test --config=ci //rust/tests/behaviour/connection/... --test_env=ROOT_CA=$ROOT_CA --//rust/tests/behaviour/config:mode=cluster --test_output=streamed --jobs=1 && + bazel test --config=ci //rust/tests/behaviour/driver:test_concept --test_env=ROOT_CA=$ROOT_CA --//rust/tests/behaviour/config:mode=cluster --test_output=streamed --jobs=1 && + bazel test --config=ci //rust/tests/behaviour/driver:test_connection --test_env=ROOT_CA=$ROOT_CA --//rust/tests/behaviour/config:mode=cluster --test_output=streamed --jobs=1 && + bazel test --config=ci //rust/tests/behaviour/driver:test_query --test_env=ROOT_CA=$ROOT_CA --//rust/tests/behaviour/config:mode=cluster --test_output=streamed --jobs=1 && + bazel test --config=ci //rust/tests/behaviour/driver:test_user --test_env=ROOT_CA=$ROOT_CA --//rust/tests/behaviour/config:mode=cluster --test_output=streamed --jobs=1 && + bazel test --config=ci //rust/tests/behaviour/driver:test_cluster --test_env=ROOT_CA=$ROOT_CA --//rust/tests/behaviour/config:mode=cluster --test_output=streamed --jobs=1 && + export TEST_SUCCESS=0 || export TEST_SUCCESS=1 + tool/test/stop-cluster-servers.sh + exit $TEST_SUCCESS test-c-integration: image: typedb-ubuntu-20.04 # Ubuntu 20.04 has GLIBC version 2.31 (2020) which we should verify to compile against @@ -153,10 +156,10 @@ build: export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc - tool/test/start-community-server.sh && + tool/test/start-core-server.sh && bazel test --config=ci //c/tests/integration:test-driver --test_output=errors && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh exit $TEST_SUCCESS test-java-integration: @@ -166,50 +169,53 @@ build: export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc - - tool/test/start-community-server.sh && + + tool/test/start-core-server.sh && bazel test --config=ci //java/test/integration:all --test_output=streamed --jobs=1 && - export COMMUNITY_FAILED= || export COMMUNITY_FAILED=1 - tool/test/stop-community-server.sh - if [[ -n "$COMMUNITY_FAILED" ]]; then exit 1; fi + export CORE_FAILED= || export CORE_FAILED=1 + tool/test/stop-core-server.sh + if [[ -n "$CORE_FAILED" ]]; then exit 1; fi # TODO: Use cluster server artifact with 3 nodes for the same common tests when available - # tool/test/start-cluster-servers.sh 3 && + # source tool/test/start-cluster-servers.sh 3 && # bazel test --config=ci //java/test/integration:all --test_output=streamed --jobs=1 && # export CLUSTER_FAILED= || export CLUSTER_FAILED=1 # tool/test/stop-cluster-servers.sh # if [[ -n "CLUSTER_FAILED" ]]; then exit 1; fi - test-java-behaviour-community: + test-java-behaviour-core: image: typedb-ubuntu-22.04 command: | export ARTIFACT_USERNAME=$REPO_TYPEDB_USERNAME export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh - - tool/test/start-community-server.sh && - .factory/test-community.sh //java/test/behaviour/... --test_output=streamed --jobs=1 && + + tool/test/start-core-server.sh && + .factory/test-core.sh //java/test/behaviour/... --test_output=streamed --jobs=1 && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 - tool/test/stop-community-server.sh + tool/test/stop-core-server.sh exit $TEST_SUCCESS - # TODO: Use cluster server artifact with 3 nodes when available (it would do the same thing as community now) - # test-java-behaviour-cluster: - # image: typedb-ubuntu-22.04 - # dependencies: - # - build - # command: | - # export ARTIFACT_USERNAME=$REPO_TYPEDB_USERNAME - # export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD - # bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh - # bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc - # - # tool/test/start-cluster-servers.sh 3 && - # .factory/test-cluster.sh //java/test/behaviour/... --test_output=streamed --jobs=1 && - # export TEST_SUCCESS=0 || export TEST_SUCCESS=1 - # tool/test/stop-cluster-servers.sh - # exit $TEST_SUCCESS + test-java-behaviour-cluster: + image: typedb-ubuntu-22.04 + command: | + export ARTIFACT_USERNAME=$REPO_TYPEDB_USERNAME + export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD + bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh + bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc + + # TODO: run `.factory/test-cluster.sh //java/test/behaviour/...` instead of multiple tests (cannot do Clustered migration now) + source tool/test/start-cluster-servers.sh 3 && + .factory/test-cluster.sh //java/test/behaviour/connection/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //java/test/behaviour/driver/concept/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //java/test/behaviour/driver/connection/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //java/test/behaviour/driver/query/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //java/test/behaviour/driver/user/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //java/test/behaviour/driver/cluster/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + export TEST_SUCCESS=0 || export TEST_SUCCESS=1 + tool/test/stop-cluster-servers.sh + exit $TEST_SUCCESS test-python-integration: image: typedb-ubuntu-22.04 @@ -221,20 +227,36 @@ build: bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc - tool/test/start-community-server.sh && + tool/test/start-core-server.sh && bazel test --config=ci //python/tests/integration:all --test_output=streamed --jobs=1 && - export COMMUNITY_FAILED= || export COMMUNITY_FAILED=1 - tool/test/stop-community-server.sh - if [[ -n "$COMMUNITY_FAILED" ]]; then exit 1; fi + export CORE_FAILED= || export CORE_FAILED=1 + tool/test/stop-core-server.sh + if [[ -n "$CORE_FAILED" ]]; then exit 1; fi # TODO: Use cluster server artifact with 3 nodes when available - # tool/test/start-cluster-servers.sh 3 && + # source tool/test/start-cluster-servers.sh 3 && # bazel test --config=ci //python/tests/integration:all --test_output=streamed --jobs=1 && # export CLUSTER_FAILED= || export CLUSTER_FAILED=1 # tool/test/stop-cluster-servers.sh # if [[ -n "$CLUSTER_FAILED" ]]; then exit 1; fi - test-python-behaviour-community: + test-python-behaviour-core: + image: typedb-ubuntu-22.04 + type: foreground + command: | + export PATH="$HOME/.local/bin:$PATH" + export ARTIFACT_USERNAME=$REPO_TYPEDB_USERNAME + export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD + bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh + bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc + + tool/test/start-core-server.sh && + .factory/test-core.sh //python/tests/behaviour/... --test_output=streamed --jobs=1 && + export TEST_SUCCESS=0 || export TEST_SUCCESS=1 + tool/test/stop-core-server.sh + exit $TEST_SUCCESS + + test-python-behaviour-cluster: image: typedb-ubuntu-22.04 type: foreground command: | @@ -244,33 +266,19 @@ build: bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc - tool/test/start-community-server.sh && - .factory/test-community.sh //python/tests/behaviour/... --test_output=streamed --jobs=1 && + # TODO: run `.factory/test-cluster.sh //python/tests/behaviour/...` instead of multiple tests (cannot do Clustered migration now) + source tool/test/start-cluster-servers.sh 3 && + .factory/test-cluster.sh //python/tests/behaviour/connection/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //python/tests/behaviour/driver/concept/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //python/tests/behaviour/driver/connection/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //python/tests/behaviour/driver/query/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //python/tests/behaviour/driver/user/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //python/tests/behaviour/driver/cluster/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 - tool/test/stop-community-server.sh + tool/test/stop-cluster-servers.sh exit $TEST_SUCCESS - # TODO: Use cluster server artifact with 3 nodes when available (it would do the same thing as community now) - # test-python-behaviour-cluster: - # image: typedb-ubuntu-22.04 - # dependencies: - # - build - # type: foreground - # command: | - # export PATH="$HOME/.local/bin:$PATH" - # export ARTIFACT_USERNAME=$REPO_TYPEDB_USERNAME - # export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD - # bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh - # bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc - # - # tool/test/start-cluster-servers.sh 3 && - # .factory/test-cluster.sh //python/tests/behaviour/... --test_output=streamed --jobs=1 && - # export TEST_SUCCESS=0 || export TEST_SUCCESS=1 - # tool/test/stop-cluster-servers.sh - # exit $TEST_SUCCESS - - - test-http-ts-behaviour-community: + test-http-ts-behaviour-core: image: typedb-ubuntu-22.04 type: foreground command: | @@ -282,10 +290,34 @@ build: tool/http-ts/install-deps.sh - tool/test/start-community-server.sh && - .factory/test-community.sh //http-ts/tests/behaviour/... --test_output=streamed --jobs=1 && + tool/test/start-core-server.sh && + .factory/test-core.sh //http-ts/tests/behaviour/... --test_output=streamed --jobs=1 && + export TEST_SUCCESS=0 || export TEST_SUCCESS=1 + tool/test/stop-core-server.sh + exit $TEST_SUCCESS + + test-http-ts-behaviour-cluster: + image: typedb-ubuntu-22.04 + type: foreground + command: | + export PATH="$HOME/.local/bin:$PATH" + export ARTIFACT_USERNAME=$REPO_TYPEDB_USERNAME + export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD + bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh + bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc + + tool/http-ts/install-deps.sh + + # TODO: we cannot run them now because we cannot register replicas through HTTP. fix it later + # .factory/test-cluster.sh //http-ts/tests/behaviour/feature:cluster-cluster --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + + source tool/test/start-cluster-servers.sh 3 && + .factory/test-cluster.sh //http-ts/tests/behaviour/feature:concept-cluster --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //http-ts/tests/behaviour/feature:query-cluster --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //http-ts/tests/behaviour/feature:user-cluster --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && + .factory/test-cluster.sh //http-ts/tests/behaviour/feature:connection-cluster --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && export TEST_SUCCESS=0 || export TEST_SUCCESS=1 - tool/test/stop-community-server.sh + tool/test/stop-cluster-servers.sh exit $TEST_SUCCESS # test-nodejs-integration: @@ -299,13 +331,13 @@ build: # bazel build --config=ci //nodejs/... # cp -rL bazel-bin/nodejs/node_modules nodejs/. # cp -rL bazel-bin/nodejs/dist nodejs/. -# tool/test/start-community-server.sh && +# tool/test/start-core-server.sh && # node nodejs/test/integration/test-concept.js && # node nodejs/test/integration/test-query.js && # node nodejs/test/integration/test-connection-core.js && -# export COMMUNITY_FAILED= || export COMMUNITY_FAILED=1 -# tool/test/stop-community-server.sh -# if [[ -n "$COMMUNITY_FAILED" ]]; then exit 1; fi +# export CORE_FAILED= || export CORE_FAILED=1 +# tool/test/stop-core-server.sh +# if [[ -n "$CORE_FAILED" ]]; then exit 1; fi # # source tool/test/start-cluster-servers.sh 3 && # use source to receive export vars # node nodejs/test/integration/test-connection-cloud.js && @@ -314,7 +346,7 @@ build: # tool/test/stop-cluster-servers.sh # if [[ -n "$CLUSTER_FAILED" ]]; then exit 1; fi # -# test-nodejs-behaviour-community: +# test-nodejs-behaviour-core: # image: typedb-ubuntu-22.04 # dependencies: # - build @@ -322,15 +354,15 @@ build: # export ARTIFACT_USERNAME=$REPO_TYPEDB_USERNAME # export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD # bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc -# tool/test/start-community-server.sh && -# .factory/test-community.sh //nodejs/test/behaviour/connection/database/... --test_output=errors --jobs=1 && -# .factory/test-community.sh //nodejs/test/behaviour/connection/session/... --test_output=errors --jobs=1 && -# .factory/test-community.sh //nodejs/test/behaviour/connection/transaction/... --test_output=errors --jobs=1 && -# .factory/test-community.sh //nodejs/test/behaviour/concept/... --test_output=errors --jobs=1 && -# .factory/test-community.sh //nodejs/test/behaviour/driver/query/... --test_output=errors --jobs=1 && -# .factory/test-community.sh //nodejs/test/behaviour/query/language/... --test_output=errors --jobs=1 && +# tool/test/start-core-server.sh && +# .factory/test-core.sh //nodejs/test/behaviour/connection/database/... --test_output=errors --jobs=1 && +# .factory/test-core.sh //nodejs/test/behaviour/connection/session/... --test_output=errors --jobs=1 && +# .factory/test-core.sh //nodejs/test/behaviour/connection/transaction/... --test_output=errors --jobs=1 && +# .factory/test-core.sh //nodejs/test/behaviour/concept/... --test_output=errors --jobs=1 && +# .factory/test-core.sh //nodejs/test/behaviour/driver/query/... --test_output=errors --jobs=1 && +# .factory/test-core.sh //nodejs/test/behaviour/query/language/... --test_output=errors --jobs=1 && # export TEST_SUCCESS=0 || export TEST_SUCCESS=1 -# tool/test/stop-community-server.sh +# tool/test/stop-core-server.sh # exit $TEST_SUCCESS # # test-nodejs-behaviour-cluster: @@ -365,11 +397,11 @@ build: # export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD # bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh # bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc -# tool/test/start-community-server.sh && +# tool/test/start-core-server.sh && # bazel test --config=ci //cpp/test/integration:test-cpp-driver-core --test_output=streamed --jobs=1 && -# export COMMUNITY_FAILED= || export COMMUNITY_FAILED=1 -# tool/test/stop-community-server.sh -# if [[ -n "$COMMUNITY_FAILED" ]]; then exit 1; fi +# export CORE_FAILED= || export CORE_FAILED=1 +# tool/test/stop-core-server.sh +# if [[ -n "$CORE_FAILED" ]]; then exit 1; fi # # source tool/test/start-cluster-servers.sh 3 && # use source to receive export vars # bazel test --config=ci //cpp/test/integration:test-cpp-driver-cloud --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && @@ -377,7 +409,7 @@ build: # tool/test/stop-cluster-servers.sh # if [[ -n "$CLUSTER_FAILED" ]]; then exit 1; fi # -# test-cpp-behaviour-community: +# test-cpp-behaviour-core: # image: typedb-ubuntu-22.04 # dependencies: # - build @@ -389,15 +421,15 @@ build: # export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD # bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh # bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc -# tool/test/start-community-server.sh && -# .factory/test-community.sh //cpp/test/behaviour/connection/database/... --test_output=streamed --jobs=1 && -# .factory/test-community.sh //cpp/test/behaviour/connection/session/... --test_output=streamed --jobs=1 && -# .factory/test-community.sh //cpp/test/behaviour/connection/transaction/... --test_output=streamed --jobs=1 && -# .factory/test-community.sh //cpp/test/behaviour/concept/... --test_output=errors --jobs=1 && -# .factory/test-community.sh //cpp/test/behaviour/driver/query/... --test_output=errors && -# .factory/test-community.sh //cpp/test/behaviour/query/language/... --test_output=errors --jobs=1 && +# tool/test/start-core-server.sh && +# .factory/test-core.sh //cpp/test/behaviour/connection/database/... --test_output=streamed --jobs=1 && +# .factory/test-core.sh //cpp/test/behaviour/connection/session/... --test_output=streamed --jobs=1 && +# .factory/test-core.sh //cpp/test/behaviour/connection/transaction/... --test_output=streamed --jobs=1 && +# .factory/test-core.sh //cpp/test/behaviour/concept/... --test_output=errors --jobs=1 && +# .factory/test-core.sh //cpp/test/behaviour/driver/query/... --test_output=errors && +# .factory/test-core.sh //cpp/test/behaviour/query/language/... --test_output=errors --jobs=1 && # export TEST_SUCCESS=0 || export TEST_SUCCESS=1 -# tool/test/stop-community-server.sh +# tool/test/stop-core-server.sh # exit $TEST_SUCCESS # # test-cpp-behaviour-cluster: @@ -433,13 +465,13 @@ build: # export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD # bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh # bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc -# tool/test/start-community-server.sh && +# tool/test/start-core-server.sh && # bazel test --config=ci //csharp/Test/Integration/Data/... --test_output=streamed --jobs=1 && # bazel test --config=ci //csharp/Test/Integration/Marshal/... --test_output=streamed --jobs=1 && -# .factory/test-community.sh //csharp/Test/Integration/Examples/... --test_output=streamed --jobs=1 && -# export COMMUNITY_FAILED= || export COMMUNITY_FAILED=1 -# tool/test/stop-community-server.sh -# if [[ -n "$COMMUNITY_FAILED" ]]; then exit 1; fi +# .factory/test-core.sh //csharp/Test/Integration/Examples/... --test_output=streamed --jobs=1 && +# export CORE_FAILED= || export CORE_FAILED=1 +# tool/test/stop-core-server.sh +# if [[ -n "$CORE_FAILED" ]]; then exit 1; fi # # source tool/test/start-cluster-servers.sh 3 && # use source to receive export vars # bazel test --config=ci //csharp/Test/Integration/Network/... --test_env=ROOT_CA=$ROOT_CA --test_output=streamed --jobs=1 && @@ -448,7 +480,7 @@ build: # tool/test/stop-cluster-servers.sh # if [[ -n "$CLUSTER_FAILED" ]]; then exit 1; fi # -# test-csharp-behaviour-community: +# test-csharp-behaviour-core: # image: typedb-ubuntu-22.04 # dependencies: # - build @@ -459,16 +491,16 @@ build: # export ARTIFACT_PASSWORD=$REPO_TYPEDB_PASSWORD # bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh # bazel run --config=ci @typedb_dependencies//distribution/artifact:create-netrc -# tool/test/start-community-server.sh && -# .factory/test-community.sh //csharp/Test/Behaviour/Connection/Database/... --test_output=errors --jobs=1 && -# .factory/test-community.sh //csharp/Test/Behaviour/Connection/Session/... --test_output=errors --jobs=1 && -# .factory/test-community.sh //csharp/Test/Behaviour/Connection/Transaction/... --test_output=errors --jobs=1 && -# .factory/test-community.sh //csharp/Test/Behaviour/Concept/... --test_output=errors --jobs=1 && -# .factory/test-community.sh //csharp/Test/Behaviour/Driver/Query/... --test_output=errors && -# .factory/test-community.sh //csharp/Test/Behaviour/Query/Language/... --test_output=errors --jobs=1 && -# .factory/test-community.sh //csharp/Test/Behaviour/Query/Reasoner/... --test_output=errors --jobs=1 && +# tool/test/start-core-server.sh && +# .factory/test-core.sh //csharp/Test/Behaviour/Connection/Database/... --test_output=errors --jobs=1 && +# .factory/test-core.sh //csharp/Test/Behaviour/Connection/Session/... --test_output=errors --jobs=1 && +# .factory/test-core.sh //csharp/Test/Behaviour/Connection/Transaction/... --test_output=errors --jobs=1 && +# .factory/test-core.sh //csharp/Test/Behaviour/Concept/... --test_output=errors --jobs=1 && +# .factory/test-core.sh //csharp/Test/Behaviour/Driver/Query/... --test_output=errors && +# .factory/test-core.sh //csharp/Test/Behaviour/Query/Language/... --test_output=errors --jobs=1 && +# .factory/test-core.sh //csharp/Test/Behaviour/Query/Reasoner/... --test_output=errors --jobs=1 && # export TEST_SUCCESS=0 || export TEST_SUCCESS=1 -# tool/test/stop-community-server.sh +# tool/test/stop-core-server.sh # exit $TEST_SUCCESS # # test-csharp-behaviour-cluster: @@ -504,23 +536,23 @@ build: # - build-dependency # - build-docs # - test-rust-unit-integration -# - test-rust-behaviour-community +# - test-rust-behaviour-core # - test-rust-behaviour-cluster # - test-c-integration # - test-java-integration -# - test-java-behaviour-community +# - test-java-behaviour-core # - test-java-behaviour-cluster -# - test-python-behaviour-community +# - test-python-behaviour-core # - test-python-behaviour-cluster # - test-python-integration # - test-nodejs-integration -# - test-nodejs-behaviour-community +# - test-nodejs-behaviour-core # - test-nodejs-behaviour-cluster # - test-cpp-integration -# - test-cpp-behaviour-community +# - test-cpp-behaviour-core # - test-cpp-behaviour-cluster # - test-csharp-integration -# - test-csharp-behaviour-community +# - test-csharp-behaviour-core # - test-csharp-behaviour-cluster # command: | # sudo add-apt-repository -y ppa:deadsnakes/ppa @@ -534,7 +566,7 @@ build: release: filter: owner: typedb - branch: [master] + branch: [master, cluster-support-feature-branch] validation: validate-dependencies: image: typedb-ubuntu-22.04 diff --git a/.factory/test-community.sh b/.factory/test-core.sh similarity index 90% rename from .factory/test-community.sh rename to .factory/test-core.sh index d4e7d4a56a..274734a960 100755 --- a/.factory/test-community.sh +++ b/.factory/test-core.sh @@ -17,4 +17,4 @@ # under the License. set -ex -bazel test $(bazel query "filter('^.*community.*$', kind(.*_test, $1))") "${@:2}" +bazel test $(bazel query "filter('^.*core.*$', kind(.*_test, $1))") "${@:2}" diff --git a/.gitignore b/.gitignore index 1a35d10719..9ad0258a09 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,12 @@ typedb-test/test-integration/benchmarks/ # Test Runner Files # typedb-all/* +typedb-cluster-all/* +1/* +2/* +3/* +4/* +5/* # Autogenerated Docs # http-ts/docs diff --git a/Cargo.lock b/Cargo.lock index d517fd6d67..ad93018364 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,26 +2,11 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -73,29 +58,29 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.10" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" [[package]] name = "async-attributes" @@ -132,9 +117,9 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.3" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" dependencies = [ "async-task", "concurrent-queue", @@ -165,7 +150,7 @@ dependencies = [ "async-channel 2.5.0", "async-executor", "async-io 2.6.0", - "async-lock 3.4.1", + "async-lock 3.4.2", "blocking", "futures-lite 2.6.1", "once_cell", @@ -204,9 +189,9 @@ dependencies = [ "futures-lite 2.6.1", "parking", "polling 3.11.0", - "rustix 1.1.2", + "rustix 1.1.3", "slab", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -220,9 +205,9 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ "event-listener 5.4.1", "event-listener-strategy", @@ -264,15 +249,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ "async-io 2.6.0", - "async-lock 3.4.1", + "async-lock 3.4.2", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 1.1.2", + "rustix 1.1.3", "signal-hook-registry", "slab", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -285,7 +270,7 @@ dependencies = [ "async-channel 1.9.0", "async-global-executor", "async-io 2.6.0", - "async-lock 3.4.1", + "async-lock 3.4.2", "crossbeam-utils", "futures-channel", "futures-core", @@ -321,7 +306,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -338,7 +323,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -386,7 +371,7 @@ dependencies = [ "rustversion", "serde", "sync_wrapper", - "tower 0.5.2", + "tower 0.5.3", "tower-layer", "tower-service", ] @@ -411,21 +396,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link 0.2.1", -] - [[package]] name = "base64" version = "0.22.1" @@ -440,9 +410,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "blocking" @@ -459,9 +429,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "serde", @@ -469,9 +439,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "bytecount" @@ -481,15 +451,15 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.40" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "shlex", @@ -497,9 +467,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" @@ -518,9 +488,9 @@ dependencies = [ [[package]] name = "chrono-tz" -version = "0.9.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" +checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" dependencies = [ "chrono", "chrono-tz-build", @@ -530,21 +500,21 @@ dependencies = [ [[package]] name = "chrono-tz-build" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" +checksum = "c7d8d1efd5109b9c1cd3b7966bd071cdfb53bb6eb0b22a473a68c2f70a11a1eb" dependencies = [ "parse-zoneinfo", - "phf", "phf_codegen", + "phf_shared", "uncased", ] [[package]] name = "clap" -version = "4.5.48" +version = "4.5.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +checksum = "c5caf74d17c3aec5495110c34cc3f78644bfa89af6c8993ed4de2790e49b6499" dependencies = [ "clap_builder", "clap_derive", @@ -552,9 +522,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.48" +version = "4.5.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +checksum = "370daa45065b80218950227371916a1633217ae42b2715b2287b606dcd618e24" dependencies = [ "anstream", "anstyle", @@ -565,21 +535,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.47" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] name = "clap_lex" -version = "0.7.5" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "colorchoice" @@ -765,7 +735,7 @@ checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -786,6 +756,19 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -799,7 +782,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -857,9 +840,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "find-msvc-tools" -version = "0.1.3" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "fixedbitset" @@ -873,11 +856,17 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -890,9 +879,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -900,27 +889,26 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", "futures-util", - "num_cpus", ] [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" @@ -952,32 +940,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -987,31 +975,43 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", ] [[package]] @@ -1031,23 +1031,17 @@ dependencies = [ "typed-builder", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "globset" -version = "0.4.16" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" dependencies = [ "aho-corasick", "bstr", "log", "regex-automata", - "regex-syntax 0.8.6", + "regex-syntax 0.8.9", ] [[package]] @@ -1075,9 +1069,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", @@ -1085,7 +1079,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.11.4", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -1106,9 +1100,18 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -1154,12 +1157,11 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -1206,9 +1208,9 @@ checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ "atomic-waker", "bytes", @@ -1242,20 +1244,19 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", "hyper", "libc", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.6.2", "tokio", "tower-service", "tracing", @@ -1263,9 +1264,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1285,11 +1286,17 @@ dependencies = [ "cc", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ignore" -version = "0.4.23" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" dependencies = [ "crossbeam-deque", "globset", @@ -1313,12 +1320,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -1357,21 +1366,21 @@ dependencies = [ ] [[package]] -name = "io-uring" -version = "0.7.10" +name = "is-terminal" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ - "bitflags 2.9.4", - "cfg-if", + "hermit-abi 0.5.2", "libc", + "windows-sys 0.61.2", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -1393,15 +1402,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", @@ -1422,11 +1431,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.176" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "linked-hash-map" @@ -1463,9 +1478,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" dependencies = [ "value-bag", ] @@ -1509,14 +1524,14 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mime" @@ -1530,24 +1545,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -1579,11 +1585,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.50.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1595,25 +1601,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi 0.5.2", - "libc", -] - -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -1622,15 +1609,15 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "openssl-probe" -version = "0.1.6" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "parking" @@ -1663,12 +1650,9 @@ dependencies = [ [[package]] name = "parse-zoneinfo" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" -dependencies = [ - "regex", -] +checksum = "e3c406c9e2aa74554e662d2c2ee11cd3e73756988800be7e6f5eddb16fed4699" [[package]] name = "paste" @@ -1716,23 +1700,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset", - "indexmap 2.11.4", + "indexmap 2.13.0", ] [[package]] name = "phf" -version = "0.11.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" dependencies = [ + "phf_macros", "phf_shared", ] [[package]] name = "phf_codegen" -version = "0.11.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +checksum = "efbdcb6f01d193b17f0b9c3360fa7e0e620991b193ff08702f78b3ce365d7e61" dependencies = [ "phf_generator", "phf_shared", @@ -1740,19 +1725,33 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +checksum = "2cbb1126afed61dd6368748dae63b1ee7dc480191c6262a3b4ff1e29d86a6c5b" dependencies = [ + "fastrand 2.3.0", "phf_shared", - "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d713258393a82f091ead52047ca779d37e5766226d009de21696c4e667044368" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.116", + "uncased", ] [[package]] name = "phf_shared" -version = "0.11.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" dependencies = [ "siphasher", "uncased", @@ -1775,7 +1774,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -1827,8 +1826,8 @@ dependencies = [ "concurrent-queue", "hermit-abi 0.5.2", "pin-project-lite", - "rustix 1.1.2", - "windows-sys 0.61.1", + "rustix 1.1.3", + "windows-sys 0.61.2", ] [[package]] @@ -1847,7 +1846,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -1876,9 +1875,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -1909,7 +1908,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.106", + "syn 2.0.116", "tempfile", ] @@ -1923,7 +1922,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -1937,9 +1936,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -1968,7 +1967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -1988,7 +1987,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -1997,16 +1996,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -2015,30 +2014,30 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.11.0", ] [[package]] name = "regex" -version = "1.11.3" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.8.6", + "regex-syntax 0.8.9", ] [[package]] name = "regex-automata" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.6", + "regex-syntax 0.8.9", ] [[package]] @@ -2049,9 +2048,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "ring" @@ -2061,18 +2060,12 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustix" version = "0.37.28" @@ -2093,7 +2086,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2102,22 +2095,22 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.32" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ "log", "once_cell", @@ -2130,9 +2123,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -2151,18 +2144,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.7" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "ring", "rustls-pki-types", @@ -2175,12 +2168,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - [[package]] name = "same-file" version = "1.0.6" @@ -2196,7 +2183,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -2231,11 +2218,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.5.1" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.11.0", "core-foundation", "core-foundation-sys", "libc", @@ -2244,14 +2231,20 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "321c8673b092a9a42605034a9879d73cb79101ed5fd117bc9a597b89b4e9e61a" dependencies = [ "core-foundation-sys", "libc", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -2279,21 +2272,21 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.13.0", "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -2339,24 +2332,25 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -2420,12 +2414,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2471,9 +2465,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", @@ -2521,15 +2515,24 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.23.0" +version = "3.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ "fastrand 2.3.0", - "getrandom 0.3.3", + "getrandom 0.4.1", "once_cell", - "rustix 1.1.2", - "windows-sys 0.61.1", + "rustix 1.1.3", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", ] [[package]] @@ -2538,7 +2541,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ - "rustix 1.1.2", + "rustix 1.1.3", "windows-sys 0.60.2", ] @@ -2570,7 +2573,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -2584,33 +2587,30 @@ dependencies = [ [[package]] name = "tokio" -version = "1.47.1" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", + "socket2 0.6.2", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -2625,9 +2625,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -2636,9 +2636,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -2691,7 +2691,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -2727,9 +2727,9 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -2753,9 +2753,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -2765,20 +2765,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -2797,9 +2797,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ "matchers", "nu-ansi-term", @@ -2842,6 +2842,7 @@ dependencies = [ "futures", "http", "itertools 0.10.5", + "log", "maybe-async", "prost", "rand 0.8.5", @@ -2864,7 +2865,7 @@ dependencies = [ [[package]] name = "typedb-protocol" version = "0.0.0" -source = "git+https://github.com/typedb/typedb-protocol?tag=3.7.0#3b75931f30f2b5cecf192515bb95071cd98a6e10" +source = "git+https://github.com/typedb/typedb-protocol?tag=3.7.0-alpha-0#40454a8c58e119a066fa81dd502ca0004042b3d0" dependencies = [ "prost", "tonic", @@ -2876,9 +2877,10 @@ name = "typedb_driver_clib" version = "0.0.0" dependencies = [ "chrono", + "env_logger", "itertools 0.10.5", + "log", "tracing", - "tracing-subscriber", "typedb-driver", ] @@ -2893,9 +2895,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-linebreak" @@ -2915,6 +2917,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "untrusted" version = "0.9.0" @@ -2929,14 +2937,14 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.18.1" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.4.1", "js-sys", "rand 0.9.2", - "serde", + "serde_core", "wasm-bindgen", ] @@ -2948,9 +2956,9 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "value-bag" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" +checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" [[package]] name = "version_check" @@ -2990,28 +2998,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "wasip2", + "wit-bindgen", ] [[package]] -name = "wasip2" -version = "1.0.1+wasi-0.2.4" +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", @@ -3020,27 +3028,14 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -3049,9 +3044,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3059,31 +3054,65 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.116", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver", +] + [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ "js-sys", "wasm-bindgen", @@ -3111,7 +3140,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -3122,9 +3151,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.62.1" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", @@ -3135,24 +3164,24 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.1" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] name = "windows-interface" -version = "0.59.2" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -3169,18 +3198,18 @@ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link 0.2.1", ] [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link 0.2.1", ] @@ -3218,14 +3247,14 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.4", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link 0.2.1", ] @@ -3263,9 +3292,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.4" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link 0.2.1", "windows_aarch64_gnullvm 0.53.1", @@ -3418,28 +3447,110 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.116", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.116", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.116", ] [[package]] @@ -3447,3 +3558,9 @@ name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/RELEASE_NOTES_LATEST.md b/RELEASE_NOTES_LATEST.md index 0dae942b0c..e0714e3a82 100644 --- a/RELEASE_NOTES_LATEST.md +++ b/RELEASE_NOTES_LATEST.md @@ -1,3 +1,6 @@ +**This is an alpha release for CLUSTERED TypeDB 3.x. Do not use this as a stable version of TypeDB.** +**Instead, reference a non-alpha release of the same major and minor versions.** + Documentation: https://typedb.com/docs/core-concepts/drivers/overview ## Distribution @@ -9,15 +12,18 @@ Documentation: https://typedb.com/docs/drivers/rust/overview ```sh -cargo add typedb-driver@3.8.0 +cargo add typedb-driver@3.7.0-alpha-3 ``` ### Java driver -Available through [https://repo.typedb.com](https://cloudsmith.io/~typedb/repos/public-release/packages/detail/maven/typedb-driver/3.8.0/a=noarch;xg=com.typedb/) +Available through [https://repo.typedb.com](https://cloudsmith.io/~typedb/repos/public-release/packages/detail/maven/typedb-driver/3.7.0-alpha-3/a=noarch;xg=com.typedb/) Documentation: https://typedb.com/docs/drivers/java/overview +**ATTENTION:** since this is an alpha version of a clustered TypeDB, the API is unstable and can drastically change between versions. +Use this driver only for the same `XYZ-alpha-A` version of the server. + ```xml @@ -29,7 +35,7 @@ Documentation: https://typedb.com/docs/drivers/java/overview com.typedb typedb-driver - 3.8.0 + 3.7.0-alpha-3 ``` @@ -39,112 +45,71 @@ Documentation: https://typedb.com/docs/drivers/java/overview PyPI package: https://pypi.org/project/typedb-driver Documentation: https://typedb.com/docs/drivers/python/overview +**ATTENTION:** since this is an alpha version of a clustered TypeDB, the API is unstable and can drastically change between versions. +Use this driver only for the same `XYZ-alpha-A` version of the server. + Available through https://pypi.org -[//]: # (TODO: Python's RC/Alpha/Beta versions are formatted differently. Don't foget to update manually until we make an automation) ``` -pip install typedb-driver==3.8.0 +pip install typedb-driver==3.7.0a2 ``` -### HTTP Typescript driver +### C driver -[//]: # (TODO: Update docs link) +Compiled distributions comprising headers and shared libraries available at: https://cloudsmith.io/~typedb/repos/public-release/packages/?q=name:^typedb-driver-clib+version:3.7.0-alpha-3 -NPM package: https://www.npmjs.com/package/@typedb/driver-http -Documentation: https://typedb.com/docs/drivers/ -``` -npm install @typedb/driver-http@3.8.0 +## New Features + +### Refactor DriverOptions' TLS configuration + +Introduce `DriverTlsConfig` with three possible constructors to eliminate ambiguity of TLS settings: + +- disabled +- enabled using default native root CA +- enabled using custom root CA + +Now, `DriverOptions` contain a separate `tls_config` field instead of `is_tls_enabled` and `tls_root_ca`, and every +`DriverOptions` object requires an instance of `DriverTlsConfig` on construction to provide explicit TLS connection +preferences. + +#### Examples + +Rust: +```rust +// Default: TLS enabled with native system trust roots +let options = DriverOptions::new(DriverTlsConfig::enabled_with_native_root_ca()).use_replication(true); + +// Custom CA (PEM) for private PKI / self-signed deployments +let options_custom_ca = DriverOptions::new( + DriverTlsConfig::enabled_with_root_ca(Path::new("path/to/ca-certificate.pem")).unwrap(), +); + +// Disable TLS (NOT recommended) +let options_insecure = DriverOptions::new(DriverTlsConfig::disabled()); ``` -### C driver +Java: +```java +// Default: TLS enabled with native system trust roots +DriverOptions options = new DriverOptions(DriverTlsConfig.enabledWithNativeRootCA()).useReplication(true); -Compiled distributions comprising headers and shared libraries available at: https://cloudsmith.io/~typedb/repos/public-release/packages/?q=name:^typedb-driver-clib+version:3.8.0 +// Custom CA (PEM) for private PKI / self-signed deployments +DriverOptions optionsCustomCA = new DriverOptions(DriverTlsConfig.enabledWithRootCA("path/to/ca-certificate.pem")); +// Disable TLS (NOT recommended) +DriverOptions optionsInsecure = new DriverOptions(DriverTlsConfig.disabled()); +``` -## New Features +Python: +```py +# Default/recommended: TLS enabled with native system trust roots +options = DriverOptions(DriverTlsConfig.enabled_with_native_root_ca(), use_replication=True) +# Custom CA (PEM) for private PKI / self-signed deployments +options_custom_ca = DriverOptions(DriverTlsConfig.enabled_with_root_ca("path/to/ca-certificate.pem")) +options_custom_ca.use_replication = True # Post-construction setter -## Bugs Fixed -- **Fix memory leaks in C integration test example** - - We fix an issue in the c driver tests and examples which used the wrong transaction close method, causing memory leaks. - - - - -## Code Refactors - - -## Other Improvements -- **Update typedb artifact** - -- **Create Bazel CI config** - - We create a separate Bazel CI config, which disables the disk cache. Disk cache is most useful on machines where we do many different builds on different branches and the standard bazel cache might be clobbered unnecessarily. In CI, where we do mostly one build per machine and also have a remote cache, this is not useful and on top of that hits the disk size limits. - - -- **Add bazel disk cache to speed up local builds when switching branches** - -- **Improve readability of reference docs** - - Add `function` before the method name (or `method` in Java/Python/Rust), to help readability of the generated docs page. - - -- **Regenerate docs with new css classes** - -- **Add doc-api-reference-driver class to classes in driver API reference pages** - -- **Improve driver docs reference formatting** - - We improve the driver reference formatting by including a `class` or `enum` or `struct` description to help delineate these constructs from methods in very long documentation pages. - - -- **Update READMEs** - -- **Update C driver documentation to TypeDB 3.x API** - - Update C driver documentation to TypeDB 3.x API structure matching Rust/Java/Python - - Add C driver example with full integration test coverage - - Add example compile verification targets for Java, Rust, and C drivers - - Fix Java Value API Javadoc to correctly describe return types - - Add TransactionOptions and QueryOptions includes to Java/Python/Rust api-reference - - - -- **Fix formatting** - -- **Set up configurable FFI/Rust driver logging** - - Rather than having Python/Java/other wrappers invoke logging initialization explicitly, we now just do it on open of the Rust driver automatically. - - This should fix warnings in Python: - ``` - Failed to initialize logging: attempted to set a logger after the logging system was already initialized - ``` - - We also remove uses of the `log` create in the `//c` layer, and use `tracing` instead. - - We can now configure logging in the Rust-driver component with the following variables: `TYPEDB_DRIVER_LOG=info|debug|warn|trace` or using the usual `RUST_LOG` variable. By default, ffi-based drivers calling `init_logging` will use INFO logging. - - Rust applications should continue set up their own logging subscriber, as usual. - - -- **Add banner to readme, fix link** - -- **Add contributing guidelines to CONTRIBUTING.md** - -- **Handle output directories properly for python BDD and docs rules (#831)** - This enables the bazel `remote_download_toplevel` flag, which broke build due to badly declared outputs. - - -- **Update README.md by removing outdated links** - -- **Handle output directories properly for python BDD and docs rules** - This enables the bazel `remote_download_toplevel` flag, which broke build due to badly declared outputs. - - -- **Remove --remote_download_toplevel since not all bazel targets have predeclared outputs (docs)** - -- **Improve bazel cache performance in CI with --remote_download_toplevel** - - +# Disable TLS (NOT recommended) +options_insecure = DriverOptions(DriverTlsConfig.disabled()) +``` diff --git a/RELEASE_TEMPLATE.md b/RELEASE_TEMPLATE.md index ced2755838..7462d27c59 100644 --- a/RELEASE_TEMPLATE.md +++ b/RELEASE_TEMPLATE.md @@ -1,3 +1,6 @@ +**This is an alpha release for CLUSTERED TypeDB 3.x. Do not use this as a stable version of TypeDB.** +**Instead, reference a non-alpha release of the same major and minor versions.** + Documentation: https://typedb.com/docs/core-concepts/drivers/overview ## Distribution @@ -7,6 +10,8 @@ Documentation: https://typedb.com/docs/core-concepts/drivers/overview Available from https://crates.io/crates/typedb-driver Documentation: https://typedb.com/docs/drivers/rust/overview +**ATTENTION:** since this is an alpha version of a clustered TypeDB, the API is unstable and may change significantly between versions. +Use this driver only for the same `XYZ-alpha-A` version of the server. ```sh cargo add typedb-driver@{version} @@ -18,6 +23,9 @@ cargo add typedb-driver@{version} Available through [https://repo.typedb.com](https://cloudsmith.io/~typedb/repos/public-release/packages/detail/maven/typedb-driver/{version}/a=noarch;xg=com.typedb/) Documentation: https://typedb.com/docs/drivers/java/overview +**ATTENTION:** since this is an alpha version of a clustered TypeDB, the API is unstable and may change significantly between versions. +Use this driver only for the same `XYZ-alpha-A` version of the server. + ```xml @@ -41,6 +49,9 @@ Documentation: https://typedb.com/docs/drivers/python/overview Available through https://pypi.org +**ATTENTION:** since this is an alpha version of a clustered TypeDB, the API is unstable and may change significantly between versions. +Use this driver only for the same `XYZaA` version of the server. + [//]: # (TODO: Python's RC/Alpha/Beta versions are formatted differently. Don't foget to update manually until we make an automation) ``` pip install typedb-driver=={version} diff --git a/VERSION b/VERSION index 0be1fc7d24..c44e262d77 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.8.0 \ No newline at end of file +3.7.0-alpha-3 \ No newline at end of file diff --git a/WORKSPACE b/WORKSPACE index 59d76a18bb..229d66a1eb 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -119,8 +119,8 @@ rust_register_toolchains( "x86_64-pc-windows-msvc", "x86_64-unknown-linux-gnu", ], - rust_analyzer_version = "1.81.0", - versions = ["1.81.0"], + rust_analyzer_version = "1.84.0", + versions = ["1.84.0"], ) rust_analyzer_toolchain_tools_repository( @@ -211,9 +211,9 @@ typedb_behaviour() typedb_protocol() # Load artifacts -load("//dependencies/typedb:artifacts.bzl", "typedb_artifact") +load("//dependencies/typedb:artifacts.bzl", "typedb_artifact", "typedb_cluster_artifact") typedb_artifact() -#typedb_cloud_artifact() +typedb_cluster_artifact() #################### # Load npm modules # diff --git a/c/Cargo.toml b/c/Cargo.toml index ea998c4eb8..cf3facadbd 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -14,14 +14,19 @@ features = {} [dependencies] + [dependencies.env_logger] + features = ["auto-color", "color", "default", "humantime", "regex"] + version = "0.10.2" + default-features = false + [dependencies.tracing] features = ["attributes", "default", "log", "std", "tracing-attributes"] version = "0.1.41" default-features = false - [dependencies.tracing-subscriber] - features = ["alloc", "ansi", "default", "env-filter", "fmt", "matchers", "nu-ansi-term", "once_cell", "regex", "registry", "sharded-slab", "smallvec", "std", "thread_local", "tracing", "tracing-log"] - version = "0.3.19" + [dependencies.log] + features = ["kv", "kv_unstable", "std", "value-bag"] + version = "0.4.28" default-features = false [dependencies.typedb-driver] @@ -31,7 +36,7 @@ features = {} [dependencies.chrono] features = ["alloc", "android-tzdata", "clock", "default", "iana-time-zone", "js-sys", "now", "oldtime", "serde", "std", "wasm-bindgen", "wasmbind", "winapi", "windows-link"] - version = "0.4.41" + version = "0.4.40" default-features = false [dependencies.itertools] diff --git a/c/README.md b/c/README.md index 65d1a5b4fa..1299d9e2ff 100644 --- a/c/README.md +++ b/c/README.md @@ -280,7 +280,7 @@ cleanup: Functions parameters & return values are either primitives or pointers to opaque structs, e.g.: ```c -struct TypeDBDriver *driver_open(const char *address, +struct TypeDBDriver *driver_new(const char *address, const struct Credentials *credentials, const struct DriverOptions *driver_options); ``` @@ -288,9 +288,10 @@ struct TypeDBDriver *driver_open(const char *address, These pointers are then used for further operations: ```c char* dbName = "hello"; - DriverOptions* options = driver_options_new(false, NULL);;; + DriverTlsConfig* tls_config = driver_tls_config_new_disabled(); + DriverOptions* options = driver_options_new(tls_config); Credentials* creds = credentials_new(username, password); - TypeDBDriver* driver = driver_open(address, creds, options); + TypeDBDriver* driver = driver_new(address, creds, options); databases_create(driver, dbName); Database* database = databases_get(driver, dbName); char* gotName = database_name(database); diff --git a/c/src/analyze.rs b/c/src/analyze.rs index 6d302d7cb4..30c4af43e2 100644 --- a/c/src/analyze.rs +++ b/c/src/analyze.rs @@ -17,33 +17,33 @@ * under the License. */ -use std::{ - ffi::c_char, - ptr::{addr_of_mut, null_mut}, -}; +use std::{ffi::c_char, ptr::addr_of_mut}; use typedb_driver::{ analyze::{ conjunction::{ - Comparator, Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintSpan, ConstraintVertex, + Comparator, Conjunction, ConjunctionID, Constraint, ConstraintExactness, ConstraintVertex, ConstraintWithSpan, NamedRole, Variable, }, pipeline::{Pipeline, PipelineStage, ReduceAssignment, Reducer, SortOrder, SortVariable}, AnalyzedQuery, Fetch, Function, ReturnOperation, TypeAnnotations, VariableAnnotations, }, box_stream, - concept::{type_::Type, AttributeType, Concept, Kind, ValueType}, + concept::{type_::Type, Concept, Kind}, BoxPromise, Promise, }; use crate::{ - common::StringIterator, - concept::ConceptIterator, - error::try_release, - iterator::{iterator_next, CIterator}, - memory::{ - borrow, free, release, release_optional, release_optional_string, release_string, string_view, take_ownership, + common::{ + error::try_release, + iterator::{iterator_next, CIterator}, + memory::{ + borrow, free, release, release_optional, release_optional_string, release_string, string_view, + take_ownership, + }, + StringIterator, }, + concept::ConceptIterator, }; // Iterators, promises & enums @@ -406,7 +406,7 @@ pub extern "C" fn pipeline_stage_require_get_variables(stage: *const PipelineSta #[no_mangle] pub extern "C" fn pipeline_stage_offset_get_offset(stage: *const PipelineStage) -> i64 { let PipelineStage::Offset { offset, .. } = borrow(stage) else { unreachable!("Expected Offset stage") }; - (*offset as i64) + *offset as i64 } /// Unwraps the PipelineStage instance as a Limit stage, and returns the limit applied. @@ -414,7 +414,7 @@ pub extern "C" fn pipeline_stage_offset_get_offset(stage: *const PipelineStage) #[no_mangle] pub extern "C" fn pipeline_stage_limit_get_limit(stage: *const PipelineStage) -> i64 { let PipelineStage::Limit { limit, .. } = borrow(stage) else { unreachable!("Expected Limit stage") }; - (*limit as i64) + *limit as i64 } /// Unwraps the PipelineStage instance as a Sort stage, and returns the SortVariable. diff --git a/c/src/answer.rs b/c/src/answer.rs index 08a915c796..5dea589501 100644 --- a/c/src/answer.rs +++ b/c/src/answer.rs @@ -27,17 +27,15 @@ use typedb_driver::{ BoxPromise, Promise, Result, }; -use super::{ - concept::ConceptIterator, - iterator::CIterator, - memory::{borrow, free, release, release_string, string_view}, -}; use crate::{ analyze::ConjunctionIDIterator, - common::StringIterator, - concept::ConceptRowIterator, - error::{try_release, try_release_optional}, - memory::{release_optional, take_ownership}, + common::{ + error::{try_release, try_release_optional}, + iterator::CIterator, + memory::{borrow, free, release, release_optional, release_string, string_view, take_ownership}, + StringIterator, + }, + concept::{ConceptIterator, ConceptRowIterator}, }; /// Promise object representing the result of an asynchronous operation. @@ -64,7 +62,7 @@ pub extern "C" fn query_answer_promise_drop(promise: *mut QueryAnswerPromise) { drop(take_ownership(promise)) } -/// Retrieve the executed query's type of the QueryAnswer. +/// Retrieves the executed query's type of the QueryAnswer. #[no_mangle] pub extern "C" fn query_answer_get_query_type(query_answer: *const QueryAnswer) -> QueryType { borrow(query_answer).get_query_type() @@ -122,14 +120,14 @@ pub extern "C" fn concept_row_get_column_names(concept_row: *const ConceptRow) - release(StringIterator(CIterator(box_stream(borrow(concept_row).get_column_names().into_iter().cloned().map(Ok))))) } -/// Retrieve the executed query's structure from the ConceptRow's header, if set. +/// Retrieves the executed query's structure from the ConceptRow's header, if set. /// It must be requested via "include query structure" in QueryOptions #[no_mangle] pub extern "C" fn concept_row_get_query_structure(concept_row: *const ConceptRow) -> *mut Pipeline { release_optional(borrow(concept_row).get_query_structure().cloned()) } -/// Retrieve the executed query's type of the ConceptRow's header. +/// Retrieves the executed query's type of the ConceptRow's header. #[no_mangle] pub extern "C" fn concept_row_get_query_type(concept_row: *const ConceptRow) -> QueryType { borrow(concept_row).get_query_type() @@ -142,14 +140,12 @@ pub extern "C" fn concept_row_get_concepts(concept_row: *const ConceptRow) -> *m } /// Retrieves a concept for a given column name. -/// #[no_mangle] pub extern "C" fn concept_row_get(concept_row: *const ConceptRow, column_name: *const c_char) -> *mut Concept { try_release_optional(borrow(concept_row).get(string_view(column_name)).map(|concept| concept.cloned()).transpose()) } /// Retrieves a concept for a given column index. -/// #[no_mangle] pub extern "C" fn concept_row_get_index(concept_row: *const ConceptRow, column_index: usize) -> *mut Concept { try_release_optional(borrow(concept_row).get_index(column_index).map(|concept| concept.cloned()).transpose()) diff --git a/c/src/error.rs b/c/src/common/error.rs similarity index 85% rename from c/src/error.rs rename to c/src/common/error.rs index 8dee207456..e27775de7c 100644 --- a/c/src/error.rs +++ b/c/src/common/error.rs @@ -47,35 +47,35 @@ fn ok_record_flatten(result: Option>) -> Option { result.and_then(ok_record) } -pub(super) fn try_release(result: Result) -> *mut T { +pub(crate) fn try_release(result: Result) -> *mut T { release_optional(ok_record(result)) } -pub(super) fn try_release_optional(result: Option>) -> *mut T { +pub(crate) fn try_release_optional(result: Option>) -> *mut T { release_optional(ok_record_flatten(result)) } -pub(super) fn try_release_string(result: Result) -> *mut c_char { +pub(crate) fn try_release_string(result: Result) -> *mut c_char { ok_record(result).map(release_string).unwrap_or_else(null_mut) } -pub(super) fn try_release_optional_string(result: Option>) -> *mut c_char { +pub(crate) fn try_release_optional_string(result: Option>) -> *mut c_char { ok_record_flatten(result).map(release_string).unwrap_or_else(null_mut) } -pub(super) fn try_release_arc(result: Result>) -> *const T { +pub(crate) fn try_release_arc(result: Result>) -> *const T { try_release_optional_arc(ok_record(result)) } -pub(super) fn try_release_optional_arc(result: Option>) -> *const T { +pub(crate) fn try_release_optional_arc(result: Option>) -> *const T { result.map(release_arc).unwrap_or_else(null) } -pub(super) fn unwrap_or_default(result: Result) -> T { +pub(crate) fn unwrap_or_default(result: Result) -> T { ok_record(result).unwrap_or_default() } -pub(super) fn unwrap_void(result: Result) { +pub(crate) fn unwrap_void(result: Result) { ok_record(result); } diff --git a/c/src/iterator.rs b/c/src/common/iterator.rs similarity index 77% rename from c/src/iterator.rs rename to c/src/common/iterator.rs index 2a3874b56a..5143cf8001 100644 --- a/c/src/iterator.rs +++ b/c/src/common/iterator.rs @@ -22,21 +22,20 @@ use std::sync::Arc; use typedb_driver::{BoxStream, Result}; use super::{ - error::try_release_optional, + error::{try_release_optional, try_release_optional_arc}, memory::{borrow_mut, release_optional}, }; -use crate::error::try_release_optional_arc; -pub struct CIterator(pub(super) BoxStream<'static, T>); +pub struct CIterator(pub(crate) BoxStream<'static, T>); -pub(super) fn iterator_next(it: *mut CIterator) -> *mut T { +pub(crate) fn iterator_next(it: *mut CIterator) -> *mut T { release_optional(borrow_mut(it).0.next()) } -pub(super) fn iterator_try_next(it: *mut CIterator>) -> *mut T { +pub(crate) fn iterator_try_next(it: *mut CIterator>) -> *mut T { try_release_optional(borrow_mut(it).0.next()) } -pub(super) fn iterator_arc_next(it: *mut CIterator>) -> *const T { +pub(crate) fn iterator_arc_next(it: *mut CIterator>) -> *const T { try_release_optional_arc(borrow_mut(it).0.next()) } diff --git a/c/src/memory.rs b/c/src/common/memory.rs similarity index 79% rename from c/src/memory.rs rename to c/src/common/memory.rs index 4fe15fefc3..a9917d679c 100644 --- a/c/src/memory.rs +++ b/c/src/common/memory.rs @@ -31,74 +31,74 @@ thread_local! { static LAST_ERROR: RefCell> = RefCell::new(None); } -pub(super) fn release(t: T) -> *mut T { +pub(crate) fn release(t: T) -> *mut T { let raw = Box::into_raw(Box::new(t)); trace!("Releasing ownership of <{}> @ {:?}", std::any::type_name::(), raw); raw } -pub(super) fn release_optional(t: Option) -> *mut T { +pub(crate) fn release_optional(t: Option) -> *mut T { t.map(release).unwrap_or_else(null_mut) } -pub(super) fn release_string(str: String) -> *mut c_char { +pub(crate) fn release_string(str: String) -> *mut c_char { let raw = CString::new(str).unwrap().into_raw(); trace!("Releasing ownership of @ {:?}", raw); raw } -pub(super) fn release_optional_string(str: Option) -> *mut c_char { +pub(crate) fn release_optional_string(str: Option) -> *mut c_char { str.map(release_string).unwrap_or_else(null_mut) } -pub(super) fn release_arc(t: Arc) -> *const T { +pub(crate) fn release_arc(t: Arc) -> *const T { let raw = Arc::into_raw(t); trace!("Releasing ownership of arc <{}> @ {:?}", std::any::type_name::(), raw); raw } -pub(super) fn take_arc(raw: *const T) -> Arc { +pub(crate) fn take_arc(raw: *const T) -> Arc { trace!("Taking ownership of arced <{}> @ {:?}", std::any::type_name::(), raw); unsafe { Arc::from_raw(raw) } } -pub(super) fn decrement_arc(raw: *const T) { +pub(crate) fn decrement_arc(raw: *const T) { trace!("Decrementing arced <{}> @ {:?}", std::any::type_name::(), raw); assert!(!raw.is_null()); drop(take_arc(raw)) } -pub(super) fn borrow(raw: *const T) -> &'static T { +pub(crate) fn borrow(raw: *const T) -> &'static T { trace!("Borrowing <{}> @ {:?}", std::any::type_name::(), raw); assert!(!raw.is_null()); unsafe { &*raw } } -pub(super) fn borrow_mut(raw: *mut T) -> &'static mut T { +pub(crate) fn borrow_mut(raw: *mut T) -> &'static mut T { trace!("Borrowing (mut) <{}> @ {:?}", std::any::type_name::(), raw); assert!(!raw.is_null()); unsafe { &mut *raw } } -pub(super) fn borrow_optional(raw: *const T) -> Option<&'static T> { +pub(crate) fn borrow_optional(raw: *const T) -> Option<&'static T> { trace!("Borrowing optional (null ok) <{}> @ {:?}", std::any::type_name::(), raw); unsafe { raw.as_ref() } } -pub(super) fn take_ownership(raw: *mut T) -> T { +pub(crate) fn take_ownership(raw: *mut T) -> T { trace!("Taking ownership of <{}> @ {:?}", std::any::type_name::(), raw); assert!(!raw.is_null()); unsafe { *Box::from_raw(raw) } } -pub(super) fn free(raw: *mut T) { +pub(crate) fn free(raw: *mut T) { trace!("Freeing <{}> @ {:?}", std::any::type_name::(), raw); if !raw.is_null() { unsafe { drop(Box::from_raw(raw)) } } } -pub(super) fn string_view(str: *const c_char) -> &'static str { +pub(crate) fn string_view(str: *const c_char) -> &'static str { assert!(!str.is_null()); unsafe { CStr::from_ptr(str).to_str().unwrap() } } @@ -113,12 +113,12 @@ pub extern "C" fn string_free(str: *mut c_char) { } } -pub(super) fn array_view(ts: *const *const T) -> impl Iterator { +pub(crate) fn array_view(ts: *const *const T) -> impl Iterator { assert!(!ts.is_null()); unsafe { (0..).map_while(move |i| (*ts.add(i)).as_ref()) } } -pub(super) fn string_array_view(strs: *const *const c_char) -> impl Iterator { +pub(crate) fn string_array_view(strs: *const *const c_char) -> impl Iterator { assert!(!strs.is_null()); unsafe { (0..).map_while(move |i| (*strs.add(i)).as_ref()).map(|p| string_view(p)) } } diff --git a/c/src/common.rs b/c/src/common/mod.rs similarity index 75% rename from c/src/common.rs rename to c/src/common/mod.rs index dea0ff67e4..ed9acb0c5b 100644 --- a/c/src/common.rs +++ b/c/src/common/mod.rs @@ -17,15 +17,19 @@ * under the License. */ -use std::{ffi::c_char, ptr::null_mut}; +use std::{collections::HashMap, ffi::c_char, hash::Hash, ptr::null_mut}; +use itertools::Itertools; use typedb_driver::Result; -use super::{ - iterator::CIterator, - memory::{borrow_mut, free}, -}; -use crate::error::try_release_string; +pub(crate) mod error; +pub(crate) mod iterator; +pub(crate) mod memory; +pub(crate) mod promise; + +use error::try_release_string; +use iterator::CIterator; +use memory::{borrow_mut, free}; /// Iterator over the strings in the result of a request or a TypeQL Fetch query. pub struct StringIterator(pub CIterator>); @@ -42,3 +46,10 @@ pub extern "C" fn string_iterator_next(it: *mut StringIterator) -> *mut c_char { pub extern "C" fn string_iterator_drop(it: *mut StringIterator) { free(it); } + +pub(crate) fn iterators_to_map( + keys: impl Iterator, + values: impl Iterator, +) -> HashMap { + keys.zip_eq(values).collect() +} diff --git a/c/src/promise.rs b/c/src/common/promise.rs similarity index 99% rename from c/src/promise.rs rename to c/src/common/promise.rs index 7ea30681b5..0f8c157d24 100644 --- a/c/src/promise.rs +++ b/c/src/common/promise.rs @@ -21,7 +21,7 @@ use std::ffi::c_char; use typedb_driver::{BoxPromise, Promise, Result}; -use crate::{ +use super::{ error::{try_release_optional_string, unwrap_or_default, unwrap_void}, memory::take_ownership, }; diff --git a/c/src/concept/concept.rs b/c/src/concept/concept.rs index a730c5f849..c4e88f084e 100644 --- a/c/src/concept/concept.rs +++ b/c/src/concept/concept.rs @@ -28,7 +28,7 @@ use typedb_driver::{ }, }; -use crate::{ +use crate::common::{ iterator::CIterator, memory::{ borrow, borrow_mut, free, release, release_optional, release_optional_string, release_string, string_free, @@ -48,17 +48,9 @@ impl DatetimeInNanos { pub fn new(datetime: &DateTime) -> Self { Self { seconds: datetime.timestamp(), subsec_nanos: datetime.timestamp_subsec_nanos() } } - - pub fn get_seconds(self) -> i64 { - self.seconds - } - - pub fn get_subsec_nanos(self) -> u32 { - self.subsec_nanos - } } -/// A DatetimeAndTimeZone used to represent time zoned datetime in FFI. +/// DatetimeAndTimeZone is used to represent time zoned datetime in FFI. /// Time zone can be represented either as an IANA Tz or as a FixedOffset. /// Either the zone_name (is_fixed_offset == false) or offset (is_fixed_offset == true) is set. #[repr(C)] @@ -84,22 +76,6 @@ impl DatetimeAndTimeZone { is_fixed_offset, } } - - pub fn get_datetime_in_nanos(self) -> DatetimeInNanos { - self.datetime_in_nanos - } - - pub fn get_zone_name(self) -> *mut c_char { - self.zone_name - } - - pub fn get_local_minus_utc_offset(self) -> i32 { - self.local_minus_utc_offset - } - - pub fn get_is_fixed_offset(self) -> bool { - self.is_fixed_offset - } } impl Drop for DatetimeAndTimeZone { @@ -345,9 +321,9 @@ pub extern "C" fn concept_get_datetime(concept: *const Concept) -> DatetimeInNan /// Returns the value of this datetime-tz value concept as seconds and nanoseconds parts since the start of the UNIX epoch and timezone information. /// If the value has another type, the error is set. #[no_mangle] -pub extern "C" fn concept_get_datetime_tz(concept: *const Concept) -> DatetimeAndTimeZone { +pub extern "C" fn concept_get_datetime_tz(concept: *const Concept) -> *mut DatetimeAndTimeZone { match borrow(concept).try_get_datetime_tz() { - Some(value) => DatetimeAndTimeZone::new(&value), + Some(value) => release(DatetimeAndTimeZone::new(&value)), None => unreachable!("Attempting to unwrap a non-datetime-tz {:?} as datetime-tz", borrow(concept)), } } diff --git a/c/src/concept/instance.rs b/c/src/concept/instance.rs index e0b753fb15..7374d4f4aa 100644 --- a/c/src/concept/instance.rs +++ b/c/src/concept/instance.rs @@ -22,7 +22,7 @@ use std::ptr::null_mut; use typedb_driver::concept::Concept; use super::concept::{borrow_as_attribute, borrow_as_entity, borrow_as_relation}; -use crate::memory::release; +use crate::common::memory::release; /// Retrieves the type which this ``Entity`` belongs to. #[no_mangle] diff --git a/c/src/concept/mod.rs b/c/src/concept/mod.rs index 30632f60a1..12dcd1a9f8 100644 --- a/c/src/concept/mod.rs +++ b/c/src/concept/mod.rs @@ -21,8 +21,11 @@ use std::ptr::addr_of_mut; use typedb_driver::{answer::ConceptRow, concept::Concept, BoxPromise, Promise, Result}; -use super::{iterator::iterator_try_next, memory::free}; -use crate::{error::try_release_optional, iterator::CIterator, memory::take_ownership}; +use crate::common::{ + error::try_release_optional, + iterator::{iterator_try_next, CIterator}, + memory::{free, take_ownership}, +}; mod concept; mod instance; diff --git a/c/src/connection.rs b/c/src/connection.rs deleted file mode 100644 index fe569e73bb..0000000000 --- a/c/src/connection.rs +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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. - */ - -use std::{ffi::c_char, path::Path}; - -use typedb_driver::{Credentials, DriverOptions, TypeDBDriver}; - -use super::{ - error::{try_release, unwrap_void}, - memory::{borrow, free, string_view}, -}; -use crate::memory::release; - -const DRIVER_LANG: &'static str = "c"; - -/// Open a TypeDB C Driver to a TypeDB server available at the provided address. -/// -/// @param address The address (host:port) on which the TypeDB Server is running -/// @param credentials The Credentials to connect with -/// @param driver_options The DriverOptions to connect with -#[no_mangle] -pub extern "C" fn driver_open( - address: *const c_char, - credentials: *const Credentials, - driver_options: *const DriverOptions, -) -> *mut TypeDBDriver { - try_release(TypeDBDriver::new_with_description( - string_view(address), - borrow(credentials).clone(), - borrow(driver_options).clone(), - DRIVER_LANG, - )) -} - -/// Open a TypeDB Driver to a TypeDB server available at the provided address. -/// This method allows driver language specification for drivers built on top of the native C layer. -/// -/// @param address The address (host:port) on which the TypeDB Server is running -/// @param credentials The Credentials to connect with -/// @param driver_options The DriverOptions to connect with -/// @param driver_lang The language of the driver connecting to the server -#[no_mangle] -pub extern "C" fn driver_open_with_description( - address: *const c_char, - credentials: *const Credentials, - driver_options: *const DriverOptions, - driver_lang: *const c_char, -) -> *mut TypeDBDriver { - try_release(TypeDBDriver::new_with_description( - string_view(address), - borrow(credentials).clone(), - borrow(driver_options).clone(), - string_view(driver_lang), - )) -} - -/// Closes the driver. Before instantiating a new driver, the driver that’s currently open should first be closed. -/// Closing a driver frees the underlying Rust object. -#[no_mangle] -pub extern "C" fn driver_close(driver: *mut TypeDBDriver) { - free(driver); -} - -/// Checks whether this connection is presently open. -#[no_mangle] -pub extern "C" fn driver_is_open(driver: *const TypeDBDriver) -> bool { - borrow(driver).is_open() -} - -/// Forcibly closes the driver. To be used in exceptional cases. -#[no_mangle] -pub extern "C" fn driver_force_close(driver: *mut TypeDBDriver) { - unwrap_void(borrow(driver).force_close()); -} - -// Creates a new Credentials for connecting to TypeDB Server. -// -// @param username The name of the user to connect as -// @param password The password for the user -#[no_mangle] -pub extern "C" fn credentials_new(username: *const c_char, password: *const c_char) -> *mut Credentials { - release(Credentials::new(string_view(username), string_view(password))) -} - -// Frees the native rust Credentials object -#[no_mangle] -pub extern "C" fn credentials_drop(credentials: *mut Credentials) { - free(credentials); -} - -// Creates a new DriverOptions for connecting to TypeDB Server. -// -// @param tls_root_ca Path to the CA certificate to use for authenticating server certificates. -// @param with_tls Specify whether the connection to TypeDB Cloud must be done over TLS -#[no_mangle] -pub extern "C" fn driver_options_new(is_tls_enabled: bool, tls_root_ca: *const c_char) -> *mut DriverOptions { - let tls_root_ca_path = unsafe { tls_root_ca.as_ref().map(|str| Path::new(string_view(str))) }; - try_release(DriverOptions::new(is_tls_enabled, tls_root_ca_path)) -} - -// Frees the native rust DriverOptions object -#[no_mangle] -pub extern "C" fn driver_options_drop(driver_options: *mut DriverOptions) { - free(driver_options); -} diff --git a/c/src/credentials.rs b/c/src/credentials.rs new file mode 100644 index 0000000000..7d1a11ecee --- /dev/null +++ b/c/src/credentials.rs @@ -0,0 +1,39 @@ +/* + * 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. + */ + +use std::ffi::c_char; + +use typedb_driver::Credentials; + +use crate::common::memory::{free, release, string_view}; + +/// Creates a new Credentials for connecting to TypeDB Server. +/// +/// @param username The name of the user to connect as +/// @param password The password for the user +#[no_mangle] +pub extern "C" fn credentials_new(username: *const c_char, password: *const c_char) -> *mut Credentials { + release(Credentials::new(string_view(username), string_view(password))) +} + +/// Frees the native rust Credentials object +#[no_mangle] +pub extern "C" fn credentials_drop(credentials: *mut Credentials) { + free(credentials); +} diff --git a/c/src/database.rs b/c/src/database.rs deleted file mode 100644 index 8e669e778f..0000000000 --- a/c/src/database.rs +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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. - */ - -use std::{ffi::c_char, path::Path}; - -use typedb_driver::Database; - -use super::{ - error::{try_release_string, unwrap_void}, - memory::{borrow, release_string}, -}; -use crate::memory::{decrement_arc, string_view, take_arc}; - -/// Frees the native rust Database object -#[no_mangle] -pub extern "C" fn database_close(database: *const Database) { - decrement_arc(database) -} - -/// The database name as a string. -#[no_mangle] -pub extern "C" fn database_get_name(database: *const Database) -> *mut c_char { - release_string(borrow(database).name().to_owned()) -} - -/// Deletes this database. -#[no_mangle] -pub extern "C" fn database_delete(database: *const Database) { - unwrap_void(take_arc(database).delete()); -} - -/// A full schema text as a valid TypeQL define query string. -#[no_mangle] -pub extern "C" fn database_schema(database: *const Database) -> *mut c_char { - try_release_string(borrow(database).schema()) -} - -/// The types in the schema as a valid TypeQL define query string. -#[no_mangle] -pub extern "C" fn database_type_schema(database: *const Database) -> *mut c_char { - try_release_string(borrow(database).type_schema()) -} - -/// Export a database into a schema definition and a data files saved to the disk. -/// This is a blocking operation and may take a significant amount of time depending on the database size. -/// -/// @param database The Database object to export from. -/// @param schema_file The path to the schema definition file to be created. -/// @param data_file The path to the data file to be created. -#[no_mangle] -pub extern "C" fn database_export_to_file( - database: *const Database, - schema_file: *const c_char, - data_file: *const c_char, -) { - let schema_file_path = Path::new(string_view(schema_file)); - let data_file_path = Path::new(string_view(data_file)); - unwrap_void(borrow(database).export_to_file(schema_file_path, data_file_path)) -} - -// /// Iterator over the ReplicaInfo corresponding to each replica of a TypeDB cloud database. -// pub struct ReplicaInfoIterator(CIterator); -// -// /// Forwards the ReplicaInfoIterator and returns the next ReplicaInfo if it exists, -// /// or null if there are no more elements. -// #[no_mangle] -// pub extern "C" fn replica_info_iterator_next(it: *mut ReplicaInfoIterator) -> *mut ReplicaInfo { -// unsafe { iterator_next(addr_of_mut!((*it).0)) } -// } -// -// /// Frees the native rust ReplicaInfoIterator object -// #[no_mangle] -// pub extern "C" fn replica_info_iterator_drop(it: *mut ReplicaInfoIterator) { -// free(it); -// } -// -// /// Set of Replica instances for this database. -// /// Only works in TypeDB Cloud -// #[no_mangle] -// pub extern "C" fn database_get_replicas_info(database: *const Database) -> *mut ReplicaInfoIterator { -// release(ReplicaInfoIterator(CIterator(box_stream(borrow(database).replicas_info().into_iter())))) -// } -// -// /// Returns the primary replica for this database. -// /// _Only works in TypeDB Cloud_ -// #[no_mangle] -// pub extern "C" fn database_get_primary_replica_info(database: *const Database) -> *mut ReplicaInfo { -// release_optional(borrow(database).primary_replica_info()) -// } -// -// /// Returns the preferred replica for this database. -// /// Operations which can be run on any replica will prefer to use this replica. -// /// _Only works in TypeDB Cloud_ -// #[no_mangle] -// pub extern "C" fn database_get_preferred_replica_info(database: *const Database) -> *mut ReplicaInfo { -// release_optional(borrow(database).preferred_replica_info()) -// } -// -// /// Frees the native rust ReplicaInfo object -// #[no_mangle] -// pub extern "C" fn replica_info_drop(replica_info: *mut ReplicaInfo) { -// free(replica_info); -// } -// -// /// The server hosting this replica -// #[no_mangle] -// pub extern "C" fn replica_info_get_server(replica_info: *const ReplicaInfo) -> *mut c_char { -// release_string(borrow(replica_info).server.to_string()) -// } -// -// /// Checks whether this is the primary replica of the raft cluster. -// #[no_mangle] -// pub extern "C" fn replica_info_is_primary(replica_info: *const ReplicaInfo) -> bool { -// borrow(replica_info).is_primary -// } -// -// /// Checks whether this is the preferred replica of the raft cluster. -// /// If true, Operations which can be run on any replica will prefer to use this replica. -// #[no_mangle] -// pub extern "C" fn replica_info_is_preferred(replica_info: *const ReplicaInfo) -> bool { -// borrow(replica_info).is_preferred -// } -// -// /// The raft protocol ‘term’ of this replica. -// #[no_mangle] -// pub extern "C" fn replica_info_get_term(replica_info: *const ReplicaInfo) -> i64 { -// borrow(replica_info).term -// } diff --git a/c/src/database/database.rs b/c/src/database/database.rs new file mode 100644 index 0000000000..5ccde2b37b --- /dev/null +++ b/c/src/database/database.rs @@ -0,0 +1,116 @@ +/* + * 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. + */ + +use std::{ffi::c_char, path::Path}; + +use typedb_driver::Database; + +use crate::{ + common::{ + error::{try_release_string, unwrap_void}, + memory::{borrow, decrement_arc, release_string, string_view, take_arc}, + }, + server::consistency_level::{native_consistency_level, ConsistencyLevel}, +}; + +/// Frees the native rust Database object. +#[no_mangle] +pub extern "C" fn database_close(database: *const Database) { + decrement_arc(database) +} + +/// The Database name as a string. +#[no_mangle] +pub extern "C" fn database_get_name(database: *const Database) -> *mut c_char { + release_string(borrow(database).name().to_owned()) +} + +/// Deletes this database. +/// +/// @param database The Database to delete. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn database_delete(database: *const Database, consistency_level: *const ConsistencyLevel) { + let database = take_arc(database); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => database.delete_with_consistency(consistency_level), + None => database.delete(), + }; + unwrap_void(result); +} + +/// A full schema text as a valid TypeQL define query string. +/// +/// @param database The Database to get the schema from. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn database_schema( + database: *const Database, + consistency_level: *const ConsistencyLevel, +) -> *mut c_char { + let database = borrow(database); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => database.schema_with_consistency(consistency_level), + None => database.schema(), + }; + try_release_string(result) +} + +/// The types in the schema as a valid TypeQL define query string. +/// +/// @param database The Database to get the type schema from. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn database_type_schema( + database: *const Database, + consistency_level: *const ConsistencyLevel, +) -> *mut c_char { + let database = borrow(database); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => database.type_schema_with_consistency(consistency_level), + None => database.type_schema(), + }; + try_release_string(result) +} + +/// Export a database into a schema definition and a data files saved to the disk. +/// This is a blocking operation and may take a significant amount of time depending on the database size. +/// +/// @param database The Database object to export from. +/// @param schema_file The path to the schema definition file to be created. +/// @param data_file The path to the data file to be created. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn database_export_to_file( + database: *const Database, + schema_file: *const c_char, + data_file: *const c_char, + consistency_level: *const ConsistencyLevel, +) { + let database = borrow(database); + let schema_file_path = Path::new(string_view(schema_file)); + let data_file_path = Path::new(string_view(data_file)); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => { + database.export_to_file_with_consistency(schema_file_path, data_file_path, consistency_level) + } + None => database.export_to_file(schema_file_path, data_file_path), + }; + unwrap_void(result) +} diff --git a/c/src/database/database_manager.rs b/c/src/database/database_manager.rs new file mode 100644 index 0000000000..eed81a2dbd --- /dev/null +++ b/c/src/database/database_manager.rs @@ -0,0 +1,144 @@ +/* + * 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. + */ + +use std::{ffi::c_char, path::Path, ptr::addr_of_mut, sync::Arc}; + +use typedb_driver::{box_stream, Database, TypeDBDriver}; + +use crate::{ + common::{ + error::{try_release, try_release_arc, unwrap_or_default, unwrap_void}, + iterator::{iterator_arc_next, CIterator}, + memory::{borrow, free, string_view}, + }, + server::consistency_level::{native_consistency_level, ConsistencyLevel}, +}; + +/// An Iterator over databases present on the TypeDB server. +pub struct DatabaseIterator(CIterator>); + +/// Forwards the DatabaseIterator and returns the next Database if it exists, +/// or null if there are no more elements. +#[no_mangle] +pub extern "C" fn database_iterator_next(it: *mut DatabaseIterator) -> *const Database { + unsafe { iterator_arc_next(addr_of_mut!((*it).0)) } +} + +/// Frees the native rust DatabaseIterator object. +#[no_mangle] +pub extern "C" fn database_iterator_drop(it: *mut DatabaseIterator) { + free(it); +} + +/// Returns a DatabaseIterator over all databases present on the TypeDB server. +/// +/// @param driver The TypeDBDriver object. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn databases_all( + driver: *mut TypeDBDriver, + consistency_level: *const ConsistencyLevel, +) -> *mut DatabaseIterator { + let databases = borrow(driver).databases(); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => databases.all_with_consistency(consistency_level), + None => databases.all(), + }; + try_release(result.map(|dbs| DatabaseIterator(CIterator(box_stream(dbs.into_iter()))))) +} + +/// Checks if a database with the given name exists. +/// +/// @param driver The TypeDBDriver object. +/// @param name The name of the database. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn databases_contains( + driver: *mut TypeDBDriver, + name: *const c_char, + consistency_level: *const ConsistencyLevel, +) -> bool { + let databases = borrow(driver).databases(); + let name = string_view(name); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => databases.contains_with_consistency(name, consistency_level), + None => databases.contains(name), + }; + unwrap_or_default(result) +} + +/// Retrieves the database with the given name. +/// +/// @param driver The TypeDBDriver object. +/// @param name The name of the database. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn databases_get( + driver: *mut TypeDBDriver, + name: *const c_char, + consistency_level: *const ConsistencyLevel, +) -> *const Database { + let databases = borrow(driver).databases(); + let name = string_view(name); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => databases.get_with_consistency(name, consistency_level), + None => databases.get(name), + }; + try_release_arc(result) +} + +/// Creates a database with the given name. +/// +/// @param driver The TypeDBDriver object. +/// @param name The name of the database to be created. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn databases_create( + driver: *mut TypeDBDriver, + name: *const c_char, + consistency_level: *const ConsistencyLevel, +) { + let databases = borrow(driver).databases(); + let name = string_view(name); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => databases.create_with_consistency(name, consistency_level), + None => databases.create(name), + }; + unwrap_void(result) +} + +/// Creates a database with the given name based on previously exported another database's data +/// loaded from a file. +/// This is a blocking operation and may take a significant amount of time depending on the database +/// size. +/// +/// @param driver The TypeDBDriver object. +/// @param name The name of the database to be created. +/// @param schema The schema definition query string for the database. +/// @param data_file The exported database file path to import the data from. +#[no_mangle] +pub extern "C" fn databases_import_from_file( + driver: *mut TypeDBDriver, + name: *const c_char, + schema: *const c_char, + data_file: *const c_char, +) { + let data_file_path = Path::new(string_view(data_file)); + unwrap_void(borrow(driver).databases().import_from_file(string_view(name), string_view(schema), data_file_path)) +} diff --git a/c/src/database/mod.rs b/c/src/database/mod.rs new file mode 100644 index 0000000000..c868b0e18e --- /dev/null +++ b/c/src/database/mod.rs @@ -0,0 +1,21 @@ +/* + * 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. + */ + +mod database; +mod database_manager; diff --git a/c/src/database_manager.rs b/c/src/database_manager.rs deleted file mode 100644 index 3345bb5971..0000000000 --- a/c/src/database_manager.rs +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. - */ - -use std::{ffi::c_char, path::Path, ptr::addr_of_mut, sync::Arc}; - -use typedb_driver::{box_stream, Database, TypeDBDriver}; - -use super::{ - error::{try_release, unwrap_or_default, unwrap_void}, - iterator::CIterator, - memory::{borrow_mut, free, string_view}, -}; -use crate::{error::try_release_arc, iterator::iterator_arc_next}; - -/// An Iterator over databases present on the TypeDB server. -pub struct DatabaseIterator(CIterator>); - -/// Forwards the DatabaseIterator and returns the next Database if it exists, -/// or null if there are no more elements. -#[no_mangle] -pub extern "C" fn database_iterator_next(it: *mut DatabaseIterator) -> *const Database { - unsafe { iterator_arc_next(addr_of_mut!((*it).0)) } -} - -/// Frees the native rust DatabaseIterator object. -#[no_mangle] -pub extern "C" fn database_iterator_drop(it: *mut DatabaseIterator) { - free(it); -} - -/// Returns a DatabaseIterator over all databases present on the TypeDB server. -#[no_mangle] -pub extern "C" fn databases_all(driver: *mut TypeDBDriver) -> *mut DatabaseIterator { - try_release( - borrow_mut(driver).databases().all().map(|dbs| DatabaseIterator(CIterator(box_stream(dbs.into_iter())))), - ) -} - -/// Create a database with the given name. -#[no_mangle] -pub extern "C" fn databases_create(driver: *mut TypeDBDriver, name: *const c_char) { - unwrap_void(borrow_mut(driver).databases().create(string_view(name))); -} - -/// Create a database with the given name based on previously exported another database's data -/// loaded from a file. -/// This is a blocking operation and may take a significant amount of time depending on the database -/// size. -/// -/// @param driver The TypeDBDriver object. -/// @param name The name of the database to be created. -/// @param schema The schema definition query string for the database. -/// @param data_file The exported database file path to import the data from. -#[no_mangle] -pub extern "C" fn databases_import_from_file( - driver: *mut TypeDBDriver, - name: *const c_char, - schema: *const c_char, - data_file: *const c_char, -) { - let data_file_path = Path::new(string_view(data_file)); - unwrap_void(borrow_mut(driver).databases().import_from_file(string_view(name), string_view(schema), data_file_path)) -} - -/// Checks if a database with the given name exists. -#[no_mangle] -pub extern "C" fn databases_contains(driver: *mut TypeDBDriver, name: *const c_char) -> bool { - unwrap_or_default(borrow_mut(driver).databases().contains(string_view(name))) -} - -/// Retrieve the database with the given name. -#[no_mangle] -pub extern "C" fn databases_get(driver: *mut TypeDBDriver, name: *const c_char) -> *const Database { - try_release_arc(borrow_mut(driver).databases().get(string_view(name))) -} diff --git a/c/src/driver.rs b/c/src/driver.rs new file mode 100644 index 0000000000..4e527184e1 --- /dev/null +++ b/c/src/driver.rs @@ -0,0 +1,292 @@ +/* + * 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. + */ + +use std::ffi::c_char; + +use typedb_driver::{box_stream, Addresses, Credentials, DriverOptions, ServerReplica, TypeDBDriver}; + +use crate::{ + common::{ + error::{try_release, try_release_optional, unwrap_or_default, unwrap_void}, + iterator::CIterator, + iterators_to_map, + memory::{borrow, free, release, string_array_view, string_view}, + }, + server::{ + consistency_level::{native_consistency_level, ConsistencyLevel}, + server_replica::ServerReplicaIterator, + server_version::ServerVersion, + }, +}; + +const DRIVER_LANG: &'static str = "c"; + +// TODO: These constructors get out of hand. Consider driver builders based on a config! + +/// Open a TypeDB C Driver to a TypeDB server available at the provided address. +/// +/// @param address The address on which the TypeDB Server is running +/// @param credentials The Credentials to connect with +/// @param driver_options The DriverOptions to connect with +#[no_mangle] +pub extern "C" fn driver_new( + address: *const c_char, + credentials: *const Credentials, + driver_options: *const DriverOptions, +) -> *mut TypeDBDriver { + try_release(TypeDBDriver::new_with_description( + unwrap_or_default(Addresses::try_from_address_str(string_view(address))), + borrow(credentials).clone(), + borrow(driver_options).clone(), + DRIVER_LANG, + )) +} + +/// Open a TypeDB Driver to a TypeDB server available at the provided address. +/// This method allows driver language specification for drivers built on top of the native C layer. +/// +/// @param address The address on which the TypeDB Server is running +/// @param credentials The Credentials to connect with +/// @param driver_options The DriverOptions to connect with +/// @param driver_lang The language of the driver connecting to the server +#[no_mangle] +pub extern "C" fn driver_new_with_description( + address: *const c_char, + credentials: *const Credentials, + driver_options: *const DriverOptions, + driver_lang: *const c_char, +) -> *mut TypeDBDriver { + try_release(TypeDBDriver::new_with_description( + unwrap_or_default(Addresses::try_from_address_str(string_view(address))), + borrow(credentials).clone(), + borrow(driver_options).clone(), + string_view(driver_lang), + )) +} + +/// Open a TypeDB C Driver to a TypeDB cluster available at the provided addresses. +/// +/// @param addresses A null-terminated array holding the server addresses on for connection +/// @param credentials The Credentials to connect with +/// @param driver_options The DriverOptions to connect with +#[no_mangle] +pub extern "C" fn driver_new_with_addresses( + addresses: *const *const c_char, + credentials: *const Credentials, + driver_options: *const DriverOptions, +) -> *mut TypeDBDriver { + try_release(TypeDBDriver::new_with_description( + unwrap_or_default(Addresses::try_from_addresses_str(string_array_view(addresses))), + borrow(credentials).clone(), + borrow(driver_options).clone(), + DRIVER_LANG, + )) +} + +/// Open a TypeDB Driver to a TypeDB cluster available at the provided addresses. +/// This method allows driver language specification for drivers built on top of the native C layer. +/// +/// @param addresses A null-terminated array holding the TypeDB cluster replica addresses on for connection +/// @param credentials The Credentials to connect with +/// @param driver_options The DriverOptions to connect with +/// @param driver_lang The language of the driver connecting to the server +#[no_mangle] +pub extern "C" fn driver_new_with_addresses_with_description( + addresses: *const *const c_char, + credentials: *const Credentials, + driver_options: *const DriverOptions, + driver_lang: *const c_char, +) -> *mut TypeDBDriver { + try_release(TypeDBDriver::new_with_description( + unwrap_or_default(Addresses::try_from_addresses_str(string_array_view(addresses))), + borrow(credentials).clone(), + borrow(driver_options).clone(), + string_view(driver_lang), + )) +} + +/// Open a TypeDB C Driver to a TypeDB cluster, using the provided address translation. +/// +/// @param public_addresses A null-terminated array holding the replica addresses on for connection. +/// @param private_addresses A null-terminated array holding the private replica addresses, configured on the server side. +/// This array must have the same length as public_addresses. +/// @param credentials The Credentials to connect with +/// @param driver_options The DriverOptions to connect with +#[no_mangle] +pub extern "C" fn driver_new_with_address_translation( + public_addresses: *const *const c_char, + private_addresses: *const *const c_char, + credentials: *const Credentials, + driver_options: *const DriverOptions, +) -> *mut TypeDBDriver { + let addresses = iterators_to_map(string_array_view(public_addresses), string_array_view(private_addresses)); + try_release(TypeDBDriver::new_with_description( + unwrap_or_default(Addresses::try_from_translation_str(addresses)), + borrow(credentials).clone(), + borrow(driver_options).clone(), + DRIVER_LANG, + )) +} + +/// Open a TypeDB Driver to a TypeDB cluster, using the provided address translation. +/// This method allows driver language specification for drivers built on top of the native C layer. +/// +/// @param public_addresses A null-terminated array holding the replica addresses on for connection. +/// @param private_addresses A null-terminated array holding the private replica addresses, configured on the server side. +/// This array must have the same length as public_addresses. +/// @param credentials The Credentials to connect with +/// @param driver_options The DriverOptions to connect with +/// @param driver_lang The language of the driver connecting to the server +#[no_mangle] +pub extern "C" fn driver_new_with_address_translation_with_description( + public_addresses: *const *const c_char, + private_addresses: *const *const c_char, + credentials: *const Credentials, + driver_options: *const DriverOptions, + driver_lang: *const c_char, +) -> *mut TypeDBDriver { + let addresses = iterators_to_map(string_array_view(public_addresses), string_array_view(private_addresses)); + try_release(TypeDBDriver::new_with_description( + unwrap_or_default(Addresses::try_from_translation_str(addresses)), + borrow(credentials).clone(), + borrow(driver_options).clone(), + string_view(driver_lang), + )) +} + +/// Closes the TypeDBDriver. Before instantiating a new driver, the driver that’s currently open should first be closed. +/// Closing a driver frees the underlying Rust object. +/// +/// @param driver The TypeDBDriver object. +#[no_mangle] +pub extern "C" fn driver_close(driver: *mut TypeDBDriver) { + free(driver); +} + +/// Forcibly closes the TypeDBDriver. To be used in exceptional cases. +/// +/// @param driver The TypeDBDriver object. +#[no_mangle] +pub extern "C" fn driver_force_close(driver: *mut TypeDBDriver) { + unwrap_void(borrow(driver).force_close()); +} + +/// Checks whether this connection is presently open. +/// +/// @param driver The TypeDBDriver object. +#[no_mangle] +pub extern "C" fn driver_is_open(driver: *const TypeDBDriver) -> bool { + borrow(driver).is_open() +} + +/// Retrieves the server version and distribution information. +/// +/// @param driver The TypeDBDriver object. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn driver_server_version( + driver: *const TypeDBDriver, + consistency_level: *const ConsistencyLevel, +) -> *mut ServerVersion { + let driver = borrow(driver); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => driver.server_version_with_consistency(consistency_level), + None => driver.server_version(), + }; + release(unwrap_or_default(result.map(|server_version| { + ServerVersion::new(server_version.distribution().to_string(), server_version.version().to_string()) + }))) +} + +/// Retrieves the server's replicas. +/// +/// @param driver The TypeDBDriver object. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn driver_replicas( + driver: *const TypeDBDriver, + consistency_level: *const ConsistencyLevel, +) -> *mut ServerReplicaIterator { + let driver = borrow(driver); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => driver.replicas_with_consistency(consistency_level), + None => driver.replicas(), + }; + release(ServerReplicaIterator(CIterator(box_stream(unwrap_or_default(result).into_iter())))) +} + +/// Retrieves the server's primary replica, if exists. +/// +/// @param driver The TypeDBDriver object. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn driver_primary_replica( + driver: *const TypeDBDriver, + consistency_level: *const ConsistencyLevel, +) -> *mut ServerReplica { + let driver = borrow(driver); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => driver.primary_replica_with_consistency(consistency_level), + None => driver.primary_replica(), + }; + // TODO: Return somehow else!! This will not work through SWIG + try_release_optional(result.map(|res| res.map(|rep| ServerReplica::Available(rep))).transpose()) +} + +/// Registers a new replica in the cluster the driver is currently connected to. The registered +/// replica will become available eventually, depending on the behavior of the whole cluster. +/// To register a replica, its clustering address should be passed, not the connection address. +/// +/// @param driver The TypeDBDriver object. +/// @param replica_id The numeric identifier of the new replica +/// @param address The address(es) of the TypeDB replica as a string +#[no_mangle] +pub extern "C" fn driver_register_replica(driver: *const TypeDBDriver, replica_id: i64, address: *const c_char) { + unwrap_void(borrow(driver).register_replica(replica_id as u64, string_view(address).to_string())) +} + +/// Deregisters a replica from the cluster the driver is currently connected to. This replica +/// will no longer play a raft role in this cluster. +/// +/// @param driver The TypeDBDriver object. +/// @param replica_id The numeric identifier of the deregistered replica +#[no_mangle] +pub extern "C" fn driver_deregister_replica(driver: *const TypeDBDriver, replica_id: i64) { + unwrap_void(borrow(driver).deregister_replica(replica_id as u64)) +} + +/// Updates address translation of the driver. This lets you actualize new translation +/// information without recreating the driver from scratch. Useful after registering new +/// replicas requiring address translation. +/// This operation will update existing connections using the provided addresses. +/// +/// @param driver The TypeDBDriver object. +/// @param public_addresses A null-terminated array holding the replica addresses on for connection. +/// @param private_addresses A null-terminated array holding the private replica addresses, configured on the server side. +/// This array must have the same length as public_addresses. +#[no_mangle] +pub extern "C" fn driver_update_address_translation( + driver: *const TypeDBDriver, + public_addresses: *const *const c_char, + private_addresses: *const *const c_char, +) { + let translation = iterators_to_map(string_array_view(public_addresses), string_array_view(private_addresses)); + let addresses = unwrap_or_default(Addresses::try_from_translation_str(translation)); + unwrap_void(borrow(driver).update_address_translation(addresses)) +} diff --git a/c/src/driver_options.rs b/c/src/driver_options.rs new file mode 100644 index 0000000000..0ffdb9fbcb --- /dev/null +++ b/c/src/driver_options.rs @@ -0,0 +1,144 @@ +/* + * 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. + */ + +use std::{ffi::c_char, path::Path, time::Duration}; + +use typedb_driver::{DriverOptions, DriverTlsConfig}; + +use crate::common::{ + error::unwrap_void, + memory::{borrow, borrow_mut, borrow_optional, free, release, release_string, string_view}, +}; + +/// Creates a new DriverOptions for connecting to TypeDB Server using custom TLS settings. +/// WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. +#[no_mangle] +pub extern "C" fn driver_options_new(tls_config: *const DriverTlsConfig) -> *mut DriverOptions { + release(DriverOptions::new(borrow(tls_config).clone())) +} + +/// Frees the native rust DriverOptions object. +#[no_mangle] +pub extern "C" fn driver_options_drop(driver_options: *mut DriverOptions) { + free(driver_options); +} + +/// Overrides the TLS configuration on DriverOptions. +/// WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. +#[no_mangle] +pub extern "C" fn driver_options_set_tls_config(options: *mut DriverOptions, tls_config: *const DriverTlsConfig) { + borrow_mut(options).tls_config = borrow(tls_config).clone(); +} + +/// Returns the TLS Config set for this DriverOptions object. +/// Specifies the TLS configuration of the connection to TypeDB. +#[no_mangle] +pub extern "C" fn driver_options_get_tls_config(options: *const DriverOptions) -> *mut DriverTlsConfig { + release(borrow(options).tls_config.clone()) +} + +/// Specifies whether the connection to TypeDB can use cluster replicas provided by the server +/// or it should be limited to a single configured address. +/// Defaults to true. +#[no_mangle] +pub extern "C" fn driver_options_set_use_replication(options: *mut DriverOptions, use_replication: bool) { + borrow_mut(options).use_replication = use_replication; +} + +/// Returns the value set for the replication usage flag in this DriverOptions object. +/// Specifies whether the connection to TypeDB can use cluster replicas provided by the server +/// or it should be limited to a single configured address. +#[no_mangle] +pub extern "C" fn driver_options_get_use_replication(options: *const DriverOptions) -> bool { + borrow(options).use_replication +} + +/// Limits the number of attempts to redirect a strongly consistent request to another +/// primary replica in case of a failure due to the change of replica roles. +/// Defaults to 1. +#[no_mangle] +pub extern "C" fn driver_options_set_primary_failover_retries( + options: *mut DriverOptions, + primary_failover_retries: i64, +) { + borrow_mut(options).primary_failover_retries = primary_failover_retries as usize; +} + +/// Returns the value set for the primary failover retries limit in this DriverOptions object. +/// Limits the number of attempts to redirect a strongly consistent request to another +/// primary replica in case of a failure due to the change of replica roles. +#[no_mangle] +pub extern "C" fn driver_options_get_primary_failover_retries(options: *const DriverOptions) -> i64 { + borrow(options).primary_failover_retries as i64 +} + +/// Limits the number of driver attempts to discover a single working replica to perform an +/// operation in case of a replica unavailability. Every replica is tested once, which means +/// that at most: +/// - {limit} operations are performed if the limit <= the number of replicas. +/// - {number of replicas} operations are performed if the limit > the number of replicas. +/// - {number of replicas} operations are performed if the limit is None. +/// Affects every eventually consistent operation, including redirect failover, when the new +/// primary replica is unknown. If not set, the maximum (practically unlimited) value is used. +#[no_mangle] +pub extern "C" fn driver_options_set_replica_discovery_attempts( + options: *mut DriverOptions, + replica_discovery_attempts: i64, +) { + borrow_mut(options).replica_discovery_attempts = Some(replica_discovery_attempts as usize); +} + +/// Returns the value set for the replica discovery attempts limit in this DriverOptions object. +/// Limits the number of driver attempts to discover a single working replica to perform an +/// operation in case of a replica unavailability. Every replica is tested once, which means +/// that at most: +/// - {limit} operations are performed if the limit <= the number of replicas. +/// - {number of replicas} operations are performed if the limit > the number of replicas. +/// - {number of replicas} operations are performed if the limit is None. +/// Affects every eventually consistent operation, including redirect failover, when the new +/// primary replica is unknown. +#[no_mangle] +pub extern "C" fn driver_options_get_replica_discovery_attempts(options: *const DriverOptions) -> i64 { + borrow(options).replica_discovery_attempts.unwrap() as i64 +} + +/// Checks whether the replica discovery attempts limit was explicitly set for this DriverOptions object. +#[no_mangle] +pub extern "C" fn driver_options_has_replica_discovery_attempts(options: *const DriverOptions) -> bool { + borrow(options).replica_discovery_attempts.is_some() +} + +/// Sets the maximum time (in milliseconds) to wait for a response to a unary RPC request. +/// This applies to operations like database creation, user management, and initial +/// transaction opening. It does NOT apply to operations within transactions (queries, commits). +/// Set to 0 to disable the timeout (not recommended for production use). +/// Defaults to 2 hours (7200000 milliseconds). +#[no_mangle] +pub extern "C" fn driver_options_set_request_timeout_millis(options: *mut DriverOptions, timeout_millis: i64) { + borrow_mut(options).request_timeout = Duration::from_millis(timeout_millis as u64); +} + +/// Returns the request timeout in milliseconds set for this DriverOptions object. +/// Specifies the maximum time to wait for a response to a unary RPC request. +/// This applies to operations like database creation, user management, and initial +/// transaction opening. It does NOT apply to operations within transactions (queries, commits). +#[no_mangle] +pub extern "C" fn driver_options_get_request_timeout_millis(options: *const DriverOptions) -> i64 { + borrow(options).request_timeout.as_millis() as i64 +} diff --git a/c/src/driver_tls_config.rs b/c/src/driver_tls_config.rs new file mode 100644 index 0000000000..0ea3d530d8 --- /dev/null +++ b/c/src/driver_tls_config.rs @@ -0,0 +1,71 @@ +/* + * 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. + */ + +use std::{ffi::c_char, path::Path}; + +use typedb_driver::DriverTlsConfig; + +use crate::common::{ + error::try_release, + memory::{borrow, borrow_mut, free, release, release_string, string_view}, +}; + +/// Creates a new DriverTlsConfig with TLS disabled. +#[no_mangle] +pub extern "C" fn driver_tls_config_new_disabled() -> *mut DriverTlsConfig { + release(DriverTlsConfig::disabled()) +} + +/// Creates a new DriverTlsConfig with TLS enabled using system native trust roots. +#[no_mangle] +pub extern "C" fn driver_tls_config_new_enabled_with_native_root_ca() -> *mut DriverTlsConfig { + release(DriverTlsConfig::enabled_with_native_root_ca()) +} + +/// Creates a new DriverTlsConfig with TLS enabled using a custom root CA certificate (PEM). +#[no_mangle] +pub extern "C" fn driver_tls_config_new_enabled_with_root_ca_path(tls_root_ca: *const c_char) -> *mut DriverTlsConfig { + let tls_root_ca_path = Path::new(string_view(tls_root_ca)); + try_release(DriverTlsConfig::enabled_with_root_ca(tls_root_ca_path)) +} + +/// Frees the native rust DriverTlsConfig object. +#[no_mangle] +pub extern "C" fn driver_tls_config_drop(tls_config: *mut DriverTlsConfig) { + free(tls_config); +} + +/// Returns whether TLS is enabled. +#[no_mangle] +pub extern "C" fn driver_tls_config_is_enabled(tls_config: *const DriverTlsConfig) -> bool { + borrow(tls_config).is_enabled() +} + +/// Returns whether a custom root CA path is set. +#[no_mangle] +pub extern "C" fn driver_tls_config_has_root_ca_path(tls_config: *const DriverTlsConfig) -> bool { + borrow(tls_config).root_ca_path().is_some() +} + +/// Returns the TLS root CA set in this DriverTlsConfig object. +/// Panics if a custom root CA is absent. +#[no_mangle] +pub extern "C" fn driver_tls_config_get_root_ca_path(tls_config: *const DriverTlsConfig) -> *mut c_char { + release_string(borrow(tls_config).root_ca_path().unwrap().to_string_lossy().to_string()) +} diff --git a/c/src/lib.rs b/c/src/lib.rs index bb8181e633..ec1f9c6d7a 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -21,18 +21,16 @@ mod analyze; mod answer; mod common; mod concept; -mod connection; +mod credentials; mod database; -mod database_manager; -mod error; -mod iterator; -mod memory; -mod promise; +mod driver; +mod driver_options; +mod driver_tls_config; mod query_options; +mod server; mod transaction; mod transaction_options; mod user; -mod user_manager; use tracing_subscriber::{filter::LevelFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; diff --git a/c/src/query_options.rs b/c/src/query_options.rs index 73be282a57..7c5862646c 100644 --- a/c/src/query_options.rs +++ b/c/src/query_options.rs @@ -19,7 +19,7 @@ use typedb_driver::QueryOptions; -use super::memory::{borrow, borrow_mut, free, release}; +use crate::common::memory::{borrow, borrow_mut, free, release}; /// Produces a new QueryOptions object. #[no_mangle] @@ -33,7 +33,7 @@ pub extern "C" fn query_options_drop(options: *mut QueryOptions) { free(options); } -/// Explicitly set the "include instance types" flag. +/// Explicitly setsthe "include instance types" flag. /// If set, specifies if types should be included in instance structs returned in ConceptRow answers. /// This option allows reducing the amount of unnecessary data transmitted. #[no_mangle] @@ -55,7 +55,7 @@ pub extern "C" fn query_options_has_include_instance_types(options: *const Query borrow(options).include_instance_types.is_some() } -/// Explicitly set the prefetch size. +/// Explicitly setsthe prefetch size. /// If set, specifies the number of extra query responses sent before the client side has to re-request more responses. /// Increasing this may increase performance for queries with a huge number of answers, as it can /// reduce the number of network round-trips at the cost of more resources on the server side. diff --git a/c/src/server/consistency_level.rs b/c/src/server/consistency_level.rs new file mode 100644 index 0000000000..9828b5d308 --- /dev/null +++ b/c/src/server/consistency_level.rs @@ -0,0 +1,127 @@ +/* + * 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. + */ +use std::ffi::c_char; + +use typedb_driver::consistency_level::ConsistencyLevel as NativeConsistencyLevel; + +use crate::common::{ + error::unwrap_or_default, + memory::{borrow_optional, free, release, release_string, string_free, string_view}, +}; + +/// ConsistencyLevelTag is used to represent consistency levels in FFI. +/// It is the tag part, which is combined with optional fields to form an instance of the original +/// enum. +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub enum ConsistencyLevelTag { + Strong, + Eventual, + ReplicaDependent, +} + +/// ConsistencyLevel is used to represent consistency levels in FFI. +/// It combines ConsistencyLevelTag and optional fields to form an instance of the +/// original enum. +/// address is not null only when tag is ReplicaDependent. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct ConsistencyLevel { + pub(crate) tag: ConsistencyLevelTag, + pub(crate) address: *mut c_char, +} + +impl ConsistencyLevel { + fn new_strong() -> Self { + ConsistencyLevel { tag: ConsistencyLevelTag::Strong, address: std::ptr::null_mut() } + } + + fn new_eventual() -> Self { + ConsistencyLevel { tag: ConsistencyLevelTag::Eventual, address: std::ptr::null_mut() } + } + + fn new_replica_dependent(address: *mut c_char) -> Self { + ConsistencyLevel { tag: ConsistencyLevelTag::ReplicaDependent, address } + } + + fn to_native(&self) -> NativeConsistencyLevel { + match self.tag { + ConsistencyLevelTag::Strong => NativeConsistencyLevel::Strong, + ConsistencyLevelTag::Eventual => NativeConsistencyLevel::Eventual, + ConsistencyLevelTag::ReplicaDependent => { + let address = unwrap_or_default(string_view(self.address).parse()); + NativeConsistencyLevel::ReplicaDependent { address } + } + } + } +} + +impl Drop for ConsistencyLevel { + fn drop(&mut self) { + string_free(self.address); + } +} + +/// Creates a strong ConsistencyLevel object. +#[no_mangle] +pub extern "C" fn consistency_level_strong() -> *mut ConsistencyLevel { + release(ConsistencyLevel::new_strong()) +} + +/// Creates an eventual ConsistencyLevel object. +#[no_mangle] +pub extern "C" fn consistency_level_eventual() -> *mut ConsistencyLevel { + release(ConsistencyLevel::new_eventual()) +} + +/// Creates a replica dependent ConsistencyLevel object. +/// +/// @param address The address of the replica to depend on. +#[no_mangle] +pub extern "C" fn consistency_level_replica_dependent(address: *const c_char) -> *mut ConsistencyLevel { + release(ConsistencyLevel::new_replica_dependent(release_string(string_view(address.clone()).to_string()))) +} + +/// Drops the ConsistencyLevel object. +#[no_mangle] +pub extern "C" fn consistency_level_drop(consistency_level: *mut ConsistencyLevel) { + free(consistency_level) +} + +pub(crate) fn native_consistency_level(consistency_level: *const ConsistencyLevel) -> Option { + borrow_optional(consistency_level).map(ConsistencyLevel::to_native) +} + +impl Into for ConsistencyLevel { + fn into(self) -> NativeConsistencyLevel { + self.to_native() + } +} + +impl From for ConsistencyLevel { + fn from(value: NativeConsistencyLevel) -> Self { + match value { + NativeConsistencyLevel::Strong => ConsistencyLevel::new_strong(), + NativeConsistencyLevel::Eventual => ConsistencyLevel::new_eventual(), + NativeConsistencyLevel::ReplicaDependent { address } => { + ConsistencyLevel::new_replica_dependent(release_string(address.to_string())) + } + } + } +} diff --git a/c/src/server/mod.rs b/c/src/server/mod.rs new file mode 100644 index 0000000000..4fe89b5313 --- /dev/null +++ b/c/src/server/mod.rs @@ -0,0 +1,22 @@ +/* + * 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. + */ + +pub(crate) mod consistency_level; +pub(crate) mod server_replica; +pub(crate) mod server_version; diff --git a/c/src/server/server_replica.rs b/c/src/server/server_replica.rs new file mode 100644 index 0000000000..a609a3fa3e --- /dev/null +++ b/c/src/server/server_replica.rs @@ -0,0 +1,91 @@ +/* + * 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. + */ + +use std::{ffi::c_char, ptr::addr_of_mut}; + +use typedb_driver::{Replica, ReplicaRole, ServerReplica}; + +use crate::common::{ + iterator::{iterator_next, CIterator}, + memory::{borrow, free, release_optional_string}, +}; + +/// Iterator over the ServerReplica corresponding to each replica of a TypeDB cluster. +pub struct ServerReplicaIterator(pub(crate) CIterator); + +/// Forwards the ServerReplicaIterator and returns the next ServerReplica if it exists, +/// or null if there are no more elements. +#[no_mangle] +pub extern "C" fn server_replica_iterator_next(it: *mut ServerReplicaIterator) -> *mut ServerReplica { + unsafe { iterator_next(addr_of_mut!((*it).0)) } +} + +/// Frees the native rust ServerReplicaIterator object. +#[no_mangle] +pub extern "C" fn server_replica_iterator_drop(it: *mut ServerReplicaIterator) { + free(it); +} + +/// Frees the native rust ServerReplica object. +#[no_mangle] +pub extern "C" fn server_replica_drop(replica_info: *mut ServerReplica) { + free(replica_info); +} + +/// Returns the id of this replica. +#[no_mangle] +pub extern "C" fn server_replica_get_id(replica_info: *const ServerReplica) -> i64 { + borrow(replica_info).id() as i64 +} + +/// Returns the address this replica is hosted at. +#[no_mangle] +pub extern "C" fn server_replica_get_address(replica_info: *const ServerReplica) -> *mut c_char { + release_optional_string(borrow(replica_info).address().map(|address| address.to_string())) +} + +/// Returns whether the role of this replica is set. +#[no_mangle] +pub extern "C" fn server_replica_has_role(replica_info: *const ServerReplica) -> bool { + borrow(replica_info).role().is_some() +} + +/// Returns whether this is the primary replica of the raft cluster or any of the supporting roles. +#[no_mangle] +pub extern "C" fn server_replica_get_role(replica_info: *const ServerReplica) -> ReplicaRole { + borrow(replica_info).role().unwrap() +} + +/// Checks whether this is the primary replica of the raft cluster. +#[no_mangle] +pub extern "C" fn server_replica_is_primary(replica_info: *const ServerReplica) -> bool { + borrow(replica_info).is_primary() +} + +/// Returns whether the raft protocol ‘term’ of this replica exists. +#[no_mangle] +pub extern "C" fn server_replica_has_term(replica_info: *const ServerReplica) -> bool { + borrow(replica_info).term().is_some() +} + +/// Returns the raft protocol ‘term’ of this replica. +#[no_mangle] +pub extern "C" fn server_replica_get_term(replica_info: *const ServerReplica) -> i64 { + borrow(replica_info).term().unwrap() as i64 +} diff --git a/c/src/server/server_version.rs b/c/src/server/server_version.rs new file mode 100644 index 0000000000..4509be51a2 --- /dev/null +++ b/c/src/server/server_version.rs @@ -0,0 +1,55 @@ +/* + * 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. + */ + +use std::{ffi::c_char, ptr::null_mut}; + +use crate::common::memory::{free, release_string, string_free}; + +/// ServerVersion is an FFI representation of a full server's version specification. +#[repr(C)] +#[derive(Debug)] +pub struct ServerVersion { + distribution: *mut c_char, + version: *mut c_char, +} + +impl ServerVersion { + pub fn new(distribution: String, version: String) -> Self { + Self { distribution: release_string(distribution), version: release_string(version) } + } +} + +impl Default for ServerVersion { + fn default() -> Self { + Self { distribution: null_mut(), version: null_mut() } + } +} + +impl Drop for ServerVersion { + fn drop(&mut self) { + string_free(self.distribution); + string_free(self.version); + } +} + +/// Frees the native rust ServerVersion object +#[no_mangle] +pub extern "C" fn server_version_drop(server_version: *mut ServerVersion) { + free(server_version); +} diff --git a/c/src/transaction.rs b/c/src/transaction.rs index 17601a1332..986acf7f6d 100644 --- a/c/src/transaction.rs +++ b/c/src/transaction.rs @@ -21,10 +21,14 @@ use std::{ffi::c_char, ptr::null_mut}; use typedb_driver::{Error, QueryOptions, Transaction, TransactionOptions, TransactionType, TypeDBDriver}; -use super::memory::{borrow, borrow_mut, free, release, take_ownership}; use crate::{ - analyze::AnalyzedQueryPromise, answer::QueryAnswerPromise, error::try_release, memory::string_view, - promise::VoidPromise, + analyze::AnalyzedQueryPromise, + answer::QueryAnswerPromise, + common::{ + error::try_release, + memory::{borrow, borrow_mut, free, release, string_view, take_ownership}, + promise::VoidPromise, + }, }; /// Opens a transaction to perform read or write queries on the database connected to the session. @@ -40,7 +44,7 @@ pub extern "C" fn transaction_new( type_: TransactionType, options: *const TransactionOptions, ) -> *mut Transaction { - try_release(borrow(driver).transaction_with_options(string_view(database_name), type_, *borrow(options))) + try_release(borrow(driver).transaction_with_options(string_view(database_name), type_, borrow(options).clone())) } /// Performs a TypeQL query in the transaction. diff --git a/c/src/transaction_options.rs b/c/src/transaction_options.rs index af2c3797ee..48aa761e34 100644 --- a/c/src/transaction_options.rs +++ b/c/src/transaction_options.rs @@ -21,7 +21,10 @@ use std::time::Duration; use typedb_driver::TransactionOptions; -use super::memory::{borrow, borrow_mut, free, release}; +use crate::{ + common::memory::{borrow, borrow_mut, free, release}, + server::consistency_level::{native_consistency_level, ConsistencyLevel}, +}; /// Produces a new TransactionOptions object. #[no_mangle] @@ -35,7 +38,7 @@ pub extern "C" fn transaction_options_drop(options: *mut TransactionOptions) { free(options); } -/// Explicitly set a transaction timeout. +/// Explicitly sets a transaction timeout. /// If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. #[no_mangle] pub extern "C" fn transaction_options_set_transaction_timeout_millis( @@ -84,3 +87,34 @@ pub extern "C" fn transaction_options_has_schema_lock_acquire_timeout_millis( ) -> bool { borrow(options).schema_lock_acquire_timeout.is_some() } + +/// Explicitly sets read consistency level. +/// If set, specifies the requested consistency level of the transaction opening operation. +/// Affects only read transactions, as write and schema transactions require primary replicas. +#[no_mangle] +pub extern "C" fn transaction_options_set_read_consistency_level( + options: *mut TransactionOptions, + read_consistency_level: *const ConsistencyLevel, +) { + // TODO: This is a hacky feature - you can unset the read consistency level if you pass a nullptr. + // We should decide what is the general approach if we want to unset an option: whether we also + // introduce "unset" (a little irritating to maintain) or we consider that the user just creates + // another object of options. We hardly want to crash here if it's a nullptr. + borrow_mut(options).read_consistency_level = native_consistency_level(read_consistency_level); +} + +/// Returns the value set for the read consistency level in this TransactionOptions object. +/// If set, specifies the requested consistency level of the transaction opening operation. +/// Affects only read transactions, as write and schema transactions require primary replicas. +#[no_mangle] +pub extern "C" fn transaction_options_get_read_consistency_level( + options: *const TransactionOptions, +) -> *mut ConsistencyLevel { + release(ConsistencyLevel::from(borrow(options).read_consistency_level.clone().unwrap())) +} + +/// Checks whether the option for read consistency level was explicitly set for this TransactionOptions object. +#[no_mangle] +pub extern "C" fn transaction_options_has_read_consistency_level(options: *const TransactionOptions) -> bool { + borrow(options).read_consistency_level.is_some() +} diff --git a/c/src/user.rs b/c/src/user.rs deleted file mode 100644 index 15a3e5c2d4..0000000000 --- a/c/src/user.rs +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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. - */ - -use std::ffi::c_char; - -use typedb_driver::User; - -use super::{ - error::unwrap_void, - memory::{borrow, free, release_string, string_view}, -}; -use crate::memory::take_ownership; - -/// Frees the native rust User object. -#[no_mangle] -pub extern "C" fn user_drop(user: *mut User) { - free(user); -} - -/// Returns the name of this user. -#[no_mangle] -pub extern "C" fn user_get_name(user: *mut User) -> *mut c_char { - release_string(borrow(user).name.clone()) -} - -// /// Returns the number of seconds remaining till this user’s current password expires. -// #[no_mangle] -// pub extern "C" fn user_get_password_expiry_seconds(user: *mut User) -> i64 { -// borrow(user).password_expiry_seconds.unwrap_or(-1) -// } - -/// Updates the password for the current authenticated user. -/// -/// @param user The user to update the password of - must be the current user. -/// @param user_manager The UserManager object on this connection. -/// @param password_old The current password of this user -/// @param password_new The new password -#[no_mangle] -pub extern "C" fn user_update_password(user: *mut User, password: *const c_char) { - unwrap_void(borrow(user).update_password(string_view(password))); -} - -/// Deletes this database. -#[no_mangle] -pub extern "C" fn user_delete(user: *mut User) { - unwrap_void(take_ownership(user).delete()); -} diff --git a/c/src/user/mod.rs b/c/src/user/mod.rs new file mode 100644 index 0000000000..3d2fb9f230 --- /dev/null +++ b/c/src/user/mod.rs @@ -0,0 +1,21 @@ +/* + * 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. + */ + +pub(crate) mod user; +pub(crate) mod user_manager; diff --git a/c/src/user/user.rs b/c/src/user/user.rs new file mode 100644 index 0000000000..afcc193057 --- /dev/null +++ b/c/src/user/user.rs @@ -0,0 +1,78 @@ +/* + * 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. + */ + +use std::ffi::c_char; + +use typedb_driver::User; + +use crate::{ + common::{ + error::unwrap_void, + memory::{borrow, free, release_string, string_view, take_ownership}, + }, + server::consistency_level::{native_consistency_level, ConsistencyLevel}, +}; + +/// Frees the native rust User object. +#[no_mangle] +pub extern "C" fn user_drop(user: *mut User) { + free(user); +} + +/// Returns the name of this user. +#[no_mangle] +pub extern "C" fn user_get_name(user: *mut User) -> *mut c_char { + release_string(borrow(user).name().to_string()) +} + +/// Updates the password for the current authenticated user. +/// +/// @param user The user to update the password of - must be the current user. +/// @param user_manager The UserManager object on this connection. +/// @param password_old The current password of this user. +/// @param password_new The new password. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn user_update_password( + user: *mut User, + password: *const c_char, + consistency_level: *const ConsistencyLevel, +) { + let user = borrow(user); + let password = string_view(password); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => user.update_password_with_consistency(password, consistency_level), + None => user.update_password(password), + }; + unwrap_void(result); +} + +/// Deletes this user. +/// +/// @param user The User to delete. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn user_delete(user: *mut User, consistency_level: *const ConsistencyLevel) { + let user = take_ownership(user); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => user.delete_with_consistency(consistency_level), + None => user.delete(), + }; + unwrap_void(result); +} diff --git a/c/src/user/user_manager.rs b/c/src/user/user_manager.rs new file mode 100644 index 0000000000..f2422d7290 --- /dev/null +++ b/c/src/user/user_manager.rs @@ -0,0 +1,142 @@ +/* + * 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. + */ + +use std::{ffi::c_char, ptr::addr_of_mut}; + +use typedb_driver::{box_stream, TypeDBDriver, User}; + +use crate::{ + common::{ + error::{try_release, try_release_optional, unwrap_or_default, unwrap_void}, + iterator::{iterator_next, CIterator}, + memory::{borrow, free, string_view}, + }, + server::consistency_level::{native_consistency_level, ConsistencyLevel}, +}; + +/// Iterator over a set of Users. +pub struct UserIterator(CIterator); + +/// Forwards the UserIterator and returns the next User if it exists, +/// or null if there are no more elements. +#[no_mangle] +pub extern "C" fn user_iterator_next(it: *mut UserIterator) -> *mut User { + unsafe { iterator_next(addr_of_mut!((*it).0)) } +} + +/// Frees the native rust UserIterator object. +#[no_mangle] +pub extern "C" fn user_iterator_drop(it: *mut UserIterator) { + free(it); +} + +/// Retrieves all users which exist on the TypeDB server. +/// +/// @param driver The TypeDBDriver object. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn users_all( + driver: *const TypeDBDriver, + consistency_level: *const ConsistencyLevel, +) -> *mut UserIterator { + let users = borrow(driver).users(); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => users.all_with_consistency(consistency_level), + None => users.all(), + }; + try_release(result.map(|users| UserIterator(CIterator(box_stream(users.into_iter()))))) +} + +/// Checks if a user with the given name exists. +/// +/// @param driver The TypeDBDriver object. +/// @param username The username of the user. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn users_contains( + driver: *const TypeDBDriver, + username: *const c_char, + consistency_level: *const ConsistencyLevel, +) -> bool { + let users = borrow(driver).users(); + let username = string_view(username); + unwrap_or_default(match native_consistency_level(consistency_level) { + Some(consistency_level) => users.contains_with_consistency(username, consistency_level), + None => users.contains(username), + }) +} + +/// Retrieves a user with the given name. +/// +/// @param driver The TypeDBDriver object. +/// @param username The username of the user. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn users_get( + driver: *const TypeDBDriver, + username: *const c_char, + consistency_level: *const ConsistencyLevel, +) -> *mut User { + let users = borrow(driver).users(); + let username = string_view(username); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => users.get_with_consistency(username, consistency_level), + None => users.get(username), + }; + try_release_optional(result.transpose()) +} + +/// Retrieves the username of the user who opened this connection. +/// +/// @param driver The TypeDBDriver object. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn users_get_current( + driver: *const TypeDBDriver, + consistency_level: *const ConsistencyLevel, +) -> *mut User { + let users = borrow(driver).users(); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => users.get_current_with_consistency(consistency_level), + None => users.get_current(), + }; + try_release_optional(result.transpose()) +} + +/// Creates a user with the given name & password. +/// +/// @param username The username of the created user. +/// @param password The password of the created user. +/// @param consistency_level The consistency level to use for the operation. Strongest possible if null. +#[no_mangle] +pub extern "C" fn users_create( + driver: *const TypeDBDriver, + username: *const c_char, + password: *const c_char, + consistency_level: *const ConsistencyLevel, +) { + let users = borrow(driver).users(); + let username = string_view(username); + let password = string_view(password); + let result = match native_consistency_level(consistency_level) { + Some(consistency_level) => users.create_with_consistency(username, password, consistency_level), + None => users.create(username, password), + }; + unwrap_void(result); +} diff --git a/c/src/user_manager.rs b/c/src/user_manager.rs deleted file mode 100644 index 5c347506d3..0000000000 --- a/c/src/user_manager.rs +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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. - */ - -use std::{ffi::c_char, ptr::addr_of_mut}; - -use typedb_driver::{box_stream, TypeDBDriver, User}; - -use super::{ - error::{try_release, try_release_optional, unwrap_or_default, unwrap_void}, - iterator::{iterator_next, CIterator}, - memory::{borrow, free, string_view}, -}; - -/// Iterator over a set of Users -pub struct UserIterator(CIterator); - -/// Forwards the UserIterator and returns the next User if it exists, -/// or null if there are no more elements. -#[no_mangle] -pub extern "C" fn user_iterator_next(it: *mut UserIterator) -> *mut User { - unsafe { iterator_next(addr_of_mut!((*it).0)) } -} - -/// Frees the native rust UserIterator object -#[no_mangle] -pub extern "C" fn user_iterator_drop(it: *mut UserIterator) { - free(it); -} - -/// Retrieves all users which exist on the TypeDB server. -#[no_mangle] -pub extern "C" fn users_all(driver: *const TypeDBDriver) -> *mut UserIterator { - try_release(borrow(driver).users().all().map(|users| UserIterator(CIterator(box_stream(users.into_iter()))))) -} - -/// Checks if a user with the given name exists. -#[no_mangle] -pub extern "C" fn users_contains(driver: *const TypeDBDriver, username: *const c_char) -> bool { - unwrap_or_default(borrow(driver).users().contains(string_view(username))) -} - -/// Creates a user with the given name & password. -#[no_mangle] -pub extern "C" fn users_create(driver: *const TypeDBDriver, username: *const c_char, password: *const c_char) { - unwrap_void(borrow(driver).users().create(string_view(username), string_view(password))); -} - -/// Retrieves a user with the given name. -#[no_mangle] -pub extern "C" fn users_get(driver: *const TypeDBDriver, username: *const c_char) -> *mut User { - try_release_optional(borrow(driver).users().get(string_view(username)).transpose()) -} - -/// Retrieves the username of the user who opened this connection -#[no_mangle] -pub extern "C" fn users_get_current_user(driver: *const TypeDBDriver) -> *mut User { - try_release_optional(borrow(driver).users().get_current_user().transpose()) -} diff --git a/c/swig/typedb_driver_java.swg b/c/swig/typedb_driver_java.swg index e23b275b9e..197a761c17 100644 --- a/c/swig/typedb_driver_java.swg +++ b/c/swig/typedb_driver_java.swg @@ -88,9 +88,9 @@ %nojavaexception transaction_options_get_schema_lock_acquire_timeout_millis; %nojavaexception transaction_options_set_schema_lock_acquire_timeout_millis; %nojavaexception transaction_options_has_schema_lock_acquire_timeout_millis; -%nojavaexception transaction_options_get_parallel; -%nojavaexception transaction_options_set_parallel; -%nojavaexception transaction_options_has_parallel; +%nojavaexception transaction_options_get_read_consistency_level; +%nojavaexception transaction_options_set_read_consistency_level; +%nojavaexception transaction_options_has_read_consistency_level; %nojavaexception query_options_new; %nojavaexception query_options_get_include_instance_types; @@ -107,21 +107,46 @@ %nojavaexception error_message; %nojavaexception driver_is_open; +// TODO: Remove from this list if we start making network calls to retrieve this +%nojavaexception driver_primary_replica; + +%nojavaexception driver_options_new; +%nojavaexception driver_options_set_tls_config; +%nojavaexception driver_options_get_tls_config; +%nojavaexception driver_options_set_request_timeout_millis; +%nojavaexception driver_options_get_request_timeout_millis; +%nojavaexception driver_options_set_use_replication; +%nojavaexception driver_options_get_use_replication; +%nojavaexception driver_options_set_primary_failover_retries; +%nojavaexception driver_options_get_primary_failover_retries; +%nojavaexception driver_options_set_replica_discovery_attempts; +%nojavaexception driver_options_get_replica_discovery_attempts; +%nojavaexception driver_options_has_replica_discovery_attempts; + +%nojavaexception driver_tls_config_new_disabled; +%nojavaexception driver_tls_config_new_enabled_with_native_root_ca; +%nojavaexception driver_tls_config_is_enabled; +%nojavaexception driver_tls_config_has_root_ca_path; +%nojavaexception driver_tls_config_get_root_ca_path; %nojavaexception transaction_is_open; %nojavaexception user_get_name; %nojavaexception user_get_password_expiry_seconds; -//%nojavaexception replica_info_get_server; -//%nojavaexception replica_info_is_primary; -//%nojavaexception replica_info_is_preferred; -//%nojavaexception replica_info_get_term; +%nojavaexception server_replica_get_address; +%nojavaexception server_replica_is_primary; +%nojavaexception server_replica_get_id; +%nojavaexception server_replica_get_role; +%nojavaexception server_replica_has_role; +%nojavaexception server_replica_get_term; +%nojavaexception server_replica_has_term; %nojavaexception database_get_name; -//%nojavaexception database_get_replicas_info; -//%nojavaexception database_get_primary_replica_info; -//%nojavaexception database_get_preferred_replica_info; + +%nojavaexception consistency_level_strong; +%nojavaexception consistency_level_eventual; +%nojavaexception consistency_level_replica_dependent; %nojavaexception concept_is_entity; %nojavaexception concept_is_relation; @@ -191,6 +216,9 @@ %nojavaexception query_answer_is_concept_row_stream; %nojavaexception query_answer_is_concept_document_stream; +%nojavaexception ServerVersion::distribution; +%nojavaexception ServerVersion::version; + %nojavaexception StringPair::_0; %nojavaexception StringPair::_1; @@ -212,6 +240,9 @@ %nojavaexception Duration::days; %nojavaexception Duration::nanos; +%nojavaexception ConsistencyLevel::tag; +%nojavaexception ConsistencyLevel::address; + /* director constructors do not throw */ %nojavaexception TransactionCallbackDirector; @@ -338,7 +369,9 @@ %nojavaexception ~ConceptIterator; %nojavaexception ~ConceptRow; %nojavaexception ~ConceptRowIterator; +%nojavaexception ~ConsistencyLevel; %nojavaexception ~DriverOptions; +%nojavaexception ~DriverTlsConfig; %nojavaexception ~Credentials; %nojavaexception ~Database; %nojavaexception ~DatabaseIterator; @@ -347,7 +380,9 @@ %nojavaexception ~Decimal; %nojavaexception ~Duration; %nojavaexception ~Error; -//%nojavaexception ~ReplicaInfo; +%nojavaexception ~ServerReplica; +%nojavaexception ~ServerReplicaIterator; +%nojavaexception ~ServerVersion; %nojavaexception ~StringIterator; %nojavaexception ~StringAndOptValue; %nojavaexception ~StringAndOptValueIterator; @@ -536,7 +571,7 @@ %iterator(StringAndOptValue, string_and_opt_value) %iterator(User, user) %iterator(Database, database) -//%iterator(ReplicaInfo, replica_info) +%iterator(ServerReplica, server_replica) %iterator(ConjunctionID, conjunction_id) %iterator(ConstraintWithSpan, constraint_with_span) diff --git a/c/tests/assembly/test.c b/c/tests/assembly/test.c index 8468a7eba5..e68a226685 100644 --- a/c/tests/assembly/test.c +++ b/c/tests/assembly/test.c @@ -42,34 +42,38 @@ bool check_error_may_print(const char* filename, int lineno) { } #define FAILED() check_error_may_print(__FILE__, __LINE__) -TypeDBDriver* driver_open_for_tests(const char* address, const char* username, const char* password) { + +TypeDBDriver* driver_new_for_tests(const char* address, const char* username, const char* password) { DriverOptions* options = NULL; + DriverTlsConfig* tls_config = driver_tls_config_new_disabled(); Credentials* creds = credentials_new(username, password); if (check_error_may_print(__FILE__, __LINE__)) goto cleanup; - options = driver_options_new(false, NULL);; + + options = driver_options_new(tls_config); if (check_error_may_print(__FILE__, __LINE__)) goto cleanup; - TypeDBDriver* driver = driver_open_with_description(address, creds, options, DRIVER_LANG); + + TypeDBDriver* driver = driver_new_with_description(address, creds, options, DRIVER_LANG); + cleanup: driver_options_drop(options); credentials_drop(creds); - + driver_tls_config_drop(tls_config); return driver; } int main() { const char databaseName[] = "test_assembly_clib"; - TypeDBDriver* driver = NULL; - + TypeDBDriver* driver = NULL; bool success = false; - driver = driver_open_for_tests(TYPEDB_CORE_ADDRESS, TYPEDB_CORE_USERNAME, TYPEDB_CORE_PASSWORD); + driver = driver_new_for_tests(TYPEDB_CORE_ADDRESS, TYPEDB_CORE_USERNAME, TYPEDB_CORE_PASSWORD); if (FAILED()) goto cleanup; - databases_create(driver, databaseName); + databases_create(driver, databaseName, NULL); if (FAILED()) goto cleanup; - if (!databases_contains(driver, databaseName)) { + if (!databases_contains(driver, databaseName, NULL)) { fprintf(stderr, "databases_contains(\'%s\') failed\n", databaseName); goto cleanup; } diff --git a/c/tests/integration/common.c b/c/tests/integration/common.c index 785cd4f17b..a51aa1ba5a 100644 --- a/c/tests/integration/common.c +++ b/c/tests/integration/common.c @@ -42,25 +42,26 @@ bool check_error_may_print(const char* filename, int lineno) { void delete_database_if_exists(TypeDBDriver* driver, const char* name) { if (driver == NULL) return; - bool contains = databases_contains(driver, name); + bool contains = databases_contains(driver, name, NULL); if (check_error_may_print(__FILE__, __LINE__)) return; if (contains) { - const Database* db = databases_get(driver, name); + const Database* db = databases_get(driver, name, NULL); if (check_error_may_print(__FILE__, __LINE__)) return; - database_delete(db); + database_delete(db, NULL); } } -TypeDBDriver* driver_open_for_tests(const char* address, const char* username, const char* password) { +TypeDBDriver* driver_new_for_tests(const char* address, const char* username, const char* password) { DriverOptions* options = NULL; + DriverTlsConfig* tls_config = driver_tls_config_new_disabled(); Credentials* creds = credentials_new(username, password); if (check_error_may_print(__FILE__, __LINE__)) goto cleanup; - options = driver_options_new(false, NULL);; + options = driver_options_new(tls_config); if (check_error_may_print(__FILE__, __LINE__)) goto cleanup; - TypeDBDriver* driver = driver_open_with_description(address, creds, options, DRIVER_LANG); + TypeDBDriver* driver = driver_new_with_description(address, creds, options, DRIVER_LANG); cleanup: driver_options_drop(options); credentials_drop(creds); - + driver_tls_config_drop(tls_config); return driver; } diff --git a/c/tests/integration/common.h b/c/tests/integration/common.h index 135863cc70..f54de973ca 100644 --- a/c/tests/integration/common.h +++ b/c/tests/integration/common.h @@ -21,8 +21,13 @@ extern const char* TYPEDB_CORE_ADDRESS; extern const char* TYPEDB_CORE_USERNAME; extern const char* TYPEDB_CORE_PASSWORD; +static const ConsistencyLevel STRONG_CONSISTENCY = { + .tag = Strong, + .address = NULL, +}; + bool check_error_may_print(const char* filename, int lineno); -TypeDBDriver* driver_open_for_tests(const char* address, const char* username, const char* password); +TypeDBDriver* driver_new_for_tests(const char* address, const char* username, const char* password); void delete_database_if_exists(TypeDBDriver* driver, const char* name); diff --git a/c/tests/integration/test_driver.c b/c/tests/integration/test_driver.c index 6e548f3d9c..51888c6da9 100644 --- a/c/tests/integration/test_driver.c +++ b/c/tests/integration/test_driver.c @@ -32,22 +32,23 @@ bool test_database_management() { bool success = false; - driver = driver_open_for_tests(TYPEDB_CORE_ADDRESS, TYPEDB_CORE_USERNAME, TYPEDB_CORE_PASSWORD); + driver = driver_new_for_tests(TYPEDB_CORE_ADDRESS, TYPEDB_CORE_USERNAME, TYPEDB_CORE_PASSWORD); if (FAILED()) goto cleanup; delete_database_if_exists(driver, databaseName); if (FAILED()) goto cleanup; - databases_create(driver, databaseName); + databases_create(driver, databaseName, NULL); if (FAILED()) goto cleanup; - if (!databases_contains(driver, databaseName)) { + // Consistency can be provided + if (!databases_contains(driver, databaseName, &STRONG_CONSISTENCY)) { fprintf(stderr, "databases_contains(\'%s\') failed\n", databaseName); goto cleanup; } bool foundDB = false; - DatabaseIterator* it = databases_all(driver); + DatabaseIterator* it = databases_all(driver, &STRONG_CONSISTENCY); const Database* database = NULL; while (NULL != (database = database_iterator_next(it))) { char* name = database_get_name(database); @@ -82,13 +83,13 @@ bool test_query_schema() { bool success = false; // Set up connection & database - driver = driver_open_for_tests(TYPEDB_CORE_ADDRESS, TYPEDB_CORE_USERNAME, TYPEDB_CORE_PASSWORD); + driver = driver_new_for_tests(TYPEDB_CORE_ADDRESS, TYPEDB_CORE_USERNAME, TYPEDB_CORE_PASSWORD); if (FAILED()) goto cleanup; delete_database_if_exists(driver, databaseName); if (FAILED()) goto cleanup; - databases_create(driver, databaseName); + databases_create(driver, databaseName, NULL); if (FAILED()) goto cleanup; tx_opts = transaction_options_new(); @@ -171,13 +172,14 @@ bool test_query_data() { bool success = false; // Set up connection & database - driver = driver_open_for_tests(TYPEDB_CORE_ADDRESS, TYPEDB_CORE_USERNAME, TYPEDB_CORE_PASSWORD); + driver = driver_new_for_tests(TYPEDB_CORE_ADDRESS, TYPEDB_CORE_USERNAME, TYPEDB_CORE_PASSWORD); if (FAILED()) goto cleanup; delete_database_if_exists(driver, databaseName); if (FAILED()) goto cleanup; - databases_create(driver, databaseName); + // ConsistencyLevel is automatically set if null + databases_create(driver, databaseName, NULL); if (FAILED()) goto cleanup; tx_opts = transaction_options_new(); @@ -187,7 +189,6 @@ bool test_query_data() { // Set up schema { - transaction = transaction_new(driver, databaseName, Schema, tx_opts); if (FAILED()) goto cleanup; diff --git a/c/typedb_driver.i b/c/typedb_driver.i index e85c8a6719..72f6e93c1a 100644 --- a/c/typedb_driver.i +++ b/c/typedb_driver.i @@ -42,7 +42,9 @@ extern "C" { %nodefaultctor; -%ignore driver_open; // use `driver_open_with_description` +%ignore driver_new; // use `driver_new_with_description` +%ignore driver_new_with_addresses; // use `driver_new_with_addresses_with_description` +%ignore driver_new_with_address_translation; // use `driver_new_with_address_translation_with_description` %define %dropproxy(Type, function_prefix) struct Type {}; @@ -59,8 +61,10 @@ struct Type {}; %dropproxy(Credentials, credentials) %dropproxy(DriverOptions, driver_options) +%dropproxy(DriverTlsConfig, driver_tls_config) %dropproxy(TransactionOptions, transaction_options) %dropproxy(QueryOptions, query_options) +%dropproxydefined(ServerVersion, server_version) #define typedb_driver_drop driver_close #define transaction_drop transaction_submit_close @@ -71,8 +75,8 @@ struct Type {}; %dropproxy(Database, database) %dropproxy(DatabaseIterator, database_iterator) -//%dropproxy(ReplicaInfo, replica_info) -//%dropproxy(ReplicaInfoIterator, replica_info_iterator) +%dropproxy(ServerReplica, server_replica) +%dropproxy(ServerReplicaIterator, server_replica_iterator) %dropproxy(User, user) %dropproxy(UserIterator, user_iterator) @@ -82,11 +86,11 @@ struct Type {}; %dropproxy(ConceptRow, concept_row) %dropproxy(ConceptRowIterator, concept_row_iterator) +%dropproxydefined(ConsistencyLevel, consistency_level) %dropproxydefined(DatetimeAndTimeZone, datetime_and_time_zone) %dropproxydefined(StringAndOptValue, string_and_opt_value) %dropproxy(StringAndOptValueIterator, string_and_opt_value_iterator) - %dropproxy(StringIterator, string_iterator) %dropproxy(QueryAnswer, query_answer) @@ -233,8 +237,8 @@ VoidPromise* transaction_on_close_register(const Transaction* transaction, Trans } %} -%delobject database_delete; - +%newobject transaction_new; +%newobject transaction_query; %delobject transaction_commit; %typemap(newfree) char* "string_free($1);"; @@ -250,9 +254,6 @@ VoidPromise* transaction_on_close_register(const Transaction* transaction, Trans %newobject concept_row_get_query_structure; %newobject concept_row_to_string; -%newobject value_get_string; -%newobject value_get_datetime_tz; - %newobject query_answer_into_rows; %newobject query_answer_into_documents; %delobject query_answer_into_rows; @@ -270,20 +271,31 @@ VoidPromise* transaction_on_close_register(const Transaction* transaction, Trans %newobject concept_try_get_value_type; %newobject concept_try_get_value; %newobject credentials_new; +%newobject consistency_level_strong; +%newobject consistency_level_eventual; +%newobject consistency_level_replica_dependent; + +%newobject driver_new_with_description; +%newobject driver_new_with_addresses_with_description; +%newobject driver_new_with_address_translation_with_description; +%newobject driver_server_version; +%newobject driver_primary_replica; +%newobject driver_replicas; -%newobject driver_open_with_description; %newobject driver_options_new; +%newobject driver_options_get_tls_config; +%newobject driver_tls_config_new_disabled; +%newobject driver_tls_config_new_enabled_with_native_root_ca; +%newobject driver_tls_config_new_enabled_with_root_ca_path; +%newobject driver_tls_config_get_root_ca_path; +%newobject transaction_options_get_read_consistency_level; %newobject database_get_name; %newobject database_schema; %newobject database_type_schema; +%delobject database_delete; -//%newobject database_get_preferred_replica_info; -//%newobject database_get_primary_replica_info; -//%newobject database_get_replicas_info; -// -//%newobject replica_info_get_server; -//%newobject replica_info_iterator_next; +%newobject server_replica_get_address; %newobject databases_all; %newobject databases_get; @@ -404,19 +416,15 @@ VoidPromise* transaction_on_close_register(const Transaction* transaction, Trans %newobject concept_iterator_next; %newobject concept_row_iterator_next; %newobject database_iterator_next; +%newobject server_replica_iterator_next; %newobject string_iterator_next; %newobject string_and_opt_value_iterator_next; %newobject user_iterator_next; %newobject variable_iterator_next; -%newobject transaction_new; -%newobject transaction_query; -%newobject transaction_analyze; - %newobject users_all; -%newobject users_get_current_user; +%newobject users_get_current; %newobject users_get; - %newobject user_get_name; %delobject user_delete; diff --git a/cpp/include/typedb/user/user_manager.hpp b/cpp/include/typedb/user/user_manager.hpp index 6c27e1ed6f..59b1c31608 100644 --- a/cpp/include/typedb/user/user_manager.hpp +++ b/cpp/include/typedb/user/user_manager.hpp @@ -43,7 +43,7 @@ class UserManager { * driver.users.contains(username); * * - * @param username The user name to be checked + * @param username The username to be checked */ bool contains(const std::string& username) const; diff --git a/csharp/Api/User/IUserManager.cs b/csharp/Api/User/IUserManager.cs index ead4a16dd1..4406a05e11 100644 --- a/csharp/Api/User/IUserManager.cs +++ b/csharp/Api/User/IUserManager.cs @@ -36,7 +36,7 @@ public interface IUserManager * driver.Users.Contains(username); * * - * @param username The user name to be checked + * @param username The username to be checked */ bool Contains(string username); diff --git a/dependencies/typedb/artifacts.bzl b/dependencies/typedb/artifacts.bzl index 44415003ec..7d2f563f29 100644 --- a/dependencies/typedb/artifacts.bzl +++ b/dependencies/typedb/artifacts.bzl @@ -25,20 +25,15 @@ def typedb_artifact(): artifact_name = "typedb-all-{platform}-{version}.{ext}", tag_source = deployment["artifact"]["release"]["download"], commit_source = deployment["artifact"]["snapshot"]["download"], - tag = "3.7.3" + commit = "360da2d0739fbd2edd8c597a62996ece360b68b0" ) -#def typedb_cloud_artifact(): -# native_artifact_files( -# name = "typedb_cloud_artifact", -# group_name = "typedb-cloud-server-{platform}", -# artifact_name = "typedb-cloud-server-{platform}-{version}.{ext}", -# tag_source = deployment_private["artifact"]["release"]["download"], -# commit_source = deployment_private["artifact"]["snapshot"]["download"], -# tag = "e4e4fee9d488e2a6e89e29716b98e3213d228809", -# ) - -#maven_artifacts = { -# 'com.typedb:typedb-runner': '2.28.3', -# 'com.typedb:typedb-cloud-runner': '2.28.3', -#} +def typedb_cluster_artifact(): + native_artifact_files( + name = "typedb_cluster_artifact", + group_name = "typedb-cluster-all-{platform}", + artifact_name = "typedb-cluster-all-{platform}-{version}.tar.gz", # TODO: Make {ext} instead of tar.gz + tag_source = deployment_private["artifact"]["release"]["download"], + commit_source = deployment_private["artifact"]["snapshot"]["download"], + commit = "350eed289eb9b357d7ca7da0416de31f897744c6", + ) diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index 418f0e85fc..074cb8f1f8 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -18,22 +18,25 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") def typedb_dependencies(): - git_repository( - name = "typedb_dependencies", - remote = "https://github.com/typedb/dependencies", - commit = "db7733a44863e26cd2d086ec71a6313f2a455c25", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_dependencies - ) + # TODO: Return ref after merge to master, currently points to 'raft-dependencies-addition' + git_repository( + name = "typedb_dependencies", + remote = "https://github.com/typedb/typedb-dependencies", + commit = "efacbdb7cc0731714586951ff83a19efa27b6e3e", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_dependencies + ) def typedb_protocol(): + # TODO: Return ref after merge to master git_repository( name = "typedb_protocol", remote = "https://github.com/typedb/typedb-protocol", - tag = "3.7.0", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol + tag = "3.7.0-alpha-0", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_protocol ) def typedb_behaviour(): + # TODO: Update ref after merge to master git_repository( name = "typedb_behaviour", remote = "https://github.com/typedb/typedb-behaviour", - commit = "a66405c982f7d266a9f07af025c670533258ea38", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour + commit = "f8ec7b8563bd44e611df41a4b180a65ef70d8bd2", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_behaviour ) diff --git a/docs/modules/ROOT/partials/c/connection/database.adoc b/docs/modules/ROOT/partials/c/connection/database.adoc index cb3c09bad1..70c4b2d076 100644 --- a/docs/modules/ROOT/partials/c/connection/database.adoc +++ b/docs/modules/ROOT/partials/c/connection/database.adoc @@ -2,21 +2,32 @@ === database [#_Struct_Database] -[.doc-api-reference-driver] ==== Struct Database -`rust struct (pointer)` - A TypeDB database +[#_Struct_DatabaseIterator] +==== Struct DatabaseIterator + + + +An ``Iterator`` over databases present on the TypeDB server + +[#_Struct_DatabaseManager] +==== Struct DatabaseManager + + + +Provides access to all database management methods. + [#_database_close] -==== function ``database_close`` +==== database_close -[source,c] +[source,cpp] ---- -void database_close(const struct Database* database) +void database_close(struct Database* database) ---- @@ -28,11 +39,11 @@ Frees the native rust ``Database`` object `void` [#_database_delete] -==== function ``database_delete`` +==== database_delete -[source,c] +[source,cpp] ---- -void database_delete(const struct Database* database) +void database_delete(struct Database* database) ---- @@ -43,56 +54,172 @@ Deletes this database. .Returns `void` -[#_database_export_to_file] -==== function ``database_export_to_file`` +[#_database_get_name] +==== database_get_name + +[source,cpp] +---- +char* database_get_name(const struct Database* database) +---- + + + +The database name as a string. + +[caption=""] +.Returns +`char*` -[source,c] +[#_database_get_preferred_replica_info] +==== database_get_preferred_replica_info + +[source,cpp] ---- -void database_export_to_file(const struct Database* database, const char* schema_file, const char* data_file) +struct ReplicaInfo* database_get_preferred_replica_info(const struct Database* database) ---- -Export a database into a schema definition and a data files saved to the disk. This is a blocking operation and may take a significant amount of time depending on the database size. +Returns the preferred replica for this database. Operations which can be run on any replica will prefer to use this replica. _Only works in TypeDB Cloud_ + +[caption=""] +.Returns +`struct ReplicaInfo*` + +[#_database_get_primary_replica_info] +==== database_get_primary_replica_info + +[source,cpp] +---- +struct ReplicaInfo* database_get_primary_replica_info(const struct Database* database) +---- + + + +Returns the primary replica for this database. _Only works in TypeDB Cloud_ + +[caption=""] +.Returns +`struct ReplicaInfo*` + +[#_database_get_replicas_info] +==== database_get_replicas_info +[source,cpp] +---- +struct ReplicaInfoIterator* database_get_replicas_info(const struct Database* database) +---- + + + +Set of ``ServerReplica`` instances for this database. Only works in TypeDB Cloud [caption=""] -.Input parameters -[cols=",,"] -[options="header"] -|=== -|Name |Description |Type -a| `database` a| The ``Database`` object to export from. a| `const struct Database*` -a| `schema_file` a| The path to the schema definition file to be created. a| `const char*` -a| `data_file` a| The path to the data file to be created. a| `const char*` -|=== +.Returns +`struct ReplicaInfoIterator*` + +[#_database_iterator_drop] +==== database_iterator_drop + +[source,cpp] +---- +void database_iterator_drop(struct DatabaseIterator* it) +---- + + + +Frees the native rust ``DatabaseIterator`` object [caption=""] .Returns `void` -[#_database_get_name] -==== function ``database_get_name`` +[#_database_iterator_next] +==== database_iterator_next -[source,c] +[source,cpp] ---- -char* database_get_name(const struct Database* database) +struct Database* database_iterator_next(struct DatabaseIterator* it) ---- -The database name as a string. +Forwards the ``DatabaseIterator`` and returns the next ``Database`` if it exists, or null if there are no more elements. + +[caption=""] +.Returns +`struct Database*` + +[#_database_manager_drop] +==== database_manager_drop + +[source,cpp] +---- +void database_manager_drop(struct DatabaseManager* databases) +---- + + + +Frees the native rust ``DatabaseManager`` object + +[caption=""] +.Returns +`void` + +[#_database_manager_new] +==== database_manager_new + +[source,cpp] +---- +struct DatabaseManager* database_manager_new(const struct Connection* connection) +---- + + + +Creates and returns a native ``DatabaseManager`` for the connection + +[caption=""] +.Returns +`struct DatabaseManager*` + +[#_database_rule_schema] +==== database_rule_schema + +[source,cpp] +---- +char* database_rule_schema(struct Database* database) +---- + + + +The rules in the schema as a valid TypeQL define query string. + +[caption=""] +.Returns +`char*` + +[#_database_schema] +==== database_schema + +[source,cpp] +---- +char* database_schema(struct Database* database) +---- + + + +A full schema text as a valid TypeQL define query string. [caption=""] .Returns `char*` [#_database_type_schema] -==== function ``database_type_schema`` +==== database_type_schema -[source,c] +[source,cpp] ---- -char* database_type_schema(const struct Database* database) +char* database_type_schema(struct Database* database) ---- @@ -103,3 +230,67 @@ The types in the schema as a valid TypeQL define query string. .Returns `char*` +[#_databases_all] +==== databases_all + +[source,cpp] +---- +struct DatabaseIterator* databases_all(struct DatabaseManager* databases) +---- + + + +Returns a ``DatabaseIterator`` over all databases present on the TypeDB server + +[caption=""] +.Returns +`struct DatabaseIterator*` + +[#_databases_contains] +==== databases_contains + +[source,cpp] +---- +bool databases_contains(struct DatabaseManager* databases, const char* name) +---- + + + +Checks if a database with the given name exists + +[caption=""] +.Returns +`bool` + +[#_databases_create] +==== databases_create + +[source,cpp] +---- +void databases_create(struct DatabaseManager* databases, const char* name) +---- + + + +Create a database with the given name + +[caption=""] +.Returns +`void` + +[#_databases_get] +==== databases_get + +[source,cpp] +---- +struct Database* databases_get(struct DatabaseManager* databases, const char* name) +---- + + + +Retrieve the database with the given name. + +[caption=""] +.Returns +`struct Database*` + diff --git a/docs/modules/ROOT/partials/c/session/options.adoc b/docs/modules/ROOT/partials/c/session/options.adoc new file mode 100644 index 0000000000..386380f351 --- /dev/null +++ b/docs/modules/ROOT/partials/c/session/options.adoc @@ -0,0 +1,533 @@ +[#_methods_session_options] +=== options + +[#_Struct_Options] +==== Struct Options + + + +TypeDB session and transaction options. ``TypeDBOptions`` object can be used to override the default server behaviour. Options are specified using properties assignment. + + +[#_options_drop] +==== options_drop + +[source,cpp] +---- +void options_drop(struct Options* options) +---- + + + +Frees the native rust ``Options`` object. + +[caption=""] +.Returns +`void` + +[#_options_get_explain] +==== options_get_explain + +[source,cpp] +---- +bool options_get_explain(const struct Options* options) +---- + + + +Returns the value set for the explanation in this ``TypeDBOptions`` object. If set to ``true``, explanations for queries are enabled. + +[caption=""] +.Returns +`bool` + +[#_options_get_infer] +==== options_get_infer + +[source,cpp] +---- +bool options_get_infer(const struct Options* options) +---- + + + +Returns the value set for the inference in this ``TypeDBOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_options_get_parallel] +==== options_get_parallel + +[source,cpp] +---- +bool options_get_parallel(const struct Options* options) +---- + + + +Returns the value set for the parallel execution in this ``TypeDBOptions`` object. If set to ``true``, the server uses parallel instead of single-threaded execution. + +[caption=""] +.Returns +`bool` + +[#_options_get_prefetch] +==== options_get_prefetch + +[source,cpp] +---- +bool options_get_prefetch(const struct Options* options) +---- + + + +Returns the value set for the prefetching in this ``TypeDBOptions`` object. If set to ``true``, the first batch of answers is streamed to the driver even without an explicit request for it. + +[caption=""] +.Returns +`bool` + +[#_options_get_prefetch_size] +==== options_get_prefetch_size + +[source,cpp] +---- +int32_t options_get_prefetch_size(const struct Options* options) +---- + + + +Returns the value set for the prefetch size in this ``TypeDBOptions`` object. If set, specifies a guideline number of answers that the server should send before the driver issues a fresh request. + +[caption=""] +.Returns +`int32_t` + +[#_options_get_read_any_replica] +==== options_get_read_any_replica + +[source,cpp] +---- +bool options_get_read_any_replica(const struct Options* options) +---- + + + +Returns the value set for reading data from any replica in this ``TypeDBOptions`` object. If set to ``True``, enables reading data from any replica, potentially boosting read throughput. + +[caption=""] +.Returns +`bool` + +[#_options_get_schema_lock_acquire_timeout_millis] +==== options_get_schema_lock_acquire_timeout_millis + +[source,cpp] +---- +int64_t options_get_schema_lock_acquire_timeout_millis(const struct Options* options) +---- + + + +Returns the value set for the schema lock acquire timeout in this ``TypeDBOptions`` object. If set, specifies how long the driver should wait if opening a session or transaction is blocked by a schema write lock. + +[caption=""] +.Returns +`int64_t` + +[#_options_get_session_idle_timeout_millis] +==== options_get_session_idle_timeout_millis + +[source,cpp] +---- +int64_t options_get_session_idle_timeout_millis(const struct Options* options) +---- + + + +Returns the value set for the session idle timeout in this ``TypeDBOptions`` object. If set, specifies a timeout that allows the server to close sessions if the driver terminates or becomes unresponsive. + +[caption=""] +.Returns +`int64_t` + +[#_options_get_trace_inference] +==== options_get_trace_inference + +[source,cpp] +---- +bool options_get_trace_inference(const struct Options* options) +---- + + + +Returns the value set for reasoning tracing in this ``TypeDBOptions`` object. If set to ``true``, reasoning tracing graphs are output in the logging directory. + +[caption=""] +.Returns +`bool` + +[#_options_get_transaction_timeout_millis] +==== options_get_transaction_timeout_millis + +[source,cpp] +---- +int64_t options_get_transaction_timeout_millis(const struct Options* options) +---- + + + +Returns the value set for the transaction timeout in this ``TypeDBOptions`` object. If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. + +[caption=""] +.Returns +`int64_t` + +[#_options_has_explain] +==== options_has_explain + +[source,cpp] +---- +bool options_has_explain(const struct Options* options) +---- + + + +Checks whether the option for explanation was explicitly set for this ``TypeDBOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_options_has_infer] +==== options_has_infer + +[source,cpp] +---- +bool options_has_infer(const struct Options* options) +---- + + + +Checks whether the option for inference was explicitly set for this ``TypeDBOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_options_has_parallel] +==== options_has_parallel + +[source,cpp] +---- +bool options_has_parallel(const struct Options* options) +---- + + + +Checks whether the option for parallel execution was explicitly set for this ``TypeDBOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_options_has_prefetch] +==== options_has_prefetch + +[source,cpp] +---- +bool options_has_prefetch(const struct Options* options) +---- + + + +Checks whether the option for prefetching was explicitly set for this ``TypeDBOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_options_has_prefetch_size] +==== options_has_prefetch_size + +[source,cpp] +---- +bool options_has_prefetch_size(const struct Options* options) +---- + + + +Checks whether the option for prefetch size was explicitly set for this ``TypeDBOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_options_has_read_any_replica] +==== options_has_read_any_replica + +[source,cpp] +---- +bool options_has_read_any_replica(const struct Options* options) +---- + + + +Checks whether the option for reading data from any replica was explicitly set for this ``TypeDBOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_options_has_schema_lock_acquire_timeout_millis] +==== options_has_schema_lock_acquire_timeout_millis + +[source,cpp] +---- +bool options_has_schema_lock_acquire_timeout_millis(const struct Options* options) +---- + + + +Checks whether the option for schema lock acquire timeout was explicitly set for this ``TypeDBOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_options_has_session_idle_timeout_millis] +==== options_has_session_idle_timeout_millis + +[source,cpp] +---- +bool options_has_session_idle_timeout_millis(const struct Options* options) +---- + + + +Checks whether the option for the session idle timeout was explicitly set for this ``TypeDBOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_options_has_trace_inference] +==== options_has_trace_inference + +[source,cpp] +---- +bool options_has_trace_inference(const struct Options* options) +---- + + + +Checks whether the option for reasoning tracing was explicitly set for this ``TypeDBOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_options_has_transaction_timeout_millis] +==== options_has_transaction_timeout_millis + +[source,cpp] +---- +bool options_has_transaction_timeout_millis(const struct Options* options) +---- + + + +Checks whether the option for transaction timeout was explicitly set for this ``TypeDBOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_options_new] +==== options_new + +[source,cpp] +---- +struct Options* options_new(void) +---- + + + +Produces a new ``TypeDBOptions`` object. + +[caption=""] +.Returns +`struct Options*` + +[#_options_set_explain] +==== options_set_explain + +[source,cpp] +---- +void options_set_explain(struct Options* options, bool explain) +---- + + + +Explicitly enables or disables explanations. If set to ``true``, enables explanations for queries. Only affects read transactions. + +[caption=""] +.Returns +`void` + +[#_options_set_infer] +==== options_set_infer + +[source,cpp] +---- +void options_set_infer(struct Options* options, bool infer) +---- + + + +Explicitly enables or disables inference. Only settable at transaction level and above. Only affects read transactions. + +[caption=""] +.Returns +`void` + +[#_options_set_parallel] +==== options_set_parallel + +[source,cpp] +---- +void options_set_parallel(struct Options* options, bool parallel) +---- + + + +Explicitly enables or disables parallel execution. If set to ``true``, the server uses parallel instead of single-threaded execution. + +[caption=""] +.Returns +`void` + +[#_options_set_prefetch] +==== options_set_prefetch + +[source,cpp] +---- +void options_set_prefetch(struct Options* options, bool prefetch) +---- + + + +Explicitly enables or disables prefetching. If set to ``true``, the first batch of answers is streamed to the driver even without an explicit request for it. + +[caption=""] +.Returns +`void` + +[#_options_set_prefetch_size] +==== options_set_prefetch_size + +[source,cpp] +---- +void options_set_prefetch_size(struct Options* options, int32_t prefetch_size) +---- + + + +Explicitly sets a prefetch size. If set, specifies a guideline number of answers that the server should send before the driver issues a fresh request. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `prefetchSize` a| Number of answers that the server should send before the driver issues a fresh request a| +|=== + +[caption=""] +.Returns +`void` + +[#_options_set_read_any_replica] +==== options_set_read_any_replica + +[source,cpp] +---- +void options_set_read_any_replica(struct Options* options, bool read_any_replica) +---- + + + +Explicitly enables or disables reading data from any replica. If set to ``True``, enables reading data from any replica, potentially boosting read throughput. Only settable in TypeDB Cloud. + +[caption=""] +.Returns +`void` + +[#_options_set_schema_lock_acquire_timeout_millis] +==== options_set_schema_lock_acquire_timeout_millis + +[source,cpp] +---- +void options_set_schema_lock_acquire_timeout_millis(struct Options* options, int64_t timeout_millis) +---- + + + +Explicitly sets schema lock acquire timeout. If set, specifies how long the driver should wait if opening a session or transaction is blocked by a schema write lock. + +[caption=""] +.Returns +`void` + +[#_options_set_session_idle_timeout_millis] +==== options_set_session_idle_timeout_millis + +[source,cpp] +---- +void options_set_session_idle_timeout_millis(struct Options* options, int64_t timeout_millis) +---- + + + +Explicitly sets a session idle timeout. If set, specifies a timeout that allows the server to close sessions if the driver terminates or becomes unresponsive. + +[caption=""] +.Returns +`void` + +[#_options_set_trace_inference] +==== options_set_trace_inference + +[source,cpp] +---- +void options_set_trace_inference(struct Options* options, bool trace_inference) +---- + + + +Explicitly enables or disables reasoning tracing. If set to ``true``, reasoning tracing graphs are output in the logging directory. Should be used with ``parallel = False``. + +[caption=""] +.Returns +`void` + +[#_options_set_transaction_timeout_millis] +==== options_set_transaction_timeout_millis + +[source,cpp] +---- +void options_set_transaction_timeout_millis(struct Options* options, int64_t timeout_millis) +---- + + + +Explicitly sets a transaction timeout. If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. + +[caption=""] +.Returns +`void` + diff --git a/docs/modules/ROOT/partials/cpp/connection/Database.adoc b/docs/modules/ROOT/partials/cpp/connection/Database.adoc index f38fcec906..e6427f9124 100644 --- a/docs/modules/ROOT/partials/cpp/connection/Database.adoc +++ b/docs/modules/ROOT/partials/cpp/connection/Database.adoc @@ -106,7 +106,7 @@ ReplicaInfoIterable TypeDB::Database::replicas() -Set of ``Replica`` instances for this database. Only works in TypeDB Cloud +Set of ``ServerReplica`` instances for this database. Only works in TypeDB Cloud [caption=""] diff --git a/docs/modules/ROOT/partials/cpp/session/Options.adoc b/docs/modules/ROOT/partials/cpp/session/Options.adoc index 0109dd1023..de8d35c991 100644 --- a/docs/modules/ROOT/partials/cpp/session/Options.adoc +++ b/docs/modules/ROOT/partials/cpp/session/Options.adoc @@ -581,7 +581,7 @@ Options& TypeDB::Options::transactionTimeoutMillis(int64_t timeoutMillis) -Explicitly set a transaction timeout. If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. +Explicitly sets a transaction timeout. If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. [caption=""] diff --git a/docs/modules/ROOT/partials/csharp/connection/IDatabase.adoc b/docs/modules/ROOT/partials/csharp/connection/IDatabase.adoc index aa892a4f30..1cb591aa88 100644 --- a/docs/modules/ROOT/partials/csharp/connection/IDatabase.adoc +++ b/docs/modules/ROOT/partials/csharp/connection/IDatabase.adoc @@ -38,7 +38,7 @@ ISet< IReplica > GetReplicas() -Set of ``Replica`` instances for this database. Only works in TypeDB Cloud +Set of ``ServerReplica`` instances for this database. Only works in TypeDB Cloud [caption=""] diff --git a/docs/modules/ROOT/partials/csharp/session/TypeDBOptions.adoc b/docs/modules/ROOT/partials/csharp/session/TypeDBOptions.adoc index e2f4c3e88b..324367fe59 100644 --- a/docs/modules/ROOT/partials/csharp/session/TypeDBOptions.adoc +++ b/docs/modules/ROOT/partials/csharp/session/TypeDBOptions.adoc @@ -555,7 +555,7 @@ TypeDBOptions TransactionTimeoutMillis(int transactionTimeoutMillis) -Explicitly set a transaction timeout. If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. +Explicitly sets a transaction timeout. If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. [caption=""] diff --git a/docs/modules/ROOT/partials/http-ts/connection/Server.adoc b/docs/modules/ROOT/partials/http-ts/connection/Server.adoc new file mode 100644 index 0000000000..065417054a --- /dev/null +++ b/docs/modules/ROOT/partials/http-ts/connection/Server.adoc @@ -0,0 +1,16 @@ +[#_Server] +=== Server + +[caption=""] +.Fields +// tag::properties[] +[cols=",,"] +[options="header"] +|=== +|Name |Type |Description +a| `address` a| `string` a| +a| `isPrimary` a| `boolean` a| +a| `term` a| `number` a| +|=== +// end::properties[] + diff --git a/docs/modules/ROOT/partials/http-ts/connection/TypeDBHttpDriver.adoc b/docs/modules/ROOT/partials/http-ts/connection/TypeDBHttpDriver.adoc index df01244b22..4bd0c741c0 100644 --- a/docs/modules/ROOT/partials/http-ts/connection/TypeDBHttpDriver.adoc +++ b/docs/modules/ROOT/partials/http-ts/connection/TypeDBHttpDriver.adoc @@ -289,6 +289,20 @@ getDatabases(): Promise> .Returns `Promise>` +[#_TypeDBHttpDriver_getServers_] +==== getServers + +[source,typescript] +---- +getServers(): Promise> +---- + + + +[caption=""] +.Returns +`Promise>` + [#_TypeDBHttpDriver_getUser_username_string] ==== method ``getUser`` diff --git a/docs/modules/ROOT/partials/http-ts/response/ServersListResponse.adoc b/docs/modules/ROOT/partials/http-ts/response/ServersListResponse.adoc new file mode 100644 index 0000000000..f5d4d8831b --- /dev/null +++ b/docs/modules/ROOT/partials/http-ts/response/ServersListResponse.adoc @@ -0,0 +1,14 @@ +[#_ServersListResponse] +=== ServersListResponse + +[caption=""] +.Fields +// tag::properties[] +[cols=",,"] +[options="header"] +|=== +|Name |Type |Description +a| `servers` a| `Server` a| +|=== +// end::properties[] + diff --git a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Eventual.adoc b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Eventual.adoc new file mode 100644 index 0000000000..652c20cd14 --- /dev/null +++ b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Eventual.adoc @@ -0,0 +1,80 @@ +[#_ConsistencyLevel_Eventual] +=== ConsistencyLevel.Eventual + +*Package*: `com.typedb.driver.api` + +Eventual consistency level. Allow stale reads from any replica and execution orchestration through a non-primary replica. Does not guarantee latest writes, but is eventually faster compared to other consistency levels. Note that the target replica can redirect the request, if needed. + +// tag::methods[] +[#_ConsistencyLevel_Eventual_Eventual_] +==== Eventual + +[source,java] +---- +public Eventual() +---- + + + +[caption=""] +.Returns +`public` + +[#_ConsistencyLevel_Eventual_nativeValue_] +==== nativeValue + +[source,java] +---- +public com.typedb.driver.jni.ConsistencyLevel nativeValue() +---- + + + +[caption=""] +.Returns +`public com.typedb.driver.jni.ConsistencyLevel` + +[#_ConsistencyLevel_Eventual_nativeValue_ConsistencyLevel] +==== nativeValue + +[source,java] +---- +public static com.typedb.driver.jni.ConsistencyLevel nativeValue​(ConsistencyLevel consistencyLevel) +---- + + + +[caption=""] +.Returns +`public static com.typedb.driver.jni.ConsistencyLevel` + +[#_ConsistencyLevel_Eventual_of_com_typedb_driver_jni_ConsistencyLevel] +==== of + +[source,java] +---- +public static ConsistencyLevel of​(com.typedb.driver.jni.ConsistencyLevel nativeValue) +---- + + + +[caption=""] +.Returns +`public static ConsistencyLevel` + +[#_ConsistencyLevel_Eventual_toString_] +==== toString + +[source,java] +---- +public java.lang.String toString() +---- + + + +[caption=""] +.Returns +`public java.lang.String` + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.ReplicaDependent.adoc b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.ReplicaDependent.adoc new file mode 100644 index 0000000000..06b76e32ac --- /dev/null +++ b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.ReplicaDependent.adoc @@ -0,0 +1,94 @@ +[#_ConsistencyLevel_ReplicaDependent] +=== ConsistencyLevel.ReplicaDependent + +*Package*: `com.typedb.driver.api` + +Replica dependent consistency level. The operation is executed against the provided replica address only. Its guarantees depend on the replica selected. Note that the target replica can redirect the request, if needed. + +// tag::methods[] +[#_ConsistencyLevel_ReplicaDependent_ReplicaDependent_java_lang_String] +==== ReplicaDependent + +[source,java] +---- +public ReplicaDependent​(java.lang.String address) +---- + + + +[caption=""] +.Returns +`public` + +[#_ConsistencyLevel_ReplicaDependent_getAddress_] +==== getAddress + +[source,java] +---- +public java.lang.String getAddress() +---- + +Retrieves the address of the replica this consistency level depends on. + +[caption=""] +.Returns +`public java.lang.String` + +[#_ConsistencyLevel_ReplicaDependent_nativeValue_] +==== nativeValue + +[source,java] +---- +public com.typedb.driver.jni.ConsistencyLevel nativeValue() +---- + + + +[caption=""] +.Returns +`public com.typedb.driver.jni.ConsistencyLevel` + +[#_ConsistencyLevel_ReplicaDependent_nativeValue_ConsistencyLevel] +==== nativeValue + +[source,java] +---- +public static com.typedb.driver.jni.ConsistencyLevel nativeValue​(ConsistencyLevel consistencyLevel) +---- + + + +[caption=""] +.Returns +`public static com.typedb.driver.jni.ConsistencyLevel` + +[#_ConsistencyLevel_ReplicaDependent_of_com_typedb_driver_jni_ConsistencyLevel] +==== of + +[source,java] +---- +public static ConsistencyLevel of​(com.typedb.driver.jni.ConsistencyLevel nativeValue) +---- + + + +[caption=""] +.Returns +`public static ConsistencyLevel` + +[#_ConsistencyLevel_ReplicaDependent_toString_] +==== toString + +[source,java] +---- +public java.lang.String toString() +---- + + + +[caption=""] +.Returns +`public java.lang.String` + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Strong.adoc b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Strong.adoc new file mode 100644 index 0000000000..9d0e9dfa4b --- /dev/null +++ b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Strong.adoc @@ -0,0 +1,80 @@ +[#_ConsistencyLevel_Strong] +=== ConsistencyLevel.Strong + +*Package*: `com.typedb.driver.api` + +Strong consistency level. Strongest consistency, always up-to-date due to the guarantee of the primary replica usage. May require more time for operation execution. + +// tag::methods[] +[#_ConsistencyLevel_Strong_Strong_] +==== Strong + +[source,java] +---- +public Strong() +---- + + + +[caption=""] +.Returns +`public` + +[#_ConsistencyLevel_Strong_nativeValue_] +==== nativeValue + +[source,java] +---- +public com.typedb.driver.jni.ConsistencyLevel nativeValue() +---- + + + +[caption=""] +.Returns +`public com.typedb.driver.jni.ConsistencyLevel` + +[#_ConsistencyLevel_Strong_nativeValue_ConsistencyLevel] +==== nativeValue + +[source,java] +---- +public static com.typedb.driver.jni.ConsistencyLevel nativeValue​(ConsistencyLevel consistencyLevel) +---- + + + +[caption=""] +.Returns +`public static com.typedb.driver.jni.ConsistencyLevel` + +[#_ConsistencyLevel_Strong_of_com_typedb_driver_jni_ConsistencyLevel] +==== of + +[source,java] +---- +public static ConsistencyLevel of​(com.typedb.driver.jni.ConsistencyLevel nativeValue) +---- + + + +[caption=""] +.Returns +`public static ConsistencyLevel` + +[#_ConsistencyLevel_Strong_toString_] +==== toString + +[source,java] +---- +public java.lang.String toString() +---- + + + +[caption=""] +.Returns +`public java.lang.String` + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.adoc b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.adoc new file mode 100644 index 0000000000..acb4c4c788 --- /dev/null +++ b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.adoc @@ -0,0 +1,66 @@ +[#_ConsistencyLevel] +=== ConsistencyLevel + +*Package*: `com.typedb.driver.api` + +Consistency levels of operations against a distributed server. All driver methods have default recommended values, however, most of the operations can be configured in order to potentially speed up the execution (introducing risks of stale data) or test a specific replica. This setting does not affect clusters with a single node. + +// tag::methods[] +[#_ConsistencyLevel_ConsistencyLevel_] +==== ConsistencyLevel + +[source,java] +---- +public ConsistencyLevel() +---- + + + +[caption=""] +.Returns +`public` + +[#_ConsistencyLevel_nativeValue_] +==== nativeValue + +[source,java] +---- +public abstract com.typedb.driver.jni.ConsistencyLevel nativeValue() +---- + + + +[caption=""] +.Returns +`public abstract com.typedb.driver.jni.ConsistencyLevel` + +[#_ConsistencyLevel_nativeValue_ConsistencyLevel] +==== nativeValue + +[source,java] +---- +public static com.typedb.driver.jni.ConsistencyLevel nativeValue​(ConsistencyLevel consistencyLevel) +---- + + + +[caption=""] +.Returns +`public static com.typedb.driver.jni.ConsistencyLevel` + +[#_ConsistencyLevel_of_com_typedb_driver_jni_ConsistencyLevel] +==== of + +[source,java] +---- +public static ConsistencyLevel of​(com.typedb.driver.jni.ConsistencyLevel nativeValue) +---- + + + +[caption=""] +.Returns +`public static ConsistencyLevel` + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/java/connection/Database.adoc b/docs/modules/ROOT/partials/java/connection/Database.adoc index d7f2dcf957..9c0202f746 100644 --- a/docs/modules/ROOT/partials/java/connection/Database.adoc +++ b/docs/modules/ROOT/partials/java/connection/Database.adoc @@ -12,13 +12,45 @@ [source,java] ---- -void delete() +default void delete() + throws TypeDBDriverException +---- + +Deletes this database, using default strong consistency. See <<#_delete_com_typedb_driver_api_ConsistencyLevel,``delete(ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Returns +`void` + +[caption=""] +.Code examples +[source,java] +---- +database.delete() +---- + +[#_Database_delete_ConsistencyLevel] +==== delete + +[source,java] +---- +void delete​(ConsistencyLevel consistencyLevel) throws TypeDBDriverException ---- Deletes this database. +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + [caption=""] .Returns `void` @@ -27,16 +59,51 @@ Deletes this database. .Code examples [source,java] ---- -database.delete() +database.delete(new ConsistencyLevel.Strong()) ---- [#_Database_exportToFile_java_lang_String_java_lang_String] ==== method ``exportToFile`` +[source,java] +---- +default void exportToFile​(java.lang.String schemaFilePath, + java.lang.String dataFilePath) + throws TypeDBDriverException +---- + +Export a database into a schema definition and a data files saved to the disk, using default strong consistency. This is a blocking operation and may take a significant amount of time depending on the database size. See <<#_exportToFile_java_lang_String_java_lang_String_com_typedb_driver_api_ConsistencyLevel,``exportToFile(String, String, ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `schemaFilePath` a| The path to the schema definition file to be created a| `java.lang.String` +a| `dataFilePath` a| The path to the data file to be created a| `java.lang.String` +|=== + +[caption=""] +.Returns +`void` + +[caption=""] +.Code examples +[source,java] +---- +database.exportToFile("schema.typeql", "data.typedb") +---- + +[#_Database_exportToFile_java_lang_String_java_lang_String_ConsistencyLevel] +==== exportToFile + [source,java] ---- void exportToFile​(java.lang.String schemaFilePath, - java.lang.String dataFilePath) + java.lang.String dataFilePath, + ConsistencyLevel consistencyLevel) throws TypeDBDriverException ---- @@ -51,6 +118,7 @@ Export a database into a schema definition and a data files saved to the disk. T |Name |Description |Type a| `schemaFilePath` a| The path to the schema definition file to be created a| `java.lang.String` a| `dataFilePath` a| The path to the data file to be created a| `java.lang.String` +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` |=== [caption=""] @@ -61,7 +129,7 @@ a| `dataFilePath` a| The path to the data file to be created a| `java.lang.Strin .Code examples [source,java] ---- -database.exportToFile("schema.typeql", "data.typedb") +database.exportToFile("schema.typeql", "data.typedb", new ConsistencyLevel.Strong()) ---- [#_Database_name_] @@ -73,25 +141,66 @@ database.exportToFile("schema.typeql", "data.typedb") java.lang.String name() ---- -The database name as a string. +The database name as a string. + [caption=""] .Returns `java.lang.String` +[caption=""] +.Code examples +[source,java] +---- +database.name() +---- + [#_Database_schema_] ==== method ``schema`` [source,java] ---- @CheckReturnValue -java.lang.String schema() +default java.lang.String schema() + throws TypeDBDriverException +---- + +A full schema text as a valid TypeQL define query string, using default strong consistency. See <<#_schema_com_typedb_driver_api_ConsistencyLevel,``schema(ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Returns +`java.lang.String` + +[caption=""] +.Code examples +[source,java] +---- +database.schema() +---- + +[#_Database_schema_ConsistencyLevel] +==== schema + +[source,java] +---- +@CheckReturnValue +java.lang.String schema​(ConsistencyLevel consistencyLevel) throws TypeDBDriverException ---- A full schema text as a valid TypeQL define query string. +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + [caption=""] .Returns `java.lang.String` @@ -100,7 +209,7 @@ A full schema text as a valid TypeQL define query string. .Code examples [source,java] ---- -database.schema() +database.schema(new ConsistencyLevel.Strong()) ---- [#_Database_typeSchema_] @@ -109,13 +218,46 @@ database.schema() [source,java] ---- @CheckReturnValue -java.lang.String typeSchema() +default java.lang.String typeSchema() + throws TypeDBDriverException +---- + +The types in the schema as a valid TypeQL define query string, using default strong consistency. See <<#_typeSchema_com_typedb_driver_api_ConsistencyLevel,``typeSchema(ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Returns +`java.lang.String` + +[caption=""] +.Code examples +[source,java] +---- +database.typeSchema() +---- + +[#_Database_typeSchema_ConsistencyLevel] +==== typeSchema + +[source,java] +---- +@CheckReturnValue +java.lang.String typeSchema​(ConsistencyLevel consistencyLevel) throws TypeDBDriverException ---- The types in the schema as a valid TypeQL define query string. +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + [caption=""] .Returns `java.lang.String` @@ -124,7 +266,7 @@ The types in the schema as a valid TypeQL define query string. .Code examples [source,java] ---- -database.typeSchema() +database.typeSchema(new ConsistencyLevel.Strong()) ---- // end::methods[] diff --git a/docs/modules/ROOT/partials/java/connection/DatabaseManager.adoc b/docs/modules/ROOT/partials/java/connection/DatabaseManager.adoc index d4ba6f7ca8..d447871da8 100644 --- a/docs/modules/ROOT/partials/java/connection/DatabaseManager.adoc +++ b/docs/modules/ROOT/partials/java/connection/DatabaseManager.adoc @@ -15,13 +15,46 @@ Provides access to all database management methods. [source,java] ---- @CheckReturnValue -java.util.List all() +default java.util.List all() + throws TypeDBDriverException +---- + +Retrieves all databases present on the TypeDB server, using default strong consistency. See <<#_all_com_typedb_driver_api_ConsistencyLevel,``all(ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Returns +`java.util.List` + +[caption=""] +.Code examples +[source,java] +---- +driver.databases().all() +---- + +[#_DatabaseManager_all_ConsistencyLevel] +==== all + +[source,java] +---- +@CheckReturnValue +java.util.List all​(ConsistencyLevel consistencyLevel) throws TypeDBDriverException ---- Retrieves all databases present on the TypeDB server. +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + [caption=""] .Returns `java.util.List` @@ -30,7 +63,7 @@ Retrieves all databases present on the TypeDB server. .Code examples [source,java] ---- -driver.databases().all() +driver.databases().all(new ConsistencyLevel.Strong()) ---- [#_DatabaseManager_contains_java_lang_String] @@ -39,7 +72,41 @@ driver.databases().all() [source,java] ---- @CheckReturnValue -boolean contains​(java.lang.String name) +default boolean contains​(java.lang.String name) + throws TypeDBDriverException +---- + +Checks if a database with the given name exists, using default strong consistency. See <<#_contains_java_lang_String_com_typedb_driver_api_ConsistencyLevel,``contains(String, ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `name` a| The database name to be checked a| `java.lang.String` +|=== + +[caption=""] +.Returns +`boolean` + +[caption=""] +.Code examples +[source,java] +---- +driver.databases().contains(name) +---- + +[#_DatabaseManager_contains_java_lang_String_ConsistencyLevel] +==== contains + +[source,java] +---- +@CheckReturnValue +boolean contains​(java.lang.String name, + ConsistencyLevel consistencyLevel) throws TypeDBDriverException ---- @@ -53,6 +120,7 @@ Checks if a database with the given name exists. |=== |Name |Description |Type a| `name` a| The database name to be checked a| `java.lang.String` +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` |=== [caption=""] @@ -63,7 +131,7 @@ a| `name` a| The database name to be checked a| `java.lang.String` .Code examples [source,java] ---- -driver.databases().contains(name) +driver.databases().contains(name, new ConsistencyLevel.Strong()) ---- [#_DatabaseManager_create_java_lang_String] @@ -71,11 +139,11 @@ driver.databases().contains(name) [source,java] ---- -void create​(java.lang.String name) - throws TypeDBDriverException +default void create​(java.lang.String name) + throws TypeDBDriverException ---- -Create a database with the given name. +Creates a database with the given name, using default strong consistency. See <<#_create_java_lang_String_com_typedb_driver_api_ConsistencyLevel,``create(String, ConsistencyLevel)``>> for more details and options. [caption=""] @@ -98,17 +166,51 @@ a| `name` a| The name of the database to be created a| `java.lang.String` driver.databases().create(name) ---- +[#_DatabaseManager_create_java_lang_String_ConsistencyLevel] +==== create + +[source,java] +---- +void create​(java.lang.String name, + ConsistencyLevel consistencyLevel) + throws TypeDBDriverException +---- + +Creates a database with the given name. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `name` a| The name of the database to be created a| `java.lang.String` +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +`void` + +[caption=""] +.Code examples +[source,java] +---- +driver.databases().create(name, new ConsistencyLevel.Strong()) +---- + [#_DatabaseManager_get_java_lang_String] ==== method ``get`` [source,java] ---- @CheckReturnValue -Database get​(java.lang.String name) - throws TypeDBDriverException +default Database get​(java.lang.String name) + throws TypeDBDriverException ---- -Retrieve the database with the given name. +Retrieves the database with the given name, using default strong consistency. See <<#_get_java_lang_String_com_typedb_driver_api_ConsistencyLevel,``get(String, ConsistencyLevel)``>> for more details and options. [caption=""] @@ -131,6 +233,41 @@ a| `name` a| The name of the database to retrieve a| `java.lang.String` driver.databases().get(name) ---- +[#_DatabaseManager_get_java_lang_String_ConsistencyLevel] +==== get + +[source,java] +---- +@CheckReturnValue +Database get​(java.lang.String name, + ConsistencyLevel consistencyLevel) + throws TypeDBDriverException +---- + +Retrieves the database with the given name. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `name` a| The name of the database to retrieve a| `java.lang.String` +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +`Database` + +[caption=""] +.Code examples +[source,java] +---- +driver.databases().get(name, new ConsistencyLevel.Strong()) +---- + [#_DatabaseManager_importFromFile_java_lang_String_java_lang_String_java_lang_String] ==== method ``importFromFile`` @@ -142,7 +279,7 @@ void importFromFile​(java.lang.String name, throws TypeDBDriverException ---- -Create a database with the given name based on previously exported another database's data loaded from a file. This is a blocking operation and may take a significant amount of time depending on the database size. +Creates a database with the given name based on previously exported another database's data loaded from a file. This is a blocking operation and may take a significant amount of time depending on the database size. [caption=""] diff --git a/docs/modules/ROOT/partials/java/connection/Driver.adoc b/docs/modules/ROOT/partials/java/connection/Driver.adoc index a029ad584d..b07b956411 100644 --- a/docs/modules/ROOT/partials/java/connection/Driver.adoc +++ b/docs/modules/ROOT/partials/java/connection/Driver.adoc @@ -41,7 +41,7 @@ Closes the driver. Before instantiating a new driver, the driver that’s curren .Code examples [source,java] ---- -driver.close() +driver.close(); ---- [#_Driver_databases_] @@ -53,12 +53,51 @@ driver.close() DatabaseManager databases() ---- -The ``DatabaseManager`` for this connection, providing access to database management methods. +The ``DatabaseManager`` for this connection, providing access to database management methods. + [caption=""] .Returns `DatabaseManager` +[caption=""] +.Code examples +[source,java] +---- +driver.databases(); +---- + +[#_Driver_deregisterReplica_long] +==== deregisterReplica + +[source,java] +---- +void deregisterReplica​(long replicaID) +---- + +Deregisters a replica from the cluster the driver is currently connected to. This replica will no longer play a raft role in this cluster. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `replicaID` a| The numeric identifier of the deregistered replica a| `long` +|=== + +[caption=""] +.Returns +`void` + +[caption=""] +.Code examples +[source,java] +---- +driver.deregisterReplica(2); +---- + [#_Driver_isOpen_] ==== method ``isOpen`` @@ -82,6 +121,204 @@ Checks whether this connection is presently open. driver.isOpen(); ---- +[#_Driver_primaryReplica_] +==== primaryReplica + +[source,java] +---- +@CheckReturnValue +default java.util.Optional primaryReplica() +---- + +Returns the primary replica for this driver connection, using default strong consistency. See <<#_primaryReplica_com_typedb_driver_api_ConsistencyLevel,``primaryReplica(ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Returns +`java.util.Optional` + +[caption=""] +.Code examples +[source,java] +---- +driver.primaryReplica(); +---- + +[#_Driver_primaryReplica_ConsistencyLevel] +==== primaryReplica + +[source,java] +---- +@CheckReturnValue +java.util.Optional primaryReplica​(ConsistencyLevel consistencyLevel) +---- + +Returns the primary replica for this driver connection. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +`java.util.Optional` + +[caption=""] +.Code examples +[source,java] +---- +driver.primaryReplica(new ConsistencyLevel.Strong()); +---- + +[#_Driver_registerReplica_long_java_lang_String] +==== registerReplica + +[source,java] +---- +void registerReplica​(long replicaID, + java.lang.String address) +---- + +Registers a new replica in the cluster the driver is currently connected to. The registered replica will become available eventually, depending on the behavior of the whole cluster. To register a replica, its clustering address should be passed, not the connection address. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `replicaID` a| The numeric identifier of the new replica a| `long` +a| `address` a| The address(es) of the TypeDB replica as a string a| `java.lang.String` +|=== + +[caption=""] +.Returns +`void` + +[caption=""] +.Code examples +[source,java] +---- +driver.registerReplica(2, "127.0.0.1:11729"); +---- + +[#_Driver_replicas_] +==== replicas + +[source,java] +---- +@CheckReturnValue +default java.util.Set replicas() +---- + +Set of ``Replica`` instances for this driver connection, using default strong consistency. See <<#_replicas_com_typedb_driver_api_ConsistencyLevel,``replicas(ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Returns +`java.util.Set` + +[caption=""] +.Code examples +[source,java] +---- +driver.replicas(); +---- + +[#_Driver_replicas_ConsistencyLevel] +==== replicas + +[source,java] +---- +@CheckReturnValue +java.util.Set replicas​(ConsistencyLevel consistencyLevel) +---- + +Set of ``Replica`` instances for this driver connection. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +`java.util.Set` + +[caption=""] +.Code examples +[source,java] +---- +driver.replicas(new ConsistencyLevel.Strong()); +---- + +[#_Driver_serverVersion_] +==== serverVersion + +[source,java] +---- +@CheckReturnValue +default ServerVersion serverVersion() +---- + +Retrieves the server's version, using default strong consistency. See <<#_serverVersion_com_typedb_driver_api_ConsistencyLevel,``serverVersion(ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Returns +`ServerVersion` + +[caption=""] +.Code examples +[source,java] +---- +driver.serverVersion(); +---- + +[#_Driver_serverVersion_ConsistencyLevel] +==== serverVersion + +[source,java] +---- +@CheckReturnValue +ServerVersion serverVersion​(ConsistencyLevel consistencyLevel) +---- + +Retrieves the server's version. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +`ServerVersion` + +[caption=""] +.Code examples +[source,java] +---- +driver.serverVersion(); +---- + [#_Driver_transaction_java_lang_String_Transaction_Type] ==== method ``transaction`` @@ -153,6 +390,37 @@ a| `options` a| ``TransactionOptions`` to configure the opened transaction a| `T driver.transaction(database, sessionType); ---- +[#_Driver_updateAddressTranslation_java_util_Map_java_lang_String_​java_lang_String_] +==== updateAddressTranslation + +[source,java] +---- +void updateAddressTranslation​(java.util.Map addressTranslation) +---- + +Updates address translation of the driver. This lets you actualize new translation information without recreating the driver from scratch. Useful after registering new replicas requiring address translation. This operation will update existing connections using the provided addresses. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `addressTranslation` a| The translation of public TypeDB cluster replica addresses (keys) to server-side private addresses (values) a| `java.util.Map` +|=== + +[caption=""] +.Returns +`void` + +[caption=""] +.Code examples +[source,java] +---- +driver.updateAddressTranslation(2); +---- + [#_Driver_users_] ==== method ``users`` @@ -162,7 +430,7 @@ driver.transaction(database, sessionType); UserManager users() ---- -The ``UserManager`` instance for this connection, providing access to user management methods. +The ``UserManager`` for this connection, providing access to user management methods. [caption=""] diff --git a/docs/modules/ROOT/partials/java/connection/DriverOptions.adoc b/docs/modules/ROOT/partials/java/connection/DriverOptions.adoc index 593dc66f72..ffb115545d 100644 --- a/docs/modules/ROOT/partials/java/connection/DriverOptions.adoc +++ b/docs/modules/ROOT/partials/java/connection/DriverOptions.adoc @@ -1,31 +1,65 @@ [#_DriverOptions] -[.doc-api-reference-driver] === DriverOptions -`class` - *Package*: `com.typedb.driver.api` -User connection settings (TLS encryption, etc.) for connecting to TypeDB Server. +TypeDB driver options. ``DriverOptions`` are used to specify the driver's connection behavior. + +// tag::methods[] +[#_DriverOptions_DriverOptions_DriverTlsConfig] +==== DriverOptions + +[source,java] +---- +public DriverOptions​(DriverTlsConfig tlsConfig) +---- + +Produces a new ``DriverOptions`` object for connecting to TypeDB Server using custom TLS settings. WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + +[caption=""] +.Returns +`public` [caption=""] -.Examples +.Code examples [source,java] ---- -DriverOptions driverOptions = new DriverOptions(true, Path.of("path/to/ca-certificate.pem")); +DriverOptions options = new DriverOptions(DriverTlsConfig.enabledWithNativeRootCA()); ---- -// tag::methods[] -[#_DriverOptions_DriverOptions_boolean_java_lang_String] -==== method ``DriverOptions`` +[#_DriverOptions_primaryFailoverRetries_] +==== primaryFailoverRetries [source,java] ---- -public DriverOptions​(boolean isTlsEnabled, - java.lang.String tlsRootCAPath) +@CheckReturnValue +public java.lang.Integer primaryFailoverRetries() ---- +Returns the value set for the primary failover retries limit in this ``DriverOptions`` object. Limits the number of attempts to redirect a strongly consistent request to another primary replica in case of a failure due to the change of replica roles. + + +[caption=""] +.Returns +`public java.lang.Integer` + +[caption=""] +.Code examples +[source,java] +---- +options.primaryFailoverRetries(); +---- + +[#_DriverOptions_primaryFailoverRetries_int] +==== primaryFailoverRetries + +[source,java] +---- +public DriverOptions primaryFailoverRetries​(int primaryFailoverRetries) +---- + +Explicitly sets the limit on the number of attempts to redirect a strongly consistent request to another primary replica in case of a failure due to the change of replica roles. Defaults to 1. [caption=""] @@ -34,13 +68,226 @@ public DriverOptions​(boolean isTlsEnabled, [options="header"] |=== |Name |Description |Type -a| `isTlsEnabled` a| Specify whether the connection to TypeDB Server must be done over TLS. a| `boolean` -a| `tlsRootCAPath` a| Path to the CA certificate to use for authenticating server certificates. a| `java.lang.String` +a| `primaryFailoverRetries` a| The limit of primary failover retries. a| `int` |=== [caption=""] .Returns -`public` +`public DriverOptions` + +[caption=""] +.Code examples +[source,java] +---- +options.primaryFailoverRetries(1); +---- + +[#_DriverOptions_replicaDiscoveryAttempts_] +==== replicaDiscoveryAttempts + +[source,java] +---- +@CheckReturnValue +public java.util.Optional replicaDiscoveryAttempts() +---- + +Returns the value set for the replica discovery attempts limit in this ``DriverOptions`` object. Limits the number of driver attempts to discover a single working replica to perform an operation in case of a replica unavailability. Every replica is tested once, which means that at most: - {limit} operations are performed if the limit <= the number of replicas. - {number of replicas} operations are performed if the limit > the number of replicas. - {number of replicas} operations are performed if the limit is None. Affects every eventually consistent operation, including redirect failover, when the new primary replica is unknown. + + +[caption=""] +.Returns +`public java.util.Optional` + +[caption=""] +.Code examples +[source,java] +---- +options.replicaDiscoveryAttempts(); +---- + +[#_DriverOptions_replicaDiscoveryAttempts_int] +==== replicaDiscoveryAttempts + +[source,java] +---- +public DriverOptions replicaDiscoveryAttempts​(int replicaDiscoveryAttempts) +---- + +Limits the number of driver attempts to discover a single working replica to perform an operation in case of a replica unavailability. Every replica is tested once, which means that at most: - {limit} operations are performed if the limit <= the number of replicas. - {number of replicas} operations are performed if the limit > the number of replicas. - {number of replicas} operations are performed if the limit is None. Affects every eventually consistent operation, including redirect failover, when the new primary replica is unknown. If not set, the maximum (practically unlimited) value is used. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `replicaDiscoveryAttempts` a| The limit of replica discovery attempts. a| `int` +|=== + +[caption=""] +.Returns +`public DriverOptions` + +[caption=""] +.Code examples +[source,java] +---- +options.primaryFailoverRetries(1); +---- + +[#_DriverOptions_requestTimeoutMillis_] +==== requestTimeoutMillis + +[source,java] +---- +@CheckReturnValue +public java.lang.Long requestTimeoutMillis() +---- + +Returns the request timeout in milliseconds set for this ``DriverOptions`` object. Specifies the maximum time to wait for a response to a unary RPC request. This applies to operations like database creation, user management, and initial transaction opening. It does NOT apply to operations within transactions (queries, commits). + + +[caption=""] +.Returns +`public java.lang.Long` + +[caption=""] +.Code examples +[source,java] +---- +options.requestTimeoutMillis(); +---- + +[#_DriverOptions_requestTimeoutMillis_long] +==== requestTimeoutMillis + +[source,java] +---- +public DriverOptions requestTimeoutMillis​(long requestTimeoutMillis) +---- + +Sets the maximum time (in milliseconds) to wait for a response to a unary RPC request. This applies to operations like database creation, user management, and initial transaction opening. It does NOT apply to operations within transactions (queries, commits). Defaults to 2 hours (7200000 milliseconds). + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `requestTimeoutMillis` a| The request timeout in milliseconds. Must be non-negative. a| `long` +|=== + +[caption=""] +.Returns +`public DriverOptions` + +[caption=""] +.Code examples +[source,java] +---- +options.requestTimeoutMillis(30000); // 30 seconds +---- + +[#_DriverOptions_tlsConfig_] +==== tlsConfig + +[source,java] +---- +@CheckReturnValue +public DriverTlsConfig tlsConfig() +---- + +Returns the TLS configuration associated with this ``DriverOptions``. Specifies the TLS configuration of the connection to TypeDB. + + +[caption=""] +.Returns +`public DriverTlsConfig` + +[caption=""] +.Code examples +[source,java] +---- +options.tlsConfig(); +---- + +[#_DriverOptions_tlsConfig_DriverTlsConfig] +==== tlsConfig + +[source,java] +---- +public DriverOptions tlsConfig​(DriverTlsConfig tlsConfig) +---- + +Overrides the TLS configuration associated with this ``DriverOptions``. WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + + +[caption=""] +.Returns +`public DriverOptions` + +[caption=""] +.Code examples +[source,java] +---- +options.tlsConfig(DriverTlsConfig.enabledWithNativeRootCA()); +---- + +[#_DriverOptions_useReplication_] +==== useReplication + +[source,java] +---- +@CheckReturnValue +public java.lang.Boolean useReplication() +---- + +Returns the value set for the replication usage flag in this ``DriverOptions`` object. Specifies whether the connection to TypeDB can use cluster replicas provided by the server or it should be limited to a single configured address. + + +[caption=""] +.Returns +`public java.lang.Boolean` + +[caption=""] +.Code examples +[source,java] +---- +options.useReplication(); +---- + +[#_DriverOptions_useReplication_boolean] +==== useReplication + +[source,java] +---- +public DriverOptions useReplication​(boolean useReplication) +---- + +Explicitly sets whether the connection to TypeDB can use cluster replicas provided by the server or it should be limited to a single configured address. Defaults to true. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `useReplication` a| Whether the connection to TypeDB can use replication. a| `boolean` +|=== + +[caption=""] +.Returns +`public DriverOptions` + +[caption=""] +.Code examples +[source,java] +---- +options.useReplication(true); +---- // end::methods[] diff --git a/docs/modules/ROOT/partials/java/connection/DriverTlsConfig.adoc b/docs/modules/ROOT/partials/java/connection/DriverTlsConfig.adoc new file mode 100644 index 0000000000..6a885f7285 --- /dev/null +++ b/docs/modules/ROOT/partials/java/connection/DriverTlsConfig.adoc @@ -0,0 +1,149 @@ +[#_DriverTlsConfig] +=== DriverTlsConfig + +*Package*: `com.typedb.driver.api` + +TLS configuration for the TypeDB driver. ``DriverTlsConfig`` represents a fully constructed and validated TLS configuration. If TLS is enabled, the underlying TLS config is built eagerly at construction time, ensuring that no connection attempt can observe a partially-configured TLS state. + +The driver defaults to using TLS with native system trust roots. This matches typical system and container deployments while still allowing explicit opt-out or custom PKI configuration. + +// tag::methods[] +[#_DriverTlsConfig_DriverTlsConfig_com_typedb_driver_jni_DriverTlsConfig] +==== DriverTlsConfig + +[source,java] +---- +protected DriverTlsConfig​(com.typedb.driver.jni.DriverTlsConfig nativeObject) +---- + + + +[caption=""] +.Returns +`protected` + +[#_DriverTlsConfig_disabled_] +==== disabled + +[source,java] +---- +@CheckReturnValue +public static DriverTlsConfig disabled() +---- + +Creates a TLS configuration with TLS disabled. WARNING: Disabling TLS causes credentials and data to be transmitted in plaintext. + + +[caption=""] +.Returns +`public static DriverTlsConfig` + +[caption=""] +.Code examples +[source,java] +---- +DriverTlsConfig tlsConfig = DriverTlsConfig.disabled(); +---- + +[#_DriverTlsConfig_enabledWithNativeRootCA_] +==== enabledWithNativeRootCA + +[source,java] +---- +@CheckReturnValue +public static DriverTlsConfig enabledWithNativeRootCA() +---- + +Creates a TLS configuration enabled with system native trust roots. + + +[caption=""] +.Returns +`public static DriverTlsConfig` + +[caption=""] +.Code examples +[source,java] +---- +DriverTlsConfig tlsConfig = DriverTlsConfig.enabledWithNativeRootCA(); +---- + +[#_DriverTlsConfig_enabledWithRootCA_java_lang_String] +==== enabledWithRootCA + +[source,java] +---- +@CheckReturnValue +public static DriverTlsConfig enabledWithRootCA​(java.lang.String tlsRootCAPath) +---- + +Creates a TLS configuration enabled with a custom root CA certificate bundle (PEM). + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `tlsRootCAPath` a| Path to PEM-encoded root CA certificate bundle. +Examples +[source,java] +---- + DriverTlsConfig tlsConfig = DriverTlsConfig.enabledWithRootCA("path/to/ca-certificate.pem"); + +---- + a| `java.lang.String` +|=== + +[caption=""] +.Returns +`public static DriverTlsConfig` + +[#_DriverTlsConfig_isEnabled_] +==== isEnabled + +[source,java] +---- +@CheckReturnValue +public boolean isEnabled() +---- + +Returns whether TLS is enabled. + + +[caption=""] +.Returns +`public boolean` + +[caption=""] +.Code examples +[source,java] +---- +tlsConfig.isEnabled(); +---- + +[#_DriverTlsConfig_rootCAPath_] +==== rootCAPath + +[source,java] +---- +@CheckReturnValue +public java.util.Optional rootCAPath() +---- + +Returns the configured custom root CA path, if present. If TLS is enabled with native roots (or disabled), this will be empty. + + +[caption=""] +.Returns +`public java.util.Optional` + +[caption=""] +.Code examples +[source,java] +---- +tlsConfig.rootCAPath(); +---- + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/java/connection/ReplicaRole.adoc b/docs/modules/ROOT/partials/java/connection/ReplicaRole.adoc new file mode 100644 index 0000000000..b040253dcc --- /dev/null +++ b/docs/modules/ROOT/partials/java/connection/ReplicaRole.adoc @@ -0,0 +1,152 @@ +[#_ReplicaRole] +=== ReplicaRole + +*Package*: `com.typedb.driver.api.server` + +This enum is used to specify the type of replica. + + +[caption=""] +.Examples +[source,java] +---- +replica.getType(); +---- + +[caption=""] +.Enum constants +// tag::enum_constants[] +[cols=""] +[options="header"] +|=== +|Name +a| `PRIMARY` +a| `SECONDARY` +|=== +// end::enum_constants[] + +// tag::methods[] +[#_ReplicaRole_id_] +==== id + +[source,java] +---- +public int id() +---- + + + +[caption=""] +.Returns +`public int` + +[#_ReplicaRole_isCandidate_] +==== isCandidate + +[source,java] +---- +public boolean isCandidate() +---- + +Checks whether this is a candidate replica of the raft cluster. + +[caption=""] +.Returns +`public boolean` + +[#_ReplicaRole_isPrimary_] +==== isPrimary + +[source,java] +---- +public boolean isPrimary() +---- + +Checks whether this is the primary replica of the raft cluster. + +[caption=""] +.Returns +`public boolean` + +[#_ReplicaRole_isSecondary_] +==== isSecondary + +[source,java] +---- +public boolean isSecondary() +---- + +Checks whether this is a secondary replica of the raft cluster. + +[caption=""] +.Returns +`public boolean` + +[#_ReplicaRole_of_com_typedb_driver_jni_ReplicaRole] +==== of + +[source,java] +---- +public static ReplicaRole of​(com.typedb.driver.jni.ReplicaRole nativeType) +---- + + + +[caption=""] +.Returns +`public static ReplicaRole` + +[#_ReplicaRole_valueOf_java_lang_String] +==== valueOf + +[source,java] +---- +public static ReplicaRole valueOf​(java.lang.String name) +---- + +Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.) + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `name` a| the name of the enum constant to be returned. a| `java.lang.String` +|=== + +[caption=""] +.Returns +`public static ReplicaRole` + +[#_ReplicaRole_values_] +==== values + +[source,java] +---- +public static ReplicaRole[] values() +---- + +Returns an array containing the constants of this enum type, in the order they are declared. This method may be used to iterate over the constants as follows: +[source,java] +---- +for (ReplicaRole c : ReplicaRole.values()) + System.out.println(c); + +---- + + +[caption=""] +.Returns +`public static ReplicaRole[]` + +[caption=""] +.Code examples +[source,java] +---- +for (ReplicaRole c : ReplicaRole.values()) + System.out.println(c); +---- + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/java/connection/ServerReplica.adoc b/docs/modules/ROOT/partials/java/connection/ServerReplica.adoc new file mode 100644 index 0000000000..19b17e21f2 --- /dev/null +++ b/docs/modules/ROOT/partials/java/connection/ServerReplica.adoc @@ -0,0 +1,85 @@ +[#_ServerReplica] +=== ServerReplica + +*Package*: `com.typedb.driver.api.server` + +The metadata and state of an individual raft replica of a driver connection. + +// tag::methods[] +[#_ServerReplica_getAddress_] +==== getAddress + +[source,java] +---- +@CheckReturnValue +java.lang.String getAddress() +---- + +Returns the address this replica is hosted at. + +[caption=""] +.Returns +`java.lang.String` + +[#_ServerReplica_getID_] +==== getID + +[source,java] +---- +@CheckReturnValue +long getID() +---- + +Returns the id of this replica. + +[caption=""] +.Returns +`long` + +[#_ServerReplica_getRole_] +==== getRole + +[source,java] +---- +@CheckReturnValue +java.util.Optional getRole() +---- + +Returns whether this is the primary replica of the raft cluster or any of the supporting types. + +[caption=""] +.Returns +`java.util.Optional` + +[#_ServerReplica_getTerm_] +==== getTerm + +[source,java] +---- +@CheckReturnValue +java.util.Optional getTerm() +---- + +Returns the raft protocol ‘term’ of this replica. + +[caption=""] +.Returns +`java.util.Optional` + +[#_ServerReplica_isPrimary_] +==== isPrimary + +[source,java] +---- +@CheckReturnValue +java.lang.Boolean isPrimary() +---- + +Checks whether this is the primary replica of the raft cluster. + +[caption=""] +.Returns +`java.lang.Boolean` + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/java/connection/ServerVersion.adoc b/docs/modules/ROOT/partials/java/connection/ServerVersion.adoc new file mode 100644 index 0000000000..17b8e25def --- /dev/null +++ b/docs/modules/ROOT/partials/java/connection/ServerVersion.adoc @@ -0,0 +1,62 @@ +[#_ServerVersion] +=== ServerVersion + +*Package*: `com.typedb.driver.api.server` + +A full TypeDB server's version specification. + + +[caption=""] +.Examples +[source,java] +---- +driver.serverVersion(); +---- + +// tag::methods[] +[#_ServerVersion_getDistribution_] +==== getDistribution + +[source,java] +---- +public java.lang.String getDistribution() +---- + +Returns the server's distribution. + + +[caption=""] +.Returns +`public java.lang.String` + +[caption=""] +.Code examples +[source,java] +---- +serverVersion.getDistribution(); +---- + +[#_ServerVersion_getVersion_] +==== getVersion + +[source,java] +---- +public java.lang.String getVersion() +---- + +Returns the server's version. + + +[caption=""] +.Returns +`public java.lang.String` + +[caption=""] +.Code examples +[source,java] +---- +serverVersion.getVersion(); +---- + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/java/connection/TypeDB.adoc b/docs/modules/ROOT/partials/java/connection/TypeDB.adoc index 0316bdc104..ad9d8361d9 100644 --- a/docs/modules/ROOT/partials/java/connection/TypeDB.adoc +++ b/docs/modules/ROOT/partials/java/connection/TypeDB.adoc @@ -54,7 +54,7 @@ Open a TypeDB Driver to a TypeDB server available at the provided address. |Name |Description |Type a| `address` a| The address of the TypeDB server a| `java.lang.String` a| `credentials` a| The credentials to connect with a| `Credentials` -a| `driverOptions` a| The connection settings to connect with a| `DriverOptions` +a| `driverOptions` a| The driver connection options to connect with a| `DriverOptions` |=== [caption=""] @@ -68,5 +68,77 @@ a| `driverOptions` a| The connection settings to connect with a| `DriverOptions` TypeDB.driver(address); ---- +[#_TypeDB_driver_java_util_Set_java_lang_String_Credentials_DriverOptions] +==== driver + +[source,java] +---- +public static Driver driver​(java.util.Set addresses, + Credentials credentials, + DriverOptions driverOptions) + throws TypeDBDriverException +---- + +Open a TypeDB Driver to a TypeDB cluster available at the provided addresses. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `addresses` a| The addresses of TypeDB cluster replicas for connection a| `java.util.Set` +a| `credentials` a| The credentials to connect with a| `Credentials` +a| `driverOptions` a| The driver connection options to connect with a| `DriverOptions` +|=== + +[caption=""] +.Returns +`public static Driver` + +[caption=""] +.Code examples +[source,java] +---- +TypeDB.driver(address); +---- + +[#_TypeDB_driver_java_util_Map_java_lang_String_​java_lang_String_Credentials_DriverOptions] +==== driver + +[source,java] +---- +public static Driver driver​(java.util.Map addressTranslation, + Credentials credentials, + DriverOptions driverOptions) + throws TypeDBDriverException +---- + +Open a TypeDB Driver to a TypeDB cluster, using the provided address translation. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `addressTranslation` a| The translation of public TypeDB cluster replica addresses (keys) to server-side private addresses (values) a| `java.util.Map` +a| `credentials` a| The credentials to connect with a| `Credentials` +a| `driverOptions` a| The driver connection options to connect with a| `DriverOptions` +|=== + +[caption=""] +.Returns +`public static Driver` + +[caption=""] +.Code examples +[source,java] +---- +TypeDB.driver(addresses); +---- + // end::methods[] diff --git a/docs/modules/ROOT/partials/java/connection/User.adoc b/docs/modules/ROOT/partials/java/connection/User.adoc index 9f40cf3f78..ac16c86db9 100644 --- a/docs/modules/ROOT/partials/java/connection/User.adoc +++ b/docs/modules/ROOT/partials/java/connection/User.adoc @@ -14,10 +14,10 @@ TypeDB user information [source,java] ---- -void delete() +default void delete() ---- -Deletes a user with the given name. +Deletes this user, using default strong consistency. See <<#_delete_com_typedb_driver_api_ConsistencyLevel,``delete(ConsistencyLevel)``>> for more details and options. [caption=""] @@ -28,7 +28,38 @@ Deletes a user with the given name. .Code examples [source,java] ---- -driver.users().delete(username); +user.delete(); +---- + +[#_User_delete_ConsistencyLevel] +==== delete + +[source,java] +---- +void delete​(ConsistencyLevel consistencyLevel) +---- + +Deletes this user. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +`void` + +[caption=""] +.Code examples +[source,java] +---- +user.delete(new ConsistencyLevel.Strong()); ---- [#_User_name_] @@ -51,10 +82,11 @@ Returns the name of this user. [source,java] ---- -void updatePassword​(java.lang.String password) +default void updatePassword​(java.lang.String password) ---- -Updates the password for this user. +Updates the password for this user, using default strong consistency. See <<#_updatePassword_java_lang_String_com_typedb_driver_api_ConsistencyLevel,``updatePassword(String, ConsistencyLevel)``>> for more details and options. + [caption=""] .Input parameters @@ -62,13 +94,52 @@ Updates the password for this user. [options="header"] |=== |Name |Description |Type -a| `passwordOld` a| The current password of this user a| -a| `passwordNew` a| The new password a| +a| `password` a| The new password a| `java.lang.String` |=== [caption=""] .Returns `void` +[caption=""] +.Code examples +[source,java] +---- +user.updatePassword("new-password"); +---- + +[#_User_updatePassword_java_lang_String_ConsistencyLevel] +==== updatePassword + +[source,java] +---- +void updatePassword​(java.lang.String password, + ConsistencyLevel consistencyLevel) +---- + +Updates the password for this user. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `password` a| The new password a| `java.lang.String` +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +`void` + +[caption=""] +.Code examples +[source,java] +---- +user.updatePassword("new-password", new ConsistencyLevel.Strong()); +---- + // end::methods[] diff --git a/docs/modules/ROOT/partials/java/connection/UserManager.adoc b/docs/modules/ROOT/partials/java/connection/UserManager.adoc index 1ba42b9cd9..e6292d7b2c 100644 --- a/docs/modules/ROOT/partials/java/connection/UserManager.adoc +++ b/docs/modules/ROOT/partials/java/connection/UserManager.adoc @@ -1,26 +1,55 @@ [#_UserManager] -[.doc-api-reference-driver] === UserManager -`class` - *Package*: `com.typedb.driver.api.user` Provides access to all user management methods. // tag::methods[] [#_UserManager_all_] -==== method ``all`` +==== all + +[source,java] +---- +default java.util.Set all() + throws TypeDBDriverException +---- + +Retrieves all users which exist on the TypeDB server, using default strong consistency. See <<#_all_com_typedb_driver_api_ConsistencyLevel,``all(ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Returns +`java.util.Set` + +[caption=""] +.Code examples +[source,java] +---- +driver.users().all(); +---- + +[#_UserManager_all_ConsistencyLevel] +==== all [source,java] ---- -java.util.Set all() +java.util.Set all​(ConsistencyLevel consistencyLevel) throws TypeDBDriverException ---- Retrieves all users which exist on the TypeDB server. +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + [caption=""] .Returns `java.util.Set` @@ -29,16 +58,50 @@ Retrieves all users which exist on the TypeDB server. .Code examples [source,java] ---- -driver.users().all(); +driver.users().all(new ConsistencyLevel.Strong()); ---- [#_UserManager_contains_java_lang_String] -==== method ``contains`` +==== contains + +[source,java] +---- +@CheckReturnValue +default boolean contains​(java.lang.String username) + throws TypeDBDriverException +---- + +Checks if a user with the given name exists., using default strong consistency. See <<#_contains_java_lang_String_com_typedb_driver_api_ConsistencyLevel,``contains(String, ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `username` a| The username to be checked a| `java.lang.String` +|=== + +[caption=""] +.Returns +`boolean` + +[caption=""] +.Code examples +[source,java] +---- +driver.users().contains(username); +---- + +[#_UserManager_contains_java_lang_String_ConsistencyLevel] +==== contains [source,java] ---- @CheckReturnValue -boolean contains​(java.lang.String username) +boolean contains​(java.lang.String username, + ConsistencyLevel consistencyLevel) throws TypeDBDriverException ---- @@ -51,7 +114,8 @@ Checks if a user with the given name exists. [options="header"] |=== |Name |Description |Type -a| `username` a| The user name to be checked a| `java.lang.String` +a| `username` a| The username to be checked a| `java.lang.String` +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` |=== [caption=""] @@ -62,16 +126,51 @@ a| `username` a| The user name to be checked a| `java.lang.String` .Code examples [source,java] ---- -driver.users().contains(username); +driver.users().contains(username, new ConsistencyLevel.Strong()); ---- [#_UserManager_create_java_lang_String_java_lang_String] -==== method ``create`` +==== create + +[source,java] +---- +default void create​(java.lang.String username, + java.lang.String password) + throws TypeDBDriverException +---- + +Creates a user with the given name & password, using default strong consistency. See <<#_create_java_lang_String_java_lang_String_com_typedb_driver_api_ConsistencyLevel,``create(String, String, ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `username` a| The name of the user to be created a| `java.lang.String` +a| `password` a| The password of the user to be created a| `java.lang.String` +|=== + +[caption=""] +.Returns +`void` + +[caption=""] +.Code examples +[source,java] +---- +driver.users().create(username, password); +---- + +[#_UserManager_create_java_lang_String_java_lang_String_ConsistencyLevel] +==== create [source,java] ---- void create​(java.lang.String username, - java.lang.String password) + java.lang.String password, + ConsistencyLevel consistencyLevel) throws TypeDBDriverException ---- @@ -86,6 +185,7 @@ Creates a user with the given name & password. |Name |Description |Type a| `username` a| The name of the user to be created a| `java.lang.String` a| `password` a| The password of the user to be created a| `java.lang.String` +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` |=== [caption=""] @@ -96,16 +196,50 @@ a| `password` a| The password of the user to be created a| `java.lang.String` .Code examples [source,java] ---- -driver.users().create(username, password); +driver.users().create(username, password, new ConsistencyLevel.Strong()); ---- [#_UserManager_get_java_lang_String] -==== method ``get`` +==== get + +[source,java] +---- +@CheckReturnValue +default User get​(java.lang.String username) + throws TypeDBDriverException +---- + +Retrieves a user with the given name, using default strong consistency. See <<#_get_java_lang_String_com_typedb_driver_api_ConsistencyLevel,``get(String, ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `username` a| The name of the user to retrieve a| `java.lang.String` +|=== + +[caption=""] +.Returns +`User` + +[caption=""] +.Code examples +[source,java] +---- +driver.users().get(username); +---- + +[#_UserManager_get_java_lang_String_ConsistencyLevel] +==== get [source,java] ---- @CheckReturnValue -User get​(java.lang.String username) +User get​(java.lang.String username, + ConsistencyLevel consistencyLevel) throws TypeDBDriverException ---- @@ -119,6 +253,7 @@ Retrieves a user with the given name. |=== |Name |Description |Type a| `username` a| The name of the user to retrieve a| `java.lang.String` +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` |=== [caption=""] @@ -129,22 +264,55 @@ a| `username` a| The name of the user to retrieve a| `java.lang.String` .Code examples [source,java] ---- -driver.users().get(username); +driver.users().get(username, new ConsistencyLevel.Strong()); ---- -[#_UserManager_getCurrentUser_] -==== method ``getCurrentUser`` +[#_UserManager_getCurrent_] +==== getCurrent [source,java] ---- @CheckReturnValue -User getCurrentUser() - throws TypeDBDriverException +default User getCurrent() + throws TypeDBDriverException +---- + +Retrieves the name of the user who opened the current connection, using default strong consistency. See <<#_getCurrent_com_typedb_driver_api_ConsistencyLevel,``getCurrent(ConsistencyLevel)``>> for more details and options. + + +[caption=""] +.Returns +`User` + +[caption=""] +.Code examples +[source,java] +---- +driver.users().getCurrent(); +---- + +[#_UserManager_getCurrent_ConsistencyLevel] +==== getCurrent + +[source,java] +---- +@CheckReturnValue +User getCurrent​(ConsistencyLevel consistencyLevel) + throws TypeDBDriverException ---- Retrieves the name of the user who opened the current connection. +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistencyLevel` a| The consistency level to use for the operation a| `ConsistencyLevel` +|=== + [caption=""] .Returns `User` @@ -153,7 +321,7 @@ Retrieves the name of the user who opened the current connection. .Code examples [source,java] ---- -driver.users().getCurrentUsername(); +driver.users().getCurrent(new ConsistencyLevel.Strong()); ---- // end::methods[] diff --git a/docs/modules/ROOT/partials/java/transaction/QueryOptions.adoc b/docs/modules/ROOT/partials/java/transaction/QueryOptions.adoc index 7b3a887fdc..6ca7c52194 100644 --- a/docs/modules/ROOT/partials/java/transaction/QueryOptions.adoc +++ b/docs/modules/ROOT/partials/java/transaction/QueryOptions.adoc @@ -62,7 +62,7 @@ options.includeInstanceTypes(); public QueryOptions includeInstanceTypes​(boolean includeInstanceTypes) ---- -Explicitly set the "include instance types" flag. If set, specifies if types should be included in instance structs returned in ConceptRow answers. This option allows reducing the amount of unnecessary data transmitted. +Explicitly setsthe "include instance types" flag. If set, specifies if types should be included in instance structs returned in ConceptRow answers. This option allows reducing the amount of unnecessary data transmitted. [caption=""] @@ -178,7 +178,7 @@ options.prefetchSize(); public QueryOptions prefetchSize​(int prefetchSize) ---- -Explicitly set the prefetch size. If set, specifies the number of extra query responses sent before the client side has to re-request more responses. Increasing this may increase performance for queries with a huge number of answers, as it can reduce the number of network round-trips at the cost of more resources on the server side. Minimal value: 1. +Explicitly setsthe prefetch size. If set, specifies the number of extra query responses sent before the client side has to re-request more responses. Increasing this may increase performance for queries with a huge number of answers, as it can reduce the number of network round-trips at the cost of more resources on the server side. Minimal value: 1. [caption=""] diff --git a/docs/modules/ROOT/partials/java/transaction/TransactionOptions.adoc b/docs/modules/ROOT/partials/java/transaction/TransactionOptions.adoc index 0b8b927609..a9161f553b 100644 --- a/docs/modules/ROOT/partials/java/transaction/TransactionOptions.adoc +++ b/docs/modules/ROOT/partials/java/transaction/TransactionOptions.adoc @@ -31,6 +31,59 @@ Produces a new ``TransactionOptions`` object. TransactionOptions options = TransactionOptions(); ---- +[#_TransactionOptions_readConsistencyLevel_] +==== readConsistencyLevel + +[source,java] +---- +public java.util.Optional readConsistencyLevel() +---- + +Returns the value set for the read consistency level in this ``TransactionOptions`` object. If set, specifies the requested consistency level of the transaction opening operation. Affects only read transactions, as write and schema transactions require primary replicas. + + +[caption=""] +.Returns +`public java.util.Optional` + +[caption=""] +.Code examples +[source,java] +---- +options.readConsistencyLevel(); +---- + +[#_TransactionOptions_readConsistencyLevel_ConsistencyLevel] +==== readConsistencyLevel + +[source,java] +---- +public TransactionOptions readConsistencyLevel​(ConsistencyLevel readConsistencyLevel) +---- + +Explicitly sets read consistency level. If set, specifies the requested consistency level of the transaction opening operation. Affects only read transactions, as write and schema transactions require primary replicas. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `readConsistencyLevel` a| The requested consistency level a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +`public TransactionOptions` + +[caption=""] +.Code examples +[source,java] +---- +options.schemaLockAcquireTimeoutMillis(schemaLockAcquireTimeoutMillis); +---- + [#_TransactionOptions_schemaLockAcquireTimeoutMillis_] ==== method ``schemaLockAcquireTimeoutMillis`` @@ -115,7 +168,7 @@ options.transactionTimeoutMillis(); public TransactionOptions transactionTimeoutMillis​(int transactionTimeoutMillis) ---- -Explicitly set a transaction timeout. If set, specifies how long the driver should wait if opening a transaction is blocked by an exclusive schema write lock. +Explicitly sets a transaction timeout. If set, specifies how long the driver should wait if opening a transaction is blocked by an exclusive schema write lock. [caption=""] diff --git a/docs/modules/ROOT/partials/nodejs/connection/Database.adoc b/docs/modules/ROOT/partials/nodejs/connection/Database.adoc index cd9193a2b2..3159bf941d 100644 --- a/docs/modules/ROOT/partials/nodejs/connection/Database.adoc +++ b/docs/modules/ROOT/partials/nodejs/connection/Database.adoc @@ -9,9 +9,9 @@ |=== |Name |Type |Description a| `name` a| `string` a| The database name as a string. -a| `preferredReplica` a| `Replica` a| The preferred replica for this database. Operations which can be run on any replica will prefer to use this replica. Only works in TypeDB Cloud -a| `primaryReplica` a| `Replica` a| The primary replica for this database. Only works in TypeDB Cloud -a| `replicas` a| `Replica` a| The Replica instances for this database. Only works in TypeDB Cloud +a| `preferredReplica` a| `ServerReplica` a| The preferred replica for this database. Operations which can be run on any replica will prefer to use this replica. Only works in TypeDB Cloud +a| `primaryReplica` a| `ServerReplica` a| The primary replica for this database. Only works in TypeDB Cloud +a| `replicas` a| `ServerReplica` a| The Replica instances for this database. Only works in TypeDB Cloud |=== // end::properties[] diff --git a/docs/modules/ROOT/partials/python/answer/ConceptRow.adoc b/docs/modules/ROOT/partials/python/answer/ConceptRow.adoc index 9382bc25ba..30acc79ecb 100644 --- a/docs/modules/ROOT/partials/python/answer/ConceptRow.adoc +++ b/docs/modules/ROOT/partials/python/answer/ConceptRow.adoc @@ -16,8 +16,6 @@ Contains a row of concepts with a header. |=== |Name |Type |Description a| `query_type` a| `QueryType` a| Retrieves the executed query’s type of this ``ConceptRow``. Shared between all the rows in a QueryAnswer. - - |=== // end::properties[] diff --git a/docs/modules/ROOT/partials/python/answer/QueryAnswer.adoc b/docs/modules/ROOT/partials/python/answer/QueryAnswer.adoc index b56671b3ae..48b8122cac 100644 --- a/docs/modules/ROOT/partials/python/answer/QueryAnswer.adoc +++ b/docs/modules/ROOT/partials/python/answer/QueryAnswer.adoc @@ -16,8 +16,6 @@ General answer on a query returned by a server. Can be a simple Ok response or a |=== |Name |Type |Description a| `query_type` a| `QueryType` a| Retrieves the executed query’s type of this ``QueryAnswer``. - - |=== // end::properties[] diff --git a/docs/modules/ROOT/partials/python/connection/ConsistencyLevel.adoc b/docs/modules/ROOT/partials/python/connection/ConsistencyLevel.adoc new file mode 100644 index 0000000000..17690c18b7 --- /dev/null +++ b/docs/modules/ROOT/partials/python/connection/ConsistencyLevel.adoc @@ -0,0 +1,80 @@ +[#_ConsistencyLevel] +=== ConsistencyLevel + +*Package*: `typedb.api.connection.consistency_level` + +Consistency levels of operations against a distributed server. All driver methods have default recommended values, however, most of the operations can be configured in order to potentially speed up the execution (introducing risks of stale data) or test a specific replica. This setting does not affect clusters with a single node. + +// tag::methods[] +[#_ConsistencyLevel_is_eventual_] +==== is_eventual + +[source,python] +---- +is_eventual() -> bool +---- + + + +[caption=""] +.Returns +`bool` + +[#_ConsistencyLevel_is_replica_dependent_] +==== is_replica_dependent + +[source,python] +---- +is_replica_dependent() -> bool +---- + + + +[caption=""] +.Returns +`bool` + +[#_ConsistencyLevel_is_strong_] +==== is_strong + +[source,python] +---- +is_strong() -> bool +---- + + + +[caption=""] +.Returns +`bool` + +[#_ConsistencyLevel_native_value_] +==== native_value + +[source,python] +---- +static native_value(consistency_level: ConsistencyLevel | None) -> ConsistencyLevel +---- + + + +[caption=""] +.Returns +`ConsistencyLevel` + +[#_ConsistencyLevel_of_] +==== of + +[source,python] +---- +static of(native_value: ConsistencyLevel) -> None | Strong | Eventual | ReplicaDependent +---- + + + +[caption=""] +.Returns +`None | Strong | Eventual | ReplicaDependent` + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/python/connection/Database.adoc b/docs/modules/ROOT/partials/python/connection/Database.adoc index 7d75c58b11..f85b779f06 100644 --- a/docs/modules/ROOT/partials/python/connection/Database.adoc +++ b/docs/modules/ROOT/partials/python/connection/Database.adoc @@ -1,10 +1,7 @@ [#_Database] -[.doc-api-reference-driver] === Database -`class` - -*Package*: `typedb.api.connection.database` +*Package*: `typedb.api.database.database` [caption=""] .Properties @@ -18,16 +15,25 @@ a| `name` a| `str` a| The database name as a string. // end::properties[] // tag::methods[] -[#_Database_delete_] -==== method ``delete`` +[#_Database_delete_consistency_level_ConsistencyLevel_None] +==== delete [source,python] ---- -delete() -> None +delete(consistency_level: ConsistencyLevel | None = None) -> None ---- Deletes this database. +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` +|=== + [caption=""] .Returns `None` @@ -37,14 +43,15 @@ Deletes this database. [source,python] ---- database.delete() +database.delete(ConsistencyLevel.Strong()) ---- -[#_Database_export_to_file_schema_file_path_str_data_file_path_str] -==== method ``export_to_file`` +[#_Database_export_to_file_schema_file_path_str_data_file_path_str_consistency_level_ConsistencyLevel_None] +==== export_to_file [source,python] ---- -export_to_file(schema_file_path: str, data_file_path: str) -> None +export_to_file(schema_file_path: str, data_file_path: str, consistency_level: ConsistencyLevel | None = None) -> None ---- Export a database into a schema definition and a data files saved to the disk. This is a blocking operation and may take a significant amount of time depending on the database size. @@ -57,6 +64,7 @@ Export a database into a schema definition and a data files saved to the disk. T |Name |Description |Type |Default Value a| `schema_file_path` a| The path to the schema definition file to be created a| `str` a| a| `data_file_path` a| The path to the data file to be created a| `str` a| +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` |=== [caption=""] @@ -68,18 +76,28 @@ a| `data_file_path` a| The path to the data file to be created a| `str` a| [source,python] ---- database.export_to_file("schema.typeql", "data.typedb") +database.export_to_file("schema.typeql", "data.typedb", ConsistencyLevel.Strong()) ---- -[#_Database_schema_] -==== method ``schema`` +[#_Database_schema_consistency_level_ConsistencyLevel_None] +==== schema [source,python] ---- -schema() -> str +schema(consistency_level: ConsistencyLevel | None = None) -> str ---- Returns a full schema text as a valid TypeQL define query string. +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` +|=== + [caption=""] .Returns `str` @@ -89,18 +107,28 @@ Returns a full schema text as a valid TypeQL define query string. [source,python] ---- database.schema() +database.schema(ConsistencyLevel.Strong()) ---- -[#_Database_type_schema_] -==== method ``type_schema`` +[#_Database_type_schema_consistency_level_ConsistencyLevel_None] +==== type_schema [source,python] ---- -type_schema() -> str +type_schema(consistency_level: ConsistencyLevel | None = None) -> str ---- Returns the types in the schema as a valid TypeQL define query string. +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` +|=== + [caption=""] .Returns `str` @@ -110,6 +138,7 @@ Returns the types in the schema as a valid TypeQL define query string. [source,python] ---- database.type_schema() +database.type_schema(ConsistencyLevel.Strong()) ---- // end::methods[] diff --git a/docs/modules/ROOT/partials/python/connection/DatabaseManager.adoc b/docs/modules/ROOT/partials/python/connection/DatabaseManager.adoc index f20f06ac9a..ce964e454c 100644 --- a/docs/modules/ROOT/partials/python/connection/DatabaseManager.adoc +++ b/docs/modules/ROOT/partials/python/connection/DatabaseManager.adoc @@ -1,24 +1,30 @@ [#_DatabaseManager] -[.doc-api-reference-driver] === DatabaseManager -`class` - -*Package*: `typedb.api.connection.database` +*Package*: `typedb.api.database.database_manager` Provides access to all database management methods. // tag::methods[] -[#_DatabaseManager_all_] -==== method ``all`` +[#_DatabaseManager_all_consistency_level_ConsistencyLevel_None] +==== all [source,python] ---- -all() -> List[Database] +all(consistency_level: ConsistencyLevel | None = None) -> List[Database] ---- Retrieves all databases present on the TypeDB server. +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` +|=== + [caption=""] .Returns `List[Database]` @@ -28,14 +34,15 @@ Retrieves all databases present on the TypeDB server. [source,python] ---- driver.databases.all() +driver.databases.all(ConsistencyLevel.Strong()) ---- -[#_DatabaseManager_contains_name_str] -==== method ``contains`` +[#_DatabaseManager_contains_name_str_consistency_level_ConsistencyLevel_None] +==== contains [source,python] ---- -contains(name: str) -> bool +contains(name: str, consistency_level: ConsistencyLevel | None = None) -> bool ---- Checks if a database with the given name exists. @@ -47,6 +54,7 @@ Checks if a database with the given name exists. |=== |Name |Description |Type |Default Value a| `name` a| The database name to be checked a| `str` a| +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` |=== [caption=""] @@ -58,17 +66,18 @@ a| `name` a| The database name to be checked a| `str` a| [source,python] ---- driver.databases.contains(name) +driver.databases.contains(name, ConsistencyLevel.Strong()) ---- -[#_DatabaseManager_create_name_str] -==== method ``create`` +[#_DatabaseManager_create_name_str_consistency_level_ConsistencyLevel_None] +==== create [source,python] ---- -create(name: str) -> None +create(name: str, consistency_level: ConsistencyLevel | None = None) -> None ---- -Create a database with the given name. +Creates a database with the given name. [caption=""] .Input parameters @@ -77,6 +86,7 @@ Create a database with the given name. |=== |Name |Description |Type |Default Value a| `name` a| The name of the database to be created a| `str` a| +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` |=== [caption=""] @@ -88,17 +98,18 @@ a| `name` a| The name of the database to be created a| `str` a| [source,python] ---- driver.databases.create(name) +driver.databases.create(name, ConsistencyLevel.Strong()) ---- -[#_DatabaseManager_get_name_str] -==== method ``get`` +[#_DatabaseManager_get_name_str_consistency_level_ConsistencyLevel_None] +==== get [source,python] ---- -get(name: str) -> Database +get(name: str, consistency_level: ConsistencyLevel | None = None) -> Database ---- -Retrieve the database with the given name. +Retrieves the database with the given name. [caption=""] .Input parameters @@ -107,6 +118,7 @@ Retrieve the database with the given name. |=== |Name |Description |Type |Default Value a| `name` a| The name of the database to retrieve a| `str` a| +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` |=== [caption=""] @@ -118,17 +130,18 @@ a| `name` a| The name of the database to retrieve a| `str` a| [source,python] ---- driver.databases.get(name) +driver.databases.get(name, ConsistencyLevel.Strong()) ---- [#_DatabaseManager_import_from_file_name_str_schema_str_data_file_path_str] -==== method ``import_from_file`` +==== import_from_file [source,python] ---- import_from_file(name: str, schema: str, data_file_path: str) -> None ---- -Create a database with the given name based on previously exported another database’s data loaded from a file. This is a blocking operation and may take a significant amount of time depending on the database size. +Creates a database with the given name based on previously exported another database’s data loaded from a file. This is a blocking operation and may take a significant amount of time depending on the database size. [caption=""] .Input parameters diff --git a/docs/modules/ROOT/partials/python/connection/Driver.adoc b/docs/modules/ROOT/partials/python/connection/Driver.adoc index 954b395209..bce8f88d53 100644 --- a/docs/modules/ROOT/partials/python/connection/Driver.adoc +++ b/docs/modules/ROOT/partials/python/connection/Driver.adoc @@ -14,7 +14,7 @@ |=== |Name |Type |Description a| `databases` a| `DatabaseManager` a| The ``DatabaseManager`` for this connection, providing access to database management methods. -a| `users` a| `UserManager` a| The ``UserManager`` instance for this connection, providing access to user management methods. Only for TypeDB Cloud. +a| `users` a| `UserManager` a| The ``UserManager`` for this connection, providing access to user management methods. |=== // end::properties[] @@ -40,6 +40,36 @@ Closes the driver. Before instantiating a new driver, the driver that’s curren driver.close() ---- +[#_Driver_deregister_replica_replica_id_int] +==== deregister_replica + +[source,python] +---- +deregister_replica(replica_id: int) -> None +---- + +Deregisters a replica from the cluster the driver is currently connected to. This replica will no longer play a raft role in this cluster. + +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `replica_id` a| The numeric identifier of the deregistered replica a| `int` a| +|=== + +[caption=""] +.Returns +`None` + +[caption=""] +.Code examples +[source,python] +---- +driver.deregister_replica(2) +---- + [#_Driver_is_open_] ==== method ``is_open`` @@ -61,6 +91,130 @@ Checks whether this connection is presently open. driver.is_open() ---- +[#_Driver_primary_replica_consistency_level_ConsistencyLevel_None] +==== primary_replica + +[source,python] +---- +primary_replica(consistency_level: ConsistencyLevel | None = None) -> ServerReplica | None +---- + +Returns the primary replica for this driver connection. + +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` +|=== + +[caption=""] +.Returns +`ServerReplica | None` + +[caption=""] +.Code examples +[source,python] +---- +driver.primary_replica() +driver.primary_replica(ConsistencyLevel.Strong()) +---- + +[#_Driver_register_replica_replica_id_int_address_str] +==== register_replica + +[source,python] +---- +register_replica(replica_id: int, address: str) -> None +---- + +Registers a new replica in the cluster the driver is currently connected to. The registered replica will become available eventually, depending on the behavior of the whole cluster. To register a replica, its clustering address should be passed, not the connection address. + +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `replica_id` a| The numeric identifier of the new replica a| `int` a| +a| `address` a| The address(es) of the TypeDB replica as a string a| `str` a| +|=== + +[caption=""] +.Returns +`None` + +[caption=""] +.Code examples +[source,python] +---- +driver.register_replica(2, "127.0.0.1:11729") +---- + +[#_Driver_replicas_consistency_level_ConsistencyLevel_None] +==== replicas + +[source,python] +---- +replicas(consistency_level: ConsistencyLevel | None = None) -> Set[ServerReplica] +---- + +Set of ``Replica`` instances for this driver connection. + +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` +|=== + +[caption=""] +.Returns +`Set[ServerReplica]` + +[caption=""] +.Code examples +[source,python] +---- +driver.replicas() +driver.replicas(ConsistencyLevel.Strong()) +---- + +[#_Driver_server_version_consistency_level_ConsistencyLevel_None] +==== server_version + +[source,python] +---- +server_version(consistency_level: ConsistencyLevel | None = None) -> ServerVersion +---- + +Retrieves the server’s version. + +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` +|=== + +[caption=""] +.Returns +`ServerVersion` + +[caption=""] +.Code examples +[source,python] +---- +driver.server_version() +driver.server_version(ConsistencyLevel.Strong()) +---- + [#_Driver_transaction_database_name_str_transaction_type_TransactionType_options_TransactionOptions_None] ==== method ``transaction`` @@ -93,5 +247,35 @@ a| `options` a| ``TransactionOptions`` to configure the opened transaction a| `T driver.transaction(database, transaction_type, options) ---- +[#_Driver_update_address_translation_address_translation_Mapping_str_str_] +==== update_address_translation + +[source,python] +---- +update_address_translation(address_translation: Mapping[str, str]) -> None +---- + +Updates address translation of the driver. This lets you actualize new translation information without recreating the driver from scratch. Useful after registering new replicas requiring address translation. This operation will update existing connections using the provided addresses. + +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `address_translation` a| The translation of public TypeDB cluster replica addresses (keys) to server-side private addresses (values) a| `Mapping[str, str]` a| +|=== + +[caption=""] +.Returns +`None` + +[caption=""] +.Code examples +[source,python] +---- +driver.update_address_translation({"typedb-cloud.ext:11729": "127.0.0.1:11729"}) +---- + // end::methods[] diff --git a/docs/modules/ROOT/partials/python/connection/DriverOptions.adoc b/docs/modules/ROOT/partials/python/connection/DriverOptions.adoc index ff4035b2a7..3e9c4e1e1b 100644 --- a/docs/modules/ROOT/partials/python/connection/DriverOptions.adoc +++ b/docs/modules/ROOT/partials/python/connection/DriverOptions.adoc @@ -6,12 +6,30 @@ *Package*: `typedb.api.connection.driver_options` -User credentials and TLS encryption settings for connecting to TypeDB Server. Arguments: 1) is_tls_enabled: Specify whether the connection to TypeDB must be done over TLS. 2) tls_root_ca_path: Path to the CA certificate to use for authenticating server certificates. +TypeDB driver options. ``DriverOptions`` are used to specify the driver’s connection behavior. + +Options could be specified either as constructor arguments or using properties assignment. [caption=""] .Examples [source,python] ---- -driver_options = DriverOptions(is_tls_enabled=True, tls_root_ca_path="path/to/ca-certificate.pem") +options = DriverOptions(DriverTlsConfig.enabled_with_native_root_ca(), request_timeout_millis=6000) +options.request_timeout_millis = 6000 ---- +[caption=""] +.Properties +// tag::properties[] +[cols=",,"] +[options="header"] +|=== +|Name |Type |Description +a| `primary_failover_retries` a| `int` a| Returns the value set for the primary failover retries limit in this ``DriverOptions`` object. Limits the number of attempts to redirect a strongly consistent request to another primary replica in case of a failure due to the change of replica roles. Defaults to 1. +a| `replica_discovery_attempts` a| `int \| None` a| Returns the value set for the replica discovery attempts limit in this ``DriverOptions`` object. Limits the number of driver attempts to discover a single working replica to perform an operation in case of a replica unavailability. Every replica is tested once, which means that at most: - {limit} operations are performed if the limit <= the number of replicas. - {number of replicas} operations are performed if the limit > the number of replicas. - {number of replicas} operations are performed if the limit is None. Affects every eventually consistent operation, including redirect failover, when the new primary replica is unknown. If not set, the maximum (practically unlimited) value is used. +a| `request_timeout_millis` a| `int` a| Returns the request timeout in milliseconds set for this ``DriverOptions`` object. Specifies the maximum time to wait for a response to a unary RPC request. This applies to operations like database creation, user management, and initial transaction opening. It does NOT apply to operations within transactions (queries, commits). +a| `tls_config` a| `DriverTlsConfig` a| Returns the TLS configuration associated with this ``DriverOptions``. Specifies the TLS configuration of the connection to TypeDB. +a| `use_replication` a| `bool` a| Returns the value set for the replication usage flag in this ``DriverOptions`` object. Specifies whether the connection to TypeDB can use cluster replicas provided by the server or it should be limited to a single configured address. Defaults to True. +|=== +// end::properties[] + diff --git a/docs/modules/ROOT/partials/python/connection/DriverTlsConfig.adoc b/docs/modules/ROOT/partials/python/connection/DriverTlsConfig.adoc new file mode 100644 index 0000000000..bd77bbc9c0 --- /dev/null +++ b/docs/modules/ROOT/partials/python/connection/DriverTlsConfig.adoc @@ -0,0 +1,98 @@ +[#_DriverTlsConfig] +=== DriverTlsConfig + +*Package*: `typedb.api.connection.driver_tls_config` + +TLS configuration for the TypeDB driver. + +``DriverTlsConfig`` represents a fully constructed and validated TLS configuration. If TLS is enabled, the underlying TLS config is built eagerly at construction time, ensuring that no connection attempt can observe a partially-configured TLS state. + +The driver defaults to using TLS with native system trust roots. This matches typical system and container deployments while still allowing explicit opt-out or custom PKI configuration. + +[caption=""] +.Properties +// tag::properties[] +[cols=",,"] +[options="header"] +|=== +|Name |Type |Description +a| `is_enabled` a| `bool` a| Returns whether TLS is enabled. +a| `root_ca_path` a| `str \| None` a| Returns the configured custom root CA path, if present. If TLS is enabled with native roots (or disabled), this will be ``None``. +|=== +// end::properties[] + +// tag::methods[] +[#_DriverTlsConfig_disabled_] +==== disabled + +[source,python] +---- +static disabled() -> DriverTlsConfig +---- + +Creates a TLS configuration with TLS disabled. WARNING: Disabling TLS causes credentials and data to be transmitted in plaintext. + +[caption=""] +.Returns +`DriverTlsConfig` + +[caption=""] +.Code examples +[source,python] +---- +tls_config = DriverTlsConfig.disabled() +---- + +[#_DriverTlsConfig_enabled_with_native_root_ca_] +==== enabled_with_native_root_ca + +[source,python] +---- +static enabled_with_native_root_ca() -> DriverTlsConfig +---- + +Creates a TLS configuration enabled with system native trust roots. + +[caption=""] +.Returns +`DriverTlsConfig` + +[caption=""] +.Code examples +[source,python] +---- +tls_config = DriverTlsConfig.enabled_with_native_root_ca() +---- + +[#_DriverTlsConfig_enabled_with_root_ca_tls_root_ca_path_str] +==== enabled_with_root_ca + +[source,python] +---- +static enabled_with_root_ca(tls_root_ca_path: str) -> DriverTlsConfig +---- + +Creates a TLS configuration enabled with a custom root CA certificate bundle (PEM). + +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `tls_root_ca_path` a| the path to PEM-encoded root CA certificate bundle a| `str` a| +|=== + +[caption=""] +.Returns +`DriverTlsConfig` + +[caption=""] +.Code examples +[source,python] +---- +tls_config = DriverTlsConfig.enabled_with_root_ca("path/to/ca-certificate.pem") +---- + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/python/connection/Eventual.adoc b/docs/modules/ROOT/partials/python/connection/Eventual.adoc new file mode 100644 index 0000000000..586934c0e2 --- /dev/null +++ b/docs/modules/ROOT/partials/python/connection/Eventual.adoc @@ -0,0 +1,11 @@ +[#_Eventual] +=== Eventual + +*Package*: `typedb.api.connection.consistency_level` + +*Supertypes:* + +* `ConsistencyLevel` + +Eventual consistency level. Allow stale reads from any replica and execution orchestration through a non-primary replica. Does not guarantee latest writes, but is eventually faster compared to other consistency levels. Note that the target replica can redirect the request, if needed. + diff --git a/docs/modules/ROOT/partials/python/connection/ReplicaDependent.adoc b/docs/modules/ROOT/partials/python/connection/ReplicaDependent.adoc new file mode 100644 index 0000000000..44fcdf5311 --- /dev/null +++ b/docs/modules/ROOT/partials/python/connection/ReplicaDependent.adoc @@ -0,0 +1,22 @@ +[#_ReplicaDependent] +=== ReplicaDependent + +*Package*: `typedb.api.connection.consistency_level` + +*Supertypes:* + +* `ConsistencyLevel` + +Replica dependent consistency level. The operation is executed against the provided replica address only. Its guarantees depend on the replica selected. Note that the target replica can redirect the request, if needed. + +[caption=""] +.Properties +// tag::properties[] +[cols=",,"] +[options="header"] +|=== +|Name |Type |Description +a| `address` a| `str` a| Retrieves the address of the replica this consistency level depends on. +|=== +// end::properties[] + diff --git a/docs/modules/ROOT/partials/python/connection/ReplicaRole.adoc b/docs/modules/ROOT/partials/python/connection/ReplicaRole.adoc new file mode 100644 index 0000000000..f6d6c6325d --- /dev/null +++ b/docs/modules/ROOT/partials/python/connection/ReplicaRole.adoc @@ -0,0 +1,72 @@ +[#_ReplicaRole] +=== ReplicaRole + +*Package*: `typedb.api.server.replica_role` + +This class is used to specify the type of replica. + +[caption=""] +.Examples +[source,python] +---- +server_replica.role +---- + +[caption=""] +.Enum constants +// tag::enum_constants[] +[cols=","] +[options="header"] +|=== +|Name |Value +a| `CANDIDATE` a| `1` +a| `PRIMARY` a| `0` +a| `SECONDARY` a| `2` +|=== +// end::enum_constants[] + +// tag::methods[] +[#_ReplicaRole_is_candidate_] +==== is_candidate + +[source,python] +---- +is_candidate() -> bool +---- + + + +[caption=""] +.Returns +`bool` + +[#_ReplicaRole_is_primary_] +==== is_primary + +[source,python] +---- +is_primary() -> bool +---- + + + +[caption=""] +.Returns +`bool` + +[#_ReplicaRole_is_secondary_] +==== is_secondary + +[source,python] +---- +is_secondary() -> bool +---- + + + +[caption=""] +.Returns +`bool` + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/python/connection/ServerReplica.adoc b/docs/modules/ROOT/partials/python/connection/ServerReplica.adoc new file mode 100644 index 0000000000..24e2958e12 --- /dev/null +++ b/docs/modules/ROOT/partials/python/connection/ServerReplica.adoc @@ -0,0 +1,45 @@ +[#_ServerReplica] +=== ServerReplica + +*Package*: `typedb.api.server.server_replica` + +The metadata and state of an individual raft replica of a driver connection. + +[caption=""] +.Properties +// tag::properties[] +[cols=",,"] +[options="header"] +|=== +|Name |Type |Description +a| `address` a| `str` a| Returns the address this replica is hosted at. +a| `id` a| `int` a| Returns the id of this replica. +a| `role` a| `ReplicaRole \| None` a| Returns whether this is the primary replica of the raft cluster or any of the supporting types. +a| `term` a| `int` a| Returns the raft protocol ‘term’ of this replica. +|=== +// end::properties[] + +// tag::methods[] +[#_ServerReplica_is_primary_] +==== is_primary + +[source,python] +---- +is_primary() -> bool +---- + +Checks whether this is the primary replica of the raft cluster. + +[caption=""] +.Returns +`bool` + +[caption=""] +.Code examples +[source,python] +---- +server_replica.is_primary() +---- + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/python/connection/ServerVersion.adoc b/docs/modules/ROOT/partials/python/connection/ServerVersion.adoc new file mode 100644 index 0000000000..3427a63baf --- /dev/null +++ b/docs/modules/ROOT/partials/python/connection/ServerVersion.adoc @@ -0,0 +1,26 @@ +[#_ServerVersion] +=== ServerVersion + +*Package*: `typedb.api.server.server_version` + +A full TypeDB server’s version specification. + +[caption=""] +.Examples +[source,python] +---- +driver.server_version() +---- + +[caption=""] +.Properties +// tag::properties[] +[cols=",,"] +[options="header"] +|=== +|Name |Type |Description +a| `distribution` a| `str` a| Returns the server’s distribution. +a| `version` a| `str` a| Returns the server’s version. +|=== +// end::properties[] + diff --git a/docs/modules/ROOT/partials/python/connection/Strong.adoc b/docs/modules/ROOT/partials/python/connection/Strong.adoc new file mode 100644 index 0000000000..4b09a9684f --- /dev/null +++ b/docs/modules/ROOT/partials/python/connection/Strong.adoc @@ -0,0 +1,11 @@ +[#_Strong] +=== Strong + +*Package*: `typedb.api.connection.consistency_level` + +*Supertypes:* + +* `ConsistencyLevel` + +Strong consistency level. Strongest consistency, always up-to-date due to the guarantee of the primary replica usage. May require more time for operation execution. + diff --git a/docs/modules/ROOT/partials/python/connection/TypeDB.adoc b/docs/modules/ROOT/partials/python/connection/TypeDB.adoc index 1e74b3cf2a..e5d7b3b14c 100644 --- a/docs/modules/ROOT/partials/python/connection/TypeDB.adoc +++ b/docs/modules/ROOT/partials/python/connection/TypeDB.adoc @@ -1,31 +1,28 @@ [#_TypeDB] -[.doc-api-reference-driver] === TypeDB -`class` - *Package*: `typedb.driver` // tag::methods[] -[#_TypeDB_driver_address_str_credentials_Credentials_driver_options_DriverOptions] -==== method ``driver`` +[#_TypeDB_driver_addresses_Mapping_str_str_Iterable_str_str] +==== driver [source,python] ---- -static driver(address: str, credentials: Credentials, driver_options: DriverOptions) -> Driver +static driver(addresses: Mapping[str, str] | Iterable[str] | str, credentials: Credentials, driver_options: DriverOptions) -> Driver ---- Creates a connection to TypeDB. +Can be a single string, multiple strings, or multiple pairs of strings. :param credentials: The credentials to connect with. :param driver_options: The driver connection options to connect with. + [caption=""] .Input parameters [cols=",,,"] [options="header"] |=== |Name |Description |Type |Default Value -a| `address` a| Address of the TypeDB server. a| `str` a| -a| `credentials` a| The credentials to connect with. a| `Credentials` a| -a| `driver_options` a| The connection settings to connect with. a| `DriverOptions` a| +a| `addresses` a| Address(-es) of the TypeDB server(-s). a| `Mapping[str, str] \| Iterable[str] \| str` a| |=== [caption=""] diff --git a/docs/modules/ROOT/partials/python/connection/User.adoc b/docs/modules/ROOT/partials/python/connection/User.adoc index 48bb45406d..e776bdee1f 100644 --- a/docs/modules/ROOT/partials/python/connection/User.adoc +++ b/docs/modules/ROOT/partials/python/connection/User.adoc @@ -1,9 +1,6 @@ [#_User] -[.doc-api-reference-driver] === User -`class` - *Package*: `typedb.api.user.user` TypeDB user information @@ -16,21 +13,19 @@ TypeDB user information |=== |Name |Type |Description a| `name` a| `str` a| Returns the name of this user. - - |=== // end::properties[] // tag::methods[] -[#_User_delete_username] -==== method ``delete`` +[#_User_delete_consistency_level_ConsistencyLevel_None] +==== delete [source,python] ---- -delete() -> None +delete(consistency_level: ConsistencyLevel | None = None) -> None ---- -Deletes a user with the given name. +Deletes this user. [caption=""] .Input parameters @@ -38,7 +33,7 @@ Deletes a user with the given name. [options="header"] |=== |Name |Description |Type |Default Value -a| `username` a| The name of the user to be deleted a| a| +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` |=== [caption=""] @@ -49,15 +44,16 @@ a| `username` a| The name of the user to be deleted a| a| .Code examples [source,python] ---- -driver.users.delete(username) +user.delete() +user.delete(ConsistencyLevel.Strong()) ---- -[#_User_update_password_password_old_password_new] -==== method ``update_password`` +[#_User_update_password_password_str_consistency_level_ConsistencyLevel_None] +==== update_password [source,python] ---- -update_password(password: str) -> None +update_password(password: str, consistency_level: ConsistencyLevel | None = None) -> None ---- Updates the password for this user. @@ -68,13 +64,21 @@ Updates the password for this user. [options="header"] |=== |Name |Description |Type |Default Value -a| `password_old` a| The current password of this user a| a| -a| `password_new` a| The new password a| a| +a| `password` a| The new password a| `str` a| +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` |=== [caption=""] .Returns `None` +[caption=""] +.Code examples +[source,python] +---- +user.update_password("new-password") +user.update_password("new-password", ConsistencyLevel.Strong()) +---- + // end::methods[] diff --git a/docs/modules/ROOT/partials/python/connection/UserManager.adoc b/docs/modules/ROOT/partials/python/connection/UserManager.adoc index c641fe1cbc..872e3bf248 100644 --- a/docs/modules/ROOT/partials/python/connection/UserManager.adoc +++ b/docs/modules/ROOT/partials/python/connection/UserManager.adoc @@ -1,24 +1,30 @@ [#_UserManager] -[.doc-api-reference-driver] === UserManager -`class` - -*Package*: `typedb.api.user.user` +*Package*: `typedb.api.user.user_manager` Provides access to all user management methods. // tag::methods[] -[#_UserManager_all_] -==== method ``all`` +[#_UserManager_all_consistency_level_ConsistencyLevel_None] +==== all [source,python] ---- -all() -> List[User] +all(consistency_level: ConsistencyLevel | None = None) -> List[User] ---- Retrieves all users which exist on the TypeDB server. +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` +|=== + [caption=""] .Returns `List[User]` @@ -28,14 +34,15 @@ Retrieves all users which exist on the TypeDB server. [source,python] ---- driver.users.all() +driver.users.all(ConsistencyLevel.Strong()) ---- -[#_UserManager_contains_username_str] -==== method ``contains`` +[#_UserManager_contains_username_str_consistency_level_ConsistencyLevel_None] +==== contains [source,python] ---- -contains(username: str) -> bool +contains(username: str, consistency_level: ConsistencyLevel | None = None) -> bool ---- Checks if a user with the given name exists. @@ -46,7 +53,8 @@ Checks if a user with the given name exists. [options="header"] |=== |Name |Description |Type |Default Value -a| `username` a| The user name to be checked a| `str` a| +a| `username` a| The username to be checked a| `str` a| +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` |=== [caption=""] @@ -58,17 +66,18 @@ a| `username` a| The user name to be checked a| `str` a| [source,python] ---- driver.users.contains(username) +driver.users.contains(username, ConsistencyLevel.Strong()) ---- -[#_UserManager_create_username_str_password_str] -==== method ``create`` +[#_UserManager_create_username_str_password_str_consistency_level_ConsistencyLevel_None] +==== create [source,python] ---- -create(username: str, password: str) -> None +create(username: str, password: str, consistency_level: ConsistencyLevel | None = None) -> None ---- -Create a user with the given name and password. +Creates a user with the given name and password. [caption=""] .Input parameters @@ -78,6 +87,7 @@ Create a user with the given name and password. |Name |Description |Type |Default Value a| `username` a| The name of the user to be created a| `str` a| a| `password` a| The password of the user to be created a| `str` a| +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` |=== [caption=""] @@ -89,17 +99,18 @@ a| `password` a| The password of the user to be created a| `str` a| [source,python] ---- driver.users.create(username, password) +driver.users.create(username, password, ConsistencyLevel.Strong()) ---- -[#_UserManager_get_username_str] -==== method ``get`` +[#_UserManager_get_username_str_consistency_level_ConsistencyLevel_None] +==== get [source,python] ---- -get(username: str) -> User | None +get(username: str, consistency_level: ConsistencyLevel | None = None) -> User | None ---- -Retrieve a user with the given name. +Retrieves a user with the given name. [caption=""] .Input parameters @@ -108,6 +119,7 @@ Retrieve a user with the given name. |=== |Name |Description |Type |Default Value a| `username` a| The name of the user to retrieve a| `str` a| +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` |=== [caption=""] @@ -119,17 +131,27 @@ a| `username` a| The name of the user to retrieve a| `str` a| [source,python] ---- driver.users.get(username) +driver.users.get(username, ConsistencyLevel.Strong()) ---- -[#_UserManager_get_current_user_] -==== method ``get_current_user`` +[#_UserManager_get_current_consistency_level_ConsistencyLevel_None] +==== get_current [source,python] ---- -get_current_user() -> User | None +get_current(consistency_level: ConsistencyLevel | None = None) -> User | None ---- -Retrieve the name of the user who opened the current connection. +Retrieves the name of the user who opened the current connection. + +[caption=""] +.Input parameters +[cols=",,,"] +[options="header"] +|=== +|Name |Description |Type |Default Value +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible by default a| `ConsistencyLevel \| None` a| `None` +|=== [caption=""] .Returns @@ -139,7 +161,8 @@ Retrieve the name of the user who opened the current connection. .Code examples [source,python] ---- -driver.users.get_current_user() +driver.users.get_current() +driver.users.get_current(ConsistencyLevel.Strong()) ---- // end::methods[] diff --git a/docs/modules/ROOT/partials/python/transaction/QueryOptions.adoc b/docs/modules/ROOT/partials/python/transaction/QueryOptions.adoc index ca5bbb0005..1f686edbef 100644 --- a/docs/modules/ROOT/partials/python/transaction/QueryOptions.adoc +++ b/docs/modules/ROOT/partials/python/transaction/QueryOptions.adoc @@ -6,7 +6,7 @@ *Package*: `typedb.api.connection.query_options` -TypeDB transaction options. ``QueryOptions`` object can be used to override the default server behaviour for executed queries. +TypeDB query options. ``QueryOptions`` object can be used to override the default server behaviour for executed queries. Options could be specified either as constructor arguments or using properties assignment. diff --git a/docs/modules/ROOT/partials/python/transaction/TransactionOptions.adoc b/docs/modules/ROOT/partials/python/transaction/TransactionOptions.adoc index d3f52320d6..fe18eca7cd 100644 --- a/docs/modules/ROOT/partials/python/transaction/TransactionOptions.adoc +++ b/docs/modules/ROOT/partials/python/transaction/TransactionOptions.adoc @@ -25,6 +25,7 @@ transaction_options.schema_lock_acquire_timeout_millis = 50_000 [options="header"] |=== |Name |Type |Description +a| `read_consistency_level` a| `ConsistencyLevel \| None` a| If set, specifies the requested consistency level of the transaction opening operation. Affects only read transactions, as write and schema transactions require primary replicas. a| `schema_lock_acquire_timeout_millis` a| `int \| None` a| If set, specifies how long the driver should wait if opening a transaction is blocked by a schema write lock. a| `transaction_timeout_millis` a| `int \| None` a| If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. |=== diff --git a/docs/modules/ROOT/partials/python/value/Datetime.adoc b/docs/modules/ROOT/partials/python/value/Datetime.adoc index b7e87f7b54..3bffdffdde 100644 --- a/docs/modules/ROOT/partials/python/value/Datetime.adoc +++ b/docs/modules/ROOT/partials/python/value/Datetime.adoc @@ -15,23 +15,23 @@ An extension class for ``datetime.datetime`` class to store additional informati [options="header"] |=== |Name |Type |Description -a| `date` a| `date` a| Return the date part. -a| `datetime_without_nanos` a| `datetime` a| Return the standard library’s datetime, containing data up to microseconds. -a| `day` a| `int` a| Return the datetime’s day (1-31). -a| `hour` a| `int` a| Return the datetime’s hour (0-23). -a| `microsecond` a| `int` a| Return the rounded number of microseconds. -a| `minute` a| `int` a| Return the datetime’s minute (0-59). -a| `month` a| `int` a| Return the datetime’s month (1-12). -a| `nanos` a| `int` a| Return the nanoseconds part. -a| `offset_seconds` a| `str \| None` a| Return the timezone offset (local minus UTC) in seconds. None if an IANA name is used for the initialisation instead. -a| `second` a| `int` a| Return the datetime’s second (0-59). -a| `total_seconds` a| `float` a| Return the total number of seconds including the nanoseconds part as a float. +a| `date` a| `date` a| Returns the date part. +a| `datetime_without_nanos` a| `datetime` a| Returns the standard library’s datetime, containing data up to microseconds. +a| `day` a| `int` a| Returns the datetime’s day (1-31). +a| `hour` a| `int` a| Returns the datetime’s hour (0-23). +a| `microsecond` a| `int` a| Returns the rounded number of microseconds. +a| `minute` a| `int` a| Returns the datetime’s minute (0-59). +a| `month` a| `int` a| Returns the datetime’s month (1-12). +a| `nanos` a| `int` a| Returns the nanoseconds part. +a| `offset_seconds` a| `str \| None` a| Returns the timezone offset (local minus UTC) in seconds. None if an IANA name is used for the initialisation instead. +a| `second` a| `int` a| Returns the datetime’s second (0-59). +a| `total_seconds` a| `float` a| Returns the total number of seconds including the nanoseconds part as a float. ValueError – If timestamp is before the start of the epoch. -a| `tz_name` a| `str \| None` a| Return the timezone IANA name. None if fixed offset is used for the initialisation instead. -a| `tzinfo` a| `tzinfo` a| Return timezone info. -a| `weekday` a| `int` a| Return the day of the week as an integer, where Monday == 0 … Sunday == 6. -a| `year` a| `int` a| Return the datetime’s year (1-9999). +a| `tz_name` a| `str \| None` a| Returns the timezone IANA name. None if fixed offset is used for the initialisation instead. +a| `tzinfo` a| `tzinfo` a| Returns timezone info. +a| `weekday` a| `int` a| Returns the day of the week as an integer, where Monday == 0 … Sunday == 6. +a| `year` a| `int` a| Returns the datetime’s year (1-9999). |=== // end::properties[] @@ -106,7 +106,7 @@ a| `offset_seconds` a| Offset in seconds from UTC (e.g., 3600 for +01:00, -18000 isoformat() -> str ---- -Return the time formatted according to ISO. +Returns the time formatted according to ISO. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/rust/answer/ConceptDocument.adoc b/docs/modules/ROOT/partials/rust/answer/ConceptDocument.adoc index af8d0f14e7..6e040a8efe 100644 --- a/docs/modules/ROOT/partials/rust/answer/ConceptDocument.adoc +++ b/docs/modules/ROOT/partials/rust/answer/ConceptDocument.adoc @@ -33,7 +33,7 @@ a| `root` a| `Option` a| pub fn get_query_type(&self) -> QueryType ---- -Retrieve the executed query’s type (shared by all elements in this stream). +Retrieves the executed query’s type (shared by all elements in this stream). [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/rust/answer/ConceptRow.adoc b/docs/modules/ROOT/partials/rust/answer/ConceptRow.adoc index 36f70a7844..db52ccfc16 100644 --- a/docs/modules/ROOT/partials/rust/answer/ConceptRow.adoc +++ b/docs/modules/ROOT/partials/rust/answer/ConceptRow.adoc @@ -66,7 +66,7 @@ concept_row.get(var_name) pub fn get_column_names(&self) -> &[String] ---- -Retrieve the row column names (shared by all elements in this stream). +Retrieves the row column names (shared by all elements in this stream). [caption=""] .Returns @@ -216,7 +216,7 @@ concept_row.get_query_structure() pub fn get_query_type(&self) -> QueryType ---- -Retrieve the executed query’s type (shared by all elements in this stream). +Retrieves the executed query’s type (shared by all elements in this stream). [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/rust/answer/QueryAnswer.adoc b/docs/modules/ROOT/partials/rust/answer/QueryAnswer.adoc index a849efc34a..6d16775d37 100644 --- a/docs/modules/ROOT/partials/rust/answer/QueryAnswer.adoc +++ b/docs/modules/ROOT/partials/rust/answer/QueryAnswer.adoc @@ -26,7 +26,7 @@ a| `Ok(QueryType)` pub fn get_query_type(&self) -> QueryType ---- -Retrieve the executed query’s type (shared by all elements in this stream). +Retrieves the executed query’s type (shared by all elements in this stream). [caption=""] .Returns @@ -98,7 +98,7 @@ query_answer.into_rows() pub fn is_document_stream(&self) -> bool ---- -Check if the ``QueryAnswer`` is a ``ConceptDocumentStream``. +Checks if the ``QueryAnswer`` is a ``ConceptDocumentStream``. [caption=""] .Returns @@ -122,7 +122,7 @@ query_answer.is_document_stream() pub fn is_ok(&self) -> bool ---- -Check if the ``QueryAnswer`` is an ``Ok`` response. +Checks if the ``QueryAnswer`` is an ``Ok`` response. [caption=""] .Returns @@ -146,7 +146,7 @@ query_answer.is_ok() pub fn is_row_stream(&self) -> bool ---- -Check if the ``QueryAnswer`` is a ``ConceptRowStream``. +Checks if the ``QueryAnswer`` is a ``ConceptRowStream``. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/rust/concept/Concept.adoc b/docs/modules/ROOT/partials/rust/concept/Concept.adoc index 88a1871f01..a95d43c827 100644 --- a/docs/modules/ROOT/partials/rust/concept/Concept.adoc +++ b/docs/modules/ROOT/partials/rust/concept/Concept.adoc @@ -67,7 +67,7 @@ Retrieves the label of this Concept. If this is an Instance, returns the label o pub fn is_attribute(&self) -> bool ---- -Check if this Concept represents an Attribute instance from the database +Checks if this Concept represents an Attribute instance from the database [caption=""] .Returns @@ -84,7 +84,7 @@ bool pub fn is_attribute_type(&self) -> bool ---- -Check if this Concept represents an Attribute Type from the schema of the database +Checks if this Concept represents an Attribute Type from the schema of the database [caption=""] .Returns @@ -101,7 +101,7 @@ bool pub fn is_boolean(&self) -> bool ---- -Check if this Concept holds a boolean as an AttributeType, an Attribute, or a Value +Checks if this Concept holds a boolean as an AttributeType, an Attribute, or a Value [caption=""] .Returns @@ -118,7 +118,7 @@ bool pub fn is_date(&self) -> bool ---- -Check if this Concept holds a date as an AttributeType, an Attribute, or a Value +Checks if this Concept holds a date as an AttributeType, an Attribute, or a Value [caption=""] .Returns @@ -135,7 +135,7 @@ bool pub fn is_datetime(&self) -> bool ---- -Check if this Concept holds a datetime as an AttributeType, an Attribute, or a Value +Checks if this Concept holds a datetime as an AttributeType, an Attribute, or a Value [caption=""] .Returns @@ -152,7 +152,7 @@ bool pub fn is_datetime_tz(&self) -> bool ---- -Check if this Concept holds a timezoned-datetime as an AttributeType, an Attribute, or a Value +Checks if this Concept holds a timezoned-datetime as an AttributeType, an Attribute, or a Value [caption=""] .Returns @@ -169,7 +169,7 @@ bool pub fn is_decimal(&self) -> bool ---- -Check if this Concept holds a fixed-decimal as an AttributeType, an Attribute, or a Value +Checks if this Concept holds a fixed-decimal as an AttributeType, an Attribute, or a Value [caption=""] .Returns @@ -186,7 +186,7 @@ bool pub fn is_double(&self) -> bool ---- -Check if this Concept holds a double as an AttributeType, an Attribute, or a Value +Checks if this Concept holds a double as an AttributeType, an Attribute, or a Value [caption=""] .Returns @@ -203,7 +203,7 @@ bool pub fn is_duration(&self) -> bool ---- -Check if this Concept holds a duration as an AttributeType, an Attribute, or a Value +Checks if this Concept holds a duration as an AttributeType, an Attribute, or a Value [caption=""] .Returns @@ -220,7 +220,7 @@ bool pub fn is_entity(&self) -> bool ---- -Check if this Concept represents an Entity instance from the database +Checks if this Concept represents an Entity instance from the database [caption=""] .Returns @@ -237,7 +237,7 @@ bool pub fn is_entity_type(&self) -> bool ---- -Check if this Concept represents an Entity Type from the schema of the database +Checks if this Concept represents an Entity Type from the schema of the database [caption=""] .Returns @@ -254,7 +254,7 @@ bool pub fn is_instance(&self) -> bool ---- -Check if this Concept represents a stored database instance from the database. These are exactly: Entity, Relation, and Attribute +Checks if this Concept represents a stored database instance from the database. These are exactly: Entity, Relation, and Attribute Equivalent to: @@ -280,7 +280,7 @@ concept.is_entity() || concept.is_relation() || concept.is_attribute() pub fn is_integer(&self) -> bool ---- -Check if this Concept holds an integer as an AttributeType, an Attribute, or a Value +Checks if this Concept holds an integer as an AttributeType, an Attribute, or a Value [caption=""] .Returns @@ -297,7 +297,7 @@ bool pub fn is_relation(&self) -> bool ---- -Check if this Concept represents an Relation instance from the database +Checks if this Concept represents an Relation instance from the database [caption=""] .Returns @@ -314,7 +314,7 @@ bool pub fn is_relation_type(&self) -> bool ---- -Check if this Concept represents a Relation Type from the schema of the database +Checks if this Concept represents a Relation Type from the schema of the database [caption=""] .Returns @@ -331,7 +331,7 @@ bool pub fn is_role_type(&self) -> bool ---- -Check if this Concept represents a Role Type from the schema of the database +Checks if this Concept represents a Role Type from the schema of the database [caption=""] .Returns @@ -348,7 +348,7 @@ bool pub fn is_string(&self) -> bool ---- -Check if this Concept holds a string as an AttributeType, an Attribute, or a Value +Checks if this Concept holds a string as an AttributeType, an Attribute, or a Value [caption=""] .Returns @@ -365,7 +365,7 @@ bool pub fn is_struct(&self) -> bool ---- -Check if this Concept holds a struct as an AttributeType, an Attribute, or a Value +Checks if this Concept holds a struct as an AttributeType, an Attribute, or a Value [caption=""] .Returns @@ -382,7 +382,7 @@ bool pub fn is_type(&self) -> bool ---- -Check if this Concept represents a Type from the schema of the database. These are exactly: Entity Types, Relation Types, Role Types, and Attribute Types +Checks if this Concept represents a Type from the schema of the database. These are exactly: Entity Types, Relation Types, Role Types, and Attribute Types Equivalent to: @@ -408,7 +408,7 @@ concept.is_entity_type() || concept.is_relation_type() || concept.is_role_type() pub fn is_value(&self) -> bool ---- -Check if this Concept represents a Value returned by the database +Checks if this Concept represents a Value returned by the database [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/rust/connection/Address.adoc b/docs/modules/ROOT/partials/rust/connection/Address.adoc new file mode 100644 index 0000000000..1613501d34 --- /dev/null +++ b/docs/modules/ROOT/partials/rust/connection/Address.adoc @@ -0,0 +1,15 @@ +[#_struct_Address] +=== Address + +*Implements traits:* + +* `Clone` +* `Debug` +* `Default` +* `Display` +* `Eq` +* `FromStr` +* `Hash` +* `PartialEq` +* `StructuralPartialEq` + diff --git a/docs/modules/ROOT/partials/rust/connection/Addresses.adoc b/docs/modules/ROOT/partials/rust/connection/Addresses.adoc new file mode 100644 index 0000000000..c77f300d74 --- /dev/null +++ b/docs/modules/ROOT/partials/rust/connection/Addresses.adoc @@ -0,0 +1,231 @@ +[#_enum_Addresses] +=== Addresses + +A collection of server addresses used for connection. + +[caption=""] +.Enum variants +// tag::enum_constants[] +[cols=""] +[options="header"] +|=== +|Variant +a| `Direct(Vec
)` +a| `Translated(HashMap)` +|=== +// end::enum_constants[] + +// tag::methods[] +[#_enum_Addresses_contains_] +==== contains + +[source,rust] +---- +pub fn contains(&self, address: &Address) -> bool +---- + +Checks if the public address is a part of the addresses. + +[caption=""] +.Returns +[source,rust] +---- +bool +---- + +[caption=""] +.Code examples +[source,rust] +---- +addresses.contains(&address) +---- + +[#_enum_Addresses_from_address_] +==== from_address + +[source,rust] +---- +pub fn from_address(address: Address) -> Self +---- + +Prepare addresses based on a single TypeDB address. + +[caption=""] +.Returns +[source,rust] +---- +Self +---- + +[caption=""] +.Code examples +[source,rust] +---- +let address = "127.0.0.1:11729".parse().unwrap(); +Addresses::from_address(address) +---- + +[#_enum_Addresses_from_addresses_] +==== from_addresses + +[source,rust] +---- +pub fn from_addresses(addresses: impl IntoIterator) -> Self +---- + +Prepare addresses based on multiple TypeDB addresses. + +[caption=""] +.Returns +[source,rust] +---- +Self +---- + +[caption=""] +.Code examples +[source,rust] +---- +let address1 = "127.0.0.1:11729".parse().unwrap(); +let address2 = "127.0.0.1:11730".parse().unwrap(); +let address3 = "127.0.0.1:11731".parse().unwrap(); +Addresses::from_addresses([address1, address2, address3]) +---- + +[#_enum_Addresses_from_translation_] +==== from_translation + +[source,rust] +---- +pub fn from_translation(addresses: HashMap) -> Self +---- + +Prepare addresses based on multiple key-value (public-private) TypeDB address pairs. Translation map from addresses to be used by the driver for connection to addresses received from the TypeDB server(s). + +[caption=""] +.Returns +[source,rust] +---- +Self +---- + +[caption=""] +.Code examples +[source,rust] +---- +let translation: HashMap = [ + ("typedb-cloud.ext:11729".parse()?, "127.0.0.1:11729".parse()?), + ("typedb-cloud.ext:11730".parse()?, "127.0.0.1:11730".parse()?), + ("typedb-cloud.ext:11731".parse()?, "127.0.0.1:11731".parse()?) +].into(); +Addresses::from_translation(translation) +---- + +[#_enum_Addresses_len_] +==== len + +[source,rust] +---- +pub fn len(&self) -> usize +---- + +Returns the number of address entries (addresses or address pairs) in the collection. + +[caption=""] +.Returns +[source,rust] +---- +usize +---- + +[caption=""] +.Code examples +[source,rust] +---- +addresses.len() +---- + +[#_enum_Addresses_try_from_address_str_] +==== try_from_address_str + +[source,rust] +---- +pub fn try_from_address_str(address_str: impl AsRef) -> Result +---- + +Prepare addresses based on a single “host:port” string. + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[source,rust] +---- +Addresses::try_from_address_str("127.0.0.1:11729") +---- + +[#_enum_Addresses_try_from_addresses_str_] +==== try_from_addresses_str + +[source,rust] +---- +pub fn try_from_addresses_str( + addresses_str: impl IntoIterator>, +) -> Result +---- + +Prepare addresses based on multiple “host:port” strings. Is used to specify multiple addresses connect to. + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[source,rust] +---- +Addresses::try_from_addresses_str(["127.0.0.1:11729", "127.0.0.1:11730", "127.0.0.1:11731"]) +---- + +[#_enum_Addresses_try_from_translation_str_] +==== try_from_translation_str + +[source,rust] +---- +pub fn try_from_translation_str( + addresses_str: HashMap, impl AsRef>, +) -> Result +---- + +Prepare addresses based on multiple key-value (public-private) “key:port” string pairs. Translation map from addresses to be used by the driver for connection to addresses received from the TypeDB server(s). + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[source,rust] +---- +Addresses::try_from_addresses_str( + [ + ("typedb-cloud.ext:11729", "127.0.0.1:11729"), + ("typedb-cloud.ext:11730", "127.0.0.1:11730"), + ("typedb-cloud.ext:11731", "127.0.0.1:11731") + ].into() +) +---- + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/rust/connection/AvailableServerReplica.adoc b/docs/modules/ROOT/partials/rust/connection/AvailableServerReplica.adoc new file mode 100644 index 0000000000..453e4f4834 --- /dev/null +++ b/docs/modules/ROOT/partials/rust/connection/AvailableServerReplica.adoc @@ -0,0 +1,103 @@ +[#_struct_AvailableServerReplica] +=== AvailableServerReplica + +*Implements traits:* + +* `Clone` +* `Debug` +* `Eq` +* `Hash` +* `PartialEq` +* `Replica` +* `StructuralPartialEq` + +A specialization of an available ``ServerReplica`` with a known connection address. + +// tag::methods[] +[#_struct_AvailableServerReplica_address_] +==== address + +[source,rust] +---- +pub fn address(&self) -> &Address +---- + +Returns the address this replica is hosted at. + +[caption=""] +.Returns +[source,rust] +---- +&Address +---- + +[#_struct_AvailableServerReplica_id_] +==== id + +[source,rust] +---- +fn id(&self) -> u64 +---- + +Returns the id of this replica. 0 (default) if it’s not a part of a cluster. + +[caption=""] +.Returns +[source,rust] +---- +u64 +---- + +[#_struct_AvailableServerReplica_is_primary_] +==== is_primary + +[source,rust] +---- +fn is_primary(&self) -> bool +---- + +Checks whether this is the primary replica of the raft cluster. + +[caption=""] +.Returns +[source,rust] +---- +bool +---- + +[#_struct_AvailableServerReplica_role_] +==== role + +[source,rust] +---- +fn role(&self) -> Option +---- + +Returns whether this is the primary replica of the raft cluster or any of the supporting roles. + +[caption=""] +.Returns +[source,rust] +---- +Option +---- + +[#_struct_AvailableServerReplica_term_] +==== term + +[source,rust] +---- +fn term(&self) -> Option +---- + +Returns the raft protocol ‘term’ of this replica. + +[caption=""] +.Returns +[source,rust] +---- +Option +---- + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/rust/connection/ConsistencyLevel.adoc b/docs/modules/ROOT/partials/rust/connection/ConsistencyLevel.adoc new file mode 100644 index 0000000000..fa19329bab --- /dev/null +++ b/docs/modules/ROOT/partials/rust/connection/ConsistencyLevel.adoc @@ -0,0 +1,18 @@ +[#_enum_ConsistencyLevel] +=== ConsistencyLevel + +Consistency levels of operations against a distributed server. All driver methods have default recommended values, however, most of the operations can be configured in order to potentially speed up the execution (introducing risks of stale data) or test a specific replica. This setting does not affect clusters with a single node. + +[caption=""] +.Enum variants +// tag::enum_constants[] +[cols=""] +[options="header"] +|=== +|Variant +a| `Eventual` +a| `ReplicaDependent` +a| `Strong` +|=== +// end::enum_constants[] + diff --git a/docs/modules/ROOT/partials/rust/connection/Database.adoc b/docs/modules/ROOT/partials/rust/connection/Database.adoc index a29aef255d..390c82fda7 100644 --- a/docs/modules/ROOT/partials/rust/connection/Database.adoc +++ b/docs/modules/ROOT/partials/rust/connection/Database.adoc @@ -6,9 +6,10 @@ *Implements traits:* +* `Clone` * `Debug` -A TypeDB database +A TypeDB database. // tag::methods[] [#_struct_Database_delete_] @@ -37,7 +38,9 @@ pub fn delete(self: Arc) -> Result -- ==== -Deletes this database. +Deletes this database, using default strong consistency. + +See <<#_struct_Database_method_delete_with_consistency,`Self::delete_with_consistency`>> for more details and options. [caption=""] .Returns @@ -71,7 +74,82 @@ database.delete(); -- ==== -[#_struct_Database_export_to_file_schema_file_path_impl_AsRef_Path_data_file_path_impl_AsRef_Path_] +[#_struct_Database_delete_with_consistency_consistency_level_ConsistencyLevel] +==== delete_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn delete_with_consistency( + self: Arc, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn delete_with_consistency( + self: Arc, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- +==== + +Deletes this database. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +database.delete_with_consistency(ConsistencyLevel::Strong).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +database.delete_with_consistency(ConsistencyLevel::Strong); +---- + +-- +==== + +[#_struct_Database_export_to_file_] ==== export_to_file [tabs] @@ -105,6 +183,78 @@ pub fn export_to_file( -- ==== +Export a database into a schema definition and a data files saved to the disk, using default strong consistency. This is a blocking operation and may take a significant amount of time depending on the database size. + +See <<#_struct_Database_method_export_to_file_with_consistency,`Self::export_to_file_with_consistency`>> for more details and options. + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +database.export_to_file(schema_path, data_path).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +database.export_to_file(schema_path, data_path); +---- + +-- +==== + +[#_struct_Database_export_to_file_with_consistency_schema_file_path_impl_AsRef_Path_data_file_path_impl_AsRef_Path_consistency_level_ConsistencyLevel] +==== export_to_file_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn export_to_file_with_consistency( + &self, + schema_file_path: impl AsRef, + data_file_path: impl AsRef, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn export_to_file_with_consistency( + &self, + schema_file_path: impl AsRef, + data_file_path: impl AsRef, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- +==== + Export a database into a schema definition and a data files saved to the disk. This is a blocking operation and may take a significant amount of time depending on the database size. [caption=""] @@ -115,6 +265,7 @@ Export a database into a schema definition and a data files saved to the disk. T |Name |Description |Type a| `schema_file_path` a| — The path to the schema definition file to be created a| `impl AsRef` a| `data_file_path` a| — The path to the data file to be created a| `impl AsRef` +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` |=== [caption=""] @@ -133,7 +284,7 @@ async:: -- [source,rust] ---- -database.export_to_file(schema_path, data_path).await; +database.export_to_file_with_consistency(schema_path, data_path, ConsistencyLevel::Strong).await; ---- -- @@ -143,7 +294,7 @@ sync:: -- [source,rust] ---- -database.export_to_file(schema_path, data_path); +database.export_to_file_with_consistency(schema_path, data_path, ConsistencyLevel::Strong); ---- -- @@ -166,80 +317,145 @@ Retrieves the database name as a string. &str ---- -[#_struct_Database_preferred_replica_info_] -==== preferred_replica_info +[#_struct_Database_schema_] +==== schema +[tabs] +==== +async:: ++ +-- [source,rust] ---- -pub fn preferred_replica_info(&self) -> Option +pub async fn schema(&self) -> Result ---- -Returns the preferred replica for this database. Operations which can be run on any replica will prefer to use this replica. _Only works in TypeDB Cloud / Enterprise_ +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn schema(&self) -> Result +---- + +-- +==== + +Returns a full schema text as a valid TypeQL define query string, using default strong consistency. + +See <<#_struct_Database_method_schema_with_consistency,`Self::schema_with_consistency`>> for more details and options. [caption=""] .Returns [source,rust] ---- -Option +Result ---- [caption=""] .Code examples +[tabs] +==== +async:: ++ +-- [source,rust] ---- -database.preferred_replica_info(); +database.schema().await; ---- -[#_struct_Database_primary_replica_info_] -==== primary_replica_info +-- +sync:: ++ +-- [source,rust] ---- -pub fn primary_replica_info(&self) -> Option +database.schema(); ---- -Returns the primary replica for this database. _Only works in TypeDB Cloud / Enterprise_ +-- +==== -[caption=""] -.Returns -[source,rust] ----- -Option ----- +[#_struct_Database_schema_with_consistency_consistency_level_ConsistencyLevel] +==== schema_with_consistency -[caption=""] -.Code examples +[tabs] +==== +async:: ++ +-- [source,rust] ---- -database.primary_replica_info() +pub async fn schema_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result ---- -[#_struct_Database_replicas_info_] -==== replicas_info +-- +sync:: ++ +-- [source,rust] ---- -pub fn replicas_info(&self) -> Vec +pub fn schema_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result ---- -Returns the ``Replica`` instances for this database. _Only works in TypeDB Cloud / Enterprise_ +-- +==== + +Returns a full schema text as a valid TypeQL define query string. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` +|=== [caption=""] .Returns [source,rust] ---- -Vec +Result ---- [caption=""] .Code examples +[tabs] +==== +async:: ++ +-- [source,rust] ---- -database.replicas_info() +database.schema_with_consistency(ConsistencyLevel::Strong).await; ---- -[#_struct_Database_schema_] -==== schema +-- + +sync:: ++ +-- +[source,rust] +---- +database.schema_with_consistency(ConsistencyLevel::Strong); +---- + +-- +==== + +[#_struct_Database_type_schema_] +==== type_schema [tabs] ==== @@ -248,7 +464,7 @@ async:: -- [source,rust] ---- -pub async fn schema(&self) -> Result +pub async fn type_schema(&self) -> Result ---- -- @@ -258,13 +474,15 @@ sync:: -- [source,rust] ---- -pub fn schema(&self) -> Result +pub fn type_schema(&self) -> Result ---- -- ==== -Returns a full schema text as a valid TypeQL define query string. +Returns the types in the schema as a valid TypeQL define query string, using default strong consistency. + +See <<#_struct_Database_method_type_schema_with_consistency,`Self::type_schema_with_consistency`>> for more details and options. [caption=""] .Returns @@ -282,7 +500,7 @@ async:: -- [source,rust] ---- -database.schema().await; +database.type_schema().await; ---- -- @@ -292,14 +510,14 @@ sync:: -- [source,rust] ---- -database.schema(); +database.type_schema(); ---- -- ==== -[#_struct_Database_type_schema_] -==== type_schema +[#_struct_Database_type_schema_with_consistency_consistency_level_ConsistencyLevel] +==== type_schema_with_consistency [tabs] ==== @@ -308,7 +526,10 @@ async:: -- [source,rust] ---- -pub async fn type_schema(&self) -> Result +pub async fn type_schema_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result ---- -- @@ -318,7 +539,10 @@ sync:: -- [source,rust] ---- -pub fn type_schema(&self) -> Result +pub fn type_schema_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result ---- -- @@ -326,6 +550,15 @@ pub fn type_schema(&self) -> Result Returns the types in the schema as a valid TypeQL define query string. +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` +|=== + [caption=""] .Returns [source,rust] @@ -342,7 +575,7 @@ async:: -- [source,rust] ---- -database.type_schema().await; +database.type_schema_with_consistency(ConsistencyLevel::Strong).await; ---- -- @@ -352,7 +585,7 @@ sync:: -- [source,rust] ---- -database.type_schema(); +database.type_schema_with_consistency(ConsistencyLevel::Strong); ---- -- diff --git a/docs/modules/ROOT/partials/rust/connection/DatabaseManager.adoc b/docs/modules/ROOT/partials/rust/connection/DatabaseManager.adoc index 61f213379a..f7e5d6d58e 100644 --- a/docs/modules/ROOT/partials/rust/connection/DatabaseManager.adoc +++ b/docs/modules/ROOT/partials/rust/connection/DatabaseManager.adoc @@ -37,7 +37,9 @@ pub fn all(&self) -> Result>> -- ==== -Retrieves all databases present on the TypeDB server +Retrieves all databases present on the TypeDB server, using default strong consistency. + +See <<#_struct_DatabaseManager_method_all_with_consistency,`Self::all_with_consistency`>> for more details and options. [caption=""] .Returns @@ -71,7 +73,82 @@ driver.databases().all(); -- ==== -[#_struct_DatabaseManager_contains_name_impl_Into_String_] +[#_struct_DatabaseManager_all_with_consistency_consistency_level_ConsistencyLevel] +==== all_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn all_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result>> +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn all_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result>> +---- + +-- +==== + +Retrieves all databases present on the TypeDB server. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result>> +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.databases().all_with_consistency(ConsistencyLevel::Strong).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.databases().all_with_consistency(ConsistencyLevel::Strong); +---- + +-- +==== + +[#_struct_DatabaseManager_contains_] ==== contains [tabs] @@ -97,7 +174,77 @@ pub fn contains(&self, name: impl Into) -> Result -- ==== -Checks if a database with the given name exists +Checks if a database with the given name exists, using default strong consistency. + +See <<#_struct_DatabaseManager_method_contains_with_consistency,`Self::contains_with_consistency`>> for more details and options. + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.databases().contains(name).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.databases().contains(name); +---- + +-- +==== + +[#_struct_DatabaseManager_contains_with_consistency_name_impl_Into_String_consistency_level_ConsistencyLevel] +==== contains_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn contains_with_consistency( + &self, + name: impl Into, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn contains_with_consistency( + &self, + name: impl Into, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- +==== + +Checks if a database with the given name exists. [caption=""] .Input parameters @@ -106,6 +253,7 @@ Checks if a database with the given name exists |=== |Name |Description |Type a| `name` a| — The database name to be checked a| `impl Into` +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` |=== [caption=""] @@ -124,7 +272,7 @@ async:: -- [source,rust] ---- -driver.databases().contains(name).await; +driver.databases().contains_with_consistency(name, ConsistencyLevel::Strong).await; ---- -- @@ -134,7 +282,7 @@ sync:: -- [source,rust] ---- -driver.databases().contains(name); +driver.databases().contains_with_consistency(name, ConsistencyLevel::Strong); ---- -- @@ -166,7 +314,9 @@ pub fn create(&self, name: impl Into) -> Result -- ==== -Create a database with the given name +Creates a database with the given name, using default strong consistency. + +See <<#_struct_DatabaseManager_method_create_with_consistency,`Self::create_with_consistency`>> for more details and options. [caption=""] .Input parameters @@ -209,8 +359,8 @@ driver.databases().create(name); -- ==== -[#_struct_DatabaseManager_get_name_impl_AsRef_str_] -==== get +[#_struct_DatabaseManager_create_with_consistency_name_impl_Into_String_consistency_level_ConsistencyLevel] +==== create_with_consistency [tabs] ==== @@ -219,7 +369,11 @@ async:: -- [source,rust] ---- -pub async fn get(&self, name: impl AsRef) -> Result> +pub async fn create_with_consistency( + &self, + name: impl Into, + consistency_level: ConsistencyLevel, +) -> Result ---- -- @@ -229,13 +383,17 @@ sync:: -- [source,rust] ---- -pub fn get(&self, name: impl AsRef) -> Result> +pub fn create_with_consistency( + &self, + name: impl Into, + consistency_level: ConsistencyLevel, +) -> Result ---- -- ==== -Retrieve the database with the given name. +Creates a database with the given name [caption=""] .Input parameters @@ -243,9 +401,72 @@ Retrieve the database with the given name. [options="header"] |=== |Name |Description |Type -a| `name` a| — The name of the database to retrieve a| `impl AsRef` +a| `name` a| — The name of the database to be created a| `impl Into` +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` |=== +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.databases().create_with_consistency(name, ConsistencyLevel::Strong).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.databases().create_with_consistency(name, ConsistencyLevel::Strong); +---- + +-- +==== + +[#_struct_DatabaseManager_get_] +==== get + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn get(&self, name: impl Into) -> Result> +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn get(&self, name: impl Into) -> Result> +---- + +-- +==== + +Retrieves the database with the given name, using default strong consistency. + +See <<#_struct_DatabaseManager_method_get_with_consistency,`Self::get_with_consistency`>> for more details and options. + [caption=""] .Returns [source,rust] @@ -278,6 +499,84 @@ driver.databases().get(name); -- ==== +[#_struct_DatabaseManager_get_with_consistency_name_impl_Into_String_consistency_level_ConsistencyLevel] +==== get_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn get_with_consistency( + &self, + name: impl Into, + consistency_level: ConsistencyLevel, +) -> Result> +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn get_with_consistency( + &self, + name: impl Into, + consistency_level: ConsistencyLevel, +) -> Result> +---- + +-- +==== + +Retrieves the database with the given name. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `name` a| — The name of the database to retrieve a| `impl Into` +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result> +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.databases().get_with_consistency(name, ConsistencyLevel::Strong).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.databases().get_with_consistency(name, ConsistencyLevel::Strong); +---- + +-- +==== + [#_struct_DatabaseManager_import_from_file_name_impl_Into_String_schema_impl_Into_String_data_file_path_impl_AsRef_Path_] ==== import_from_file @@ -314,7 +613,7 @@ pub fn import_from_file( -- ==== -Create a database with the given name based on previously exported another database’s data loaded from a file. This is a blocking operation and may take a significant amount of time depending on the database size. +Creates a database with the given name based on previously exported another database’s data loaded from a file. Always uses strong consistency. This is a blocking operation and may take a significant amount of time depending on the database size. [caption=""] .Input parameters diff --git a/docs/modules/ROOT/partials/rust/connection/DriverOptions.adoc b/docs/modules/ROOT/partials/rust/connection/DriverOptions.adoc index 38bd4a2736..3d30a4783a 100644 --- a/docs/modules/ROOT/partials/rust/connection/DriverOptions.adoc +++ b/docs/modules/ROOT/partials/rust/connection/DriverOptions.adoc @@ -8,59 +8,134 @@ * `Clone` * `Debug` +* `Default` -User connection settings for connecting to TypeDB. +TypeDB driver connection options. ``DriverOptions`` object can be used to override the default driver behavior while connecting to TypeDB. + +[caption=""] +.Fields +// tag::properties[] +[cols=",,"] +[options="header"] +|=== +|Name |Type |Description +a| `primary_failover_retries` a| `usize` a| Limits the number of attempts to redirect a strongly consistent request to another primary replica in case of a failure due to the change of replica roles. Defaults to 1. +a| `replica_discovery_attempts` a| `Option` a| Limits the number of driver attempts to discover a single working replica to perform an operation in case of a replica unavailability. Every replica is tested once, which means that at most: + + {limit} operations are performed if the limit <= the number of replicas. + {number of replicas} operations are performed if the limit > the number of replicas. + {number of replicas} operations are performed if the limit is None. Affects every eventually consistent operation, including redirect failover, when the new primary replica is unknown. Defaults to None. + +a| `request_timeout` a| `Duration` a| Specifies the maximum time to wait for a response to a unary RPC request. This applies to operations like database creation, user management, and initial transaction opening. It does NOT apply to operations within transactions (queries, commits). Defaults to 2 hours. +a| `tls_config` a| `DriverTlsConfig` a| Specifies the TLS configuration of the connection to TypeDB. WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. Defaults to an enabled TLS configuration based on the system’s native trust roots. +a| `use_replication` a| `bool` a| Specifies whether the connection to TypeDB can use cluster replicas provided by the server or it should be limited to a single configured address. Defaults to true. +|=== +// end::properties[] // tag::methods[] -[#_struct_DriverOptions_is_tls_enabled_] -==== is_tls_enabled +[#_struct_DriverOptions_new_] +==== new [source,rust] ---- -pub fn is_tls_enabled(&self) -> bool +pub fn new(tls_config: DriverTlsConfig) -> Self ---- -Retrieves whether TLS is enabled for the connection. +Creates new ``DriverOptions`` to configure connections to TypeDB using custom TLS settings. WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. [caption=""] .Returns [source,rust] ---- -bool +Self ---- -[#_struct_DriverOptions_new_is_tls_enabled_bool_tls_root_ca_Option_Path_] -==== new +[#_struct_DriverOptions_primary_failover_retries_] +==== primary_failover_retries [source,rust] ---- -pub fn new(is_tls_enabled: bool, tls_root_ca: Option<&Path>) -> Result +pub fn primary_failover_retries(self, primary_failover_retries: usize) -> Self ---- -Creates a credentials with username and password. Specifies the connection must use TLS +Limits the number of attempts to redirect a strongly consistent request to another primary replica in case of a failure due to the change of replica roles. Defaults to 1. [caption=""] -.Input parameters -[cols=",,"] -[options="header"] -|=== -|Name |Description |Type -a| `is_tls_enabled` a| — Specify whether the connection to TypeDB Server must be done over TLS. a| `bool` -a| `tls_root_ca` a| — Path to the CA certificate to use for authenticating server certificates. a| `Option<&Path>` -|=== +.Returns +[source,rust] +---- +Self +---- + +[#_struct_DriverOptions_replica_discovery_attempts_] +==== replica_discovery_attempts + +[source,rust] +---- +pub fn replica_discovery_attempts( + self, + replica_discovery_attempts: Option, +) -> Self +---- + +Limits the number of driver attempts to discover a single working replica to perform an operation in case of a replica unavailability. Every replica is tested once, which means that at most: [caption=""] .Returns [source,rust] ---- -Result +Self ---- +[#_struct_DriverOptions_request_timeout_] +==== request_timeout + +[source,rust] +---- +pub fn request_timeout(self, request_timeout: Duration) -> Self +---- + +Specifies the maximum time to wait for a response to a unary RPC request. This applies to operations like database creation, user management, and initial transaction opening. It does NOT apply to operations within transactions (queries, commits). Defaults to 2 hours. + +[caption=""] +.Returns +[source,rust] +---- +Self +---- + +[#_struct_DriverOptions_tls_config_] +==== tls_config + +[source,rust] +---- +pub fn tls_config(self, tls_config: DriverTlsConfig) -> Self +---- + +Override the existing TLS configuration. WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + [caption=""] -.Code examples +.Returns +[source,rust] +---- +Self +---- + +[#_struct_DriverOptions_use_replication_] +==== use_replication + +[source,rust] +---- +pub fn use_replication(self, use_replication: bool) -> Self +---- + +Specifies whether the connection to TypeDB can use cluster replicas provided by the server or it should be limited to the provided address. If set to false, restricts the driver to only a single address. + +[caption=""] +.Returns [source,rust] ---- -DriverOptions::new(true, Some(&path_to_ca)); +Self ---- // end::methods[] diff --git a/docs/modules/ROOT/partials/rust/connection/DriverTlsConfig.adoc b/docs/modules/ROOT/partials/rust/connection/DriverTlsConfig.adoc new file mode 100644 index 0000000000..320cc350a5 --- /dev/null +++ b/docs/modules/ROOT/partials/rust/connection/DriverTlsConfig.adoc @@ -0,0 +1,164 @@ +[#_struct_DriverTlsConfig] +=== DriverTlsConfig + +*Implements traits:* + +* `Clone` +* `Debug` +* `Default` + +TLS configuration for the TypeDB driver. + +``DriverTlsConfig`` represents a fully constructed and validated TLS configuration. If TLS is enabled, the underlying TLS config is built eagerly at construction time, ensuring that no connection attempt can observe a partially-configured TLS state. + +The driver defaults to using TLS with native system trust roots. This matches typical system and container deployments while still allowing explicit opt-out or custom PKI configuration. + +// tag::methods[] +[#_struct_DriverTlsConfig_disabled_] +==== disabled + +[source,rust] +---- +pub fn disabled() -> Self +---- + +Disable TLS entirely (NOT recommended for production). + +Disabling TLS causes credentials and data to be transmitted in plaintext. This should only be used in trusted, local, or test environments. + +[caption=""] +.Returns +[source,rust] +---- +Self +---- + +[caption=""] +.Code examples +[source,rust] +---- +let tls = DriverTlsConfig::disabled(); +---- + +[#_struct_DriverTlsConfig_enabled_with_native_root_ca_] +==== enabled_with_native_root_ca + +[source,rust] +---- +pub fn enabled_with_native_root_ca() -> Self +---- + +Default TLS using system trust roots. + +[caption=""] +.Returns +[source,rust] +---- +Self +---- + +[caption=""] +.Code examples +[source,rust] +---- +let tls = DriverTlsConfig::enabled_with_native_root_ca(); +---- + +[#_struct_DriverTlsConfig_enabled_with_root_ca_] +==== enabled_with_root_ca + +[source,rust] +---- +pub fn enabled_with_root_ca(tls_root_ca: &Path) -> Result +---- + +TLS with a custom root CA. + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[source,rust] +---- +let tls = DriverTlsConfig::enabled_with_root_ca("path/to/ca-certificate.pem").unwrap(); +---- + +[#_struct_DriverTlsConfig_is_enabled_] +==== is_enabled + +[source,rust] +---- +pub fn is_enabled(&self) -> bool +---- + +Returns whether TLS is enabled in the configuration. + +[caption=""] +.Returns +[source,rust] +---- +bool +---- + +[caption=""] +.Code examples +[source,rust] +---- +config.is_enabled() +---- + +[#_struct_DriverTlsConfig_network_config_] +==== network_config + +[source,rust] +---- +pub fn network_config(&self) -> Option<&NetworkTlsConfig> +---- + +Returns the network TLS config object, if present. + +[caption=""] +.Returns +[source,rust] +---- +Option<&NetworkTlsConfig> +---- + +[caption=""] +.Code examples +[source,rust] +---- +config.network_config() +---- + +[#_struct_DriverTlsConfig_root_ca_path_] +==== root_ca_path + +[source,rust] +---- +pub fn root_ca_path(&self) -> Option<&Path> +---- + +Returns the custom root CA path, if provided. + +[caption=""] +.Returns +[source,rust] +---- +Option<&Path> +---- + +[caption=""] +.Code examples +[source,rust] +---- +config.root_ca_path() +---- + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/rust/connection/ReplicaRole.adoc b/docs/modules/ROOT/partials/rust/connection/ReplicaRole.adoc new file mode 100644 index 0000000000..b26bd431ee --- /dev/null +++ b/docs/modules/ROOT/partials/rust/connection/ReplicaRole.adoc @@ -0,0 +1,18 @@ +[#_enum_ReplicaRole] +=== ReplicaRole + +This enum is used to specify the type of replica. + +[caption=""] +.Enum variants +// tag::enum_constants[] +[cols=""] +[options="header"] +|=== +|Variant +a| `Candidate = 1` +a| `Primary = 0` +a| `Secondary = 2` +|=== +// end::enum_constants[] + diff --git a/docs/modules/ROOT/partials/rust/connection/ServerReplica.adoc b/docs/modules/ROOT/partials/rust/connection/ServerReplica.adoc new file mode 100644 index 0000000000..d106e4ebaf --- /dev/null +++ b/docs/modules/ROOT/partials/rust/connection/ServerReplica.adoc @@ -0,0 +1,37 @@ +[#_enum_ServerReplica] +=== ServerReplica + +The metadata and state of an individual raft replica of a driver connection. + +[caption=""] +.Enum variants +// tag::enum_constants[] +[cols=""] +[options="header"] +|=== +|Variant +a| `Available(AvailableServerReplica)` +a| `Unavailable` +|=== +// end::enum_constants[] + +// tag::methods[] +[#_enum_ServerReplica_address_] +==== address + +[source,rust] +---- +pub fn address(&self) -> Option<&Address> +---- + +Returns the address this replica is hosted at. None if the information is unavailable. + +[caption=""] +.Returns +[source,rust] +---- +Option<&Address> +---- + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/rust/connection/ServerVersion.adoc b/docs/modules/ROOT/partials/rust/connection/ServerVersion.adoc new file mode 100644 index 0000000000..916ffbce46 --- /dev/null +++ b/docs/modules/ROOT/partials/rust/connection/ServerVersion.adoc @@ -0,0 +1,48 @@ +[#_struct_ServerVersion] +=== ServerVersion + +*Implements traits:* + +* `Clone` +* `Debug` +* `Display` + +A full TypeDB server’s version specification + +// tag::methods[] +[#_struct_ServerVersion_distribution_] +==== distribution + +[source,rust] +---- +pub fn distribution(&self) -> &str +---- + +Retrieves the server’s distribution. + +[caption=""] +.Returns +[source,rust] +---- +&str +---- + +[#_struct_ServerVersion_version_] +==== version + +[source,rust] +---- +pub fn version(&self) -> &str +---- + +Retrieves the server’s version number. + +[caption=""] +.Returns +[source,rust] +---- +&str +---- + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/rust/connection/Trait_Replica.adoc b/docs/modules/ROOT/partials/rust/connection/Trait_Replica.adoc new file mode 100644 index 0000000000..e5020d8d8a --- /dev/null +++ b/docs/modules/ROOT/partials/rust/connection/Trait_Replica.adoc @@ -0,0 +1,78 @@ +[#_trait_Replica] +=== Trait Replica + +*Implementors:* + +* `AvailableServerReplica` + +// tag::methods[] +[#_trait_Replica_id_] +==== id + +[source,rust] +---- +fn id(&self) -> u64 +---- + +Returns the id of this replica. 0 (default) if it’s not a part of a cluster. + +[caption=""] +.Returns +[source,rust] +---- +u64 +---- + +[#_trait_Replica_is_primary_] +==== is_primary + +[source,rust] +---- +fn is_primary(&self) -> bool +---- + +Checks whether this is the primary replica of the raft cluster. + +[caption=""] +.Returns +[source,rust] +---- +bool +---- + +[#_trait_Replica_role_] +==== role + +[source,rust] +---- +fn role(&self) -> Option +---- + +Returns whether this is the primary replica of the raft cluster or any of the supporting roles. + +[caption=""] +.Returns +[source,rust] +---- +Option +---- + +[#_trait_Replica_term_] +==== term + +[source,rust] +---- +fn term(&self) -> Option +---- + +Returns the raft protocol ‘term’ of this replica. + +[caption=""] +.Returns +[source,rust] +---- +Option +---- + +// end::methods[] + diff --git a/docs/modules/ROOT/partials/rust/connection/TypeDBDriver.adoc b/docs/modules/ROOT/partials/rust/connection/TypeDBDriver.adoc index 5d3fef2b86..969c0d96ec 100644 --- a/docs/modules/ROOT/partials/rust/connection/TypeDBDriver.adoc +++ b/docs/modules/ROOT/partials/rust/connection/TypeDBDriver.adoc @@ -11,6 +11,123 @@ A connection to a TypeDB server which serves as the starting point for all interaction. // tag::methods[] +[#_struct_TypeDBDriver_configured_addresses_] +==== configured_addresses + +[source,rust] +---- +pub fn configured_addresses(&self) -> &Addresses +---- + +The ``Addresses`` this connection is configured to. + +[caption=""] +.Returns +[source,rust] +---- +&Addresses +---- + +[caption=""] +.Code examples +[source,rust] +---- +driver.configured_addresses() +---- + +[#_struct_TypeDBDriver_databases_] +==== databases + +[source,rust] +---- +pub fn databases(&self) -> &DatabaseManager +---- + +The ``DatabaseManager`` for this connection, providing access to database management methods. + +[caption=""] +.Returns +[source,rust] +---- +&DatabaseManager +---- + +[caption=""] +.Code examples +[source,rust] +---- +driver.databases() +---- + +[#_struct_TypeDBDriver_deregister_replica_replica_id_u64] +==== deregister_replica + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn deregister_replica(&self, replica_id: u64) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn deregister_replica(&self, replica_id: u64) -> Result +---- + +-- +==== + +Deregisters a replica from the cluster the driver is currently connected to. This replica will no longer play a raft role in this cluster. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `replica_id` a| — The numeric identifier of the deregistered replica a| `u64` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.deregister_replica(2).await +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.deregister_replica(2) +---- + +-- +==== + [#_struct_TypeDBDriver_force_close_] ==== force_close @@ -59,7 +176,7 @@ bool driver.is_open() ---- -[#_struct_TypeDBDriver_new_address_impl_AsRef_str_credentials_Credentials_driver_options_DriverOptions] +[#_struct_TypeDBDriver_new_addresses_Addresses_credentials_Credentials_driver_options_DriverOptions] ==== new [tabs] @@ -70,7 +187,7 @@ async:: [source,rust] ---- pub async fn new( - address: impl AsRef, + addresses: Addresses, credentials: Credentials, driver_options: DriverOptions, ) -> Result @@ -84,7 +201,7 @@ sync:: [source,rust] ---- pub fn new( - address: impl AsRef, + addresses: Addresses, credentials: Credentials, driver_options: DriverOptions, ) -> Result @@ -101,7 +218,7 @@ Creates a new TypeDB Server connection. [options="header"] |=== |Name |Description |Type -a| `address` a| — The address (host:port) on which the TypeDB Server is running a| `impl AsRef` +a| `addresses` a| — The address(es) of the TypeDB Server(s), provided in a unified format a| `Addresses` a| `credentials` a| — The Credentials to connect with a| `Credentials` a| `driver_options` a| — The DriverOptions to connect with a| `DriverOptions` |=== @@ -122,7 +239,7 @@ async:: -- [source,rust] ---- -TypeDBDriver::new("127.0.0.1:1729", Credentials::new("username", "password"), DriverOptions::new(true, None)).await +TypeDBDriver::new(Addresses::try_from_address_str("127.0.0.1:1729").unwrap(), Credentials::new("username", "password"), DriverOptions::new(true, None)).await ---- -- @@ -132,13 +249,13 @@ sync:: -- [source,rust] ---- -TypeDBDriver::new("127.0.0.1:1729", Credentials::new("username", "password"), DriverOptions::new(true, None)) +TypeDBDriver::new(Addresses::try_from_address_str("127.0.0.1:1729").unwrap(), Credentials::new("username", "password"), DriverOptions::new(true, None)) ---- -- ==== -[#_struct_TypeDBDriver_new_with_description_address_impl_AsRef_str_credentials_Credentials_driver_options_DriverOptions_driver_lang_impl_AsRef_str_] +[#_struct_TypeDBDriver_new_with_description_addresses_Addresses_credentials_Credentials_driver_options_DriverOptions_driver_lang_impl_AsRef_str_] ==== new_with_description [tabs] @@ -149,7 +266,7 @@ async:: [source,rust] ---- pub async fn new_with_description( - address: impl AsRef, + addresses: Addresses, credentials: Credentials, driver_options: DriverOptions, driver_lang: impl AsRef, @@ -164,7 +281,7 @@ sync:: [source,rust] ---- pub fn new_with_description( - address: impl AsRef, + addresses: Addresses, credentials: Credentials, driver_options: DriverOptions, driver_lang: impl AsRef, @@ -182,7 +299,7 @@ Creates a new TypeDB Server connection with a description. This method is genera [options="header"] |=== |Name |Description |Type -a| `address` a| — The address (host:port) on which the TypeDB Server is running a| `impl AsRef` +a| `addresses` a| — The address(es) of the TypeDB Server(s), provided in a unified format a| `Addresses` a| `credentials` a| — The Credentials to connect with a| `Credentials` a| `driver_options` a| — The DriverOptions to connect with a| `DriverOptions` a| `driver_lang` a| — The language of the driver connecting to the server a| `impl AsRef` @@ -204,7 +321,7 @@ async:: -- [source,rust] ---- -TypeDBDriver::new_with_description("127.0.0.1:1729", Credentials::new("username", "password"), DriverOptions::new(true, None), "rust").await +TypeDBDriver::new_with_description(Addresses::try_from_address_str("127.0.0.1:1729").unwrap(), Credentials::new("username", "password"), DriverOptions::new(true, None), "rust").await ---- -- @@ -214,14 +331,38 @@ sync:: -- [source,rust] ---- -TypeDBDriver::new_with_description("127.0.0.1:1729", Credentials::new("username", "password"), DriverOptions::new(true, None), "rust") +TypeDBDriver::new_with_description(Addresses::try_from_address_str("127.0.0.1:1729").unwrap(), Credentials::new("username", "password"), DriverOptions::new(true, None), "rust") ---- -- ==== -[#_struct_TypeDBDriver_transaction_] -==== transaction +[#_struct_TypeDBDriver_options_] +==== options + +[source,rust] +---- +pub fn options(&self) -> &DriverOptions +---- + +The ``DriverOptions`` for this connection. + +[caption=""] +.Returns +[source,rust] +---- +&DriverOptions +---- + +[caption=""] +.Code examples +[source,rust] +---- +driver.options() +---- + +[#_struct_TypeDBDriver_primary_replica_] +==== primary_replica [tabs] ==== @@ -230,11 +371,7 @@ async:: -- [source,rust] ---- -pub async fn transaction( - &self, - database_name: impl AsRef, - transaction_type: TransactionType, -) -> Result +pub async fn primary_replica(&self) -> Result> ---- -- @@ -244,27 +381,50 @@ sync:: -- [source,rust] ---- -pub fn transaction( - &self, - database_name: impl AsRef, - transaction_type: TransactionType, -) -> Result +pub fn primary_replica(&self) -> Result> ---- -- ==== -Opens a transaction with default options. See <<#_struct_TypeDBDriver_method_transaction_with_options,`TypeDBDriver::transaction_with_options`>> +Retrieves the server’s primary replica, if exists, using default strong consistency. + +See <<#_struct_TypeDBDriver_method_primary_replica_with_consistency,`Self::primary_replica_with_consistency`>> for more details and options. [caption=""] .Returns [source,rust] ---- -Result +Result> ---- -[#_struct_TypeDBDriver_transaction_with_options_database_name_impl_AsRef_str_transaction_type_TransactionType_options_TransactionOptions] -==== transaction_with_options +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.primary_replica().await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.primary_replica(); +---- + +-- +==== + +[#_struct_TypeDBDriver_primary_replica_with_consistency_consistency_level_ConsistencyLevel] +==== primary_replica_with_consistency [tabs] ==== @@ -273,12 +433,10 @@ async:: -- [source,rust] ---- -pub async fn transaction_with_options( +pub async fn primary_replica_with_consistency( &self, - database_name: impl AsRef, - transaction_type: TransactionType, - options: TransactionOptions, -) -> Result + consistency_level: ConsistencyLevel, +) -> Result> ---- -- @@ -288,18 +446,16 @@ sync:: -- [source,rust] ---- -pub fn transaction_with_options( +pub fn primary_replica_with_consistency( &self, - database_name: impl AsRef, - transaction_type: TransactionType, - options: TransactionOptions, -) -> Result + consistency_level: ConsistencyLevel, +) -> Result> ---- -- ==== -Performs a TypeQL query in this transaction. +Retrieves the server’s primary replica, if exists. [caption=""] .Input parameters @@ -307,23 +463,628 @@ Performs a TypeQL query in this transaction. [options="header"] |=== |Name |Description |Type -a| `database_name` a| — The name of the database to connect to a| `impl AsRef` -a| `transaction_type` a| — The TransactionType to open the transaction with a| `TransactionType` -a| `options` a| — The TransactionOptions to open the transaction with a| `TransactionOptions` +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` |=== [caption=""] .Returns [source,rust] ---- -Result +Result> ---- [caption=""] .Code examples +[tabs] +==== +async:: ++ +-- [source,rust] ---- -transaction.transaction_with_options(database_name, transaction_type, options) +driver.primary_replica_with_consistency(ConsistencyLevel::Strong).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.primary_replica_with_consistency(ConsistencyLevel::Strong); +---- + +-- +==== + +[#_struct_TypeDBDriver_register_replica_replica_id_u64_address_String] +==== register_replica + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn register_replica(&self, replica_id: u64, address: String) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn register_replica(&self, replica_id: u64, address: String) -> Result +---- + +-- +==== + +Registers a new replica in the cluster the driver is currently connected to. The registered replica will become available eventually, depending on the behavior of the whole cluster. To register a replica, its clustering address should be passed, not the connection address. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `replica_id` a| — The numeric identifier of the new replica a| `u64` +a| `address` a| — The clustering address of the TypeDB replica as a string a| `String` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.register_replica(2, "127.0.0.1:2729").await +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.register_replica(2, "127.0.0.1:2729") +---- + +-- +==== + +[#_struct_TypeDBDriver_replicas_] +==== replicas + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn replicas(&self) -> Result> +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn replicas(&self) -> Result> +---- + +-- +==== + +Retrieves the server’s replicas, using default strong consistency. + +See <<#_struct_TypeDBDriver_method_replicas_with_consistency,`Self::replicas_with_consistency`>> for more details and options. + +[caption=""] +.Returns +[source,rust] +---- +Result> +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.replicas().await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.replicas(); +---- + +-- +==== + +[#_struct_TypeDBDriver_replicas_with_consistency_consistency_level_ConsistencyLevel] +==== replicas_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn replicas_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result> +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn replicas_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result> +---- + +-- +==== + +Retrieves the server’s replicas, using default strong consistency. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result> +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.replicas_with_consistency(ConsistencyLevel::Strong).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.replicas_with_consistency(); +---- + +-- +==== + +[#_struct_TypeDBDriver_server_version_] +==== server_version + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn server_version(&self) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn server_version(&self) -> Result +---- + +-- +==== + +Retrieves the server’s version, using default strong consistency. + +See <<#_struct_TypeDBDriver_method_server_version_with_consistency,`Self::server_version_with_consistency`>> for more details and options. + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.server_version().await +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.server_version() +---- + +-- +==== + +[#_struct_TypeDBDriver_server_version_with_consistency_consistency_level_ConsistencyLevel] +==== server_version_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn server_version_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn server_version_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- +==== + +Retrieves the server’s version, using default strong consistency. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.server_version_with_consistency(ConsistencyLevel::Strong).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.server_version_with_consistency(ConsistencyLevel::Strong); +---- + +-- +==== + +[#_struct_TypeDBDriver_transaction_] +==== transaction + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn transaction( + &self, + database_name: impl AsRef, + transaction_type: TransactionType, +) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn transaction( + &self, + database_name: impl AsRef, + transaction_type: TransactionType, +) -> Result +---- + +-- +==== + +Opens a transaction with default options. + +See <<#_struct_TypeDBDriver_method_transaction_with_options,`TypeDBDriver::transaction_with_options`>> for more details. + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.users().all_with_consistency(ConsistencyLevel::Strong).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.users().all_with_consistency(ConsistencyLevel::Strong); +---- + +-- +==== + +[#_struct_TypeDBDriver_transaction_with_options_options_TransactionOptions_database_name_impl_AsRef_str_transaction_type_TransactionType_options_TransactionOptions] +==== transaction_with_options + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn transaction_with_options( + &self, + database_name: impl AsRef, + transaction_type: TransactionType, + options: TransactionOptions, +) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn transaction_with_options( + &self, + database_name: impl AsRef, + transaction_type: TransactionType, + options: TransactionOptions, +) -> Result +---- + +-- +==== + +Opens a new transaction with the following consistency level: + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `options` a| read transaction - strong consistency, can be overridden through ; a| `TransactionOptions` +a| `database_name` a| — The name of the database to connect to a| `impl AsRef` +a| `transaction_type` a| — The TransactionType to open the transaction with a| `TransactionType` +a| `options` a| — The TransactionOptions to open the transaction with a| `TransactionOptions` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +transaction.transaction_with_options(database_name, transaction_type, options).await +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +transaction.transaction_with_options(database_name, transaction_type, options) +---- + +-- +==== + +[#_struct_TypeDBDriver_update_address_translation_addresses_Addresses] +==== update_address_translation + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn update_address_translation(&self, addresses: Addresses) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn update_address_translation(&self, addresses: Addresses) -> Result +---- + +-- +==== + +Updates address translation of the driver. This lets you actualize new translation information without recreating the driver from scratch. Useful after registering new replicas requiring address translation. This operation will update existing connections using the provided addresses. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `addresses` a| — Addresses containing the new address translation information a| `Addresses` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.update_address_translation(Addresses::try_from_translation_str([("typedb-cloud.ext:11729", "127.0.0.1:1729")].into()).unwrap()).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.update_address_translation(Addresses::try_from_translation_str([("typedb-cloud.ext:11729", "127.0.0.1:1729")].into()).unwrap()); +---- + +-- +==== + +[#_struct_TypeDBDriver_users_] +==== users + +[source,rust] +---- +pub fn users(&self) -> &UserManager +---- + +The ``UserManager`` for this connection, providing access to user management methods. + +[caption=""] +.Returns +[source,rust] +---- +&UserManager +---- + +[caption=""] +.Code examples +[source,rust] +---- +driver.databases() ---- // end::methods[] diff --git a/docs/modules/ROOT/partials/rust/connection/User.adoc b/docs/modules/ROOT/partials/rust/connection/User.adoc index 17464a04b0..d406b1d26f 100644 --- a/docs/modules/ROOT/partials/rust/connection/User.adoc +++ b/docs/modules/ROOT/partials/rust/connection/User.adoc @@ -9,21 +9,8 @@ * `Clone` * `Debug` -[caption=""] -.Fields -// tag::properties[] -[cols=",,"] -[options="header"] -|=== -|Name |Type |Description -a| `name` a| `String` a| -a| `password` a| `Option` a| -a| `server_connections` a| `HashMap` a| -|=== -// end::properties[] - // tag::methods[] -[#_struct_User_delete_username] +[#_struct_User_delete_] ==== delete [tabs] @@ -49,7 +36,77 @@ pub fn delete(self) -> Result -- ==== -Deletes this user +Deletes this user, using default strong consistency. + +See <<#_struct_User_method_delete_with_consistency,`Self::delete_with_consistency`>> for more details and options. + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +user.delete().await; +user.delete(username).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +user.delete(); +user.delete(username).await; +---- + +-- +==== + +[#_struct_User_delete_with_consistency_consistency_level_ConsistencyLevel] +==== delete_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn delete_with_consistency( + self, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn delete_with_consistency( + self, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- +==== + +Deletes this user. [caption=""] .Input parameters @@ -57,7 +114,7 @@ Deletes this user [options="header"] |=== |Name |Description |Type -a| `username` a| — The name of the user to be deleted a| +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` |=== [caption=""] @@ -76,8 +133,7 @@ async:: -- [source,rust] ---- -user.delete().await; -user.delete(username).await; +user.delete_with_consistency(ConsistencyLevel::Strong).await; ---- -- @@ -87,14 +143,47 @@ sync:: -- [source,rust] ---- -user.delete(); -user.delete(username).await; +user.delete_with_consistency(ConsistencyLevel::Strong); ---- -- ==== -[#_struct_User_update_password_username_password_impl_Into_String_-_Result_] +[#_struct_User_name_] +==== name + +[source,rust] +---- +pub fn name(&self) -> &str +---- + +Retrieves the username as a string. + +[caption=""] +.Returns +[source,rust] +---- +&str +---- + +[#_struct_User_password_] +==== password + +[source,rust] +---- +pub fn password(&self) -> Option<&str> +---- + +Retrieves the password as a string, if accessible. + +[caption=""] +.Returns +[source,rust] +---- +Option<&str> +---- + +[#_struct_User_update_password_password_impl_Into_String_-_Result_] ==== update_password [tabs] @@ -120,7 +209,9 @@ pub fn update_password(&self, password: impl Into) -> Result<()> -- ==== -Update the user’s password. +Updates the user’s password, using default strong consistency. + +See <<#_struct_User_method_update_password_with_consistency,`Self::update_password_with_consistency`>> for more details and options. [caption=""] .Input parameters @@ -128,7 +219,6 @@ Update the user’s password. [options="header"] |=== |Name |Description |Type -a| `username` a| — The name of the user a| a| `password` a| — The new password a| `impl Into) -> Result<(` |=== @@ -148,8 +238,85 @@ async:: -- [source,rust] ---- -user.update_password(username, password).await; -user.update_password(username, password).await; +user.update_password(password).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +user.update_password(password); +---- + +-- +==== + +[#_struct_User_update_password_with_consistency_password_impl_Into_String_consistency_level_ConsistencyLevel] +==== update_password_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn update_password_with_consistency( + &self, + password: impl Into, + consistency_level: ConsistencyLevel, +) -> Result<()> +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn update_password_with_consistency( + &self, + password: impl Into, + consistency_level: ConsistencyLevel, +) -> Result<()> +---- + +-- +==== + +Updates the user’s password. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `password` a| — The new password a| `impl Into` +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result<()> +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +user.update_password_with_consistency(password, ConsistencyLevel::Strong).await; ---- -- @@ -159,8 +326,7 @@ sync:: -- [source,rust] ---- -user.update_password(username, password); -user.update_password(username, password).await; +user.update_password_with_consistency(password, ConsistencyLevel::Strong); ---- -- diff --git a/docs/modules/ROOT/partials/rust/connection/UserManager.adoc b/docs/modules/ROOT/partials/rust/connection/UserManager.adoc index 6544bcd857..1b13633c53 100644 --- a/docs/modules/ROOT/partials/rust/connection/UserManager.adoc +++ b/docs/modules/ROOT/partials/rust/connection/UserManager.adoc @@ -37,8 +37,85 @@ pub fn all(&self) -> Result> -- ==== +Retrieves all users which exist on the TypeDB server, using default strong consistency. + +See <<#_struct_UserManager_method_all_with_consistency,`Self::all_with_consistency`>> for more details and options. + +[caption=""] +.Returns +[source,rust] +---- +Result> +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.users().all().await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.users().all(); +---- + +-- +==== + +[#_struct_UserManager_all_with_consistency_consistency_level_ConsistencyLevel] +==== all_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn all_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result> +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn all_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result> +---- + +-- +==== + Retrieves all users which exist on the TypeDB server. +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` +|=== + [caption=""] .Returns [source,rust] @@ -48,12 +125,30 @@ Result> [caption=""] .Code examples +[tabs] +==== +async:: ++ +-- [source,rust] ---- -driver.users.all().await; +driver.users().all_with_consistency(ConsistencyLevel::Strong).await; ---- -[#_struct_UserManager_contains_username_impl_Into_String_] +-- + +sync:: ++ +-- +[source,rust] +---- +driver.users().all_with_consistency(ConsistencyLevel::Strong); +---- + +-- +==== + +[#_struct_UserManager_contains_] ==== contains [tabs] @@ -79,6 +174,76 @@ pub fn contains(&self, username: impl Into) -> Result -- ==== +Checks if a user with the given name exists, using default strong consistency. + +See <<#_struct_UserManager_method_contains_with_consistency,`Self::contains_with_consistency`>> for more details and options. + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.users().contains(username).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.users().contains(username); +---- + +-- +==== + +[#_struct_UserManager_contains_with_consistency_username_impl_Into_String_consistency_level_ConsistencyLevel] +==== contains_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn contains_with_consistency( + &self, + username: impl Into, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn contains_with_consistency( + &self, + username: impl Into, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- +==== + Checks if a user with the given name exists. [caption=""] @@ -87,7 +252,8 @@ Checks if a user with the given name exists. [options="header"] |=== |Name |Description |Type -a| `username` a| — The user name to be checked a| `impl Into` +a| `username` a| — The username to be checked a| `impl Into` +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` |=== [caption=""] @@ -99,11 +265,29 @@ Result [caption=""] .Code examples +[tabs] +==== +async:: ++ +-- [source,rust] ---- -driver.users.contains(username).await; +driver.users().contains_with_consistency(username, ConsistencyLevel::Strong).await; ---- +-- + +sync:: ++ +-- +[source,rust] +---- +driver.users().contains_with_consistency(username, ConsistencyLevel::Strong); +---- + +-- +==== + [#_struct_UserManager_create_username_impl_Into_String_password_impl_Into_String_] ==== create @@ -138,7 +322,9 @@ pub fn create( -- ==== -Create a user with the given name & password. +Creates a user with the given name & password, using default strong consistency. + +See <<#_struct_UserManager_method_contains_with_consistency,`Self::contains_with_consistency`>> for more details and options. [caption=""] .Input parameters @@ -159,12 +345,111 @@ Result [caption=""] .Code examples +[tabs] +==== +async:: ++ +-- [source,rust] ---- -driver.users.create(username, password).await; +driver.users().create(username, password).await; ---- -[#_struct_UserManager_get_username_impl_Into_String_] +-- + +sync:: ++ +-- +[source,rust] +---- +driver.users().create(username, password); +---- + +-- +==== + +[#_struct_UserManager_create_with_consistency_username_impl_Into_String_password_impl_Into_String_consistency_level_ConsistencyLevel] +==== create_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn create_with_consistency( + &self, + username: impl Into, + password: impl Into, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn create_with_consistency( + &self, + username: impl Into, + password: impl Into, + consistency_level: ConsistencyLevel, +) -> Result +---- + +-- +==== + +Creates a user with the given name & password. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `username` a| — The name of the user to be created a| `impl Into` +a| `password` a| — The password of the user to be created a| `impl Into` +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.users().create_with_consistency(username, password, ConsistencyLevel::Strong).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.users().create_with_consistency(username, password, ConsistencyLevel::Strong); +---- + +-- +==== + +[#_struct_UserManager_get_] ==== get [tabs] @@ -190,7 +475,214 @@ pub fn get(&self, username: impl Into) -> Result> -- ==== -Retrieve a user with the given name. +Retrieves a user with the given name, using default strong consistency. + +See <<#_struct_UserManager_method_get_with_consistency,`Self::get_with_consistency`>> for more details and options. + +[caption=""] +.Returns +[source,rust] +---- +Result> +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.users().get(username).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.users().get(username); +---- + +-- +==== + +[#_struct_UserManager_get_current_] +==== get_current + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn get_current(&self) -> Result> +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn get_current(&self) -> Result> +---- + +-- +==== + +Returns the user of the current connection, using default strong consistency. + +See <<#_struct_UserManager_method_get_current_with_consistency,`Self::get_current_with_consistency`>> for more details and options. + +[caption=""] +.Returns +[source,rust] +---- +Result> +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.users().get_current().await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.users().get_current(); +---- + +-- +==== + +[#_struct_UserManager_get_current_with_consistency_consistency_level_ConsistencyLevel] +==== get_current_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn get_current_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result> +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn get_current_with_consistency( + &self, + consistency_level: ConsistencyLevel, +) -> Result> +---- + +-- +==== + +Returns the user of the current connection. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` +|=== + +[caption=""] +.Returns +[source,rust] +---- +Result> +---- + +[caption=""] +.Code examples +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +driver.users().get_current_with_consistency(ConsistencyLevel::Strong).await; +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +driver.users().get_current_with_consistency(ConsistencyLevel::Strong); +---- + +-- +==== + +[#_struct_UserManager_get_with_consistency_username_impl_Into_String_consistency_level_ConsistencyLevel] +==== get_with_consistency + +[tabs] +==== +async:: ++ +-- +[source,rust] +---- +pub async fn get_with_consistency( + &self, + username: impl Into, + consistency_level: ConsistencyLevel, +) -> Result> +---- + +-- + +sync:: ++ +-- +[source,rust] +---- +pub fn get_with_consistency( + &self, + username: impl Into, + consistency_level: ConsistencyLevel, +) -> Result> +---- + +-- +==== + +Retrieves a user with the given name. [caption=""] .Input parameters @@ -199,6 +691,7 @@ Retrieve a user with the given name. |=== |Name |Description |Type a| `username` a| — The name of the user to retrieve a| `impl Into` +a| `consistency_level` a| — The consistency level to use for the operation a| `ConsistencyLevel` |=== [caption=""] @@ -210,10 +703,28 @@ Result> [caption=""] .Code examples +[tabs] +==== +async:: ++ +-- [source,rust] ---- -driver.users.get(username).await; +driver.users().get_with_consistency(username, ConsistencyLevel::Strong).await; ---- +-- + +sync:: ++ +-- +[source,rust] +---- +driver.users().get_with_consistency(username, ConsistencyLevel::Strong); +---- + +-- +==== + // end::methods[] diff --git a/docs/modules/ROOT/partials/rust/errors/ConnectionError.adoc b/docs/modules/ROOT/partials/rust/errors/ConnectionError.adoc index 3ad993e6a3..c86fcfe0fc 100644 --- a/docs/modules/ROOT/partials/rust/errors/ConnectionError.adoc +++ b/docs/modules/ROOT/partials/rust/errors/ConnectionError.adoc @@ -12,38 +12,43 @@ |=== |Variant a| `AbsentTlsConfigForTlsConnection` -a| `AddressTranslationMismatch` +a| `AddressTranslationWithoutTranslation` a| `AnalyzeNoResponse` a| `BrokenPipe` -a| `ClusterAllNodesFailed` a| `ClusterReplicaNotPrimary` -a| `ConnectionFailed` +a| `ConnectionRefusedNetworking` a| `DatabaseExportChannelIsClosed` a| `DatabaseExportStreamNoResponse` a| `DatabaseImportChannelIsClosed` a| `DatabaseImportStreamUnexpectedResponse` -a| `DatabaseNotFound` a| `EncryptionSettingsMismatch` -a| `InvalidResponseField` +a| `InvalidAddressWithScheme` a| `ListsNotImplemented` a| `MissingPort` a| `MissingResponseField` -a| `NonTlsConnectionWithHttps` +a| `NoAvailableReplicas` +a| `NoPrimaryReplica` +a| `NotPrimaryOnReadOnly` a| `QueryStreamNoResponse` a| `RPCMethodUnavailable` -a| `SSLCertificateNotValidated` +a| `RequestTimeout` +a| `SchemeTlsSettingsMismatch` a| `ServerConnectionFailed` -a| `ServerConnectionFailedStatusError` +a| `ServerConnectionFailedNetworking` a| `ServerConnectionFailedWithError` a| `ServerConnectionIsClosed` -a| `TlsConnectionWithoutHttps` +a| `ServerConnectionIsClosedUnexpectedly` +a| `ServerIsNotInitialised` +a| `SslCertificateNotValidated` a| `TokenCredentialInvalid` a| `TransactionIsClosed` a| `TransactionIsClosedWithErrors` a| `UnexpectedConnectionClose` a| `UnexpectedKind` a| `UnexpectedQueryType` +a| `UnexpectedReplicaRole` a| `UnexpectedResponse` +a| `UnknownDirectReplica` a| `UnknownRequestId` a| `ValueStructNotImplemented` a| `ValueTimeZoneNameNotRecognised` diff --git a/docs/modules/ROOT/partials/rust/errors/InternalError.adoc b/docs/modules/ROOT/partials/rust/errors/InternalError.adoc index 04d94b7fb8..112b5d9615 100644 --- a/docs/modules/ROOT/partials/rust/errors/InternalError.adoc +++ b/docs/modules/ROOT/partials/rust/errors/InternalError.adoc @@ -11,12 +11,11 @@ [options="header"] |=== |Variant -a| `EnumOutOfBounds` a| `RecvError` a| `SendError` a| `UnexpectedRequestType` a| `UnexpectedResponseType` -a| `UnknownServer` +a| `Unimplemented` |=== // end::enum_constants[] diff --git a/docs/modules/ROOT/partials/rust/transaction/Transaction.adoc b/docs/modules/ROOT/partials/rust/transaction/Transaction.adoc index 359c907a4e..6025b18359 100644 --- a/docs/modules/ROOT/partials/rust/transaction/Transaction.adoc +++ b/docs/modules/ROOT/partials/rust/transaction/Transaction.adoc @@ -139,7 +139,7 @@ transaction.commit() pub fn is_open(&self) -> bool ---- -Closes the transaction. +Checks if the transaction is open. [caption=""] .Returns @@ -152,7 +152,7 @@ bool .Code examples [source,rust] ---- -transaction.close() +transaction.is_open() ---- [#_struct_Transaction_on_close_function] @@ -211,6 +211,13 @@ Performs a TypeQL query with default options. See <<#_struct_Transaction_method_ impl Promise<'static, Result> ---- +[caption=""] +.Code examples +[source,rust] +---- +transaction.query(query) +---- + [#_struct_Transaction_query_with_options_query_impl_AsRef_str_options_QueryOptions] ==== query_with_options diff --git a/docs/modules/ROOT/partials/rust/transaction/TransactionOptions.adoc b/docs/modules/ROOT/partials/rust/transaction/TransactionOptions.adoc index 9181c52477..0766a6c0f0 100644 --- a/docs/modules/ROOT/partials/rust/transaction/TransactionOptions.adoc +++ b/docs/modules/ROOT/partials/rust/transaction/TransactionOptions.adoc @@ -7,11 +7,10 @@ *Implements traits:* * `Clone` -* `Copy` * `Debug` * `Default` -TypeDB transaction options. ``TransactionOptions`` object can be used to override the default server behaviour for opened transactions. +TypeDB transaction options. ``TransactionOptions`` object can be used to override the default behaviour for opened transactions. [caption=""] .Fields @@ -20,12 +19,30 @@ TypeDB transaction options. ``TransactionOptions`` object can be used to overrid [options="header"] |=== |Name |Type |Description +a| `read_consistency_level` a| `Option` a| If set, specifies the requested consistency level of the transaction opening operation. Affects only read transactions, as write and schema transactions require primary replicas. a| `schema_lock_acquire_timeout` a| `Option` a| If set, specifies how long the driver should wait if opening a transaction is blocked by an exclusive schema write lock. a| `transaction_timeout` a| `Option` a| If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. |=== // end::properties[] // tag::methods[] +[#_struct_TransactionOptions_read_consistency_level_] +==== read_consistency_level + +[source,rust] +---- +pub fn read_consistency_level(self, consistency_level: ConsistencyLevel) -> Self +---- + +If set, specifies the requested consistency level of the transaction opening operation. Affects only read transactions, as write and schema transactions require primary replicas. + +[caption=""] +.Returns +[source,rust] +---- +Self +---- + [#_struct_TransactionOptions_schema_lock_acquire_timeout_] ==== schema_lock_acquire_timeout diff --git a/docs/modules/ROOT/partials/rust/value/Decimal.adoc b/docs/modules/ROOT/partials/rust/value/Decimal.adoc index 8afd75f238..410cfef7ca 100644 --- a/docs/modules/ROOT/partials/rust/value/Decimal.adoc +++ b/docs/modules/ROOT/partials/rust/value/Decimal.adoc @@ -23,40 +23,15 @@ A fixed-point decimal number. Holds exactly 19 digits after the decimal point and a 64-bit value before the decimal point. -// tag::methods[] -[#_struct_Decimal_fractional_part_] -==== fractional_part - -[source,rust] ----- -pub fn fractional_part(&self) -> u64 ----- - -Get the fractional part of the decimal, in multiples of 10^-19 (Decimal::FRACTIONAL_PART_DENOMINATOR) This means, the smallest decimal representable is 10^-19, and up to 19 decimal places are supported. - [caption=""] -.Returns -[source,rust] ----- -u64 ----- - -[#_struct_Decimal_integer_part_] -==== integer_part - -[source,rust] ----- -pub fn integer_part(&self) -> i64 ----- - -Get the integer part of the decimal as normal signed 64 bit number - -[caption=""] -.Returns -[source,rust] ----- -i64 ----- - -// end::methods[] +.Fields +// tag::properties[] +[cols=",,"] +[options="header"] +|=== +|Name |Type |Description +a| `fractional` a| `u64` a| The fractional part of the decimal, in multiples of 10^-19 (Decimal::FRACTIONAL_PART_DENOMINATOR). This means that the smallest decimal representable is 10^-19, and up to 19 decimal places are supported. +a| `integer` a| `i64` a| The integer part of the decimal as normal signed 64 bit number +|=== +// end::properties[] diff --git a/http-ts/docs_structure.bzl b/http-ts/docs_structure.bzl index 5e4500fcf9..5ebb9e1818 100644 --- a/http-ts/docs_structure.bzl +++ b/http-ts/docs_structure.bzl @@ -116,6 +116,8 @@ dir_mapping = { "RoleType.adoc": "concept", "SignInResponse.adoc": "response", "TransactionOpenResponse.adoc": "response", + "ServersListResponse.adoc": "response", + "Server.adoc": "connection", "TransactionOptions.adoc": "connection", "TranslatedAddress.adoc": "connection", "User.adoc": "connection", diff --git a/http-ts/src/index.ts b/http-ts/src/index.ts index 7087b66274..3b818479c2 100644 --- a/http-ts/src/index.ts +++ b/http-ts/src/index.ts @@ -25,6 +25,7 @@ import { DatabasesListResponse, isApiError, QueryResponse, + ServersListResponse, SignInResponse, TransactionOpenResponse, UsersListResponse, @@ -131,6 +132,10 @@ export class TypeDBHttpDriver { return this.apiGet(`/v1/version`); } + getServers(): Promise> { + return this.apiGet(`/v1/servers`); + } + private async apiGetString(path: string, options?: { headers?: Record }): Promise> { return this.stringApiReq("GET", path, options); } diff --git a/http-ts/src/response.ts b/http-ts/src/response.ts index 7ef382fe3c..b8c8adf3fa 100644 --- a/http-ts/src/response.ts +++ b/http-ts/src/response.ts @@ -45,6 +45,16 @@ export interface UsersListResponse { users: User[]; } +export interface Server { + address: string; + isPrimary: boolean; + term: number; +} + +export interface ServersListResponse { + servers: Server[]; +} + export interface TransactionOpenResponse { transactionId: string; } diff --git a/http-ts/tests/behaviour/feature/BUILD b/http-ts/tests/behaviour/feature/BUILD index 87b16a3f39..8c603ffbc9 100644 --- a/http-ts/tests/behaviour/feature/BUILD +++ b/http-ts/tests/behaviour/feature/BUILD @@ -16,7 +16,7 @@ # under the License. load("@typedb_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") -load("//http-ts/tests/behaviour:rules.bzl", "typedb_behaviour_http_ts_test") +load("//http-ts/tests/behaviour:rules.bzl", "typedb_behaviour_http_ts_test", "typedb_behaviour_http_ts_cluster_test") checkstyle_test( name = "checkstyle", @@ -24,26 +24,29 @@ checkstyle_test( license_type = "apache-header", ) +# Creates both -core and -cluster test targets typedb_behaviour_http_ts_test( name = "query", features = ["@typedb_behaviour//driver:query.feature"], - data = [], ) typedb_behaviour_http_ts_test( name = "user", features = ["@typedb_behaviour//driver:user.feature"], - data = [], ) typedb_behaviour_http_ts_test( name = "connection", features = ["@typedb_behaviour//driver:connection.feature"], - data = [], ) typedb_behaviour_http_ts_test( name = "concept", features = ["@typedb_behaviour//driver:concept.feature"], - data = [], +) + +# Cluster-only test (no core equivalent) +typedb_behaviour_http_ts_cluster_test( + name = "cluster", + features = ["@typedb_behaviour//driver:cluster.feature"], ) diff --git a/http-ts/tests/behaviour/rules.bzl b/http-ts/tests/behaviour/rules.bzl index 24f5dfd83b..b703bad612 100644 --- a/http-ts/tests/behaviour/rules.bzl +++ b/http-ts/tests/behaviour/rules.bzl @@ -29,12 +29,17 @@ def behaviour_test_ts_config(): } } -def http_ts_cucumber_test(name, features, data, steps, **kwargs): +def typedb_behaviour_http_ts_test(name, **kwargs): + """Creates both core and cluster test targets for HTTP TS behaviour tests.""" + typedb_behaviour_http_ts_core_test(name, **kwargs) + typedb_behaviour_http_ts_cluster_test(name, **kwargs) + +def typedb_behaviour_http_ts_core_test(name, features, data = [], **kwargs): cucumber_bin.cucumber_js_test( - name = name, + name = name + "-core", data = [ "//http-ts:node_modules/@cucumber/cucumber", - ] + data + features + [steps], + ] + data + features + ["//http-ts/tests/behaviour/steps"], no_copy_to_bin = features, fixed_args = [ "--publish-quiet", "--strict", @@ -44,9 +49,21 @@ def http_ts_cucumber_test(name, features, data, steps, **kwargs): **kwargs, ) -def typedb_behaviour_http_ts_test(name, **kwargs): - http_ts_cucumber_test( - name = name + "-community", - steps = "//http-ts/tests/behaviour/steps", +def typedb_behaviour_http_ts_cluster_test(name, features, data = [], **kwargs): + cucumber_bin.cucumber_js_test( + name = name + "-cluster", + data = [ + "//http-ts:node_modules/@cucumber/cucumber", + "//tool/test/resources:certificates", + ] + data + features + ["//http-ts/tests/behaviour/steps"], + no_copy_to_bin = features + ["//tool/test/resources:certificates"], + fixed_args = [ + "--publish-quiet", "--strict", + "--tags 'not @ignore and not @ignore-typedb-driver and not @ignore-typedb-driver-nodejs and not @ignore-typedb-http and not @ignore-typedb-http-driver and not @ignore-typedb-driver-cluster'", + "--require", "http-ts/tests/**/*.js", + ] + ["$(location {})".format(feature) for feature in features], + env = { + "TYPEDB_CLUSTER_MODE": "true", + }, **kwargs, ) diff --git a/http-ts/tests/behaviour/steps/connection.ts b/http-ts/tests/behaviour/steps/connection.ts index 6ed9d1a28f..05c4622c96 100644 --- a/http-ts/tests/behaviour/steps/connection.ts +++ b/http-ts/tests/behaviour/steps/connection.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Given, Then, When } from "@cucumber/cucumber"; +import { Given, Then, When, DataTable } from "@cucumber/cucumber"; import { assertNotError, checkMayError, EXPECT_ERROR_CONTAINING, MayError } from "./params"; import { closeConnection, DEFAULT_HOST, @@ -28,6 +28,7 @@ import { openAndTestConnectionWithHostPort } from "./context"; import assert from "assert"; +import { Server } from "../../../dist/index.cjs"; Given("typedb starts", () => {}); Given("connection is open: {boolean}", (_) => {}); @@ -57,3 +58,57 @@ Then("connection has {int} user(s)", async (expectedUserCount: number) => { }); When("connection closes", closeConnection); + +// Cluster/Replica steps +let cachedServers: Server[] = []; + +async function getServers(): Promise { + const res = await driver.getServers().then(assertNotError); + cachedServers = res.ok.servers; + return cachedServers; +} + +Then("connection has {int} replica(s)", async (expectedCount: number) => { + const servers = await getServers(); + assert.equal(servers.length, expectedCount, `Expected ${expectedCount} replicas but got ${servers.length}`); +}); + +Then("connection primary replica exists", async () => { + const servers = await getServers(); + const primary = servers.find(s => s.isPrimary); + assert.ok(primary, "No primary replica found"); +}); + +Then("connection get replica\\({word}) exists", async (address: string) => { + const servers = await getServers(); + const replica = servers.find(s => s.address === address); + assert.ok(replica, `Replica with address ${address} not found`); +}); + +Then("connection get replica\\({word}) does not exist", async (address: string) => { + const servers = await getServers(); + const replica = servers.find(s => s.address === address); + assert.ok(!replica, `Replica with address ${address} should not exist`); +}); + +Then("connection get replica\\({word}) has term", async (address: string) => { + const servers = await getServers(); + const replica = servers.find(s => s.address === address); + assert.ok(replica, `Replica with address ${address} not found`); + assert.ok(typeof replica.term === 'number', `Replica ${address} has no term`); +}); + +Then("connection replicas have roles:", async (dataTable: DataTable) => { + const servers = await getServers(); + const rows = dataTable.hashes(); + + for (const row of rows) { + const expectedAddress = row['address']; + const expectedIsPrimary = row['is_primary'] === 'true'; + + const replica = servers.find(s => s.address === expectedAddress); + assert.ok(replica, `Replica with address ${expectedAddress} not found`); + assert.equal(replica.isPrimary, expectedIsPrimary, + `Replica ${expectedAddress} isPrimary: expected ${expectedIsPrimary}, got ${replica.isPrimary}`); + } +}); diff --git a/http-ts/tests/behaviour/steps/context.ts b/http-ts/tests/behaviour/steps/context.ts index 86cc059119..588b18542e 100644 --- a/http-ts/tests/behaviour/steps/context.ts +++ b/http-ts/tests/behaviour/steps/context.ts @@ -17,9 +17,13 @@ * under the License. */ -import { After, Before } from "@cucumber/cucumber"; +import { After, Before, BeforeAll } from "@cucumber/cucumber"; import { AnalyzeResponse, isOkResponse, QueryOptions, QueryResponse, TransactionOptions, TransactionType, TypeDBHttpDriver } from "../../../dist/index.cjs"; import { assertNotError } from "./params"; +import * as https from "https"; +import * as http from "http"; +import * as fs from "fs"; +import * as path from "path"; export let driver: TypeDBHttpDriver; let transactionID: string; @@ -89,12 +93,97 @@ export function setConcurrentAnswers(answers: QueryResponse[]) { export const DEFAULT_USERNAME = "admin"; export const DEFAULT_PASSWORD = "password"; -export const DEFAULT_HOST = "http://127.0.0.1"; -export const DEFAULT_PORT = 8000; +export const DEFAULT_HOST = process.env.TYPEDB_HTTP_HOST || "http://127.0.0.1"; +export const DEFAULT_PORT = parseInt(process.env.TYPEDB_HTTP_PORT || "8000"); + +export const isClusterMode = process.env.TYPEDB_CLUSTER_MODE === "true"; +export const CLUSTER_ADDRESSES = [ + "https://127.0.0.1:18000", + "https://127.0.0.1:28000", + "https://127.0.0.1:38000" +]; + +// For cluster mode tests, replace global fetch with one that handles mTLS +if (isClusterMode) { + // Load TLS certificates for mTLS - ROOT_CA env var points to the CA certificate + const rootCaPath = process.env.ROOT_CA; + if (!rootCaPath) { + throw new Error("ROOT_CA environment variable must be set for cluster mode tests"); + } + const certDir = path.dirname(rootCaPath); + const ca = fs.readFileSync(rootCaPath); + const cert = fs.readFileSync(path.join(certDir, "ext-grpc-certificate.pem")); + const key = fs.readFileSync(path.join(certDir, "ext-grpc-private-key.pem")); + + console.log("Cluster mode: Using custom fetch with mTLS"); + + // Create a custom fetch that uses https module with client certificates + const customFetch = async (input: RequestInfo | URL, init?: RequestInit): Promise => { + const url = typeof input === 'string' ? new URL(input) : input instanceof URL ? input : new URL(input.url); + const isHttps = url.protocol === 'https:'; + + return new Promise((resolve, reject) => { + const options: https.RequestOptions = { + hostname: url.hostname, + port: url.port || (isHttps ? 443 : 80), + path: url.pathname + url.search, + method: init?.method || 'GET', + headers: init?.headers as Record, + ca: ca, + cert: cert, + key: key, + rejectUnauthorized: true, + }; + + const client = isHttps ? https : http; + const req = client.request(options, (res) => { + const chunks: Buffer[] = []; + res.on('data', (chunk) => chunks.push(chunk)); + res.on('end', () => { + const body = Buffer.concat(chunks).toString(); + const headers = new Headers(); + Object.entries(res.headers).forEach(([key, value]) => { + if (value) headers.set(key, Array.isArray(value) ? value.join(', ') : value); + }); + const status = res.statusCode || 200; + // Status codes 204 and 304 are "null body" statuses - Response constructor rejects body for these + const isNullBodyStatus = status === 204 || status === 304; + resolve(new Response(isNullBodyStatus ? null : body, { + status, + statusText: res.statusMessage || '', + headers, + })); + }); + }); + + req.on('error', reject); + + if (init?.body) { + req.write(init.body); + } + req.end(); + }); + }; + + // Replace global fetch + (globalThis as any).fetch = customFetch; +} export async function openAndTestConnection(username: string, password: string) { + if (isClusterMode) { + return openAndTestConnectionWithAddresses(username, password, CLUSTER_ADDRESSES); + } return openAndTestConnectionWithHostPort(username, password, DEFAULT_HOST, DEFAULT_PORT); } + +export async function openAndTestConnectionWithAddresses(username: string, password: string, addresses: string[]) { + const newDriver = new TypeDBHttpDriver({ + username, password, addresses + }); + const healthCheck = await newDriver.health(); + if (isOkResponse(healthCheck)) driver = newDriver; + return healthCheck; +} export async function openAndTestConnectionWithHostPort(username: string, password: string, host: string, port: number) { const newDriver = new TypeDBHttpDriver({ username, password, addresses: [`${host}:${port}`] @@ -110,7 +199,11 @@ export function closeConnection() { } export function setDefaultDriver() { - driver = new TypeDBHttpDriver({username: DEFAULT_USERNAME, password: DEFAULT_PASSWORD, addresses: [`${DEFAULT_HOST}:${DEFAULT_PORT}`]}); + if (isClusterMode) { + driver = new TypeDBHttpDriver({username: DEFAULT_USERNAME, password: DEFAULT_PASSWORD, addresses: CLUSTER_ADDRESSES}); + } else { + driver = new TypeDBHttpDriver({username: DEFAULT_USERNAME, password: DEFAULT_PASSWORD, addresses: [`${DEFAULT_HOST}:${DEFAULT_PORT}`]}); + } } Before(resetDB); diff --git a/java/README.md b/java/README.md index eb7ca1d4e7..577da2bae2 100644 --- a/java/README.md +++ b/java/README.md @@ -62,6 +62,7 @@ import com.typedb.driver.TypeDB; import com.typedb.driver.api.Credentials; import com.typedb.driver.api.Driver; import com.typedb.driver.api.DriverOptions; +import com.typedb.driver.api.DriverTlsConfig; import com.typedb.driver.api.QueryOptions; import com.typedb.driver.api.QueryType; import com.typedb.driver.api.Transaction; @@ -87,7 +88,7 @@ import java.util.stream.Collectors; public class TypeDBExample { public void example() { // Open a driver connection. Try-with-resources can be used for automatic driver connection management - try (Driver driver = TypeDB.driver(TypeDB.DEFAULT_ADDRESS, new Credentials("admin", "password"), new DriverOptions(false, null))) { + try (Driver driver = TypeDB.driver(TypeDB.DEFAULT_ADDRESS, new Credentials("admin", "password"), new DriverOptions(DriverTlsConfig.disabled()))) { // Create a database driver.databases().create("typedb"); Database database = driver.databases().get("typedb"); diff --git a/java/TypeDB.java b/java/TypeDB.java index 93e530c2bc..84c6034528 100644 --- a/java/TypeDB.java +++ b/java/TypeDB.java @@ -25,8 +25,11 @@ import com.typedb.driver.common.exception.TypeDBDriverException; import com.typedb.driver.connection.DriverImpl; +import java.util.Map; +import java.util.Set; + public class TypeDB { - public static final String DEFAULT_ADDRESS = "localhost:1729"; + public static final String DEFAULT_ADDRESS = "127.0.0.1:1729"; /** * Open a TypeDB Driver to a TypeDB server available at the provided address. @@ -38,9 +41,41 @@ public class TypeDB { * * @param address The address of the TypeDB server * @param credentials The credentials to connect with - * @param driverOptions The connection settings to connect with + * @param driverOptions The driver connection options to connect with */ public static Driver driver(String address, Credentials credentials, DriverOptions driverOptions) throws TypeDBDriverException { return new DriverImpl(address, credentials, driverOptions); } + + /** + * Open a TypeDB Driver to a TypeDB cluster available at the provided addresses. + * + *

Examples

+ *
+     * TypeDB.driver(address);
+     * 
+ * + * @param addresses The addresses of TypeDB cluster replicas for connection + * @param credentials The credentials to connect with + * @param driverOptions The driver connection options to connect with + */ + public static Driver driver(Set addresses, Credentials credentials, DriverOptions driverOptions) throws TypeDBDriverException { + return new DriverImpl(addresses, credentials, driverOptions); + } + + /** + * Open a TypeDB Driver to a TypeDB cluster, using the provided address translation. + * + *

Examples

+ *
+     * TypeDB.driver(addresses);
+     * 
+ * + * @param addressTranslation The translation of public TypeDB cluster replica addresses (keys) to server-side private addresses (values) + * @param credentials The credentials to connect with + * @param driverOptions The driver connection options to connect with + */ + public static Driver driver(Map addressTranslation, Credentials credentials, DriverOptions driverOptions) throws TypeDBDriverException { + return new DriverImpl(addressTranslation, credentials, driverOptions); + } } diff --git a/java/TypeDBExample.java b/java/TypeDBExample.java index e127e429c7..31462fd004 100644 --- a/java/TypeDBExample.java +++ b/java/TypeDBExample.java @@ -6,6 +6,7 @@ import com.typedb.driver.api.Credentials; import com.typedb.driver.api.Driver; import com.typedb.driver.api.DriverOptions; +import com.typedb.driver.api.DriverTlsConfig; import com.typedb.driver.api.QueryOptions; import com.typedb.driver.api.QueryType; import com.typedb.driver.api.Transaction; @@ -31,7 +32,7 @@ public class TypeDBExample { public void example() { // Open a driver connection. Try-with-resources can be used for automatic driver connection management - try (Driver driver = TypeDB.driver(TypeDB.DEFAULT_ADDRESS, new Credentials("admin", "password"), new DriverOptions(false, null))) { + try (Driver driver = TypeDB.driver(TypeDB.DEFAULT_ADDRESS, new Credentials("admin", "password"), new DriverOptions(DriverTlsConfig.disabled()))) { // Create a database driver.databases().create("typedb"); Database database = driver.databases().get("typedb"); diff --git a/java/analyze/ConstraintImpl.java b/java/analyze/ConstraintImpl.java index fcd970e264..3038ea049e 100644 --- a/java/analyze/ConstraintImpl.java +++ b/java/analyze/ConstraintImpl.java @@ -82,14 +82,15 @@ public static ConstraintImpl of(com.typedb.driver.jni.ConstraintWithSpan constra public SpanImpl span() { return new SpanImpl( - com.typedb.driver.jni.typedb_driver.constraint_span_begin(nativeObject), - com.typedb.driver.jni.typedb_driver.constraint_span_end(nativeObject) + com.typedb.driver.jni.typedb_driver.constraint_span_begin(nativeObject), + com.typedb.driver.jni.typedb_driver.constraint_span_end(nativeObject) ); } public static class SpanImpl implements Span { long begin; long end; + SpanImpl(long begin, long end) { this.begin = begin; this.end = end; diff --git a/java/api/ConsistencyLevel.java b/java/api/ConsistencyLevel.java new file mode 100644 index 0000000000..281291ff9d --- /dev/null +++ b/java/api/ConsistencyLevel.java @@ -0,0 +1,137 @@ +/* + * 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 com.typedb.driver.api; + +import com.typedb.driver.common.exception.TypeDBDriverException; + +import static com.typedb.driver.common.exception.ErrorMessage.Internal.UNEXPECTED_NATIVE_VALUE; +import static com.typedb.driver.jni.typedb_driver.consistency_level_eventual; +import static com.typedb.driver.jni.typedb_driver.consistency_level_replica_dependent; +import static com.typedb.driver.jni.typedb_driver.consistency_level_strong; + +/** + * Consistency levels of operations against a distributed server. All driver methods have default + * recommended values, however, most of the operations can be configured in order to potentially + * speed up the execution (introducing risks of stale data) or test a specific replica. + * This setting does not affect clusters with a single node. + */ +public abstract class ConsistencyLevel { + public abstract com.typedb.driver.jni.ConsistencyLevel nativeValue(); + + public static ConsistencyLevel of(com.typedb.driver.jni.ConsistencyLevel nativeValue) { + if (nativeValue.getTag() == com.typedb.driver.jni.ConsistencyLevelTag.Strong) return new Strong(); + else if (nativeValue.getTag() == com.typedb.driver.jni.ConsistencyLevelTag.Eventual) return new Eventual(); + else if (nativeValue.getTag() == com.typedb.driver.jni.ConsistencyLevelTag.ReplicaDependent) { + return new ReplicaDependent(nativeValue.getAddress()); + } + throw new TypeDBDriverException(UNEXPECTED_NATIVE_VALUE); + } + + public static com.typedb.driver.jni.ConsistencyLevel nativeValue(ConsistencyLevel consistencyLevel) { + if (consistencyLevel == null) { + return null; + } else { + return consistencyLevel.nativeValue(); + } + } + + /** + * Strong consistency level. + * Strongest consistency, always up-to-date due to the guarantee of the primary replica usage. + * May require more time for operation execution. + */ + public static final class Strong extends ConsistencyLevel { + public Strong() { + } + + @Override + public com.typedb.driver.jni.ConsistencyLevel nativeValue() { + return newNative(); + } + + private static com.typedb.driver.jni.ConsistencyLevel newNative() { + return consistency_level_strong(); + } + + @Override + public String toString() { + return "Strong"; + } + } + + /** + * Eventual consistency level. + * Allow stale reads from any replica and execution orchestration through a non-primary replica. + * Does not guarantee latest writes, but is eventually faster compared to other consistency levels. + * Note that the target replica can redirect the request, if needed. + */ + public static final class Eventual extends ConsistencyLevel { + public Eventual() { + } + + @Override + public com.typedb.driver.jni.ConsistencyLevel nativeValue() { + return newNative(); + } + + private static com.typedb.driver.jni.ConsistencyLevel newNative() { + return consistency_level_eventual(); + } + + @Override + public String toString() { + return "Eventual"; + } + } + + /** + * Replica dependent consistency level. + * The operation is executed against the provided replica address only. Its guarantees depend + * on the replica selected. Note that the target replica can redirect the request, if needed. + */ + public static final class ReplicaDependent extends ConsistencyLevel { + private final String address; + + public ReplicaDependent(String address) { + this.address = address; + } + + @Override + public com.typedb.driver.jni.ConsistencyLevel nativeValue() { + return newNative(this.address); + } + + private static com.typedb.driver.jni.ConsistencyLevel newNative(String address) { + return consistency_level_replica_dependent(address); + } + + /** + * Retrieves the address of the replica this consistency level depends on. + */ + public String getAddress() { + return address; + } + + @Override + public String toString() { + return "ReplicaDependent(" + address + ")"; + } + } +} \ No newline at end of file diff --git a/java/api/Driver.java b/java/api/Driver.java index acf156ff68..757d7da010 100644 --- a/java/api/Driver.java +++ b/java/api/Driver.java @@ -20,10 +20,15 @@ package com.typedb.driver.api; import com.typedb.driver.api.database.DatabaseManager; +import com.typedb.driver.api.server.ServerReplica; +import com.typedb.driver.api.server.ServerVersion; import com.typedb.driver.api.user.UserManager; import com.typedb.driver.common.exception.TypeDBDriverException; import javax.annotation.CheckReturnValue; +import java.util.Map; +import java.util.Optional; +import java.util.Set; public interface Driver extends AutoCloseable { String LANGUAGE = "java"; @@ -39,12 +44,55 @@ public interface Driver extends AutoCloseable { @CheckReturnValue boolean isOpen(); + /** + * Retrieves the server's version, using default strong consistency. + * See {@link #serverVersion(ConsistencyLevel)} for more details and options. + * + *

Examples

+ *
+     * driver.serverVersion();
+     * 
+ */ + @CheckReturnValue + default ServerVersion serverVersion() { + return serverVersion(null); + } + + /** + * Retrieves the server's version. + * + *

Examples

+ *
+     * driver.serverVersion();
+     * 
+ * + * @param consistencyLevel The consistency level to use for the operation + */ + @CheckReturnValue + ServerVersion serverVersion(ConsistencyLevel consistencyLevel); + /** * The DatabaseManager for this connection, providing access to database management methods. + * + *

Examples

+ *
+     * driver.databases();
+     * 
*/ @CheckReturnValue DatabaseManager databases(); + /** + * The UserManager for this connection, providing access to user management methods. + * + *

Examples

+ *
+     * driver.users();
+     * 
+ */ + @CheckReturnValue + UserManager users(); + /** * Opens a communication tunnel (transaction) to the given database on the running TypeDB server. * @@ -75,23 +123,109 @@ public interface Driver extends AutoCloseable { Transaction transaction(String database, Transaction.Type type, TransactionOptions options); /** - * Closes the driver. Before instantiating a new driver, the driver that’s currently open should first be closed. + * Set of Replica instances for this driver connection, using default strong consistency. + * See {@link #replicas(ConsistencyLevel)} for more details and options. * *

Examples

*
-     * driver.close()
+     * driver.replicas();
      * 
*/ - void close(); + @CheckReturnValue + default Set replicas() { + return replicas(null); + } /** - * The UserManager instance for this connection, providing access to user management methods. + * Set of Replica instances for this driver connection. * *

Examples

*
-     * driver.users();
+     * driver.replicas(new ConsistencyLevel.Strong());
      * 
+ * + * @param consistencyLevel The consistency level to use for the operation */ @CheckReturnValue - UserManager users(); + Set replicas(ConsistencyLevel consistencyLevel); + + /** + * Returns the primary replica for this driver connection, using default strong consistency. + * See {@link #primaryReplica(ConsistencyLevel)} for more details and options. + * + *

Examples

+ *
+     * driver.primaryReplica();
+     * 
+ */ + @CheckReturnValue + default Optional primaryReplica() { + return primaryReplica(null); + } + + /** + * Returns the primary replica for this driver connection. + * + *

Examples

+ *
+     * driver.primaryReplica(new ConsistencyLevel.Strong());
+     * 
+ * + * @param consistencyLevel The consistency level to use for the operation + */ + @CheckReturnValue + Optional primaryReplica(ConsistencyLevel consistencyLevel); + + /** + * Registers a new replica in the cluster the driver is currently connected to. The registered + * replica will become available eventually, depending on the behavior of the whole cluster. + * To register a replica, its clustering address should be passed, not the connection address. + * + *

Examples

+ *
+     * driver.registerReplica(2, "127.0.0.1:11729");
+     * 
+ * + * @param replicaID The numeric identifier of the new replica + * @param address The address(es) of the TypeDB replica as a string + */ + void registerReplica(long replicaID, String address); + + /** + * Deregisters a replica from the cluster the driver is currently connected to. This replica + * will no longer play a raft role in this cluster. + * + *

Examples

+ *
+     * driver.deregisterReplica(2);
+     * 
+ * + * @param replicaID The numeric identifier of the deregistered replica + */ + void deregisterReplica(long replicaID); + + /** + * Updates address translation of the driver. This lets you actualize new translation + * information without recreating the driver from scratch. Useful after registering new + * replicas requiring address translation. + * This operation will update existing connections using the provided addresses. + * + *

Examples

+ *
+     * driver.updateAddressTranslation(2);
+     * 
+ * + * @param addressTranslation The translation of public TypeDB cluster replica addresses (keys) to server-side private addresses (values) + */ + void updateAddressTranslation(Map addressTranslation); + + /** + * Closes the driver. Before instantiating a new driver, the driver that’s currently open should first be closed. + * + *

Examples

+ *
+     * driver.close();
+     * 
+ */ + void close(); } diff --git a/java/api/DriverOptions.java b/java/api/DriverOptions.java index f14e42ff9c..3869833ed2 100644 --- a/java/api/DriverOptions.java +++ b/java/api/DriverOptions.java @@ -19,35 +19,213 @@ package com.typedb.driver.api; +import com.typedb.driver.api.DriverTlsConfig; import com.typedb.driver.common.NativeObject; -import com.typedb.driver.common.exception.TypeDBDriverException; +import com.typedb.driver.common.Validator; -import javax.annotation.Nullable; +import javax.annotation.CheckReturnValue; +import java.util.Optional; +import static com.typedb.driver.jni.typedb_driver.driver_options_get_tls_config; +import static com.typedb.driver.jni.typedb_driver.driver_options_get_primary_failover_retries; +import static com.typedb.driver.jni.typedb_driver.driver_options_get_replica_discovery_attempts; +import static com.typedb.driver.jni.typedb_driver.driver_options_get_request_timeout_millis; +import static com.typedb.driver.jni.typedb_driver.driver_options_get_use_replication; +import static com.typedb.driver.jni.typedb_driver.driver_options_has_replica_discovery_attempts; import static com.typedb.driver.jni.typedb_driver.driver_options_new; +import static com.typedb.driver.jni.typedb_driver.driver_options_set_tls_config; +import static com.typedb.driver.jni.typedb_driver.driver_options_set_primary_failover_retries; +import static com.typedb.driver.jni.typedb_driver.driver_options_set_replica_discovery_attempts; +import static com.typedb.driver.jni.typedb_driver.driver_options_set_request_timeout_millis; +import static com.typedb.driver.jni.typedb_driver.driver_options_set_use_replication; /** - * User connection settings (TLS encryption, etc.) for connecting to TypeDB Server. - * - *

Examples

- *
- * DriverOptions driverOptions = new DriverOptions(true, Path.of("path/to/ca-certificate.pem"));
- * 
+ * TypeDB driver options. DriverOptions are used to specify the driver's connection behavior. */ public class DriverOptions extends NativeObject { /** - * @param isTlsEnabled Specify whether the connection to TypeDB Server must be done over TLS. - * @param tlsRootCAPath Path to the CA certificate to use for authenticating server certificates. + * Produces a new DriverOptions object for connecting to TypeDB Server using custom TLS settings. + * WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + * + *

Examples

+ *
+     * DriverOptions options = new DriverOptions(DriverTlsConfig.enabledWithNativeRootCA());
+     * 
+ */ + public DriverOptions(DriverTlsConfig tlsConfig) { + super(driver_options_new(tlsConfig.nativeObject)); + } + + /** + * Returns the TLS configuration associated with this DriverOptions. + * Specifies the TLS configuration of the connection to TypeDB. + * + *

Examples

+ *
+     * options.tlsConfig();
+     * 
+ */ + @CheckReturnValue + public DriverTlsConfig tlsConfig() { + return new DriverTlsConfig(driver_options_get_tls_config(nativeObject)); + } + + /** + * Overrides the TLS configuration associated with this {@code DriverOptions}. + * WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + * + *

Examples

+ *
+     * options.tlsConfig(DriverTlsConfig.enabledWithNativeRootCA());
+     * 
+ */ + public DriverOptions tlsConfig(DriverTlsConfig tlsConfig) { + Validator.requireNonNull(tlsConfig, "tlsConfig"); + driver_options_set_tls_config(nativeObject, tlsConfig.nativeObject); + return this; + } + + /** + * Returns the request timeout in milliseconds set for this ``DriverOptions`` object. + * Specifies the maximum time to wait for a response to a unary RPC request. + * This applies to operations like database creation, user management, and initial + * transaction opening. It does NOT apply to operations within transactions (queries, commits). + * + *

Examples

+ *
+     * options.requestTimeoutMillis();
+     * 
+ */ + @CheckReturnValue + public Long requestTimeoutMillis() { + return driver_options_get_request_timeout_millis(nativeObject); + } + + /** + * Sets the maximum time (in milliseconds) to wait for a response to a unary RPC request. + * This applies to operations like database creation, user management, and initial + * transaction opening. It does NOT apply to operations within transactions (queries, commits). + * Defaults to 2 hours (7200000 milliseconds). + * + *

Examples

+ *
+     * options.requestTimeoutMillis(30000); // 30 seconds
+     * 
+ * + * @param requestTimeoutMillis The request timeout in milliseconds. Must be non-negative. */ - public DriverOptions(boolean isTlsEnabled, String tlsRootCAPath) { // TODO: Maybe Optional? Optional.of(Path.of(..))?.. - super(newNative(isTlsEnabled, tlsRootCAPath)); + public DriverOptions requestTimeoutMillis(long requestTimeoutMillis) { + Validator.requireNonNegative(requestTimeoutMillis, "requestTimeoutMillis"); + driver_options_set_request_timeout_millis(nativeObject, requestTimeoutMillis); + return this; } - private static com.typedb.driver.jni.DriverOptions newNative(boolean isTlsEnabled, @Nullable String tlsRootCAPath) { - try { - return driver_options_new(isTlsEnabled, tlsRootCAPath); - } catch (com.typedb.driver.jni.Error error) { - throw new TypeDBDriverException(error); - } + /** + * Returns the value set for the replication usage flag in this DriverOptions object. + * Specifies whether the connection to TypeDB can use cluster replicas provided by the server + * or it should be limited to a single configured address. + * + *

Examples

+ *
+     * options.useReplication();
+     * 
+ */ + @CheckReturnValue + public Boolean useReplication() { + return driver_options_get_use_replication(nativeObject); + } + + /** + * Explicitly sets whether the connection to TypeDB can use cluster replicas provided by the server + * or it should be limited to a single configured address. Defaults to true. + * + *

Examples

+ *
+     * options.useReplication(true);
+     * 
+ * + * @param useReplication Whether the connection to TypeDB can use replication. + */ + public DriverOptions useReplication(boolean useReplication) { + driver_options_set_use_replication(nativeObject, useReplication); + return this; + } + + /** + * Returns the value set for the primary failover retries limit in this DriverOptions object. + * Limits the number of attempts to redirect a strongly consistent request to another + * primary replica in case of a failure due to the change of replica roles. + * + *

Examples

+ *
+     * options.primaryFailoverRetries();
+     * 
+ */ + @CheckReturnValue + public Integer primaryFailoverRetries() { + return (int) driver_options_get_primary_failover_retries(nativeObject); + } + + /** + * Explicitly sets the limit on the number of attempts to redirect a strongly consistent request to another + * primary replica in case of a failure due to the change of replica roles. Defaults to 1. + * + *

Examples

+ *
+     * options.primaryFailoverRetries(1);
+     * 
+ * + * @param primaryFailoverRetries The limit of primary failover retries. + */ + public DriverOptions primaryFailoverRetries(int primaryFailoverRetries) { + Validator.requireNonNegative(primaryFailoverRetries, "primaryFailoverRetries"); + driver_options_set_primary_failover_retries(nativeObject, primaryFailoverRetries); + return this; + } + + /** + * Returns the value set for the replica discovery attempts limit in this DriverOptions object. + * Limits the number of driver attempts to discover a single working replica to perform an + * operation in case of a replica unavailability. Every replica is tested once, which means + * that at most: + * - {limit} operations are performed if the limit <= the number of replicas. + * - {number of replicas} operations are performed if the limit > the number of replicas. + * - {number of replicas} operations are performed if the limit is None. + * Affects every eventually consistent operation, including redirect failover, when the new + * primary replica is unknown. + * + *

Examples

+ *
+     * options.replicaDiscoveryAttempts();
+     * 
+ */ + @CheckReturnValue + public Optional replicaDiscoveryAttempts() { + if (driver_options_has_replica_discovery_attempts(nativeObject)) + return Optional.of((int) driver_options_get_replica_discovery_attempts(nativeObject)); + return Optional.empty(); + } + + /** + * Limits the number of driver attempts to discover a single working replica to perform an + * operation in case of a replica unavailability. Every replica is tested once, which means + * that at most: + * - {limit} operations are performed if the limit <= the number of replicas. + * - {number of replicas} operations are performed if the limit > the number of replicas. + * - {number of replicas} operations are performed if the limit is None. + * Affects every eventually consistent operation, including redirect failover, when the new + * primary replica is unknown. If not set, the maximum (practically unlimited) value is used. + * + *

Examples

+ *
+     * options.primaryFailoverRetries(1);
+     * 
+ * + * @param replicaDiscoveryAttempts The limit of replica discovery attempts. + */ + public DriverOptions replicaDiscoveryAttempts(int replicaDiscoveryAttempts) { + Validator.requireNonNegative(replicaDiscoveryAttempts, "replicaDiscoveryAttempts"); + driver_options_set_replica_discovery_attempts(nativeObject, replicaDiscoveryAttempts); + return this; } } diff --git a/java/api/DriverTlsConfig.java b/java/api/DriverTlsConfig.java new file mode 100644 index 0000000000..0bca6546fd --- /dev/null +++ b/java/api/DriverTlsConfig.java @@ -0,0 +1,126 @@ +/* + * 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 com.typedb.driver.api; + +import com.typedb.driver.common.exception.TypeDBDriverException; +import com.typedb.driver.common.NativeObject; +import com.typedb.driver.common.Validator; + +import javax.annotation.CheckReturnValue; +import java.util.Optional; + +import static com.typedb.driver.jni.typedb_driver.driver_tls_config_new_disabled; +import static com.typedb.driver.jni.typedb_driver.driver_tls_config_new_enabled_with_native_root_ca; +import static com.typedb.driver.jni.typedb_driver.driver_tls_config_new_enabled_with_root_ca_path; +import static com.typedb.driver.jni.typedb_driver.driver_tls_config_is_enabled; +import static com.typedb.driver.jni.typedb_driver.driver_tls_config_has_root_ca_path; +import static com.typedb.driver.jni.typedb_driver.driver_tls_config_get_root_ca_path; + +/** + * TLS configuration for the TypeDB driver. + * + * DriverTlsConfig represents a fully constructed and validated TLS configuration. + * If TLS is enabled, the underlying TLS config is built eagerly at construction time, + * ensuring that no connection attempt can observe a partially-configured TLS state. + *

+ * The driver defaults to using TLS with native system trust roots. + * This matches typical system and container deployments while still allowing + * explicit opt-out or custom PKI configuration. + */ +public class DriverTlsConfig extends NativeObject { + protected DriverTlsConfig(com.typedb.driver.jni.DriverTlsConfig nativeObject) { + super(nativeObject); + } + + /** + * Creates a TLS configuration with TLS disabled. + * WARNING: Disabling TLS causes credentials and data to be transmitted in plaintext. + * + *

Examples

+ *
+     * DriverTlsConfig tlsConfig = DriverTlsConfig.disabled();
+     * 
+ */ + @CheckReturnValue + public static DriverTlsConfig disabled() { + return new DriverTlsConfig(driver_tls_config_new_disabled()); + } + + /** + * Creates a TLS configuration enabled with system native trust roots. + * + *

Examples

+ *
+     * DriverTlsConfig tlsConfig = DriverTlsConfig.enabledWithNativeRootCA();
+     * 
+ */ + @CheckReturnValue + public static DriverTlsConfig enabledWithNativeRootCA() { + return new DriverTlsConfig(driver_tls_config_new_enabled_with_native_root_ca()); + } + + /** + * Creates a TLS configuration enabled with a custom root CA certificate bundle (PEM). + * + * @param tlsRootCAPath Path to PEM-encoded root CA certificate bundle. + * + *

Examples

+ *
+     *                                                                                     DriverTlsConfig tlsConfig = DriverTlsConfig.enabledWithRootCA("path/to/ca-certificate.pem");
+     *                                                                                     
+ */ + @CheckReturnValue + public static DriverTlsConfig enabledWithRootCA(String tlsRootCAPath) { + Validator.requireNonNull(tlsRootCAPath, "tlsRootCAPath"); + try { + return new DriverTlsConfig(driver_tls_config_new_enabled_with_root_ca_path(tlsRootCAPath)); + } catch (com.typedb.driver.jni.Error e) { + throw new TypeDBDriverException(e); + } + } + + /** + * Returns whether TLS is enabled. + * + *

Examples

+ *
+     * tlsConfig.isEnabled();
+     * 
+ */ + @CheckReturnValue + public boolean isEnabled() { + return driver_tls_config_is_enabled(nativeObject); + } + + /** + * Returns the configured custom root CA path, if present. + * If TLS is enabled with native roots (or disabled), this will be empty. + * + *

Examples

+ *
+     * tlsConfig.rootCAPath();
+     * 
+ */ + @CheckReturnValue + public Optional rootCAPath() { + if (!driver_tls_config_has_root_ca_path(nativeObject)) return Optional.empty(); + return Optional.ofNullable(driver_tls_config_get_root_ca_path(nativeObject)); + } +} diff --git a/java/api/QueryOptions.java b/java/api/QueryOptions.java index 65e7b63967..c9c4138320 100644 --- a/java/api/QueryOptions.java +++ b/java/api/QueryOptions.java @@ -72,7 +72,7 @@ public Optional includeInstanceTypes() { } /** - * Explicitly set the "include instance types" flag. + * Explicitly setsthe "include instance types" flag. * If set, specifies if types should be included in instance structs returned in ConceptRow answers. * This option allows reducing the amount of unnecessary data transmitted. * @@ -107,7 +107,7 @@ public Optional prefetchSize() { } /** - * Explicitly set the prefetch size. + * Explicitly setsthe prefetch size. * If set, specifies the number of extra query responses sent before the client side has to re-request more responses. * Increasing this may increase performance for queries with a huge number of answers, as it can * reduce the number of network round-trips at the cost of more resources on the server side. diff --git a/java/api/TransactionOptions.java b/java/api/TransactionOptions.java index cbf246b347..4b6d3d587d 100644 --- a/java/api/TransactionOptions.java +++ b/java/api/TransactionOptions.java @@ -25,15 +25,17 @@ import javax.annotation.CheckReturnValue; import java.util.Optional; +import static com.typedb.driver.jni.typedb_driver.transaction_options_get_read_consistency_level; import static com.typedb.driver.jni.typedb_driver.transaction_options_get_schema_lock_acquire_timeout_millis; import static com.typedb.driver.jni.typedb_driver.transaction_options_get_transaction_timeout_millis; +import static com.typedb.driver.jni.typedb_driver.transaction_options_has_read_consistency_level; import static com.typedb.driver.jni.typedb_driver.transaction_options_has_schema_lock_acquire_timeout_millis; import static com.typedb.driver.jni.typedb_driver.transaction_options_has_transaction_timeout_millis; import static com.typedb.driver.jni.typedb_driver.transaction_options_new; +import static com.typedb.driver.jni.typedb_driver.transaction_options_set_read_consistency_level; import static com.typedb.driver.jni.typedb_driver.transaction_options_set_schema_lock_acquire_timeout_millis; import static com.typedb.driver.jni.typedb_driver.transaction_options_set_transaction_timeout_millis; - /** * TypeDB transaction options. TransactionOptions object can be used to override * the default server behaviour for opened transactions. @@ -68,7 +70,7 @@ public Optional transactionTimeoutMillis() { } /** - * Explicitly set a transaction timeout. + * Explicitly sets a transaction timeout. * If set, specifies how long the driver should wait if opening a transaction is blocked by an exclusive schema write lock. * *

Examples

@@ -116,4 +118,37 @@ public TransactionOptions schemaLockAcquireTimeoutMillis(int schemaLockAcquireTi transaction_options_set_schema_lock_acquire_timeout_millis(nativeObject, schemaLockAcquireTimeoutMillis); return this; } + + /** + * Returns the value set for the read consistency level in this TransactionOptions object. + * If set, specifies the requested consistency level of the transaction opening operation. + * Affects only read transactions, as write and schema transactions require primary replicas. + * + *

Examples

+ *
+     * options.readConsistencyLevel();
+     * 
+ */ + public Optional readConsistencyLevel() { + if (transaction_options_has_read_consistency_level(nativeObject)) + return Optional.of(ConsistencyLevel.of(transaction_options_get_read_consistency_level(nativeObject))); + return Optional.empty(); + } + + /** + * Explicitly sets read consistency level. + * If set, specifies the requested consistency level of the transaction opening operation. + * Affects only read transactions, as write and schema transactions require primary replicas. + * + *

Examples

+ *
+     * options.schemaLockAcquireTimeoutMillis(schemaLockAcquireTimeoutMillis);
+     * 
+ * + * @param readConsistencyLevel The requested consistency level + */ + public TransactionOptions readConsistencyLevel(ConsistencyLevel readConsistencyLevel) { + transaction_options_set_read_consistency_level(nativeObject, readConsistencyLevel.nativeValue()); + return this; + } } diff --git a/java/api/analyze/NamedRole.java b/java/api/analyze/NamedRole.java index 41832448df..01e3d17a40 100644 --- a/java/api/analyze/NamedRole.java +++ b/java/api/analyze/NamedRole.java @@ -22,8 +22,8 @@ /** * 'links' & 'relates' constraints accept unscoped role names. * Since an unscoped role-name does not uniquely identify a role-type, - * (Different role-types belonging to different relation types may share the same name) - * an internal variable is introduced to handle the ambiguity + * (Different role-types belonging to different relation types may share the same name) + * an internal variable is introduced to handle the ambiguity */ public interface NamedRole { diff --git a/java/api/answer/ConceptRow.java b/java/api/answer/ConceptRow.java index 03543e9712..e05f5ffd8a 100644 --- a/java/api/answer/ConceptRow.java +++ b/java/api/answer/ConceptRow.java @@ -79,7 +79,7 @@ public interface ConceptRow { * conceptRow.get(columnName); * * - * @param columnName the variable (column name from ``column_names``) + * @param columnName the variable (column name from column_names) */ @CheckReturnValue Optional get(String columnName) throws TypeDBDriverException; diff --git a/java/api/database/Database.java b/java/api/database/Database.java index 4b2bb4bc15..ed2dbbf6d4 100644 --- a/java/api/database/Database.java +++ b/java/api/database/Database.java @@ -19,6 +19,7 @@ package com.typedb.driver.api.database; +import com.typedb.driver.api.ConsistencyLevel; import com.typedb.driver.common.exception.TypeDBDriverException; import javax.annotation.CheckReturnValue; @@ -27,12 +28,18 @@ public interface Database { /** * The database name as a string. + * + *

Examples

+ *
+     * database.name()
+     * 
*/ @CheckReturnValue String name(); /** - * A full schema text as a valid TypeQL define query string. + * A full schema text as a valid TypeQL define query string, using default strong consistency. + * See {@link #schema(ConsistencyLevel)} for more details and options. * *

Examples

*
@@ -40,10 +47,26 @@ public interface Database {
      * 
*/ @CheckReturnValue - String schema() throws TypeDBDriverException; + default String schema() throws TypeDBDriverException { + return schema(null); + } /** - * The types in the schema as a valid TypeQL define query string. + * A full schema text as a valid TypeQL define query string. + * + *

Examples

+ *
+     * database.schema(new ConsistencyLevel.Strong())
+     * 
+ * + * @param consistencyLevel The consistency level to use for the operation + */ + @CheckReturnValue + String schema(ConsistencyLevel consistencyLevel) throws TypeDBDriverException; + + /** + * The types in the schema as a valid TypeQL define query string, using default strong consistency. + * See {@link #typeSchema(ConsistencyLevel)} for more details and options. * *

Examples

*
@@ -51,11 +74,27 @@ public interface Database {
      * 
*/ @CheckReturnValue - String typeSchema() throws TypeDBDriverException; + default String typeSchema() throws TypeDBDriverException { + return typeSchema(null); + } /** - * Export a database into a schema definition and a data files saved to the disk. + * The types in the schema as a valid TypeQL define query string. + * + *

Examples

+ *
+     * database.typeSchema(new ConsistencyLevel.Strong())
+     * 
+ * + * @param consistencyLevel The consistency level to use for the operation + */ + @CheckReturnValue + String typeSchema(ConsistencyLevel consistencyLevel) throws TypeDBDriverException; + + /** + * Export a database into a schema definition and a data files saved to the disk, using default strong consistency. * This is a blocking operation and may take a significant amount of time depending on the database size. + * See {@link #exportToFile(String, String, ConsistencyLevel)} for more details and options. * *

Examples

*
@@ -65,82 +104,47 @@ public interface Database {
      * @param schemaFilePath The path to the schema definition file to be created
      * @param dataFilePath   The path to the data file to be created
      */
-    void exportToFile(String schemaFilePath, String dataFilePath) throws TypeDBDriverException;
+    default void exportToFile(String schemaFilePath, String dataFilePath) throws TypeDBDriverException {
+        exportToFile(schemaFilePath, dataFilePath, null);
+    }
 
     /**
-     * Deletes this database.
+     * Export a database into a schema definition and a data files saved to the disk.
+     * This is a blocking operation and may take a significant amount of time depending on the database size.
+     *
+     * 

Examples

+ *
+     * database.exportToFile("schema.typeql", "data.typedb", new ConsistencyLevel.Strong())
+     * 
+ * + * @param schemaFilePath The path to the schema definition file to be created + * @param dataFilePath The path to the data file to be created + * @param consistencyLevel The consistency level to use for the operation + */ + void exportToFile(String schemaFilePath, String dataFilePath, ConsistencyLevel consistencyLevel) throws TypeDBDriverException; + + /** + * Deletes this database, using default strong consistency. + * See {@link #delete(ConsistencyLevel)} for more details and options. * *

Examples

*
      * database.delete()
      * 
*/ - void delete() throws TypeDBDriverException; + default void delete() throws TypeDBDriverException { + delete(null); + } -// /** -// * Set of Replica instances for this database. -// * Only works in TypeDB Cloud / Enterprise -// * -// *

Examples

-// *
-//     * database.replicas()
-//     * 
-// */ -// @CheckReturnValue -// Set replicas(); -// -// /** -// * Returns the primary replica for this database. -// * Only works in TypeDB Cloud / Enterprise -// * -// *

Examples

-// *
-//     * database.primaryReplica()
-//     * 
-// */ -// @CheckReturnValue -// Optional primaryReplica(); -// -// /** -// * Returns the preferred replica for this database. Operations which can be run on any replica will prefer to use this replica. -// * Only works in TypeDB Cloud / Enterprise -// * -// *

Examples

-// *
-//     * database.preferredReplica()
-//     * 
-// */ -// @CheckReturnValue -// Optional preferredReplica(); -// -// /** -// * The metadata and state of an individual raft replica of a database. -// */ -// interface Replica { -// -// /** -// * The server hosting this replica -// */ -// @CheckReturnValue -// String server(); -// -// /** -// * Checks whether this is the primary replica of the raft cluster. -// */ -// @CheckReturnValue -// boolean isPrimary(); -// -// /** -// * Checks whether this is the preferred replica of the raft cluster. -// * If true, Operations which can be run on any replica will prefer to use this replica. -// */ -// @CheckReturnValue -// boolean isPreferred(); -// -// /** -// * The raft protocol ‘term’ of this replica. -// */ -// @CheckReturnValue -// long term(); -// } + /** + * Deletes this database. + * + *

Examples

+ *
+     * database.delete(new ConsistencyLevel.Strong())
+     * 
+ * + * @param consistencyLevel The consistency level to use for the operation + */ + void delete(ConsistencyLevel consistencyLevel) throws TypeDBDriverException; } diff --git a/java/api/database/DatabaseManager.java b/java/api/database/DatabaseManager.java index 7fdb30e5da..8334388550 100644 --- a/java/api/database/DatabaseManager.java +++ b/java/api/database/DatabaseManager.java @@ -19,6 +19,7 @@ package com.typedb.driver.api.database; +import com.typedb.driver.api.ConsistencyLevel; import com.typedb.driver.common.exception.TypeDBDriverException; import javax.annotation.CheckReturnValue; @@ -28,22 +29,36 @@ * Provides access to all database management methods. */ public interface DatabaseManager { + /** + * Retrieves all databases present on the TypeDB server, using default strong consistency. + * See {@link #all(ConsistencyLevel)} for more details and options. + * + *

Examples

+ *
+     * driver.databases().all()
+     * 
+ */ + @CheckReturnValue + default List all() throws TypeDBDriverException { + return all(null); + } /** - * Retrieve the database with the given name. + * Retrieves all databases present on the TypeDB server. * *

Examples

*
-     * driver.databases().get(name)
+     * driver.databases().all(new ConsistencyLevel.Strong())
      * 
* - * @param name The name of the database to retrieve + * @param consistencyLevel The consistency level to use for the operation */ @CheckReturnValue - Database get(String name) throws TypeDBDriverException; + List all(ConsistencyLevel consistencyLevel) throws TypeDBDriverException; /** - * Checks if a database with the given name exists. + * Checks if a database with the given name exists, using default strong consistency. + * See {@link #contains(String, ConsistencyLevel)} for more details and options. * *

Examples

*
@@ -53,10 +68,57 @@ public interface DatabaseManager {
      * @param name The database name to be checked
      */
     @CheckReturnValue
-    boolean contains(String name) throws TypeDBDriverException;
+    default boolean contains(String name) throws TypeDBDriverException {
+        return contains(name, null);
+    }
+
+    /**
+     * Checks if a database with the given name exists.
+     *
+     * 

Examples

+ *
+     * driver.databases().contains(name, new ConsistencyLevel.Strong())
+     * 
+ * + * @param name The database name to be checked + * @param consistencyLevel The consistency level to use for the operation + */ + @CheckReturnValue + boolean contains(String name, ConsistencyLevel consistencyLevel) throws TypeDBDriverException; + + /** + * Retrieves the database with the given name, using default strong consistency. + * See {@link #get(String, ConsistencyLevel)} for more details and options. + * + *

Examples

+ *
+     * driver.databases().get(name)
+     * 
+ * + * @param name The name of the database to retrieve + */ + @CheckReturnValue + default Database get(String name) throws TypeDBDriverException { + return get(name, null); + } /** - * Create a database with the given name. + * Retrieves the database with the given name. + * + *

Examples

+ *
+     * driver.databases().get(name, new ConsistencyLevel.Strong())
+     * 
+ * + * @param name The name of the database to retrieve + * @param consistencyLevel The consistency level to use for the operation + */ + @CheckReturnValue + Database get(String name, ConsistencyLevel consistencyLevel) throws TypeDBDriverException; + + /** + * Creates a database with the given name, using default strong consistency. + * See {@link #create(String, ConsistencyLevel)} for more details and options. * *

Examples

*
@@ -65,31 +127,35 @@ public interface DatabaseManager {
      *
      * @param name The name of the database to be created
      */
-    void create(String name) throws TypeDBDriverException;
+    default void create(String name) throws TypeDBDriverException {
+        create(name, null);
+    }
 
     /**
-     * Create a database with the given name based on previously exported another database's data loaded from a file.
-     * This is a blocking operation and may take a significant amount of time depending on the database size.
+     * Creates a database with the given name.
      *
      * 

Examples

*
-     * driver.databases().importFromFile(name, schema, "data.typedb")
+     * driver.databases().create(name, new ConsistencyLevel.Strong())
      * 
* - * @param name The name of the database to be created - * @param schema The schema definition query string for the database - * @param dataFilePath The exported database file path to import the data from + * @param name The name of the database to be created + * @param consistencyLevel The consistency level to use for the operation */ - void importFromFile(String name, String schema, String dataFilePath) throws TypeDBDriverException; + void create(String name, ConsistencyLevel consistencyLevel) throws TypeDBDriverException; /** - * Retrieves all databases present on the TypeDB server. + * Creates a database with the given name based on previously exported another database's data loaded from a file. + * This is a blocking operation and may take a significant amount of time depending on the database size. * *

Examples

*
-     * driver.databases().all()
+     * driver.databases().importFromFile(name, schema, "data.typedb")
      * 
+ * + * @param name The name of the database to be created + * @param schema The schema definition query string for the database + * @param dataFilePath The exported database file path to import the data from */ - @CheckReturnValue - List all() throws TypeDBDriverException; + void importFromFile(String name, String schema, String dataFilePath) throws TypeDBDriverException; } diff --git a/java/api/server/ReplicaRole.java b/java/api/server/ReplicaRole.java new file mode 100644 index 0000000000..f86a80fdda --- /dev/null +++ b/java/api/server/ReplicaRole.java @@ -0,0 +1,76 @@ +/* + * 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 com.typedb.driver.api.server; + +import com.typedb.driver.common.exception.TypeDBDriverException; + +import static com.typedb.driver.common.exception.ErrorMessage.Internal.UNEXPECTED_NATIVE_VALUE; + +/** + * This enum is used to specify the type of replica. + * + *

Examples

+ *
+ * replica.getType();
+ * 
+ */ +public enum ReplicaRole { + PRIMARY(0, com.typedb.driver.jni.ReplicaRole.Primary), + SECONDARY(1, com.typedb.driver.jni.ReplicaRole.Secondary); + + public final com.typedb.driver.jni.ReplicaRole nativeObject; + private final int id; + + ReplicaRole(int id, com.typedb.driver.jni.ReplicaRole nativeObject) { + this.id = id; + this.nativeObject = nativeObject; + } + + public static ReplicaRole of(com.typedb.driver.jni.ReplicaRole nativeType) { + if (nativeType == com.typedb.driver.jni.ReplicaRole.Primary) return PRIMARY; + else if (nativeType == com.typedb.driver.jni.ReplicaRole.Secondary) return SECONDARY; + throw new TypeDBDriverException(UNEXPECTED_NATIVE_VALUE); + } + + public int id() { + return id; + } + + /** + * Checks whether this is the primary replica of the raft cluster. + */ + public boolean isPrimary() { + return nativeObject == com.typedb.driver.jni.ReplicaRole.Primary; + } + + /** + * Checks whether this is a candidate replica of the raft cluster. + */ + public boolean isCandidate() { + return nativeObject == com.typedb.driver.jni.ReplicaRole.Candidate; + } + + /** + * Checks whether this is a secondary replica of the raft cluster. + */ + public boolean isSecondary() { + return nativeObject == com.typedb.driver.jni.ReplicaRole.Secondary; + } +} diff --git a/java/api/server/ServerReplica.java b/java/api/server/ServerReplica.java new file mode 100644 index 0000000000..0c83680c82 --- /dev/null +++ b/java/api/server/ServerReplica.java @@ -0,0 +1,62 @@ +/* + * 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 com.typedb.driver.api.server; + +import com.typedb.driver.api.server.ReplicaRole; + +import javax.annotation.CheckReturnValue; +import java.util.Optional; + +/** + * The metadata and state of an individual raft replica of a driver connection. + */ +public interface ServerReplica { + // TODO: This is what u64 is converted to. This one feels weird, although I don't know what to do with it. + + /** + * Returns the id of this replica. + */ + @CheckReturnValue + long getID(); + + /** + * Returns the address this replica is hosted at. + */ + @CheckReturnValue + String getAddress(); + + /** + * Returns whether this is the primary replica of the raft cluster or any of the supporting types. + */ + @CheckReturnValue + Optional getRole(); + + /** + * Checks whether this is the primary replica of the raft cluster. + */ + @CheckReturnValue + Boolean isPrimary(); + + /** + * Returns the raft protocol ‘term’ of this replica. + */ + @CheckReturnValue + Optional getTerm(); +} diff --git a/java/api/server/ServerVersion.java b/java/api/server/ServerVersion.java new file mode 100644 index 0000000000..f216a8ed79 --- /dev/null +++ b/java/api/server/ServerVersion.java @@ -0,0 +1,65 @@ +/* + * 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 com.typedb.driver.api.server; + +import com.typedb.driver.common.NativeObject; + +/** + * A full TypeDB server's version specification. + * + *

Examples

+ *
+ * driver.serverVersion();
+ * 
+ */ +public class ServerVersion extends NativeObject { + /** + * @hidden + */ + public ServerVersion(com.typedb.driver.jni.ServerVersion nativeObject) { + super(nativeObject); + } + + /** + * Returns the server's distribution. + * + *

Examples

+ *
+     * serverVersion.getDistribution();
+     * 
+ */ + public String getDistribution() { + assert (nativeObject.isOwned()); + return nativeObject.getDistribution(); + } + + /** + * Returns the server's version. + * + *

Examples

+ *
+     * serverVersion.getVersion();
+     * 
+ */ + public String getVersion() { + assert (nativeObject.isOwned()); + return nativeObject.getVersion(); + } +} diff --git a/java/api/user/User.java b/java/api/user/User.java index 8ce4af72d9..46b3f43b3a 100644 --- a/java/api/user/User.java +++ b/java/api/user/User.java @@ -20,6 +20,8 @@ package com.typedb.driver.api.user; +import com.typedb.driver.api.ConsistencyLevel; + import javax.annotation.CheckReturnValue; /** @@ -32,27 +34,56 @@ public interface User { @CheckReturnValue String name(); - // TODO: Not implemented -// /** -// * Returns the number of seconds remaining till this user’s current password expires. -// */ -// Optional passwordExpirySeconds(); + /** + * Updates the password for this user, using default strong consistency. + * See {@link #updatePassword(String, ConsistencyLevel)} for more details and options. + * + *

Examples

+ *
+     * user.updatePassword("new-password");
+     * 
+ * + * @param password The new password + */ + default void updatePassword(String password) { + updatePassword(password, null); + } /** * Updates the password for this user. * - * @param passwordOld The current password of this user - * @param passwordNew The new password + *

Examples

+ *
+     * user.updatePassword("new-password", new ConsistencyLevel.Strong());
+     * 
+ * + * @param password The new password + * @param consistencyLevel The consistency level to use for the operation + */ + void updatePassword(String password, ConsistencyLevel consistencyLevel); + + /** + * Deletes this user, using default strong consistency. + * See {@link #delete(ConsistencyLevel)} for more details and options. + * + *

Examples

+ *
+     * user.delete();
+     * 
*/ - void updatePassword(String password); + default void delete() { + delete(null); + } /** - * Deletes a user with the given name. + * Deletes this user. * *

Examples

*
-     * driver.users().delete(username);
+     * user.delete(new ConsistencyLevel.Strong());
      * 
+ * + * @param consistencyLevel The consistency level to use for the operation */ - void delete(); + void delete(ConsistencyLevel consistencyLevel); } diff --git a/java/api/user/UserManager.java b/java/api/user/UserManager.java index 5c2a693fb3..1eb4e84d17 100644 --- a/java/api/user/UserManager.java +++ b/java/api/user/UserManager.java @@ -19,6 +19,7 @@ package com.typedb.driver.api.user; +import com.typedb.driver.api.ConsistencyLevel; import com.typedb.driver.common.exception.TypeDBDriverException; import javax.annotation.CheckReturnValue; @@ -29,20 +30,63 @@ */ public interface UserManager { /** - * Checks if a user with the given name exists. + * Retrieves all users which exist on the TypeDB server, using default strong consistency. + * See {@link #all(ConsistencyLevel)} for more details and options. + * + *

Examples

+ *
+     * driver.users().all();
+     * 
+ */ + default Set all() throws TypeDBDriverException { + return all(null); + } + + /** + * Retrieves all users which exist on the TypeDB server. + * + *

Examples

+ *
+     * driver.users().all(new ConsistencyLevel.Strong());
+     * 
+ * + * @param consistencyLevel The consistency level to use for the operation + */ + Set all(ConsistencyLevel consistencyLevel) throws TypeDBDriverException; + + /** + * Checks if a user with the given name exists., using default strong consistency. + * See {@link #contains(String, ConsistencyLevel)} for more details and options. * *

Examples

*
      * driver.users().contains(username);
      * 
* - * @param username The user name to be checked + * @param username The username to be checked */ @CheckReturnValue - boolean contains(String username) throws TypeDBDriverException; + default boolean contains(String username) throws TypeDBDriverException { + return contains(username, null); + } /** - * Retrieves a user with the given name. + * Checks if a user with the given name exists. + * + *

Examples

+ *
+     * driver.users().contains(username, new ConsistencyLevel.Strong());
+     * 
+ * + * @param username The username to be checked + * @param consistencyLevel The consistency level to use for the operation + */ + @CheckReturnValue + boolean contains(String username, ConsistencyLevel consistencyLevel) throws TypeDBDriverException; + + /** + * Retrieves a user with the given name, using default strong consistency. + * See {@link #get(String, ConsistencyLevel)} for more details and options. * *

Examples

*
@@ -52,33 +96,54 @@ public interface UserManager {
      * @param username The name of the user to retrieve
      */
     @CheckReturnValue
-    User get(String username) throws TypeDBDriverException;
+    default User get(String username) throws TypeDBDriverException {
+        return get(username, null);
+    }
 
-    // TODO: I don't like this, leaving this way for now. Use driver.users().get(username)
+    /**
+     * Retrieves a user with the given name.
+     *
+     * 

Examples

+ *
+     * driver.users().get(username, new ConsistencyLevel.Strong());
+     * 
+ * + * @param username The name of the user to retrieve + * @param consistencyLevel The consistency level to use for the operation + */ + @CheckReturnValue + User get(String username, ConsistencyLevel consistencyLevel) throws TypeDBDriverException; /** - * Retrieves the name of the user who opened the current connection. + * Retrieves the name of the user who opened the current connection, using default strong consistency. + * See {@link #getCurrent(ConsistencyLevel)} for more details and options. * *

Examples

*
-     * driver.users().getCurrentUsername();
+     * driver.users().getCurrent();
      * 
*/ @CheckReturnValue - User getCurrentUser() throws TypeDBDriverException; + default User getCurrent() throws TypeDBDriverException { + return getCurrent(null); + } /** - * Retrieves all users which exist on the TypeDB server. + * Retrieves the name of the user who opened the current connection. * *

Examples

*
-     * driver.users().all();
+     * driver.users().getCurrent(new ConsistencyLevel.Strong());
      * 
+ * + * @param consistencyLevel The consistency level to use for the operation */ - Set all() throws TypeDBDriverException; + @CheckReturnValue + User getCurrent(ConsistencyLevel consistencyLevel) throws TypeDBDriverException; /** - * Creates a user with the given name & password. + * Creates a user with the given name & password, using default strong consistency. + * See {@link #create(String, String, ConsistencyLevel)} for more details and options. * *

Examples

*
@@ -88,5 +153,21 @@ public interface UserManager {
      * @param username The name of the user to be created
      * @param password The password of the user to be created
      */
-    void create(String username, String password) throws TypeDBDriverException;
+    default void create(String username, String password) throws TypeDBDriverException {
+        create(username, password, null);
+    }
+
+    /**
+     * Creates a user with the given name & password.
+     *
+     * 

Examples

+ *
+     * driver.users().create(username, password, new ConsistencyLevel.Strong());
+     * 
+ * + * @param username The name of the user to be created + * @param password The password of the user to be created + * @param consistencyLevel The consistency level to use for the operation + */ + void create(String username, String password, ConsistencyLevel consistencyLevel) throws TypeDBDriverException; } diff --git a/java/connection/DatabaseImpl.java b/java/connection/DatabaseImpl.java index 24cb2a83cc..4a41bb29a4 100644 --- a/java/connection/DatabaseImpl.java +++ b/java/connection/DatabaseImpl.java @@ -19,6 +19,7 @@ package com.typedb.driver.connection; +import com.typedb.driver.api.ConsistencyLevel; import com.typedb.driver.api.database.Database; import com.typedb.driver.common.NativeObject; import com.typedb.driver.common.Validator; @@ -43,42 +44,42 @@ public String name() { } @Override - public String schema() throws TypeDBDriverException { + public String schema(ConsistencyLevel consistencyLevel) throws TypeDBDriverException { if (!nativeObject.isOwned()) throw new TypeDBDriverException(DATABASE_DELETED); try { - return database_schema(nativeObject); + return database_schema(nativeObject, ConsistencyLevel.nativeValue(consistencyLevel)); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } @Override - public String typeSchema() throws TypeDBDriverException { + public String typeSchema(ConsistencyLevel consistencyLevel) throws TypeDBDriverException { if (!nativeObject.isOwned()) throw new TypeDBDriverException(DATABASE_DELETED); try { - return database_type_schema(nativeObject); + return database_type_schema(nativeObject, ConsistencyLevel.nativeValue(consistencyLevel)); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } @Override - public void exportToFile(String schemaFilePath, String dataFilePath) throws TypeDBDriverException { + public void exportToFile(String schemaFilePath, String dataFilePath, ConsistencyLevel consistencyLevel) throws TypeDBDriverException { Validator.requireNonNull(schemaFilePath, "schemaFilePath"); Validator.requireNonNull(dataFilePath, "dataFilePath"); try { - database_export_to_file(nativeObject, schemaFilePath, dataFilePath); + database_export_to_file(nativeObject, schemaFilePath, dataFilePath, ConsistencyLevel.nativeValue(consistencyLevel)); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } @Override - public void delete() throws TypeDBDriverException { + public void delete(ConsistencyLevel consistencyLevel) throws TypeDBDriverException { if (!nativeObject.isOwned()) throw new TypeDBDriverException(DATABASE_DELETED); try { // NOTE: .released() relinquishes ownership of the native object to the Rust side - database_delete(nativeObject.released()); + database_delete(nativeObject.released(), ConsistencyLevel.nativeValue(consistencyLevel)); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } @@ -88,52 +89,4 @@ public void delete() throws TypeDBDriverException { public String toString() { return name(); } - -// @Override -// public Set replicas() { -// if (!nativeObject.isOwned()) throw new TypeDBDriverException(DATABASE_DELETED); -// return new NativeIterator<>(database_get_replicas_info(nativeObject)).stream().map(Replica::new).collect(Collectors.toSet()); -// } -// -// @Override -// public Optional primaryReplica() { -// if (!nativeObject.isOwned()) throw new TypeDBDriverException(DATABASE_DELETED); -// com.typedb.driver.jni.ReplicaInfo res = database_get_primary_replica_info(nativeObject); -// if (res != null) return Optional.of(new Replica(res)); -// else return Optional.empty(); -// } -// -// @Override -// public Optional preferredReplica() { -// if (!nativeObject.isOwned()) throw new TypeDBDriverException(DATABASE_DELETED); -// com.typedb.driver.jni.ReplicaInfo res = database_get_preferred_replica_info(nativeObject); -// if (res != null) return Optional.of(new Replica(res)); -// else return Optional.empty(); -// } -// -// public static class Replica extends NativeObject implements Database.Replica { -// Replica(com.typedb.driver.jni.ReplicaInfo replicaInfo) { -// super(replicaInfo); -// } -// -// @Override -// public String server() { -// return replica_info_get_server(nativeObject); -// } -// -// @Override -// public boolean isPrimary() { -// return replica_info_is_primary(nativeObject); -// } -// -// @Override -// public boolean isPreferred(){ -// return replica_info_is_preferred(nativeObject); -// } -// -// @Override -// public long term() { -// return replica_info_get_term(nativeObject); -// } -// } } diff --git a/java/connection/DatabaseManagerImpl.java b/java/connection/DatabaseManagerImpl.java index 8c2a2f83df..6bfca5c968 100644 --- a/java/connection/DatabaseManagerImpl.java +++ b/java/connection/DatabaseManagerImpl.java @@ -19,6 +19,7 @@ package com.typedb.driver.connection; +import com.typedb.driver.api.ConsistencyLevel; import com.typedb.driver.api.database.Database; import com.typedb.driver.api.database.DatabaseManager; import com.typedb.driver.common.NativeIterator; @@ -42,51 +43,51 @@ public DatabaseManagerImpl(com.typedb.driver.jni.TypeDBDriver driver) { } @Override - public Database get(String name) throws TypeDBDriverException { - Validator.requireNonNull(name, "name"); + public List all(ConsistencyLevel consistencyLevel) throws TypeDBDriverException { try { - return new DatabaseImpl(databases_get(nativeDriver, name)); + return new NativeIterator<>(databases_all(nativeDriver, ConsistencyLevel.nativeValue(consistencyLevel))).stream().map(DatabaseImpl::new).collect(toList()); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } @Override - public boolean contains(String name) throws TypeDBDriverException { + public boolean contains(String name, ConsistencyLevel consistencyLevel) throws TypeDBDriverException { Validator.requireNonNull(name, "name"); try { - return databases_contains(nativeDriver, name); + return databases_contains(nativeDriver, name, ConsistencyLevel.nativeValue(consistencyLevel)); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } @Override - public void create(String name) throws TypeDBDriverException { + public Database get(String name, ConsistencyLevel consistencyLevel) throws TypeDBDriverException { Validator.requireNonNull(name, "name"); try { - databases_create(nativeDriver, name); + return new DatabaseImpl(databases_get(nativeDriver, name, ConsistencyLevel.nativeValue(consistencyLevel))); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } @Override - public void importFromFile(String name, String schema, String dataFilePath) throws TypeDBDriverException { + public void create(String name, ConsistencyLevel consistencyLevel) throws TypeDBDriverException { Validator.requireNonNull(name, "name"); - Validator.requireNonNull(schema, "schema"); - Validator.requireNonNull(dataFilePath, "dataFilePath"); try { - databases_import_from_file(nativeDriver, name, schema, dataFilePath); + databases_create(nativeDriver, name, ConsistencyLevel.nativeValue(consistencyLevel)); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } @Override - public List all() throws TypeDBDriverException { + public void importFromFile(String name, String schema, String dataFilePath) throws TypeDBDriverException { + Validator.requireNonNull(name, "name"); + Validator.requireNonNull(schema, "schema"); + Validator.requireNonNull(dataFilePath, "dataFilePath"); try { - return new NativeIterator<>(databases_all(nativeDriver)).stream().map(DatabaseImpl::new).collect(toList()); + databases_import_from_file(nativeDriver, name, schema, dataFilePath); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } diff --git a/java/connection/DriverImpl.java b/java/connection/DriverImpl.java index 1bcfd734d5..46a02d0069 100644 --- a/java/connection/DriverImpl.java +++ b/java/connection/DriverImpl.java @@ -19,21 +19,41 @@ package com.typedb.driver.connection; +import com.typedb.driver.api.ConsistencyLevel; import com.typedb.driver.api.Credentials; import com.typedb.driver.api.Driver; import com.typedb.driver.api.DriverOptions; import com.typedb.driver.api.Transaction; import com.typedb.driver.api.TransactionOptions; import com.typedb.driver.api.database.DatabaseManager; +import com.typedb.driver.api.server.ServerReplica; +import com.typedb.driver.api.server.ServerVersion; import com.typedb.driver.api.user.UserManager; +import com.typedb.driver.common.NativeIterator; import com.typedb.driver.common.NativeObject; import com.typedb.driver.common.Validator; import com.typedb.driver.common.exception.TypeDBDriverException; import com.typedb.driver.user.UserManagerImpl; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import static com.typedb.driver.jni.typedb_driver.driver_deregister_replica; import static com.typedb.driver.jni.typedb_driver.driver_force_close; import static com.typedb.driver.jni.typedb_driver.driver_is_open; -import static com.typedb.driver.jni.typedb_driver.driver_open_with_description; +import static com.typedb.driver.jni.typedb_driver.driver_new_with_address_translation_with_description; +import static com.typedb.driver.jni.typedb_driver.driver_new_with_addresses_with_description; +import static com.typedb.driver.jni.typedb_driver.driver_new_with_description; +import static com.typedb.driver.jni.typedb_driver.driver_primary_replica; +import static com.typedb.driver.jni.typedb_driver.driver_register_replica; +import static com.typedb.driver.jni.typedb_driver.driver_replicas; +import static com.typedb.driver.jni.typedb_driver.driver_server_version; +import static com.typedb.driver.jni.typedb_driver.driver_update_address_translation; +import static java.util.stream.Collectors.toSet; public class DriverImpl extends NativeObject implements Driver { @@ -41,6 +61,14 @@ public DriverImpl(String address, Credentials credentials, DriverOptions driverO this(open(address, credentials, driverOptions)); } + public DriverImpl(Set addresses, Credentials credentials, DriverOptions driverOptions) throws TypeDBDriverException { + this(open(addresses, credentials, driverOptions)); + } + + public DriverImpl(Map addressTranslation, Credentials credentials, DriverOptions driverOptions) throws TypeDBDriverException { + this(open(addressTranslation, credentials, driverOptions)); + } + private DriverImpl(com.typedb.driver.jni.TypeDBDriver connection) { super(connection); } @@ -50,7 +78,30 @@ private static com.typedb.driver.jni.TypeDBDriver open(String address, Credentia Validator.requireNonNull(credentials, "credentials"); Validator.requireNonNull(driverOptions, "driverOptions"); try { - return driver_open_with_description(address, credentials.nativeObject, driverOptions.nativeObject, LANGUAGE); + return driver_new_with_description(address, credentials.nativeObject, driverOptions.nativeObject, LANGUAGE); + } catch (com.typedb.driver.jni.Error e) { + throw new TypeDBDriverException(e); + } + } + + private static com.typedb.driver.jni.TypeDBDriver open(Set addresses, Credentials credentials, DriverOptions driverOptions) { + Validator.requireNonNull(addresses, "addresses"); + Validator.requireNonNull(credentials, "credentials"); + Validator.requireNonNull(driverOptions, "driverOptions"); + try { + return driver_new_with_addresses_with_description(addresses.toArray(new String[0]), credentials.nativeObject, driverOptions.nativeObject, LANGUAGE); + } catch (com.typedb.driver.jni.Error e) { + throw new TypeDBDriverException(e); + } + } + + private static com.typedb.driver.jni.TypeDBDriver open(Map addressTranslation, Credentials credentials, DriverOptions driverOptions) { + Validator.requireNonNull(addressTranslation, "addressTranslation"); + Validator.requireNonNull(credentials, "credentials"); + Validator.requireNonNull(driverOptions, "driverOptions"); + try { + Map.Entry addresses = getTranslatedAddresses(addressTranslation); + return driver_new_with_address_translation_with_description(addresses.getKey(), addresses.getValue(), credentials.nativeObject, driverOptions.nativeObject, LANGUAGE); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } @@ -61,6 +112,15 @@ public boolean isOpen() { return driver_is_open(nativeObject); } + @Override + public ServerVersion serverVersion(ConsistencyLevel consistencyLevel) { + try { + return new ServerVersion(driver_server_version(nativeObject, ConsistencyLevel.nativeValue(consistencyLevel))); + } catch (com.typedb.driver.jni.Error e) { + throw new TypeDBDriverException(e); + } + } + @Override public UserManager users() { return new UserManagerImpl(nativeObject); @@ -83,6 +143,55 @@ public Transaction transaction(String database, Transaction.Type type, Transacti return new TransactionImpl(this, database, type, options); } + @Override + public Set replicas(ConsistencyLevel consistencyLevel) { + try { + + return new NativeIterator<>(driver_replicas(nativeObject, ConsistencyLevel.nativeValue(consistencyLevel))) + .stream().map(ServerReplicaImpl::new).collect(toSet()); + } catch (com.typedb.driver.jni.Error error) { + throw new TypeDBDriverException(error); + } + } + + @Override + public Optional primaryReplica(ConsistencyLevel consistencyLevel) { + com.typedb.driver.jni.ServerReplica nativeReplica = driver_primary_replica(nativeObject, ConsistencyLevel.nativeValue(consistencyLevel)); + if (nativeReplica != null) { + return Optional.of(new ServerReplicaImpl(nativeReplica)); + } + return Optional.empty(); + } + + @Override + public void registerReplica(long replicaID, String address) { + try { + driver_register_replica(nativeObject, replicaID, address); + } catch (com.typedb.driver.jni.Error error) { + throw new TypeDBDriverException(error); + } + } + + @Override + public void deregisterReplica(long replicaID) { + try { + driver_deregister_replica(nativeObject, replicaID); + } catch (com.typedb.driver.jni.Error error) { + throw new TypeDBDriverException(error); + } + } + + @Override + public void updateAddressTranslation(Map addressTranslation) { + Validator.requireNonNull(addressTranslation, "addressTranslation"); + try { + Map.Entry addresses = getTranslatedAddresses(addressTranslation); + driver_update_address_translation(nativeObject, addresses.getKey(), addresses.getValue()); + } catch (com.typedb.driver.jni.Error e) { + throw new TypeDBDriverException(e); + } + } + @Override public void close() { try { @@ -91,4 +200,16 @@ public void close() { throw new TypeDBDriverException(error); } } + + public static Map.Entry getTranslatedAddresses(Map addressTranslation) { + List publicAddresses = new ArrayList<>(); + List privateAddresses = new ArrayList<>(); + + for (Map.Entry entry : addressTranslation.entrySet()) { + publicAddresses.add(entry.getKey()); + privateAddresses.add(entry.getValue()); + } + + return new AbstractMap.SimpleEntry<>(publicAddresses.toArray(new String[0]), privateAddresses.toArray(new String[0])); + } } diff --git a/java/connection/ServerReplicaImpl.java b/java/connection/ServerReplicaImpl.java new file mode 100644 index 0000000000..006747efaa --- /dev/null +++ b/java/connection/ServerReplicaImpl.java @@ -0,0 +1,76 @@ +/* + * 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 com.typedb.driver.connection; + +import com.typedb.driver.api.server.ReplicaRole; +import com.typedb.driver.api.server.ServerReplica; +import com.typedb.driver.common.NativeObject; + +import java.util.Optional; + +import static com.typedb.driver.jni.typedb_driver.server_replica_get_address; +import static com.typedb.driver.jni.typedb_driver.server_replica_get_id; +import static com.typedb.driver.jni.typedb_driver.server_replica_is_primary; +import static com.typedb.driver.jni.typedb_driver.server_replica_has_term; +import static com.typedb.driver.jni.typedb_driver.server_replica_has_role; +import static com.typedb.driver.jni.typedb_driver.server_replica_get_term; +import static com.typedb.driver.jni.typedb_driver.server_replica_get_role; + +public class ServerReplicaImpl extends NativeObject implements ServerReplica { + public ServerReplicaImpl(com.typedb.driver.jni.ServerReplica serverReplica) { + super(serverReplica); + } + + @Override + public long getID() { + return server_replica_get_id(nativeObject); + } + + @Override + public String getAddress() { + return server_replica_get_address(nativeObject); + } + + @Override + public Optional getRole() { + if (server_replica_has_role(nativeObject)) { + return Optional.of(ReplicaRole.of(server_replica_get_role(nativeObject))); + } + return Optional.empty(); + } + + @Override + public Boolean isPrimary() { + return server_replica_is_primary(nativeObject); + } + + @Override + public Optional getTerm() { + if (server_replica_has_term(nativeObject)) { + return Optional.of(server_replica_get_term(nativeObject)); + } + return Optional.empty(); + } + + @Override + public String toString() { + return getAddress(); + } +} diff --git a/java/docs_structure.bzl b/java/docs_structure.bzl index a34c1ae3e6..0baaebb922 100644 --- a/java/docs_structure.bzl +++ b/java/docs_structure.bzl @@ -83,11 +83,18 @@ dir_mapping = { "Concept.adoc": "concept", "TypeDB.adoc": "connection", "DriverOptions.adoc": "connection", + "DriverTlsConfig.adoc": "connection", "Credentials.adoc": "connection", + "ConsistencyLevel.adoc": "connection", + "ConsistencyLevel.Strong.adoc": "connection", + "ConsistencyLevel.Eventual.adoc": "connection", + "ConsistencyLevel.ReplicaDependent.adoc": "connection", + "ReplicaRole.adoc": "connection", + "ServerReplica.adoc": "connection", + "ServerVersion.adoc": "connection", "Driver.adoc": "connection", "User.adoc": "connection", "UserManager.adoc": "connection", -# "Database.Replica.adoc": "connection", "Database.adoc": "connection", "DatabaseManager.adoc": "connection", "Relation.adoc": "data", diff --git a/java/test/behaviour/config/Parameters.java b/java/test/behaviour/config/Parameters.java index ef3673044e..c1d8c0e250 100644 --- a/java/test/behaviour/config/Parameters.java +++ b/java/test/behaviour/config/Parameters.java @@ -19,6 +19,7 @@ package com.typedb.driver.test.behaviour.config; +import com.typedb.driver.api.ConsistencyLevel; import com.typedb.driver.api.QueryType; import com.typedb.driver.api.Transaction; import io.cucumber.java.DataTableType; @@ -42,6 +43,14 @@ public class Parameters { + private static boolean clusterMode = false; + private static final int RETRY_ATTEMPTS = 3; + private static final int RETRY_DELAY_MS = 500; + + public static void setClusterMode(boolean isCluster) { + clusterMode = isCluster; + } + @ParameterType("true|false") public Boolean bool(String bool) { return Boolean.parseBoolean(bool); @@ -173,6 +182,11 @@ public IsByVarIndex by_index_of_var(String value) { return null; } + @ParameterType("strong|eventual|replica\\(.*\\)") + public Consistency consistency_level(String value) { + return Consistency.parse(value); + } + public enum ConceptKind { CONCEPT("concept"), TYPE("type"), @@ -280,6 +294,8 @@ public MayError(boolean mayError, String message) { } public void check(Runnable function) { + int attempts = clusterMode ? RETRY_ATTEMPTS : 1; + if (mayError) { if (message.isEmpty()) { assertThrows(function); @@ -287,7 +303,24 @@ public void check(Runnable function) { assertThrowsWithMessage(function, message); } } else { - function.run(); + Exception lastException = null; + for (int i = 0; i < attempts; i++) { + try { + function.run(); + return; + } catch (Exception e) { + lastException = e; + if (i < attempts - 1) { + try { + Thread.sleep(RETRY_DELAY_MS); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException(ie); + } + } + } + } + throw new RuntimeException(lastException); } } } @@ -385,4 +418,34 @@ public void check(boolean toCheck) { DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS VV"), DateTimeFormatter.ISO_ZONED_DATE_TIME ); + + public static class Consistency { + private final ConsistencyLevel level; + + public Consistency(ConsistencyLevel level) { + this.level = level; + } + + public ConsistencyLevel level() { + return level; + } + + public static Consistency parse(String value) { + if (value.equalsIgnoreCase("strong")) { + return new Consistency(new ConsistencyLevel.Strong()); + } else if (value.equalsIgnoreCase("eventual")) { + return new Consistency(new ConsistencyLevel.Eventual()); + } else if (value.toLowerCase().startsWith("replica(") && value.endsWith(")")) { + String address = value.substring("replica(".length(), value.length() - 1); + return new Consistency(new ConsistencyLevel.ReplicaDependent(address)); + } else { + throw new IllegalArgumentException("Unknown consistency level: " + value); + } + } + + @Override + public String toString() { + return "Consistency(" + level + ")"; + } + } } diff --git a/java/test/behaviour/connection/BUILD b/java/test/behaviour/connection/BUILD index 3508c0c97a..f0908654e5 100644 --- a/java/test/behaviour/connection/BUILD +++ b/java/test/behaviour/connection/BUILD @@ -33,13 +33,14 @@ java_library( # External dependencies from Maven "@maven//:junit_junit", # "@maven//:com_typedb_typedb_runner", + "@maven//:io_cucumber_cucumber_java", ], ) java_library( - name = "steps-community", + name = "steps-core", srcs = [ - "ConnectionStepsCommunity.java", + "ConnectionStepsCore.java", ], visibility = ["//visibility:public"], deps = [ diff --git a/java/test/behaviour/connection/ConnectionStepsBase.java b/java/test/behaviour/connection/ConnectionStepsBase.java index d2df6a82c1..7022a9f924 100644 --- a/java/test/behaviour/connection/ConnectionStepsBase.java +++ b/java/test/behaviour/connection/ConnectionStepsBase.java @@ -19,20 +19,22 @@ package com.typedb.driver.test.behaviour.connection; +import com.typedb.driver.api.ConsistencyLevel; import com.typedb.driver.api.Credentials; import com.typedb.driver.api.Driver; import com.typedb.driver.api.DriverOptions; +import com.typedb.driver.api.DriverTlsConfig; import com.typedb.driver.api.QueryOptions; import com.typedb.driver.api.Transaction; import com.typedb.driver.api.TransactionOptions; +import com.typedb.driver.api.server.ReplicaRole; +import com.typedb.driver.api.server.ServerVersion; import com.typedb.driver.test.behaviour.config.Parameters; import com.typedb.driver.test.behaviour.util.Util; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; @@ -41,13 +43,13 @@ import static com.typedb.driver.test.behaviour.util.Util.createTempDir; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public abstract class ConnectionStepsBase { public static final String ADMIN_USERNAME = "admin"; public static final String ADMIN_PASSWORD = "password"; public static final Credentials DEFAULT_CREDENTIALS = new Credentials(ADMIN_USERNAME, ADMIN_PASSWORD); - public static final DriverOptions DEFAULT_CONNECTION_SETTINGS = new DriverOptions(false, null); - public static final Map serverOptions = Collections.emptyMap(); public static int THREAD_POOL_SIZE = 32; public static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE); public static Driver driver; @@ -57,8 +59,10 @@ public abstract class ConnectionStepsBase { public static List backgroundTransactions = new ArrayList<>(); public static List> transactionsParallel = new ArrayList<>(); + public static DriverOptions driverOptions = new DriverOptions(DriverTlsConfig.disabled()); public static Optional transactionOptions = Optional.empty(); public static Optional queryOptions = Optional.empty(); + public static Optional databaseOperationConsistency = Optional.empty(); static boolean isBeforeAllRan = false; static final int BEFORE_TIMEOUT_MILLIS = 10; @@ -117,13 +121,18 @@ void after() { cleanupBackgroundTransactions(); transactionOptions = Optional.empty(); queryOptions = Optional.empty(); + databaseOperationConsistency = Optional.empty(); + if (driver.isOpen()) { + driver.close(); + } driver = createDefaultTypeDBDriver(); driver.users().all().stream().filter(user -> !user.name().equals(ADMIN_USERNAME)).forEach(user -> driver.users().get(user.name()).delete()); driver.users().get(ADMIN_USERNAME).updatePassword(ADMIN_PASSWORD); driver.databases().all().forEach(database -> driver.databases().get(database.name()).delete()); driver.close(); backgroundDriver.close(); + driverOptions = new DriverOptions(DriverTlsConfig.disabled()); } void cleanupTransactions() { @@ -144,11 +153,9 @@ void cleanupBackgroundTransactions() { backgroundTransactions.clear(); } - abstract Driver createTypeDBDriver(String address, Credentials credentials, DriverOptions driverOptions); - abstract Driver createDefaultTypeDBDriver(); - public static void initTransactionOptionsIfNeeded() { // TODO: Implement steps + public static void initTransactionOptionsIfNeeded() { if (transactionOptions.isEmpty()) { transactionOptions = Optional.of(new TransactionOptions()); } @@ -173,6 +180,73 @@ void connection_is_open(boolean isOpen) { assertEquals(isOpen, driver != null && driver.isOpen()); } + void connection_contains_distribution(Parameters.MayError mayError) { + mayError.check(() -> { + ServerVersion serverVersion = driver.serverVersion(); + assertFalse(serverVersion.getDistribution().isEmpty()); + }); + } + + void connection_contains_version(Parameters.MayError mayError) { + mayError.check(() -> { + ServerVersion serverVersion = driver.serverVersion(); + assertFalse(serverVersion.getVersion().isEmpty()); + }); + } + + void connection_has_count_replicas(int count) { + assertEquals(driver.replicas().size(), count); + } + + void connection_primary_replica_exists() { + assertTrue(driver.primaryReplica().isPresent()); + } + + void connection_get_replica_exists(String address, Parameters.ExistsOrDoesnt existsOrDoesnt) { + boolean exists = driver.replicas().stream().anyMatch(r -> r.getAddress().equals(address)); + existsOrDoesnt.check(exists); + } + + void connection_get_replica_has_term(String address) { + var replica = driver.replicas().stream().filter(r -> r.getAddress().equals(address)).findFirst(); + Parameters.ExistsOrDoesnt.DOES.check(replica.isPresent()); + // term should exist (can be any value >= 0) + } + + void connection_replicas_have_roles(List roles) { + int expectedPrimaryCount = 0; + int expectedSecondaryCount = 0; + int expectedCandidateCount = 0; + + for (String role : roles) { + switch (role.toLowerCase()) { + case "primary": + expectedPrimaryCount++; + break; + case "secondary": + expectedSecondaryCount++; + break; + case "candidate": + expectedCandidateCount++; + break; + default: + throw new IllegalArgumentException("Unknown replica role: " + role); + } + } + + var replicas = driver.replicas(); + int actualPrimaryCount = (int) replicas.stream() + .filter(r -> r.getRole().map(ReplicaRole::isPrimary).orElse(false)).count(); + int actualSecondaryCount = (int) replicas.stream() + .filter(r -> r.getRole().map(ReplicaRole::isSecondary).orElse(false)).count(); + int actualCandidateCount = (int) replicas.stream() + .filter(r -> r.getRole().map(ReplicaRole::isCandidate).orElse(false)).count(); + + assertEquals("Primary replica count mismatch", expectedPrimaryCount, actualPrimaryCount); + assertEquals("Secondary replica count mismatch", expectedSecondaryCount, actualSecondaryCount); + assertEquals("Candidate replica count mismatch", expectedCandidateCount, actualCandidateCount); + } + void connection_has_count_databases(int count) { assertEquals(count, driver.databases().all().size()); } @@ -180,4 +254,20 @@ void connection_has_count_databases(int count) { void connection_has_count_users(int count) { assertEquals(count, driver.users().all().size()); } + + void set_driver_option_use_replication_to(boolean value) { + driverOptions = driverOptions.useReplication(value); + } + + void set_driver_option_primary_failover_retries_to(int value) { + driverOptions = driverOptions.primaryFailoverRetries(value); + } + + void set_driver_option_replica_discovery_attempts_to(int value) { + driverOptions = driverOptions.replicaDiscoveryAttempts(value); + } + + void set_database_operation_consistency_to(Parameters.Consistency consistency) { + databaseOperationConsistency = Optional.of(consistency.level()); + } } diff --git a/java/test/behaviour/connection/ConnectionStepsCluster.java b/java/test/behaviour/connection/ConnectionStepsCluster.java index 10a3ff029c..2664e8abd2 100644 --- a/java/test/behaviour/connection/ConnectionStepsCluster.java +++ b/java/test/behaviour/connection/ConnectionStepsCluster.java @@ -22,20 +22,38 @@ import com.typedb.driver.api.Credentials; import com.typedb.driver.api.Driver; import com.typedb.driver.api.DriverOptions; +import com.typedb.driver.api.DriverTlsConfig; import com.typedb.driver.test.behaviour.config.Parameters; import io.cucumber.java.After; import io.cucumber.java.Before; -import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; import io.cucumber.java.en.When; +import java.util.List; +import java.util.Set; + public class ConnectionStepsCluster extends ConnectionStepsBase { + public static Set DEFAULT_CLUSTER_ADDRESSES = Set.of( + "127.0.0.1:11729", + "127.0.0.1:21729", + "127.0.0.1:31729" + ); + public static List DEFAULT_CLUSTER_CLUSTERING_ADDRESSES = List.of( + "127.0.0.1:11730", + "127.0.0.1:21730", + "127.0.0.1:31730" + ); + @Override public void beforeAll() { super.beforeAll(); + setupCluster(); } @Before public synchronized void before() { + Parameters.setClusterMode(true); + driverOptions = driverOptions.tlsConfig(DriverTlsConfig.enabledWithRootCA(System.getenv("ROOT_CA"))); super.before(); } @@ -44,15 +62,34 @@ public synchronized void after() { super.after(); } - @Override Driver createTypeDBDriver(String address, Credentials credentials, DriverOptions driverOptions) { + return TypeDB.driver(Set.of(address), credentials, driverOptions); + } + + Driver createTypeDBDriver(Set address, Credentials credentials, DriverOptions driverOptions) { return TypeDB.driver(address, credentials, driverOptions); } + void setupCluster() { + try (Driver driver = createDefaultTypeDBDriver()) { + List clusteringAddresses = DEFAULT_CLUSTER_CLUSTERING_ADDRESSES; + if (driver.replicas().size() != clusteringAddresses.size()) { + for (int i = 0; i < clusteringAddresses.size(); i++) { + long id = i + 1L; + String address = clusteringAddresses.get(i); + + // 1 is the default registered replica + if (id != 1) { + driver.registerReplica(id, address); + } + } + } + } + } + @Override Driver createDefaultTypeDBDriver() { - // TODO: Add encryption to cluster tests - return createTypeDBDriver(TypeDB.DEFAULT_ADDRESS, DEFAULT_CREDENTIALS, DEFAULT_CONNECTION_SETTINGS); + return createTypeDBDriver(DEFAULT_CLUSTER_ADDRESSES, DEFAULT_CREDENTIALS, driverOptions); } @When("typedb starts") @@ -64,30 +101,36 @@ public void connection_opens_with_default_authentication() { driver = createDefaultTypeDBDriver(); } + @When("connection opens to single server with default authentication") + public void connection_opens_to_single_server_with_default_authentication() { + driver = createTypeDBDriver(Set.of(DEFAULT_CLUSTER_ADDRESSES.iterator().next()), DEFAULT_CREDENTIALS, driverOptions); + } + @When("connection opens with username '{non_semicolon}', password '{non_semicolon}'{may_error}") public void connection_opens_with_username_password(String username, String password, Parameters.MayError mayError) { Credentials credentials = new Credentials(username, password); - mayError.check(() -> driver = createTypeDBDriver(TypeDB.DEFAULT_ADDRESS, credentials, DEFAULT_CONNECTION_SETTINGS)); + mayError.check(() -> driver = createTypeDBDriver(DEFAULT_CLUSTER_ADDRESSES, credentials, driverOptions)); } @When("connection opens with a wrong host{may_error}") public void connection_opens_with_a_wrong_host(Parameters.MayError mayError) { mayError.check(() -> driver = createTypeDBDriver( - TypeDB.DEFAULT_ADDRESS.replace("localhost", "surely-not-localhost"), + DEFAULT_CLUSTER_ADDRESSES.iterator().next().replace("127.0.0.1", "surely-not-localhost"), DEFAULT_CREDENTIALS, - DEFAULT_CONNECTION_SETTINGS + driverOptions )); } @When("connection opens with a wrong port{may_error}") public void connection_opens_with_a_wrong_port(Parameters.MayError mayError) { mayError.check(() -> driver = createTypeDBDriver( - TypeDB.DEFAULT_ADDRESS.replace("localhost", "surely-not-localhost"), + DEFAULT_CLUSTER_ADDRESSES.iterator().next().replace("127.0.0.1", "surely-not-localhost"), DEFAULT_CREDENTIALS, - DEFAULT_CONNECTION_SETTINGS + driverOptions )); } + @Override @When("connection closes") public void connection_closes() { @@ -95,20 +138,86 @@ public void connection_closes() { } @Override - @Given("connection is open: {bool}") + @Then("connection is open: {bool}") public void connection_is_open(boolean isOpen) { super.connection_is_open(isOpen); } @Override - @Given("connection has {integer} database(s)") + @Then("connection contains distribution{may_error}") + public void connection_contains_distribution(Parameters.MayError mayError) { + super.connection_contains_distribution(mayError); + } + + @Override + @Then("connection contains version{may_error}") + public void connection_contains_version(Parameters.MayError mayError) { + super.connection_contains_version(mayError); + } + + @Override + @Then("connection has {integer} replica(s)") + public void connection_has_count_replicas(int count) { + super.connection_has_count_replicas(count); + } + + @Override + @Then("connection primary replica exists") + public void connection_primary_replica_exists() { + super.connection_primary_replica_exists(); + } + + @Override + @Then("connection get replica\\({word}) {exists_or_doesnt}") + public void connection_get_replica_exists(String address, Parameters.ExistsOrDoesnt existsOrDoesnt) { + super.connection_get_replica_exists(address, existsOrDoesnt); + } + + @Override + @Then("connection get replica\\({word}) has term") + public void connection_get_replica_has_term(String address) { + super.connection_get_replica_has_term(address); + } + + @Override + @Then("connection replicas have roles:") + public void connection_replicas_have_roles(List roles) { + super.connection_replicas_have_roles(roles); + } + + @Override + @Then("connection has {integer} database(s)") public void connection_has_count_databases(int count) { super.connection_has_count_databases(count); } @Override - @Given("connection has {integer} user(s)") + @Then("connection has {integer} user(s)") public void connection_has_count_users(int count) { super.connection_has_count_users(count); } + + @Override + @When("set driver option use_replication to: {bool}") + public void set_driver_option_use_replication_to(boolean value) { + super.set_driver_option_use_replication_to(value); + } + + @Override + @When("set driver option primary_failover_retries to: {integer}") + public void set_driver_option_primary_failover_retries_to(int value) { + super.set_driver_option_primary_failover_retries_to(value); + } + + @Override + @When("set driver option replica_discovery_attempts to: {integer}") + public void set_driver_option_replica_discovery_attempts_to(int value) { + super.set_driver_option_replica_discovery_attempts_to(value); + } + + @Override + @When("set database operation consistency to: {consistency_level}") + public void set_database_operation_consistency_to(Parameters.Consistency consistency) { + super.set_database_operation_consistency_to(consistency); + } } diff --git a/java/test/behaviour/connection/ConnectionStepsCommunity.java b/java/test/behaviour/connection/ConnectionStepsCore.java similarity index 63% rename from java/test/behaviour/connection/ConnectionStepsCommunity.java rename to java/test/behaviour/connection/ConnectionStepsCore.java index 2e0a619de8..231e6e9168 100644 --- a/java/test/behaviour/connection/ConnectionStepsCommunity.java +++ b/java/test/behaviour/connection/ConnectionStepsCore.java @@ -26,10 +26,10 @@ import com.typedb.driver.test.behaviour.config.Parameters; import io.cucumber.java.After; import io.cucumber.java.Before; -import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; import io.cucumber.java.en.When; -public class ConnectionStepsCommunity extends ConnectionStepsBase { +public class ConnectionStepsCore extends ConnectionStepsBase { @Override public void beforeAll() { super.beforeAll(); @@ -45,14 +45,13 @@ public synchronized void after() { super.after(); } - @Override Driver createTypeDBDriver(String address, Credentials credentials, DriverOptions driverOptions) { return TypeDB.driver(address, credentials, driverOptions); } @Override Driver createDefaultTypeDBDriver() { - return createTypeDBDriver(TypeDB.DEFAULT_ADDRESS, DEFAULT_CREDENTIALS, DEFAULT_CONNECTION_SETTINGS); + return createTypeDBDriver(TypeDB.DEFAULT_ADDRESS, DEFAULT_CREDENTIALS, driverOptions); } @When("typedb starts") @@ -67,24 +66,24 @@ public void connection_opens_with_default_authentication() { @When("connection opens with username '{non_semicolon}', password '{non_semicolon}'{may_error}") public void connection_opens_with_username_password(String username, String password, Parameters.MayError mayError) { Credentials credentials = new Credentials(username, password); - mayError.check(() -> driver = createTypeDBDriver(TypeDB.DEFAULT_ADDRESS, credentials, DEFAULT_CONNECTION_SETTINGS)); + mayError.check(() -> driver = createTypeDBDriver(TypeDB.DEFAULT_ADDRESS, credentials, driverOptions)); } @When("connection opens with a wrong host{may_error}") public void connection_opens_with_a_wrong_host(Parameters.MayError mayError) { mayError.check(() -> driver = createTypeDBDriver( - TypeDB.DEFAULT_ADDRESS.replace("localhost", "surely-not-localhost"), + TypeDB.DEFAULT_ADDRESS.replace("127.0.0.1", "surely-not-localhost"), DEFAULT_CREDENTIALS, - DEFAULT_CONNECTION_SETTINGS + driverOptions )); } @When("connection opens with a wrong port{may_error}") public void connection_opens_with_a_wrong_port(Parameters.MayError mayError) { mayError.check(() -> driver = createTypeDBDriver( - TypeDB.DEFAULT_ADDRESS.replace("localhost", "surely-not-localhost"), + TypeDB.DEFAULT_ADDRESS.replace("127.0.0.1", "surely-not-localhost"), DEFAULT_CREDENTIALS, - DEFAULT_CONNECTION_SETTINGS + driverOptions )); } @@ -95,20 +94,62 @@ public void connection_closes() { } @Override - @Given("connection is open: {bool}") + @Then("connection is open: {bool}") public void connection_is_open(boolean isOpen) { super.connection_is_open(isOpen); } @Override - @Given("connection has {integer} database(s)") + @Then("connection contains distribution{may_error}") + public void connection_contains_distribution(Parameters.MayError mayError) { + super.connection_contains_distribution(mayError); + } + + @Override + @Then("connection contains version{may_error}") + public void connection_contains_version(Parameters.MayError mayError) { + super.connection_contains_version(mayError); + } + + @Override + @Then("connection has {integer} replica(s)") + public void connection_has_count_replicas(int count) { + super.connection_has_count_replicas(count); + } + + @Override + @Then("connection primary replica exists") + public void connection_primary_replica_exists() { + super.connection_primary_replica_exists(); + } + + @Override + @Then("connection has {integer} database(s)") public void connection_has_count_databases(int count) { super.connection_has_count_databases(count); } @Override - @Given("connection has {integer} user(s)") + @Then("connection has {integer} user(s)") public void connection_has_count_users(int count) { super.connection_has_count_users(count); } + + @Override + @When("set driver option use_replication to: {bool}") + public void set_driver_option_use_replication_to(boolean value) { + super.set_driver_option_use_replication_to(value); + } + + @Override + @When("set driver option primary_failover_retries to: {integer}") + public void set_driver_option_primary_failover_retries_to(int value) { + super.set_driver_option_primary_failover_retries_to(value); + } + + @Override + @When("set driver option replica_discovery_attempts to: {integer}") + public void set_driver_option_replica_discovery_attempts_to(int value) { + super.set_driver_option_replica_discovery_attempts_to(value); + } } diff --git a/java/test/behaviour/connection/database/BUILD b/java/test/behaviour/connection/database/BUILD index c45f2de26d..34f988899d 100644 --- a/java/test/behaviour/connection/database/BUILD +++ b/java/test/behaviour/connection/database/BUILD @@ -49,8 +49,6 @@ typedb_behaviour_java_test( data = [ "@typedb_behaviour//connection:database.feature", ], - connection_steps_community = "//java/test/behaviour/connection:steps-community", - connection_steps_cluster = "//java/test/behaviour/connection:steps-cluster", steps = [ ":steps", "//java/test/behaviour/connection/transaction:steps", @@ -67,7 +65,6 @@ typedb_behaviour_java_test( runtime_deps = [ "//java/test/behaviour/config:parameters", ], - size = "large", ) checkstyle_test( diff --git a/java/test/behaviour/connection/database/DatabaseSteps.java b/java/test/behaviour/connection/database/DatabaseSteps.java index 2aee4365d3..9bc70e81d0 100644 --- a/java/test/behaviour/connection/database/DatabaseSteps.java +++ b/java/test/behaviour/connection/database/DatabaseSteps.java @@ -19,6 +19,7 @@ package com.typedb.driver.test.behaviour.connection.database; +import com.typedb.driver.api.ConsistencyLevel; import com.typedb.driver.api.Driver; import com.typedb.driver.api.Transaction; import com.typedb.driver.api.database.Database; @@ -35,6 +36,7 @@ import static com.typedb.driver.common.collection.Collections.list; import static com.typedb.driver.test.behaviour.connection.ConnectionStepsBase.THREAD_POOL_SIZE; import static com.typedb.driver.test.behaviour.connection.ConnectionStepsBase.backgroundDriver; +import static com.typedb.driver.test.behaviour.connection.ConnectionStepsBase.databaseOperationConsistency; import static com.typedb.driver.test.behaviour.connection.ConnectionStepsBase.driver; import static com.typedb.driver.test.behaviour.connection.ConnectionStepsBase.fullPath; import static com.typedb.driver.test.behaviour.connection.ConnectionStepsBase.threadPool; @@ -78,7 +80,8 @@ public void importDatabase(String name, String schema, String dataFile, Paramete @When("connection create database: {non_semicolon}{may_error}") public void connection_create_database(String name, Parameters.MayError mayError) { - mayError.check(() -> createDatabases(driver, list(name))); + ConsistencyLevel consistency = databaseOperationConsistency.orElse(null); + mayError.check(() -> driver.databases().create(name, consistency)); } @When("connection create database with empty name{may_error}") @@ -109,7 +112,8 @@ public void in_background_connection_create_database(String name, Parameters.May @When("connection delete database: {word}{may_error}") public void connection_delete_database(String name, Parameters.MayError mayError) { - mayError.check(() -> deleteDatabases(driver, list(name))); + ConsistencyLevel consistency = databaseOperationConsistency.orElse(null); + mayError.check(() -> driver.databases().get(name, consistency).delete()); } @When("connection delete database(s):") @@ -135,12 +139,16 @@ public void in_background_connection_delete_database(String name, Parameters.May @When("connection has database: {word}") public void connection_has_database(String name) { - connection_has_databases(list(name)); + ConsistencyLevel consistency = databaseOperationConsistency.orElse(null); + Parameters.ContainsOrDoesnt.DOES.check(driver.databases().contains(name, consistency)); } @Then("connection has database(s):") public void connection_has_databases(List names) { - assertTrue(names.stream().allMatch(name -> driver.databases().contains(name))); + ConsistencyLevel consistency = databaseOperationConsistency.orElse(null); + for (String name : names) { + Parameters.ContainsOrDoesnt.DOES.check(driver.databases().contains(name, consistency)); + } } @Then("connection does not have database: {word}") @@ -150,9 +158,9 @@ public void connection_does_not_have_database(String name) { @Then("connection does not have database(s):") public void connection_does_not_have_databases(List names) { - Set databases = driver.databases().all().stream().map(Database::name).collect(Collectors.toSet()); + ConsistencyLevel consistency = databaseOperationConsistency.orElse(null); for (String databaseName : names) { - assertFalse(databases.contains(databaseName)); + Parameters.ContainsOrDoesnt.DOES_NOT.check(driver.databases().contains(databaseName, consistency)); } } diff --git a/java/test/behaviour/connection/database/DatabaseTest.java b/java/test/behaviour/connection/database/DatabaseTest.java index 06cc1db141..8548ab5ff3 100644 --- a/java/test/behaviour/connection/database/DatabaseTest.java +++ b/java/test/behaviour/connection/database/DatabaseTest.java @@ -42,7 +42,7 @@ public class DatabaseTest extends BehaviourTest { // 3) Select 'Bazel test DatabaseTest' // // 4) Ensure 'Target Expression' is set correctly: - // a) Use '////:test-community' to test against typedb (TypeDB Community Edition) + // a) Use '////:test-core' to test against typedb (TypeDB Community Edition) // b) Use '////:test-cluster' to test against typedb-cluster (TypeDB Cloud / Enterprise) // // 5) Update 'Bazel Flags': diff --git a/java/test/behaviour/connection/transaction/BUILD b/java/test/behaviour/connection/transaction/BUILD index c1257f1e29..69db7260f5 100644 --- a/java/test/behaviour/connection/transaction/BUILD +++ b/java/test/behaviour/connection/transaction/BUILD @@ -49,8 +49,6 @@ typedb_behaviour_java_test( data = [ "@typedb_behaviour//connection:transaction.feature", ], - connection_steps_community = "//java/test/behaviour/connection:steps-community", - connection_steps_cluster = "//java/test/behaviour/connection:steps-cluster", steps = [ ":steps", "//java/test/behaviour/connection/database:steps", @@ -68,7 +66,6 @@ typedb_behaviour_java_test( runtime_deps = [ "//java/test/behaviour/config:parameters", ], - size = "large", ) checkstyle_test( diff --git a/java/test/behaviour/connection/transaction/TransactionSteps.java b/java/test/behaviour/connection/transaction/TransactionSteps.java index 4440ca2ec7..56fc1d22c9 100644 --- a/java/test/behaviour/connection/transaction/TransactionSteps.java +++ b/java/test/behaviour/connection/transaction/TransactionSteps.java @@ -181,4 +181,10 @@ public void set_transaction_option_schema_lock_acquire_timeout_millis_to(int val initTransactionOptionsIfNeeded(); transactionOptions.get().schemaLockAcquireTimeoutMillis(value); } + + @When("set transaction option read_consistency_level to: {consistency_level}") + public void set_transaction_option_read_consistency_level_to(Parameters.Consistency consistency) { + initTransactionOptionsIfNeeded(); + transactionOptions.get().readConsistencyLevel(consistency.level()); + } } diff --git a/java/test/behaviour/connection/transaction/TransactionTest.java b/java/test/behaviour/connection/transaction/TransactionTest.java index e44dddcbd9..f5bff471b3 100644 --- a/java/test/behaviour/connection/transaction/TransactionTest.java +++ b/java/test/behaviour/connection/transaction/TransactionTest.java @@ -42,7 +42,7 @@ public class TransactionTest extends BehaviourTest { // 3) Select 'Bazel test TransactionTest' // // 4) Ensure 'Target Expression' is set correctly: - // a) Use '////:test-community' to test against typedb (TypeDB Community Edition) + // a) Use '////:test-core' to test against typedb (TypeDB Community Edition) // b) Use '////:test-cluster' to test against typedb-cluster (TypeDB Cloud / Enterprise) // // 5) Update 'Bazel Flags': diff --git a/java/test/behaviour/connection/user/UserSteps.java b/java/test/behaviour/connection/user/UserSteps.java index e7bfd4b674..bc1980d685 100644 --- a/java/test/behaviour/connection/user/UserSteps.java +++ b/java/test/behaviour/connection/user/UserSteps.java @@ -82,7 +82,7 @@ public void delete_user(String username, Parameters.MayError mayError) { } @Then("get current username: {non_semicolon}") - public void get_current_username(String username) { - assertEquals(username, driver.users().getCurrentUser().name()); + public void get_currentname(String username) { + assertEquals(username, driver.users().getCurrent().name()); } } diff --git a/java/test/behaviour/debug/BUILD b/java/test/behaviour/debug/BUILD index be5537dfa0..9e357a8d17 100644 --- a/java/test/behaviour/debug/BUILD +++ b/java/test/behaviour/debug/BUILD @@ -39,7 +39,7 @@ typedb_java_test( "@maven//:io_cucumber_cucumber_junit", ], runtime_deps = [ - "//java/test/behaviour/connection:steps-community", + "//java/test/behaviour/connection:steps-core", "//java/test/behaviour/config:parameters", "//java/test/behaviour/query:steps", ], @@ -51,7 +51,7 @@ typedb_java_test( "@typedb_bazel_distribution//platform:is_linux_x86_64": "@typedb_artifact_linux-x86_64//file", "@typedb_bazel_distribution//platform:is_mac_arm64": "@typedb_artifact_mac-arm64//file", "@typedb_bazel_distribution//platform:is_mac_x86_64": "@typedb_artifact_mac-x86_64//file", -# "@typedb_bazel_distribution//platform:is_windows_x86_64": "@typedb_artifact_windows-x86_64//file", + "@typedb_bazel_distribution//platform:is_windows_x86_64": "@typedb_artifact_windows-x86_64//file", }, size = "large", tags = ["manual"] diff --git a/java/test/behaviour/driver/cluster/BUILD b/java/test/behaviour/driver/cluster/BUILD new file mode 100644 index 0000000000..15ab39cefb --- /dev/null +++ b/java/test/behaviour/driver/cluster/BUILD @@ -0,0 +1,52 @@ +# 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 = ["//visibility:__subpackages__"]) +load("@typedb_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") +load("//java/test/behaviour:rules.bzl", "typedb_behaviour_java_cluster_test") + +typedb_behaviour_java_cluster_test( + name = "test", + srcs = [ + "ClusterTest.java", + ], + test_class = "com.typedb.driver.test.behaviour.driver.cluster.ClusterTest", + data = [ + "@typedb_behaviour//driver:cluster.feature", + ], + steps = [ + "//java/test/behaviour/query:steps", + "//java/test/behaviour/util:steps", + ], + deps = [ + # Internal Package Dependencies + "//java/test/behaviour:behaviour", + + # External dependencies from Maven + "@maven//:io_cucumber_cucumber_junit", + ], + runtime_deps = [ + "//java/test/behaviour/config:parameters", + ], + visibility = ["//visibility:public"], +) + +checkstyle_test( + name = "checkstyle", + include = glob(["*"]), + license_type = "apache-header", +) diff --git a/java/test/behaviour/driver/cluster/ClusterTest.java b/java/test/behaviour/driver/cluster/ClusterTest.java new file mode 100644 index 0000000000..5cd0897555 --- /dev/null +++ b/java/test/behaviour/driver/cluster/ClusterTest.java @@ -0,0 +1,58 @@ +/* + * 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 com.typedb.driver.test.behaviour.driver.cluster; + +import com.typedb.driver.test.behaviour.BehaviourTest; +import io.cucumber.junit.Cucumber; +import io.cucumber.junit.CucumberOptions; +import org.junit.runner.RunWith; + +@RunWith(Cucumber.class) +@CucumberOptions( + strict = true, + plugin = "pretty", + glue = "com.typedb.driver.test.behaviour", + features = "external/typedb_behaviour/driver/cluster.feature", + tags = "not @ignore and not @ignore-typedb-driver and not @ignore-typedb-driver-java" +) +public class ClusterTest extends BehaviourTest { + // ATTENTION: + // When you click RUN from within this class through Intellij IDE, it will fail. + // You can fix it by doing: + // + // 1) Go to 'Run' + // 2) Select 'Edit Configurations...' + // 3) Select 'Bazel test DefineTest' + // + // 4) Ensure 'Target Expression' is set correctly: + // a) Use '////:test-core' to test against typedb (TypeDB Community Edition) + // b) Use '////:test-cluster' to test against typedb-cluster (TypeDB Cloud / Enterprise) + // + // 5) Update 'Bazel Flags': + // a) Remove the line that says: '--test_filter=com.typedb.driver.*' + // b) Use the following Bazel flags: + // --cache_test_results=no : to make sure you're not using cache + // --test_output=streamed : to make sure all output is printed + // --subcommands : to print the low-level commands and execution paths + // --sandbox_debug : to keep the sandbox not deleted after test runs + // --spawn_strategy=standalone : if you're on Mac, tests need permission to access filesystem (to run TypeDB) + // + // 6) Hit the RUN button by selecting the test from the dropdown menu on the top bar +} diff --git a/java/test/behaviour/driver/concept/BUILD b/java/test/behaviour/driver/concept/BUILD index 52910fa626..ec25a55097 100644 --- a/java/test/behaviour/driver/concept/BUILD +++ b/java/test/behaviour/driver/concept/BUILD @@ -28,8 +28,6 @@ typedb_behaviour_java_test( data = [ "@typedb_behaviour//driver:concept.feature", ], - connection_steps_community = "//java/test/behaviour/connection:steps-community", - connection_steps_cluster = "//java/test/behaviour/connection:steps-cluster", steps = [ "//java/test/behaviour/query:steps", "//java/test/behaviour/util:steps", @@ -44,7 +42,6 @@ typedb_behaviour_java_test( runtime_deps = [ "//java/test/behaviour/config:parameters", ], - size = "enormous", visibility = ["//visibility:public"], ) diff --git a/java/test/behaviour/driver/concept/ConceptTest.java b/java/test/behaviour/driver/concept/ConceptTest.java index dc979fb782..78f929ea80 100644 --- a/java/test/behaviour/driver/concept/ConceptTest.java +++ b/java/test/behaviour/driver/concept/ConceptTest.java @@ -42,7 +42,7 @@ public class ConceptTest extends BehaviourTest { // 3) Select 'Bazel test DefineTest' // // 4) Ensure 'Target Expression' is set correctly: - // a) Use '////:test-community' to test against typedb (TypeDB Community Edition) + // a) Use '////:test-core' to test against typedb (TypeDB Community Edition) // b) Use '////:test-cluster' to test against typedb-cluster (TypeDB Cloud / Enterprise) // // 5) Update 'Bazel Flags': diff --git a/java/test/behaviour/driver/connection/BUILD b/java/test/behaviour/driver/connection/BUILD index 3fd35b5030..a2a5a5576b 100644 --- a/java/test/behaviour/driver/connection/BUILD +++ b/java/test/behaviour/driver/connection/BUILD @@ -28,8 +28,6 @@ typedb_behaviour_java_test( data = [ "@typedb_behaviour//driver:connection.feature", ], - connection_steps_community = "//java/test/behaviour/connection:steps-community", - connection_steps_cluster = "//java/test/behaviour/connection:steps-cluster", steps = [ "//java/test/behaviour/query:steps", "//java/test/behaviour/util:steps", @@ -44,7 +42,6 @@ typedb_behaviour_java_test( runtime_deps = [ "//java/test/behaviour/config:parameters", ], - size = "enormous", visibility = ["//visibility:public"], ) diff --git a/java/test/behaviour/driver/connection/ConnectionTest.java b/java/test/behaviour/driver/connection/ConnectionTest.java index 5609f7c12e..d4ab7264c8 100644 --- a/java/test/behaviour/driver/connection/ConnectionTest.java +++ b/java/test/behaviour/driver/connection/ConnectionTest.java @@ -42,7 +42,7 @@ public class ConnectionTest extends BehaviourTest { // 3) Select 'Bazel test DefineTest' // // 4) Ensure 'Target Expression' is set correctly: - // a) Use '////:test-community' to test against typedb (TypeDB Community Edition) + // a) Use '////:test-core' to test against typedb (TypeDB Community Edition) // b) Use '////:test-cluster' to test against typedb-cluster (TypeDB Cloud / Enterprise) // // 5) Update 'Bazel Flags': diff --git a/java/test/behaviour/driver/migration/BUILD b/java/test/behaviour/driver/migration/BUILD index e7a86c3149..886388b8c7 100644 --- a/java/test/behaviour/driver/migration/BUILD +++ b/java/test/behaviour/driver/migration/BUILD @@ -28,8 +28,6 @@ typedb_behaviour_java_test( data = [ "@typedb_behaviour//driver:migration.feature", ], - connection_steps_community = "//java/test/behaviour/connection:steps-community", - connection_steps_cluster = "//java/test/behaviour/connection:steps-cluster", steps = [ "//java/test/behaviour/query:steps", "//java/test/behaviour/util:steps", @@ -44,7 +42,6 @@ typedb_behaviour_java_test( runtime_deps = [ "//java/test/behaviour/config:parameters", ], - size = "enormous", visibility = ["//visibility:public"], ) diff --git a/java/test/behaviour/driver/migration/MigrationTest.java b/java/test/behaviour/driver/migration/MigrationTest.java index 7ca7eebb06..002dabc059 100644 --- a/java/test/behaviour/driver/migration/MigrationTest.java +++ b/java/test/behaviour/driver/migration/MigrationTest.java @@ -42,7 +42,7 @@ public class MigrationTest extends BehaviourTest { // 3) Select 'Bazel test DefineTest' // // 4) Ensure 'Target Expression' is set correctly: - // a) Use '////:test-community' to test against typedb (TypeDB Community Edition) + // a) Use '////:test-core' to test against typedb (TypeDB Community Edition) // b) Use '////:test-cluster' to test against typedb-cluster (TypeDB Cloud / Enterprise) // // 5) Update 'Bazel Flags': diff --git a/java/test/behaviour/driver/query/BUILD b/java/test/behaviour/driver/query/BUILD index b5528f986b..a8722ddd29 100644 --- a/java/test/behaviour/driver/query/BUILD +++ b/java/test/behaviour/driver/query/BUILD @@ -29,8 +29,6 @@ typedb_behaviour_java_test( data = [ "@typedb_behaviour//driver:query.feature", ], - connection_steps_community = "//java/test/behaviour/connection:steps-community", - connection_steps_cluster = "//java/test/behaviour/connection:steps-cluster", steps = [ "//java/test/behaviour/query:steps", "//java/test/behaviour/util:steps", @@ -45,7 +43,6 @@ typedb_behaviour_java_test( runtime_deps = [ "//java/test/behaviour/config:parameters", ], - size = "enormous", visibility = ["//visibility:public"], ) diff --git a/java/test/behaviour/driver/query/QueryTest.java b/java/test/behaviour/driver/query/QueryTest.java index 2c5d69c0b7..8b45e0380b 100644 --- a/java/test/behaviour/driver/query/QueryTest.java +++ b/java/test/behaviour/driver/query/QueryTest.java @@ -42,7 +42,7 @@ public class QueryTest extends BehaviourTest { // 3) Select 'Bazel test DefineTest' // // 4) Ensure 'Target Expression' is set correctly: - // a) Use '////:test-community' to test against typedb (TypeDB Community Edition) + // a) Use '////:test-core' to test against typedb (TypeDB Community Edition) // b) Use '////:test-cluster' to test against typedb-cluster (TypeDB Cloud / Enterprise) // // 5) Update 'Bazel Flags': diff --git a/java/test/behaviour/driver/user/BUILD b/java/test/behaviour/driver/user/BUILD index fea723a8a2..1cf6f2ae3c 100644 --- a/java/test/behaviour/driver/user/BUILD +++ b/java/test/behaviour/driver/user/BUILD @@ -29,8 +29,6 @@ typedb_behaviour_java_test( data = [ "@typedb_behaviour//driver:user.feature", ], - connection_steps_community = "//java/test/behaviour/connection:steps-community", - connection_steps_cluster = "//java/test/behaviour/connection:steps-cluster", steps = [ "//java/test/behaviour/connection/transaction:steps", "//java/test/behaviour/connection/user:steps", @@ -47,7 +45,6 @@ typedb_behaviour_java_test( runtime_deps = [ "//java/test/behaviour/config:parameters", ], - size = "enormous", visibility = ["//visibility:public"], ) diff --git a/java/test/behaviour/driver/user/UserTest.java b/java/test/behaviour/driver/user/UserTest.java index 093bd40840..317801f46e 100644 --- a/java/test/behaviour/driver/user/UserTest.java +++ b/java/test/behaviour/driver/user/UserTest.java @@ -42,7 +42,7 @@ public class UserTest extends BehaviourTest { // 3) Select 'Bazel test DatabaseTestCluster' // // 4) Ensure 'Target Expression' is set correctly: - // a) Use '////:test-community' to test against typedb (TypeDB Community Edition) + // a) Use '////:test-core' to test against typedb (TypeDB Community Edition) // b) Use '////:test-cluster' to test against typedb-cluster (TypeDB Cloud / Enterprise) // // 5) Update 'Bazel Flags': diff --git a/java/test/behaviour/query/AnalyzeSteps.java b/java/test/behaviour/query/AnalyzeSteps.java index fe38af5e8f..2966d47479 100644 --- a/java/test/behaviour/query/AnalyzeSteps.java +++ b/java/test/behaviour/query/AnalyzeSteps.java @@ -35,6 +35,7 @@ public class AnalyzeSteps { private static AnalyzedQuery analyzedQuery; + @When("get answers of typeql analyze") public void get_answers_of_typeql_analyze(String query) { analyzedQuery = null; @@ -61,8 +62,8 @@ public void analyzed_query_preamble_contains(String docString) { }).collect(Collectors.toList()); assertTrue( - String.format("Did not find %s in %s", expectedFunctor, preambleFunctors.stream().collect(Collectors.joining(","))), - preambleFunctors.contains(expectedFunctor) + String.format("Did not find %s in %s", expectedFunctor, preambleFunctors.stream().collect(Collectors.joining(","))), + preambleFunctors.contains(expectedFunctor) ); } diff --git a/java/test/behaviour/rules.bzl b/java/test/behaviour/rules.bzl index 0c35d3bdbf..5294a02e7a 100644 --- a/java/test/behaviour/rules.bzl +++ b/java/test/behaviour/rules.bzl @@ -19,34 +19,58 @@ load("@typedb_dependencies//builder/java:rules.bzl", "typedb_java_test") def typedb_behaviour_java_test( name, - connection_steps_community, - connection_steps_cluster, + steps, + runtime_deps = [], + **kwargs): + + typedb_behaviour_java_core_test( + name, + steps, + runtime_deps, + **kwargs + ) + + typedb_behaviour_java_cluster_test( + name, + steps, + runtime_deps, + **kwargs + ) + +def typedb_behaviour_java_core_test( + name, steps, runtime_deps = [], **kwargs): typedb_java_test( - name = name + "-community", + name = name + "-core", server_artifacts = { "@typedb_bazel_distribution//platform:is_linux_arm64": "@typedb_artifact_linux-arm64//file", "@typedb_bazel_distribution//platform:is_linux_x86_64": "@typedb_artifact_linux-x86_64//file", "@typedb_bazel_distribution//platform:is_mac_arm64": "@typedb_artifact_mac-arm64//file", "@typedb_bazel_distribution//platform:is_mac_x86_64": "@typedb_artifact_mac-x86_64//file", -# "@typedb_bazel_distribution//platform:is_windows_x86_64": "@typedb_artifact_windows-x86_64//file", + "@typedb_bazel_distribution//platform:is_windows_x86_64": "@typedb_artifact_windows-x86_64//file", }, - runtime_deps = runtime_deps + [connection_steps_community] + steps, + runtime_deps = runtime_deps + ["//java/test/behaviour/connection:steps-core"] + steps, **kwargs, ) +def typedb_behaviour_java_cluster_test( + name, + steps, + runtime_deps = [], + **kwargs): + typedb_java_test( name = name + "-cluster", - server_artifacts = { # TODO: Use cluster artifacts - "@typedb_bazel_distribution//platform:is_linux_arm64": "@typedb_artifact_linux-arm64//file", - "@typedb_bazel_distribution//platform:is_linux_x86_64": "@typedb_artifact_linux-x86_64//file", - "@typedb_bazel_distribution//platform:is_mac_arm64": "@typedb_artifact_mac-arm64//file", - "@typedb_bazel_distribution//platform:is_mac_x86_64": "@typedb_artifact_mac-x86_64//file", + server_artifacts = { # TODO: Uncomment all platforms + "@typedb_bazel_distribution//platform:is_linux_arm64": "@typedb_cluster_artifact_linux-arm64//file", + "@typedb_bazel_distribution//platform:is_linux_x86_64": "@typedb_cluster_artifact_linux-x86_64//file", + "@typedb_bazel_distribution//platform:is_mac_arm64": "@typedb_cluster_artifact_linux-arm64//file", + "@typedb_bazel_distribution//platform:is_mac_x86_64": "@typedb_cluster_artifact_linux-x86_64//file", # "@typedb_bazel_distribution//platform:is_windows_x86_64": "@typedb_artifact_windows-x86_64//file", }, - runtime_deps = runtime_deps + [connection_steps_cluster] + steps, + runtime_deps = runtime_deps + ["//java/test/behaviour/connection:steps-cluster"] + steps, **kwargs, ) diff --git a/java/test/deployment/src/test/java/application/MavenApplicationTest.java b/java/test/deployment/src/test/java/application/MavenApplicationTest.java index ef1d593989..911a968d64 100644 --- a/java/test/deployment/src/test/java/application/MavenApplicationTest.java +++ b/java/test/deployment/src/test/java/application/MavenApplicationTest.java @@ -23,6 +23,7 @@ import com.typedb.driver.api.Credentials; import com.typedb.driver.api.Driver; import com.typedb.driver.api.DriverOptions; +import com.typedb.driver.api.DriverTlsConfig; import com.typedb.driver.api.Transaction; import org.junit.Test; @@ -37,7 +38,7 @@ public void test() { Driver driver = TypeDB.driver( TypeDB.DEFAULT_ADDRESS, new Credentials("admin", "password"), - new DriverOptions(false, null) + new DriverOptions(DriverTlsConfig.disabled()) ); if (driver.databases().contains(DB_NAME)) { driver.databases().get(DB_NAME).delete(); diff --git a/java/test/integration/BUILD b/java/test/integration/BUILD index 2ac781f4e7..e3d8ab6aa6 100644 --- a/java/test/integration/BUILD +++ b/java/test/integration/BUILD @@ -54,7 +54,7 @@ typedb_java_test( "@typedb_bazel_distribution//platform:is_linux_x86_64": "@typedb_artifact_linux-x86_64//file", "@typedb_bazel_distribution//platform:is_mac_arm64": "@typedb_artifact_mac-arm64//file", "@typedb_bazel_distribution//platform:is_mac_x86_64": "@typedb_artifact_mac-x86_64//file", -# "@typedb_bazel_distribution//platform:is_windows_x86_64": "@typedb_artifact_windows-x86_64//file", + "@typedb_bazel_distribution//platform:is_windows_x86_64": "@typedb_artifact_windows-x86_64//file", }, test_class = "com.typedb.driver.test.integration.DriverTest", deps = [ @@ -77,7 +77,7 @@ typedb_java_test( "@typedb_bazel_distribution//platform:is_linux_x86_64": "@typedb_artifact_linux-x86_64//file", "@typedb_bazel_distribution//platform:is_mac_arm64": "@typedb_artifact_mac-arm64//file", "@typedb_bazel_distribution//platform:is_mac_x86_64": "@typedb_artifact_mac-x86_64//file", -# "@typedb_bazel_distribution//platform:is_windows_x86_64": "@typedb_artifact_windows-x86_64//file", + "@typedb_bazel_distribution//platform:is_windows_x86_64": "@typedb_artifact_windows-x86_64//file", }, test_class = "com.typedb.driver.test.integration.ValueTest", deps = [ diff --git a/java/test/integration/DriverTest.java b/java/test/integration/DriverTest.java index 18014d195d..9d4da9c0bc 100644 --- a/java/test/integration/DriverTest.java +++ b/java/test/integration/DriverTest.java @@ -23,6 +23,7 @@ import com.typedb.driver.api.Credentials; import com.typedb.driver.api.Driver; import com.typedb.driver.api.DriverOptions; +import com.typedb.driver.api.DriverTlsConfig; import com.typedb.driver.api.Transaction; import com.typedb.driver.api.answer.ConceptRow; import com.typedb.driver.api.answer.QueryAnswer; @@ -59,12 +60,12 @@ @SuppressWarnings("Duplicates") public class DriverTest { private static final String DB_NAME = "typedb"; - private static final String ADDRESS = "0.0.0.0:1729"; + private static final String ADDRESS = "127.0.0.1:1729"; private static Driver typedbDriver; @BeforeClass public static void setUpClass() { - typedbDriver = TypeDB.driver(ADDRESS, new Credentials("admin", "password"), new DriverOptions(false, null)); + typedbDriver = TypeDB.driver(ADDRESS, new Credentials("admin", "password"), new DriverOptions(DriverTlsConfig.disabled())); if (typedbDriver.databases().contains(DB_NAME)) typedbDriver.databases().get(DB_NAME).delete(); typedbDriver.databases().create(DB_NAME); } diff --git a/java/test/integration/ExampleTest.java b/java/test/integration/ExampleTest.java index 147cead227..2248ee5203 100644 --- a/java/test/integration/ExampleTest.java +++ b/java/test/integration/ExampleTest.java @@ -26,6 +26,7 @@ import com.typedb.driver.api.Credentials; import com.typedb.driver.api.Driver; import com.typedb.driver.api.DriverOptions; +import com.typedb.driver.api.DriverTlsConfig; import com.typedb.driver.api.QueryOptions; import com.typedb.driver.api.QueryType; import com.typedb.driver.api.Transaction; @@ -64,7 +65,7 @@ public class ExampleTest { // EXAMPLE END MARKER @BeforeClass public static void setUpClass() { - Driver typedbDriver = TypeDB.driver(TypeDB.DEFAULT_ADDRESS, new Credentials("admin", "password"), new DriverOptions(false, null)); + Driver typedbDriver = TypeDB.driver(TypeDB.DEFAULT_ADDRESS, new Credentials("admin", "password"), new DriverOptions(DriverTlsConfig.disabled())); if (typedbDriver.databases().contains("typedb")) { typedbDriver.databases().get("typedb").delete(); } @@ -75,7 +76,7 @@ public static void setUpClass() { // EXAMPLE START MARKER public void example() { // Open a driver connection. Try-with-resources can be used for automatic driver connection management - try (Driver driver = TypeDB.driver(TypeDB.DEFAULT_ADDRESS, new Credentials("admin", "password"), new DriverOptions(false, null))) { + try (Driver driver = TypeDB.driver(TypeDB.DEFAULT_ADDRESS, new Credentials("admin", "password"), new DriverOptions(DriverTlsConfig.disabled()))) { // Create a database driver.databases().create("typedb"); Database database = driver.databases().get("typedb"); diff --git a/java/test/integration/ValueTest.java b/java/test/integration/ValueTest.java index b996084d5a..76f633bca8 100644 --- a/java/test/integration/ValueTest.java +++ b/java/test/integration/ValueTest.java @@ -23,6 +23,7 @@ import com.typedb.driver.api.Credentials; import com.typedb.driver.api.Driver; import com.typedb.driver.api.DriverOptions; +import com.typedb.driver.api.DriverTlsConfig; import com.typedb.driver.api.Transaction; import com.typedb.driver.api.answer.ConceptRow; import com.typedb.driver.api.answer.QueryAnswer; @@ -58,12 +59,12 @@ @SuppressWarnings("Duplicates") public class ValueTest { private static final String DB_NAME = "typedb"; - private static final String ADDRESS = "0.0.0.0:1729"; + private static final String ADDRESS = "127.0.0.1:1729"; private static Driver typedbDriver; @BeforeClass public static void setUpClass() { - typedbDriver = TypeDB.driver(ADDRESS, new Credentials("admin", "password"), new DriverOptions(false, null)); + typedbDriver = TypeDB.driver(ADDRESS, new Credentials("admin", "password"), new DriverOptions(DriverTlsConfig.disabled())); if (typedbDriver.databases().contains(DB_NAME)) typedbDriver.databases().get(DB_NAME).delete(); typedbDriver.databases().create(DB_NAME); } diff --git a/java/test/integration/cluster/BUILD b/java/test/integration/cluster/BUILD index aba279ff02..23d6d906f6 100644 --- a/java/test/integration/cluster/BUILD +++ b/java/test/integration/cluster/BUILD @@ -18,7 +18,7 @@ load("@typedb_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") load("@typedb_dependencies//builder/java:rules.bzl", "typedb_java_test") -# TODO: This package can contain cluster-specific integration tests. Tests available for running for both community +# TODO: This package can contain cluster-specific integration tests. Tests available for running for both core # edition and cluster should be run for both setups (and be limited: always prefer BDDs to integration tests)! checkstyle_test( diff --git a/java/user/UserImpl.java b/java/user/UserImpl.java index 37d5b259a1..bedd38c1d3 100644 --- a/java/user/UserImpl.java +++ b/java/user/UserImpl.java @@ -19,6 +19,7 @@ package com.typedb.driver.user; +import com.typedb.driver.api.ConsistencyLevel; import com.typedb.driver.api.user.User; import com.typedb.driver.common.NativeObject; import com.typedb.driver.common.Validator; @@ -29,11 +30,8 @@ import static com.typedb.driver.jni.typedb_driver.user_update_password; public class UserImpl extends NativeObject implements User { - private final UserManagerImpl users; - - UserImpl(com.typedb.driver.jni.User user, UserManagerImpl users) { + UserImpl(com.typedb.driver.jni.User user) { super(user); - this.users = users; } @Override @@ -41,31 +39,22 @@ public String name() { return user_get_name(nativeObject); } -// TODO: Not implemented -// @Override -// public Optional passwordExpirySeconds() { -// var res = user_get_password_expiry_seconds(nativeObject); -// if (res >= 0) return Optional.of(res); -// else return Optional.empty(); -// } - @Override - public void updatePassword(String password) { + public void updatePassword(String password, ConsistencyLevel consistencyLevel) { Validator.requireNonNull(password, "password"); try { - user_update_password(nativeObject, password); + user_update_password(nativeObject, password, ConsistencyLevel.nativeValue(consistencyLevel)); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } @Override - public void delete() { + public void delete(ConsistencyLevel consistencyLevel) { try { - user_delete(nativeObject.released()); + user_delete(nativeObject.released(), ConsistencyLevel.nativeValue(consistencyLevel)); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } - } diff --git a/java/user/UserManagerImpl.java b/java/user/UserManagerImpl.java index fc08b63dd3..65558c290d 100644 --- a/java/user/UserManagerImpl.java +++ b/java/user/UserManagerImpl.java @@ -19,6 +19,7 @@ package com.typedb.driver.user; +import com.typedb.driver.api.ConsistencyLevel; import com.typedb.driver.api.user.User; import com.typedb.driver.api.user.UserManager; import com.typedb.driver.common.NativeIterator; @@ -32,7 +33,7 @@ import static com.typedb.driver.jni.typedb_driver.users_contains; import static com.typedb.driver.jni.typedb_driver.users_create; import static com.typedb.driver.jni.typedb_driver.users_get; -import static com.typedb.driver.jni.typedb_driver.users_get_current_user; +import static com.typedb.driver.jni.typedb_driver.users_get_current; public class UserManagerImpl implements UserManager { com.typedb.driver.jni.TypeDBDriver nativeDriver; @@ -42,32 +43,30 @@ public UserManagerImpl(com.typedb.driver.jni.TypeDBDriver driver) { } @Override - public boolean contains(String username) throws TypeDBDriverException { - Validator.requireNonNull(username, "username"); + public Set all(ConsistencyLevel consistencyLevel) throws TypeDBDriverException { try { - return users_contains(nativeDriver, username); + return new NativeIterator<>(users_all(nativeDriver, ConsistencyLevel.nativeValue(consistencyLevel))).stream().map(user -> new UserImpl(user)).collect(Collectors.toSet()); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } @Override - public User get(String username) throws TypeDBDriverException { + public boolean contains(String username, ConsistencyLevel consistencyLevel) throws TypeDBDriverException { Validator.requireNonNull(username, "username"); try { - com.typedb.driver.jni.User user = users_get(nativeDriver, username); - if (user != null) return new UserImpl(user, this); - else return null; + return users_contains(nativeDriver, username, ConsistencyLevel.nativeValue(consistencyLevel)); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } @Override - public User getCurrentUser() throws TypeDBDriverException { - try { // TODO: Make noexcept if we leave it returning just a String - com.typedb.driver.jni.User user = users_get_current_user(nativeDriver); - if (user != null) return new UserImpl(user, this); + public User get(String username, ConsistencyLevel consistencyLevel) throws TypeDBDriverException { + Validator.requireNonNull(username, "username"); + try { + com.typedb.driver.jni.User user = users_get(nativeDriver, username, ConsistencyLevel.nativeValue(consistencyLevel)); + if (user != null) return new UserImpl(user); else return null; } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); @@ -75,20 +74,22 @@ public User getCurrentUser() throws TypeDBDriverException { } @Override - public Set all() throws TypeDBDriverException { + public User getCurrent(ConsistencyLevel consistencyLevel) throws TypeDBDriverException { try { - return new NativeIterator<>(users_all(nativeDriver)).stream().map(user -> new UserImpl(user, this)).collect(Collectors.toSet()); + com.typedb.driver.jni.User user = users_get_current(nativeDriver, ConsistencyLevel.nativeValue(consistencyLevel)); + if (user != null) return new UserImpl(user); + else return null; } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } } @Override - public void create(String username, String password) throws TypeDBDriverException { + public void create(String username, String password, ConsistencyLevel consistencyLevel) throws TypeDBDriverException { Validator.requireNonNull(username, "username"); Validator.requireNonNull(password, "password"); try { - users_create(nativeDriver, username, password); + users_create(nativeDriver, username, password, ConsistencyLevel.nativeValue(consistencyLevel)); } catch (com.typedb.driver.jni.Error e) { throw new TypeDBDriverException(e); } diff --git a/nodejs/api/connection/user/UserManager.ts b/nodejs/api/connection/user/UserManager.ts index 761dd1b097..c791f53584 100644 --- a/nodejs/api/connection/user/UserManager.ts +++ b/nodejs/api/connection/user/UserManager.ts @@ -30,7 +30,7 @@ export interface UserManager { * driver.users.contains(username) * ``` * - * @param username - The user name to be checked + * @param username - The username to be checked */ contains(name: string): Promise; diff --git a/python/README.md b/python/README.md index b3caae3046..2c9319aae7 100644 --- a/python/README.md +++ b/python/README.md @@ -22,10 +22,11 @@ pip3 install typedb-driver 3. Make sure a [TypeDB Server](https://typedb.com/docs/home/install/) is running. 4. In your python program, import from `typedb.driver` (see [Example usage](#example-usage) or `tests/integration` for examples): + ```py from typedb.driver import * -driver = TypeDB.driver(address=TypeDB.DEFAULT_ADDRESS, ...) +driver = TypeDB.driver(addresses=TypeDB.DEFAULT_ADDRESS, ...) ``` ## Example usage @@ -41,7 +42,8 @@ class TypeDBExample: def typedb_example(self): # Open a driver connection. Specify your parameters if needed # The connection will be automatically closed on the "with" block exit - with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) as driver: + with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) as driver: # Create a database driver.databases.create("typedb") database = driver.databases.get("typedb") diff --git a/python/docs_structure.bzl b/python/docs_structure.bzl index 020e4bcbd8..66d2a47f81 100644 --- a/python/docs_structure.bzl +++ b/python/docs_structure.bzl @@ -100,12 +100,19 @@ dir_mapping = { "Promise.adoc": "answer", "Concept.adoc": "concept", "TypeDB.adoc": "connection", - "DriverOptions.adoc": "connection", "Credentials.adoc": "connection", + "ConsistencyLevel.adoc": "connection", + "Strong.adoc": "connection", + "Eventual.adoc": "connection", + "ReplicaDependent.adoc": "connection", + "DriverOptions.adoc": "connection", + "DriverTlsConfig.adoc": "connection", "Driver.adoc": "connection", + "ServerReplica.adoc": "connection", + "ServerVersion.adoc": "connection", + "ReplicaRole.adoc": "connection", "User.adoc": "connection", "UserManager.adoc": "connection", -# "Replica.adoc": "connection", "Database.adoc": "connection", "DatabaseManager.adoc": "connection", "Relation.adoc": "data", diff --git a/python/example.py b/python/example.py index 3f806395a7..aa6a23cfac 100644 --- a/python/example.py +++ b/python/example.py @@ -8,7 +8,8 @@ class TypeDBExample: def typedb_example(self): # Open a driver connection. Specify your parameters if needed # The connection will be automatically closed on the "with" block exit - with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) as driver: + with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) as driver: # Create a database driver.databases.create("typedb") database = driver.databases.get("typedb") diff --git a/python/rules.bzl b/python/rules.bzl index 0c269ff0fd..9abcb39623 100644 --- a/python/rules.bzl +++ b/python/rules.bzl @@ -77,7 +77,7 @@ def native_driver_versioned(python_versions): ], url = "https://github.com/typedb/typedb-driver", author = "TypeDB Community", - author_email = "community@typedb.com", + author_email = "core@typedb.com", license = "Apache-2.0", requirements_file = "//python:requirements.txt", keywords = ["typedb", "database", "graph", "knowledgebase", "knowledge-engineering"], diff --git a/python/tests/behaviour/background/BUILD b/python/tests/behaviour/background/BUILD index 6efe10918a..5d06114aea 100644 --- a/python/tests/behaviour/background/BUILD +++ b/python/tests/behaviour/background/BUILD @@ -26,8 +26,8 @@ py_library( ) py_library( - name = "community", - srcs = ["community/environment.py"], + name = "core", + srcs = ["core/environment.py"], deps = [], ) diff --git a/python/tests/behaviour/background/cluster/environment.py b/python/tests/behaviour/background/cluster/environment.py index 62df61d775..aae7f59363 100644 --- a/python/tests/behaviour/background/cluster/environment.py +++ b/python/tests/behaviour/background/cluster/environment.py @@ -15,60 +15,62 @@ # specific language governing permissions and limitations # under the License. +import os + from tests.behaviour.background import environment_base +from tests.behaviour.config.parameters import set_cluster_mode from tests.behaviour.context import Context from typedb.driver import * -# TODO: Reuse code from the community environment when needed, update for multiple clusters -IGNORE_TAGS = ["ignore", "ignore-typedb-driver", "ignore-typedb-driver-python"] + +def setup_cluster(context: Context): + with create_driver(context) as driver: + if len(driver.replicas()) != len(context.default_clustering_addresses): + for i, address in enumerate(context.default_clustering_addresses): + replica_id = i + 1 + + # 1 is the default registered replica + if replica_id != 1: + driver.register_replica(replica_id, address) def before_all(context: Context): environment_base.before_all(context) - # context.credentials_root_ca_path = os.environ["ROOT_CA"] # TODO: test root ca with cluster - context.create_driver_fn = lambda host="localhost", port=None, user=None, password=None: \ - create_driver(context, host, port, user, password) - context.setup_context_driver_fn = lambda host="localhost", port=None, username=None, password=None: \ - setup_context_driver(context, host, port, username, password) + context.tls_root_ca_path = os.environ["ROOT_CA"] + context.create_driver_fn = lambda address=None, user=None, password=None: \ + create_driver(context, address, user, password) + context.setup_context_driver_fn = lambda address=None, username=None, password=None: \ + setup_context_driver(context, address, username, password) + context.default_address = ["127.0.0.1:11729", "127.0.0.1:21729", "127.0.0.1:31729"] + context.default_clustering_addresses = ["127.0.0.1:11730", "127.0.0.1:21730", "127.0.0.1:31730"] + context.driver_options.tls_config = DriverTlsConfig.enabled_with_root_ca(context.tls_root_ca_path) + setup_cluster(context) 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) + set_cluster_mode(True) + environment_base.before_scenario(context, scenario) + context.driver_options.tls_config = DriverTlsConfig.enabled_with_root_ca(context.tls_root_ca_path) -def setup_context_driver(context, host="localhost", port=None, username=None, password=None): - # TODO: Use root_ca_path in connection - context.driver = create_driver(context, host, port, username, password) +def setup_context_driver(context, address=None, username=None, password=None): + context.driver = create_driver(context, address, username, password) -def create_driver(context, host="localhost", port=None, username=None, password=None) -> Driver: - if port is None: - port = int(context.config.userdata["port"]) +def create_driver(context, address=None, username=None, password=None) -> Driver: + if address is None: + address = context.default_address if username is None: - username = "admin" + username = context.DEFAULT_USERNAME if password is None: - password = "password" + password = context.DEFAULT_PASSWORD credentials = Credentials(username, password) - return TypeDB.driver(address=f"{host}:{port}", credentials=credentials, driver_options=DriverOptions(is_tls_enabled=False)) + return TypeDB.driver(addresses=address, credentials=credentials, driver_options=context.driver_options) def after_scenario(context: Context, scenario): environment_base.after_scenario(context, scenario) - # TODO: reset the database through the TypeDB runner once it exists - context.setup_context_driver_fn() - for database in context.driver.databases.all(): - database.delete() - for user in context.driver.users.all(): - if user.name == "admin": - continue - context.driver.users.get(user.name).delete() - context.driver.close() - def after_all(context: Context): environment_base.after_all(context) diff --git a/python/tests/behaviour/background/community/environment.py b/python/tests/behaviour/background/community/environment.py deleted file mode 100644 index aa55a1c1ec..0000000000 --- a/python/tests/behaviour/background/community/environment.py +++ /dev/null @@ -1,71 +0,0 @@ -# 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. - -from tests.behaviour.background import environment_base -from tests.behaviour.context import Context -from typedb.driver import * - -IGNORE_TAGS = ["ignore", "ignore-typedb-driver", "ignore-typedb-driver-python"] - - -def before_all(context: Context): - environment_base.before_all(context) - context.create_driver_fn = lambda host="localhost", port=None, user=None, password=None: \ - create_driver(context, host, port, user, password) - context.setup_context_driver_fn = lambda host="localhost", port=None, username=None, password=None: \ - setup_context_driver(context, host, port, username, password) - - -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) - - -def setup_context_driver(context, host="localhost", port=None, username=None, password=None): - context.driver = create_driver(context, host, port, username, password) - - -def create_driver(context, host="localhost", port=None, username=None, password=None) -> Driver: - if port is None: - port = int(context.config.userdata["port"]) - if username is None: - username = "admin" - if password is None: - password = "password" - credentials = Credentials(username, password) - return TypeDB.driver(address=f"{host}:{port}", credentials=credentials, driver_options=DriverOptions(is_tls_enabled=False)) - - -def after_scenario(context: Context, scenario): - environment_base.after_scenario(context, scenario) - - # TODO: reset the database through the TypeDB runner once it exists - context.setup_context_driver_fn() - for database in context.driver.databases.all(): - database.delete() - for user in context.driver.users.all(): - if user.name == "admin": - continue - context.driver.users.get(user.name).delete() - context.driver.close() - - -def after_all(context: Context): - environment_base.after_all(context) diff --git a/python/tests/behaviour/background/core/environment.py b/python/tests/behaviour/background/core/environment.py new file mode 100644 index 0000000000..ec53d7d10f --- /dev/null +++ b/python/tests/behaviour/background/core/environment.py @@ -0,0 +1,58 @@ +# 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. + +from tests.behaviour.background import environment_base +from tests.behaviour.context import Context +from typedb.driver import * + + +def before_all(context: Context): + environment_base.before_all(context) + context.create_driver_fn = lambda address=None, user=None, password=None: \ + create_driver(context, address, user, password) + context.setup_context_driver_fn = lambda address=None, username=None, password=None: \ + setup_context_driver(context, address, username, password) + context.default_address = TypeDB.DEFAULT_ADDRESS + context.driver_options.tls_config = DriverTlsConfig.disabled() + + +def before_scenario(context: Context, scenario): + environment_base.before_scenario(context, scenario) + context.driver_options.tls_config = DriverTlsConfig.disabled() + + +def setup_context_driver(context, address=None, username=None, password=None): + context.driver = create_driver(context, address, username, password) + + +def create_driver(context, address=None, username=None, password=None) -> Driver: + if address is None: + address = context.default_address + if username is None: + username = context.DEFAULT_USERNAME + if password is None: + password = context.DEFAULT_PASSWORD + credentials = Credentials(username, password) + return TypeDB.driver(addresses=address, credentials=credentials, driver_options=context.driver_options) + + +def after_scenario(context: Context, scenario): + environment_base.after_scenario(context, scenario) + + +def after_all(context: Context): + environment_base.after_all(context) diff --git a/python/tests/behaviour/background/environment_base.py b/python/tests/behaviour/background/environment_base.py index ae45bda82b..dadae21d8a 100644 --- a/python/tests/behaviour/background/environment_base.py +++ b/python/tests/behaviour/background/environment_base.py @@ -24,14 +24,26 @@ from tests.behaviour.util.util import delete_dir from typedb.driver import * +IGNORE_TAGS = ["ignore", "ignore-typedb-driver", "ignore-typedb-driver-python"] + def before_all(context: Context): context.THREAD_POOL_SIZE = 32 + context.DEFAULT_USERNAME = "admin" + context.DEFAULT_PASSWORD = "password" + context.driver_options = DriverOptions(DriverTlsConfig.disabled()) context.init_transaction_options_if_needed_fn = lambda: _init_transaction_options_if_needed(context) context.init_query_options_if_needed_fn = lambda: _init_query_options_if_needed(context) + context.full_path = lambda file_name: _full_path(context, file_name) + context.tx = lambda: next(iter(context.transactions), None) + context.clear_answers = lambda: _clear_answers(context) + context.clear_concurrent_answers = lambda: _clear_concurrent_answers(context) + +def before_scenario(context: Context, scenario): + if ignored(scenario): + return -def before_scenario(context: Context): # setup context state context.temp_dir = None context.background_driver = None @@ -43,13 +55,17 @@ def before_scenario(context: Context): context.collected_answer = None # [ConceptRow] / [dict] context.concurrent_answers = None context.unwrapped_concurrent_answers = None - # setup context functions - context.full_path = lambda file_name: _full_path(context, file_name) - context.tx = lambda: next(iter(context.transactions), None) - context.clear_answers = lambda: _clear_answers(context) - context.clear_concurrent_answers = lambda: _clear_concurrent_answers(context) context.transaction_options = None context.query_options = None + context.driver_options = DriverOptions(DriverTlsConfig.disabled()) + + +def ignored(scenario): + for tag in IGNORE_TAGS: + if tag in scenario.effective_tags: + scenario.skip("tagged with @" + tag) + return True + return False def after_scenario(context: Context, scenario): @@ -62,6 +78,14 @@ def after_scenario(context: Context, scenario): if context.background_driver and context.background_driver.is_open(): context.background_driver.close() + context.setup_context_driver_fn() + for database in context.driver.databases.all(): + database.delete() + for user in context.driver.users.all(): + if user.name != "admin": + context.driver.users.get(user.name).delete() + context.driver.close() + def after_all(_: Context): pass diff --git a/python/tests/behaviour/behave_rule.bzl b/python/tests/behaviour/behave_rule.bzl index cb0a420329..6d9c049753 100644 --- a/python/tests/behaviour/behave_rule.bzl +++ b/python/tests/behaviour/behave_rule.bzl @@ -18,7 +18,7 @@ load("@typedb_driver_pip//:requirements.bzl", "requirement") -def py_behave_test(*, name, background, native_typedb_artifact, steps, feats, deps, data=[], typedb_port, **kwargs): +def py_behave_test(*, name, background, steps, feats, deps, data=[], typedb_port, **kwargs): prepare_py_behave_directory( name = name + "_features", background = background, @@ -32,15 +32,15 @@ def py_behave_test(*, name, background, native_typedb_artifact, steps, feats, de srcs = ["//python/tests/behaviour:entry_point_behave.py"], args = ["$(location :" + name + "_features)", "--no-capture", "-D", "port=" + typedb_port], main = "//python/tests/behaviour:entry_point_behave.py", + **kwargs, ) -def typedb_behaviour_py_test_community(name, **kwargs): +def typedb_behaviour_py_test_core(name, **kwargs): py_behave_test( - name = name + "-community", - background = "@//python/tests/behaviour/background:community", - native_typedb_artifact = "@//tool/test:native-typedb-artifact", + name = name + "-core", + background = "@//python/tests/behaviour/background:core", toolchains = ["@rules_python//python:current_py_toolchain"], - typedb_port = "1729", + typedb_port = "1729", # TODO: Not needed? **kwargs, ) @@ -48,14 +48,13 @@ def typedb_behaviour_py_test_cluster(name, **kwargs): py_behave_test( name = name + "-cluster", background = "@//python/tests/behaviour/background:cluster", - native_typedb_artifact = "@//tool/test:native-typedb-artifact", # TODO: Change to cloud artifact when available toolchains = ["@rules_python//python:current_py_toolchain"], - typedb_port = "1729", # TODO: Might want to change back to 11729 when cloud has multiple nodes + typedb_port = "11729", # TODO: Not needed? **kwargs, ) def typedb_behaviour_py_test(name, **kwargs): - typedb_behaviour_py_test_community(name, **kwargs) + typedb_behaviour_py_test_core(name, **kwargs) typedb_behaviour_py_test_cluster(name, **kwargs) def _prepare_py_behave_directory_impl(ctx): diff --git a/python/tests/behaviour/config/parameters.py b/python/tests/behaviour/config/parameters.py index 80a61ecdd5..03b0349339 100644 --- a/python/tests/behaviour/config/parameters.py +++ b/python/tests/behaviour/config/parameters.py @@ -18,16 +18,34 @@ from __future__ import annotations import re +import time from enum import Enum from typing import Callable, Optional import parse + +# Cluster mode retry settings +_cluster_mode = False +RETRY_ATTEMPTS = 3 +RETRY_DELAY_S = 0.5 + + +def set_cluster_mode(is_cluster: bool): + global _cluster_mode + _cluster_mode = is_cluster + + +def is_cluster_mode() -> bool: + return _cluster_mode + + from behave import register_type from behave.model import Table, Row from behave.runner import Context from hamcrest import * from typedb.api.answer.query_type import QueryType from typedb.api.connection.transaction import TransactionType +from typedb.api.connection.consistency_level import ConsistencyLevel as TypeDBConsistencyLevel from typedb.common.exception import TypeDBDriverException from typedb.driver import * @@ -242,7 +260,17 @@ def check(self, func: Callable, exception=TypeDBDriverException): if self.may_error: assert_that(func, raises(exception, self.message)) else: - func() + attempts = RETRY_ATTEMPTS if is_cluster_mode() else 1 + last_exception = None + for i in range(attempts): + try: + func() + return + except Exception as e: + last_exception = e + if i < attempts - 1: + time.sleep(RETRY_DELAY_S) + raise last_exception def __repr__(self): return f"MayError({self.may_error})" @@ -328,3 +356,29 @@ def parse_by_index_of_variable_or_not(value: str) -> bool: register_type(IsByVarIndex=parse_by_index_of_variable_or_not) + + +class ConsistencyLevel: + + def __init__(self, consistency_level: TypeDBConsistencyLevel): + self.consistency_level = consistency_level + + def __repr__(self): + return f"ConsistencyLevel({self.consistency_level})" + + +@parse.with_pattern("strong|eventual|replica\((?P
.*)\)") +def parse_consistency_level(value: str) -> ConsistencyLevel: + if value == "strong": + return ConsistencyLevel(TypeDBConsistencyLevel.Strong()) + elif value == "eventual": + return ConsistencyLevel(TypeDBConsistencyLevel.Eventual()) + else: + match = re.match(r'replica\((?P
.*)\)', value) + if match: + return ConsistencyLevel(TypeDBConsistencyLevel.ReplicaDependent(match.group("address"))) + else: + raise ValueError(f"Unrecognised ConsistencyLevel: {value}") + + +register_type(ConsistencyLevel=parse_consistency_level) diff --git a/python/tests/behaviour/connection/connection_steps.py b/python/tests/behaviour/connection/connection_steps.py index 28bfa66e30..36ce2b435c 100644 --- a/python/tests/behaviour/connection/connection_steps.py +++ b/python/tests/behaviour/connection/connection_steps.py @@ -16,9 +16,23 @@ # under the License. from behave import * -from tests.behaviour.config.parameters import MayError +from hamcrest import * +from tests.behaviour.config.parameters import MayError, check_is_none from tests.behaviour.context import Context +from tests.behaviour.config.parameters import ConsistencyLevel, parse_list +from typedb.api.server.replica_role import ReplicaRole + + +def replace_host(address: str, new_host: str) -> str: + return address.replace("127.0.0.1", new_host) + + +def replace_port(address: str, new_port: str) -> str: + address_parts = address.rsplit(":", 1) + address_parts[-1] = new_port + return "".join(address_parts) + @step(u'typedb has configuration') def step_impl(context: Context): @@ -37,14 +51,33 @@ def step_impl(context: Context): context.setup_context_driver_fn() +@step(u'connection opens to single server with default authentication') +def step_impl(context: Context): + context.setup_context_driver_fn(address=[context.default_address[0]]) + + @step(u'connection opens with a wrong host{may_error:MayError}') def step_impl(context: Context, may_error: MayError): - may_error.check(lambda: context.setup_context_driver_fn(host="surely-not-localhost")) + address = context.default_address + if isinstance(address, str): + address = replace_host(address, "surely-not-localhost") + elif isinstance(address, list): + address = [replace_host(addr, "surely-not-localhost") for addr in address] + else: + raise Exception("Unexpected default address: cannot finish the test") + may_error.check(lambda: context.setup_context_driver_fn(address=address)) @step(u'connection opens with a wrong port{may_error:MayError}') def step_impl(context: Context, may_error: MayError): - may_error.check(lambda: context.setup_context_driver_fn(port=0)) + address = context.default_address + if isinstance(address, str): + address = replace_port(address, "0") + elif isinstance(address, list): + address = [replace_port(addr, "0") for addr in address] + else: + raise Exception("Unexpected default address: cannot finish the test") + may_error.check(lambda: context.setup_context_driver_fn(address=address)) @step( @@ -67,16 +100,101 @@ def step_impl(context: Context): @step("connection is open: {is_open:Bool}") def step_impl(context: Context, is_open: bool): real_is_open = hasattr(context, 'driver') and context.driver and context.driver.is_open() - assert is_open == real_is_open + assert_that(real_is_open, equal_to(is_open)) + + +@step(u'connection contains distribution{may_error:MayError}') +def step_impl(context: Context, may_error: MayError): + may_error.check(lambda: assert_that(len(context.driver.server_version().distribution), greater_than(0))) + + +@step(u'connection contains version{may_error:MayError}') +def step_impl(context: Context, may_error: MayError): + may_error.check(lambda: assert_that(len(context.driver.server_version().version), greater_than(0))) + + +@step("connection has {count:Int} replica") +@step("connection has {count:Int} replicas") +def step_impl(context: Context, count: int): + assert_that(len(context.driver.replicas()), equal_to(count)) + + +@step(u'connection primary replica exists') +def step_impl(context: Context): + check_is_none(context.driver.primary_replica(), False) + + +@step(u'connection get replica({address}) {exists_or_doesnt:ExistsOrDoesnt}') +def step_impl(context: Context, address: str, exists_or_doesnt: bool): + replicas = context.driver.replicas() + exists = any(r.address == address for r in replicas) + assert_that(exists, equal_to(exists_or_doesnt), f"replica {address}") + + +@step(u'connection get replica({address}) has term') +def step_impl(context: Context, address: str): + replicas = context.driver.replicas() + replica = next((r for r in replicas if r.address == address), None) + check_is_none(replica, False) + check_is_none(replica.term, False) + + +@step(u'connection replicas have roles') +def step_impl(context: Context): + replicas = context.driver.replicas() + expected_roles = parse_list(context) + expected_primary_count = 0 + expected_secondary_count = 0 + expected_candidate_count = 0 + for role in expected_roles: + if role == 'primary': + expected_primary_count += 1 + elif role == 'secondary': + expected_secondary_count += 1 + elif role == 'candidate': + expected_candidate_count += 1 + else: + raise ValueError(f"Unknown replica role: {role}") + + actual_primary_count = sum(1 for r in replicas if r.role.is_primary()) + actual_secondary_count = sum(1 for r in replicas if r.role.is_secondary()) + actual_candidate_count = sum(1 for r in replicas if r.role.is_candidate()) + + assert_that(actual_primary_count, equal_to(expected_primary_count), + f"Expected {expected_primary_count} primary replicas, found {actual_primary_count}") + assert_that(actual_secondary_count, equal_to(expected_secondary_count), + f"Expected {expected_secondary_count} secondary replicas, found {actual_secondary_count}") + assert_that(actual_candidate_count, equal_to(expected_candidate_count), + f"Expected {expected_candidate_count} candidate replicas, found {actual_candidate_count}") @step("connection has {count:Int} database") @step("connection has {count:Int} databases") def step_impl(context: Context, count: int): - assert len(context.driver.databases.all()) == count + assert_that(len(context.driver.databases.all()), equal_to(count)) @step("connection has {count:Int} user") @step("connection has {count:Int} users") def step_impl(context: Context, count: int): - assert len(context.driver.users.all()) == count + assert_that(len(context.driver.users.all()), equal_to(count)) + + +@step("set driver option use_replication to: {value:Bool}") +def step_impl(context: Context, value: bool): + context.driver_options.use_replication = value + + +@step("set driver option primary_failover_retries to: {value:Int}") +def step_impl(context: Context, value: int): + context.driver_options.primary_failover_retries = value + + +@step("set driver option replica_discovery_attempts to: {value:Int}") +def step_impl(context: Context, value: int): + context.driver_options.replica_discovery_attempts = value + + +@step("set database operation consistency to: {consistency_level:ConsistencyLevel}") +def step_impl(context: Context, consistency_level: ConsistencyLevel): + context.database_operation_consistency = consistency_level.consistency_level diff --git a/python/tests/behaviour/connection/database/BUILD b/python/tests/behaviour/connection/database/BUILD index 04edcfe840..901617bada 100644 --- a/python/tests/behaviour/connection/database/BUILD +++ b/python/tests/behaviour/connection/database/BUILD @@ -42,7 +42,7 @@ typedb_behaviour_py_test( "//python/tests/behaviour/util:util", ], data = ["//python:native-driver-binary-link", "//python:native-driver-wrapper-link"], - size = "small", + size = "medium", ) checkstyle_test( diff --git a/python/tests/behaviour/connection/database/database_steps.py b/python/tests/behaviour/connection/database/database_steps.py index e0e728df96..17f5d284a2 100644 --- a/python/tests/behaviour/connection/database/database_steps.py +++ b/python/tests/behaviour/connection/database/database_steps.py @@ -28,6 +28,10 @@ from typedb.driver import * +def get_database_consistency(context: Context): + return getattr(context, 'database_operation_consistency', None) + + def create_databases(driver: Driver, names: list[str]): for name in names: driver.databases.create(name) @@ -64,7 +68,8 @@ def import_database(context: Context, name: str, schema: str, data_file: str, ma @step("connection create database: {name:NonSemicolon}{may_error:MayError}") def step_impl(context: Context, name: str, may_error: MayError): - may_error.check(lambda: create_databases(context.driver, [name])) + consistency = get_database_consistency(context) + may_error.check(lambda: context.driver.databases.create(name, consistency)) @step("connection create database with empty name{may_error:MayError}") @@ -96,7 +101,8 @@ def step_impl(context: Context, name: str, may_error: MayError): @step("connection delete database: {name:NonSemicolon}{may_error:MayError}") def step_impl(context: Context, name: str, may_error: MayError): - may_error.check(lambda: delete_databases(context.driver, [name])) + consistency = get_database_consistency(context) + may_error.check(lambda: context.driver.databases.get(name, consistency).delete()) @step("connection delete databases") @@ -122,16 +128,23 @@ def step_impl(context: Context, name: str, may_error: MayError): @step("connection has database: {name:NonSemicolon}") def step_impl(context: Context, name: str): - has_databases(context, [name]) + consistency = get_database_consistency(context) + assert_that(context.driver.databases.contains(name, consistency), equal_to(True), + f"Expected database {name} to exist") @step("connection has databases") def step_impl(context: Context): - has_databases(context, names=parse_list(context)) + consistency = get_database_consistency(context) + names = parse_list(context) + for name in names: + assert_that(context.driver.databases.contains(name, consistency), equal_to(True), + f"Expected database {name} to exist") def does_not_have_databases(context: Context, names: list[str]): - databases = [db.name for db in context.driver.databases.all()] + consistency = get_database_consistency(context) + databases = [db.name for db in context.driver.databases.all(consistency)] for name in names: assert_that(name, not_(is_in(databases))) diff --git a/python/tests/behaviour/connection/transaction/transaction_steps.py b/python/tests/behaviour/connection/transaction/transaction_steps.py index 84797e2c54..0b3139eeb9 100644 --- a/python/tests/behaviour/connection/transaction/transaction_steps.py +++ b/python/tests/behaviour/connection/transaction/transaction_steps.py @@ -21,7 +21,7 @@ from behave import * from hamcrest import * -from tests.behaviour.config.parameters import MayError, parse_list, parse_transaction_type +from tests.behaviour.config.parameters import ConsistencyLevel, MayError, parse_list, parse_transaction_type from tests.behaviour.context import Context from typedb.api.connection.transaction import TransactionType from typedb.driver import * @@ -156,6 +156,12 @@ def step_impl(context: Context, value: int): context.transaction_options.schema_lock_acquire_timeout_millis = value +@step("set transaction option read_consistency_level to: {consistency_level:ConsistencyLevel}") +def step_impl(context: Context, consistency_level: ConsistencyLevel): + context.init_transaction_options_if_needed_fn() + context.transaction_options.read_consistency_level = consistency_level.consistency_level + + @step("schedule database creation on transaction close: {database_name:Words}") def step_impl(context: Context, database_name: str): context.tx().on_close(lambda: context.driver.databases.create(database_name)) diff --git a/python/tests/behaviour/connection/user/user_steps.py b/python/tests/behaviour/connection/user/user_steps.py index 66af246f68..29832e2a47 100644 --- a/python/tests/behaviour/connection/user/user_steps.py +++ b/python/tests/behaviour/connection/user/user_steps.py @@ -70,4 +70,4 @@ def step_impl(context: Context, username: str, may_error: MayError): @step("get current username: {username:NonSemicolon}") def step_impl(context: Context, username: str): - assert_that(context.driver.users.get_current_user().name, is_(equal_to(username))) + assert_that(context.driver.users.get_current().name, is_(equal_to(username))) diff --git a/python/tests/behaviour/driver/cluster/BUILD b/python/tests/behaviour/driver/cluster/BUILD new file mode 100644 index 0000000000..ecdc5c3cab --- /dev/null +++ b/python/tests/behaviour/driver/cluster/BUILD @@ -0,0 +1,47 @@ +# 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 = ["//python/tests/behaviour:__subpackages__"]) +load("//python/tests/behaviour:behave_rule.bzl", "typedb_behaviour_py_test_cluster") +load("@typedb_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") + +typedb_behaviour_py_test_cluster( + name = "test", + feats = ["@typedb_behaviour//driver:cluster.feature"], + steps = [ + "//python/tests/behaviour/connection:steps", + "//python/tests/behaviour/connection/database:steps", + "//python/tests/behaviour/connection/transaction:steps", + "//python/tests/behaviour/query:steps", + "//python/tests/behaviour/util:steps", + ], + deps = [ + "//python:driver_python", + "//python/tests/behaviour:context", + "//python/tests/behaviour/util:util", + "//python/tests/behaviour/config:parameters", + "//python/tests/behaviour/background", + ], + data = ["//python:native-driver-binary-link", "//python:native-driver-wrapper-link"], +) + +checkstyle_test( + name = "checkstyle", + include = glob(["*"]), + license_type = "apache-header", + size = "small", +) diff --git a/python/tests/behaviour/driver/concept/BUILD b/python/tests/behaviour/driver/concept/BUILD index a5f168f338..539bba747c 100644 --- a/python/tests/behaviour/driver/concept/BUILD +++ b/python/tests/behaviour/driver/concept/BUILD @@ -37,7 +37,6 @@ typedb_behaviour_py_test( "//python/tests/behaviour/background", ], data = ["//python:native-driver-binary-link", "//python:native-driver-wrapper-link"], - size = "medium", ) checkstyle_test( diff --git a/python/tests/behaviour/driver/user/BUILD b/python/tests/behaviour/driver/user/BUILD index 76aa702378..1db37a762f 100644 --- a/python/tests/behaviour/driver/user/BUILD +++ b/python/tests/behaviour/driver/user/BUILD @@ -36,7 +36,7 @@ typedb_behaviour_py_test( "//python/tests/behaviour/util:util", ], data = ["//python:native-driver-binary-link", "//python:native-driver-wrapper-link"], - size = "small", + size = "medium", ) checkstyle_test( diff --git a/python/tests/behaviour/query/query_steps.py b/python/tests/behaviour/query/query_steps.py index 02777d3273..188da036d0 100644 --- a/python/tests/behaviour/query/query_steps.py +++ b/python/tests/behaviour/query/query_steps.py @@ -295,7 +295,15 @@ def get_row_get_concept_of_kind(context: Context, row_index: int, var: str, is_b elif kind == ConceptKind.VALUE: return get_row_get_value(context, row_index, var, is_by_var_index) else: - raise ValueError(f"Not all ConceptKind variants are covered! Found {kind}") + # Debug info: print type details to diagnose enum comparison issues + raise ValueError( + f"Not all ConceptKind variants are covered! Found {kind}\n" + f" kind type: {type(kind)}, module: {type(kind).__module__}\n" + f" ConceptKind.CONCEPT type: {type(ConceptKind.CONCEPT)}, module: {type(ConceptKind.CONCEPT).__module__}\n" + f" kind == ConceptKind.CONCEPT: {kind == ConceptKind.CONCEPT}\n" + f" kind.name: {kind.name}, ConceptKind.CONCEPT.name: {ConceptKind.CONCEPT.name}\n" + f" id(type(kind)): {id(type(kind))}, id(ConceptKind): {id(ConceptKind)}" + ) @step("answer get row({row_index:Int}) query type {is_or_not:IsOrNot}: {query_type:QueryType}") diff --git a/python/tests/behaviour/util/functor_encoder.py b/python/tests/behaviour/util/functor_encoder.py index 1b5289112c..fe8ec920e5 100644 --- a/python/tests/behaviour/util/functor_encoder.py +++ b/python/tests/behaviour/util/functor_encoder.py @@ -20,7 +20,7 @@ from typedb.analyze import ( Constraint, ConstraintVertex, Variable, - ConjunctionID, Pipeline, PipelineStage, Fetch, + ConjunctionID, Pipeline, PipelineStage, Fetch, Function, ReturnOperation, ReduceStage, Reducer, SortStage, VariableAnnotations, ) diff --git a/python/tests/deployment/test.py b/python/tests/deployment/test.py index 9f90999d6c..d9ecf5cee6 100644 --- a/python/tests/deployment/test.py +++ b/python/tests/deployment/test.py @@ -35,7 +35,8 @@ class TestDeployedPythonDriver(TestCase): def setUpClass(cls): super(TestDeployedPythonDriver, cls).setUpClass() global driver - driver = TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) + driver = TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) @classmethod def tearDownClass(cls): diff --git a/python/tests/integration/cluster/BUILD b/python/tests/integration/cluster/BUILD index 1fbbb525d6..a17ae2fc2d 100644 --- a/python/tests/integration/cluster/BUILD +++ b/python/tests/integration/cluster/BUILD @@ -19,7 +19,7 @@ load(":cluster_test_rule.bzl", "typedb_cloud_py_test") load("@typedb_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") load("@typedb_driver_pip//:requirements.bzl", "requirement") -# TODO: This package can contain cluster-specific integration tests. Tests available for running for both community +# TODO: This package can contain cluster-specific integration tests. Tests available for running for both core # edition and cluster should be run for both setups (and be limited: always prefer BDDs to integration tests)! #typedb_cloud_py_test( @@ -30,7 +30,7 @@ load("@typedb_driver_pip//:requirements.bzl", "requirement") # ], # data = ["//python:native-driver-binary-link", "//python:native-driver-wrapper-link"], # size = "medium", -# native_typedb_cloud_artifact = "//tool/test:native-typedb-cloud-artifact", +# native_typedb_cluster_artifact = "//tool/test:native-typedb-cloud-artifact", #) checkstyle_test( diff --git a/python/tests/integration/cluster/cluster_test_rule.bzl b/python/tests/integration/cluster/cluster_test_rule.bzl index 815f236361..b64f4e48df 100644 --- a/python/tests/integration/cluster/cluster_test_rule.bzl +++ b/python/tests/integration/cluster/cluster_test_rule.bzl @@ -26,7 +26,7 @@ def _rule_implementation(ctx): # Store the path of the test source file. It is recommended to only have one source file. test_src = ctx.files.srcs[0].path - typedb_cloud_distro = str(ctx.files.native_typedb_cloud_artifact[0].short_path) + typedb_cloud_distro = str(ctx.files.native_typedb_cluster_artifact[0].short_path) # TODO: This code is, mostly, copied from our TypeDB behave test cmd = "set -xe && TYPEDB_ARCHIVE=%s" % typedb_cloud_distro @@ -48,7 +48,7 @@ def _rule_implementation(ctx): --server.peers.peer-3.internal-address.grpc=localhost:31731 \ --server.encryption.enable=true \ --diagnostics.monitoring.port=${1}1732 \ - --development-mode.enable=true + --development-mode.enabled=true } if test -d typedb_distribution; then echo Existing distribution detected. Cleaning. @@ -127,7 +127,7 @@ def _rule_implementation(ctx): # https://bazel.build/versions/master/docs/skylark/rules.html#runfiles return [DefaultInfo( # The shell executable - the output of this rule - can use these files at runtime. - runfiles = ctx.runfiles(files = ctx.files.srcs + ctx.files.deps + ctx.files.data + ctx.files.native_typedb_cloud_artifact) + runfiles = ctx.runfiles(files = ctx.files.srcs + ctx.files.deps + ctx.files.data + ctx.files.native_typedb_cluster_artifact) )] """ @@ -151,7 +151,7 @@ typedb_cloud_py_test = rule( "srcs": attr.label_list(mandatory=True,allow_empty=False,allow_files=True), "deps": attr.label_list(mandatory=True,allow_empty=False), "data": attr.label_list(), - "native_typedb_cloud_artifact": attr.label(mandatory=True) + "native_typedb_cluster_artifact": attr.label(mandatory=True) }, test=True, ) diff --git a/python/tests/integration/test_debug.py b/python/tests/integration/test_debug.py index c6cfa73b67..c3df5bb2bb 100644 --- a/python/tests/integration/test_debug.py +++ b/python/tests/integration/test_debug.py @@ -29,7 +29,8 @@ class TestDebug(TestCase): def setUp(self): - with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) as driver: + with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) as driver: if TYPEDB not in [db.name for db in driver.databases.all()]: driver.databases.create(TYPEDB) diff --git a/python/tests/integration/test_driver.py b/python/tests/integration/test_driver.py index 981d30e561..fde17b25ed 100644 --- a/python/tests/integration/test_driver.py +++ b/python/tests/integration/test_driver.py @@ -26,13 +26,14 @@ class TestDriver(TestCase): def setUp(self): - with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) as driver: + with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) as driver: if driver.databases.contains("typedb"): driver.databases.get("typedb").delete() - def test_on_close_callback(self): - with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) as driver: + with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) as driver: driver.databases.create("typedb") database = driver.databases.get("typedb") assert_that(database.name, is_("typedb")) @@ -40,8 +41,10 @@ def test_on_close_callback(self): tx = driver.transaction(database.name, TransactionType.READ) transaction_closed = {"closed": False} + def callback(_error): transaction_closed.update({"closed": True}) + tx.on_close(callback) tx.close() diff --git a/python/tests/integration/test_example.py b/python/tests/integration/test_example.py index 23b62baf91..8185fc5831 100644 --- a/python/tests/integration/test_example.py +++ b/python/tests/integration/test_example.py @@ -27,7 +27,8 @@ class TestExample(TestCase): # EXAMPLE END MARKER def setUp(self): - with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) as driver: + with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) as driver: if driver.databases.contains("typedb"): driver.databases.get("typedb").delete() @@ -36,7 +37,8 @@ def setUp(self): def test_example(self): # Open a driver connection. Specify your parameters if needed # The connection will be automatically closed on the "with" block exit - with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) as driver: + with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) as driver: # Create a database driver.databases.create("typedb") database = driver.databases.get("typedb") diff --git a/python/tests/integration/test_values.py b/python/tests/integration/test_values.py index f296c4b0cd..13291c8dc0 100644 --- a/python/tests/integration/test_values.py +++ b/python/tests/integration/test_values.py @@ -34,7 +34,8 @@ class TestValues(TestCase): def setUp(self): - with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) as driver: + with TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) as driver: if driver.databases.contains(TYPEDB): driver.databases.get(TYPEDB).delete() driver.databases.create(TYPEDB) @@ -67,7 +68,8 @@ def test_values(self): "expiration": "P1Y10M7DT15H44M5.00394892S" } - with (TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) as driver): + with (TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) as driver): database = driver.databases.get(TYPEDB) with driver.transaction(database.name, SCHEMA) as tx: @@ -184,7 +186,8 @@ def test_datetime(self): Datetime.fromstring("2024-09-21", tz_name="Asia/Calcutta", datetime_fmt="%Y-%m-%d") Datetime.fromstring("21/09/24 18:34", tz_name="Africa/Cairo", datetime_fmt="%d/%m/%y %H:%M") - with (TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) as driver): + with (TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) as driver): database = driver.databases.get(TYPEDB) with driver.transaction(database.name, SCHEMA) as tx: @@ -374,7 +377,8 @@ def test_duration(self): Duration.fromstring("P1Y10M7DT15H44M5.00394892S") Duration.fromstring("P55W") - with (TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), DriverOptions(is_tls_enabled=False)) as driver): + with (TypeDB.driver(TypeDB.DEFAULT_ADDRESS, Credentials("admin", "password"), + DriverOptions(DriverTlsConfig.disabled())) as driver): database = driver.databases.get(TYPEDB) with driver.transaction(database.name, SCHEMA) as tx: diff --git a/python/typedb/analyze/__init__.py b/python/typedb/analyze/__init__.py index a3f5ca10c5..8a4f6a16b7 100644 --- a/python/typedb/analyze/__init__.py +++ b/python/typedb/analyze/__init__.py @@ -17,7 +17,7 @@ from typedb.api.analyze.analyzed_query import * # noqa # pylint: disable=unused-import from typedb.api.analyze.conjunction import * # noqa # pylint: disable=unused-import -from typedb.api.analyze.conjunction_id import * # noqa # pylint: disable=unused-import +from typedb.api.analyze.conjunction_id import * # noqa # pylint: disable=unused-import from typedb.api.analyze.constraint import * # noqa # pylint: disable=unused-import from typedb.api.analyze.constraint_vertex import * # noqa # pylint: disable=unused-import from typedb.api.analyze.fetch import * # noqa # pylint: disable=unused-import @@ -27,4 +27,4 @@ from typedb.api.analyze.pipeline_stage import * # noqa # pylint: disable=unused-import from typedb.api.analyze.reducer import * # noqa # pylint: disable=unused-import from typedb.api.analyze.variable_annotations import * # noqa # pylint: disable=unused-import -from typedb.api.analyze.variable import * # noqa # pylint: disable=unused-import +from typedb.api.analyze.variable import * # noqa # pylint: disable=unused-import diff --git a/python/typedb/analyze/function.py b/python/typedb/analyze/function.py index eb633dc763..87b94c5fc7 100644 --- a/python/typedb/analyze/function.py +++ b/python/typedb/analyze/function.py @@ -156,7 +156,8 @@ def as_stream(self): return self def variables(self) -> Iterator["Variable"]: - return map(_Variable, IteratorWrapper(return_operation_stream_variables(self.native_object), variable_iterator_next)) + return map(_Variable, + IteratorWrapper(return_operation_stream_variables(self.native_object), variable_iterator_next)) class _ReturnOperationSingle(_ReturnOperation, ReturnOperationSingle): @@ -170,7 +171,8 @@ def as_single(self): return self def variables(self) -> Iterator["Variable"]: - return map(_Variable, IteratorWrapper(return_operation_single_variables(self.native_object), variable_iterator_next)) + return map(_Variable, + IteratorWrapper(return_operation_single_variables(self.native_object), variable_iterator_next)) def selector(self) -> str: return return_operation_single_selector(self.native_object) diff --git a/python/typedb/analyze/pipeline.py b/python/typedb/analyze/pipeline.py index 1fdc8531a4..9a695bf5d5 100644 --- a/python/typedb/analyze/pipeline.py +++ b/python/typedb/analyze/pipeline.py @@ -42,6 +42,7 @@ from typedb.api.analyze.pipeline_stage import PipelineStage from typedb.api.analyze.variable import Variable + class _Pipeline(Pipeline, NativeWrapper[NativePipeline]): def __init__(self, pipeline: NativePipeline): @@ -64,4 +65,3 @@ def get_variable_name(self, variable: "Variable") -> Optional[str]: def conjunction(self, conjunction_id: "ConjunctionID") -> Optional["Conjunction"]: native_conj = pipeline_get_conjunction(self.native_object, conjunction_id.native_object) return None if native_conj is None else _Conjunction(native_conj) - diff --git a/python/typedb/analyze/pipeline_stage.py b/python/typedb/analyze/pipeline_stage.py index 5ec5e07fac..3b109da0f8 100644 --- a/python/typedb/analyze/pipeline_stage.py +++ b/python/typedb/analyze/pipeline_stage.py @@ -190,6 +190,7 @@ def as_reduce(self): def __repr__(self): return pipeline_stage_string_repr(self.native_object) + class _MatchStage(MatchStage, _PipelineStage): def __init__(self, native): super().__init__(native) diff --git a/python/typedb/api/analyze/constraint.py b/python/typedb/api/analyze/constraint.py index 670cb115ae..734917e8b6 100644 --- a/python/typedb/api/analyze/constraint.py +++ b/python/typedb/api/analyze/constraint.py @@ -26,6 +26,7 @@ from typedb.common.enums import Comparator, ConstraintExactness import typedb + class Constraint(ABC): """ A representation of a TypeQL constraint. diff --git a/python/typedb/api/analyze/named_role.py b/python/typedb/api/analyze/named_role.py index 789e081fbd..7a17b77b46 100644 --- a/python/typedb/api/analyze/named_role.py +++ b/python/typedb/api/analyze/named_role.py @@ -31,6 +31,7 @@ class NamedRole(ABC): (Different role-types belonging to different relation types may share the same name) an internal variable is introduced to handle the ambiguity """ + @abstractmethod def variable(self) -> "Variable": """ diff --git a/python/typedb/api/answer/concept_document_iterator.py b/python/typedb/api/answer/concept_document_iterator.py index 61a40e6a04..f52e251c2f 100644 --- a/python/typedb/api/answer/concept_document_iterator.py +++ b/python/typedb/api/answer/concept_document_iterator.py @@ -31,8 +31,6 @@ def is_concept_documents(self) -> bool: """ Checks if the query answer is a ``ConceptDocumentIterator``. - :return: - Examples -------- :: @@ -45,8 +43,6 @@ def as_concept_documents(self) -> ConceptDocumentIterator: """ Casts the query answer to ``ConceptDocumentIterator``. - :return: - Examples -------- :: diff --git a/python/typedb/api/answer/concept_row.py b/python/typedb/api/answer/concept_row.py index 3533454f66..d5b2f0c7c2 100644 --- a/python/typedb/api/answer/concept_row.py +++ b/python/typedb/api/answer/concept_row.py @@ -38,8 +38,6 @@ def column_names(self) -> Iterator[str]: Produces an iterator over all column names (variables) in the header of this ``ConceptRow``. Shared between all the rows in a QueryAnswer. - :return: - Examples -------- :: @@ -55,8 +53,6 @@ def query_type(self) -> QueryType: Retrieves the executed query's type of this ``ConceptRow``. Shared between all the rows in a QueryAnswer. - :return: - Examples -------- :: @@ -72,8 +68,6 @@ def query_structure(self) -> Optional["Pipeline"]: It must be requested via "include query structure" in ``QueryOptions`` Shared between all the rows in a QueryAnswer. - :return: - Examples -------- :: @@ -89,7 +83,6 @@ def get(self, column_name: str) -> Optional[Concept]: Throws an exception if the variable is not present. :param column_name: The string representation of a variable (column name from ``column_names``) - :return: Examples -------- @@ -106,7 +99,6 @@ def get_index(self, column_index: int) -> Optional[Concept]: an empty answer. Throws an exception if the index is not in the row's range. :param column_index: The column index - :return: Examples -------- @@ -121,8 +113,6 @@ def concepts(self) -> Iterator[Concept]: """ Produces an iterator over all concepts in this `ConceptRow`, skipping empty results. - :return: - Examples -------- :: @@ -136,8 +126,6 @@ def involved_conjunctions(self) -> Optional[Iterator["ConjunctionID"]]: """ Retrieve the ConjunctionIDs of Conjunctions that answered this row. - :return: - Examples -------- :: diff --git a/python/typedb/api/answer/concept_row_iterator.py b/python/typedb/api/answer/concept_row_iterator.py index 2a0a4b4497..1b14825238 100644 --- a/python/typedb/api/answer/concept_row_iterator.py +++ b/python/typedb/api/answer/concept_row_iterator.py @@ -31,8 +31,6 @@ def is_concept_rows(self) -> bool: """ Checks if the query answer is a ``ConceptRowIterator``. - :return: - Examples -------- :: @@ -45,8 +43,6 @@ def as_concept_rows(self) -> ConceptRowIterator: """ Casts the query answer to ``ConceptRowIterator``. - :return: - Examples -------- :: diff --git a/python/typedb/api/answer/ok_query_answer.py b/python/typedb/api/answer/ok_query_answer.py index d625848eaf..a05e954264 100644 --- a/python/typedb/api/answer/ok_query_answer.py +++ b/python/typedb/api/answer/ok_query_answer.py @@ -31,8 +31,6 @@ def is_ok(self) -> bool: """ Checks if the query answer is an ``Ok``. - :return: - Examples -------- :: @@ -45,8 +43,6 @@ def as_ok(self) -> OkQueryAnswer: """ Casts the query answer to ``OkQueryAnswer``. - :return: - Examples -------- :: diff --git a/python/typedb/api/answer/query_answer.py b/python/typedb/api/answer/query_answer.py index 472a80ec6f..877ebd9778 100644 --- a/python/typedb/api/answer/query_answer.py +++ b/python/typedb/api/answer/query_answer.py @@ -37,8 +37,6 @@ def query_type(self) -> QueryType: """ Retrieves the executed query's type of this ``QueryAnswer``. - :return: - Examples -------- :: @@ -51,8 +49,6 @@ def is_ok(self) -> bool: """ Checks if the query answer is an ``Ok``. - :return: - Examples -------- :: @@ -65,8 +61,6 @@ def is_concept_rows(self) -> bool: """ Checks if the query answer is a ``ConceptRowIterator``. - :return: - Examples -------- :: @@ -79,8 +73,6 @@ def is_concept_documents(self) -> bool: """ Checks if the query answer is a ``ConceptDocumentIterator``. - :return: - Examples -------- :: @@ -93,8 +85,6 @@ def as_ok(self) -> OkQueryAnswer: """ Casts the query answer to ``OkQueryAnswer``. - :return: - Examples -------- :: @@ -107,8 +97,6 @@ def as_concept_rows(self) -> ConceptRowIterator: """ Casts the query answer to ``ConceptRowIterator``. - :return: - Examples -------- :: @@ -121,8 +109,6 @@ def as_concept_documents(self) -> ConceptDocumentIterator: """ Casts the query answer to ``ConceptDocumentIterator``. - :return: - Examples -------- :: diff --git a/python/typedb/api/concept/concept.py b/python/typedb/api/concept/concept.py index a4c568c304..084b33c1b5 100644 --- a/python/typedb/api/concept/concept.py +++ b/python/typedb/api/concept/concept.py @@ -47,8 +47,6 @@ def is_type(self) -> bool: """ Checks if the concept is a ``Type``. - :return: - Examples -------- :: @@ -61,8 +59,6 @@ def is_entity_type(self) -> bool: """ Checks if the concept is an ``EntityType``. - :return: - Examples -------- :: @@ -75,8 +71,6 @@ def is_attribute_type(self) -> bool: """ Checks if the concept is an ``AttributeType``. - :return: - Examples -------- :: @@ -89,8 +83,6 @@ def is_relation_type(self) -> bool: """ Checks if the concept is a ``RelationType``. - :return: - Examples -------- :: @@ -103,8 +95,6 @@ def is_role_type(self) -> bool: """ Checks if the concept is a ``RoleType``. - :return: - Examples -------- :: @@ -117,8 +107,6 @@ def is_instance(self) -> bool: """ Checks if the concept is a ``Instance``. - :return: - Examples -------- :: @@ -131,8 +119,6 @@ def is_entity(self) -> bool: """ Checks if the concept is an ``Entity``. - :return: - Examples -------- :: @@ -145,8 +131,6 @@ def is_attribute(self) -> bool: """ Checks if the concept is an ``Attribute``. - :return: - Examples -------- :: @@ -159,8 +143,6 @@ def is_relation(self) -> bool: """ Checks if the concept is a ``Relation``. - :return: - Examples -------- :: @@ -173,8 +155,6 @@ def is_value(self) -> bool: """ Checks if the concept is a ``Value``. - :return: - Examples -------- :: @@ -187,8 +167,6 @@ def as_type(self) -> Type: """ Casts the concept to ``Type``. - :return: - Examples -------- :: @@ -201,8 +179,6 @@ def as_entity_type(self) -> EntityType: """ Casts the concept to ``EntityType``. - :return: - Examples -------- :: @@ -215,8 +191,6 @@ def as_attribute_type(self) -> AttributeType: """ Casts the concept to ``AttributeType``. - :return: - Examples -------- :: @@ -229,8 +203,6 @@ def as_relation_type(self) -> RelationType: """ Casts the concept to ``RelationType``. - :return: - Examples -------- :: @@ -243,8 +215,6 @@ def as_role_type(self) -> RoleType: """ Casts the concept to ``RoleType``. - :return: - Examples -------- :: @@ -257,8 +227,6 @@ def as_instance(self) -> Instance: """ Casts the concept to ``Instance``. - :return: - Examples -------- :: @@ -271,8 +239,6 @@ def as_entity(self) -> Entity: """ Casts the concept to ``Entity``. - :return: - Examples -------- :: @@ -285,8 +251,6 @@ def as_attribute(self) -> Attribute: """ Casts the concept to ``Attribute``. - :return: - Examples -------- :: @@ -299,8 +263,6 @@ def as_relation(self) -> Relation: """ Casts the concept to ``Relation``. - :return: - Examples -------- :: @@ -313,8 +275,6 @@ def as_value(self) -> Value: """ Casts the concept to ``Value``. - :return: - Examples -------- :: @@ -330,8 +290,6 @@ def is_boolean(self) -> bool: or if this ``Concept`` is an ``AttributeType`` of type ``boolean``. Otherwise, returns ``False``. - :return: - Examples -------- :: @@ -347,8 +305,6 @@ def is_integer(self) -> bool: or if this ``Concept`` is an ``AttributeType`` of type ``integer``. Otherwise, returns ``False``. - :return: - Examples -------- :: @@ -364,8 +320,6 @@ def is_double(self) -> bool: or if this ``Concept`` is an ``AttributeType`` of type ``double``. Otherwise, returns ``False``. - :return: - Examples -------- :: @@ -381,8 +335,6 @@ def is_decimal(self) -> bool: or if this ``Concept`` is an ``AttributeType`` of type ``decimal``. Otherwise, returns ``False``. - :return: - Examples -------- :: @@ -398,8 +350,6 @@ def is_string(self) -> bool: or if this ``Concept`` is an ``AttributeType`` of type ``string``. Otherwise, returns ``False``. - :return: - Examples -------- :: @@ -415,8 +365,6 @@ def is_date(self) -> bool: or if this ``Concept`` is an ``AttributeType`` of type ``date``. Otherwise, returns ``False``. - :return: - Examples -------- :: @@ -432,8 +380,6 @@ def is_datetime(self) -> bool: or if this ``Concept`` is an ``AttributeType`` of type ``datetime``. Otherwise, returns ``False``. - :return: - Examples -------- :: @@ -449,8 +395,6 @@ def is_datetime_tz(self) -> bool: or if this ``Concept`` is an ``AttributeType`` of type ``datetime-tz``. Otherwise, returns ``False``. - :return: - Examples -------- :: @@ -466,8 +410,6 @@ def is_duration(self) -> bool: or if this ``Concept`` is an ``AttributeType`` of type ``duration``. Otherwise, returns ``False``. - :return: - Examples -------- :: @@ -483,8 +425,6 @@ def is_struct(self) -> bool: or if this ``Concept`` is an ``AttributeType`` of type ``struct``. Otherwise, returns ``False``. - :return: - Examples -------- :: @@ -501,8 +441,6 @@ def try_get_boolean(self) -> Optional[bool]: Returns a ``boolean`` value of this ``Concept``. If it's not a ``Value`` or it has another type, raises an exception. - :return: - Examples -------- :: @@ -517,8 +455,6 @@ def try_get_integer(self) -> Optional[int]: Returns a ``integer`` value of this ``Concept``. If it's not a ``Value`` or it has another type, raises an exception. - :return: - Examples -------- :: @@ -533,8 +469,6 @@ def try_get_double(self) -> Optional[float]: Returns a ``double`` value of this ``Concept``. If it's not a ``Value`` or it has another type, raises an exception. - :return: - Examples -------- :: @@ -549,8 +483,6 @@ def try_get_decimal(self) -> Optional[Decimal]: Returns a ``decimal`` value of this ``Concept``. If it's not a ``Value`` or it has another type, raises an exception. - :return: - Examples -------- :: @@ -565,8 +497,6 @@ def try_get_string(self) -> Optional[str]: Returns a ``string`` value of this ``Concept``. If it's not a ``Value`` or it has another type, raises an exception. - :return: - Examples -------- :: @@ -581,8 +511,6 @@ def try_get_date(self) -> Optional[date]: Returns a timezone naive ``date`` value of this ``Concept``. If it's not a ``Value`` or it has another type, raises an exception. - :return: - Examples -------- :: @@ -597,8 +525,6 @@ def try_get_datetime(self) -> Optional[Datetime]: Returns a timezone naive ``datetime`` value of this ``Concept``. If it's not a ``Value`` or it has another type, raises an exception. - :return: - Examples -------- :: @@ -613,8 +539,6 @@ def try_get_datetime_tz(self) -> Optional[Datetime]: Returns a timezone naive ``datetime_tz`` value of this ``Concept``. If it's not a ``Value`` or it has another type, raises an exception. - :return: - Examples -------- :: @@ -629,8 +553,6 @@ def try_get_duration(self) -> Optional[Duration]: Returns a timezone naive ``duration`` value of this ``Concept``. If it's not a ``Value`` or it has another type, raises an exception. - :return: - Examples -------- :: @@ -645,8 +567,6 @@ def try_get_struct(self) -> Optional[STRUCT]: Returns a ``struct`` value of this ``Concept`` represented as a map from field names to values. If it's not a ``Value`` or it has another type, raises an exception. - :return: - Examples -------- :: @@ -663,8 +583,6 @@ def get_label(self) -> str: If this is a ``Value``, return the label of the value type of the value. If this is a ``Type``, return the label of the type. - :return: - Examples -------- :: @@ -682,8 +600,6 @@ def try_get_label(self) -> Optional[str]: If this is a ``Value``, return the label of the value type of the value. If this is a ``Type``, return the label of the type. - :return: - Examples -------- :: @@ -697,8 +613,6 @@ def try_get_iid(self) -> Optional[str]: """ Retrieves the unique id of the ``Concept``. Returns ``None`` if absent. - :return: - Examples -------- :: @@ -712,8 +626,6 @@ def try_get_value_type(self) -> Optional[str]: """ Retrieves the ``str` describing the value type fo this ``Concept``. Returns ``None`` if absent. - :return: - Examples -------- :: @@ -727,8 +639,6 @@ def try_get_value(self) -> Optional[VALUE]: """ Retrieves the value which this ``Concept`` holds. Returns ``None`` if this ``Concept`` does not hold any value. - :return: - Examples -------- :: diff --git a/python/typedb/api/concept/instance/attribute.py b/python/typedb/api/concept/instance/attribute.py index de33bbb7d2..46c0f4b02e 100644 --- a/python/typedb/api/concept/instance/attribute.py +++ b/python/typedb/api/concept/instance/attribute.py @@ -45,8 +45,6 @@ def get_type(self) -> AttributeType: """ Retrieves the type which this ``Attribute`` belongs to. - :return: - Examples -------- :: @@ -60,8 +58,6 @@ def get_value(self) -> Concept.VALUE: """ Retrieves the value which the ``Attribute`` instance holds. - :return: - Examples -------- :: @@ -75,8 +71,6 @@ def get_value_type(self) -> str: """ Retrieves the description of the value type of the value which the ``Attribute`` instance holds. - :return: - Examples -------- :: @@ -91,8 +85,6 @@ def get_boolean(self) -> bool: Returns a ``boolean`` value of the value concept that this attribute holds. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -107,8 +99,6 @@ def get_integer(self) -> int: Returns a ``integer`` value of the value concept that this attribute holds. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -123,8 +113,6 @@ def get_double(self) -> float: Returns a ``double`` value of the value concept that this attribute holds. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -139,8 +127,6 @@ def get_decimal(self) -> Decimal: Returns a ``decimal`` value of the value concept that this attribute holds. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -155,8 +141,6 @@ def get_string(self) -> str: Returns a ``string`` value of the value concept that this attribute holds. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -171,8 +155,6 @@ def get_date(self) -> date: Returns a timezone naive ``date`` value of the value concept that this attribute holds. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -187,8 +169,6 @@ def get_datetime(self) -> Datetime: Returns a timezone naive ``datetime`` value of the value concept that this attribute holds. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -203,8 +183,6 @@ def get_datetime_tz(self) -> Datetime: Returns a timezone naive ``datetime_tz`` value of the value concept that this attribute holds. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -219,8 +197,6 @@ def get_duration(self) -> Duration: Returns a timezone naive ``duration`` value of the value concept that this attribute holds. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -235,8 +211,6 @@ def get_struct(self) -> Concept.STRUCT: Returns a ``struct`` value of the value concept that this attribute holds represented as a map from field names to values. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -249,8 +223,6 @@ def is_attribute(self) -> bool: """ Checks if the concept is an ``Attribute``. - :return: - Examples -------- :: @@ -263,8 +235,6 @@ def as_attribute(self) -> Attribute: """ Casts the concept to ``Attribute``. - :return: - Examples -------- :: diff --git a/python/typedb/api/concept/instance/entity.py b/python/typedb/api/concept/instance/entity.py index 52deb450af..bc42bfe32f 100644 --- a/python/typedb/api/concept/instance/entity.py +++ b/python/typedb/api/concept/instance/entity.py @@ -39,8 +39,6 @@ def is_entity(self) -> bool: """ Checks if the concept is an ``Entity``. - :return: - Examples -------- :: @@ -53,8 +51,6 @@ def as_entity(self) -> Entity: """ Casts the concept to ``Entity``. - :return: - Examples -------- :: @@ -68,8 +64,6 @@ def get_type(self) -> EntityType: """ Retrieves the type which this ``Entity`` belongs to. - :return: - Examples -------- :: @@ -83,8 +77,6 @@ def get_iid(self) -> str: """ Retrieves the unique id of the ``Entity``. - :return: - Examples -------- :: diff --git a/python/typedb/api/concept/instance/instance.py b/python/typedb/api/concept/instance/instance.py index 0ffb1dfc2d..4e96b00b3a 100644 --- a/python/typedb/api/concept/instance/instance.py +++ b/python/typedb/api/concept/instance/instance.py @@ -33,8 +33,6 @@ def get_type(self) -> Type: """ Retrieves the type which this ``Instance`` belongs to. - :return: - Examples -------- :: @@ -47,8 +45,6 @@ def is_instance(self) -> bool: """ Checks if the concept is a ``Instance``. - :return: - Examples -------- :: @@ -61,8 +57,6 @@ def as_instance(self) -> Instance: """ Casts the concept to ``Instance``. - :return: - Examples -------- :: diff --git a/python/typedb/api/concept/instance/relation.py b/python/typedb/api/concept/instance/relation.py index 547e78860b..48ef5eebbf 100644 --- a/python/typedb/api/concept/instance/relation.py +++ b/python/typedb/api/concept/instance/relation.py @@ -36,8 +36,6 @@ def is_relation(self) -> bool: """ Checks if the concept is a ``Relation``. - :return: - Examples -------- :: @@ -50,8 +48,6 @@ def as_relation(self) -> Relation: """ Casts the concept to ``Relation``. - :return: - Examples -------- :: @@ -65,8 +61,6 @@ def get_type(self) -> RelationType: """ Retrieves the type which this ``Relation`` belongs to. - :return: - Examples -------- :: @@ -80,8 +74,6 @@ def get_iid(self) -> str: """ Retrieves the unique id of the ``Relation``. - :return: - Examples -------- :: diff --git a/python/typedb/api/concept/type/attribute_type.py b/python/typedb/api/concept/type/attribute_type.py index 7eead4ee8c..7568dd38e8 100644 --- a/python/typedb/api/concept/type/attribute_type.py +++ b/python/typedb/api/concept/type/attribute_type.py @@ -43,8 +43,6 @@ def as_attribute_type(self) -> AttributeType: """ Casts the concept to ``AttributeType``. - :return: - Examples -------- :: @@ -57,8 +55,6 @@ def is_attribute_type(self) -> bool: """ Checks if the concept is an ``AttributeType``. - :return: - Examples -------- :: diff --git a/python/typedb/api/concept/type/entity_type.py b/python/typedb/api/concept/type/entity_type.py index 0127b6f917..d0c11ccbc8 100644 --- a/python/typedb/api/concept/type/entity_type.py +++ b/python/typedb/api/concept/type/entity_type.py @@ -36,8 +36,6 @@ def is_entity_type(self) -> bool: """ Checks if the concept is an ``EntityType``. - :return: - Examples -------- :: @@ -50,8 +48,6 @@ def as_entity_type(self) -> EntityType: """ Casts the concept to ``EntityType``. - :return: - Examples -------- :: diff --git a/python/typedb/api/concept/type/relation_type.py b/python/typedb/api/concept/type/relation_type.py index 393e7b95a9..8a7d29560a 100644 --- a/python/typedb/api/concept/type/relation_type.py +++ b/python/typedb/api/concept/type/relation_type.py @@ -40,8 +40,6 @@ def is_relation_type(self) -> bool: """ Checks if the concept is a ``RelationType``. - :return: - Examples -------- :: @@ -54,8 +52,6 @@ def as_relation_type(self) -> RelationType: """ Casts the concept to ``RelationType``. - :return: - Examples -------- :: diff --git a/python/typedb/api/concept/type/role_type.py b/python/typedb/api/concept/type/role_type.py index 0c568e9e58..01db992e11 100644 --- a/python/typedb/api/concept/type/role_type.py +++ b/python/typedb/api/concept/type/role_type.py @@ -41,8 +41,6 @@ def is_role_type(self) -> bool: """ Checks if the concept is a ``RoleType``. - :return: - Examples -------- :: @@ -55,8 +53,6 @@ def as_role_type(self) -> RoleType: """ Casts the concept to ``RoleType``. - :return: - Examples -------- :: diff --git a/python/typedb/api/concept/type/type.py b/python/typedb/api/concept/type/type.py index a39d81cade..4c4cb720ca 100644 --- a/python/typedb/api/concept/type/type.py +++ b/python/typedb/api/concept/type/type.py @@ -28,8 +28,6 @@ def is_type(self) -> bool: """ Checks if the concept is a ``Type``. - :return: - Examples -------- :: diff --git a/python/typedb/api/concept/value/value.py b/python/typedb/api/concept/value/value.py index 6b8b8911e5..a96b0f0234 100644 --- a/python/typedb/api/concept/value/value.py +++ b/python/typedb/api/concept/value/value.py @@ -32,8 +32,6 @@ def get_type(self) -> str: """ Retrieves the ``str`` describing the value type of this ``Value`` concept. - :return: - Examples -------- :: @@ -47,8 +45,6 @@ def get(self) -> Concept.VALUE: """ Retrieves the value which this value concept holds. - :return: - Examples -------- :: @@ -61,8 +57,6 @@ def is_value(self) -> bool: """ Checks if the concept is a ``Value``. - :return: - Examples -------- :: @@ -75,8 +69,6 @@ def as_value(self) -> Value: """ Casts the concept to ``Value``. - :return: - Examples -------- :: @@ -91,8 +83,6 @@ def get_boolean(self) -> bool: Returns a ``boolean`` value of this value concept. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -107,8 +97,6 @@ def get_integer(self) -> int: Returns a ``integer`` value of this value concept. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -123,8 +111,6 @@ def get_double(self) -> float: Returns a ``double`` value of this value concept. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -139,8 +125,6 @@ def get_decimal(self) -> Decimal: Returns a ``decimal`` value of this value concept. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -155,8 +139,6 @@ def get_string(self) -> str: Returns a ``string`` value of this value concept. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -171,8 +153,6 @@ def get_date(self) -> date: Returns a timezone naive ``date`` value of this value concept. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -187,8 +167,6 @@ def get_datetime(self) -> Datetime: Returns a timezone naive ``datetime`` value of this value concept. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -203,8 +181,6 @@ def get_datetime_tz(self) -> Datetime: Returns a timezone naive ``datetime_tz`` value of this value concept. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -219,8 +195,6 @@ def get_duration(self) -> Duration: Returns a timezone naive ``duration`` value of this value concept. If the value has another type, raises an exception. - :return: - Examples -------- :: @@ -235,8 +209,6 @@ def get_struct(self) -> Concept.STRUCT: Returns a ``struct`` value of this value concept represented as a map from field names to values. If the value has another type, raises an exception. - :return: - Examples -------- :: diff --git a/python/typedb/api/connection/consistency_level.py b/python/typedb/api/connection/consistency_level.py new file mode 100644 index 0000000000..9fe5d2e108 --- /dev/null +++ b/python/typedb/api/connection/consistency_level.py @@ -0,0 +1,129 @@ +# 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. + +from abc import ABC +from typing import Optional, Union + +from typedb.common.exception import TypeDBDriverException, UNEXPECTED_NATIVE_VALUE, ILLEGAL_STATE +from typedb.common.native_wrapper import NativeWrapper +from typedb.native_driver_wrapper import consistency_level_strong, consistency_level_eventual, \ + consistency_level_replica_dependent, ConsistencyLevel as NativeConsistencyLevel, \ + Strong as NativeStrong, Eventual as NativeEventual, ReplicaDependent as NativeReplicaDependent + + +class ConsistencyLevel(NativeWrapper[NativeConsistencyLevel], ABC): + """ + Consistency levels of operations against a distributed server. All driver methods have default + recommended values, however, most of the operations can be configured in order to potentially + speed up the execution (introducing risks of stale data) or test a specific replica. + This setting does not affect clusters with a single node. + """ + + @staticmethod + def of(native_value: NativeConsistencyLevel) -> Union[None, "Strong", "Eventual", "ReplicaDependent"]: + if native_value is None: + return None + + if native_value.tag == NativeStrong: + return Strong() + elif native_value.tag == NativeEventual: + return Eventual() + elif native_value.tag == NativeReplicaDependent: + return ReplicaDependent(native_value.address) + else: + raise TypeDBDriverException(UNEXPECTED_NATIVE_VALUE) + + @staticmethod + def native_value(consistency_level: Optional["ConsistencyLevel"]) -> NativeConsistencyLevel: + return None if consistency_level is None else consistency_level.native_object + + def is_strong(self) -> bool: + return isinstance(self, Strong) + + def is_eventual(self) -> bool: + return isinstance(self, Eventual) + + def is_replica_dependent(self) -> bool: + return isinstance(self, ReplicaDependent) + + +class Strong(ConsistencyLevel): + """ + Strong consistency level. + Strongest consistency, always up-to-date due to the guarantee of the primary replica usage. + May require more time for operation execution. + """ + + def __init__(self): + super().__init__(consistency_level_strong()) + + @property + def _native_object_not_owned_exception(self) -> TypeDBDriverException: + return TypeDBDriverException(ILLEGAL_STATE) + + def __str__(self): + return "Strong" + + +class Eventual(ConsistencyLevel): + """ + Eventual consistency level. + Allow stale reads from any replica and execution orchestration through a non-primary replica. + Does not guarantee latest writes, but is eventually faster compared to other consistency levels. + Note that the target replica can redirect the request, if needed. + """ + + def __init__(self): + super().__init__(consistency_level_eventual()) + + @property + def _native_object_not_owned_exception(self) -> TypeDBDriverException: + return TypeDBDriverException(ILLEGAL_STATE) + + def __str__(self): + return "Eventual" + + +class ReplicaDependent(ConsistencyLevel): + """ + Replica dependent consistency level. + The operation is executed against the provided replica address only. Its guarantees depend + on the replica selected. Note that the target replica can redirect the request, if needed. + """ + + def __init__(self, address: str): + super().__init__(consistency_level_replica_dependent(address)) + self._address = address + + @property + def _native_object_not_owned_exception(self) -> TypeDBDriverException: + return TypeDBDriverException(ILLEGAL_STATE) + + @property + def address(self) -> str: + """ + Retrieves the address of the replica this consistency level depends on. + """ + return self._address + + def __str__(self): + return f"ReplicaDependent({self._address})" + + +ConsistencyLevel.Strong = Strong +ConsistencyLevel.Eventual = Eventual +ConsistencyLevel.ReplicaDependent = ReplicaDependent diff --git a/python/typedb/api/connection/database.py b/python/typedb/api/connection/database.py deleted file mode 100644 index 4172aeb376..0000000000 --- a/python/typedb/api/connection/database.py +++ /dev/null @@ -1,286 +0,0 @@ -# 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. - -from __future__ import annotations - -from abc import ABC, abstractmethod -from typing import List - - -class Database(ABC): - - @property - @abstractmethod - def name(self) -> str: - """ - The database name as a string. - """ - pass - - @abstractmethod - def schema(self) -> str: - """ - Returns a full schema text as a valid TypeQL define query string. - - :return: - - Examples: - --------- - :: - - database.schema() - """ - pass - - @abstractmethod - def type_schema(self) -> str: - """ - Returns the types in the schema as a valid TypeQL define query string. - - :return: - - Examples: - --------- - :: - - database.type_schema() - """ - pass - - def export_to_file(self, schema_file_path: str, data_file_path: str) -> None: - """ - Export a database into a schema definition and a data files saved to the disk. - This is a blocking operation and may take a significant amount of time depending on the database size. - - :param schema_file_path: The path to the schema definition file to be created - :param data_file_path: The path to the data file to be created - :return: - - Examples: - --------- - :: - - database.export_to_file("schema.typeql", "data.typedb") - """ - pass - - @abstractmethod - def delete(self) -> None: - """ - Deletes this database. - - :return: - - Examples: - --------- - :: - - database.delete() - """ - pass - - # @abstractmethod - # def replicas(self) -> Set[Replica]: - # """ - # Set of ``Replica`` instances for this database. - # *Only works in TypeDB Cloud* - # - # :return: - # - # Examples: - # --------- - # :: - # - # database.replicas() - # """ - # pass - # - # @abstractmethod - # def primary_replica(self) -> Optional[Replica]: - # """ - # Returns the primary replica for this database. - # *Only works in TypeDB Cloud* - # - # :return: - # - # Examples: - # --------- - # :: - # - # database.primary_replica() - # """ - # pass - # - # @abstractmethod - # def preferred_replica(self) -> Optional[Replica]: - # """ - # Returns the preferred replica for this database. - # Operations which can be run on any replica will prefer to use this replica. - # *Only works in TypeDB Cloud* - # - # :return: - # - # Examples: - # --------- - # :: - # - # database.preferred_replica() - # """ - # pass - - -# -# -# class Replica(ABC): -# """ -# The metadata and state of an individual raft replica of a database. -# """ -# -# @abstractmethod -# def database(self) -> Database: -# """ -# Retrieves the database for which this is a replica -# -# :return: -# """ -# pass -# -# @abstractmethod -# def server(self) -> str: -# """ -# The server hosting this replica -# -# :return: -# """ -# pass -# -# @abstractmethod -# def is_primary(self) -> bool: -# """ -# Checks whether this is the primary replica of the raft cluster. -# -# :return: -# """ -# -# pass -# -# @abstractmethod -# def is_preferred(self) -> bool: -# """ -# Checks whether this is the preferred replica of the raft cluster. -# If true, Operations which can be run on any replica will prefer to use this replica. -# -# :return: -# """ -# pass -# -# @abstractmethod -# def term(self) -> int: -# """ -# The raft protocol 'term' of this replica. -# -# :return: -# """ -# pass - - -class DatabaseManager(ABC): - """ - Provides access to all database management methods. - """ - - @abstractmethod - def get(self, name: str) -> Database: - """ - Retrieve the database with the given name. - - :param name: The name of the database to retrieve - :return: - - Examples: - --------- - :: - - driver.databases.get(name) - """ - pass - - @abstractmethod - def contains(self, name: str) -> bool: - """ - Checks if a database with the given name exists. - - :param name: The database name to be checked - :return: - - Examples: - --------- - :: - - driver.databases.contains(name) - """ - pass - - @abstractmethod - def create(self, name: str) -> None: - """ - Create a database with the given name. - - :param name: The name of the database to be created - :return: - - Examples: - --------- - :: - - driver.databases.create(name) - """ - pass - - @abstractmethod - def import_from_file(self, name: str, schema: str, data_file_path: str) -> None: - """ - Create a database with the given name based on previously exported another database's data loaded from a file. - This is a blocking operation and may take a significant amount of time depending on the database size. - - :param name: The name of the database to be created - :param schema: The schema definition query string for the database - :param data_file_path: The exported database file path to import the data from - :return: - - Examples: - --------- - :: - - driver.databases.import_from_file(name, schema, "data.typedb") - """ - pass - - @abstractmethod - def all(self) -> List[Database]: - """ - Retrieves all databases present on the TypeDB server. - - :return: - - Examples: - --------- - :: - - driver.databases.all() - """ - pass diff --git a/python/typedb/api/connection/driver.py b/python/typedb/api/connection/driver.py index 34891d1173..a4d89af6d5 100644 --- a/python/typedb/api/connection/driver.py +++ b/python/typedb/api/connection/driver.py @@ -18,13 +18,16 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, Set, Mapping if TYPE_CHECKING: - from typedb.api.connection.database import DatabaseManager + from typedb.api.connection.consistency_level import ConsistencyLevel + from typedb.api.database.database_manager import DatabaseManager from typedb.api.connection.transaction_options import TransactionOptions from typedb.api.connection.transaction import Transaction, TransactionType - from typedb.api.user.user import UserManager + from typedb.api.user.user_manager import UserManager + from typedb.api.server.server_replica import ServerReplica + from typedb.api.server.server_version import ServerVersion class Driver(ABC): @@ -35,8 +38,6 @@ def is_open(self) -> bool: """ Checks whether this connection is presently open. - :return: - Examples: --------- :: @@ -53,6 +54,30 @@ def databases(self) -> DatabaseManager: """ pass + @property + @abstractmethod + def users(self) -> UserManager: + """ + The ``UserManager`` for this connection, providing access to user management methods. + """ + pass + + @abstractmethod + def server_version(self, consistency_level: Optional[ConsistencyLevel] = None) -> ServerVersion: + """ + Retrieves the server's version. + + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + driver.server_version() + driver.server_version(ConsistencyLevel.Strong()) + """ + pass + @abstractmethod def transaction(self, database_name: str, transaction_type: TransactionType, options: Optional[TransactionOptions] = None) -> Transaction: @@ -62,7 +87,6 @@ def transaction(self, database_name: str, transaction_type: TransactionType, :param database_name: The name of the database with which the transaction connects :param transaction_type: The type of transaction to be created (READ, WRITE, or SCHEMA) :param options: ``TransactionOptions`` to configure the opened transaction - :return: Examples: --------- @@ -73,26 +97,99 @@ def transaction(self, database_name: str, transaction_type: TransactionType, pass @abstractmethod - def close(self) -> None: + def replicas(self, consistency_level: Optional[ConsistencyLevel] = None) -> Set[ServerReplica]: """ - Closes the driver. Before instantiating a new driver, the driver that’s currently open should first be closed. + Set of ``Replica`` instances for this driver connection. - :return: + :param consistency_level: The consistency level to use for the operation. Strongest possible by default Examples: --------- :: - driver.close() + driver.replicas() + driver.replicas(ConsistencyLevel.Strong()) """ pass - @property @abstractmethod - def users(self) -> UserManager: + def primary_replica(self, consistency_level: Optional[ConsistencyLevel] = None) -> Optional[ServerReplica]: + """ + Returns the primary replica for this driver connection. + + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + driver.primary_replica() + driver.primary_replica(ConsistencyLevel.Strong()) + """ + pass + + @abstractmethod + def register_replica(self, replica_id: int, address: str) -> None: + """ + Registers a new replica in the cluster the driver is currently connected to. The registered + replica will become available eventually, depending on the behavior of the whole cluster. + To register a replica, its clustering address should be passed, not the connection address. + + :param replica_id: The numeric identifier of the new replica + :param address: The address(es) of the TypeDB replica as a string + + Examples: + --------- + :: + + driver.register_replica(2, "127.0.0.1:11729") + """ + pass + + @abstractmethod + def deregister_replica(self, replica_id: int) -> None: + """ + Deregisters a replica from the cluster the driver is currently connected to. This replica + will no longer play a raft role in this cluster. + + :param replica_id: The numeric identifier of the deregistered replica + + Examples: + --------- + :: + + driver.deregister_replica(2) + """ + pass + + @abstractmethod + def update_address_translation(self, address_translation: Mapping[str, str]) -> None: """ - The ``UserManager`` instance for this connection, providing access to user management methods. - Only for TypeDB Cloud. + Updates address translation of the driver. This lets you actualize new translation + information without recreating the driver from scratch. Useful after registering new + replicas requiring address translation. + This operation will update existing connections using the provided addresses. + + :param address_translation: The translation of public TypeDB cluster replica addresses (keys) to server-side private addresses (values) + + Examples: + --------- + :: + + driver.update_address_translation({"typedb-cloud.ext:11729": "127.0.0.1:11729"}) + """ + pass + + @abstractmethod + def close(self) -> None: + """ + Closes the driver. Before instantiating a new driver, the driver that’s currently open should first be closed. + + Examples: + --------- + :: + + driver.close() """ pass diff --git a/python/typedb/api/connection/driver_options.py b/python/typedb/api/connection/driver_options.py index bc5f83e864..72318cf233 100644 --- a/python/typedb/api/connection/driver_options.py +++ b/python/typedb/api/connection/driver_options.py @@ -17,27 +17,161 @@ from typing import Optional +from typedb.api.connection.driver_tls_config import DriverTlsConfig from typedb.common.exception import TypeDBDriverException, ILLEGAL_STATE from typedb.common.native_wrapper import NativeWrapper -from typedb.native_driver_wrapper import driver_options_new, DriverOptions as NativeDriverOptions +from typedb.common.validation import require_non_negative, require_non_null +from typedb.native_driver_wrapper import driver_options_get_tls_config, driver_options_new, \ + driver_options_set_tls_config, \ + driver_options_get_use_replication, driver_options_set_use_replication, driver_options_get_primary_failover_retries, \ + driver_options_set_primary_failover_retries, driver_options_get_replica_discovery_attempts, \ + driver_options_set_replica_discovery_attempts, driver_options_has_replica_discovery_attempts, \ + driver_options_get_request_timeout_millis, driver_options_set_request_timeout_millis, \ + DriverOptions as NativeDriverOptions class DriverOptions(NativeWrapper[NativeDriverOptions]): """ - User credentials and TLS encryption settings for connecting to TypeDB Server. Arguments: - 1) is_tls_enabled: Specify whether the connection to TypeDB must be done over TLS. - 2) tls_root_ca_path: Path to the CA certificate to use for authenticating server certificates. + TypeDB driver options. ``DriverOptions`` are used to specify the driver's connection behavior. + + Options could be specified either as constructor arguments or using + properties assignment. Examples: -------- :: - driver_options = DriverOptions(is_tls_enabled=True, tls_root_ca_path="path/to/ca-certificate.pem") + options = DriverOptions(DriverTlsConfig.enabled_with_native_root_ca(), request_timeout_millis=6000) + options.request_timeout_millis = 6000 """ - def __init__(self, is_tls_enabled: bool = True, tls_root_ca_path: Optional[str] = None): - super().__init__(driver_options_new(is_tls_enabled, tls_root_ca_path)) + def __init__(self, + tls_config: DriverTlsConfig, + *, + use_replication: Optional[bool] = None, + primary_failover_retries: Optional[int] = None, + replica_discovery_attempts: Optional[int] = None, + request_timeout_millis: Optional[int] = None, + ): + """ + Produces a new ``DriverOptions`` object for connecting to TypeDB Server using custom TLS settings. + WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + + Examples + -------- + :: + + options = DriverOptions(DriverTlsConfig.enabled_with_native_root_ca()) + """ + require_non_null(tls_config, "tls_config") + super().__init__(driver_options_new(tls_config.native_object)) + if use_replication is not None: + self.use_replication = use_replication + if primary_failover_retries is not None: + self.primary_failover_retries = primary_failover_retries + if replica_discovery_attempts is not None: + self.replica_discovery_attempts = replica_discovery_attempts + if request_timeout_millis is not None: + self.request_timeout_millis = request_timeout_millis @property def _native_object_not_owned_exception(self) -> TypeDBDriverException: return TypeDBDriverException(ILLEGAL_STATE) + + @property + def tls_config(self) -> DriverTlsConfig: + """ + Returns the TLS configuration associated with this ``DriverOptions``. + Specifies the TLS configuration of the connection to TypeDB. + + Examples + -------- + :: + + options.tls_config + """ + return DriverTlsConfig(driver_options_get_tls_config(self.native_object)) + + @tls_config.setter + def tls_config(self, tls_config: DriverTlsConfig): + """ + Overrides the TLS configuration associated with this ``DriverOptions``. + WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + + Examples + -------- + :: + + options.tls_config = DriverTlsConfig.enabled_with_native_root_ca() + """ + require_non_null(tls_config, "tls_config") + driver_options_set_tls_config(self.native_object, tls_config.native_object) + + @property + def request_timeout_millis(self) -> int: + """ + Returns the request timeout in milliseconds set for this ``DriverOptions`` object. + Specifies the maximum time to wait for a response to a unary RPC request. + This applies to operations like database creation, user management, and initial + transaction opening. It does NOT apply to operations within transactions (queries, commits). + """ + return driver_options_get_request_timeout_millis(self.native_object) + + @request_timeout_millis.setter + def request_timeout_millis(self, request_timeout_millis: int): + """ + Sets the maximum time (in milliseconds) to wait for a response to a unary RPC request. + This applies to operations like database creation, user management, and initial + transaction opening. It does NOT apply to operations within transactions (queries, commits). + Defaults to 2 hours (7200000 milliseconds). + """ + require_non_negative(request_timeout_millis, "request_timeout_millis") + driver_options_set_request_timeout_millis(self.native_object, request_timeout_millis) + + @property + def use_replication(self) -> bool: + """ + Returns the value set for the replication usage flag in this ``DriverOptions`` object. + Specifies whether the connection to TypeDB can use cluster replicas provided by the server + or it should be limited to a single configured address. Defaults to True. + """ + return driver_options_get_use_replication(self.native_object) + + @use_replication.setter + def use_replication(self, use_replication: bool): + driver_options_set_use_replication(self.native_object, use_replication) + + @property + def primary_failover_retries(self) -> int: + """ + Returns the value set for the primary failover retries limit in this ``DriverOptions`` object. + Limits the number of attempts to redirect a strongly consistent request to another + primary replica in case of a failure due to the change of replica roles. Defaults to 1. + """ + return driver_options_get_primary_failover_retries(self.native_object) + + @primary_failover_retries.setter + def primary_failover_retries(self, primary_failover_retries: int): + require_non_negative(primary_failover_retries, "primary_failover_retries") + driver_options_set_primary_failover_retries(self.native_object, primary_failover_retries) + + @property + def replica_discovery_attempts(self) -> Optional[int]: + """ + Returns the value set for the replica discovery attempts limit in this ``DriverOptions`` object. + Limits the number of driver attempts to discover a single working replica to perform an + operation in case of a replica unavailability. Every replica is tested once, which means + that at most: + - {limit} operations are performed if the limit <= the number of replicas. + - {number of replicas} operations are performed if the limit > the number of replicas. + - {number of replicas} operations are performed if the limit is None. + Affects every eventually consistent operation, including redirect failover, when the new + primary replica is unknown. If not set, the maximum (practically unlimited) value is used. + """ + return driver_options_get_replica_discovery_attempts(self.native_object) \ + if driver_options_has_replica_discovery_attempts(self.native_object) else None + + @replica_discovery_attempts.setter + def replica_discovery_attempts(self, replica_discovery_attempts: int): + require_non_negative(replica_discovery_attempts, "replica_discovery_attempts") + driver_options_set_replica_discovery_attempts(self.native_object, replica_discovery_attempts) diff --git a/python/typedb/api/connection/driver_tls_config.py b/python/typedb/api/connection/driver_tls_config.py new file mode 100644 index 0000000000..38d0b18b71 --- /dev/null +++ b/python/typedb/api/connection/driver_tls_config.py @@ -0,0 +1,118 @@ +# 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. + +from typing import Optional + +from typedb.common.exception import TypeDBDriverException, ILLEGAL_STATE +from typedb.common.native_wrapper import NativeWrapper +from typedb.common.validation import require_non_negative, require_non_null +from typedb.native_driver_wrapper import driver_tls_config_new_disabled, \ + driver_tls_config_new_enabled_with_native_root_ca, \ + driver_tls_config_new_enabled_with_root_ca_path, driver_tls_config_is_enabled, driver_tls_config_has_root_ca_path, \ + driver_tls_config_get_root_ca_path, DriverTlsConfig as NativeDriverTlsConfig + + +class DriverTlsConfig(NativeWrapper[NativeDriverTlsConfig]): + """ + TLS configuration for the TypeDB driver. + + ``DriverTlsConfig`` represents a fully constructed and validated TLS configuration. + If TLS is enabled, the underlying TLS config is built eagerly at construction time, + ensuring that no connection attempt can observe a partially-configured TLS state. + + The driver defaults to using TLS with **native system trust roots**. + This matches typical system and container deployments while still allowing + explicit opt-out or custom PKI configuration. + """ + + def __init__(self, native_object: NativeDriverTlsConfig): + super().__init__(native_object) + + @property + def _native_object_not_owned_exception(self) -> TypeDBDriverException: + return TypeDBDriverException(ILLEGAL_STATE) + + @staticmethod + def disabled() -> "DriverTlsConfig": + """ + Creates a TLS configuration with TLS disabled. + WARNING: Disabling TLS causes credentials and data to be transmitted in plaintext. + + Examples + -------- + :: + + tls_config = DriverTlsConfig.disabled() + """ + return DriverTlsConfig(driver_tls_config_new_disabled()) + + @staticmethod + def enabled_with_native_root_ca() -> "DriverTlsConfig": + """ + Creates a TLS configuration enabled with system native trust roots. + + Examples + -------- + :: + + tls_config = DriverTlsConfig.enabled_with_native_root_ca() + """ + return DriverTlsConfig(driver_tls_config_new_enabled_with_native_root_ca()) + + @staticmethod + def enabled_with_root_ca(tls_root_ca_path: str) -> "DriverTlsConfig": + """ + Creates a TLS configuration enabled with a custom root CA certificate bundle (PEM). + + :param tls_root_ca_path: the path to PEM-encoded root CA certificate bundle + + Examples + -------- + :: + + tls_config = DriverTlsConfig.enabled_with_root_ca("path/to/ca-certificate.pem") + """ + require_non_null(tls_root_ca_path, "tls_root_ca_path") + return DriverTlsConfig(driver_tls_config_new_enabled_with_root_ca_path(tls_root_ca_path)) + + @property + def is_enabled(self) -> bool: + """ + Returns whether TLS is enabled. + + Examples + -------- + :: + + tls_config.is_enabled + """ + return driver_tls_config_is_enabled(self.native_object) + + @property + def root_ca_path(self) -> Optional[str]: + """ + Returns the configured custom root CA path, if present. + If TLS is enabled with native roots (or disabled), this will be ``None``. + + Examples + -------- + :: + + tls_config.root_ca_path + """ + return driver_tls_config_get_root_ca_path(self.native_object) \ + if driver_tls_config_has_root_ca_path(self.native_object) else None diff --git a/python/typedb/api/connection/query_options.py b/python/typedb/api/connection/query_options.py index e6f89e0317..a4aaf87f21 100644 --- a/python/typedb/api/connection/query_options.py +++ b/python/typedb/api/connection/query_options.py @@ -34,7 +34,7 @@ class QueryOptions(NativeWrapper[NativeOptions]): """ - TypeDB transaction options. ``QueryOptions`` object can be used to override the default server behaviour + TypeDB query options. ``QueryOptions`` object can be used to override the default server behaviour for executed queries. Options could be specified either as constructor arguments or using diff --git a/python/typedb/api/connection/transaction.py b/python/typedb/api/connection/transaction.py index 6bdc8ead9f..3f141f3235 100644 --- a/python/typedb/api/connection/transaction.py +++ b/python/typedb/api/connection/transaction.py @@ -59,8 +59,6 @@ def is_open(self) -> bool: """ Checks whether this transaction is open. - :return: - Examples: --------- :: @@ -92,7 +90,6 @@ def query(self, query: str, options: Optional[QueryOptions] = None) -> Promise[Q :param query: The query to execute. :param options: The ``QueryOptions`` to execute the query with.. - :return: Examples: --------- @@ -109,8 +106,6 @@ def commit(self) -> None: **Whether or not the transaction is commited successfully, it gets closed after the commit call.** - :return: - Examples: --------- :: @@ -124,8 +119,6 @@ def rollback(self) -> None: """ Rolls back the uncommitted changes made via this transaction. - :return: - Examples: --------- :: @@ -140,7 +133,6 @@ def on_close(self, function: Callable) -> None: Registers a callback function which will be executed when this transaction is closed. :param function: The callback function. - :return: Examples: --------- @@ -155,8 +147,6 @@ def close(self) -> None: """ Closes the transaction. - :return: - Examples: --------- :: diff --git a/python/typedb/api/connection/transaction_options.py b/python/typedb/api/connection/transaction_options.py index 519095e54b..7032522cf5 100644 --- a/python/typedb/api/connection/transaction_options.py +++ b/python/typedb/api/connection/transaction_options.py @@ -19,6 +19,7 @@ from typing import Optional +from typedb.api.connection.consistency_level import ConsistencyLevel from typedb.common.exception import TypeDBDriverException, ILLEGAL_STATE from typedb.common.native_wrapper import NativeWrapper from typedb.common.validation import require_positive @@ -26,7 +27,9 @@ transaction_options_has_transaction_timeout_millis, transaction_options_get_transaction_timeout_millis, \ transaction_options_set_transaction_timeout_millis, transaction_options_get_schema_lock_acquire_timeout_millis, \ transaction_options_has_schema_lock_acquire_timeout_millis, \ - transaction_options_set_schema_lock_acquire_timeout_millis, TransactionOptions as NativeOptions + transaction_options_set_schema_lock_acquire_timeout_millis, transaction_options_get_read_consistency_level, \ + transaction_options_has_read_consistency_level, transaction_options_set_read_consistency_level, \ + TransactionOptions as NativeOptions class TransactionOptions(NativeWrapper[NativeOptions]): @@ -49,12 +52,15 @@ class TransactionOptions(NativeWrapper[NativeOptions]): def __init__(self, *, transaction_timeout_millis: Optional[int] = None, schema_lock_acquire_timeout_millis: Optional[int] = None, + read_consistency_level: Optional[ConsistencyLevel] = None, ): super().__init__(transaction_options_new()) if transaction_timeout_millis is not None: self.transaction_timeout_millis = transaction_timeout_millis if schema_lock_acquire_timeout_millis is not None: self.schema_lock_acquire_timeout_millis = schema_lock_acquire_timeout_millis + if read_consistency_level is not None: + self.read_consistency_level = read_consistency_level @property def _native_object_not_owned_exception(self) -> TypeDBDriverException: @@ -88,3 +94,17 @@ def schema_lock_acquire_timeout_millis(self, schema_lock_acquire_timeout_millis: require_positive(schema_lock_acquire_timeout_millis, "schema_lock_acquire_timeout_millis") transaction_options_set_schema_lock_acquire_timeout_millis(self.native_object, schema_lock_acquire_timeout_millis) + + @property + def read_consistency_level(self) -> Optional[ConsistencyLevel]: + """ + If set, specifies the requested consistency level of the transaction opening operation. + Affects only read transactions, as write and schema transactions require primary replicas. + """ + return ConsistencyLevel.of(transaction_options_get_read_consistency_level(self.native_object)) \ + if transaction_options_has_read_consistency_level(self.native_object) else None + + @read_consistency_level.setter + def read_consistency_level(self, read_consistency_level: ConsistencyLevel): + transaction_options_set_read_consistency_level(self.native_object, + ConsistencyLevel.native_value(read_consistency_level)) diff --git a/python/typedb/api/database/database.py b/python/typedb/api/database/database.py new file mode 100644 index 0000000000..a9048257e5 --- /dev/null +++ b/python/typedb/api/database/database.py @@ -0,0 +1,101 @@ +# 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. + +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Optional + +from typedb.api.connection.consistency_level import ConsistencyLevel + + +class Database(ABC): + + @property + @abstractmethod + def name(self) -> str: + """ + The database name as a string. + """ + pass + + @abstractmethod + def schema(self, consistency_level: Optional[ConsistencyLevel] = None) -> str: + """ + Returns a full schema text as a valid TypeQL define query string. + + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + database.schema() + database.schema(ConsistencyLevel.Strong()) + """ + pass + + @abstractmethod + def type_schema(self, consistency_level: Optional[ConsistencyLevel] = None) -> str: + """ + Returns the types in the schema as a valid TypeQL define query string. + + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + database.type_schema() + database.type_schema(ConsistencyLevel.Strong()) + """ + pass + + def export_to_file(self, schema_file_path: str, data_file_path: str, + consistency_level: Optional[ConsistencyLevel] = None) -> None: + """ + Export a database into a schema definition and a data files saved to the disk. + This is a blocking operation and may take a significant amount of time depending on the database size. + + :param schema_file_path: The path to the schema definition file to be created + :param data_file_path: The path to the data file to be created + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + database.export_to_file("schema.typeql", "data.typedb") + database.export_to_file("schema.typeql", "data.typedb", ConsistencyLevel.Strong()) + """ + pass + + @abstractmethod + def delete(self, consistency_level: Optional[ConsistencyLevel] = None) -> None: + """ + Deletes this database. + + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + database.delete() + database.delete(ConsistencyLevel.Strong()) + """ + pass diff --git a/python/typedb/api/database/database_manager.py b/python/typedb/api/database/database_manager.py new file mode 100644 index 0000000000..96190ca2fc --- /dev/null +++ b/python/typedb/api/database/database_manager.py @@ -0,0 +1,114 @@ +# 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. + +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import List, Optional + +from typedb.api.connection.consistency_level import ConsistencyLevel + + +class DatabaseManager(ABC): + """ + Provides access to all database management methods. + """ + + @abstractmethod + def all(self, consistency_level: Optional[ConsistencyLevel] = None) -> List[Database]: + """ + Retrieves all databases present on the TypeDB server. + + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + driver.databases.all() + driver.databases.all(ConsistencyLevel.Strong()) + """ + pass + + @abstractmethod + def contains(self, name: str, consistency_level: Optional[ConsistencyLevel] = None) -> bool: + """ + Checks if a database with the given name exists. + + :param name: The database name to be checked + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + driver.databases.contains(name) + driver.databases.contains(name, ConsistencyLevel.Strong()) + """ + pass + + @abstractmethod + def get(self, name: str, consistency_level: Optional[ConsistencyLevel] = None) -> Database: + """ + Retrieves the database with the given name. + + :param name: The name of the database to retrieve + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + driver.databases.get(name) + driver.databases.get(name, ConsistencyLevel.Strong()) + """ + pass + + @abstractmethod + def create(self, name: str, consistency_level: Optional[ConsistencyLevel] = None) -> None: + """ + Creates a database with the given name. + + :param name: The name of the database to be created + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + driver.databases.create(name) + driver.databases.create(name, ConsistencyLevel.Strong()) + """ + pass + + @abstractmethod + def import_from_file(self, name: str, schema: str, data_file_path: str) -> None: + """ + Creates a database with the given name based on previously exported another database's data loaded from a file. + This is a blocking operation and may take a significant amount of time depending on the database size. + + :param name: The name of the database to be created + :param schema: The schema definition query string for the database + :param data_file_path: The exported database file path to import the data from + + Examples: + --------- + :: + + driver.databases.import_from_file(name, schema, "data.typedb") + """ + pass diff --git a/python/typedb/api/server/replica_role.py b/python/typedb/api/server/replica_role.py new file mode 100644 index 0000000000..d4106ac4e2 --- /dev/null +++ b/python/typedb/api/server/replica_role.py @@ -0,0 +1,54 @@ +# 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. + +from __future__ import annotations + +import enum + + +class ReplicaRole(enum.Enum): + """ + This class is used to specify the type of replica. + + Examples + -------- + :: + + server_replica.role + """ + PRIMARY = 0 + CANDIDATE = 1 + SECONDARY = 2 + + def is_primary(self) -> bool: + return self is ReplicaRole.PRIMARY + + def is_candidate(self) -> bool: + return self is ReplicaRole.CANDIDATE + + def is_secondary(self) -> bool: + return self is ReplicaRole.SECONDARY + + def __repr__(self): + if self.is_primary: + return "ReplicaRole.PRIMARY" + elif self.is_candidate: + return "ReplicaRole.CANDIDATE" + elif self.is_secondary: + return "ReplicaRole.SECONDARY" + else: + return "UNKNOWN" diff --git a/python/typedb/api/server/server_replica.py b/python/typedb/api/server/server_replica.py new file mode 100644 index 0000000000..6a62a76f8c --- /dev/null +++ b/python/typedb/api/server/server_replica.py @@ -0,0 +1,100 @@ +# 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. + + +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from typedb.api.server.replica_role import ReplicaRole + + +class ServerReplica(ABC): + """ + The metadata and state of an individual raft replica of a driver connection. + """ + + @property + @abstractmethod + def id(self) -> int: + """ + Returns the id of this replica. + + Examples + -------- + :: + + server_replica.id + """ + pass + + @property + @abstractmethod + def address(self) -> str: + """ + Returns the address this replica is hosted at. + + Examples + -------- + :: + + server_replica.address + """ + pass + + @property + @abstractmethod + def role(self) -> Optional[ReplicaRole]: + """ + Returns whether this is the primary replica of the raft cluster or any of the supporting types. + + Examples + -------- + :: + + server_replica.role + """ + pass + + @abstractmethod + def is_primary(self) -> bool: + """ + Checks whether this is the primary replica of the raft cluster. + + Examples + -------- + :: + + server_replica.is_primary() + """ + pass + + @property + @abstractmethod + def term(self) -> int: + """ + Returns the raft protocol ‘term’ of this replica. + + Examples + -------- + :: + + server_replica.term + """ + pass diff --git a/python/typedb/api/server/server_version.py b/python/typedb/api/server/server_version.py new file mode 100644 index 0000000000..87568cd701 --- /dev/null +++ b/python/typedb/api/server/server_version.py @@ -0,0 +1,71 @@ +# 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. + +from typedb.common.exception import TypeDBDriverException, ILLEGAL_STATE +from typedb.common.native_wrapper import NativeWrapper +from typedb.native_driver_wrapper import ServerVersion as NativeServerVersion + + +class ServerVersion(NativeWrapper[NativeServerVersion]): + """ + A full TypeDB server's version specification. + + Examples: + -------- + :: + + driver.server_version() + """ + + def __init__(self, native_object: NativeServerVersion): + super().__init__(native_object) + + @property + def _native_object_not_owned_exception(self) -> TypeDBDriverException: + return TypeDBDriverException(ILLEGAL_STATE) + + @property + def distribution(self) -> str: + """ + Returns the server's distribution. + + Examples + -------- + :: + + server_version.distribution + """ + return self.native_object.distribution + + @property + def version(self) -> str: + """ + Returns the server's version. + + Examples + -------- + :: + + server_version.version + """ + return self.native_object.version + + def __str__(self): + return f"{self.distribution} {self.version}" + + def __repr__(self): + return f"ServerVersion('{str(self)}')" diff --git a/python/typedb/api/user/user.py b/python/typedb/api/user/user.py index d46e808b13..af38acd3a9 100644 --- a/python/typedb/api/user/user.py +++ b/python/typedb/api/user/user.py @@ -16,7 +16,9 @@ # under the License. from abc import ABC, abstractmethod -from typing import Optional, List +from typing import Optional, TYPE_CHECKING + +from typedb.api.connection.consistency_level import ConsistencyLevel class User(ABC): @@ -27,130 +29,38 @@ class User(ABC): def name(self) -> str: """ Returns the name of this user. - - :return: """ pass - # TODO: Not implemented - # @abstractmethod - # def password_expiry_seconds(self) -> Optional[int]: - # """ - # Returns the number of seconds remaining till this user's current password expires. - # - # :return: - # """ - # pass - @abstractmethod - def update_password(self, password: str) -> None: + def update_password(self, password: str, consistency_level: Optional[ConsistencyLevel] = None) -> None: """ Updates the password for this user. - :param password_old: The current password of this user - :param password_new: The new password - :return: - """ - pass - - @abstractmethod - def delete(self) -> None: - """ - Deletes a user with the given name. - - :param username: The name of the user to be deleted - :return: - - Examples: - --------- - :: - - driver.users.delete(username) - """ - pass - - -class UserManager(ABC): - """ - Provides access to all user management methods. - """ - - @abstractmethod - def contains(self, username: str) -> bool: - """ - Checks if a user with the given name exists. - - :param username: The user name to be checked - :return: - - Examples: - --------- - :: - - driver.users.contains(username) - """ - pass - - @abstractmethod - def create(self, username: str, password: str) -> None: - """ - Create a user with the given name and password. - - :param username: The name of the user to be created - :param password: The password of the user to be created - :return: - - Examples: - --------- - :: - - driver.users.create(username, password) - """ - pass - - @abstractmethod - def get(self, username: str) -> Optional[User]: - """ - Retrieve a user with the given name. - - :param username: The name of the user to retrieve - :return: - - Examples: - --------- - :: - - driver.users.get(username) - """ - pass - - @abstractmethod - def get_current_user(self) -> Optional[User]: - """ - Retrieve the name of the user who opened the current connection. - - :return: + :param password: The new password + :param consistency_level: The consistency level to use for the operation. Strongest possible by default Examples: --------- :: - driver.users.get_current_user() + user.update_password("new-password") + user.update_password("new-password", ConsistencyLevel.Strong()) """ pass @abstractmethod - def all(self) -> List[User]: + def delete(self, consistency_level: Optional[ConsistencyLevel] = None) -> None: """ - Retrieves all users which exist on the TypeDB server. + Deletes this user. - :return: + :param consistency_level: The consistency level to use for the operation. Strongest possible by default Examples: --------- :: - driver.users.all() - + user.delete() + user.delete(ConsistencyLevel.Strong()) """ pass diff --git a/python/typedb/api/user/user_manager.py b/python/typedb/api/user/user_manager.py new file mode 100644 index 0000000000..e2767de4f3 --- /dev/null +++ b/python/typedb/api/user/user_manager.py @@ -0,0 +1,112 @@ +# 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. + +from abc import ABC, abstractmethod +from typing import Optional, List +from typedb.api.user.user import User + +from typedb.api.connection.consistency_level import ConsistencyLevel + + +class UserManager(ABC): + """ + Provides access to all user management methods. + """ + + @abstractmethod + def all(self, consistency_level: Optional[ConsistencyLevel] = None) -> List[User]: + """ + Retrieves all users which exist on the TypeDB server. + + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + driver.users.all() + driver.users.all(ConsistencyLevel.Strong()) + """ + pass + + @abstractmethod + def contains(self, username: str, consistency_level: Optional[ConsistencyLevel] = None) -> bool: + """ + Checks if a user with the given name exists. + + :param username: The username to be checked + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + driver.users.contains(username) + driver.users.contains(username, ConsistencyLevel.Strong()) + """ + pass + + @abstractmethod + def get(self, username: str, consistency_level: Optional[ConsistencyLevel] = None) -> Optional[User]: + """ + Retrieves a user with the given name. + + :param username: The name of the user to retrieve + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + driver.users.get(username) + driver.users.get(username, ConsistencyLevel.Strong()) + """ + pass + + @abstractmethod + def get_current(self, consistency_level: Optional[ConsistencyLevel] = None) -> Optional[User]: + """ + Retrieves the name of the user who opened the current connection. + + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + driver.users.get_current() + driver.users.get_current(ConsistencyLevel.Strong()) + """ + pass + + @abstractmethod + def create(self, username: str, password: str, consistency_level: Optional[ConsistencyLevel] = None) -> None: + """ + Creates a user with the given name and password. + + :param username: The name of the user to be created + :param password: The password of the user to be created + :param consistency_level: The consistency level to use for the operation. Strongest possible by default + + Examples: + --------- + :: + + driver.users.create(username, password) + driver.users.create(username, password, ConsistencyLevel.Strong()) + """ + pass diff --git a/python/typedb/common/datetime.py b/python/typedb/common/datetime.py index dbcfe71777..7c8e3622fe 100644 --- a/python/typedb/common/datetime.py +++ b/python/typedb/common/datetime.py @@ -206,19 +206,19 @@ def offset_seconds_fromstring(cls, offset: str) -> int: @property def datetime_without_nanos(self) -> datetime: - """Return the standard library's datetime, containing data up to microseconds.""" + """Returns the standard library's datetime, containing data up to microseconds.""" return datetime(year=self.year, month=self.month, day=self.day, hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, tzinfo=self.tzinfo) @property def tz_name(self) -> Optional[str]: - """Return the timezone IANA name. None if fixed offset is used for the initialisation instead.""" + """Returns the timezone IANA name. None if fixed offset is used for the initialisation instead.""" return self._tz_name @property def offset_seconds(self) -> Optional[str]: """ - Return the timezone offset (local minus UTC) in seconds. + Returns the timezone offset (local minus UTC) in seconds. None if an IANA name is used for the initialisation instead. """ return self._offset_seconds @@ -226,7 +226,7 @@ def offset_seconds(self) -> Optional[str]: @property def total_seconds(self) -> float: """ - Return the total number of seconds including the nanoseconds part as a float. + Returns the total number of seconds including the nanoseconds part as a float. :raises ValueError: If timestamp is before the start of the epoch. """ @@ -234,63 +234,63 @@ def total_seconds(self) -> float: @property def year(self) -> int: - """Return the datetime's year (1-9999).""" + """Returns the datetime's year (1-9999).""" return self._datetime_of_seconds.year @property def month(self) -> int: - """Return the datetime's month (1-12).""" + """Returns the datetime's month (1-12).""" return self._datetime_of_seconds.month @property def day(self) -> int: - """Return the datetime's day (1-31).""" + """Returns the datetime's day (1-31).""" return self._datetime_of_seconds.day @property def hour(self) -> int: - """Return the datetime's hour (0-23).""" + """Returns the datetime's hour (0-23).""" return self._datetime_of_seconds.hour @property def minute(self) -> int: - """Return the datetime's minute (0-59).""" + """Returns the datetime's minute (0-59).""" return self._datetime_of_seconds.minute @property def second(self) -> int: - """Return the datetime's second (0-59).""" + """Returns the datetime's second (0-59).""" return self._datetime_of_seconds.second @property def microsecond(self) -> int: - """Return the rounded number of microseconds.""" + """Returns the rounded number of microseconds.""" return self._nanos // MICROS_IN_NANO @property def nanos(self) -> int: - """Return the nanoseconds part.""" + """Returns the nanoseconds part.""" return self._nanos @property def tzinfo(self) -> tzinfo: - """Return timezone info.""" + """Returns timezone info.""" return self._datetime_of_seconds.tzinfo @property def date(self) -> date: - """Return the date part.""" + """Returns the date part.""" return self._datetime_of_seconds.date() @property def weekday(self) -> int: - """Return the day of the week as an integer, where Monday == 0 ... Sunday == 6.""" + """Returns the day of the week as an integer, where Monday == 0 ... Sunday == 6.""" return self._datetime_of_seconds.weekday() ISO_TZ_LEN = 6 def isoformat(self) -> str: - """Return the time formatted according to ISO.""" + """Returns the time formatted according to ISO.""" datetime_part = self._datetime_of_seconds.isoformat() tz_part = "" if self._tz_name is not None or self._offset_seconds is not None: diff --git a/python/typedb/common/enums.py b/python/typedb/common/enums.py index d8342257bd..123ebe2db1 100644 --- a/python/typedb/common/enums.py +++ b/python/typedb/common/enums.py @@ -88,6 +88,7 @@ ValueAnnotations as NativeValueAnnotations, ) + class ConstraintExactness(IntEnum): Exact = NativeExact Subtypes = NativeSubtypes diff --git a/python/typedb/common/exception.py b/python/typedb/common/exception.py index 1b1c1eaab8..d0218b761b 100644 --- a/python/typedb/common/exception.py +++ b/python/typedb/common/exception.py @@ -92,6 +92,7 @@ def __init__(self, code: int, message: str): NON_NEGATIVE_VALUE_REQUIRED = DriverErrorMessage(5, "Value of '%s' should be non-negative, was: '%d'.") NON_NULL_VALUE_REQUIRED = DriverErrorMessage(6, "Value of '%s' should not be null.") UNIMPLEMENTED = DriverErrorMessage(7, "This operation is not implemented yet.") +INVALID_ADDRESS_FORMAT = DriverErrorMessage(8, "Driver addresses should be either a string, a list, or a dict.") class ConceptErrorMessage(ErrorMessage): @@ -124,6 +125,7 @@ def __init__(self, code: int, message: str): NULL_NATIVE_OBJECT = InternalErrorMessage(3, "Unhandled null pointer to a native object encountered!") NULL_CONCEPT_PROPERTY = InternalErrorMessage(4, "Unexpected null for a concept (%s) property is found!"); + class AnalyzeExceptionMessage(ErrorMessage): """ :meta private: @@ -132,14 +134,16 @@ class AnalyzeExceptionMessage(ErrorMessage): def __init__(self, code: int, message: str): super(AnalyzeExceptionMessage, self).__init__(code_prefix="PAN", code_number=code, message_prefix="Analyze Error", message_body=message) - + INVALID_CONSTRAINT_CASTING = AnalyzeExceptionMessage(1, "Invalid constraint conversion from '%s' to '%s'.") -INVALID_CONSTRAINT_VERTEX_CASTING = AnalyzeExceptionMessage(2, "Invalid constraint vertex conversion from '%s' to '%s'.") +INVALID_CONSTRAINT_VERTEX_CASTING = AnalyzeExceptionMessage(2, + "Invalid constraint vertex conversion from '%s' to '%s'.") INVALID_STAGE_CASTING = AnalyzeExceptionMessage(3, "Invalid stage conversion from '%s' to '%s'.") INVALID_RETURN_OPERATION_CASTING = AnalyzeExceptionMessage(4, "Invalid return operation conversion from '%s' to '%s'.") INVALID_FETCH_CASTING = AnalyzeExceptionMessage(5, "Invalid fetch conversion from '%s' to '%s'.") -INVALID_VARIABLE_ANNOTATIONS_CASTING = AnalyzeExceptionMessage(6, "Invalid VariableAnnotations conversion from '%s' to '%s'.") +INVALID_VARIABLE_ANNOTATIONS_CASTING = AnalyzeExceptionMessage(6, + "Invalid VariableAnnotations conversion from '%s' to '%s'.") class TypeDBException(Exception): diff --git a/python/typedb/common/promise.py b/python/typedb/common/promise.py index 7980f6cf4e..22c936de43 100644 --- a/python/typedb/common/promise.py +++ b/python/typedb/common/promise.py @@ -48,8 +48,6 @@ def resolve(self) -> T: """ Retrieves the result of the Promise. - :return: - Examples -------- diff --git a/python/typedb/connection/driver.py b/python/typedb/connection/driver.py index 0a16bb1b19..b9cc7e3526 100644 --- a/python/typedb/connection/driver.py +++ b/python/typedb/connection/driver.py @@ -17,35 +17,60 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, Tuple +from typedb.api.connection.consistency_level import ConsistencyLevel from typedb.api.connection.driver import Driver from typedb.api.connection.transaction_options import TransactionOptions -from typedb.common.exception import TypeDBDriverException, DRIVER_CLOSED +from typedb.api.server.server_version import ServerVersion +from typedb.common.exception import TypeDBDriverException, DRIVER_CLOSED, INVALID_ADDRESS_FORMAT +from typedb.common.iterator_wrapper import IteratorWrapper from typedb.common.native_wrapper import NativeWrapper -from typedb.common.validation import require_non_null -from typedb.connection.database_manager import _DatabaseManager +from typedb.common.validation import require_non_null, require_non_negative +from typedb.database.database_manager import _DatabaseManager +from typedb.connection.server_replica import _ServerReplica from typedb.connection.transaction import _Transaction -from typedb.native_driver_wrapper import driver_open_with_description, driver_is_open, driver_force_close, \ - TypeDBDriver as NativeDriver, TypeDBDriverExceptionNative +from typedb.native_driver_wrapper import driver_new_with_description, driver_new_with_addresses_with_description, \ + driver_new_with_address_translation_with_description, driver_is_open, driver_force_close, driver_register_replica, \ + driver_deregister_replica, driver_replicas, driver_primary_replica, driver_server_version, \ + driver_update_address_translation, server_replica_iterator_next, TypeDBDriver as NativeDriver, \ + TypeDBDriverExceptionNative from typedb.user.user_manager import _UserManager if TYPE_CHECKING: - from typedb.connection.driver_options import DriverOptions + from typedb.api.connection.driver_options import DriverOptions from typedb.api.connection.credentials import Credentials from typedb.api.connection.transaction import Transaction, TransactionType - from typedb.api.user.user import UserManager + from typedb.api.user.user_manager import UserManager + from typedb.api.server.server_replica import ServerReplica class _Driver(Driver, NativeWrapper[NativeDriver]): - def __init__(self, address: str, credentials: Credentials, driver_options: DriverOptions): - require_non_null(address, "address") + def __init__(self, addresses: str | list[str] | dict[str, str], credentials: Credentials, + driver_options: DriverOptions): + require_non_null(addresses, "addresses") require_non_null(credentials, "credentials") require_non_null(driver_options, "driver_options") + try: - native_driver = driver_open_with_description(address, credentials.native_object, - driver_options.native_object, Driver.LANGUAGE) + if isinstance(addresses, str): + native_driver = driver_new_with_description(addresses, credentials.native_object, + driver_options.native_object, + Driver.LANGUAGE) + elif isinstance(addresses, list): + native_driver = driver_new_with_addresses_with_description(addresses, credentials.native_object, + driver_options.native_object, + Driver.LANGUAGE) + elif isinstance(addresses, dict): + public_addresses, private_addresses = _Driver._get_translated_addresses(addresses) + native_driver = driver_new_with_address_translation_with_description(public_addresses, + private_addresses, + credentials.native_object, + driver_options.native_object, + Driver.LANGUAGE) + else: + raise TypeDBDriverException(INVALID_ADDRESS_FORMAT) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None super().__init__(native_driver) @@ -58,12 +83,6 @@ def _native_object_not_owned_exception(self) -> TypeDBDriverException: def _native_driver(self) -> NativeDriver: return self.native_object - def transaction(self, database_name: str, transaction_type: TransactionType, - options: Optional[TransactionOptions] = None) -> Transaction: - require_non_null(database_name, "database_name") - require_non_null(transaction_type, "transaction_type") - return _Transaction(self, database_name, transaction_type, options if options else TransactionOptions()) - def is_open(self) -> bool: return driver_is_open(self._native_driver) @@ -75,6 +94,66 @@ def databases(self) -> _DatabaseManager: def users(self) -> UserManager: return _UserManager(self._native_driver) + def server_version(self, consistency_level: Optional[ConsistencyLevel] = None) -> ServerVersion: + try: + consistency_level = ConsistencyLevel.native_value(consistency_level) + return ServerVersion(driver_server_version(self._native_driver, consistency_level)) + except TypeDBDriverExceptionNative as e: + raise TypeDBDriverException.of(e) from None + + def transaction(self, database_name: str, transaction_type: TransactionType, + options: Optional[TransactionOptions] = None) -> Transaction: + require_non_null(database_name, "database_name") + require_non_null(transaction_type, "transaction_type") + return _Transaction(self, database_name, transaction_type, options if options else TransactionOptions()) + + def replicas(self, consistency_level: Optional[ConsistencyLevel] = None) -> set[ServerReplica]: + try: + consistency_level = ConsistencyLevel.native_value(consistency_level) + replica_iter = IteratorWrapper(driver_replicas(self._native_driver, consistency_level), + server_replica_iterator_next) + return set(_ServerReplica(server_replica) for server_replica in replica_iter) + except TypeDBDriverExceptionNative as e: + raise TypeDBDriverException.of(e) from None + + def primary_replica(self, consistency_level: Optional[ConsistencyLevel] = None) -> Optional[ServerReplica]: + consistency_level = ConsistencyLevel.native_value(consistency_level) + if res := driver_primary_replica(self._native_driver, consistency_level): + return _ServerReplica(res) + return None + + def register_replica(self, replica_id: int, address: str) -> None: + require_non_negative(replica_id, "replica_id") + require_non_null(address, "address") + try: + driver_register_replica(self._native_driver, replica_id, address) + except TypeDBDriverExceptionNative as e: + raise TypeDBDriverException.of(e) from None + + def deregister_replica(self, replica_id: int) -> None: + require_non_negative(replica_id, "replica_id") + try: + driver_deregister_replica(self._native_driver, replica_id) + except TypeDBDriverExceptionNative as e: + raise TypeDBDriverException.of(e) from None + + def update_address_translation(self, address_translation: dict[str, str]) -> None: + require_non_null(address_translation, "address_translation") + public_addresses, private_addresses = _Driver._get_translated_addresses(address_translation) + try: + driver_update_address_translation(self._native_driver, public_addresses, private_addresses) + except TypeDBDriverExceptionNative as e: + raise TypeDBDriverException.of(e) from None + + def close(self) -> None: + driver_force_close(self._native_driver) + + @classmethod + def _get_translated_addresses(cls, address_translation: dict[str, str]) -> Tuple[list[str], list[str]]: + public_addresses = list(address_translation.keys()) + private_addresses = [address_translation[public] for public in public_addresses] + return public_addresses, private_addresses + def __enter__(self): return self @@ -82,6 +161,3 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.close() if exc_tb is not None: return False - - def close(self) -> None: - driver_force_close(self._native_driver) diff --git a/python/typedb/connection/server_replica.py b/python/typedb/connection/server_replica.py new file mode 100644 index 0000000000..c0b6a9d3bd --- /dev/null +++ b/python/typedb/connection/server_replica.py @@ -0,0 +1,68 @@ +# 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. + +from __future__ import annotations + +from typing import Optional + +from typedb.api.server.replica_role import ReplicaRole +from typedb.api.server.server_replica import ServerReplica +from typedb.common.exception import TypeDBDriverException, NULL_NATIVE_OBJECT, ILLEGAL_STATE +from typedb.common.native_wrapper import NativeWrapper +from typedb.native_driver_wrapper import (server_replica_has_role, server_replica_has_term, server_replica_get_address, \ + server_replica_get_id, server_replica_get_role, server_replica_is_primary, + server_replica_get_term, \ + ServerReplica as NativeServerReplica, TypeDBDriverExceptionNative) + + +class _ServerReplica(ServerReplica, NativeWrapper[NativeServerReplica]): + + def __init__(self, server_replica: NativeServerReplica): + if not server_replica: + raise TypeDBDriverException(NULL_NATIVE_OBJECT) + super().__init__(server_replica) + + @property + def _native_object_not_owned_exception(self) -> TypeDBDriverException: + return TypeDBDriverException(ILLEGAL_STATE) + + @property + def id(self) -> int: + return server_replica_get_id(self.native_object) + + @property + def address(self) -> str: + return server_replica_get_address(self.native_object) + + @property + def role(self) -> Optional[ReplicaRole]: + return ReplicaRole(server_replica_get_role(self.native_object)) \ + if server_replica_has_role(self.native_object) else None + + def is_primary(self) -> bool: + return server_replica_is_primary(self.native_object) + + @property + def term(self) -> int: + return server_replica_get_term(self.native_object) \ + if server_replica_has_term(self.native_object) else None + + def __str__(self): + return self.address + + def __repr__(self): + return f"ServerReplica('{str(self)}')" diff --git a/python/typedb/connection/transaction.py b/python/typedb/connection/transaction.py index 82b5e3d1d1..ce63acac5a 100644 --- a/python/typedb/connection/transaction.py +++ b/python/typedb/connection/transaction.py @@ -97,7 +97,7 @@ def __init__(self, function: Callable): def callback(self, error: NativeError) -> None: try: if error: - self._function(TypeDBException(error_code(error), error_message(error))) + self._function(TypeDBException(error_code(error), error_message(error))) else: self._function(None) except Exception as e: diff --git a/python/typedb/connection/database.py b/python/typedb/database/database.py similarity index 60% rename from python/typedb/connection/database.py rename to python/typedb/database/database.py index 5710a10c5e..4011506ee2 100644 --- a/python/typedb/connection/database.py +++ b/python/typedb/database/database.py @@ -17,7 +17,10 @@ from __future__ import annotations -from typedb.api.connection.database import Database +from typing import Optional + +from typedb.api.connection.consistency_level import ConsistencyLevel +from typedb.api.database.database import Database from typedb.common.exception import TypeDBDriverException, DATABASE_DELETED, NULL_NATIVE_OBJECT from typedb.common.native_wrapper import NativeWrapper from typedb.common.validation import require_non_null @@ -44,72 +47,37 @@ def name(self) -> str: raise self._native_object_not_owned_exception return self._name - def schema(self) -> str: + def schema(self, consistency_level: Optional[ConsistencyLevel] = None) -> str: try: - return database_schema(self.native_object) + return database_schema(self.native_object, ConsistencyLevel.native_value(consistency_level)) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - def type_schema(self) -> str: + def type_schema(self, consistency_level: Optional[ConsistencyLevel] = None) -> str: try: - return database_type_schema(self.native_object) + return database_type_schema(self.native_object, ConsistencyLevel.native_value(consistency_level)) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - def export_to_file(self, schema_file_path: str, data_file_path: str) -> None: + def export_to_file(self, schema_file_path: str, data_file_path: str, + consistency_level: Optional[ConsistencyLevel] = None) -> None: require_non_null(schema_file_path, "schema_file_path") require_non_null(data_file_path, "data_file_path") try: - return database_export_to_file(self.native_object, schema_file_path, data_file_path) + consistency_level = ConsistencyLevel.native_value(consistency_level) + return database_export_to_file(self.native_object, schema_file_path, data_file_path, consistency_level) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - def delete(self) -> None: + def delete(self, consistency_level: Optional[ConsistencyLevel] = None) -> None: try: self._native_object.thisown = 0 - database_delete(self._native_object) + database_delete(self._native_object, ConsistencyLevel.native_value(consistency_level)) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - # def replicas(self) -> set[Replica]: - # try: - # repl_iter = IteratorWrapper(database_get_replicas_info(self.native_object), replica_info_iterator_next) - # return set(_Database.Replica(replica_info) for replica_info in repl_iter) - # except TypeDBDriverExceptionNative as e: - # raise TypeDBDriverException.of(e) from None - # - # def primary_replica(self) -> Optional[Replica]: - # if res := database_get_primary_replica_info(self.native_object): - # return _Database.Replica(res) - # return None - # - # def preferred_replica(self) -> Optional[Replica]: - # if res := database_get_preferred_replica_info(self.native_object): - # return _Database.Replica(res) - # return None - def __str__(self): return self.name def __repr__(self): return f"Database('{str(self)}')" - - # class Replica(Replica): - # - # def __init__(self, replica_info: ReplicaInfo): - # self._info = replica_info - # - # def database(self) -> Database: - # pass - # - # def server(self) -> str: - # return replica_info_get_server(self._info) - # - # def is_primary(self) -> bool: - # return replica_info_is_primary(self._info) - # - # def is_preferred(self) -> bool: - # return replica_info_is_preferred(self._info) - # - # def term(self) -> int: - # return replica_info_get_term(self._info) diff --git a/python/typedb/connection/database_manager.py b/python/typedb/database/database_manager.py similarity index 71% rename from python/typedb/connection/database_manager.py rename to python/typedb/database/database_manager.py index 88ddcebc2c..f112128d09 100644 --- a/python/typedb/connection/database_manager.py +++ b/python/typedb/database/database_manager.py @@ -17,13 +17,14 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Optional -from typedb.api.connection.database import DatabaseManager +from typedb.api.connection.consistency_level import ConsistencyLevel +from typedb.api.database.database_manager import DatabaseManager from typedb.common.exception import TypeDBDriverException from typedb.common.iterator_wrapper import IteratorWrapper from typedb.common.validation import require_non_null -from typedb.connection.database import _Database +from typedb.database.database import _Database from typedb.native_driver_wrapper import databases_all, databases_contains, databases_create, databases_get, \ databases_import_from_file, database_iterator_next, TypeDBDriverExceptionNative @@ -36,24 +37,31 @@ class _DatabaseManager(DatabaseManager): def __init__(self, native_driver: NativeDriver): self.native_driver = native_driver - def get(self, name: str) -> _Database: + def all(self, consistency_level: Optional[ConsistencyLevel] = None) -> list[_Database]: + try: + databases = databases_all(self.native_driver, ConsistencyLevel.native_value(consistency_level)) + return list(map(_Database, IteratorWrapper(databases, database_iterator_next))) + except TypeDBDriverExceptionNative as e: + raise TypeDBDriverException.of(e) from None + + def contains(self, name: str, consistency_level: Optional[ConsistencyLevel] = None) -> bool: require_non_null(name, "name") try: - return _Database(databases_get(self.native_driver, name)) + return databases_contains(self.native_driver, name, ConsistencyLevel.native_value(consistency_level)) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - def contains(self, name: str) -> bool: + def get(self, name: str, consistency_level: Optional[ConsistencyLevel] = None) -> _Database: require_non_null(name, "name") try: - return databases_contains(self.native_driver, name) + return _Database(databases_get(self.native_driver, name, ConsistencyLevel.native_value(consistency_level))) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - def create(self, name: str) -> None: + def create(self, name: str, consistency_level: Optional[ConsistencyLevel] = None) -> None: require_non_null(name, "name") try: - databases_create(self.native_driver, name) + databases_create(self.native_driver, name, ConsistencyLevel.native_value(consistency_level)) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None @@ -65,9 +73,3 @@ def import_from_file(self, name: str, schema: str, data_file_path: str) -> None: databases_import_from_file(self.native_driver, name, schema, data_file_path) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - - def all(self) -> list[_Database]: - try: - return list(map(_Database, IteratorWrapper(databases_all(self.native_driver), database_iterator_next))) - except TypeDBDriverExceptionNative as e: - raise TypeDBDriverException.of(e) from None diff --git a/python/typedb/driver.py b/python/typedb/driver.py index f519d9724c..10cddc29db 100644 --- a/python/typedb/driver.py +++ b/python/typedb/driver.py @@ -15,6 +15,9 @@ # specific language governing permissions and limitations # under the License. +from collections.abc import Mapping as ABCMapping +from typing import Iterable + from typedb.api.answer.concept_document_iterator import * # noqa # pylint: disable=unused-import from typedb.api.answer.concept_row import * # noqa # pylint: disable=unused-import from typedb.api.answer.concept_row_iterator import * # noqa # pylint: disable=unused-import @@ -31,14 +34,18 @@ from typedb.api.concept.type.role_type import * # noqa # pylint: disable=unused-import from typedb.api.concept.type.type import * # noqa # pylint: disable=unused-import from typedb.api.concept.value import * # noqa # pylint: disable=unused-import +from typedb.api.connection.consistency_level import * # noqa # pylint: disable=unused-import from typedb.api.connection.credentials import * # noqa # pylint: disable=unused-import -from typedb.api.connection.database import * # noqa # pylint: disable=unused-import from typedb.api.connection.driver import * # noqa # pylint: disable=unused-import from typedb.api.connection.driver_options import * # noqa # pylint: disable=unused-import +from typedb.api.connection.driver_tls_config import * # noqa # pylint: disable=unused-import from typedb.api.connection.query_options import * # noqa # pylint: disable=unused-import from typedb.api.connection.transaction import * # noqa # pylint: disable=unused-import from typedb.api.connection.transaction_options import * # noqa # pylint: disable=unused-import +from typedb.api.database.database import * # noqa # pylint: disable=unused-import +from typedb.api.database.database_manager import * # noqa # pylint: disable=unused-import from typedb.api.user.user import * # noqa # pylint: disable=unused-import +from typedb.api.user.user_manager import * # noqa # pylint: disable=unused-import from typedb.common.datetime import * # noqa # pylint: disable=unused-import from typedb.common.duration import * # noqa # pylint: disable=unused-import from typedb.common.exception import * # noqa # pylint: disable=unused-import @@ -49,16 +56,22 @@ class TypeDB: - DEFAULT_ADDRESS = "localhost:1729" + DEFAULT_ADDRESS = "127.0.0.1:1729" + ADDRESSES = Union[Mapping[str, str], Iterable[str], str] @staticmethod - def driver(address: str, credentials: Credentials, driver_options: DriverOptions) -> Driver: + def driver(addresses: ADDRESSES, credentials: Credentials, driver_options: DriverOptions) -> Driver: """ Creates a connection to TypeDB. - :param address: Address of the TypeDB server. + :param addresses: Address(-es) of the TypeDB server(-s). + Can be a single string, multiple strings, or multiple pairs of strings. :param credentials: The credentials to connect with. - :param driver_options: The connection settings to connect with. - :return: + :param driver_options: The driver connection options to connect with. """ - return _Driver(address, credentials, driver_options) + if isinstance(addresses, str): + return _Driver(addresses, credentials, driver_options) + elif isinstance(addresses, ABCMapping): + return _Driver(dict(addresses), credentials, driver_options) + else: + return _Driver(list(addresses), credentials, driver_options) diff --git a/python/typedb/user/user.py b/python/typedb/user/user.py index c3da92488e..d435896015 100644 --- a/python/typedb/user/user.py +++ b/python/typedb/user/user.py @@ -17,7 +17,9 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Optional + +from typedb.api.connection.consistency_level import ConsistencyLevel from typedb.api.user.user import User from typedb.common.exception import TypeDBDriverException, ILLEGAL_STATE @@ -44,21 +46,15 @@ def _native_object_not_owned_exception(self) -> TypeDBDriverException: def name(self) -> str: return user_get_name(self.native_object) - # TODO: Not implemented - # def password_expiry_seconds(self) -> Optional[int]: - # if res := user_get_password_expiry_seconds(self.native_object) >= 0: - # return res - # return None - - def update_password(self, password: str) -> None: + def update_password(self, password: str, consistency_level: Optional[ConsistencyLevel] = None) -> None: require_non_null(password, "password") try: - user_update_password(self.native_object, password) + user_update_password(self.native_object, password, ConsistencyLevel.native_value(consistency_level)) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - def delete(self) -> None: + def delete(self, consistency_level: Optional[ConsistencyLevel] = None) -> None: try: - user_delete(self.native_object) + user_delete(self.native_object, ConsistencyLevel.native_value(consistency_level)) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None diff --git a/python/typedb/user/user_manager.py b/python/typedb/user/user_manager.py index a1571a5406..f731250925 100644 --- a/python/typedb/user/user_manager.py +++ b/python/typedb/user/user_manager.py @@ -19,12 +19,13 @@ from typing import TYPE_CHECKING, Optional -from typedb.api.user.user import UserManager +from typedb.api.connection.consistency_level import ConsistencyLevel +from typedb.api.user.user_manager import UserManager from typedb.common.exception import TypeDBDriverException from typedb.common.iterator_wrapper import IteratorWrapper from typedb.common.validation import require_non_null from typedb.native_driver_wrapper import users_contains, users_create, users_all, users_get, \ - users_get_current_user, user_iterator_next, TypeDBDriverExceptionNative + users_get_current, user_iterator_next, TypeDBDriverExceptionNative from typedb.user.user import _User if TYPE_CHECKING: @@ -37,40 +38,41 @@ class _UserManager(UserManager): def __init__(self, native_driver: NativeDriver): self.native_driver = native_driver - def contains(self, username: str) -> bool: - require_non_null(username, "username") + def all(self, consistency_level: Optional[ConsistencyLevel] = None) -> list[User]: try: - return users_contains(self.native_driver, username) + native_users = users_all(self.native_driver, ConsistencyLevel.native_value(consistency_level)) + return [_User(user, self) for user in IteratorWrapper(native_users, user_iterator_next)] except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - def create(self, username: str, password: str) -> None: + def contains(self, username: str, consistency_level: Optional[ConsistencyLevel] = None) -> bool: require_non_null(username, "username") - require_non_null(password, "password") try: - users_create(self.native_driver, username, password) + return users_contains(self.native_driver, username, ConsistencyLevel.native_value(consistency_level)) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - def all(self) -> list[User]: + def get(self, username: str, consistency_level: Optional[ConsistencyLevel] = None) -> Optional[User]: + require_non_null(username, "username") try: - return [_User(user, self) for user in IteratorWrapper(users_all(self.native_driver), user_iterator_next)] + if user := users_get(self.native_driver, username, ConsistencyLevel.native_value(consistency_level)): + return _User(user, self) + return None except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - def get(self, username: str) -> Optional[User]: - require_non_null(username, "username") + def get_current(self, consistency_level: Optional[ConsistencyLevel] = None) -> Optional[User]: try: - if user := users_get(self.native_driver, username): + if user := users_get_current(self.native_driver, ConsistencyLevel.native_value(consistency_level)): return _User(user, self) return None except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None - def get_current_user(self) -> Optional[User]: + def create(self, username: str, password: str, consistency_level: Optional[ConsistencyLevel] = None) -> None: + require_non_null(username, "username") + require_non_null(password, "password") try: - if user := users_get_current_user(self.native_driver): - return _User(user, self) - return None + users_create(self.native_driver, username, password, ConsistencyLevel.native_value(consistency_level)) except TypeDBDriverExceptionNative as e: raise TypeDBDriverException.of(e) from None diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 717c80320e..81d590b621 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -28,7 +28,7 @@ [dev-dependencies.regex] features = ["default", "perf", "perf-backtrack", "perf-cache", "perf-dfa", "perf-inline", "perf-literal", "perf-onepass", "std", "unicode", "unicode-age", "unicode-bool", "unicode-case", "unicode-gencat", "unicode-perl", "unicode-script", "unicode-segment"] - version = "1.11.1" + version = "1.12.2" default-features = false [dev-dependencies.async-std] @@ -53,14 +53,14 @@ [dev-dependencies.serde_json] features = ["alloc", "default", "indexmap", "preserve_order", "raw_value", "std"] - version = "1.0.143" + version = "1.0.145" default-features = false [dependencies] [dependencies.tokio] - features = ["bytes", "default", "fs", "full", "io-std", "io-util", "libc", "macros", "mio", "net", "parking_lot", "process", "rt", "rt-multi-thread", "signal", "signal-hook-registry", "socket2", "sync", "time", "tokio-macros"] - version = "1.47.1" + features = ["bytes", "default", "fs", "full", "io-std", "io-util", "libc", "macros", "mio", "net", "parking_lot", "process", "rt", "rt-multi-thread", "signal", "signal-hook-registry", "socket2", "sync", "test-util", "time", "tokio-macros"] + version = "1.48.0" default-features = false [dependencies.tracing] @@ -71,17 +71,22 @@ [dependencies.typedb-protocol] features = [] git = "https://github.com/typedb/typedb-protocol" - tag = "3.7.0" + tag = "3.7.0-alpha-0" + default-features = false + + [dependencies.log] + features = ["kv", "kv_unstable", "std", "value-bag"] + version = "0.4.28" default-features = false [dependencies.serde] features = ["alloc", "default", "derive", "rc", "serde_derive", "std"] - version = "1.0.219" + version = "1.0.228" default-features = false [dependencies.tracing-subscriber] - features = ["alloc", "ansi", "default", "env-filter", "fmt", "matchers", "nu-ansi-term", "once_cell", "regex", "registry", "sharded-slab", "smallvec", "std", "thread_local", "tracing", "tracing-log"] - version = "0.3.19" + features = ["alloc", "ansi", "default", "env-filter", "fmt", "matchers", "nu-ansi-term", "once_cell", "registry", "sharded-slab", "smallvec", "std", "thread_local", "tracing", "tracing-log"] + version = "0.3.20" default-features = false [dependencies.tokio-stream] @@ -101,7 +106,7 @@ [dependencies.uuid] features = ["default", "fast-rng", "rng", "serde", "std", "v4"] - version = "1.18.0" + version = "1.18.1" default-features = false [dependencies.prost] @@ -111,7 +116,7 @@ [dependencies.chrono-tz] features = ["case-insensitive", "default", "std"] - version = "0.9.0" + version = "0.10.3" default-features = false [dependencies.tonic-types] @@ -136,7 +141,7 @@ [dependencies.chrono] features = ["alloc", "android-tzdata", "clock", "default", "iana-time-zone", "js-sys", "now", "oldtime", "serde", "std", "wasm-bindgen", "wasmbind", "winapi", "windows-link"] - version = "0.4.41" + version = "0.4.40" default-features = false [dependencies.crossbeam] @@ -144,6 +149,14 @@ version = "0.8.4" default-features = false +[[test]] + path = "tests/integration/cluster/playground.rs" + name = "test_playground" + +[[test]] + path = "tests/integration/cluster/clustering.rs" + name = "test_clustering" + [[test]] path = "tests/integration/driver.rs" name = "test_driver" diff --git a/rust/README.md b/rust/README.md index 8ee9db180f..9980ce071b 100644 --- a/rust/README.md +++ b/rust/README.md @@ -82,16 +82,17 @@ use typedb_driver::{ ConceptRow, QueryAnswer, }, concept::{Concept, ValueType}, - Credentials, DriverOptions, Error, QueryOptions, TransactionOptions, TransactionType, TypeDBDriver, + Addresses, Credentials, DriverOptions, DriverTlsConfig, Error, QueryOptions, TransactionOptions, TransactionType, + TypeDBDriver, }; fn typedb_example() { async_std::task::block_on(async { // Open a driver connection. Specify your parameters if needed let driver = TypeDBDriver::new( - TypeDBDriver::DEFAULT_ADDRESS, + Addresses::try_from_address_str(TypeDBDriver::DEFAULT_ADDRESS).unwrap(), Credentials::new("admin", "password"), - DriverOptions::new(false, None).unwrap(), + DriverOptions::new(DriverTlsConfig::disabled()), ) .await .unwrap(); @@ -234,7 +235,7 @@ fn typedb_example() { // just call `commit`, which will wait for all ongoing operations to finish before executing. let queries = ["insert $a isa person, has name \"Alice\";", "insert $b isa person, has name \"Bob\";"]; for query in queries { - transaction.query(query); + let _unawaited_future = transaction.query(query); } transaction.commit().await.unwrap(); diff --git a/rust/docs_structure.bzl b/rust/docs_structure.bzl index 2f5bd3eb56..cefaf422fc 100644 --- a/rust/docs_structure.bzl +++ b/rust/docs_structure.bzl @@ -42,7 +42,6 @@ dir_mapping = { "VariableInfo.adoc": "analyze", "QueryAnswer.adoc": "answer", "QueryType.adoc": "answer", - "OkQueryAnswer.adoc": "answer", "ConceptDocument.adoc": "answer", "ConceptDocumentHeader.adoc": "answer", "ConceptRow.adoc": "answer", @@ -51,24 +50,30 @@ dir_mapping = { "Leaf.adoc": "answer", "Trait_Promise.adoc": "answer", "JSON.adoc": "answer", - "ValueGroup.adoc": "answer", "Concept.adoc": "concept", "ConceptCategory.adoc": "concept", + "Kind.adoc": "concept", "Type.adoc": "concept", "TypeDBDriver.adoc": "connection", + "Address.adoc": "connection", + "Addresses.adoc": "connection", + "ConsistencyLevel.adoc": "connection", + "Credentials.adoc": "connection", "Database.adoc": "connection", "DatabaseManager.adoc": "connection", "DriverOptions.adoc": "connection", - "Credentials.adoc": "connection", - "Kind.adoc": "concept", - "ReplicaInfo.adoc": "connection", + "DriverTlsConfig.adoc": "connection", + "Trait_Replica.adoc": "connection", + "ReplicaRole.adoc": "connection", + "AvailableServerReplica.adoc": "connection", + "ServerReplica.adoc": "connection", + "ServerVersion.adoc": "connection", "User.adoc": "connection", "UserManager.adoc": "connection", "Relation.adoc": "data", "Entity.adoc": "data", "Attribute.adoc": "data", "Value.adoc": "data", - "Instance.adoc": "data", "Error.adoc": "errors", "AnalyzeError.adoc": "errors", "ConceptError.adoc": "errors", diff --git a/rust/example.rs b/rust/example.rs index 58de9a7f80..4d5d05a4bd 100644 --- a/rust/example.rs +++ b/rust/example.rs @@ -9,16 +9,17 @@ use typedb_driver::{ ConceptRow, QueryAnswer, }, concept::{Concept, ValueType}, - Credentials, DriverOptions, Error, QueryOptions, TransactionOptions, TransactionType, TypeDBDriver, + Addresses, Credentials, DriverOptions, DriverTlsConfig, Error, QueryOptions, TransactionOptions, TransactionType, + TypeDBDriver, }; fn typedb_example() { async_std::task::block_on(async { // Open a driver connection. Specify your parameters if needed let driver = TypeDBDriver::new( - TypeDBDriver::DEFAULT_ADDRESS, + Addresses::try_from_address_str(TypeDBDriver::DEFAULT_ADDRESS).unwrap(), Credentials::new("admin", "password"), - DriverOptions::new(false, None).unwrap(), + DriverOptions::new(DriverTlsConfig::disabled()), ) .await .unwrap(); @@ -161,7 +162,7 @@ fn typedb_example() { // just call `commit`, which will wait for all ongoing operations to finish before executing. let queries = ["insert $a isa person, has name \"Alice\";", "insert $b isa person, has name \"Bob\";"]; for query in queries { - transaction.query(query); + let _unawaited_future = transaction.query(query); } transaction.commit().await.unwrap(); diff --git a/rust/src/analyze/pipeline.rs b/rust/src/analyze/pipeline.rs index cac4e793c3..5c697f2c46 100644 --- a/rust/src/analyze/pipeline.rs +++ b/rust/src/analyze/pipeline.rs @@ -17,7 +17,7 @@ * under the License. */ -use std::{collections::HashMap, fmt}; +use std::collections::HashMap; use crate::analyze::conjunction::{Conjunction, ConjunctionID, Variable}; diff --git a/rust/src/answer/concept_document.rs b/rust/src/answer/concept_document.rs index 7447b1289c..58202d5044 100644 --- a/rust/src/answer/concept_document.rs +++ b/rust/src/answer/concept_document.rs @@ -49,7 +49,7 @@ impl ConceptDocument { } } - /// Retrieve the executed query's type (shared by all elements in this stream). + /// Retrieves the executed query's type (shared by all elements in this stream). /// /// # Examples /// diff --git a/rust/src/answer/concept_row.rs b/rust/src/answer/concept_row.rs index d0136c5b11..e965eeffe0 100644 --- a/rust/src/answer/concept_row.rs +++ b/rust/src/answer/concept_row.rs @@ -65,7 +65,7 @@ impl ConceptRow { Self { header, involved_conjunctions, row } } - /// Retrieve the row column names (shared by all elements in this stream). + /// Retrieves the row column names (shared by all elements in this stream). /// /// # Examples /// @@ -76,7 +76,7 @@ impl ConceptRow { &self.header.column_names } - /// Retrieve the executed query's type (shared by all elements in this stream). + /// Retrieves the executed query's type (shared by all elements in this stream). /// /// # Examples /// diff --git a/rust/src/answer/mod.rs b/rust/src/answer/mod.rs index 6638095be1..aa40bbfe29 100644 --- a/rust/src/answer/mod.rs +++ b/rust/src/answer/mod.rs @@ -38,7 +38,7 @@ pub enum QueryAnswer { } impl QueryAnswer { - /// Retrieve the executed query's type (shared by all elements in this stream). + /// Retrieves the executed query's type (shared by all elements in this stream). /// /// # Examples /// @@ -53,7 +53,7 @@ impl QueryAnswer { } } - /// Check if the QueryAnswer is an Ok response. + /// Checks if the QueryAnswer is an Ok response. /// /// # Examples /// @@ -64,7 +64,7 @@ impl QueryAnswer { matches!(self, Self::Ok(_)) } - /// Check if the QueryAnswer is a ConceptRowStream. + /// Checks if the QueryAnswer is a ConceptRowStream. /// /// # Examples /// @@ -75,7 +75,7 @@ impl QueryAnswer { matches!(self, Self::ConceptRowStream(_, _)) } - /// Check if the QueryAnswer is a ConceptDocumentStream. + /// Checks if the QueryAnswer is a ConceptDocumentStream. /// /// # Examples /// diff --git a/rust/src/common/address.rs b/rust/src/common/address/address.rs similarity index 77% rename from rust/src/common/address.rs rename to rust/src/common/address/address.rs index ea30a0956a..7bf9ed3476 100644 --- a/rust/src/common/address.rs +++ b/rust/src/common/address/address.rs @@ -19,7 +19,7 @@ use std::{fmt, str::FromStr}; -use http::Uri; +use http::{uri::PathAndQuery, Uri}; use crate::{ common::{Error, Result}, @@ -32,7 +32,7 @@ pub struct Address { } impl Address { - const DEFAULT_SCHEME: &'static str = "http"; + const DEFAULT_PATH: &'static str = "/"; pub(crate) fn into_uri(self) -> Uri { self.uri @@ -42,8 +42,13 @@ impl Address { self.uri.scheme() } - pub(crate) fn is_https(&self) -> bool { - self.uri_scheme().map_or(false, |scheme| scheme == &http::uri::Scheme::HTTPS) + pub(crate) fn with_scheme(&self, scheme: http::uri::Scheme) -> Self { + let mut parts = self.uri.clone().into_parts(); + parts.scheme = Some(scheme); + if parts.path_and_query.is_none() { + parts.path_and_query = Some(PathAndQuery::from_static(Self::DEFAULT_PATH)); + } + Self { uri: Uri::from_parts(parts).expect("Expected valid URI after scheme change") } } } @@ -51,11 +56,7 @@ impl FromStr for Address { type Err = Error; fn from_str(address: &str) -> Result { - let uri = if address.contains("://") { - address.parse::()? - } else { - format!("{}://{}", Self::DEFAULT_SCHEME, address).parse::()? - }; + let uri = address.parse::()?; if uri.port().is_none() { return Err(Error::Connection(ConnectionError::MissingPort { address: address.to_owned() })); } diff --git a/rust/src/common/address/address_translation.rs b/rust/src/common/address/address_translation.rs new file mode 100644 index 0000000000..4d050bf8e3 --- /dev/null +++ b/rust/src/common/address/address_translation.rs @@ -0,0 +1,44 @@ +/* + * 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. + */ + +use std::collections::HashMap; + +use crate::common::address::Address; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub(crate) enum AddressTranslation { + // public : private + Mapping(HashMap), +} + +impl AddressTranslation { + pub(crate) fn to_private(&self, address: &Address) -> Option
{ + match self { + AddressTranslation::Mapping(mapping) => mapping.get(address).cloned(), + } + } + + pub(crate) fn to_public(&self, address: &Address) -> Option
{ + match self { + AddressTranslation::Mapping(mapping) => { + mapping.iter().find(|(_, private)| private == &address).map(|(public, _)| public.clone()) + } + } + } +} diff --git a/rust/src/common/address/addresses.rs b/rust/src/common/address/addresses.rs new file mode 100644 index 0000000000..b36756f929 --- /dev/null +++ b/rust/src/common/address/addresses.rs @@ -0,0 +1,232 @@ +/* + * 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. + */ + +use std::{ + collections::HashMap, + fmt, + fmt::{Formatter, Write}, +}; + +use itertools::Itertools; + +use crate::common::address::{address_translation::AddressTranslation, Address}; + +/// A collection of server addresses used for connection. +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Addresses { + Direct(Vec
), + Translated(HashMap), +} + +impl Addresses { + /// Prepare addresses based on a single "host:port" string. + /// + /// # Examples + /// + /// ```rust + /// Addresses::try_from_address_str("127.0.0.1:11729") + /// ``` + pub fn try_from_address_str(address_str: impl AsRef) -> crate::Result { + let address = address_str.as_ref().parse()?; + Ok(Self::from_address(address)) + } + + /// Prepare addresses based on a single TypeDB address. + /// + /// # Examples + /// + /// ```rust + /// let address = "127.0.0.1:11729".parse().unwrap(); + /// Addresses::from_address(address) + /// ``` + pub fn from_address(address: Address) -> Self { + Self::Direct(Vec::from([address])) + } + + /// Prepare addresses based on multiple "host:port" strings. + /// Is used to specify multiple addresses connect to. + /// + /// # Examples + /// + /// ```rust + /// Addresses::try_from_addresses_str(["127.0.0.1:11729", "127.0.0.1:11730", "127.0.0.1:11731"]) + /// ``` + pub fn try_from_addresses_str(addresses_str: impl IntoIterator>) -> crate::Result { + let addresses: Vec
= + addresses_str.into_iter().map(|address_str| address_str.as_ref().parse()).try_collect()?; + Ok(Self::from_addresses(addresses)) + } + + /// Prepare addresses based on multiple TypeDB addresses. + /// + /// # Examples + /// + /// ```rust + /// let address1 = "127.0.0.1:11729".parse().unwrap(); + /// let address2 = "127.0.0.1:11730".parse().unwrap(); + /// let address3 = "127.0.0.1:11731".parse().unwrap(); + /// Addresses::from_addresses([address1, address2, address3]) + /// ``` + pub fn from_addresses(addresses: impl IntoIterator) -> Self { + Self::Direct(addresses.into_iter().collect()) + } + + /// Prepare addresses based on multiple key-value (public-private) "key:port" string pairs. + /// Translation map from addresses to be used by the driver for connection to addresses received + /// from the TypeDB server(s). + /// + /// # Examples + /// + /// ```rust + /// Addresses::try_from_addresses_str( + /// [ + /// ("typedb-cloud.ext:11729", "127.0.0.1:11729"), + /// ("typedb-cloud.ext:11730", "127.0.0.1:11730"), + /// ("typedb-cloud.ext:11731", "127.0.0.1:11731") + /// ].into() + /// ) + /// ``` + pub fn try_from_translation_str(addresses_str: HashMap, impl AsRef>) -> crate::Result { + let mut addresses = HashMap::new(); + for (address_key, address_value) in addresses_str.into_iter() { + addresses.insert(address_key.as_ref().parse()?, address_value.as_ref().parse()?); + } + Ok(Self::from_translation(addresses)) + } + + /// Prepare addresses based on multiple key-value (public-private) TypeDB address pairs. + /// Translation map from addresses to be used by the driver for connection to addresses received + /// from the TypeDB server(s). + /// + /// # Examples + /// + /// ```rust + /// let translation: HashMap = [ + /// ("typedb-cloud.ext:11729".parse()?, "127.0.0.1:11729".parse()?), + /// ("typedb-cloud.ext:11730".parse()?, "127.0.0.1:11730".parse()?), + /// ("typedb-cloud.ext:11731".parse()?, "127.0.0.1:11731".parse()?) + /// ].into(); + /// Addresses::from_translation(translation) + /// ``` + pub fn from_translation(addresses: HashMap) -> Self { + Self::Translated(addresses) + } + + /// Returns the number of address entries (addresses or address pairs) in the collection. + /// + /// # Examples + /// + /// ```rust + /// addresses.len() + /// ``` + pub fn len(&self) -> usize { + match self { + Addresses::Direct(vec) => vec.len(), + Addresses::Translated(map) => map.len(), + } + } + + /// Checks if the public address is a part of the addresses. + /// + /// # Examples + /// + /// ```rust + /// addresses.contains(&address) + /// ``` + pub fn contains(&self, address: &Address) -> bool { + match self { + Addresses::Direct(vec) => vec.contains(address), + Addresses::Translated(map) => map.contains_key(address), + } + } + + pub(crate) fn addresses(&self) -> AddressIter<'_> { + match self { + Addresses::Direct(vec) => AddressIter::Direct(vec.iter()), + Addresses::Translated(map) => AddressIter::Translated(map.keys()), + } + } + + pub(crate) fn address_translation(&self) -> AddressTranslation { + match self { + Addresses::Direct(addresses) => AddressTranslation::Mapping( + addresses.into_iter().map(|address| (address.clone(), address.clone())).collect(), + ), + Addresses::Translated(translation) => AddressTranslation::Mapping(translation.clone()), + } + } + + pub(crate) fn exclude_addresses(&mut self, excluded_addresses: &Addresses) { + match self { + Addresses::Direct(addresses) => { + addresses.retain(|address| excluded_addresses.contains(address)); + } + Addresses::Translated(translation) => translation.retain(|address, _| excluded_addresses.contains(address)), + } + } +} + +impl fmt::Display for Addresses { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Addresses::Direct(addresses) => { + f.write_char('[')?; + for (i, address) in addresses.iter().enumerate() { + if i > 0 { + f.write_str(", ")?; + } + write!(f, "{address}")?; + } + f.write_char(']') + } + Addresses::Translated(translation) => { + f.write_char('{')?; + for (i, (public, private)) in translation.iter().enumerate() { + if i > 0 { + f.write_str(", ")?; + } + write!(f, "{public}: {private}")?; + } + f.write_char('}') + } + } + } +} + +impl Default for Addresses { + fn default() -> Self { + Self::Direct(Vec::default()) + } +} + +pub(crate) enum AddressIter<'a> { + Direct(std::slice::Iter<'a, Address>), + Translated(std::collections::hash_map::Keys<'a, Address, Address>), +} + +impl<'a> Iterator for AddressIter<'a> { + type Item = &'a Address; + + fn next(&mut self) -> Option { + match self { + AddressIter::Direct(iter) => iter.next(), + AddressIter::Translated(iter) => iter.next(), + } + } +} diff --git a/tool/test/EchoJavaHome.java b/rust/src/common/address/mod.rs similarity index 81% rename from tool/test/EchoJavaHome.java rename to rust/src/common/address/mod.rs index 42c783955a..83ba5ed8f2 100644 --- a/tool/test/EchoJavaHome.java +++ b/rust/src/common/address/mod.rs @@ -17,10 +17,8 @@ * under the License. */ -package com.typedb.driver.tool.test; +pub use self::{address::Address, addresses::Addresses}; -public class EchoJavaHome { - public static void main(String[] args) { - System.out.println(System.getProperty("java.home")); - } -} +pub(crate) mod address; +pub(crate) mod address_translation; +pub(crate) mod addresses; diff --git a/rust/src/common/consistency_level.rs b/rust/src/common/consistency_level.rs new file mode 100644 index 0000000000..c6513ba03a --- /dev/null +++ b/rust/src/common/consistency_level.rs @@ -0,0 +1,54 @@ +/* + * 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. + */ +use std::fmt; + +use crate::common::address::Address; + +/// Consistency levels of operations against a distributed server. All driver methods have default +/// recommended values, however, most of the operations can be configured in order to potentially +/// speed up the execution (introducing risks of stale data) or test a specific replica. +/// This setting does not affect clusters with a single node. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ConsistencyLevel { + /// Strong consistency level. + /// Strongest consistency, always up-to-date due to the guarantee of the primary replica usage. + /// May require more time for operation execution. + Strong, + + /// Eventual consistency level. + /// Allow stale reads from any replica and execution orchestration through a non-primary replica. + /// Does not guarantee latest writes, but is eventually faster compared to other consistency levels. + /// Note that the target replica can redirect the request, if needed. + Eventual, + + /// Replica dependent consistency level. + /// The operation is executed against the provided replica address only. Its guarantees depend + /// on the replica selected. Note that the target replica can redirect the request, if needed. + ReplicaDependent { address: Address }, +} + +impl fmt::Display for ConsistencyLevel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ConsistencyLevel::Strong => write!(f, "Strong"), + ConsistencyLevel::Eventual => write!(f, "Eventual"), + ConsistencyLevel::ReplicaDependent { address } => write!(f, "ReplicaDependent({address})"), + } + } +} diff --git a/rust/src/common/error.rs b/rust/src/common/error.rs index a4b885f027..d17cf8320c 100644 --- a/rust/src/common/error.rs +++ b/rust/src/common/error.rs @@ -17,13 +17,13 @@ * under the License. */ -use std::{collections::HashSet, error::Error as StdError, fmt}; +use std::{error::Error as StdError, fmt, time::Duration}; -use itertools::Itertools; use tonic::{Code, Status}; use tonic_types::StatusExt; -use super::{address::Address, RequestID}; +use super::RequestID; +use crate::common::address::{Address, Addresses}; macro_rules! error_messages { { @@ -128,50 +128,48 @@ error_messages! { ConnectionError code: "CXN", type: "Connection Error", RPCMethodUnavailable { message: String } = 1: "The server does not support this method, please check the driver-server compatibility:\n'{message}'.", - ServerConnectionFailed { addresses: Vec
} = - 2: "Unable to connect to TypeDB server(s) at: \n{addresses:?}", + ServerConnectionFailed { configured_addresses: Addresses, accessed_addresses: Addresses, details: String } = + 2: "Unable to connect to TypeDB server(s).\nInitially configured addresses: {configured_addresses}.\nTried accessing addresses: {accessed_addresses}. Details: {details}", ServerConnectionFailedWithError { error: String } = 3: "Unable to connect to TypeDB server(s), received errors: \n{error}", - ServerConnectionFailedStatusError { error: String } = + ServerConnectionFailedNetworking { error: String } = 4: "Unable to connect to TypeDB server(s), received network or protocol error: \n{error}", ServerConnectionIsClosed = 5: "The connection has been closed and no further operation is allowed.", + ServerConnectionIsClosedUnexpectedly = + 6: "The connection has been closed unexpectedly and no further operation is allowed.", TransactionIsClosed = - 6: "The transaction is closed and no further operation is allowed.", + 7: "The transaction is closed and no further operation is allowed.", TransactionIsClosedWithErrors { errors: String } = - 7: "The transaction is closed because of the error(s):\n{errors}", - DatabaseNotFound { name: String } = - 8: "Database '{name}' not found.", + 8: "The transaction is closed because of the error(s):\n{errors}", MissingResponseField { field: &'static str } = 9: "Missing field in message received from server: '{field}'. This is either a version compatibility issue or a bug.", UnknownRequestId { request_id: RequestID } = 10: "Received a response with unknown request id '{request_id}'", UnexpectedResponse { response: String } = 11: "Received unexpected response from server: '{response}'. This is either a version compatibility issue or a bug.", - InvalidResponseField { name: &'static str } = - 12: "Invalid field in message received from server: '{name}'. This is either a version compatibility issue or a bug.", QueryStreamNoResponse = 13: "Didn't receive any server responses for the query.", UnexpectedQueryType { query_type: i32 } = 14: "Unexpected query type in message received from server: {query_type}. This is either a version compatibility issue or a bug.", ClusterReplicaNotPrimary = 15: "The replica is not the primary replica.", - ClusterAllNodesFailed { errors: String } = - 16: "Attempted connecting to all TypeDB Cluster servers, but the following errors occurred: \n{errors}.", + UnknownDirectReplica { address: Address, configured_addresses: Addresses } = + 16: "Could not execute operation against '{address}' since it's not a known replica of configured addresses ({configured_addresses}).", TokenCredentialInvalid = 17: "Invalid token credentials.", EncryptionSettingsMismatch = 18: "Unable to connect to TypeDB: possible encryption settings mismatch.", - SSLCertificateNotValidated = + SslCertificateNotValidated = 19: "SSL handshake with TypeDB failed: the server's identity could not be verified. Possible CA mismatch.", BrokenPipe = 20: "Stream closed because of a broken pipe. This could happen if you are attempting to connect to an unencrypted TypeDB server using a TLS-enabled credentials.", - ConnectionFailed = - 21: "Connection failed. Please check the server is running and the address is accessible. Encrypted TypeDB endpoints may also have misconfigured SSL certificates.", + ConnectionRefusedNetworking = + 21: "Connection refused. Please check the server is running and the address is accessible. Encrypted TypeDB endpoints may also have misconfigured SSL certificates.", MissingPort { address: String } = 22: "Invalid URL '{address}': missing port.", - AddressTranslationMismatch { unknown: HashSet
, unmapped: HashSet
} = - 23: "Address translation map does not match the server's advertised address list. User-provided servers not in the advertised list: {unknown:?}. Advertised servers not mapped by user: {unmapped:?}.", + UnexpectedReplicaRole { replica_role: i32 } = + 23: "Unexpected replica type in message received from server: {replica_role}. This is either a version compatibility issue or a bug.", ValueTimeZoneNameNotRecognised { time_zone: String } = 24: "Time zone provided by the server has name '{time_zone}', which is not an officially recognized timezone.", ValueTimeZoneOffsetNotRecognised { offset: i32 } = @@ -194,12 +192,47 @@ error_messages! { ConnectionError 33: "Didn't receive any server responses for the database export command.", AbsentTlsConfigForTlsConnection = 34: "Could not establish a TLS connection without a TLS config specified. Please verify your driver options.", - TlsConnectionWithoutHttps = - 35: "TLS connections can only be enabled when connecting to HTTPS endpoints, for example using 'https://:port'. Please modify the address, or disable TLS (WARNING: this will send passwords over plaintext).", - NonTlsConnectionWithHttps = - 36: "Connecting to an https endpoint requires enabling TLS in driver options.", + ServerIsNotInitialised = + 35: "Server is not yet initialized.", AnalyzeNoResponse = - 37: "Didn't receive any server responses for the analyze request.", + 36: "Didn't receive any server responses for the analyze request.", + NotPrimaryOnReadOnly { address: Address } = + 37: "Could not execute a readonly operation on a non-primary replica '{address}'.", + NoAvailableReplicas { configured_addresses: Addresses } = + 38: "Could not connect: no available replicas read from addresses {configured_addresses}.", + InvalidAddressWithScheme { addresses: Addresses } = + 39: "Invalid address format: a scheme was found in one or more addresses. Please provide addresses as 'host:port'. Use driver options to configure TLS. Addresses: {addresses}.", + AddressTranslationWithoutTranslation { addresses: Addresses } = + 40: "Specified addresses do not contain address translation: {addresses}.", + NoPrimaryReplica = + 41: "Could not find a primary replica.", + SchemeTlsSettingsMismatch { scheme: http::uri::Scheme, is_tls_enabled: bool } = + 42: "Scheme {scheme} is not compatible with tls setting `enabled: {is_tls_enabled}`", + RequestTimeout { timeout: String } = + 43: "Request timed out after {timeout}. The server may be unresponsive.", +} + +impl ConnectionError { + pub fn request_timeout(timeout: Duration) -> Self { + let (value, decimal, unit) = if timeout.as_secs() > 0 { + let decimal = timeout.subsec_millis(); + (timeout.as_secs(), (decimal > 0).then_some(decimal), "seconds") + } else if timeout.subsec_millis() > 0 { + let decimal = timeout.subsec_micros() % 1000; + (timeout.subsec_millis() as u64, (decimal > 0).then_some(decimal), "milliseconds") + } else if timeout.subsec_micros() > 0 { + let decimal = timeout.subsec_nanos() % 1000; + (timeout.subsec_micros() as u64, (decimal > 0).then_some(decimal), "microseconds") + } else { + (timeout.subsec_nanos() as u64, None, "nanoseconds") + }; + + let timeout_str = match decimal { + Some(d) => format!("{value}.{d:03} {unit}"), + None => format!("{value} {unit}"), + }; + ConnectionError::RequestTimeout { timeout: timeout_str } + } } error_messages! { ConceptError @@ -236,10 +269,8 @@ error_messages! { InternalError 3: "Unexpected request type for remote procedure call: {request_type}. This is either a version compatibility issue or a bug.", UnexpectedResponseType { response_type: String } = 4: "Unexpected response type for remote procedure call: {response_type}. This is either a version compatibility issue or a bug.", - UnknownServer { server: Address } = - 5: "Received replica at unrecognized server: {server}.", - EnumOutOfBounds { value: i32, enum_name: &'static str } = - 6: "Value '{value}' is out of bounds for enum '{enum_name}'.", + Unimplemented { details: String } = + 5: "Unimplemented feature: {details}.", } #[derive(Clone, PartialEq, Eq)] @@ -321,19 +352,23 @@ impl Error { } } - fn try_extracting_connection_error(status: &Status, code: &str) -> Option { - // TODO: We should probably catch more connection errors instead of wrapping them into - // ServerErrors. However, the most valuable information even for connection is inside - // stacktraces now. + fn try_extracting_connection_error_code(code: &str) -> Option { match code { "AUT2" | "AUT3" => Some(ConnectionError::TokenCredentialInvalid {}), + "SRV14" | "RFT1" | "CSV7" => Some(ConnectionError::ServerIsNotInitialised {}), + "CSV8" => Some(ConnectionError::ClusterReplicaNotPrimary {}), _ => None, } } - fn from_message(message: String) -> Self { - // TODO: Consider converting some of the messages to connection errors - Self::Other(message) + fn try_extracting_connection_error_message(message: &str) -> Option { + if is_rst_stream(message) || is_tcp_connect_error(message) { + Some(ConnectionError::ServerConnectionFailedNetworking { error: message.to_string() }) + } else if is_reading_body_from_connection_error(message) { + Some(ConnectionError::ServerConnectionIsClosedUnexpectedly) + } else { + None + } } fn parse_unavailable(status_message: &str) -> Error { @@ -342,11 +377,11 @@ impl Error { } else if status_message.contains("received corrupt message") { Error::Connection(ConnectionError::EncryptionSettingsMismatch) } else if status_message.contains("UnknownIssuer") { - Error::Connection(ConnectionError::SSLCertificateNotValidated) + Error::Connection(ConnectionError::SslCertificateNotValidated) } else if status_message.contains("Connection refused") { - Error::Connection(ConnectionError::ConnectionFailed) + Error::Connection(ConnectionError::ConnectionRefusedNetworking) } else { - Error::Connection(ConnectionError::ServerConnectionFailedStatusError { error: status_message.to_owned() }) + Error::Connection(ConnectionError::ServerConnectionFailedNetworking { error: status_message.to_owned() }) } } } @@ -397,6 +432,12 @@ impl From for Error { } } +impl From for Error { + fn from(error: MigrationError) -> Self { + Self::Migration(error) + } +} + impl From for Error { fn from(error: InternalError) -> Self { Self::Internal(error) @@ -413,45 +454,64 @@ impl From for Error { fn from(status: Status) -> Self { if let Ok(details) = status.check_error_details() { if let Some(bad_request) = details.bad_request() { - Self::Connection(ConnectionError::ServerConnectionFailedWithError { + return Self::Connection(ConnectionError::ServerConnectionFailedWithError { error: format!("{:?}", bad_request), - }) - } else if let Some(error_info) = details.error_info() { + }); + } + + let message = concat_source_messages(&status); + if let Some(connection_error) = Self::try_extracting_connection_error_message(&message) { + return Self::Connection(connection_error); + } + + if let Some(error_info) = details.error_info() { let code = error_info.reason.clone(); - if let Some(connection_error) = Self::try_extracting_connection_error(&status, &code) { - return Self::Connection(connection_error); + if let Some(connection_error) = Self::try_extracting_connection_error_code(&code) { + Self::Connection(connection_error) + } else { + let domain = error_info.domain.clone(); + let stack_trace = + details.debug_info().map(|debug_info| debug_info.stack_entries.clone()).unwrap_or_default(); + Self::Server(ServerError::new(code, domain, status.message().to_owned(), stack_trace)) } - let domain = error_info.domain.clone(); - let stack_trace = - if let Some(debug_info) = details.debug_info() { debug_info.stack_entries.clone() } else { vec![] }; - - Self::Server(ServerError::new(code, domain, status.message().to_owned(), stack_trace)) } else { - Self::from_message(concat_source_messages(&status)) + Self::Other(message) } } else { - if status.code() == Code::Unavailable { - Self::parse_unavailable(status.message()) - } else if status.code() == Code::Unknown - || is_rst_stream(&status) - || status.code() == Code::FailedPrecondition - || status.code() == Code::AlreadyExists - { - Self::Connection(ConnectionError::ServerConnectionFailedStatusError { - error: status.message().to_owned(), - }) - } else if status.code() == Code::Unimplemented { - Self::Connection(ConnectionError::RPCMethodUnavailable { message: status.message().to_owned() }) - } else { - Self::from_message(concat_source_messages(&status)) + match status.code() { + Code::Unavailable => Self::parse_unavailable(status.message()), + Code::Unknown | Code::FailedPrecondition | Code::AlreadyExists => { + Self::Connection(ConnectionError::ServerConnectionFailedNetworking { + error: status.message().to_owned(), + }) + } + Code::Unimplemented => { + Self::Connection(ConnectionError::RPCMethodUnavailable { message: status.message().to_owned() }) + } + _ => { + let message = concat_source_messages(&status); + Self::try_extracting_connection_error_message(&message) + .map(|error| Self::Connection(error)) + .unwrap_or_else(|| Self::Other(message)) + } } } } } -fn is_rst_stream(status: &Status) -> bool { +fn is_rst_stream(message: &str) -> bool { // "Received Rst Stream" occurs if the server is in the process of shutting down. - status.message().contains("Received Rst Stream") + message.contains("Received Rst Stream") +} + +fn is_reading_body_from_connection_error(message: &str) -> bool { + // This error can be returned when the server crashes + message.contains("error reading a body from connection") +} + +fn is_tcp_connect_error(message: &str) -> bool { + // No TCP connection + message.contains("tcp connect error") } fn concat_source_messages(status: &Status) -> String { diff --git a/rust/src/common/info.rs b/rust/src/common/info.rs index 23eb0e3e4b..c73d02f29d 100644 --- a/rust/src/common/info.rs +++ b/rust/src/common/info.rs @@ -17,26 +17,9 @@ * under the License. */ -use super::address::Address; - #[derive(Debug)] pub(crate) struct DatabaseInfo { pub(crate) name: String, - pub(crate) replicas: Vec, -} - -/// The metadata and state of an individual raft replica of a database. -#[derive(Debug)] -pub struct ReplicaInfo { - /// The server hosting this replica - pub server: Address, - /// Whether this is the primary replica of the raft cluster. - pub is_primary: bool, - /// Whether this is the preferred replica of the raft cluster. - /// If true, Operations which can be run on any replica will prefer to use this replica. - pub is_preferred: bool, - /// The raft protocol ‘term’ of this replica. - pub term: i64, } #[derive(Debug)] diff --git a/rust/src/common/mod.rs b/rust/src/common/mod.rs index d7ae057e05..3fb96295e3 100644 --- a/rust/src/common/mod.rs +++ b/rust/src/common/mod.rs @@ -18,6 +18,7 @@ */ pub use self::{ + address::{Address, Addresses}, error::Error, promise::{box_promise, BoxPromise, Promise}, query_options::QueryOptions, @@ -26,6 +27,7 @@ pub use self::{ }; pub(crate) mod address; +pub mod consistency_level; pub mod error; mod id; pub mod info; diff --git a/rust/src/common/transaction_options.rs b/rust/src/common/transaction_options.rs index 36c33edf88..fa593e66aa 100644 --- a/rust/src/common/transaction_options.rs +++ b/rust/src/common/transaction_options.rs @@ -19,8 +19,10 @@ use std::time::Duration; +use crate::consistency_level::ConsistencyLevel; + /// TypeDB transaction options. -/// `TransactionOptions` object can be used to override the default server behaviour for opened +/// `TransactionOptions` object can be used to override the default behaviour for opened /// transactions. /// /// # Examples @@ -28,12 +30,15 @@ use std::time::Duration; /// ```rust /// let options = TransactionOptions::new().transaction_timeout(Duration::from_secs(60)); /// ``` -#[derive(Clone, Copy, Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct TransactionOptions { /// If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. pub transaction_timeout: Option, /// If set, specifies how long the driver should wait if opening a transaction is blocked by an exclusive schema write lock. pub schema_lock_acquire_timeout: Option, + /// If set, specifies the requested consistency level of the transaction opening operation. + /// Affects only read transactions, as write and schema transactions require primary replicas. + pub read_consistency_level: Option, } impl TransactionOptions { @@ -50,4 +55,10 @@ impl TransactionOptions { pub fn schema_lock_acquire_timeout(self, timeout: Duration) -> Self { Self { schema_lock_acquire_timeout: Some(timeout), ..self } } + + /// If set, specifies the requested consistency level of the transaction opening operation. + /// Affects only read transactions, as write and schema transactions require primary replicas. + pub fn read_consistency_level(self, consistency_level: ConsistencyLevel) -> Self { + Self { read_consistency_level: Some(consistency_level), ..self } + } } diff --git a/rust/src/concept/mod.rs b/rust/src/concept/mod.rs index 49cf8f8b77..76d21b3c2c 100644 --- a/rust/src/concept/mod.rs +++ b/rust/src/concept/mod.rs @@ -262,7 +262,7 @@ impl Concept { } } - /// Check if this Concept represents a Type from the schema of the database. + /// Checks if this Concept represents a Type from the schema of the database. /// These are exactly: Entity Types, Relation Types, Role Types, and Attribute Types /// /// Equivalent to: @@ -276,27 +276,27 @@ impl Concept { } } - /// Check if this Concept represents an Entity Type from the schema of the database + /// Checks if this Concept represents an Entity Type from the schema of the database pub fn is_entity_type(&self) -> bool { matches!(self.get_category(), ConceptCategory::EntityType) } - /// Check if this Concept represents a Relation Type from the schema of the database + /// Checks if this Concept represents a Relation Type from the schema of the database pub fn is_relation_type(&self) -> bool { matches!(self.get_category(), ConceptCategory::RelationType) } - /// Check if this Concept represents a Role Type from the schema of the database + /// Checks if this Concept represents a Role Type from the schema of the database pub fn is_role_type(&self) -> bool { matches!(self.get_category(), ConceptCategory::RoleType) } - /// Check if this Concept represents an Attribute Type from the schema of the database + /// Checks if this Concept represents an Attribute Type from the schema of the database pub fn is_attribute_type(&self) -> bool { matches!(self.get_category(), ConceptCategory::AttributeType) } - /// Check if this Concept represents a stored database instance from the database. + /// Checks if this Concept represents a stored database instance from the database. /// These are exactly: Entity, Relation, and Attribute /// /// Equivalent to: @@ -310,72 +310,72 @@ impl Concept { } } - /// Check if this Concept represents an Entity instance from the database + /// Checks if this Concept represents an Entity instance from the database pub fn is_entity(&self) -> bool { matches!(self.get_category(), ConceptCategory::Entity) } - /// Check if this Concept represents an Relation instance from the database + /// Checks if this Concept represents an Relation instance from the database pub fn is_relation(&self) -> bool { matches!(self.get_category(), ConceptCategory::Relation) } - /// Check if this Concept represents an Attribute instance from the database + /// Checks if this Concept represents an Attribute instance from the database pub fn is_attribute(&self) -> bool { matches!(self.get_category(), ConceptCategory::Attribute) } - /// Check if this Concept represents a Value returned by the database + /// Checks if this Concept represents a Value returned by the database pub fn is_value(&self) -> bool { matches!(self.get_category(), ConceptCategory::Value) } - /// Check if this Concept holds a boolean as an AttributeType, an Attribute, or a Value + /// Checks if this Concept holds a boolean as an AttributeType, an Attribute, or a Value pub fn is_boolean(&self) -> bool { matches!(self.try_get_value_type(), Some(ValueType::Boolean)) } - /// Check if this Concept holds an integer as an AttributeType, an Attribute, or a Value + /// Checks if this Concept holds an integer as an AttributeType, an Attribute, or a Value pub fn is_integer(&self) -> bool { matches!(self.try_get_value_type(), Some(ValueType::Integer)) } - /// Check if this Concept holds a fixed-decimal as an AttributeType, an Attribute, or a Value + /// Checks if this Concept holds a fixed-decimal as an AttributeType, an Attribute, or a Value pub fn is_decimal(&self) -> bool { matches!(self.try_get_value_type(), Some(ValueType::Decimal)) } - /// Check if this Concept holds a double as an AttributeType, an Attribute, or a Value + /// Checks if this Concept holds a double as an AttributeType, an Attribute, or a Value pub fn is_double(&self) -> bool { matches!(self.try_get_value_type(), Some(ValueType::Double)) } - /// Check if this Concept holds a string as an AttributeType, an Attribute, or a Value + /// Checks if this Concept holds a string as an AttributeType, an Attribute, or a Value pub fn is_string(&self) -> bool { matches!(self.try_get_value_type(), Some(ValueType::String)) } - /// Check if this Concept holds a date as an AttributeType, an Attribute, or a Value + /// Checks if this Concept holds a date as an AttributeType, an Attribute, or a Value pub fn is_date(&self) -> bool { matches!(self.try_get_value_type(), Some(ValueType::Date)) } - /// Check if this Concept holds a datetime as an AttributeType, an Attribute, or a Value + /// Checks if this Concept holds a datetime as an AttributeType, an Attribute, or a Value pub fn is_datetime(&self) -> bool { matches!(self.try_get_value_type(), Some(ValueType::Datetime)) } - /// Check if this Concept holds a timezoned-datetime as an AttributeType, an Attribute, or a Value + /// Checks if this Concept holds a timezoned-datetime as an AttributeType, an Attribute, or a Value pub fn is_datetime_tz(&self) -> bool { matches!(self.try_get_value_type(), Some(ValueType::DatetimeTZ)) } - /// Check if this Concept holds a duration as an AttributeType, an Attribute, or a Value + /// Checks if this Concept holds a duration as an AttributeType, an Attribute, or a Value pub fn is_duration(&self) -> bool { matches!(self.try_get_value_type(), Some(ValueType::Duration)) } - /// Check if this Concept holds a struct as an AttributeType, an Attribute, or a Value + /// Checks if this Concept holds a struct as an AttributeType, an Attribute, or a Value pub fn is_struct(&self) -> bool { matches!(self.try_get_value_type(), Some(ValueType::Struct(_))) } diff --git a/rust/src/concept/value.rs b/rust/src/concept/value.rs index 37e830d504..26f9d8b376 100644 --- a/rust/src/concept/value.rs +++ b/rust/src/concept/value.rs @@ -267,8 +267,11 @@ impl fmt::Debug for Value { #[repr(C)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Decimal { - integer: i64, - fractional: u64, + /// The integer part of the decimal as normal signed 64 bit number + pub integer: i64, + /// The fractional part of the decimal, in multiples of 10^-19 (Decimal::FRACTIONAL_PART_DENOMINATOR). + /// This means that the smallest decimal representable is 10^-19, and up to 19 decimal places are supported. + pub fractional: u64, } impl Decimal { @@ -281,17 +284,6 @@ impl Decimal { assert!(fractional < Decimal::FRACTIONAL_PART_DENOMINATOR); Self { integer, fractional } } - - /// Get the integer part of the decimal as normal signed 64 bit number - pub fn integer_part(&self) -> i64 { - self.integer - } - - /// Get the fractional part of the decimal, in multiples of 10^-19 (Decimal::FRACTIONAL_PART_DENOMINATOR) - /// This means, the smallest decimal representable is 10^-19, and up to 19 decimal places are supported. - pub fn fractional_part(&self) -> u64 { - self.fractional - } } impl Neg for Decimal { @@ -345,7 +337,7 @@ impl fmt::Display for Decimal { impl fmt::Debug for Decimal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.fractional == 0 { - write!(f, "{}.0", self.integer_part())?; + write!(f, "{}.0", self.integer)?; } else { // count number of tailing 0's that don't have to be represented let mut tail_0s = 0; @@ -356,7 +348,7 @@ impl fmt::Debug for Decimal { } let fractional_width = Self::FRACTIONAL_PART_DENOMINATOR_LOG10 - tail_0s; - write!(f, "{}.{:0width$}dec", self.integer_part(), fractional, width = fractional_width as usize)?; + write!(f, "{}.{:0width$}dec", self.integer, fractional, width = fractional_width as usize)?; } Ok(()) } @@ -461,18 +453,6 @@ impl Duration { Self { months, days, nanos } } - pub fn months(&self) -> u32 { - self.months - } - - pub fn days(&self) -> u32 { - self.days - } - - pub fn nanos(&self) -> u64 { - self.nanos - } - fn is_empty(&self) -> bool { self.months == 0 && self.days == 0 && self.nanos == 0 } diff --git a/rust/src/connection/database/import_stream.rs b/rust/src/connection/database/import_stream.rs index 9897d75b2e..a3929426f8 100644 --- a/rust/src/connection/database/import_stream.rs +++ b/rust/src/connection/database/import_stream.rs @@ -24,7 +24,7 @@ use futures::{stream, StreamExt}; use typedb_protocol::migration; use crate::{ - common::{stream::Stream, Promise, Result}, + common::{Promise, Result}, connection::{message::DatabaseImportRequest, network::transmitter::DatabaseImportTransmitter}, promisify, resolve, }; diff --git a/rust/src/connection/driver_options.rs b/rust/src/connection/driver_options.rs index b16ddc5ece..50e4a7e7df 100644 --- a/rust/src/connection/driver_options.rs +++ b/rust/src/connection/driver_options.rs @@ -17,46 +17,120 @@ * under the License. */ -use std::{fs, path::Path}; +use std::{ + fs, + path::{Path, PathBuf}, + sync::Arc, + time::Duration, +}; -use tonic::transport::{Certificate, ClientTlsConfig}; +use crate::connection::driver_tls_config::DriverTlsConfig; -/// User connection settings for connecting to TypeDB. +// When changing these numbers, also update docs in DriverOptions +const DEFAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(2 * 60 * 60); // 2 hours +const DEFAULT_USE_REPLICATION: bool = true; +const DEFAULT_REDIRECT_FAILOVER_RETRIES: usize = 1; +const DEFAULT_DISCOVERY_FAILOVER_RETRIES: Option = None; + +/// TypeDB driver connection options. +/// `DriverOptions` object can be used to override the default driver behavior while connecting to +/// TypeDB. +/// +/// # Examples +/// +/// ```rust +/// let options = DriverOptions::new(DriverTlsConfig::default()).use_replication(false); +/// ``` #[derive(Debug, Clone)] pub struct DriverOptions { - is_tls_enabled: bool, - tls_config: Option, + /// Specifies the TLS configuration of the connection to TypeDB. + /// WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + /// Defaults to an enabled TLS configuration based on the system's native trust roots. + pub tls_config: DriverTlsConfig, + /// Specifies the maximum time to wait for a response to a unary RPC request. + /// This applies to operations like database creation, user management, and initial + /// transaction opening. It does NOT apply to operations within transactions (queries, commits). + /// Defaults to 2 hours. + // TODO: What if the server does not respond on queries/commits? + // Shall we apply the same or a different timeout? + pub request_timeout: Duration, + /// Specifies whether the connection to TypeDB can use cluster replicas provided by the server + /// or it should be limited to a single configured address. + /// Defaults to true. + pub use_replication: bool, + /// Limits the number of attempts to redirect a strongly consistent request to another + /// primary replica in case of a failure due to the change of replica roles. + /// Defaults to 1. + pub primary_failover_retries: usize, + /// Limits the number of driver attempts to discover a single working replica to perform an + /// operation in case of a replica unavailability. Every replica is tested once, which means + /// that at most: + /// - {limit} operations are performed if the limit <= the number of replicas. + /// - {number of replicas} operations are performed if the limit > the number of replicas. + /// - {number of replicas} operations are performed if the limit is None. + /// Affects every eventually consistent operation, including redirect failover, when the new + /// primary replica is unknown. + /// Defaults to None. + pub replica_discovery_attempts: Option, } impl DriverOptions { - /// Creates a credentials with username and password. Specifies the connection must use TLS - /// - /// # Arguments - /// - /// * `is_tls_enabled` — Specify whether the connection to TypeDB Server must be done over TLS. - /// * `tls_root_ca` — Path to the CA certificate to use for authenticating server certificates. - /// - /// # Examples - /// - /// ```rust - /// DriverOptions::new(true, Some(&path_to_ca)); - ///``` - pub fn new(is_tls_enabled: bool, tls_root_ca: Option<&Path>) -> crate::Result { - let tls_config = Some(if let Some(tls_root_ca) = tls_root_ca { - ClientTlsConfig::new().ca_certificate(Certificate::from_pem(fs::read_to_string(tls_root_ca)?)) - } else { - ClientTlsConfig::new().with_native_roots() - }); - - Ok(Self { is_tls_enabled, tls_config }) + /// Creates new `DriverOptions` to configure connections to TypeDB using custom TLS settings. + /// WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + pub fn new(tls_config: DriverTlsConfig) -> Self { + Self { tls_config, ..Default::default() } + } + + /// Override the existing TLS configuration. + /// WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + pub fn tls_config(mut self, tls_config: DriverTlsConfig) -> Self { + Self { tls_config, ..self } + } + + /// Specifies the maximum time to wait for a response to a unary RPC request. + /// This applies to operations like database creation, user management, and initial + /// transaction opening. It does NOT apply to operations within transactions (queries, commits). + /// Defaults to 2 hours. + pub fn request_timeout(self, request_timeout: Duration) -> Self { + Self { request_timeout, ..self } } - /// Retrieves whether TLS is enabled for the connection. - pub fn is_tls_enabled(&self) -> bool { - self.is_tls_enabled + /// Specifies whether the connection to TypeDB can use cluster replicas provided by the server + /// or it should be limited to the provided address. + /// If set to false, restricts the driver to only a single address. + pub fn use_replication(self, use_replication: bool) -> Self { + Self { use_replication, ..self } } - pub fn tls_config(&self) -> &Option { - &self.tls_config + /// Limits the number of attempts to redirect a strongly consistent request to another + /// primary replica in case of a failure due to the change of replica roles. + /// Defaults to 1. + pub fn primary_failover_retries(self, primary_failover_retries: usize) -> Self { + Self { primary_failover_retries, ..self } + } + + /// Limits the number of driver attempts to discover a single working replica to perform an + /// operation in case of a replica unavailability. Every replica is tested once, which means + /// that at most: + /// - {limit} operations are performed if the limit <= the number of replicas. + /// - {number of replicas} operations are performed if the limit > the number of replicas. + /// - {number of replicas} operations are performed if the limit is None. + /// Affects every eventually consistent operation, including redirect failover, when the new + /// primary replica is unknown. + /// Defaults to None. + pub fn replica_discovery_attempts(self, replica_discovery_attempts: Option) -> Self { + Self { replica_discovery_attempts, ..self } + } +} + +impl Default for DriverOptions { + fn default() -> Self { + Self { + tls_config: DriverTlsConfig::default(), + request_timeout: DEFAULT_REQUEST_TIMEOUT, + use_replication: DEFAULT_USE_REPLICATION, + primary_failover_retries: DEFAULT_REDIRECT_FAILOVER_RETRIES, + replica_discovery_attempts: DEFAULT_DISCOVERY_FAILOVER_RETRIES, + } } } diff --git a/rust/src/connection/driver_tls_config.rs b/rust/src/connection/driver_tls_config.rs new file mode 100644 index 0000000000..f138591a2c --- /dev/null +++ b/rust/src/connection/driver_tls_config.rs @@ -0,0 +1,121 @@ +/* + * 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. + */ + +use std::{ + fs, + path::{Path, PathBuf}, + sync::Arc, +}; + +use tonic::transport::{Certificate, ClientTlsConfig as NetworkTlsConfig}; + +/// TLS configuration for the TypeDB driver. +/// +/// `DriverTlsConfig` represents a fully constructed and validated TLS configuration. +/// If TLS is enabled, the underlying TLS config is built eagerly at construction time, +/// ensuring that no connection attempt can observe a partially-configured TLS state. +/// +/// The driver defaults to using TLS with **native system trust roots**. +/// This matches typical system and container deployments while still allowing +/// explicit opt-out or custom PKI configuration. +#[derive(Debug, Clone)] +pub struct DriverTlsConfig { + network_config: Option>, + root_ca_path: Option, +} + +impl DriverTlsConfig { + /// Disable TLS entirely (NOT recommended for production). + /// + /// Disabling TLS causes credentials and data to be transmitted in plaintext. + /// This should only be used in trusted, local, or test environments. + /// + /// # Examples + /// + /// ```rust + /// let tls = DriverTlsConfig::disabled(); + /// ``` + pub fn disabled() -> Self { + Self { network_config: None, root_ca_path: None } + } + + /// Default TLS using system trust roots. + /// + /// # Examples + /// + /// ```rust + /// let tls = DriverTlsConfig::enabled_with_native_root_ca(); + /// ``` + pub fn enabled_with_native_root_ca() -> Self { + let network_config = Some(Arc::new(NetworkTlsConfig::new().with_native_roots())); + Self { network_config, root_ca_path: None } + } + + /// TLS with a custom root CA. + /// + /// # Examples + /// + /// ```rust + /// let tls = DriverTlsConfig::enabled_with_root_ca("path/to/ca-certificate.pem").unwrap(); + /// ``` + pub fn enabled_with_root_ca(tls_root_ca: &Path) -> crate::Result { + let ca_certificate = Certificate::from_pem(fs::read_to_string(tls_root_ca)?); + let network_config = Some(Arc::new(NetworkTlsConfig::new().ca_certificate(ca_certificate))); + Ok(Self { network_config, root_ca_path: Some(tls_root_ca.to_path_buf()) }) + } + + /// Returns whether TLS is enabled in the configuration. + /// + /// # Examples + /// + /// ```rust + /// config.is_enabled() + /// ``` + pub fn is_enabled(&self) -> bool { + self.network_config.is_some() + } + + /// Returns the network TLS config object, if present. + /// + /// # Examples + /// + /// ```rust + /// config.network_config() + /// ``` + pub fn network_config(&self) -> Option<&NetworkTlsConfig> { + self.network_config.as_deref() + } + + /// Returns the custom root CA path, if provided. + /// + /// # Examples + /// + /// ```rust + /// config.root_ca_path() + /// ``` + pub fn root_ca_path(&self) -> Option<&Path> { + self.root_ca_path.as_deref() + } +} + +impl Default for DriverTlsConfig { + fn default() -> Self { + Self::enabled_with_native_root_ca() + } +} diff --git a/rust/src/connection/message.rs b/rust/src/connection/message.rs index 628e119946..ec726ba5e4 100644 --- a/rust/src/connection/message.rs +++ b/rust/src/connection/message.rs @@ -31,8 +31,9 @@ use crate::{ concept_row::ConceptRowHeader, QueryType, }, - common::{address::Address, info::DatabaseInfo, RequestID}, + common::{info::DatabaseInfo, RequestID}, concept::Concept, + connection::{server_replica::ServerReplica, server_version::ServerVersion}, error::ServerError, info::UserInfo, Credentials, QueryOptions, TransactionOptions, TransactionType, @@ -43,6 +44,10 @@ pub(super) enum Request { ConnectionOpen { driver_lang: String, driver_version: String, credentials: Credentials }, ServersAll, + ServersGet, + ServersRegister { replica_id: u64, address: String }, + ServersDeregister { replica_id: u64 }, + ServerVersion, DatabasesAll, DatabaseGet { database_name: String }, @@ -70,11 +75,19 @@ pub(super) enum Response { ConnectionOpen { connection_id: Uuid, server_duration_millis: u64, - databases: Vec, + servers: Vec, }, ServersAll { - servers: Vec
, + servers: Vec, + }, + ServersGet { + server: ServerReplica, + }, + ServersRegister, + ServersDeregister, + ServerVersion { + server_version: ServerVersion, }, DatabasesContains { diff --git a/rust/src/connection/mod.rs b/rust/src/connection/mod.rs index 25a8d4ecaa..e387064610 100644 --- a/rust/src/connection/mod.rs +++ b/rust/src/connection/mod.rs @@ -18,13 +18,19 @@ */ pub(crate) use self::transaction_stream::TransactionStream; -pub use self::{credentials::Credentials, driver_options::DriverOptions}; +pub use self::{ + credentials::Credentials, + driver_options::DriverOptions, + driver_tls_config::DriverTlsConfig, + server::{server_replica, server_version}, +}; mod credentials; pub(crate) mod database; mod driver_options; +mod driver_tls_config; mod message; mod network; pub(crate) mod runtime; -pub(crate) mod server_connection; +pub(crate) mod server; pub(crate) mod transaction_stream; diff --git a/rust/src/connection/network/channel.rs b/rust/src/connection/network/channel.rs index d4d64fecd9..10199060b7 100644 --- a/rust/src/connection/network/channel.rs +++ b/rust/src/connection/network/channel.rs @@ -35,7 +35,8 @@ use tonic::{ use crate::{ common::{address::Address, Result, StdResult}, - Credentials, DriverOptions, + error::ConnectionError, + Credentials, DriverOptions, Error, }; type ResponseFuture = InterceptorResponseFuture; @@ -54,11 +55,22 @@ pub(super) fn open_callcred_channel( credentials: Credentials, driver_options: DriverOptions, ) -> Result<(CallCredChannel, Arc)> { - let mut builder = Channel::builder(address.into_uri()); - if driver_options.is_tls_enabled() { - let tls_config = - driver_options.tls_config().clone().expect("TLS config object must be set when TLS is enabled"); - builder = builder.tls_config(tls_config)?; + let is_tls_enabled = driver_options.tls_config.is_enabled(); + let connection_scheme = match is_tls_enabled { + true => http::uri::Scheme::HTTPS, + false => http::uri::Scheme::HTTP, + }; + if let Some(address_scheme) = address.uri_scheme() { + if address_scheme != &connection_scheme { + return Err(Error::Connection(ConnectionError::SchemeTlsSettingsMismatch { + scheme: address_scheme.clone(), + is_tls_enabled, + })); + } + } + let mut builder = Channel::builder(address.with_scheme(connection_scheme).into_uri()); + if let Some(tls_config) = driver_options.tls_config.network_config() { + builder = builder.tls_config(tls_config.clone())?; } builder = builder.keep_alive_while_idle(true).http2_keep_alive_interval(Duration::from_secs(3)); let channel = builder.connect_lazy(); diff --git a/rust/src/connection/network/proto/concept.rs b/rust/src/connection/network/proto/concept.rs index 685f413a89..b06dd73ab0 100644 --- a/rust/src/connection/network/proto/concept.rs +++ b/rust/src/connection/network/proto/concept.rs @@ -21,7 +21,6 @@ use std::{collections::HashMap, str::FromStr}; use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, TimeZone as ChronoTimeZone}; use chrono_tz::Tz; -use futures::TryFutureExt; use itertools::Itertools; use typedb_protocol::{ concept, diff --git a/rust/src/connection/network/proto/database.rs b/rust/src/connection/network/proto/database.rs index 306845bca6..935a26e392 100644 --- a/rust/src/connection/network/proto/database.rs +++ b/rust/src/connection/network/proto/database.rs @@ -17,31 +17,13 @@ * under the License. */ -use itertools::Itertools; -use typedb_protocol::{database_replicas::Replica as ReplicaProto, DatabaseReplicas as DatabaseProto}; +use typedb_protocol::Database as DatabaseProto; use super::TryFromProto; -use crate::common::{ - info::{DatabaseInfo, ReplicaInfo}, - Result, -}; +use crate::common::{info::DatabaseInfo, Result}; impl TryFromProto for DatabaseInfo { fn try_from_proto(proto: DatabaseProto) -> Result { - Ok(Self { - name: proto.name, - replicas: proto.replicas.into_iter().map(ReplicaInfo::try_from_proto).try_collect()?, - }) - } -} - -impl TryFromProto for ReplicaInfo { - fn try_from_proto(proto: ReplicaProto) -> Result { - Ok(Self { - server: proto.address.parse()?, - is_primary: proto.primary, - is_preferred: proto.preferred, - term: proto.term, - }) + Ok(Self { name: proto.name }) } } diff --git a/rust/src/connection/network/proto/message.rs b/rust/src/connection/network/proto/message.rs index 8a55c1b71e..9a9a877bf3 100644 --- a/rust/src/connection/network/proto/message.rs +++ b/rust/src/connection/network/proto/message.rs @@ -19,7 +19,7 @@ use itertools::Itertools; use typedb_protocol::{ - authentication, connection, database, database_manager, migration, query::initial_res::Res, server_manager, + authentication, connection, database, database_manager, migration, query::initial_res::Res, server, server_manager, transaction, user, user_manager, ExtensionVersion::Extension, Version::Version, }; use uuid::Uuid; @@ -29,9 +29,13 @@ use crate::{ analyze::pipeline::Pipeline, answer::{concept_document::ConceptDocumentHeader, concept_row::ConceptRowHeader, QueryType}, common::{info::DatabaseInfo, RequestID, Result}, - connection::message::{ - AnalyzeResponse, DatabaseExportResponse, DatabaseImportRequest, QueryRequest, QueryResponse, Request, Response, - TransactionRequest, TransactionResponse, + connection::{ + message::{ + AnalyzeResponse, DatabaseExportResponse, DatabaseImportRequest, QueryRequest, QueryResponse, Request, + Response, TransactionRequest, TransactionResponse, + }, + server_replica::ServerReplica, + server_version::ServerVersion, }, error::{ConnectionError, InternalError, ServerError}, info::UserInfo, @@ -62,6 +66,42 @@ impl TryIntoProto for Request { } } +impl TryIntoProto for Request { + fn try_into_proto(self) -> Result { + match self { + Self::ServersGet => Ok(server_manager::get::Req {}), + other => Err(InternalError::UnexpectedRequestType { request_type: format!("{other:?}") }.into()), + } + } +} + +impl TryIntoProto for Request { + fn try_into_proto(self) -> Result { + match self { + Self::ServersRegister { replica_id, address } => Ok(server_manager::register::Req { replica_id, address }), + other => Err(InternalError::UnexpectedRequestType { request_type: format!("{other:?}") }.into()), + } + } +} + +impl TryIntoProto for Request { + fn try_into_proto(self) -> Result { + match self { + Self::ServersDeregister { replica_id } => Ok(server_manager::deregister::Req { replica_id }), + other => Err(InternalError::UnexpectedRequestType { request_type: format!("{other:?}") }.into()), + } + } +} + +impl TryIntoProto for Request { + fn try_into_proto(self) -> Result { + match self { + Self::ServerVersion => Ok(server::version::Req {}), + other => Err(InternalError::UnexpectedRequestType { request_type: format!("{other:?}") }.into()), + } + } +} + impl TryIntoProto for Request { fn try_into_proto(self) -> Result { match self { @@ -290,15 +330,24 @@ impl TryIntoProto for Credentials { impl TryFromProto for Response { fn try_from_proto(proto: connection::open::Res) -> Result { - let mut database_infos = Vec::new(); - for database_info_proto in proto.databases_all.expect("Expected databases data").databases { - database_infos.push(DatabaseInfo::try_from_proto(database_info_proto)?); - } + let servers = proto + .servers_all + .ok_or(ConnectionError::MissingResponseField { field: "servers_all" })? + .servers + .into_iter() + .map(|server_proto| ServerReplica::try_from_proto(server_proto)) + .try_collect()?; Ok(Self::ConnectionOpen { - connection_id: Uuid::from_slice(proto.connection_id.expect("Expected connection id").id.as_slice()) - .unwrap(), + connection_id: Uuid::from_slice( + proto + .connection_id + .ok_or(ConnectionError::MissingResponseField { field: "connection_id" })? + .id + .as_slice(), + ) + .expect("Expected connection id creation"), server_duration_millis: proto.server_duration_millis, - databases: database_infos, + servers, }) } } @@ -306,11 +355,39 @@ impl TryFromProto for Response { impl TryFromProto for Response { fn try_from_proto(proto: server_manager::all::Res) -> Result { let server_manager::all::Res { servers } = proto; - let servers = servers.into_iter().map(|server| server.address.parse()).try_collect()?; + let servers = servers.into_iter().map(|server| ServerReplica::try_from_proto(server)).try_collect()?; Ok(Self::ServersAll { servers }) } } +impl TryFromProto for Response { + fn try_from_proto(proto: server_manager::get::Res) -> Result { + let server_manager::get::Res { server } = proto; + let server = + ServerReplica::try_from_proto(server.ok_or(ConnectionError::MissingResponseField { field: "server" })?)?; + Ok(Self::ServersGet { server }) + } +} + +impl TryFromProto for Response { + fn try_from_proto(_proto: server_manager::register::Res) -> Result { + Ok(Self::ServersRegister) + } +} + +impl TryFromProto for Response { + fn try_from_proto(_proto: server_manager::deregister::Res) -> Result { + Ok(Self::ServersDeregister) + } +} + +impl TryFromProto for Response { + fn try_from_proto(proto: server::version::Res) -> Result { + let server::version::Res { distribution, version } = proto; + Ok(Self::ServerVersion { server_version: ServerVersion { distribution, version } }) + } +} + impl TryFromProto for Response { fn try_from_proto(proto: database_manager::all::Res) -> Result { let database_manager::all::Res { databases } = proto; @@ -336,7 +413,11 @@ impl FromProto for Response { impl TryFromProto for Response { fn try_from_proto(proto: database_manager::create::Res) -> Result { - Ok(Self::DatabaseCreate { database: DatabaseInfo::try_from_proto(proto.database.unwrap())? }) + Ok(Self::DatabaseCreate { + database: DatabaseInfo::try_from_proto( + proto.database.ok_or(ConnectionError::MissingResponseField { field: "database" })?, + )?, + }) } } diff --git a/rust/src/connection/network/proto/mod.rs b/rust/src/connection/network/proto/mod.rs index 91b9910a23..e09641a6ef 100644 --- a/rust/src/connection/network/proto/mod.rs +++ b/rust/src/connection/network/proto/mod.rs @@ -24,6 +24,7 @@ mod common; mod concept; mod database; mod message; +mod server; mod user; pub(super) trait IntoProto { diff --git a/rust/src/connection/network/proto/server.rs b/rust/src/connection/network/proto/server.rs new file mode 100644 index 0000000000..5289ec9c8c --- /dev/null +++ b/rust/src/connection/network/proto/server.rs @@ -0,0 +1,73 @@ +/* + * 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. + */ + +use typedb_protocol::{ + server::{version::Res as VersionProto, ReplicaStatus as ReplicaStatusProto}, + Server as ServerProto, +}; + +use super::TryFromProto; +use crate::{ + common::Result, + connection::{ + server_replica::{ReplicaRole, ReplicaStatus, ServerReplica}, + server_version::ServerVersion, + }, + error::ConnectionError, +}; + +impl TryFromProto for ServerReplica { + fn try_from_proto(proto: ServerProto) -> Result { + let replica_status = proto.replica_status.map(|status| ReplicaStatus::try_from_proto(status)).transpose()?; + match proto.connection_address { + Some(address) => Ok(ServerReplica::available_from_private(address.parse()?, replica_status)), + None => Ok(ServerReplica::Unavailable { replica_status }), + } + } +} + +impl TryFromProto for ReplicaStatus { + fn try_from_proto(proto: ReplicaStatusProto) -> Result { + Ok(Self { + id: proto.replica_id, + role: Option::::try_from_proto(proto.replica_role)?, + term: proto.term, + }) + } +} + +impl TryFromProto> for Option { + fn try_from_proto(replica_role: Option) -> Result> { + let Some(replica_role) = replica_role else { + return Ok(None); + }; + match replica_role { + 0 => Ok(Some(ReplicaRole::Primary)), + 1 => Ok(Some(ReplicaRole::Candidate)), + 2 => Ok(Some(ReplicaRole::Secondary)), + _ => Err(ConnectionError::UnexpectedReplicaRole { replica_role }.into()), + } + } +} + +impl TryFromProto for ServerVersion { + fn try_from_proto(proto: VersionProto) -> Result { + Ok(Self { distribution: proto.distribution, version: proto.version }) + } +} diff --git a/rust/src/connection/network/stub.rs b/rust/src/connection/network/stub.rs index b13487850b..95f1aa01ff 100644 --- a/rust/src/connection/network/stub.rs +++ b/rust/src/connection/network/stub.rs @@ -17,7 +17,7 @@ * under the License. */ -use std::sync::Arc; +use std::{sync::Arc, time::Duration}; use futures::{future::BoxFuture, FutureExt, TryFutureExt}; use tokio::sync::mpsc::{unbounded_channel as unbounded_async, UnboundedSender}; @@ -25,7 +25,7 @@ use tokio_stream::wrappers::UnboundedReceiverStream; use tonic::{Response, Status, Streaming}; use tracing::{debug, trace}; use typedb_protocol::{ - connection, database, database_manager, migration, server_manager, transaction, + connection, database, database_manager, migration, server, server_manager, transaction, type_db_client::TypeDbClient as GRPC, user, user_manager, }; @@ -41,11 +41,16 @@ type TonicResult = StdResult, Status>; pub(super) struct RPCStub { grpc: GRPC, call_credentials: Option>, + request_timeout: Duration, } impl RPCStub { - pub(super) async fn new(channel: Channel, call_credentials: Option>) -> Self { - Self { grpc: GRPC::new(channel), call_credentials } + pub(super) async fn new( + channel: Channel, + call_credentials: Option>, + request_timeout: Duration, + ) -> Self { + Self { grpc: GRPC::new(channel), call_credentials, request_timeout } } async fn call_with_auto_renew_token(&mut self, call: F) -> Result @@ -89,6 +94,28 @@ impl RPCStub { self.single(|this| Box::pin(this.grpc.servers_all(req.clone()))).await } + pub(super) async fn servers_get(&mut self, req: server_manager::get::Req) -> Result { + self.single(|this| Box::pin(this.grpc.servers_get(req.clone()))).await + } + + pub(super) async fn servers_register( + &mut self, + req: server_manager::register::Req, + ) -> Result { + self.single(|this| Box::pin(this.grpc.servers_register(req.clone()))).await + } + + pub(super) async fn servers_deregister( + &mut self, + req: server_manager::deregister::Req, + ) -> Result { + self.single(|this| Box::pin(this.grpc.servers_deregister(req.clone()))).await + } + + pub(super) async fn server_version(&mut self, req: server::version::Req) -> Result { + self.single(|this| Box::pin(this.grpc.server_version(req.clone()))).await + } + pub(super) async fn databases_all( &mut self, req: database_manager::all::Req, @@ -204,11 +231,21 @@ impl RPCStub { self.single(|this| Box::pin(this.grpc.users_delete(req.clone()))).await } + pub(super) fn request_timeout(&self) -> Duration { + self.request_timeout + } + async fn single(&mut self, call: F) -> Result where for<'a> F: Fn(&'a mut Self) -> BoxFuture<'a, TonicResult> + Send + Sync, R: 'static, { - self.call_with_auto_renew_token(|this| Box::pin(call(this).map(|r| Ok(r?.into_inner())))).await + let timeout = self.request_timeout; + tokio::time::timeout( + timeout, + self.call_with_auto_renew_token(|this| Box::pin(call(this).map(|r| Ok(r?.into_inner())))), + ) + .await + .map_err(|_| ConnectionError::request_timeout(timeout))? } } diff --git a/rust/src/connection/network/transmitter/rpc.rs b/rust/src/connection/network/transmitter/rpc.rs index 92934e6565..bcac7264e5 100644 --- a/rust/src/connection/network/transmitter/rpc.rs +++ b/rust/src/connection/network/transmitter/rpc.rs @@ -17,6 +17,8 @@ * under the License. */ +use std::time::Duration; + use futures::StreamExt; use tokio::{ select, @@ -57,9 +59,10 @@ impl RPCTransmitter { ) -> Result { let (request_sink, request_source) = unbounded_async(); let (shutdown_sink, shutdown_source) = unbounded_async(); + let request_timeout = driver_options.request_timeout; runtime.run_blocking(async move { let (channel, call_cred) = open_callcred_channel(address, credentials, driver_options)?; - let rpc = RPCStub::new(channel, Some(call_cred)).await; + let rpc = RPCStub::new(channel, Some(call_cred), request_timeout).await; tokio::spawn(Self::dispatcher_loop(rpc, request_source, shutdown_source)); Ok::<(), Error>(()) })?; @@ -122,6 +125,16 @@ impl RPCTransmitter { } Request::ServersAll => rpc.servers_all(request.try_into_proto()?).await.and_then(Response::try_from_proto), + Request::ServersGet => rpc.servers_get(request.try_into_proto()?).await.and_then(Response::try_from_proto), + Request::ServersRegister { .. } => { + rpc.servers_register(request.try_into_proto()?).await.and_then(Response::try_from_proto) + } + Request::ServersDeregister { .. } => { + rpc.servers_deregister(request.try_into_proto()?).await.and_then(Response::try_from_proto) + } + Request::ServerVersion => { + rpc.server_version(request.try_into_proto()?).await.and_then(Response::try_from_proto) + } Request::DatabasesAll => { rpc.databases_all(request.try_into_proto()?).await.and_then(Response::try_from_proto) @@ -150,37 +163,15 @@ impl RPCTransmitter { rpc.database_type_schema(request.try_into_proto()?).await.map(Response::from_proto) } Request::DatabaseExport { .. } => { - let mut response_source = rpc.database_export(request.try_into_proto()?).await?; + let response_source = rpc.database_export(request.try_into_proto()?).await?; Ok(Response::DatabaseExportStream { response_source }) } Request::Transaction(transaction_request) => { - let req = transaction_request.into_proto(); - let open_request_id = RequestID::from(req.req_id.clone()); - let (request_sink, mut response_source) = rpc.transaction(req).await?; - match response_source.next().await { - Some(Ok(transaction::Server { server: Some(Server::Res(res)) })) => { - match TransactionResponse::try_from_proto(res) { - Ok(TransactionResponse::Open { server_duration_millis }) => { - Ok(Response::TransactionStream { - open_request_id, - request_sink, - response_source, - server_duration_millis, - }) - } - Err(error) => Err(error), - Ok(other) => Err(Error::Connection(ConnectionError::UnexpectedResponse { - response: format!("{other:?}"), - })), - } - } - Some(Ok(other)) => { - Err(Error::Connection(ConnectionError::UnexpectedResponse { response: format!("{other:?}") })) - } - Some(Err(status)) => Err(status.into()), - None => Err(Error::Connection(ConnectionError::UnexpectedConnectionClose)), - } + let timeout = rpc.request_timeout(); + tokio::time::timeout(timeout, Self::open_transaction(rpc, transaction_request)) + .await + .map_err(|_| ConnectionError::request_timeout(timeout))? } Request::UsersAll => rpc.users_all(request.try_into_proto()?).await.map(Response::from_proto), @@ -193,4 +184,34 @@ impl RPCTransmitter { Request::UsersGet { .. } => rpc.users_get(request.try_into_proto()?).await.map(Response::from_proto), } } + + async fn open_transaction( + mut rpc: RPCStub, + transaction_request: crate::connection::message::TransactionRequest, + ) -> Result { + let req = transaction_request.into_proto(); + let open_request_id = RequestID::from(req.req_id.clone()); + let (request_sink, mut response_source) = rpc.transaction(req).await?; + match response_source.next().await { + Some(Ok(transaction::Server { server: Some(Server::Res(res)) })) => { + match TransactionResponse::try_from_proto(res) { + Ok(TransactionResponse::Open { server_duration_millis }) => Ok(Response::TransactionStream { + open_request_id, + request_sink, + response_source, + server_duration_millis, + }), + Err(error) => Err(error), + Ok(other) => { + Err(Error::Connection(ConnectionError::UnexpectedResponse { response: format!("{other:?}") })) + } + } + } + Some(Ok(other)) => { + Err(Error::Connection(ConnectionError::UnexpectedResponse { response: format!("{other:?}") })) + } + Some(Err(status)) => Err(status.into()), + None => Err(Error::Connection(ConnectionError::UnexpectedConnectionClose)), + } + } } diff --git a/rust/src/connection/network/transmitter/transaction.rs b/rust/src/connection/network/transmitter/transaction.rs index d063db3a12..b4151509e3 100644 --- a/rust/src/connection/network/transmitter/transaction.rs +++ b/rust/src/connection/network/transmitter/transaction.rs @@ -38,7 +38,7 @@ use tokio::sync::oneshot::channel as oneshot; use tokio::{ select, sync::{ - mpsc::{error::SendError, unbounded_channel as unbounded_async, UnboundedReceiver, UnboundedSender}, + mpsc::{unbounded_channel as unbounded_async, UnboundedReceiver, UnboundedSender}, oneshot::{channel as oneshot_async, Sender as AsyncOneshotSender}, }, task, @@ -299,7 +299,7 @@ impl TransactionTransmitter { shutdown_sink: UnboundedSender<()>, shutdown_signal: UnboundedReceiver<()>, ) { - let mut collector = ResponseCollector { + let collector = ResponseCollector { callbacks: Default::default(), is_open, error, diff --git a/rust/src/connection/server/mod.rs b/rust/src/connection/server/mod.rs new file mode 100644 index 0000000000..b068d0a425 --- /dev/null +++ b/rust/src/connection/server/mod.rs @@ -0,0 +1,23 @@ +/* + * 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. + */ + +pub(crate) mod server_connection; +pub(crate) mod server_manager; +pub mod server_replica; +pub mod server_version; diff --git a/rust/src/connection/server_connection.rs b/rust/src/connection/server/server_connection.rs similarity index 80% rename from rust/src/connection/server_connection.rs rename to rust/src/connection/server/server_connection.rs index f257436c6b..e2b72a7112 100644 --- a/rust/src/connection/server_connection.rs +++ b/rust/src/connection/server/server_connection.rs @@ -38,11 +38,13 @@ use crate::{ DatabaseExportTransmitter, DatabaseImportTransmitter, RPCTransmitter, TransactionTransmitter, }, runtime::BackgroundRuntime, + server_replica::ServerReplica, + server_version::ServerVersion, TransactionStream, }, error::{ConnectionError, InternalError}, info::{DatabaseInfo, UserInfo}, - Credentials, DriverOptions, TransactionOptions, TransactionType, + Credentials, DriverOptions, Result, TransactionOptions, TransactionType, }; #[derive(Clone)] @@ -64,13 +66,11 @@ impl ServerConnection { driver_options: DriverOptions, driver_lang: &str, driver_version: &str, - ) -> crate::Result<(Self, Vec)> { - Self::validate_tls(&address, &driver_options)?; - + ) -> Result<(Self, Vec)> { let username = credentials.username().to_string(); let request_transmitter = Arc::new(RPCTransmitter::start(address, credentials.clone(), driver_options, &background_runtime)?); - let (connection_id, latency, database_info) = + let (connection_id, latency, servers) = Self::open_connection(&request_transmitter, driver_lang, driver_version, credentials).await?; let latency_tracker = LatencyTracker::new(latency); let server_connection = Self { @@ -81,7 +81,7 @@ impl ServerConnection { shutdown_senders: Default::default(), latency_tracker, }; - Ok((server_connection, database_info)) + Ok((server_connection, servers)) } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] @@ -90,7 +90,7 @@ impl ServerConnection { driver_lang: &str, driver_version: &str, credentials: Credentials, - ) -> crate::Result<(Uuid, Duration, Vec)> { + ) -> Result<(Uuid, Duration, Vec)> { let message = Request::ConnectionOpen { driver_lang: driver_lang.to_owned(), driver_version: driver_version.to_owned(), @@ -99,66 +99,76 @@ impl ServerConnection { let request_time = Instant::now(); match request_transmitter.request(message).await? { - Response::ConnectionOpen { connection_id, server_duration_millis, databases: database_info } => { + Response::ConnectionOpen { connection_id, server_duration_millis, servers } => { let latency = Instant::now().duration_since(request_time) - Duration::from_millis(server_duration_millis); - Ok((connection_id, latency, database_info)) + Ok((connection_id, latency, servers)) } other => Err(ConnectionError::UnexpectedResponse { response: format!("{other:?}") }.into()), } } - pub fn username(&self) -> &str { + pub(crate) fn username(&self) -> &str { self.username.as_str() } + pub(crate) fn force_close(&self) -> Result { + for sender in self.shutdown_senders.lock().unwrap().drain(..) { + let _ = sender.send(()); + } + self.request_transmitter.force_close() + } + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - async fn request(&self, request: Request) -> crate::Result { - if !self.background_runtime.is_open() { - return Err(ConnectionError::ServerConnectionIsClosed.into()); + pub(crate) async fn servers_all(&self) -> Result> { + match self.request(Request::ServersAll).await? { + Response::ServersAll { servers } => Ok(servers), + other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), } - self.request_transmitter.request(request).await } - fn request_blocking(&self, request: Request) -> crate::Result { - if !self.background_runtime.is_open() { - return Err(ConnectionError::ServerConnectionIsClosed.into()); + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub(crate) async fn servers_get(&self) -> Result { + match self.request(Request::ServersGet).await? { + Response::ServersGet { server } => Ok(server), + other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), } - self.request_transmitter.request_blocking(request) } - pub(crate) fn force_close(&self) -> crate::Result { - for sender in self.shutdown_senders.lock().unwrap().drain(..) { - let _ = sender.send(()); + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub(crate) async fn servers_register(&self, replica_id: u64, address: String) -> Result { + match self.request(Request::ServersRegister { replica_id, address }).await? { + Response::ServersRegister => Ok(()), + other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), } - self.request_transmitter.force_close() } - pub(crate) fn servers_all(&self) -> crate::Result> { - match self.request_blocking(Request::ServersAll)? { - Response::ServersAll { servers } => Ok(servers), + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub(crate) async fn servers_deregister(&self, replica_id: u64) -> Result { + match self.request(Request::ServersDeregister { replica_id }).await? { + Response::ServersDeregister => Ok(()), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), } } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn all_databases(&self) -> crate::Result> { - match self.request(Request::DatabasesAll).await? { - Response::DatabasesAll { databases } => Ok(databases), + pub(crate) async fn version(&self) -> Result { + match self.request(Request::ServerVersion).await? { + Response::ServerVersion { server_version: version } => Ok(version), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), } } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn get_database_replicas(&self, database_name: String) -> crate::Result { - match self.request(Request::DatabaseGet { database_name }).await? { - Response::DatabaseGet { database } => Ok(database), + pub(crate) async fn all_databases(&self) -> Result> { + match self.request(Request::DatabasesAll).await? { + Response::DatabasesAll { databases } => Ok(databases), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), } } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn contains_database(&self, database_name: String) -> crate::Result { + pub(crate) async fn contains_database(&self, database_name: String) -> Result { match self.request(Request::DatabasesContains { database_name }).await? { Response::DatabasesContains { contains } => Ok(contains), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), @@ -166,19 +176,23 @@ impl ServerConnection { } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn create_database(&self, database_name: String) -> crate::Result { + pub(crate) async fn get_database(&self, database_name: String) -> Result { + match self.request(Request::DatabaseGet { database_name }).await? { + Response::DatabaseGet { database } => Ok(database), + other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), + } + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub(crate) async fn create_database(&self, database_name: String) -> Result { match self.request(Request::DatabaseCreate { database_name }).await? { - Response::DatabaseCreate { database } => Ok(database), + Response::DatabaseCreate { .. } => Ok(()), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), } } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn import_database( - &self, - database_name: String, - schema: String, - ) -> crate::Result { + pub(crate) async fn import_database(&self, database_name: String, schema: String) -> Result { match self .request(Request::DatabaseImport(DatabaseImportRequest::Initial { name: database_name, schema })) .await? @@ -197,13 +211,13 @@ impl ServerConnection { } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn delete_database(&self, database_name: String) -> crate::Result { + pub(crate) async fn delete_database(&self, database_name: String) -> Result { self.request(Request::DatabaseDelete { database_name }).await?; Ok(()) } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn database_schema(&self, database_name: String) -> crate::Result { + pub(crate) async fn database_schema(&self, database_name: String) -> Result { match self.request(Request::DatabaseSchema { database_name }).await? { Response::DatabaseSchema { schema } => Ok(schema), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), @@ -211,7 +225,7 @@ impl ServerConnection { } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn database_type_schema(&self, database_name: String) -> crate::Result { + pub(crate) async fn database_type_schema(&self, database_name: String) -> Result { match self.request(Request::DatabaseTypeSchema { database_name }).await? { Response::DatabaseTypeSchema { schema } => Ok(schema), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), @@ -219,7 +233,7 @@ impl ServerConnection { } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn database_export(&self, database_name: String) -> crate::Result { + pub(crate) async fn database_export(&self, database_name: String) -> Result { match self.request(Request::DatabaseExport { database_name }).await? { Response::DatabaseExportStream { response_source } => { let transmitter = DatabaseExportTransmitter::new(self.background_runtime.clone(), response_source); @@ -238,7 +252,7 @@ impl ServerConnection { database_name: &str, transaction_type: TransactionType, options: TransactionOptions, - ) -> crate::Result { + ) -> Result { let network_latency = self.latency_tracker.current_latency(); let open_request_start = Instant::now(); @@ -246,13 +260,13 @@ impl ServerConnection { .request(Request::Transaction(TransactionRequest::Open { database: database_name.to_owned(), transaction_type, - options, + options: options.clone(), network_latency, })) .await? { Response::TransactionStream { - open_request_id: request_id, + open_request_id: _, request_sink, response_source, server_duration_millis, @@ -272,7 +286,7 @@ impl ServerConnection { } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn all_users(&self) -> crate::Result> { + pub(crate) async fn all_users(&self) -> Result> { match self.request(Request::UsersAll).await? { Response::UsersAll { users } => Ok(users), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), @@ -280,7 +294,7 @@ impl ServerConnection { } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn get_user(&self, name: String) -> crate::Result> { + pub(crate) async fn get_user(&self, name: String) -> Result> { match self.request(Request::UsersGet { name }).await? { Response::UsersGet { user } => Ok(user), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), @@ -288,7 +302,7 @@ impl ServerConnection { } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn contains_user(&self, name: String) -> crate::Result { + pub(crate) async fn contains_user(&self, name: String) -> Result { match self.request(Request::UsersContains { name }).await? { Response::UsersContain { contains } => Ok(contains), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), @@ -296,7 +310,7 @@ impl ServerConnection { } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn create_user(&self, name: String, password: String) -> crate::Result { + pub(crate) async fn create_user(&self, name: String, password: String) -> Result { match self.request(Request::UsersCreate { user: UserInfo { name, password: Some(password) } }).await? { Response::UsersCreate => Ok(()), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), @@ -304,7 +318,7 @@ impl ServerConnection { } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn update_password(&self, name: String, password: String) -> crate::Result { + pub(crate) async fn update_password(&self, name: String, password: String) -> Result { match self .request(Request::UsersUpdate { username: name, @@ -318,30 +332,26 @@ impl ServerConnection { } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn delete_user(&self, name: String) -> crate::Result { + pub(crate) async fn delete_user(&self, name: String) -> Result { match self.request(Request::UsersDelete { name }).await? { Response::UsersDelete => Ok(()), other => Err(InternalError::UnexpectedResponseType { response_type: format!("{other:?}") }.into()), } } - fn validate_tls(address: &Address, driver_options: &DriverOptions) -> crate::Result { - match driver_options.is_tls_enabled() { - true => { - if driver_options.tls_config().is_none() { - return Err(ConnectionError::AbsentTlsConfigForTlsConnection {}.into()); - } - if !address.is_https() { - return Err(ConnectionError::TlsConnectionWithoutHttps {}.into()); - } - } - false => { - if address.is_https() { - return Err(ConnectionError::NonTlsConnectionWithHttps {}.into()); - } - } + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn request(&self, request: Request) -> Result { + if !self.background_runtime.is_open() { + return Err(ConnectionError::ServerConnectionIsClosed.into()); } - Ok(()) + self.request_transmitter.request(request).await + } + + fn request_blocking(&self, request: Request) -> Result { + if !self.background_runtime.is_open() { + return Err(ConnectionError::ServerConnectionIsClosed.into()); + } + self.request_transmitter.request_blocking(request) } } diff --git a/rust/src/connection/server/server_manager.rs b/rust/src/connection/server/server_manager.rs new file mode 100644 index 0000000000..640af2b7eb --- /dev/null +++ b/rust/src/connection/server/server_manager.rs @@ -0,0 +1,553 @@ +/* + * 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. + */ +use std::{ + collections::{HashMap, HashSet}, + fmt, + future::Future, + iter, + sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}, + thread::sleep, + time::Duration, +}; + +use itertools::{enumerate, Itertools}; +use log::debug; + +use crate::{ + common::{ + address::{address_translation::AddressTranslation, Address, Addresses}, + consistency_level::ConsistencyLevel, + }, + connection::{ + runtime::BackgroundRuntime, + server::{server_connection::ServerConnection, server_replica::ServerReplica}, + server_replica::{AvailableServerReplica, Replica}, + }, + error::{ConnectionError, InternalError}, + Credentials, DriverOptions, Error, Result, +}; + +macro_rules! filter_available_replicas { + ($iter:expr) => {{ + $iter.into_iter().filter_map(|replica| match replica { + ServerReplica::Available(available) => Some(available), + ServerReplica::Unavailable { .. } => None, + }) + }}; +} + +macro_rules! find_primary_replica { + ($iter:expr) => {{ + $iter.filter(|replica| replica.is_primary()).max_by_key(|replica| replica.term().unwrap_or_default()) + }}; +} + +pub(crate) struct ServerManager { + configured_addresses: Addresses, + replicas: RwLock>, + replica_connections: RwLock>, + address_translation: RwLock, + + background_runtime: Arc, + credentials: Credentials, + driver_options: DriverOptions, + driver_lang: String, + driver_version: String, +} + +impl ServerManager { + const PRIMARY_REPLICA_SELECTION_TIMEOUT: Duration = Duration::from_secs(2); + + // TODO: Introduce a timer-based connections update to have a more actualized connections list + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub(crate) async fn new( + background_runtime: Arc, + addresses: Addresses, + credentials: Credentials, + driver_options: DriverOptions, + driver_lang: impl AsRef, + driver_version: impl AsRef, + ) -> Result { + let (source_connections, replicas) = Self::fetch_replicas_from_addresses( + background_runtime.clone(), + &addresses, + credentials.clone(), + driver_options.clone(), + driver_lang.as_ref(), + driver_version.as_ref(), + driver_options.use_replication, + ) + .await?; + let address_translation = addresses.address_translation(); + let server_manager = Self { + configured_addresses: addresses, + replicas: RwLock::new(filter_available_replicas!(replicas).collect()), + replica_connections: RwLock::new(source_connections), + address_translation: RwLock::new(address_translation), + background_runtime, + credentials, + driver_options, + driver_lang: driver_lang.as_ref().to_string(), + driver_version: driver_version.as_ref().to_string(), + }; + server_manager.refresh_replica_connections().await?; + Ok(server_manager) + } + + pub(crate) fn driver_options(&self) -> &DriverOptions { + &self.driver_options + } + + pub(crate) fn configured_addresses(&self) -> &Addresses { + &self.configured_addresses + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub(crate) async fn register_replica(&self, replica_id: u64, address: String) -> Result { + self.execute(ConsistencyLevel::Strong, |replica_connection| { + let address = address.clone(); + async move { replica_connection.servers_register(replica_id, address).await } + }) + .await?; + self.refresh_replicas().await + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub(crate) async fn deregister_replica(&self, replica_id: u64) -> Result { + self.execute(ConsistencyLevel::Strong, |replica_connection| async move { + replica_connection.servers_deregister(replica_id).await + }) + .await?; + self.refresh_replicas().await + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub(crate) async fn update_address_translation(&self, addresses: Addresses) -> Result { + if !matches!(addresses, Addresses::Translated(_)) { + return Err(ConnectionError::AddressTranslationWithoutTranslation { addresses }.into()); + } + + *self.address_translation.write().expect("Expected address translation write access") = + addresses.address_translation(); + + self.refresh_replicas().await?; + self.refresh_replica_connections().await + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn refresh_replica_connections(&self) -> Result { + let mut replicas = self.read_replicas().clone(); + let mut connection_errors = HashMap::with_capacity(replicas.len()); + let mut new_replica_connections = HashMap::new(); + let connection_addresses: HashSet
= self.read_replica_connections().keys().cloned().collect(); + for replica in &replicas { + let private_address = replica.private_address().clone(); + if !connection_addresses.contains(&private_address) { + match self.new_replica_connection(replica.address().clone()).await { + Ok(replica_connection) => { + new_replica_connections.insert(private_address, replica_connection); + } + Err(err) => { + connection_errors.insert(replica.address().clone(), err); + } + } + } + } + + let replica_addresses: HashSet
= + replicas.into_iter().map(|replica| replica.private_address().clone()).collect(); + let mut replica_connections = self.write_replica_connections(); + replica_connections.retain(|address, _| replica_addresses.contains(address)); + replica_connections.extend(new_replica_connections); + + if replica_connections.is_empty() { + Err(self.server_connection_failed_err(connection_errors)) + } else { + Ok(()) + } + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn new_replica_connection(&self, address: Address) -> Result { + ServerConnection::new( + self.background_runtime.clone(), + address, + self.credentials.clone(), + self.driver_options.clone(), + self.driver_lang.as_ref(), + self.driver_version.as_ref(), + ) + .await + .map(|(replica_connection, _)| replica_connection) + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn record_new_replica_connection( + &self, + public_address: Address, + private_address: Address, + ) -> Result { + let replica_connection = self.new_replica_connection(public_address).await?; + let mut replica_connections = self.write_replica_connections(); + replica_connections.insert(private_address, replica_connection.clone()); + Ok(replica_connection) + } + + fn read_replica_connections(&self) -> RwLockReadGuard<'_, HashMap> { + self.replica_connections.read().expect("Expected server connections read access") + } + + fn write_replica_connections(&self) -> RwLockWriteGuard<'_, HashMap> { + self.replica_connections.write().expect("Expected server connections write access") + } + + fn read_address_translation(&self) -> RwLockReadGuard<'_, AddressTranslation> { + self.address_translation.read().expect("Expected address translation read access") + } + + pub(crate) fn force_close(&self) -> Result { + self.read_replica_connections().values().map(ServerConnection::force_close).try_collect().map_err(Into::into) + } + + pub(crate) fn username(&self) -> Result { + match self.read_replica_connections().iter().next() { + Some((_, replica_connection)) => Ok(replica_connection.username().to_string()), + None => Err(ConnectionError::ServerConnectionIsClosed {}.into()), + } + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub(crate) async fn execute(&self, consistency_level: ConsistencyLevel, task: F) -> Result + where + F: Fn(ServerConnection) -> P, + P: Future>, + { + match consistency_level { + ConsistencyLevel::Strong => self.execute_strongly_consistent(task).await, + ConsistencyLevel::Eventual => { + let replicas: HashSet<_> = self.read_replicas().iter().cloned().collect(); + self.execute_on_any(replicas, task).await + } + ConsistencyLevel::ReplicaDependent { address } => { + if self.read_replicas().iter().find(|replica| replica.address() == &address).is_none() { + return Err(ConnectionError::UnknownDirectReplica { + address, + configured_addresses: self.configured_addresses.clone(), + } + .into()); + } + let private_address = + self.read_address_translation().to_private(&address).unwrap_or_else(|| address.clone()); + self.execute_on(&address, &private_address, &task).await + } + } + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn execute_strongly_consistent(&self, task: F) -> Result + where + F: Fn(ServerConnection) -> P, + P: Future>, + { + let mut primary_replica = match self.read_primary_replica() { + Some(replica) => replica, + None => { + let replicas: HashSet<_> = self.read_replicas().iter().cloned().collect(); + if replicas.len() == 1 && replicas.iter().next().unwrap().replica_status().is_none() { + // Only replica without status => not Cluster + replicas.into_iter().next().unwrap() + } else { + self.seek_primary_replica_in(replicas).await? + } + } + }; + + let retries = self.driver_options.primary_failover_retries; + let mut connection_errors = HashMap::new(); + for x in 0..=retries { + let private_address = primary_replica.private_address().clone(); + match self.execute_on(primary_replica.address(), &private_address, &task).await { + Err(Error::Connection(connection_error)) => { + let replicas: HashSet<_> = self.read_replicas().iter().cloned().collect(); + let replicas_without_old_primary = + replicas.into_iter().filter(|replica| replica.private_address() != &private_address); + primary_replica = match &connection_error { + ConnectionError::ClusterReplicaNotPrimary => { + debug!("Could not connect to the primary replica: no longer primary. Retrying..."); + let replicas = iter::once(primary_replica).chain(replicas_without_old_primary); + match self.seek_primary_replica_in(replicas).await { + Ok(replica) => replica, + Err(_) => return Err(connection_error.into()), + } + } + err => { + debug!("Could not connect to the primary replica: {err:?}. Retrying..."); + match self.seek_primary_replica_in(replicas_without_old_primary).await { + Ok(replica) => replica, + Err(_) => return Err(connection_error.into()), + } + } + }; + + connection_errors.insert(primary_replica.address().clone(), connection_error.into()); + + if primary_replica.private_address() == &private_address { + break; + } + } + Err(err) => { + return Err(err); + } + res => { + return res; + } + } + } + Err(self.server_connection_failed_err(connection_errors)) + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn execute_on_any( + &self, + replicas: impl IntoIterator, + task: F, + ) -> Result + where + F: Fn(ServerConnection) -> P, + P: Future>, + { + let limit = self.driver_options.replica_discovery_attempts.unwrap_or(usize::MAX); + let mut connection_errors = HashMap::new(); + for (attempt, replica) in enumerate(replicas.into_iter()) { + if attempt == limit { + break; + } + // TODO: If we only use eventual consistency, we won't ever reconnect to disconnected / + // new replicas. We need to think how to update the connections in this case. + match self.execute_on(replica.address(), replica.private_address(), &task).await { + Err(Error::Connection(ConnectionError::ClusterReplicaNotPrimary)) => { + return Err(ConnectionError::NotPrimaryOnReadOnly { address: replica.address().clone() }.into()); + } + Err(Error::Connection(error)) => { + debug!("Unable to connect to {}: {error:?}. May attempt the next server.", replica.address()); + connection_errors.insert(replica.address().clone(), error.into()); + } + res => return res, + } + } + Err(self.server_connection_failed_err(connection_errors)) + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn execute_on(&self, public_address: &Address, private_address: &Address, task: &F) -> Result + where + F: Fn(ServerConnection) -> P, + P: Future>, + { + let existing_connection = { self.read_replica_connections().get(private_address).cloned() }; + let replica_connection = match existing_connection { + Some(replica_connection) => replica_connection, + None => self.record_new_replica_connection(public_address.clone(), private_address.clone()).await?, + }; + task(replica_connection).await + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn seek_primary_replica_in( + &self, + source_replicas: impl IntoIterator, + ) -> Result { + let result = self + .execute_on_any(source_replicas, |replica_connection| async { + let result = self.seek_primary_replica(replica_connection).await; + if &result == &Err(Error::Connection(ConnectionError::NoPrimaryReplica {})) { + // TODO: Cannot actually happen + Self::wait_for_primary_replica_selection().await; + } + result + }) + .await; + + match result { + // TODO: We may not check newly added configured addresses, and we need to somehow integrate it here... + // Err(Error::Connection(ConnectionError::ServerConnectionFailed { configured_addresses, accessed_addresses, details })) => { + // + // // Last resort: try configured addresses if they are not in the list of accessed addresses + // let addresses = configured_addresses.exclude_addresses(accessed_addresses); + // } + res => res, + } + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn seek_primary_replica(&self, replica_connection: ServerConnection) -> Result { + let address_translation = self.read_address_translation().clone(); + if self.driver_options.use_replication { + let replicas = Self::fetch_replicas_from_connection(&replica_connection, &address_translation).await?; + *self.replicas.write().expect("Expected replicas write lock") = + filter_available_replicas!(replicas).collect(); + } + if let Some(replica) = self.read_primary_replica() { + self.refresh_replica_connections().await?; + Ok(replica) + } else { + Err(ConnectionError::NoPrimaryReplica {}.into()) + } + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn wait_for_primary_replica_selection() { + // FIXME: blocking sleep! Can't do agnostic async sleep. + sleep(Self::PRIMARY_REPLICA_SELECTION_TIMEOUT); + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn fetch_replicas_from_addresses( + background_runtime: Arc, + addresses: &Addresses, + credentials: Credentials, + driver_options: DriverOptions, + driver_lang: impl AsRef, + driver_version: impl AsRef, + use_replication: bool, + ) -> Result<(HashMap, HashSet)> { + let address_translation = addresses.address_translation(); + let mut errors = Vec::with_capacity(addresses.len()); + for address in addresses.addresses() { + let replica_connection = ServerConnection::new( + background_runtime.clone(), + address.clone(), + credentials.clone(), + driver_options.clone(), + driver_lang.as_ref(), + driver_version.as_ref(), + ) + .await; + match replica_connection { + Ok((replica_connection, replicas)) => { + debug!("Fetched replicas from configured address '{address}': {replicas:?}"); + let translated_replicas = Self::translate_replicas(replicas, &address_translation); + if use_replication { + let mut source_connections = HashMap::with_capacity(translated_replicas.len()); + source_connections.insert(address.clone(), replica_connection); + return Ok((source_connections, translated_replicas)); + } else { + if let Some(target_replica) = + translated_replicas.into_iter().find(|replica| replica.address() == Some(address)) + { + let source_connections = HashMap::from([(address.clone(), replica_connection)]); + return Ok((source_connections, HashSet::from([target_replica]))); + } + } + } + Err(Error::Connection(err)) => { + debug!("Unable to fetch replicas from {}: {err:?}. Attempting next server.", address); + errors.push(err); + } + Err(err) => { + return Err(err); + } + } + } + Err(ConnectionError::ServerConnectionFailed { + configured_addresses: addresses.clone(), + accessed_addresses: addresses.clone(), + details: errors.into_iter().join(";\n"), + } + .into()) + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub(crate) async fn fetch_replicas(&self, consistency_level: ConsistencyLevel) -> Result> { + let is_strongly_consistent = consistency_level == ConsistencyLevel::Strong; + let replicas = self + .execute(consistency_level, |replica_connection| { + let address_translation = self.read_address_translation().clone(); + async move { Self::fetch_replicas_from_connection(&replica_connection, &address_translation).await } + }) + .await?; + + if is_strongly_consistent && self.driver_options.use_replication { + // Update cached replicas since it's the most recent info + *self.replicas.write().expect("Expected replicas write lock") = + filter_available_replicas!(replicas.clone()).collect(); + } + Ok(replicas) + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn fetch_replicas_from_connection( + replica_connection: &ServerConnection, + address_translation: &AddressTranslation, + ) -> Result> { + replica_connection.servers_all().await.map(|replicas| Self::translate_replicas(replicas, address_translation)) + } + + fn translate_replicas( + replicas: impl IntoIterator, + address_translation: &AddressTranslation, + ) -> HashSet { + replicas.into_iter().map(|replica| replica.translated(address_translation)).collect() + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub(crate) async fn fetch_primary_replica( + &self, + consistency_level: ConsistencyLevel, + ) -> Result> { + let replicas = self.fetch_replicas(consistency_level).await?; + Ok(find_primary_replica!(filter_available_replicas!(replicas.iter())).cloned()) + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn refresh_replicas(&self) -> Result { + self.fetch_replicas(ConsistencyLevel::Strong).await.map(|_| ()) + } + + fn read_replicas(&self) -> RwLockReadGuard<'_, HashSet> { + self.replicas.read().expect("Expected a read replica lock") + } + + fn read_primary_replica(&self) -> Option { + find_primary_replica!(self.read_replicas().iter()).cloned() + } + + fn server_connection_failed_err(&self, errors: HashMap) -> Error { + let accessed_addresses = + Addresses::from_addresses(self.read_replicas().iter().map(|replica| replica.address().clone())); + let details = if errors.is_empty() { + "none".to_string() + } else { + errors.into_iter().map(|(address, error)| format!("'{address}': '{error}'")).join(";\n") + }; + ConnectionError::ServerConnectionFailed { + configured_addresses: self.configured_addresses.clone(), + accessed_addresses, + details, + } + .into() + } +} + +impl fmt::Debug for ServerManager { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ServerConnection").field("replicas", &self.replicas).finish() + } +} diff --git a/rust/src/connection/server/server_replica.rs b/rust/src/connection/server/server_replica.rs new file mode 100644 index 0000000000..ded40adbe7 --- /dev/null +++ b/rust/src/connection/server/server_replica.rs @@ -0,0 +1,183 @@ +/* + * 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. + */ +use crate::common::address::{address_translation::AddressTranslation, Address}; + +pub const DEFAULT_REPLICA_ID: u64 = 0; + +pub trait Replica: Clone { + /// Returns the id of this replica. 0 (default) if it's not a part of a cluster. + fn id(&self) -> u64; + + /// Returns whether this is the primary replica of the raft cluster or any of the supporting roles. + fn role(&self) -> Option; + + /// Checks whether this is the primary replica of the raft cluster. + fn is_primary(&self) -> bool; + + /// Returns the raft protocol ‘term’ of this replica. + fn term(&self) -> Option; +} + +/// The metadata and state of an individual raft replica of a driver connection. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum ServerReplica { + Available(AvailableServerReplica), + Unavailable { replica_status: Option }, +} + +impl ServerReplica { + pub(crate) fn available_from_private(private_address: Address, replica_status: Option) -> Self { + Self::Available(AvailableServerReplica::from_private(private_address, replica_status)) + } + + pub(crate) fn translate_address(&mut self, address_translation: &AddressTranslation) { + match self { + ServerReplica::Available(available) => available.translate_address(address_translation), + ServerReplica::Unavailable { .. } => {} + } + } + + pub(crate) fn translated(mut self, address_translation: &AddressTranslation) -> Self { + self.translate_address(address_translation); + self + } + + pub(crate) fn replica_status(&self) -> &Option { + match self { + ServerReplica::Available(available_replica) => available_replica.replica_status(), + ServerReplica::Unavailable { replica_status } => replica_status, + } + } + + /// Returns the address this replica is hosted at. None if the information is unavailable. + pub fn address(&self) -> Option<&Address> { + match self { + ServerReplica::Available(available_replica) => Some(available_replica.address()), + ServerReplica::Unavailable { .. } => None, + } + } +} + +impl Replica for ServerReplica { + /// Returns the id of this replica. 0 (default) if it's not a part of a cluster. + fn id(&self) -> u64 { + self.replica_status().map(|status| status.id).unwrap_or(DEFAULT_REPLICA_ID) + } + + /// Returns whether this is the primary replica of the raft cluster or any of the supporting roles. + fn role(&self) -> Option { + self.replica_status().map(|status| status.role).flatten() + } + + /// Checks whether this is the primary replica of the raft cluster. + fn is_primary(&self) -> bool { + matches!(self.role(), Some(ReplicaRole::Primary)) + } + + /// Returns the raft protocol ‘term’ of this replica. + fn term(&self) -> Option { + self.replica_status().map(|status| status.term).flatten() + } +} + +/// A specialization of an available `ServerReplica` with a known connection address. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct AvailableServerReplica { + private_address: Address, + public_address: Option
, + replica_status: Option, +} + +impl AvailableServerReplica { + pub(crate) fn from_private(private_address: Address, replica_status: Option) -> Self { + Self { private_address, public_address: None, replica_status } + } + + pub(crate) fn translate_address(&mut self, address_translation: &AddressTranslation) { + if let Some(translated) = address_translation.to_public(&self.private_address) { + self.public_address = Some(translated); + } + } + + pub(crate) fn translated(mut self, address_translation: &AddressTranslation) -> Self { + self.translate_address(address_translation); + self + } + + pub(crate) fn private_address(&self) -> &Address { + &self.private_address + } + + pub(crate) fn replica_status(&self) -> &Option { + &self.replica_status + } + + /// Returns the address this replica is hosted at. + pub fn address(&self) -> &Address { + self.public_address.as_ref().unwrap_or_else(|| &self.private_address) + } +} + +impl Replica for AvailableServerReplica { + /// Returns the id of this replica. 0 (default) if it's not a part of a cluster. + fn id(&self) -> u64 { + self.replica_status().map(|status| status.id).unwrap_or(DEFAULT_REPLICA_ID) + } + + /// Returns whether this is the primary replica of the raft cluster or any of the supporting roles. + fn role(&self) -> Option { + self.replica_status().map(|status| status.role).flatten() + } + + /// Checks whether this is the primary replica of the raft cluster. + fn is_primary(&self) -> bool { + matches!(self.role(), Some(ReplicaRole::Primary)) + } + + /// Returns the raft protocol ‘term’ of this replica. + fn term(&self) -> Option { + self.replica_status().map(|status| status.term).flatten() + } +} + +/// The metadata and state of an individual server as a raft replica. +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct ReplicaStatus { + /// The id of this replica. + pub(crate) id: u64, + /// The role of this replica in the raft cluster. May be unknown when the replica is unavailable. + pub(crate) role: Option, + /// The raft protocol ‘term’ of this server replica. May be unknown when the replica is unavailable. + pub(crate) term: Option, +} + +impl Default for ReplicaStatus { + fn default() -> Self { + Self { id: DEFAULT_REPLICA_ID, role: None, term: None } + } +} + +/// This enum is used to specify the type of replica. +#[repr(C)] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub enum ReplicaRole { + Primary, + Candidate, + Secondary, +} diff --git a/rust/src/connection/server/server_version.rs b/rust/src/connection/server/server_version.rs new file mode 100644 index 0000000000..2214f691cc --- /dev/null +++ b/rust/src/connection/server/server_version.rs @@ -0,0 +1,44 @@ +/* + * 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. + */ +use std::fmt; + +/// A full TypeDB server's version specification +#[derive(Debug, Clone)] +pub struct ServerVersion { + pub(crate) distribution: String, + pub(crate) version: String, +} + +impl ServerVersion { + /// Retrieves the server's distribution. + pub fn distribution(&self) -> &str { + &self.distribution + } + + /// Retrieves the server's version number. + pub fn version(&self) -> &str { + &self.version + } +} + +impl fmt::Display for ServerVersion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} {}", self.distribution, self.version) + } +} diff --git a/rust/src/connection/transaction_stream.rs b/rust/src/connection/transaction_stream.rs index d223feff29..cc4a794f62 100644 --- a/rust/src/connection/transaction_stream.rs +++ b/rust/src/connection/transaction_stream.rs @@ -84,8 +84,8 @@ impl TransactionStream { self.type_ } - pub(crate) fn options(&self) -> TransactionOptions { - self.options + pub(crate) fn options(&self) -> &TransactionOptions { + &self.options } pub(crate) fn on_close( diff --git a/rust/src/database/database.rs b/rust/src/database/database.rs index 43383613fd..4fd983b255 100644 --- a/rust/src/database/database.rs +++ b/rust/src/database/database.rs @@ -17,65 +17,38 @@ * under the License. */ -#[cfg(not(feature = "sync"))] -use std::future::Future; use std::{ - collections::HashMap, - fmt, - fs::File, io::{BufWriter, Write}, path::Path, - sync::{Arc, RwLock}, - thread::sleep, - time::Duration, + sync::Arc, }; -use itertools::Itertools; use prost::Message; use tracing::{debug, error}; use crate::{ - common::{ - address::Address, - error::ConnectionError, - info::{DatabaseInfo, ReplicaInfo}, - Error, Result, - }, - connection::{database::export_stream::DatabaseExportStream, server_connection::ServerConnection}, + common::{consistency_level::ConsistencyLevel, info::DatabaseInfo, Error, Result}, + connection::server::server_manager::ServerManager, database::migration::{try_create_export_file, try_open_existing_export_file, DatabaseExportAnswer}, - driver::TypeDBDriver, - error::{InternalError, MigrationError}, - resolve, Transaction, TransactionOptions, TransactionType, + error::MigrationError, + resolve, }; -/// A TypeDB database +/// A TypeDB database. +#[derive(Debug, Clone)] pub struct Database { name: String, - replicas: RwLock>, - server_connections: HashMap, + server_manager: Arc, } impl Database { - const PRIMARY_REPLICA_TASK_MAX_RETRIES: usize = 10; - const FETCH_REPLICAS_MAX_RETRIES: usize = 10; - const WAIT_FOR_PRIMARY_REPLICA_SELECTION: Duration = Duration::from_secs(2); - - pub(super) fn new( - database_info: DatabaseInfo, - server_connections: HashMap, - ) -> Result { - let name = database_info.name.clone(); - let replicas = RwLock::new(Replica::try_from_info(database_info, &server_connections)?); - Ok(Self { name, replicas, server_connections }) + pub(super) fn new(database_info: DatabaseInfo, server_manager: Arc) -> Result { + Ok(Self { name: database_info.name, server_manager }) } #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(super) async fn get(name: String, server_connections: HashMap) -> Result { - Ok(Self { - name: name.clone(), - replicas: RwLock::new(Replica::fetch_all(name, &server_connections).await?), - server_connections, - }) + pub(super) async fn get(name: String, server_manager: Arc) -> Result { + Ok(Self { name, server_manager }) } /// Retrieves the database name as a string. @@ -83,80 +56,131 @@ impl Database { self.name.as_str() } - /// Returns the `Replica` instances for this database. - /// _Only works in TypeDB Cloud / Enterprise_ + /// Deletes this database, using default strong consistency. + /// + /// See [`Self::delete_with_consistency`] for more details and options. /// /// # Examples /// /// ```rust - /// database.replicas_info() + #[cfg_attr(feature = "sync", doc = "database.delete();")] + #[cfg_attr(not(feature = "sync"), doc = "database.delete().await;")] /// ``` - pub fn replicas_info(&self) -> Vec { - self.replicas.read().unwrap().iter().map(Replica::to_info).collect() + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn delete(self: Arc) -> Result { + self.delete_with_consistency(ConsistencyLevel::Strong).await } - /// Returns the primary replica for this database. - /// _Only works in TypeDB Cloud / Enterprise_ + /// Deletes this database. + /// + /// # Arguments + /// + /// * `consistency_level` — The consistency level to use for the operation /// /// # Examples /// /// ```rust - /// database.primary_replica_info() + #[cfg_attr(feature = "sync", doc = "database.delete_with_consistency(ConsistencyLevel::Strong);")] + #[cfg_attr(not(feature = "sync"), doc = "database.delete_with_consistency(ConsistencyLevel::Strong).await;")] /// ``` - pub fn primary_replica_info(&self) -> Option { - self.primary_replica().map(|replica| replica.to_info()) + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn delete_with_consistency(self: Arc, consistency_level: ConsistencyLevel) -> Result { + self.server_manager + .execute(consistency_level, |server_connection| { + let name = self.name.clone(); + async move { server_connection.delete_database(name).await } + }) + .await } - /// Returns the preferred replica for this database. - /// Operations which can be run on any replica will prefer to use this replica. - /// _Only works in TypeDB Cloud / Enterprise_ + /// Returns a full schema text as a valid TypeQL define query string, using default strong consistency. + /// + /// See [`Self::schema_with_consistency`] for more details and options. /// /// # Examples /// /// ```rust - /// database.preferred_replica_info(); + #[cfg_attr(feature = "sync", doc = "database.schema();")] + #[cfg_attr(not(feature = "sync"), doc = "database.schema().await;")] /// ``` - pub fn preferred_replica_info(&self) -> Option { - self.preferred_replica().map(|replica| replica.to_info()) + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn schema(&self) -> Result { + self.schema_with_consistency(ConsistencyLevel::Strong).await } - /// Deletes this database. + /// Returns a full schema text as a valid TypeQL define query string. + /// + /// # Arguments + /// + /// * `consistency_level` — The consistency level to use for the operation /// /// # Examples /// /// ```rust - #[cfg_attr(feature = "sync", doc = "database.delete();")] - #[cfg_attr(not(feature = "sync"), doc = "database.delete().await;")] + #[cfg_attr(feature = "sync", doc = "database.schema_with_consistency(ConsistencyLevel::Strong);")] + #[cfg_attr(not(feature = "sync"), doc = "database.schema_with_consistency(ConsistencyLevel::Strong).await;")] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub async fn delete(self: Arc) -> Result { - self.run_on_primary_replica(|database| database.delete()).await + pub async fn schema_with_consistency(&self, consistency_level: ConsistencyLevel) -> Result { + self.server_manager + .execute(consistency_level, |server_connection| { + let name = self.name.clone(); + async move { server_connection.database_schema(name).await } + }) + .await } - /// Returns a full schema text as a valid TypeQL define query string. + /// Returns the types in the schema as a valid TypeQL define query string, using default strong consistency. + /// + /// See [`Self::type_schema_with_consistency`] for more details and options. /// /// # Examples /// /// ```rust - #[cfg_attr(feature = "sync", doc = "database.schema();")] - #[cfg_attr(not(feature = "sync"), doc = "database.schema().await;")] + #[cfg_attr(feature = "sync", doc = "database.type_schema();")] + #[cfg_attr(not(feature = "sync"), doc = "database.type_schema().await;")] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub async fn schema(&self) -> Result { - self.run_failsafe(|database| async move { database.schema().await }).await + pub async fn type_schema(&self) -> Result { + self.type_schema_with_consistency(ConsistencyLevel::Strong).await } /// Returns the types in the schema as a valid TypeQL define query string. /// + /// # Arguments + /// + /// * `consistency_level` — The consistency level to use for the operation + /// /// # Examples /// /// ```rust - #[cfg_attr(feature = "sync", doc = "database.type_schema();")] - #[cfg_attr(not(feature = "sync"), doc = "database.type_schema().await;")] + #[cfg_attr(feature = "sync", doc = "database.type_schema_with_consistency(ConsistencyLevel::Strong);")] + #[cfg_attr(not(feature = "sync"), doc = "database.type_schema_with_consistency(ConsistencyLevel::Strong).await;")] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub async fn type_schema(&self) -> Result { - self.run_failsafe(|database| async move { database.type_schema().await }).await + pub async fn type_schema_with_consistency(&self, consistency_level: ConsistencyLevel) -> Result { + self.server_manager + .execute(consistency_level, |server_connection| { + let name = self.name.clone(); + async move { server_connection.database_type_schema(name).await } + }) + .await + } + + /// Export a database into a schema definition and a data files saved to the disk, using default strong consistency. + /// This is a blocking operation and may take a significant amount of time depending on the database size. + /// + /// See [`Self::export_to_file_with_consistency`] for more details and options. + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "database.export_to_file(schema_path, data_path);")] + #[cfg_attr(not(feature = "sync"), doc = "database.export_to_file(schema_path, data_path).await;")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn export_to_file(&self, schema_file_path: impl AsRef, data_file_path: impl AsRef) -> Result { + self.export_to_file_with_consistency(schema_file_path, data_file_path, ConsistencyLevel::Strong).await } /// Export a database into a schema definition and a data files saved to the disk. @@ -166,15 +190,27 @@ impl Database { /// /// * `schema_file_path` — The path to the schema definition file to be created /// * `data_file_path` — The path to the data file to be created + /// * `consistency_level` — The consistency level to use for the operation /// /// # Examples /// /// ```rust - #[cfg_attr(feature = "sync", doc = "database.export_to_file(schema_path, data_path);")] - #[cfg_attr(not(feature = "sync"), doc = "database.export_to_file(schema_path, data_path).await;")] + #[cfg_attr( + feature = "sync", + doc = "database.export_to_file_with_consistency(schema_path, data_path, ConsistencyLevel::Strong);" + )] + #[cfg_attr( + not(feature = "sync"), + doc = "database.export_to_file_with_consistency(schema_path, data_path, ConsistencyLevel::Strong).await;" + )] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub async fn export_to_file(&self, schema_file_path: impl AsRef, data_file_path: impl AsRef) -> Result { + pub async fn export_to_file_with_consistency( + &self, + schema_file_path: impl AsRef, + data_file_path: impl AsRef, + consistency_level: ConsistencyLevel, + ) -> Result { let schema_file_path = schema_file_path.as_ref(); let data_file_path = data_file_path.as_ref(); if schema_file_path == data_file_path { @@ -188,11 +224,37 @@ impl Database { } let result = self - .run_failsafe(|database| async move { - // File opening should be idempotent for multiple function invocations - let schema_file = try_open_existing_export_file(schema_file_path)?; - let data_file = try_open_existing_export_file(data_file_path)?; - database.export_to_file(schema_file, data_file).await + .server_manager + .execute(consistency_level, |server_connection| { + let name = self.name.clone(); + async move { + // File opening should be idempotent for multiple function invocations + let mut schema_file = try_open_existing_export_file(schema_file_path)?; + let data_file = try_open_existing_export_file(data_file_path)?; + let mut export_stream = server_connection.database_export(name).await?; + let mut data_writer = BufWriter::new(data_file); + + loop { + match resolve!(export_stream.next())? { + DatabaseExportAnswer::Done => break, + DatabaseExportAnswer::Schema(schema) => { + schema_file.write_all(schema.as_bytes())?; + schema_file.flush()?; + } + DatabaseExportAnswer::Items(items) => { + for item in items { + let mut buf = Vec::new(); + item.encode_length_delimited(&mut buf) + .map_err(|_| Error::Migration(MigrationError::CannotEncodeExportedConcept))?; + data_writer.write_all(&buf)?; + } + } + } + } + + data_writer.flush()?; + Ok(()) + } }) .await; @@ -202,276 +264,4 @@ impl Database { } result } - - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn run_failsafe(&self, task: F) -> Result - where - F: Fn(ServerDatabase) -> P, - P: Future>, - { - match self.run_on_any_replica(&task).await { - Err(Error::Connection(ConnectionError::ClusterReplicaNotPrimary)) => { - debug!("Attempted to run on a non-primary replica, retrying on primary..."); - self.run_on_primary_replica(&task).await - } - res => res, - } - } - - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(super) async fn run_on_any_replica(&self, task: F) -> Result - where - F: Fn(ServerDatabase) -> P, - P: Future>, - { - let replicas = self.replicas.read().unwrap().clone(); - for replica in replicas { - match task(replica.database.clone()).await { - Err(Error::Connection( - ConnectionError::ServerConnectionFailedStatusError { .. } | ConnectionError::ConnectionFailed, - )) => { - debug!("Unable to connect to {}. Attempting next server.", replica.server); - } - res => return res, - } - } - Err(Self::unable_to_connect_error(&self.server_connections)) - } - - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(super) async fn run_on_primary_replica(&self, task: F) -> Result - where - F: Fn(ServerDatabase) -> P, - P: Future>, - { - let mut primary_replica = - if let Some(replica) = self.primary_replica() { replica } else { self.seek_primary_replica().await? }; - - for _ in 0..Self::PRIMARY_REPLICA_TASK_MAX_RETRIES { - match task(primary_replica.database.clone()).await { - Err(Error::Connection( - ConnectionError::ClusterReplicaNotPrimary - | ConnectionError::ServerConnectionFailedStatusError { .. } - | ConnectionError::ConnectionFailed, - )) => { - debug!("Primary replica error, waiting..."); - Self::wait_for_primary_replica_selection().await; - primary_replica = self.seek_primary_replica().await?; - } - res => return res, - } - } - Err(Self::unable_to_connect_error(&self.server_connections)) - } - - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - async fn seek_primary_replica(&self) -> Result { - for _ in 0..Self::FETCH_REPLICAS_MAX_RETRIES { - let replicas = Replica::fetch_all(self.name.clone(), &self.server_connections).await?; - *self.replicas.write().unwrap() = replicas; - if let Some(replica) = self.primary_replica() { - return Ok(replica); - } - Self::wait_for_primary_replica_selection().await; - } - Err(Self::unable_to_connect_error(&self.server_connections)) - } - - fn unable_to_connect_error(server_connections: &HashMap) -> Error { - Error::Connection(ConnectionError::ServerConnectionFailed { - addresses: server_connections.keys().map(Address::clone).collect_vec(), - }) - } - - fn primary_replica(&self) -> Option { - self.replicas.read().unwrap().iter().filter(|r| r.is_primary).max_by_key(|r| r.term).cloned() - } - - fn preferred_replica(&self) -> Option { - self.replicas.read().unwrap().iter().filter(|r| r.is_preferred).max_by_key(|r| r.term).cloned() - } - - #[cfg(feature = "sync")] - fn wait_for_primary_replica_selection() { - sleep(Self::WAIT_FOR_PRIMARY_REPLICA_SELECTION); - } - - #[cfg(not(feature = "sync"))] - async fn wait_for_primary_replica_selection() { - tokio::time::sleep(Self::WAIT_FOR_PRIMARY_REPLICA_SELECTION).await - } -} - -impl fmt::Debug for Database { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Database").field("name", &self.name).field("replicas", &self.replicas).finish() - } -} - -/// The metadata and state of an individual raft replica of a database. -#[derive(Clone)] -pub(super) struct Replica { - /// The server hosting this replica - server: Address, - /// Retrieves the database name for which this is a replica - database_name: String, - /// Checks whether this is the primary replica of the raft cluster. - is_primary: bool, - /// The raft protocol ‘term’ of this replica. - term: i64, - /// Checks whether this is the preferred replica of the raft cluster. If true, Operations which can be run on any replica will prefer to use this replica. - is_preferred: bool, - /// Retrieves the database for which this is a replica - database: ServerDatabase, -} - -impl Replica { - fn new(name: String, metadata: ReplicaInfo, server_connection: ServerConnection) -> Self { - Self { - server: metadata.server, - database_name: name.clone(), - is_primary: metadata.is_primary, - term: metadata.term, - is_preferred: metadata.is_preferred, - database: ServerDatabase::new(name, server_connection), - } - } - - fn try_from_info( - database_info: DatabaseInfo, - server_connections: &HashMap, - ) -> Result> { - database_info - .replicas - .into_iter() - .map(|replica| { - if server_connections.len() == 1 { - Ok(Self::new( - database_info.name.clone(), - replica, - server_connections.values().next().unwrap().clone(), - )) - } else { - // TODO: actually check the advertised == provided, if that is the strategy we want - let server_connection = server_connections - .get(&replica.server) - .ok_or_else(|| InternalError::UnknownServer { server: replica.server.clone() })?; - Ok(Self::new(database_info.name.clone(), replica, server_connection.clone())) - } - }) - .collect() - } - - fn to_info(&self) -> ReplicaInfo { - ReplicaInfo { - server: self.server.clone(), - is_primary: self.is_primary, - is_preferred: self.is_preferred, - term: self.term, - } - } - - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - async fn fetch_all(name: String, server_connections: &HashMap) -> Result> { - for (server, server_connection) in server_connections { - let res = server_connection.get_database_replicas(name.clone()).await; - match res { - Ok(info) => { - return Self::try_from_info(info, server_connections); - } - Err(Error::Connection( - ConnectionError::DatabaseNotFound { .. } - | ConnectionError::ServerConnectionFailedStatusError { .. } - | ConnectionError::ConnectionFailed, - )) => { - error!( - "Failed to fetch replica info for database '{}' from {}. Attempting next server.", - name, server - ); - } - Err(err) => return Err(err), - } - } - Err(Database::unable_to_connect_error(server_connections)) - } -} - -impl fmt::Debug for Replica { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Replica") - .field("server", &self.server) - .field("database_name", &self.database_name) - .field("is_primary", &self.is_primary) - .field("term", &self.term) - .field("is_preferred", &self.is_preferred) - .finish() - } -} - -#[derive(Clone, Debug)] -pub(crate) struct ServerDatabase { - name: String, - connection: ServerConnection, -} - -impl ServerDatabase { - fn new(name: String, connection: ServerConnection) -> Self { - Self { name, connection } - } - - pub fn name(&self) -> &str { - self.name.as_str() - } - - pub(crate) fn connection(&self) -> &ServerConnection { - &self.connection - } - - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - async fn delete(self) -> Result { - self.connection.delete_database(self.name).await - } - - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - async fn schema(&self) -> Result { - self.connection.database_schema(self.name.clone()).await - } - - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - async fn type_schema(&self) -> Result { - self.connection.database_type_schema(self.name.clone()).await - } - - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - async fn export_to_file(&self, mut schema_file: File, data_file: File) -> Result { - let mut export_stream = self.connection.database_export(self.name.clone()).await?; - let mut data_writer = BufWriter::new(data_file); - - loop { - match resolve!(export_stream.next())? { - DatabaseExportAnswer::Done => break, - DatabaseExportAnswer::Schema(schema) => { - schema_file.write_all(schema.as_bytes())?; - schema_file.flush()?; - } - DatabaseExportAnswer::Items(items) => { - for item in items { - let mut buf = Vec::new(); - item.encode_length_delimited(&mut buf) - .map_err(|_| Error::Migration(MigrationError::CannotEncodeExportedConcept))?; - data_writer.write_all(&buf)?; - } - } - } - } - - data_writer.flush()?; - Ok(()) - } -} - -impl fmt::Display for ServerDatabase { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.name) - } } diff --git a/rust/src/database/database_manager.rs b/rust/src/database/database_manager.rs index d2dff1dafa..992af51acd 100644 --- a/rust/src/database/database_manager.rs +++ b/rust/src/database/database_manager.rs @@ -17,49 +17,35 @@ * under the License. */ -#[cfg(not(feature = "sync"))] -use std::future::Future; -use std::{ - collections::HashMap, - io::BufReader, - path::Path, - sync::{Arc, RwLock}, -}; +use std::{io::BufReader, path::Path, sync::Arc}; -use tracing::{debug, error, info}; +use itertools::Itertools; use typedb_protocol::migration::Item; use super::Database; use crate::{ - common::{address::Address, error::ConnectionError, Result}, - connection::server_connection::ServerConnection, + common::{consistency_level::ConsistencyLevel, Result}, + connection::server::server_manager::ServerManager, database::migration::{try_open_import_file, ProtoMessageIterator}, info::DatabaseInfo, - resolve, Error, + resolve, }; /// Provides access to all database management methods. #[derive(Debug)] pub struct DatabaseManager { - server_connections: HashMap, - databases_cache: RwLock>>, + server_manager: Arc, } /// Provides access to all database management methods. impl DatabaseManager { - pub(crate) fn new( - server_connections: HashMap, - database_info: Vec, - ) -> Result { - let mut databases = HashMap::new(); - for info in database_info { - let database = Database::new(info, server_connections.clone())?; - databases.insert(database.name().to_owned(), Arc::new(database)); - } - Ok(Self { server_connections, databases_cache: RwLock::new(databases) }) + pub(crate) fn new(server_manager: Arc) -> Result { + Ok(Self { server_manager }) } - /// Retrieves all databases present on the TypeDB server + /// Retrieves all databases present on the TypeDB server, using default strong consistency. + /// + /// See [`Self::all_with_consistency`] for more details and options. /// /// # Examples /// @@ -69,31 +55,38 @@ impl DatabaseManager { /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] pub async fn all(&self) -> Result>> { - let mut error_buffer = Vec::with_capacity(self.server_connections.len()); - for (server_id, server_connection) in self.server_connections.iter() { - match server_connection.all_databases().await { - Ok(list) => { - let mut new_databases: Vec> = Vec::new(); - for db_info in list { - new_databases.push(Arc::new(Database::new(db_info, self.server_connections.clone())?)); - } - let mut databases = self.databases_cache.write().unwrap(); - databases.clear(); - databases - .extend(new_databases.iter().map(|database| (database.name().to_owned(), database.clone()))); - return Ok(new_databases); - } - Err(err) => error_buffer.push(format!("- {}: {}", server_id, err)), - } - } - Err(ConnectionError::ServerConnectionFailedWithError { error: error_buffer.join("\n") })? + self.all_with_consistency(ConsistencyLevel::Strong).await } - /// Retrieve the database with the given name. + /// Retrieves all databases present on the TypeDB server. /// /// # Arguments /// - /// * `name` — The name of the database to retrieve + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.databases().all_with_consistency(ConsistencyLevel::Strong);")] + #[cfg_attr(not(feature = "sync"), doc = "driver.databases().all_with_consistency(ConsistencyLevel::Strong).await;")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn all_with_consistency(&self, consistency_level: ConsistencyLevel) -> Result>> { + self.server_manager + .execute(consistency_level, move |server_connection| async move { + server_connection + .all_databases() + .await? + .into_iter() + .map(|database_info| self.try_build_database(database_info)) + .try_collect() + }) + .await + } + + /// Retrieves the database with the given name, using default strong consistency. + /// + /// See [`Self::get_with_consistency`] for more details and options. /// /// # Examples /// @@ -102,27 +95,46 @@ impl DatabaseManager { #[cfg_attr(not(feature = "sync"), doc = "driver.databases().get(name).await;")] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub async fn get(&self, name: impl AsRef) -> Result> { - let name = name.as_ref(); - - if !self.contains(name.to_owned()).await? { - self.databases_cache.write().unwrap().remove(name); - return Err(ConnectionError::DatabaseNotFound { name: name.to_owned() }.into()); - } - - if let Some(cached_database) = self.try_get_cached(name) { - return Ok(cached_database); - } - - self.cache_insert(Database::get(name.to_owned(), self.server_connections.clone()).await?); - Ok(self.try_get_cached(name).unwrap()) + pub async fn get(&self, name: impl Into) -> Result> { + self.get_with_consistency(name, ConsistencyLevel::Strong).await } - /// Checks if a database with the given name exists + /// Retrieves the database with the given name. /// /// # Arguments /// - /// * `name` — The database name to be checked + /// * `name` — The name of the database to retrieve + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.databases().get_with_consistency(name, ConsistencyLevel::Strong);")] + #[cfg_attr( + not(feature = "sync"), + doc = "driver.databases().get_with_consistency(name, ConsistencyLevel::Strong).await;" + )] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn get_with_consistency( + &self, + name: impl Into, + consistency_level: ConsistencyLevel, + ) -> Result> { + let name = name.into(); + let database_info = self + .server_manager + .execute(consistency_level, move |server_connection| { + let name = name.clone(); + async move { server_connection.get_database(name).await } + }) + .await?; + self.try_build_database(database_info) + } + + /// Checks if a database with the given name exists, using default strong consistency. + /// + /// See [`Self::contains_with_consistency`] for more details and options. /// /// # Examples /// @@ -132,15 +144,43 @@ impl DatabaseManager { /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] pub async fn contains(&self, name: impl Into) -> Result { + self.contains_with_consistency(name, ConsistencyLevel::Strong).await + } + + /// Checks if a database with the given name exists. + /// + /// # Arguments + /// + /// * `name` — The database name to be checked + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.databases().contains_with_consistency(name, ConsistencyLevel::Strong);")] + #[cfg_attr( + not(feature = "sync"), + doc = "driver.databases().contains_with_consistency(name, ConsistencyLevel::Strong).await;" + )] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn contains_with_consistency( + &self, + name: impl Into, + consistency_level: ConsistencyLevel, + ) -> Result { let name = name.into(); - self.run_failsafe( - name, - |server_connection, name| async move { server_connection.contains_database(name).await }, - ) - .await + self.server_manager + .execute(consistency_level, move |server_connection| { + let name = name.clone(); + async move { server_connection.contains_database(name).await } + }) + .await } - /// Create a database with the given name + /// Creates a database with the given name, using default strong consistency. + /// + /// See [`Self::create_with_consistency`] for more details and options. /// /// # Arguments /// @@ -154,16 +194,42 @@ impl DatabaseManager { /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] pub async fn create(&self, name: impl Into) -> Result { + self.create_with_consistency(name, ConsistencyLevel::Strong).await + } + + /// Creates a database with the given name + /// + /// # Arguments + /// + /// * `name` — The name of the database to be created + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.databases().create_with_consistency(name, ConsistencyLevel::Strong);")] + #[cfg_attr( + not(feature = "sync"), + doc = "driver.databases().create_with_consistency(name, ConsistencyLevel::Strong).await;" + )] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn create_with_consistency( + &self, + name: impl Into, + consistency_level: ConsistencyLevel, + ) -> Result { let name = name.into(); - let database_info = self - .run_failsafe(name, |server_connection, name| async move { server_connection.create_database(name).await }) // TODO: run_failsafe produces additiona Connection error if the database name is incorrect. Is it ok? - .await?; - self.cache_insert(Database::new(database_info, self.server_connections.clone())?); - Ok(()) + self.server_manager + .execute(consistency_level, move |server_connection| { + let name = name.clone(); + async move { server_connection.create_database(name).await } + }) + .await } - /// Create a database with the given name based on previously exported another database's data - /// loaded from a file. + /// Creates a database with the given name based on previously exported another database's data + /// loaded from a file. Always uses strong consistency. /// This is a blocking operation and may take a significant amount of time depending on the /// database size. /// @@ -185,6 +251,17 @@ impl DatabaseManager { name: impl Into, schema: impl Into, data_file_path: impl AsRef, + ) -> Result { + self.import_from_file_with_consistency(name, schema, data_file_path, ConsistencyLevel::Strong).await + } + + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + async fn import_from_file_with_consistency( + &self, + name: impl Into, + schema: impl Into, + data_file_path: impl AsRef, + consistency_level: ConsistencyLevel, ) -> Result { const ITEM_BATCH_SIZE: usize = 250; @@ -193,74 +270,35 @@ impl DatabaseManager { let schema_ref: &str = schema.as_ref(); let data_file_path = data_file_path.as_ref(); - self.run_failsafe(name, |server_connection, name| async move { - let file = try_open_import_file(data_file_path)?; - let mut import_stream = server_connection.import_database(name, schema_ref.to_string()).await?; - - let mut item_buffer = Vec::with_capacity(ITEM_BATCH_SIZE); - let mut read_item_iterator = ProtoMessageIterator::::new(BufReader::new(file)); - - while let Some(item) = read_item_iterator.next() { - let item = item?; - item_buffer.push(item); - if item_buffer.len() >= ITEM_BATCH_SIZE { - import_stream.send_items(item_buffer.split_off(0))?; - } - } + self.server_manager + .execute(consistency_level, move |server_connection| { + let name = name.clone(); + async move { + let file = try_open_import_file(data_file_path)?; + let mut import_stream = server_connection.import_database(name, schema_ref.to_string()).await?; - if !item_buffer.is_empty() { - import_stream.send_items(item_buffer)?; - } + let mut item_buffer = Vec::with_capacity(ITEM_BATCH_SIZE); + let mut read_item_iterator = ProtoMessageIterator::::new(BufReader::new(file)); - resolve!(import_stream.done()) - }) - .await - } - - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub(crate) async fn get_cached_or_fetch(&self, name: &str) -> Result> { - match self.try_get_cached(name) { - Some(cached_database) => Ok(cached_database), - None => self.get(name).await, - } - } + while let Some(item) = read_item_iterator.next() { + let item = item?; + item_buffer.push(item); + if item_buffer.len() >= ITEM_BATCH_SIZE { + import_stream.send_items(item_buffer.split_off(0))?; + } + } - fn try_get_cached(&self, name: &str) -> Option> { - self.databases_cache.read().unwrap().get(name).cloned() - } + if !item_buffer.is_empty() { + import_stream.send_items(item_buffer)?; + } - fn cache_insert(&self, database: Database) { - self.databases_cache.write().unwrap().insert(database.name().to_owned(), Arc::new(database)); + resolve!(import_stream.done()) + } + }) + .await } - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - async fn run_failsafe(&self, name: String, task: F) -> Result - where - F: Fn(ServerConnection, String) -> P, - P: Future>, - { - let mut error_buffer = Vec::with_capacity(self.server_connections.len()); - for (server_id, server_connection) in self.server_connections.iter() { - match task(server_connection.clone(), name.clone()).await { - Ok(res) => return Ok(res), - // TODO: database manager should never encounter NOT PRIMARY errors since we are failing over server connections, not replicas - - // Err(Error::Connection(ConnectionError::ClusterReplicaNotPrimary)) => { - // return Database::get(name, self.connection.clone()) - // .await? - // .run_on_primary_replica(|database| { - // let task = &task; - // async move { task(database.connection().clone(), database.name().to_owned()).await } - // }) - // .await - // } - err @ Err(Error::Connection(ConnectionError::ServerConnectionIsClosed)) => return err, - Err(err) => error_buffer.push(format!("- {}: {}", server_id, err)), - } - } - // TODO: With this, every operation fails with - // [CXN03] Connection Error: Unable to connect to TypeDB server(s), received errors: .... - // Which is quite confusing as it's not really connected to connection. - Err(ConnectionError::ServerConnectionFailedWithError { error: error_buffer.join("\n") })? + fn try_build_database(&self, database_info: DatabaseInfo) -> Result> { + Database::new(database_info, self.server_manager.clone()).map(Arc::new) } } diff --git a/rust/src/database/migration.rs b/rust/src/database/migration.rs index 7f8ab401fc..a09c7c79e4 100644 --- a/rust/src/database/migration.rs +++ b/rust/src/database/migration.rs @@ -82,10 +82,10 @@ impl ProtoMessageIterator { return if self.buffer.is_empty() { Ok(None) } else { - Err(Error::Migration(MigrationError::CannotDecodeImportedConceptLength)) + Err(MigrationError::CannotDecodeImportedConceptLength.into()) }; } - Err(_) => return Err(Error::Migration(MigrationError::CannotDecodeImportedConceptLength)), + Err(_) => return Err(MigrationError::CannotDecodeImportedConceptLength.into()), Ok(_) => continue, } } @@ -108,14 +108,14 @@ impl Iterator for ProtoMessageIterator { while self.buffer.len() < required { let to_read = required - self.buffer.len(); match self.read_more(max(to_read, Self::BUF_CAPACITY)) { - Ok(0) | Err(_) => return Some(Err(Error::Migration(MigrationError::CannotDecodeImportedConcept))), + Ok(0) | Err(_) => return Some(Err(MigrationError::CannotDecodeImportedConcept.into())), Ok(_) => {} } } self.buffer.advance(consumed); let message_bytes = self.buffer.split_to(message_len).freeze(); - Some(M::decode(message_bytes).map_err(|_| Error::Migration(MigrationError::CannotDecodeImportedConcept))) + Some(M::decode(message_bytes).map_err(|_| MigrationError::CannotDecodeImportedConcept.into())) } } diff --git a/rust/src/driver.rs b/rust/src/driver.rs index c7fe1b55c4..b1288585d5 100644 --- a/rust/src/driver.rs +++ b/rust/src/driver.rs @@ -16,30 +16,27 @@ * specific language governing permissions and limitations * under the License. */ +use std::{collections::HashSet, fmt, sync::Arc}; -use std::{ - collections::{HashMap, HashSet}, - fmt, - sync::Arc, -}; - -use itertools::Itertools; use tracing::{debug, error, info, trace}; use tracing_subscriber::{fmt as tracing_fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; use crate::{ - common::{ - address::Address, - error::{ConnectionError, Error}, - Result, + common::{consistency_level::ConsistencyLevel, Addresses, Result}, + connection::{ + runtime::BackgroundRuntime, + server::{ + server_connection::ServerConnection, server_manager::ServerManager, server_replica::ServerReplica, + server_version::ServerVersion, + }, + server_replica::AvailableServerReplica, }, - connection::{runtime::BackgroundRuntime, server_connection::ServerConnection}, Credentials, DatabaseManager, DriverOptions, Transaction, TransactionOptions, TransactionType, UserManager, }; /// A connection to a TypeDB server which serves as the starting point for all interaction. pub struct TypeDBDriver { - server_connections: HashMap, + server_manager: Arc, database_manager: DatabaseManager, user_manager: UserManager, background_runtime: Arc, @@ -52,13 +49,13 @@ impl TypeDBDriver { Some(version) => version, }; - pub const DEFAULT_ADDRESS: &'static str = "localhost:1729"; + pub const DEFAULT_ADDRESS: &'static str = "127.0.0.1:1729"; /// Creates a new TypeDB Server connection. /// /// # Arguments /// - /// * `address` — The address (host:port) on which the TypeDB Server is running + /// * `addresses` — The address(es) of the TypeDB Server(s), provided in a unified format /// * `credentials` — The Credentials to connect with /// * `driver_options` — The DriverOptions to connect with /// @@ -67,21 +64,17 @@ impl TypeDBDriver { /// ```rust #[cfg_attr( feature = "sync", - doc = "TypeDBDriver::new(\"127.0.0.1:1729\", Credentials::new(\"username\", \"password\"), DriverOptions::new(true, None))" + doc = "TypeDBDriver::new(Addresses::try_from_address_str(\"127.0.0.1:1729\").unwrap(), Credentials::new(\"username\", \"password\"), DriverOptions::new(true, None))" )] #[cfg_attr( not(feature = "sync"), - doc = "TypeDBDriver::new(\"127.0.0.1:1729\", Credentials::new(\"username\", \"password\"), DriverOptions::new(true, None)).await" + doc = "TypeDBDriver::new(Addresses::try_from_address_str(\"127.0.0.1:1729\").unwrap(), Credentials::new(\"username\", \"password\"), DriverOptions::new(true, None)).await" )] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub async fn new( - address: impl AsRef, - credentials: Credentials, - driver_options: DriverOptions, - ) -> Result { - debug!("Creating new TypeDB driver connection to {}", address.as_ref()); - Self::new_with_description(address, credentials, driver_options, Self::DRIVER_LANG).await + pub async fn new(addresses: Addresses, credentials: Credentials, driver_options: DriverOptions) -> Result { + debug!("Creating new TypeDB driver connection to {:?}", addresses); + Self::new_with_description(addresses, credentials, driver_options, Self::DRIVER_LANG).await } /// Creates a new TypeDB Server connection with a description. @@ -90,7 +83,7 @@ impl TypeDBDriver { /// /// # Arguments /// - /// * `address` — The address (host:port) on which the TypeDB Server is running + /// * `addresses` — The address(es) of the TypeDB Server(s), provided in a unified format /// * `credentials` — The Credentials to connect with /// * `driver_options` — The DriverOptions to connect with /// * `driver_lang` — The language of the driver connecting to the server @@ -100,92 +93,47 @@ impl TypeDBDriver { /// ```rust #[cfg_attr( feature = "sync", - doc = "TypeDBDriver::new_with_description(\"127.0.0.1:1729\", Credentials::new(\"username\", \"password\"), DriverOptions::new(true, None), \"rust\")" + doc = "TypeDBDriver::new_with_description(Addresses::try_from_address_str(\"127.0.0.1:1729\").unwrap(), Credentials::new(\"username\", \"password\"), DriverOptions::new(true, None), \"rust\")" )] #[cfg_attr( not(feature = "sync"), - doc = "TypeDBDriver::new_with_description(\"127.0.0.1:1729\", Credentials::new(\"username\", \"password\"), DriverOptions::new(true, None), \"rust\").await" + doc = "TypeDBDriver::new_with_description(Addresses::try_from_address_str(\"127.0.0.1:1729\").unwrap(), Credentials::new(\"username\", \"password\"), DriverOptions::new(true, None), \"rust\").await" )] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] pub async fn new_with_description( - address: impl AsRef, + addresses: Addresses, credentials: Credentials, driver_options: DriverOptions, driver_lang: impl AsRef, ) -> Result { debug!("Initializing TypeDB driver with description: {}", driver_lang.as_ref()); - let id = address.as_ref().to_string(); - let address: Address = id.parse()?; - let background_runtime = Arc::new(BackgroundRuntime::new()?); - debug!("Establishing server connection to {}", address); - let (server_connection, database_info) = ServerConnection::new( - background_runtime.clone(), - address.clone(), - credentials, - driver_options, - driver_lang.as_ref(), - Self::VERSION, - ) - .await?; - debug!("Successfully connected to server at {}", address); - - // // validate - // let advertised_address = server_connection - // .servers_all()? - // .into_iter() - // .exactly_one() - // .map_err(|e| ConnectionError::ServerConnectionFailedStatusError { error: e.to_string() })?; - - // TODO: this solidifies the assumption that servers don't change - let server_connections: HashMap = [(address, server_connection)].into(); - let database_manager = DatabaseManager::new(server_connections.clone(), database_info)?; - let user_manager = UserManager::new(server_connections.clone()); - debug!("Created database manager and user manager"); - - debug!("TypeDB driver initialization completed successfully"); - Ok(Self { server_connections, database_manager, user_manager, background_runtime }) - } - - #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - async fn fetch_server_list( - background_runtime: Arc, - addresses: impl IntoIterator> + Clone, - credentials: Credentials, - driver_options: DriverOptions, - ) -> Result> { - let addresses: Vec
= addresses.into_iter().map(|addr| addr.as_ref().parse()).try_collect()?; - for address in &addresses { - let server_connection = ServerConnection::new( + debug!("Establishing server connection to {:?}", addresses); + let server_manager = Arc::new( + ServerManager::new( background_runtime.clone(), - address.clone(), - credentials.clone(), - driver_options.clone(), - Self::DRIVER_LANG, + addresses, + credentials, + driver_options, + driver_lang.as_ref(), Self::VERSION, ) - .await; - match server_connection { - Ok((server_connection, _)) => match server_connection.servers_all() { - Ok(servers) => return Ok(servers.into_iter().collect()), - Err(Error::Connection( - ConnectionError::ServerConnectionFailedStatusError { .. } | ConnectionError::ConnectionFailed, - )) => (), - Err(err) => Err(err)?, - }, - Err(Error::Connection( - ConnectionError::ServerConnectionFailedStatusError { .. } | ConnectionError::ConnectionFailed, - )) => (), - Err(err) => Err(err)?, - } - } - Err(ConnectionError::ServerConnectionFailed { addresses }.into()) + .await?, + ); + debug!("Successfully connected to servers"); + + let database_manager = DatabaseManager::new(server_manager.clone())?; + let user_manager = UserManager::new(server_manager.clone()); + debug!("Created database manager and user manager"); + + debug!("TypeDB driver initialization completed successfully"); + Ok(Self { server_manager, database_manager, user_manager, background_runtime }) } /// Checks it this connection is opened. - // + /// /// # Examples /// /// ```rust @@ -195,16 +143,233 @@ impl TypeDBDriver { self.background_runtime.is_open() } + /// The ``DatabaseManager`` for this connection, providing access to database management methods. + /// + /// # Examples + /// + /// ```rust + /// driver.databases() + /// ``` pub fn databases(&self) -> &DatabaseManager { &self.database_manager } + /// The ``UserManager`` for this connection, providing access to user management methods. + /// + /// # Examples + /// + /// ```rust + /// driver.databases() + /// ``` pub fn users(&self) -> &UserManager { &self.user_manager } + /// Retrieves the server's version, using default strong consistency. + /// + /// See [`Self::server_version_with_consistency`] for more details and options. + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.server_version()")] + #[cfg_attr(not(feature = "sync"), doc = "driver.server_version().await")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn server_version(&self) -> Result { + self.server_version_with_consistency(ConsistencyLevel::Strong).await + } + + /// Retrieves the server's version, using default strong consistency. + /// + /// # Arguments + /// + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.server_version_with_consistency(ConsistencyLevel::Strong);")] + #[cfg_attr(not(feature = "sync"), doc = "driver.server_version_with_consistency(ConsistencyLevel::Strong).await;")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn server_version_with_consistency(&self, consistency_level: ConsistencyLevel) -> Result { + self.server_manager + .execute(consistency_level, |server_connection| async move { server_connection.version().await }) + .await + } + + // TODO: Maybe call it just "servers"? + /// Retrieves the server's replicas, using default strong consistency. + /// + /// See [`Self::replicas_with_consistency`] for more details and options. + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.replicas();")] + #[cfg_attr(not(feature = "sync"), doc = "driver.replicas().await;")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn replicas(&self) -> Result> { + self.replicas_with_consistency(ConsistencyLevel::Strong).await + } + + /// Retrieves the server's replicas, using default strong consistency. + /// + /// # Arguments + /// + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.replicas_with_consistency();")] + #[cfg_attr(not(feature = "sync"), doc = "driver.replicas_with_consistency(ConsistencyLevel::Strong).await;")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn replicas_with_consistency( + &self, + consistency_level: ConsistencyLevel, + ) -> Result> { + self.server_manager.fetch_replicas(consistency_level).await + } + + // TODO: Add servers_get call for a specific server. How to design it? + + /// Retrieves the server's primary replica, if exists, using default strong consistency. + /// + /// See [`Self::primary_replica_with_consistency`] for more details and options. + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.primary_replica();")] + #[cfg_attr(not(feature = "sync"), doc = "driver.primary_replica().await;")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn primary_replica(&self) -> Result> { + self.primary_replica_with_consistency(ConsistencyLevel::Strong).await + } + + /// Retrieves the server's primary replica, if exists. + /// + /// # Arguments + /// + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.primary_replica_with_consistency(ConsistencyLevel::Strong);")] + #[cfg_attr(not(feature = "sync"), doc = "driver.primary_replica_with_consistency(ConsistencyLevel::Strong).await;")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn primary_replica_with_consistency( + &self, + consistency_level: ConsistencyLevel, + ) -> Result> { + self.server_manager.fetch_primary_replica(consistency_level).await + } + + /// Registers a new replica in the cluster the driver is currently connected to. The registered + /// replica will become available eventually, depending on the behavior of the whole cluster. + /// To register a replica, its clustering address should be passed, not the connection address. + /// + /// # Arguments + /// + /// * `replica_id` — The numeric identifier of the new replica + /// * `address` — The clustering address of the TypeDB replica as a string + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.register_replica(2, \"127.0.0.1:2729\")")] + #[cfg_attr(not(feature = "sync"), doc = "driver.register_replica(2, \"127.0.0.1:2729\").await")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn register_replica(&self, replica_id: u64, address: String) -> Result { + self.server_manager.register_replica(replica_id, address).await + } + + // TODO: Rename to replica_register and replica_deregister? Does not actually matter since we're removing this + + /// Deregisters a replica from the cluster the driver is currently connected to. This replica + /// will no longer play a raft role in this cluster. + /// + /// # Arguments + /// + /// * `replica_id` — The numeric identifier of the deregistered replica + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.deregister_replica(2)")] + #[cfg_attr(not(feature = "sync"), doc = "driver.deregister_replica(2).await")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn deregister_replica(&self, replica_id: u64) -> Result { + self.server_manager.deregister_replica(replica_id).await + } + + /// Updates address translation of the driver. This lets you actualize new translation + /// information without recreating the driver from scratch. Useful after registering new + /// replicas requiring address translation. + /// This operation will update existing connections using the provided addresses. + /// + /// # Arguments + /// + /// * `addresses` — Addresses containing the new address translation information + /// + /// # Examples + /// + /// ```rust + #[cfg_attr( + feature = "sync", + doc = "driver.update_address_translation(Addresses::try_from_translation_str([(\"typedb-cloud.ext:11729\", \"127.0.0.1:1729\")].into()).unwrap());" + )] + #[cfg_attr( + not(feature = "sync"), + doc = "driver.update_address_translation(Addresses::try_from_translation_str([(\"typedb-cloud.ext:11729\", \"127.0.0.1:1729\")].into()).unwrap()).await;" + )] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn update_address_translation(&self, addresses: Addresses) -> Result { + self.server_manager.update_address_translation(addresses).await + } + + /// The ``DriverOptions`` for this connection. + /// + /// # Examples + /// + /// ```rust + /// driver.options() + /// ``` + pub fn options(&self) -> &DriverOptions { + self.server_manager.driver_options() + } + + /// The ``Addresses`` this connection is configured to. + /// + /// # Examples + /// + /// ```rust + /// driver.configured_addresses() + /// ``` + pub fn configured_addresses(&self) -> &Addresses { + self.server_manager.configured_addresses() + } + /// Opens a transaction with default options. - /// See [`TypeDBDriver::transaction_with_options`] + /// + /// See [`TypeDBDriver::transaction_with_options`] for more details. + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.users().all_with_consistency(ConsistencyLevel::Strong);")] + #[cfg_attr(not(feature = "sync"), doc = "driver.users().all_with_consistency(ConsistencyLevel::Strong).await;")] + /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] pub async fn transaction( &self, @@ -214,7 +379,10 @@ impl TypeDBDriver { self.transaction_with_options(database_name, transaction_type, TransactionOptions::new()).await } - /// Performs a TypeQL query in this transaction. + /// Opens a new transaction with the following consistency level: + /// * read transaction - strong consistency, can be overridden through `options`; + /// * write transaction - strong consistency, cannot be overridden; + /// * schema transaction - strong consistency, cannot be overridden. /// /// # Arguments /// @@ -225,7 +393,14 @@ impl TypeDBDriver { /// # Examples /// /// ```rust - /// transaction.transaction_with_options(database_name, transaction_type, options) + #[cfg_attr( + feature = "sync", + doc = "transaction.transaction_with_options(database_name, transaction_type, options)" + )] + #[cfg_attr( + not(feature = "sync"), + doc = "transaction.transaction_with_options(database_name, transaction_type, options).await" + )] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] pub async fn transaction_with_options( @@ -235,15 +410,21 @@ impl TypeDBDriver { options: TransactionOptions, ) -> Result { let database_name = database_name.as_ref(); - debug!("Opening transaction for database: {} with type: {:?}", database_name, transaction_type); + let open_fn = |server_connection: ServerConnection| { + let options = options.clone(); + async move { server_connection.open_transaction(database_name, transaction_type, options).await } + }; - let database = self.database_manager.get_cached_or_fetch(database_name).await?; - let transaction_stream = database - .run_failsafe(|database| async move { - let res = database.connection().open_transaction(database.name(), transaction_type, options).await; - res - }) - .await?; + debug!("Opening transaction for database: {} with type: {:?}", database_name, transaction_type); + let transaction_stream = match transaction_type { + TransactionType::Read => { + let consistency_level = options.read_consistency_level.clone().unwrap_or(ConsistencyLevel::Strong); + self.server_manager.execute(consistency_level, open_fn).await? + } + TransactionType::Write | TransactionType::Schema => { + self.server_manager.execute(ConsistencyLevel::Strong, open_fn).await? + } + }; debug!("Successfully opened transaction for database: {}", database_name); Ok(Transaction::new(transaction_stream)) @@ -262,43 +443,17 @@ impl TypeDBDriver { } debug!("Closing TypeDB driver connection"); - let result = - self.server_connections.values().map(ServerConnection::force_close).try_collect().map_err(Into::into); - let close_result = self.background_runtime.force_close().and(result); - + let close_result = self.server_manager.force_close().and(self.background_runtime.force_close()); match &close_result { Ok(_) => debug!("Successfully closed TypeDB driver connection"), Err(e) => error!("Failed to close TypeDB driver connection: {}", e), } - close_result } - - pub(crate) fn server_count(&self) -> usize { - self.server_connections.len() - } - - pub(crate) fn servers(&self) -> impl Iterator { - self.server_connections.keys() - } - - pub(crate) fn connection(&self, id: &Address) -> Option<&ServerConnection> { - self.server_connections.get(id) - } - - pub(crate) fn connections(&self) -> impl Iterator + '_ { - self.server_connections.iter() - } - - pub(crate) fn unable_to_connect_error(&self) -> Error { - Error::Connection(ConnectionError::ServerConnectionFailed { - addresses: self.servers().map(Address::clone).collect_vec(), - }) - } } impl fmt::Debug for TypeDBDriver { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Connection").field("server_connections", &self.server_connections).finish() + f.debug_struct("TypeDBDriver").field("server_manager", &self.server_manager).finish() } } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index ae45e6ab60..9ecb937c07 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -22,10 +22,14 @@ pub use self::{ common::{ - box_stream, error, info, BoxPromise, BoxStream, Error, Promise, QueryOptions, Result, TransactionOptions, - TransactionType, IID, + box_stream, consistency_level, error, info, Address, Addresses, BoxPromise, BoxStream, Error, Promise, + QueryOptions, Result, TransactionOptions, TransactionType, IID, + }, + connection::{ + server_replica::{AvailableServerReplica, Replica, ReplicaRole, ServerReplica}, + server_version::ServerVersion, + Credentials, DriverOptions, DriverTlsConfig, }, - connection::{Credentials, DriverOptions}, database::{Database, DatabaseManager}, driver::TypeDBDriver, transaction::Transaction, diff --git a/rust/src/transaction.rs b/rust/src/transaction.rs index acf3875928..911cf1a95d 100644 --- a/rust/src/transaction.rs +++ b/rust/src/transaction.rs @@ -41,15 +41,19 @@ pub struct Transaction { impl Transaction { pub(super) fn new(transaction_stream: TransactionStream) -> Self { let transaction_stream = Box::pin(transaction_stream); - Transaction { type_: transaction_stream.type_(), options: transaction_stream.options(), transaction_stream } + Transaction { + type_: transaction_stream.type_(), + options: transaction_stream.options().clone(), + transaction_stream, + } } - /// Closes the transaction. + /// Checks if the transaction is open. /// /// # Examples /// /// ```rust - /// transaction.close() + /// transaction.is_open() /// ``` pub fn is_open(&self) -> bool { self.transaction_stream.is_open() @@ -57,6 +61,12 @@ impl Transaction { /// Performs a TypeQL query with default options. /// See [`Transaction::query_with_options`] + /// + /// # Examples + /// + /// ```rust + /// transaction.query(query) + /// ``` pub fn query(&self, query: impl AsRef) -> impl Promise<'static, Result> { self.query_with_options(query, QueryOptions::new()) } diff --git a/rust/src/user/user.rs b/rust/src/user/user.rs index 98b9fb3061..508dcbc67f 100644 --- a/rust/src/user/user.rs +++ b/rust/src/user/user.rs @@ -16,52 +16,95 @@ * specific language governing permissions and limitations * under the License. */ -use std::{collections::HashMap, sync::Arc}; +use std::sync::Arc; use crate::{ - common::{address::Address, Result}, - connection::server_connection::ServerConnection, - error::ConnectionError, + common::{consistency_level::ConsistencyLevel, Result}, + connection::server::server_manager::ServerManager, + info::UserInfo, }; #[derive(Clone, Debug)] pub struct User { - pub name: String, - pub password: Option, - pub server_connections: HashMap, + name: String, + password: Option, + server_manager: Arc, } impl User { - /// Update the user's password. + pub(crate) fn new(name: String, password: Option, server_manager: Arc) -> Self { + Self { name, password, server_manager } + } + + pub(crate) fn from_info(user_info: UserInfo, server_manager: Arc) -> Self { + Self::new(user_info.name, user_info.password, server_manager) + } + + /// Retrieves the username as a string. + pub fn name(&self) -> &str { + self.name.as_str() + } + + // TODO: We don't actually need to expose it? + /// Retrieves the password as a string, if accessible. + pub fn password(&self) -> Option<&str> { + self.password.as_ref().map(|value| value.as_str()) + } + + /// Updates the user's password, using default strong consistency. + /// + /// See [`Self::update_password_with_consistency`] for more details and options. /// /// # Arguments /// - /// * `username` — The name of the user /// * `password` — The new password /// /// # Examples /// /// ```rust - #[cfg_attr(feature = "sync", doc = "user.update_password(username, password);")] - #[cfg_attr(not(feature = "sync"), doc = "user.update_password(username, password).await;")] - /// user.update_password(username, password).await; + #[cfg_attr(feature = "sync", doc = "user.update_password(password);")] + #[cfg_attr(not(feature = "sync"), doc = "user.update_password(password).await;")] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] pub async fn update_password(&self, password: impl Into) -> Result<()> { + self.update_password_with_consistency(password, ConsistencyLevel::Strong).await + } + + /// Updates the user's password. + /// + /// # Arguments + /// + /// * `password` — The new password + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "user.update_password_with_consistency(password, ConsistencyLevel::Strong);")] + #[cfg_attr( + not(feature = "sync"), + doc = "user.update_password_with_consistency(password, ConsistencyLevel::Strong).await;" + )] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn update_password_with_consistency( + &self, + password: impl Into, + consistency_level: ConsistencyLevel, + ) -> Result<()> { let password = password.into(); - let mut error_buffer = Vec::with_capacity(self.server_connections.len()); - for (server_id, server_connection) in self.server_connections.iter() { - match server_connection.update_password(self.name.clone(), password.clone()).await { - Ok(res) => return Ok(()), - Err(err) => error_buffer.push(format!("- {}: {}", server_id, err)), - } - } - Err(ConnectionError::ServerConnectionFailedWithError { error: error_buffer.join("\n") })? + self.server_manager + .execute(consistency_level, |server_connection| { + let name = self.name.clone(); + let password = password.clone(); + async move { server_connection.update_password(name, password).await } + }) + .await } - /// Deletes this user + /// Deletes this user, using default strong consistency. /// - /// * `username` — The name of the user to be deleted + /// See [`Self::delete_with_consistency`] for more details and options. /// /// # Examples /// @@ -72,13 +115,28 @@ impl User { /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] pub async fn delete(self) -> Result { - let mut error_buffer = Vec::with_capacity(self.server_connections.len()); - for (server_id, server_connection) in self.server_connections.iter() { - match server_connection.delete_user(self.name.clone()).await { - Ok(res) => return Ok(res), - Err(err) => error_buffer.push(format!("- {}: {}", server_id, err)), - } - } - Err(ConnectionError::ServerConnectionFailedWithError { error: error_buffer.join("\n") })? + self.delete_with_consistency(ConsistencyLevel::Strong).await + } + + /// Deletes this user. + /// + /// # Arguments + /// + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "user.delete_with_consistency(ConsistencyLevel::Strong);")] + #[cfg_attr(not(feature = "sync"), doc = "user.delete_with_consistency(ConsistencyLevel::Strong).await;")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn delete_with_consistency(self, consistency_level: ConsistencyLevel) -> Result { + self.server_manager + .execute(consistency_level, |server_connection| { + let name = self.name.clone(); + async move { server_connection.delete_user(name).await } + }) + .await } } diff --git a/rust/src/user/user_manager.rs b/rust/src/user/user_manager.rs index 39dbc4837c..c8cb27990c 100644 --- a/rust/src/user/user_manager.rs +++ b/rust/src/user/user_manager.rs @@ -16,119 +16,202 @@ * specific language governing permissions and limitations * under the License. */ -use std::collections::HashMap; +use std::sync::Arc; use crate::{ - common::{address::Address, Result}, - connection::server_connection::ServerConnection, - error::ConnectionError, + common::{consistency_level::ConsistencyLevel, Result}, + connection::server::server_manager::ServerManager, User, }; /// Provides access to all user management methods. #[derive(Debug)] pub struct UserManager { - server_connections: HashMap, + server_manager: Arc, } impl UserManager { - pub fn new(server_connections: HashMap) -> Self { - Self { server_connections } + pub fn new(server_manager: Arc) -> Self { + Self { server_manager } } + /// Checks if a user with the given name exists, using default strong consistency. + /// + /// See [`Self::contains_with_consistency`] for more details and options. + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.users().contains(username);")] + #[cfg_attr(not(feature = "sync"), doc = "driver.users().contains(username).await;")] + /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub async fn get_current_user(&self) -> Result> { - let (_, connection) = self - .server_connections - .iter() - .next() - .expect("Unexpected condition: the server connection collection is empty"); - self.get(connection.username()).await + pub async fn contains(&self, username: impl Into) -> Result { + self.contains_with_consistency(username, ConsistencyLevel::Strong).await } /// Checks if a user with the given name exists. /// /// # Arguments /// - /// * `username` — The user name to be checked + /// * `username` — The username to be checked + /// * `consistency_level` — The consistency level to use for the operation /// /// # Examples /// /// ```rust - /// driver.users.contains(username).await; + #[cfg_attr(feature = "sync", doc = "driver.users().contains_with_consistency(username, ConsistencyLevel::Strong);")] + #[cfg_attr( + not(feature = "sync"), + doc = "driver.users().contains_with_consistency(username, ConsistencyLevel::Strong).await;" + )] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub async fn contains(&self, username: impl Into) -> Result { + pub async fn contains_with_consistency( + &self, + username: impl Into, + consistency_level: ConsistencyLevel, + ) -> Result { let username = username.into(); - let mut error_buffer = Vec::with_capacity(self.server_connections.len()); - for (server_id, server_connection) in self.server_connections.iter() { - match server_connection.contains_user(username.clone()).await { - Ok(res) => return Ok(res), - Err(err) => error_buffer.push(format!("- {}: {}", server_id, err)), - } - } - Err(ConnectionError::ServerConnectionFailedWithError { error: error_buffer.join("\n") })? + self.server_manager + .execute(consistency_level, move |server_connection| { + let username = username.clone(); + async move { server_connection.contains_user(username).await } + }) + .await + } + + /// Retrieves a user with the given name, using default strong consistency. + /// + /// See [`Self::get_with_consistency`] for more details and options. + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.users().get(username);")] + #[cfg_attr(not(feature = "sync"), doc = "driver.users().get(username).await;")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn get(&self, username: impl Into) -> Result> { + self.get_with_consistency(username, ConsistencyLevel::Strong).await } - /// Retrieve a user with the given name. + /// Retrieves a user with the given name. /// /// # Arguments /// /// * `username` — The name of the user to retrieve + /// * `consistency_level` — The consistency level to use for the operation /// /// # Examples /// /// ```rust - /// driver.users.get(username).await; + #[cfg_attr(feature = "sync", doc = "driver.users().get_with_consistency(username, ConsistencyLevel::Strong);")] + #[cfg_attr( + not(feature = "sync"), + doc = "driver.users().get_with_consistency(username, ConsistencyLevel::Strong).await;" + )] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] - pub async fn get(&self, username: impl Into) -> Result> { - let uname = username.into(); - let mut error_buffer = Vec::with_capacity(self.server_connections.len()); - for (server_id, server_connection) in self.server_connections.iter() { - match server_connection.get_user(uname.clone()).await { - Ok(res) => { - return Ok(res.map(|u_info| User { - name: u_info.name, - password: u_info.password, - server_connections: self.server_connections.clone(), - })) + pub async fn get_with_consistency( + &self, + username: impl Into, + consistency_level: ConsistencyLevel, + ) -> Result> { + let username = username.into(); + self.server_manager + .execute(consistency_level, |server_connection| { + let username = username.clone(); + let server_manager = self.server_manager.clone(); + async move { + let user_info = server_connection.get_user(username).await?; + Ok(user_info.map(|user_info| User::from_info(user_info, server_manager))) } - Err(err) => error_buffer.push(format!("- {}: {}", server_id, err)), - } - } - Err(ConnectionError::ServerConnectionFailedWithError { error: error_buffer.join("\n") })? + }) + .await } - /// Retrieves all users which exist on the TypeDB server. + /// Returns the user of the current connection, using default strong consistency. + /// + /// See [`Self::get_current_with_consistency`] for more details and options. /// /// # Examples /// /// ```rust - /// driver.users.all().await; + #[cfg_attr(feature = "sync", doc = "driver.users().get_current();")] + #[cfg_attr(not(feature = "sync"), doc = "driver.users().get_current().await;")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn get_current(&self) -> Result> { + self.get(self.server_manager.username()?).await + } + + /// Returns the user of the current connection. + /// + /// # Arguments + /// + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.users().get_current_with_consistency(ConsistencyLevel::Strong);")] + #[cfg_attr( + not(feature = "sync"), + doc = "driver.users().get_current_with_consistency(ConsistencyLevel::Strong).await;" + )] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn get_current_with_consistency(&self, consistency_level: ConsistencyLevel) -> Result> { + self.get_with_consistency(self.server_manager.username()?, consistency_level).await + } + + /// Retrieves all users which exist on the TypeDB server, using default strong consistency. + /// + /// See [`Self::all_with_consistency`] for more details and options. + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.users().all();")] + #[cfg_attr(not(feature = "sync"), doc = "driver.users().all().await;")] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] pub async fn all(&self) -> Result> { - let mut error_buffer = Vec::with_capacity(self.server_connections.len()); - for (server_id, server_connection) in self.server_connections.iter() { - match server_connection.all_users().await { - Ok(res) => { - return Ok(res - .iter() - .map(|u_info| User { - name: u_info.name.clone(), - password: u_info.password.clone(), - server_connections: self.server_connections.clone(), - }) + self.all_with_consistency(ConsistencyLevel::Strong).await + } + + /// Retrieves all users which exist on the TypeDB server. + /// + /// # Arguments + /// + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr(feature = "sync", doc = "driver.users().all_with_consistency(ConsistencyLevel::Strong);")] + #[cfg_attr(not(feature = "sync"), doc = "driver.users().all_with_consistency(ConsistencyLevel::Strong).await;")] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn all_with_consistency(&self, consistency_level: ConsistencyLevel) -> Result> { + self.server_manager + .execute(consistency_level, |server_connection| { + let server_manager = self.server_manager.clone(); + async move { + let user_infos = server_connection.all_users().await?; + Ok(user_infos + .into_iter() + .map(|user_info| User::from_info(user_info, server_manager.clone())) .collect()) } - Err(err) => error_buffer.push(format!("- {}: {}", server_id, err)), - } - } - Err(ConnectionError::ServerConnectionFailedWithError { error: error_buffer.join("\n") })? + }) + .await } - /// Create a user with the given name & password. + /// Creates a user with the given name & password, using default strong consistency. + /// + /// See [`Self::contains_with_consistency`] for more details and options. /// /// # Arguments /// @@ -138,19 +221,49 @@ impl UserManager { /// # Examples /// /// ```rust - /// driver.users.create(username, password).await; + #[cfg_attr(feature = "sync", doc = "driver.users().create(username, password);")] + #[cfg_attr(not(feature = "sync"), doc = "driver.users().create(username, password).await;")] /// ``` #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] pub async fn create(&self, username: impl Into, password: impl Into) -> Result { - let uname = username.into(); - let passwd = password.into(); - let mut error_buffer = Vec::with_capacity(self.server_connections.len()); - for (server_id, server_connection) in self.server_connections.iter() { - match server_connection.create_user(uname.clone(), passwd.clone()).await { - Ok(res) => return Ok(res), - Err(err) => error_buffer.push(format!("- {}: {}", server_id, err)), - } - } - Err(ConnectionError::ServerConnectionFailedWithError { error: error_buffer.join("\n") })? + self.create_with_consistency(username, password, ConsistencyLevel::Strong).await + } + + /// Creates a user with the given name & password. + /// + /// # Arguments + /// + /// * `username` — The name of the user to be created + /// * `password` — The password of the user to be created + /// * `consistency_level` — The consistency level to use for the operation + /// + /// # Examples + /// + /// ```rust + #[cfg_attr( + feature = "sync", + doc = "driver.users().create_with_consistency(username, password, ConsistencyLevel::Strong);" + )] + #[cfg_attr( + not(feature = "sync"), + doc = "driver.users().create_with_consistency(username, password, ConsistencyLevel::Strong).await;" + )] + /// ``` + #[cfg_attr(feature = "sync", maybe_async::must_be_sync)] + pub async fn create_with_consistency( + &self, + username: impl Into, + password: impl Into, + consistency_level: ConsistencyLevel, + ) -> Result { + let username = username.into(); + let password = password.into(); + self.server_manager + .execute(consistency_level, move |server_connection| { + let username = username.clone(); + let password = password.clone(); + async move { server_connection.create_user(username, password).await } + }) + .await } } diff --git a/rust/tests/BUILD b/rust/tests/BUILD index 5efcddde72..da2593c008 100644 --- a/rust/tests/BUILD +++ b/rust/tests/BUILD @@ -33,6 +33,7 @@ rustfmt_test( "//rust/tests/behaviour/driver:test_user", "//rust/tests/integration:test_example", + "//rust/tests/integration/cluster:test_clustering", ], size = "small", ) diff --git a/rust/tests/behaviour/config/BUILD b/rust/tests/behaviour/config/BUILD index 2e9837678a..5d2e7e496c 100644 --- a/rust/tests/behaviour/config/BUILD +++ b/rust/tests/behaviour/config/BUILD @@ -24,13 +24,13 @@ load("//rust/tests/behaviour:defs.bzl", "crate_features_common") string_flag( name = "mode", - build_setting_default = "community", + build_setting_default = "core", ) config_setting( - name = "community", + name = "core", flag_values = { - ":mode": "community", + ":mode": "core", }, ) @@ -45,7 +45,7 @@ rust_library( name = "config", srcs = [":lib.rs"], crate_features = select({ - ":community": crate_features_common, + ":core": crate_features_common, ":cluster": crate_features_common + ["cluster"], }), ) diff --git a/rust/tests/behaviour/driver/BUILD b/rust/tests/behaviour/driver/BUILD index 1104ab519e..627457acdc 100644 --- a/rust/tests/behaviour/driver/BUILD +++ b/rust/tests/behaviour/driver/BUILD @@ -20,6 +20,12 @@ package(default_visibility = ["//visibility:public"]) load("//rust/tests/behaviour:rules.bzl", "rust_behaviour_test") load("@typedb_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") +rust_behaviour_test( + name = "test_cluster", + srcs = ["cluster.rs"], + data = ["@typedb_behaviour//driver:cluster.feature"], +) + rust_behaviour_test( name = "test_concept", srcs = ["concept.rs"], diff --git a/rust/tests/behaviour/driver/cluster.rs b/rust/tests/behaviour/driver/cluster.rs new file mode 100644 index 0000000000..2b23a6bbd7 --- /dev/null +++ b/rust/tests/behaviour/driver/cluster.rs @@ -0,0 +1,42 @@ +/* + * 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. + */ + +use config::is_cluster; +use serial_test::serial; +use steps::Context; + +#[tokio::test] +#[serial] +async fn test() { + if !is_cluster() { + println!("Skipping Cluster tests in a non-clustered environment"); + return; + } + + // Bazel specific path: when running the test in bazel, the external data from + // @typedb_behaviour is stored in a directory that is a sibling to + // the working directory. + #[cfg(feature = "bazel")] + let path = "../typedb_behaviour/driver/cluster.feature"; + + #[cfg(not(feature = "bazel"))] + let path = "../../typedb-behaviour/driver/cluster.feature"; + + assert!(Context::test(path, is_cluster()).await); +} diff --git a/rust/tests/behaviour/steps/Cargo.toml b/rust/tests/behaviour/steps/Cargo.toml index 6e97ec5009..53452a3424 100644 --- a/rust/tests/behaviour/steps/Cargo.toml +++ b/rust/tests/behaviour/steps/Cargo.toml @@ -15,8 +15,8 @@ features = {} [dependencies] [dependencies.tokio] - features = ["bytes", "default", "fs", "full", "io-std", "io-util", "libc", "macros", "mio", "net", "parking_lot", "process", "rt", "rt-multi-thread", "signal", "signal-hook-registry", "socket2", "sync", "time", "tokio-macros"] - version = "1.47.1" + features = ["bytes", "default", "fs", "full", "io-std", "io-util", "libc", "macros", "mio", "net", "parking_lot", "process", "rt", "rt-multi-thread", "signal", "signal-hook-registry", "socket2", "sync", "test-util", "time", "tokio-macros"] + version = "1.48.0" default-features = false [dependencies.smol] @@ -26,7 +26,7 @@ features = {} [dependencies.regex] features = ["default", "perf", "perf-backtrack", "perf-cache", "perf-dfa", "perf-inline", "perf-literal", "perf-onepass", "std", "unicode", "unicode-age", "unicode-bool", "unicode-case", "unicode-gencat", "unicode-perl", "unicode-script", "unicode-segment"] - version = "1.11.1" + version = "1.12.2" default-features = false [dependencies.cucumber] @@ -56,12 +56,12 @@ features = {} [dependencies.chrono] features = ["alloc", "android-tzdata", "clock", "default", "iana-time-zone", "js-sys", "now", "oldtime", "serde", "std", "wasm-bindgen", "wasmbind", "winapi", "windows-link"] - version = "0.4.41" + version = "0.4.40" default-features = false [dependencies.uuid] features = ["default", "fast-rng", "rng", "serde", "std", "v4"] - version = "1.18.0" + version = "1.18.1" default-features = false [dependencies.itertools] @@ -71,6 +71,6 @@ features = {} [dependencies.serde_json] features = ["alloc", "default", "indexmap", "preserve_order", "raw_value", "std"] - version = "1.0.143" + version = "1.0.145" default-features = false diff --git a/rust/tests/behaviour/steps/analyze.rs b/rust/tests/behaviour/steps/analyze.rs index 926e0ae3d3..f02ee5daac 100644 --- a/rust/tests/behaviour/steps/analyze.rs +++ b/rust/tests/behaviour/steps/analyze.rs @@ -413,7 +413,7 @@ pub mod functor_encoding { let preamble = analyzed .preamble .iter() - .map(|(func)| { + .map(|func| { let context = FunctorContext { structure: &func.body }; func.encode_as_functor(&context) }) @@ -431,7 +431,7 @@ pub mod functor_encoding { let preamble = analyzed .preamble .iter() - .map(|(func)| { + .map(|func| { let context = FunctorContext { structure: &func.body }; FunctionAnnotations(func).encode_as_functor(&context) }) diff --git a/rust/tests/behaviour/steps/connection/database.rs b/rust/tests/behaviour/steps/connection/database.rs index 9ed45176be..7eed58774a 100644 --- a/rust/tests/behaviour/steps/connection/database.rs +++ b/rust/tests/behaviour/steps/connection/database.rs @@ -17,16 +17,14 @@ * under the License. */ -use std::io::Read; - -use cucumber::{gherkin::Step, given, then, when}; +use cucumber::gherkin::Step; use futures::{ future::{join_all, try_join_all}, - stream, StreamExt, TryFutureExt, + TryFutureExt, }; use macro_rules_attribute::apply; use tokio::time::sleep; -use typedb_driver::{Database, DatabaseManager, Result as TypeDBResult, TransactionType, TypeDBDriver}; +use typedb_driver::{Database, TransactionType, TypeDBDriver}; use uuid::Uuid; use crate::{ @@ -89,7 +87,12 @@ async fn import_database( #[apply(generic_step)] #[step(expr = "connection create database: {word}{may_error}")] pub async fn connection_create_database(context: &mut Context, name: String, may_error: params::MayError) { - create_database(context.driver.as_ref().unwrap(), name, may_error).await; + let driver = context.driver.as_ref().unwrap(); + let result = match &context.database_operation_consistency { + Some(c) => driver.databases().create_with_consistency(name, c.clone()).await, + None => driver.databases().create(name).await, + }; + may_error.check(result); } #[apply(generic_step)] @@ -127,7 +130,12 @@ pub async fn in_background_connection_create_database( #[apply(generic_step)] #[step(expr = "connection delete database: {word}{may_error}")] pub async fn connection_delete_database(context: &mut Context, name: String, may_error: params::MayError) { - delete_database(context.driver.as_ref().unwrap(), &name, may_error).await; + let driver = context.driver.as_ref().unwrap(); + let result = match &context.database_operation_consistency { + Some(c) => driver.databases().get_with_consistency(&name, c.clone()).and_then(Database::delete).await, + None => driver.databases().get(&name).and_then(Database::delete).await, + }; + may_error.check(result); } #[apply(generic_step)] @@ -163,8 +171,13 @@ pub async fn in_background_connection_delete_database( #[apply(generic_step)] #[step(expr = "connection has database: {word}")] async fn connection_has_database(context: &mut Context, name: String) { + let driver = context.driver.as_ref().unwrap(); + let consistency = context.database_operation_consistency.clone(); assert_with_timeout!( - has_database(context.driver.as_ref().unwrap(), &name).await, + match &consistency { + Some(c) => driver.databases().contains_with_consistency(&name, c.clone()).await.unwrap(), + None => driver.databases().contains(&name).await.unwrap(), + }, "Connection doesn't contain database {name}.", ); } @@ -172,9 +185,14 @@ async fn connection_has_database(context: &mut Context, name: String) { #[apply(generic_step)] #[step(expr = "connection has database(s):")] async fn connection_has_databases(context: &mut Context, step: &Step) { + let driver = context.driver.as_ref().unwrap(); + let consistency = context.database_operation_consistency.clone(); for name in iter_table(step).map(|name| name.to_owned()) { assert_with_timeout!( - has_database(context.driver.as_ref().unwrap(), &name).await, + match &consistency { + Some(c) => driver.databases().contains_with_consistency(&name, c.clone()).await.unwrap(), + None => driver.databases().contains(&name).await.unwrap(), + }, "Connection doesn't contain at least one of the databases.", ); } @@ -183,8 +201,13 @@ async fn connection_has_databases(context: &mut Context, step: &Step) { #[apply(generic_step)] #[step(expr = "connection does not have database: {word}")] async fn connection_does_not_have_database(context: &mut Context, name: String) { + let driver = context.driver.as_ref().unwrap(); + let consistency = context.database_operation_consistency.clone(); assert_with_timeout!( - !has_database(context.driver.as_ref().unwrap(), &name).await, + !match &consistency { + Some(c) => driver.databases().contains_with_consistency(&name, c.clone()).await.unwrap(), + None => driver.databases().contains(&name).await.unwrap(), + }, "Connection contains database {name}.", ); } @@ -192,9 +215,14 @@ async fn connection_does_not_have_database(context: &mut Context, name: String) #[apply(generic_step)] #[step(expr = "connection does not have database(s):")] async fn connection_does_not_have_databases(context: &mut Context, step: &Step) { + let driver = context.driver.as_ref().unwrap(); + let consistency = context.database_operation_consistency.clone(); for name in iter_table(step).map(|name| name.to_owned()) { assert_with_timeout!( - !has_database(context.driver.as_ref().unwrap(), &name).await, + !match &consistency { + Some(c) => driver.databases().contains_with_consistency(&name, c.clone()).await.unwrap(), + None => driver.databases().contains(&name).await.unwrap(), + }, "Connection doesn't contain at least one of the databases.", ); } diff --git a/rust/tests/behaviour/steps/connection/mod.rs b/rust/tests/behaviour/steps/connection/mod.rs index 67d85db5cb..280fba124b 100644 --- a/rust/tests/behaviour/steps/connection/mod.rs +++ b/rust/tests/behaviour/steps/connection/mod.rs @@ -16,16 +16,20 @@ * specific language governing permissions and limitations * under the License. */ - -use cucumber::{given, then, when}; +use cucumber::gherkin::Step; use macro_rules_attribute::apply; +use typedb_driver::{Replica, ReplicaRole, ServerVersion, TypeDBDriver}; -use crate::{assert_with_timeout, generic_step, params, params::check_boolean, Context}; +use crate::{assert_with_timeout, generic_step, params, params::check_boolean, util::iter_table, Context}; mod database; mod transaction; mod user; +async fn get_server_version(driver: &TypeDBDriver, may_error: params::MayError) -> Option { + may_error.check(driver.server_version().await) +} + #[apply(generic_step)] #[step("typedb starts")] async fn typedb_starts(_: &mut Context) {} @@ -36,6 +40,17 @@ async fn connection_opens_with_default_authentication(context: &mut Context) { context.set_driver(context.create_default_driver().await.unwrap()); } +#[apply(generic_step)] +#[step(expr = "connection opens to single server with default authentication{may_error}")] +async fn connection_opens_to_single_server_with_default_authentication( + context: &mut Context, + may_error: params::MayError, +) { + if let Some(driver) = may_error.check(context.create_default_single_driver().await) { + context.set_driver(driver) + } +} + #[apply(generic_step)] #[step(expr = "connection opens with username '{word}', password '{word}'{may_error}")] async fn connection_opens_with_authentication( @@ -67,7 +82,7 @@ async fn connection_opens_with_a_wrong_host(context: &mut Context, may_error: pa may_error.check(match context.is_cluster { false => { context - .create_driver_community( + .create_driver_core( &change_host(Context::DEFAULT_ADDRESS, "surely-not-localhost"), Context::ADMIN_USERNAME, Context::ADMIN_PASSWORD, @@ -88,7 +103,7 @@ async fn connection_opens_with_a_wrong_port(context: &mut Context, may_error: pa may_error.check(match context.is_cluster { false => { context - .create_driver_community( + .create_driver_core( &change_port(Context::DEFAULT_ADDRESS, "0"), Context::ADMIN_USERNAME, Context::ADMIN_PASSWORD, @@ -108,6 +123,96 @@ async fn connection_has_been_opened(context: &mut Context, is_open: params::Bool check_boolean!(is_open, context.driver.is_some() && context.driver.as_ref().unwrap().is_open()); } +#[apply(generic_step)] +#[step(expr = r"connection contains distribution{may_error}")] +async fn connection_has_distribution(context: &mut Context, may_error: params::MayError) { + if let Some(server_version) = get_server_version(context.driver.as_ref().unwrap(), may_error).await { + assert!(!server_version.distribution().is_empty()); + } +} + +#[apply(generic_step)] +#[step(expr = r"connection contains version{may_error}")] +async fn connection_has_version(context: &mut Context, may_error: params::MayError) { + if let Some(server_version) = get_server_version(context.driver.as_ref().unwrap(), may_error).await { + assert!(!server_version.version().is_empty()); + } +} + +#[apply(generic_step)] +#[step(expr = r"connection has {int} replica(s)")] +async fn connection_has_count_replicas(context: &mut Context, count: usize) { + assert_eq!(context.driver.as_ref().unwrap().replicas().await.unwrap().len(), count); +} + +#[apply(generic_step)] +#[step(expr = r"connection primary replica exists")] +async fn connection_primary_replica_exists(context: &mut Context) { + assert!(context.driver.as_ref().unwrap().primary_replica().await.unwrap().is_some()); +} + +#[apply(generic_step)] +#[step(expr = r"connection get replica\({word}\) {exists_or_doesnt}")] +async fn connection_get_replica_exists( + context: &mut Context, + address: String, + exists_or_doesnt: params::ExistsOrDoesnt, +) { + let replicas = context.driver.as_ref().unwrap().replicas().await.unwrap(); + let exists = replicas.iter().any(|r| r.address().unwrap().to_string() == address); + exists_or_doesnt.check_bool(exists, &format!("replica {}", address)); +} + +#[apply(generic_step)] +#[step(expr = r"connection get replica\({word}\) has term")] +async fn connection_get_replica_has_term(context: &mut Context, address: String) { + let replicas = context.driver.as_ref().unwrap().replicas().await.unwrap(); + let replica = replicas.iter().find(|r| r.address().unwrap().to_string() == address); + params::ExistsOrDoesnt::Exists.check(&replica, &format!("replica {}", address)); + let term = replica.unwrap().term(); + params::ExistsOrDoesnt::Exists.check(&term, &format!("term {:?}", term)); + assert!(term.unwrap() > 0, "Term expected"); +} + +#[apply(generic_step)] +#[step("connection replicas have roles:")] +async fn connection_replicas_have_roles(context: &mut Context, step: &Step) { + let replicas = context.driver.as_ref().unwrap().replicas().await.unwrap(); + let table = step.table.as_ref().expect("Expected a table with replica roles"); + + let mut expected_primary_count = 0; + let mut expected_secondary_count = 0; + let mut expected_candidate_count = 0; + for expected_role in iter_table(step) { + match expected_role { + "primary" => expected_primary_count += 1, + "secondary" => expected_secondary_count += 1, + "candidate" => expected_candidate_count += 1, + other => panic!("Unknown replica role: {}", other), + } + } + + let actual_primary_count = replicas.iter().filter(|r| matches!(r.role(), Some(ReplicaRole::Primary))).count(); + let actual_secondary_count = replicas.iter().filter(|r| matches!(r.role(), Some(ReplicaRole::Secondary))).count(); + let actual_candidate_count = replicas.iter().filter(|r| matches!(r.role(), Some(ReplicaRole::Candidate))).count(); + + assert_eq!( + expected_primary_count, actual_primary_count, + "Expected {} primary replicas, found {}", + expected_primary_count, actual_primary_count + ); + assert_eq!( + expected_secondary_count, actual_secondary_count, + "Expected {} secondary replicas, found {}", + expected_secondary_count, actual_secondary_count + ); + assert_eq!( + expected_candidate_count, actual_candidate_count, + "Expected {} candidate replicas, found {}", + expected_candidate_count, actual_candidate_count + ); +} + #[apply(generic_step)] #[step(expr = r"connection has {int} database(s)")] async fn connection_has_count_databases(context: &mut Context, count: usize) { @@ -126,3 +231,30 @@ async fn driver_closes(context: &mut Context, may_error: params::MayError) { may_error.check(context.driver.as_ref().unwrap().force_close()); context.cleanup_transactions().await; } + +#[apply(generic_step)] +#[step(expr = "set driver option use_replication to: {boolean}")] +pub async fn set_transaction_option_use_replication(context: &mut Context, value: params::Boolean) { + context.init_driver_options_if_needed(); + context.driver_options_mut().unwrap().use_replication = value.to_bool(); +} + +#[apply(generic_step)] +#[step(expr = "set driver option primary_failover_retries to: {int}")] +pub async fn set_transaction_option_primary_failover_retries(context: &mut Context, value: usize) { + context.init_driver_options_if_needed(); + context.driver_options_mut().unwrap().primary_failover_retries = value; +} + +#[apply(generic_step)] +#[step(expr = "set driver option replica_discovery_attempts to: {int}")] +pub async fn set_transaction_option_replica_discovery_attempts(context: &mut Context, value: usize) { + context.init_driver_options_if_needed(); + context.driver_options_mut().unwrap().replica_discovery_attempts = Some(value); +} + +#[apply(generic_step)] +#[step(expr = r"set database operation consistency to: {consistency_level}")] +pub async fn set_database_operation_consistency(context: &mut Context, consistency_level: params::ConsistencyLevel) { + context.database_operation_consistency = Some(consistency_level.into_typedb()); +} diff --git a/rust/tests/behaviour/steps/connection/transaction.rs b/rust/tests/behaviour/steps/connection/transaction.rs index 8b03a1f7d2..85aac899c3 100644 --- a/rust/tests/behaviour/steps/connection/transaction.rs +++ b/rust/tests/behaviour/steps/connection/transaction.rs @@ -19,14 +19,12 @@ use std::{collections::VecDeque, time::Duration}; -use cucumber::{gherkin::Step, given, then, when}; -use futures::{future::join_all, FutureExt}; +use cucumber::gherkin::Step; +use futures::future::join_all; use macro_rules_attribute::apply; use typedb_driver::{Result as TypeDBResult, Transaction, TransactionOptions, TransactionType, TypeDBDriver}; -use crate::{ - generic_step, in_background, in_oneshot_background, params, params::check_boolean, util::iter_table, Context, -}; +use crate::{generic_step, in_background, params, params::check_boolean, util::iter_table, Context}; pub(crate) async fn open_transaction_for_database( driver: &TypeDBDriver, @@ -55,7 +53,7 @@ pub async fn connection_open_transaction_for_database( context.driver.as_ref().unwrap(), &database_name, type_.transaction_type, - context.transaction_options, + context.transaction_options(), ) .await, ), @@ -73,7 +71,7 @@ async fn connection_open_transactions_for_database(context: &mut Context, databa context.driver.as_ref().unwrap(), &database_name, transaction_type, - context.transaction_options, + context.transaction_options(), ) .await, ) @@ -90,7 +88,7 @@ pub async fn connection_open_transactions_in_parallel(context: &mut Context, dat context.driver.as_ref().unwrap(), &database_name, transaction_type, - context.transaction_options, + context.transaction_options(), ) })) .await @@ -115,7 +113,7 @@ pub async fn in_background_connection_open_transaction_for_database( &background, &database_name, type_.transaction_type, - context.transaction_options, + context.transaction_options(), ) .await, ), @@ -169,12 +167,22 @@ pub async fn transaction_rollbacks(context: &mut Context, may_error: params::May #[step(expr = "set transaction option transaction_timeout_millis to: {int}")] pub async fn set_transaction_option_transaction_timeout_millis(context: &mut Context, value: u64) { context.init_transaction_options_if_needed(); - context.transaction_options.as_mut().unwrap().transaction_timeout = Some(Duration::from_millis(value)); + context.transaction_options_mut().unwrap().transaction_timeout = Some(Duration::from_millis(value)); } #[apply(generic_step)] #[step(expr = "set transaction option schema_lock_acquire_timeout_millis to: {int}")] pub async fn set_transaction_option_schema_lock_acquire_timeout_millis(context: &mut Context, value: u64) { context.init_transaction_options_if_needed(); - context.transaction_options.as_mut().unwrap().schema_lock_acquire_timeout = Some(Duration::from_millis(value)); + context.transaction_options_mut().unwrap().schema_lock_acquire_timeout = Some(Duration::from_millis(value)); +} + +#[apply(generic_step)] +#[step(expr = "set transaction option read_consistency_level to: {consistency_level}")] +pub async fn set_transaction_option_read_consistency_level( + context: &mut Context, + consistency_level: params::ConsistencyLevel, +) { + context.init_transaction_options_if_needed(); + context.transaction_options_mut().unwrap().read_consistency_level = Some(consistency_level.into_typedb()); } diff --git a/rust/tests/behaviour/steps/connection/user.rs b/rust/tests/behaviour/steps/connection/user.rs index 139c7ae48e..448290a134 100644 --- a/rust/tests/behaviour/steps/connection/user.rs +++ b/rust/tests/behaviour/steps/connection/user.rs @@ -19,16 +19,25 @@ use std::collections::HashSet; -use cucumber::{gherkin::Step, given, then, when}; +use cucumber::gherkin::Step; use futures::TryFutureExt; use macro_rules_attribute::apply; use tokio::time::sleep; -use typedb_driver::{Database, Result as TypeDBResult, TypeDBDriver, User}; -use crate::{assert_err, assert_with_timeout, generic_step, params, util::iter_table, Context}; +use crate::{assert_with_timeout, generic_step, params, util::iter_table, Context}; async fn all_user_names(context: &Context) -> HashSet { - context.driver.as_ref().unwrap().users().all().await.unwrap().into_iter().map(|user| user.name).collect() + context + .driver + .as_ref() + .unwrap() + .users() + .all() + .await + .unwrap() + .into_iter() + .map(|user| user.name().to_string()) + .collect() } #[apply(generic_step)] @@ -61,7 +70,7 @@ async fn get_user(context: &mut Context, username: String, may_error: params::Ma #[step(expr = r"get user\({word}\) get name: {word}")] async fn get_user_get_name(context: &mut Context, user: String, name: String) { let user = context.driver.as_ref().unwrap().users().get(user).await.unwrap().unwrap(); - assert_eq!(user.name, name); + assert_eq!(user.name(), name); } #[apply(generic_step)] @@ -99,6 +108,6 @@ async fn delete_user(context: &mut Context, username: String, may_error: params: #[apply(generic_step)] #[step(expr = "get current username: {word}")] -async fn get_current_username(context: &mut Context, username: String) { - assert_eq!(context.driver.as_ref().unwrap().users().get_current_user().await.unwrap().unwrap().name, username); +async fn get_currentname(context: &mut Context, username: String) { + assert_eq!(context.driver.as_ref().unwrap().users().get_current().await.unwrap().unwrap().name(), username); } diff --git a/rust/tests/behaviour/steps/lib.rs b/rust/tests/behaviour/steps/lib.rs index c7fb84d7af..ef4dde24dd 100644 --- a/rust/tests/behaviour/steps/lib.rs +++ b/rust/tests/behaviour/steps/lib.rs @@ -35,12 +35,16 @@ use futures::{ stream::{self, StreamExt}, }; use itertools::Itertools; -use tokio::time::{sleep, Duration}; +use tokio::{ + sync::OnceCell, + time::{sleep, Duration}, +}; use typedb_driver::{ analyze::AnalyzedQuery, answer::{ConceptDocument, ConceptRow, QueryAnswer, QueryType}, - BoxStream, Credentials, DriverOptions, QueryOptions, Result as TypeDBResult, Transaction, TransactionOptions, - TypeDBDriver, + consistency_level::ConsistencyLevel, + Addresses, BoxStream, Credentials, DriverOptions, DriverTlsConfig, QueryOptions, Result as TypeDBResult, + Transaction, TransactionOptions, TypeDBDriver, }; use crate::{ @@ -96,12 +100,16 @@ impl> cucumber::Parser for SingletonParser { } } +static CLUSTER_SETUP: OnceCell<()> = OnceCell::const_new(); + #[derive(World)] pub struct Context { pub is_cluster: bool, - pub tls_root_ca: PathBuf, + pub tls_root_ca: Option, + pub driver_options: Option, pub transaction_options: Option, pub query_options: Option, + pub database_operation_consistency: Option, pub driver: Option, pub background_driver: Option, pub temp_dir: Option, @@ -122,8 +130,10 @@ impl fmt::Debug for Context { f.debug_struct("Context") .field("is_cluster", &self.is_cluster) .field("tls_root_ca", &self.tls_root_ca) + .field("driver_options", &self.driver_options) .field("transaction_options", &self.transaction_options) .field("query_options", &self.query_options) + .field("database_operation_consistency", &self.database_operation_consistency) .field("driver", &self.driver) .field("background_driver", &self.background_driver) .field("transactions", &self.transactions) @@ -145,8 +155,10 @@ impl fmt::Debug for Context { impl Context { const DEFAULT_ADDRESS: &'static str = "127.0.0.1:1729"; - // TODO when multiple nodes are available: "127.0.0.1:11729", "127.0.0.1:21729", "127.0.0.1:31729" - const DEFAULT_CLUSTER_ADDRESSES: [&'static str; 1] = ["127.0.0.1:1729"]; + const DEFAULT_CLUSTER_ADDRESSES: [&'static str; 3] = ["127.0.0.1:11729", "127.0.0.1:21729", "127.0.0.1:31729"]; + // Used to register cluster peers + const DEFAULT_CLUSTER_CLUSTERING_ADDRESSES: [&'static str; 3] = + ["127.0.0.1:11730", "127.0.0.1:21730", "127.0.0.1:31730"]; const ADMIN_USERNAME: &'static str = "admin"; const ADMIN_PASSWORD: &'static str = "password"; const STEP_REATTEMPT_SLEEP: Duration = Duration::from_millis(250); @@ -169,7 +181,15 @@ impl Context { context.is_cluster = is_cluster; // cucumber removes the default hook before each scenario and restores it after! std::panic::set_hook(Box::new(move |info| println!("{}", info))); - Box::pin(async move {}) + Box::pin(async move { + if is_cluster { + CLUSTER_SETUP + .get_or_init(|| async { + context.setup_cluster().await; + }) + .await; + } + }) }) .after(|_, _, _, _, context| { Box::pin(async { @@ -255,7 +275,7 @@ impl Context { .await .expect("Expected all users") .into_iter() - .filter(|user| user.name != Context::ADMIN_USERNAME) + .filter(|user| user.name() != Context::ADMIN_USERNAME) .map(|user| user.delete()), ) .await @@ -284,6 +304,22 @@ impl Context { self.concurrent_rows_streams = None; } + pub fn driver_options(&self) -> Option { + self.driver_options.clone() + } + + pub fn driver_options_mut(&mut self) -> Option<&mut DriverOptions> { + self.driver_options.as_mut() + } + + pub fn transaction_options(&self) -> Option { + self.transaction_options.clone() + } + + pub fn transaction_options_mut(&mut self) -> Option<&mut TransactionOptions> { + self.transaction_options.as_mut() + } + pub fn transaction_opt(&self) -> Option<&Transaction> { self.transactions.get(0) } @@ -319,6 +355,12 @@ impl Context { self.transactions = transactions; } + pub fn init_driver_options_if_needed(&mut self) { + if self.driver_options.is_none() { + self.driver_options = Some(DriverOptions::default()); + } + } + pub fn init_transaction_options_if_needed(&mut self) { if self.transaction_options.is_none() { self.transaction_options = Some(TransactionOptions::default()); @@ -437,25 +479,35 @@ impl Context { self.create_driver(Some(Self::ADMIN_USERNAME), Some(Self::ADMIN_PASSWORD)).await } + async fn create_default_single_driver(&self) -> TypeDBResult { + self.create_single_driver(Some(Self::ADMIN_USERNAME), Some(Self::ADMIN_PASSWORD)).await + } + + async fn create_single_driver(&self, username: Option<&str>, password: Option<&str>) -> TypeDBResult { + let username = username.unwrap_or(Self::ADMIN_USERNAME); + let password = password.unwrap_or(Self::ADMIN_USERNAME); + match self.is_cluster { + false => self.create_driver_core(Self::DEFAULT_ADDRESS, username, password).await, + true => self.create_driver_cluster(&[Self::DEFAULT_CLUSTER_ADDRESSES[0]], username, password).await, + } + } + async fn create_driver(&self, username: Option<&str>, password: Option<&str>) -> TypeDBResult { let username = username.unwrap_or(Self::ADMIN_USERNAME); let password = password.unwrap_or(Self::ADMIN_USERNAME); match self.is_cluster { - false => self.create_driver_community(Self::DEFAULT_ADDRESS, username, password).await, + false => self.create_driver_core(Self::DEFAULT_ADDRESS, username, password).await, true => self.create_driver_cluster(&Self::DEFAULT_CLUSTER_ADDRESSES, username, password).await, } } - async fn create_driver_community( - &self, - address: &str, - username: &str, - password: &str, - ) -> TypeDBResult { - assert!(!self.is_cluster); + async fn create_driver_core(&self, address: &str, username: &str, password: &str) -> TypeDBResult { + assert!(!self.is_cluster, "Only non-cluster drivers are available in this mode"); + let addresses = Addresses::try_from_address_str(address).expect("Expected addresses"); let credentials = Credentials::new(username, password); - let conn_settings = DriverOptions::new(false, None)?; - TypeDBDriver::new(address, credentials, conn_settings).await + // TLS is always off for a core driver test + let options = self.driver_options().unwrap_or_default().tls_config(DriverTlsConfig::disabled()); + TypeDBDriver::new(addresses, credentials, options).await } async fn create_driver_cluster( @@ -464,14 +516,18 @@ impl Context { username: &str, password: &str, ) -> TypeDBResult { - assert!(self.is_cluster); - // TODO: Change when multiple addresses are introduced - let address = addresses.iter().next().expect("Expected at least one address"); + assert!(self.is_cluster, "Only cluster drivers are available in this mode"); + let addresses = Addresses::try_from_addresses_str(addresses).expect("Expected addresses"); - // TODO: We probably want to add encryption to cluster tests let credentials = Credentials::new(username, password); - let conn_settings = DriverOptions::new(false, None)?; - TypeDBDriver::new(address, credentials, conn_settings).await + assert!( + self.tls_root_ca.is_some() && self.tls_root_ca.as_ref().unwrap().exists(), + "Root CA is expected for cluster tests!" + ); + let root_ca = self.tls_root_ca.as_ref().map(|path| path.as_path()).expect("Expected root CA for cluster tests"); + let driver_options = + self.driver_options().unwrap_or_default().tls_config(DriverTlsConfig::enabled_with_root_ca(root_ca)?); + TypeDBDriver::new(addresses, credentials, driver_options).await } pub fn set_driver(&mut self, driver: TypeDBDriver) { @@ -483,19 +539,36 @@ impl Context { driver.force_close().unwrap() } } + + async fn setup_cluster(&self) { + let driver = Self::create_default_driver(&self).await.expect("Expected a default driver in setup"); + + let clustering_addresses = Self::DEFAULT_CLUSTER_CLUSTERING_ADDRESSES; + if driver.replicas().await.unwrap().len() != clustering_addresses.len() { + for (i, address) in clustering_addresses.iter().enumerate() { + let id = (i + 1) as u64; + // 1 is default registered replica + if id != 1 { + driver + .register_replica(id, address.to_string()) + .await + .expect("Expected to register replica in setup"); + } + } + } + } } impl Default for Context { fn default() -> Self { - let tls_root_ca = match std::env::var("ROOT_CA") { - Ok(root_ca) => PathBuf::from(root_ca), - Err(_) => PathBuf::new(), - }; + let tls_root_ca = std::env::var("ROOT_CA").ok().map(|root_ca| PathBuf::from(root_ca)); Self { is_cluster: false, tls_root_ca, + driver_options: None, transaction_options: None, query_options: None, + database_operation_consistency: None, driver: None, background_driver: None, transactions: VecDeque::new(), diff --git a/rust/tests/behaviour/steps/params.rs b/rust/tests/behaviour/steps/params.rs index bd173c6dca..7b2669bcf4 100644 --- a/rust/tests/behaviour/steps/params.rs +++ b/rust/tests/behaviour/steps/params.rs @@ -17,19 +17,20 @@ * under the License. */ -use std::{borrow::Borrow, convert::Infallible, fmt, str::FromStr}; +use std::{convert::Infallible, fmt, str::FromStr}; use chrono::{FixedOffset, NaiveDate, NaiveDateTime, NaiveTime}; use cucumber::Parameter; use typedb_driver::{ answer::QueryType as TypeDBQueryType, concept::{Value as TypeDBValue, ValueType as TypeDBValueType}, - TransactionType as TypeDBTransactionType, + consistency_level::ConsistencyLevel as TypeDBConsistencyLevel, + Address, TransactionType as TypeDBTransactionType, }; #[derive(Debug, Default, Parameter, Clone)] #[param(name = "value", regex = ".*?")] -pub(crate) struct Value { +pub struct Value { raw_value: String, } @@ -238,7 +239,7 @@ impl FromStr for Var { #[derive(Debug, Parameter)] #[param(name = "boolean", regex = "(true|false)")] -pub(crate) enum Boolean { +pub enum Boolean { False, True, } @@ -279,7 +280,7 @@ impl FromStr for Boolean { #[derive(Debug, Clone, Parameter)] #[param(name = "may_error", regex = "(|; fails|; parsing fails|; fails with a message containing: \".*\")")] -pub(crate) enum MayError { +pub enum MayError { False, True(Option), } @@ -335,7 +336,7 @@ impl FromStr for MayError { #[derive(Debug, Parameter)] #[param(name = "is_or_not", regex = "(is|is not)")] -pub(crate) enum IsOrNot { +pub enum IsOrNot { Is, IsNot, } @@ -388,7 +389,7 @@ impl FromStr for IsOrNot { #[derive(Debug, Parameter)] #[param(name = "contains_or_doesnt", regex = "(contains|does not contain)")] -pub(crate) enum ContainsOrDoesnt { +pub enum ContainsOrDoesnt { Contains, DoesNotContain, } @@ -431,7 +432,7 @@ impl FromStr for ContainsOrDoesnt { #[derive(Debug, Parameter)] #[param(name = "exists_or_doesnt", regex = "(exists|does not exist)")] -pub(crate) enum ExistsOrDoesnt { +pub enum ExistsOrDoesnt { Exists, DoesNotExist, } @@ -474,7 +475,7 @@ impl FromStr for ExistsOrDoesnt { #[derive(Debug, Parameter)] #[param(name = "is_by_var_index", regex = "(| by index of variable)")] -pub(crate) enum IsByVarIndex { +pub enum IsByVarIndex { Is, IsNot, } @@ -492,7 +493,7 @@ impl FromStr for IsByVarIndex { #[derive(Debug, Clone, Copy, Parameter)] #[param(name = "query_answer_type", regex = "(ok|concept rows|concept documents)")] -pub(crate) enum QueryAnswerType { +pub enum QueryAnswerType { Ok, ConceptRows, ConceptDocuments, @@ -520,12 +521,55 @@ impl fmt::Display for QueryAnswerType { } } +#[derive(Debug, Clone, Parameter)] +#[param(name = "consistency_level", regex = "(strong|eventual|replica(.*))")] +pub enum ConsistencyLevel { + Strong, + Eventual, + ReplicaDependent { address: Address }, +} + +impl ConsistencyLevel { + pub fn into_typedb(self) -> TypeDBConsistencyLevel { + match self { + ConsistencyLevel::Strong => TypeDBConsistencyLevel::Strong, + ConsistencyLevel::Eventual => TypeDBConsistencyLevel::Eventual, + ConsistencyLevel::ReplicaDependent { address } => TypeDBConsistencyLevel::ReplicaDependent { address }, + } + } +} + +impl FromStr for ConsistencyLevel { + type Err = String; + fn from_str(s: &str) -> Result { + if s == "strong" { + Ok(Self::Strong) + } else if s == "eventual" { + Ok(Self::Eventual) + } else if let Some(message) = s.strip_prefix("replica(").and_then(|suffix| suffix.strip_suffix(")")) { + Ok(Self::ReplicaDependent { address: message.parse().expect("Expected a valid address") }) + } else { + Err(format!("Invalid `ConsistencyLevel`: {}", s)) + } + } +} + +impl fmt::Display for ConsistencyLevel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Strong => write!(f, "Strong"), + Self::Eventual => write!(f, "Eventual"), + Self::ReplicaDependent { address } => write!(f, "ReplicaDependent({address:?})"), + } + } +} + #[derive(Debug, Parameter)] #[param( name = "concept_kind", regex = "(concept|variable|type|instance|entity type|relation type|attribute type|role type|entity|relation|attribute|value)" )] -pub(crate) enum ConceptKind { +pub enum ConceptKind { Concept, Type, Instance, @@ -540,7 +584,7 @@ pub(crate) enum ConceptKind { } impl ConceptKind { - pub(crate) fn matches_concept(&self, concept: &Concept) -> bool { + pub fn matches_concept(&self, concept: &Concept) -> bool { match self { ConceptKind::Concept => true, ConceptKind::Type => match concept { diff --git a/rust/tests/behaviour/steps/query.rs b/rust/tests/behaviour/steps/query.rs index 121127fa07..397170fb00 100644 --- a/rust/tests/behaviour/steps/query.rs +++ b/rust/tests/behaviour/steps/query.rs @@ -17,24 +17,20 @@ * under the License. */ -use std::{collections::VecDeque, ops::Index}; - -use cucumber::{gherkin::Step, given, then, when}; -use futures::{future::join_all, StreamExt, TryStreamExt}; +use cucumber::gherkin::Step; +use futures::{future::join_all, StreamExt}; use itertools::Itertools; use macro_rules_attribute::apply; use typedb_driver::{ - answer::{ConceptRow, QueryAnswer, JSON}, + answer::{ConceptRow, QueryAnswer}, concept::{AttributeType, Concept, ConceptCategory, EntityType, RelationType, Value, ValueType}, error::ConceptError, QueryOptions, Result as TypeDBResult, Transaction, }; use crate::{ - analyze::functor_encoding::encode_query_structure_as_functor, - assert_err, generic_step, params, + generic_step, params, params::check_boolean, - util, util::{iter_table, list_contains_json, parse_json}, BehaviourTestOptionalError, Context, }; @@ -713,7 +709,7 @@ pub async fn answer_get_row_get_variable_try_get_specific_value_is_none( var_kind: params::ConceptKind, is_by_var_index: params::IsByVarIndex, var: params::Var, - value_type: params::ValueType, + _value_type: params::ValueType, is_or_not: params::IsOrNot, ) { let concept = get_answer_rows_var(context, index, is_by_var_index, var).await.unwrap().unwrap(); @@ -740,7 +736,7 @@ pub async fn answer_get_row_get_variable_get_specific_value( ) { let concept = get_answer_rows_var(context, index, is_by_var_index, var).await.unwrap().unwrap(); check_concept_is_kind(concept, var_kind, params::Boolean::True); - let actual_value = concept.try_get_value().expect("Value is expected"); + let _actual_value = concept.try_get_value().expect("Value is expected"); let expected_value = value.into_typedb(value_type.value_type.clone()); match value_type.value_type { ValueType::Boolean => { diff --git a/rust/tests/behaviour/steps/util.rs b/rust/tests/behaviour/steps/util.rs index 84ae730ae3..f7dbc58b9d 100644 --- a/rust/tests/behaviour/steps/util.rs +++ b/rust/tests/behaviour/steps/util.rs @@ -23,31 +23,17 @@ use std::{ env, fs, fs::File, io::{Read, Write}, - iter, mem, ops::Deref, path::{Path, PathBuf}, }; -use chrono::{NaiveDate, NaiveDateTime, NaiveTime}; -use cucumber::{ - gherkin::{Feature, Step}, - given, then, when, StatsWriter, World, -}; -use futures::{ - future::{try_join_all, Either}, - stream::{self, StreamExt}, -}; -use itertools::Itertools; +use cucumber::gherkin::Step; use macro_rules_attribute::apply; use tokio::time::{sleep, Duration}; -use typedb_driver::{ - answer::{ConceptRow, JSON}, - concept::{Attribute, AttributeType, Concept, Entity, EntityType, Relation, RelationType, RoleType, Value}, - DatabaseManager, Error, Result as TypeDBResult, -}; +use typedb_driver::{answer::JSON, Result as TypeDBResult}; use uuid::Uuid; -use crate::{assert_with_timeout, generic_step, params, params::check_boolean, Context}; +use crate::{generic_step, params, Context}; pub fn iter_table(step: &Step) -> impl Iterator { step.table().unwrap().rows.iter().flatten().map(String::as_str) diff --git a/rust/tests/integration/BUILD b/rust/tests/integration/BUILD index b3af28ff89..d55eb24995 100644 --- a/rust/tests/integration/BUILD +++ b/rust/tests/integration/BUILD @@ -20,11 +20,6 @@ package(default_visibility = ["//visibility:public"]) load("@rules_rust//rust:defs.bzl", "rust_test") load("@typedb_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") -exports_files( - ["quickstart"], - visibility = ["//rust:__subpackages__"], -) - rust_test( name = "test_example", srcs = ["example.rs"], diff --git a/rust/tests/integration/cluster/BUILD b/rust/tests/integration/cluster/BUILD index f61fa8fb80..f98218b4c8 100644 --- a/rust/tests/integration/cluster/BUILD +++ b/rust/tests/integration/cluster/BUILD @@ -17,10 +17,44 @@ package(default_visibility = ["//visibility:public"]) +load("@rules_rust//rust:defs.bzl", "rust_test") load("@typedb_dependencies//tool/checkstyle:rules.bzl", "checkstyle_test") -# TODO: This package can contain cluster-specific integration tests. Tests available for running for both community -# edition and cluster should be run for both setups (and be limited: always prefer BDDs to integration tests)! +rust_test( + name = "test_clustering", + srcs = ["clustering.rs"], + deps = [ + "//rust:typedb_driver", + "@crates//:async-std", + "@crates//:chrono", + "@crates//:futures", + "@crates//:itertools", + "@crates//:regex", + "@crates//:serde_json", + "@crates//:serial_test", + "@crates//:smol", + "@crates//:tokio", + "@crates//:uuid", + ], +) + +rust_test( + name = "test_playground", + srcs = ["playground.rs"], + deps = [ + "//rust:typedb_driver", + "@crates//:async-std", + "@crates//:chrono", + "@crates//:futures", + "@crates//:itertools", + "@crates//:regex", + "@crates//:serde_json", + "@crates//:serial_test", + "@crates//:smol", + "@crates//:tokio", + "@crates//:uuid", + ], +) checkstyle_test( name = "checkstyle", diff --git a/rust/tests/integration/cluster/clustering.rs b/rust/tests/integration/cluster/clustering.rs new file mode 100644 index 0000000000..0eadbaeea0 --- /dev/null +++ b/rust/tests/integration/cluster/clustering.rs @@ -0,0 +1,338 @@ +/* + * 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. + */ +use std::{ + env, fs, + path::Path, + process::{Child, Command}, + str::FromStr, + time::Duration, +}; + +use async_std::task::sleep; +use futures::{StreamExt, TryStreamExt}; +use serial_test::serial; +use typedb_driver::{ + answer::ConceptRow, Addresses, Credentials, DriverOptions, DriverTlsConfig, Error, ServerReplica, + TransactionOptions, TransactionType, TypeDBDriver, +}; + +const ADDRESSES: [&'static str; 3] = ["127.0.0.1:11729", "127.0.0.1:21729", "127.0.0.1:31729"]; +const CLUSTERING_ADDRESSES: [&'static str; 3] = ["127.0.0.1:11730", "127.0.0.1:21730", "127.0.0.1:31730"]; +const USERNAME: &'static str = "admin"; +const PASSWORD: &'static str = "password"; + +#[test] +#[serial] +fn primary_reelection_read_query() { + async_std::task::block_on(async { + kill_servers().await.ok(); + + for (i, address) in ADDRESSES.iter().enumerate() { + let (_, port) = address.rsplit_once(':').unwrap(); + start_server_replica_from_parts(&(i + 1).to_string(), port).await; + } + sleep(Duration::from_secs(10)).await; + + remove_test_database().await; + + println!("Building the main driver"); + let driver = TypeDBDriver::new( + Addresses::try_from_address_str(ADDRESSES[0]).unwrap(), + Credentials::new(USERNAME, PASSWORD), + DriverOptions::new(DriverTlsConfig::disabled()), + ) + .await + .unwrap(); + + for (i, address) in CLUSTERING_ADDRESSES[1..].iter().enumerate() { + driver.register_replica((i + 2) as u64, address.to_string()).await.unwrap(); + } + + // TODO: Temp, resolve it somehow!!! + sleep(Duration::from_secs(6)).await; + println!("Recreating the driver to fetch new replicas"); + drop(driver); + let driver = TypeDBDriver::new( + Addresses::try_from_address_str(ADDRESSES[0]).unwrap(), + Credentials::new(USERNAME, PASSWORD), + DriverOptions::new(DriverTlsConfig::disabled()), + ) + .await + .unwrap(); + + // sleep(Duration::from_secs(5)).await; + // TODO: Does it need to return all the current replicas? Or is it not needed? + // It's currently handled automatically, so we won't see the new replicas now after registering them!!! + let replicas = driver.replicas().await; + println!("Replicas: {replicas:?}"); + + let database_name = "typedb"; + println!("Registered replicas. Creating the database"); + driver.databases().create(database_name).await.unwrap(); + println!("Retrieving the database..."); + + verify_created_database(&driver, database_name).await; + + for iteration in 0..10 { + let primary_replica = get_primary_replica(&driver).await; + println!("Stopping primary replica (iteration {}). Testing retrieval from other replicas", iteration); + kill_server_replica(&primary_replica).await.unwrap(); + + sleep(Duration::from_secs(5)).await; + verify_created_database(&driver, database_name).await; + + start_server_replica(&primary_replica).await; + } + + println!("Done!"); + }); + + async_std::task::block_on(async { + println!("Cleanup!"); + remove_test_database().await; + kill_servers().await.unwrap(); + println!("Successfully cleaned up!"); + }) +} + +// #[test] +// #[serial] +// fn primary_reelection_read_query() { +// async_std::task::block_on(async { +// kill_servers().await.ok(); +// +// for (i, address) in ADDRESSES.iter().enumerate() { +// let (_, port) = address.rsplit_once(':').unwrap(); +// start_server_replica_from_parts(&(i + 1).to_string(), port).await; +// } +// sleep(Duration::from_secs(10)).await; +// +// remove_test_database().await; +// +// println!("Building the main driver"); +// let driver = TypeDBDriver::new( +// Addresses::try_from_address_str(ADDRESSES[0]).unwrap(), +// Credentials::new(USERNAME, PASSWORD), +// DriverOptions::new(DriverTlsConfig::disabled()), +// ) +// .await +// .unwrap(); +// +// for (i, address) in CLUSTERING_ADDRESSES[1..].iter().enumerate() { +// driver.register_replica((i + 2) as u64, address.to_string()).await.unwrap(); +// } +// +// // sleep(Duration::from_secs(5)).await; +// // TODO: Does it need to return all the current replicas? Or is it not needed? +// // It's currently handled automatically, so we won't see the new replicas now after registering them!!! +// // let replicas = driver.replicas(); +// +// println!("Registered replicas. Creating the database"); +// driver.databases().create("typedb").await.unwrap(); +// println!("Retrieving the database..."); +// let database = driver.databases().get("typedb").await.unwrap(); +// assert_eq!(database.name(), "typedb"); +// +// println!("Created database {}. Initializing schema", database.name()); +// { +// let transaction = driver +// .transaction_with_options(database.name(), TransactionType::Schema, TransactionOptions::default()) +// .await +// .unwrap(); +// transaction.query("define entity person;").await.unwrap(); +// transaction.commit().await.unwrap(); +// } +// +// verify_defined(&driver, database.name()).await; +// +// for iteration in 0..10 { +// let primary_replica = get_primary_replica(&driver).await; +// println!("Stopping primary replica (iteration {}). Testing retrieval from other replicas", iteration); +// kill_server_replica(&primary_replica).await.unwrap(); +// +// sleep(Duration::from_secs(5)).await; +// verify_defined(&driver, database.name()).await; +// +// start_server_replica(&primary_replica).await; +// } +// +// println!("Done!"); +// }); +// +// async_std::task::block_on(async { +// println!("Cleanup!"); +// remove_test_database().await; +// kill_servers().await.unwrap(); +// println!("Successfully cleaned up!"); +// }) +// } + +async fn remove_test_database() { + let driver = TypeDBDriver::new( + Addresses::try_from_addresses_str(ADDRESSES.iter()).unwrap(), + Credentials::new(USERNAME, PASSWORD), + DriverOptions::new(DriverTlsConfig::disabled()), + ) + .await + .unwrap(); + if driver.databases().contains("typedb").await.unwrap() { + driver.databases().get("typedb").await.unwrap().delete().await.unwrap(); + } +} + +async fn kill_servers() -> Result<(), TestError> { + for address in &ADDRESSES { + let (_, port) = address.rsplit_once(':').unwrap(); + kill_server_replica_from_parts(port).await?; + } + Ok(()) +} + +fn start_server(index: &str) -> Child { + // Command::new(format!("../{index}/typedb")) + let data_directory_path = format!("{index}/data"); + let data_directory = Path::new(&data_directory_path); + fs::create_dir_all(data_directory).unwrap(); + let data_directory_path = fs::canonicalize(data_directory).unwrap(); + let logs_directory_path = format!("{index}/logs"); + let logs_directory = Path::new(&logs_directory_path); + fs::create_dir_all(logs_directory).unwrap(); + let logs_directory_path = fs::canonicalize(logs_directory).unwrap(); + // TODO: Temporary, should be called in a better way + Command::new(format!("{}/tool/test/temp-cluster-server/typedb", env::current_dir().unwrap().to_string_lossy())) + .args([ + "--server.address", + &format!("127.0.0.1:{index}1729"), + "--server-clustering-id", + &format!("{index}"), + "--server-clustering-address", + &format!("127.0.0.1:{index}1730"), + "--storage.data-directory", + &data_directory_path.display().to_string(), + "--logging.logdir", + &logs_directory_path.display().to_string(), + "--diagnostics.deployment-id", + "test", + "--server.encryption.enabled", + "false", + "--diagnostics.monitoring.port", + &format!("{index}1731"), + "--server.http.enabled", + "false", + "--development-mode.enabled", + "true", + ]) + .spawn() + .expect("Failed to start TypeDB server") +} + +async fn get_primary_replica(driver: &TypeDBDriver) -> ServerReplica { + for _ in 0..10 { + if let Some(replica) = driver.primary_replica().await.unwrap() { + return ServerReplica::Available(replica); + } + println!("No primary replica yet. Retrying in 2s..."); + sleep(Duration::from_secs(2)).await; + } + panic!("Retry limit exceeded while seeking a primary replica."); +} + +async fn verify_defined_type(driver: &TypeDBDriver, database_name: impl AsRef) { + let transaction = driver + .transaction_with_options(database_name, TransactionType::Read, TransactionOptions::default()) + .await + .unwrap(); + let answer = transaction.query("match entity $p;").await.unwrap(); + let rows: Vec = answer.into_rows().try_collect().await.unwrap(); + assert_eq!(rows.len(), 1); + let row = rows.get(0).unwrap(); + let entity_type = row.get("p").unwrap().unwrap(); + assert_eq!(entity_type.is_entity_type(), true); + assert_eq!(entity_type.get_label(), "person"); +} + +async fn verify_created_database(driver: &TypeDBDriver, database_name: impl AsRef) { + // TODO: Can additionally test with eventual consistency when it's introduced. Like this: + // use typedb_driver::consistency_level::ConsistencyLevel; + // assert_eq!(driver.databases().get_with_consistency(database_name.as_ref(), ConsistencyLevel::Eventual).await.unwrap().name(), database_name.as_ref()); + // assert!(driver.databases().contains_with_consistency(database_name.as_ref(), ConsistencyLevel::Eventual).await.unwrap()); + + assert_eq!(driver.databases().get(database_name.as_ref()).await.unwrap().name(), database_name.as_ref()); + assert!(driver.databases().contains(database_name.as_ref()).await.unwrap()); +} + +async fn start_server_replica(server_replica: &ServerReplica) { + let address_parts = ServerReplicaAddressParts::from_str(&server_replica.address().unwrap().to_string()).unwrap(); + start_server_replica_from_parts(&address_parts.replica_id, &address_parts.port).await +} + +async fn start_server_replica_from_parts(replica_id: &str, port: &str) { + println!("Starting server replica from parts: {replica_id}, port: {port}"); + let _child = start_server(replica_id); + let mut attempts = 0; + while attempts < 60 { + sleep(Duration::from_secs(1)).await; + let check = Command::new("lsof").args(["-i", &format!(":{}", port)]).output(); + if check.is_ok() { + break; + } + attempts += 1; + } +} + +async fn kill_server_replica(server_replica: &ServerReplica) -> Result<(), TestError> { + let address_parts = ServerReplicaAddressParts::from_str(&server_replica.address().unwrap().to_string()).unwrap(); + kill_server_replica_from_parts(&address_parts.port).await +} + +async fn kill_server_replica_from_parts(port: &str) -> Result<(), TestError> { + let lsof = Command::new("lsof").args(["-i", &format!(":{}", port)]).output().expect("Failed to run lsof"); + + let stdout = String::from_utf8_lossy(&lsof.stdout); + let pid = stdout + .lines() + .find(|line| line.contains("LISTEN")) + .and_then(|line| line.split_whitespace().nth(1)) + .ok_or(TestError::NoServerPid)?; + + let res = Command::new("kill").args(["-9", pid]).status(); + println!("Replica on port {port} killed"); + res.map(|_| ()).map_err(|_| TestError::NoServerProcess) +} + +struct ServerReplicaAddressParts { + replica_id: String, + port: String, +} + +impl FromStr for ServerReplicaAddressParts { + type Err = Error; + + fn from_str(address: &str) -> typedb_driver::Result { + let port = address.rsplit_once(':').map(|(_, port)| port.to_string()).unwrap(); + let replica_id = port[0..1].to_string(); + Ok(Self { replica_id, port }) + } +} + +#[derive(Debug)] +enum TestError { + NoServerPid, + NoServerProcess, +} diff --git a/rust/tests/integration/cluster/mod.rs b/rust/tests/integration/cluster/mod.rs index 042f3ce1f3..d220cef87b 100644 --- a/rust/tests/integration/cluster/mod.rs +++ b/rust/tests/integration/cluster/mod.rs @@ -16,3 +16,6 @@ * specific language governing permissions and limitations * under the License. */ + +mod clustering; +mod playground; diff --git a/rust/tests/integration/cluster/playground.rs b/rust/tests/integration/cluster/playground.rs new file mode 100644 index 0000000000..66143a4606 --- /dev/null +++ b/rust/tests/integration/cluster/playground.rs @@ -0,0 +1,106 @@ +/* + * 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. + */ +use std::{ + collections::HashSet, + env, fs, + path::Path, + process::{Child, Command}, + str::FromStr, + time::Duration, +}; + +use async_std::task::sleep; +use futures::{StreamExt, TryStreamExt}; +use serial_test::serial; +use typedb_driver::{ + answer::ConceptRow, consistency_level::ConsistencyLevel, Address, Addresses, AvailableServerReplica, Credentials, + DriverOptions, DriverTlsConfig, Error, Replica, ServerReplica, TransactionOptions, TransactionType, TypeDBDriver, +}; +// DO NOT commit changes to this test. Use it as playground for dev. +const ADDRESSES: [&'static str; 3] = ["127.0.0.1:11729", "127.0.0.1:21729", "127.0.0.1:31729"]; +const ADDRESS: &'static str = "127.0.0.1:11729"; +const CLUSTERING_ADDRESSES: [&'static str; 3] = ["127.0.0.1:11730", "127.0.0.1:21730", "127.0.0.1:31730"]; +const USERNAME: &'static str = "admin"; +const PASSWORD: &'static str = "password"; + +#[test] +#[serial] +fn playground_test() { + async_std::task::block_on(async { + let driver = TypeDBDriver::new( + // Try automatic replicas retrieval by connecting to only a single server! + // Use Addresses::try_from_addresses_str() to provide multiple addresses instead. + Addresses::try_from_address_str(ADDRESS).unwrap(), + Credentials::new(USERNAME, PASSWORD), + DriverOptions::new(DriverTlsConfig::enabled_with_native_root_ca()).use_replication(true), + ) + .await + .expect("Error while setting up the driver"); + + // setup_cluster(&driver).await; + + let replicas = driver.replicas().await.unwrap(); + let addresses = replicas.iter().map(|replica| replica.address().unwrap()).collect::>(); + println!("Replicas known to the driver: {addresses:?}"); + + const DATABASE_NAME: &str = "clustered-test"; + + if !driver.databases().contains(DATABASE_NAME).await.expect("Expected database check") { + driver + .databases() + .create_with_consistency(DATABASE_NAME, ConsistencyLevel::Strong) + .await + .expect("Expected database creation"); + } + + let database = driver.databases().get(DATABASE_NAME).await.expect("Expected database retrieval"); + println!("Database exists: {}", database.name()); + + let transaction_options = TransactionOptions::new() + .transaction_timeout(Duration::from_secs(100)) + .read_consistency_level(ConsistencyLevel::Eventual); + + // Schema transactions are always strongly consistent + let transaction = driver + .transaction_with_options(DATABASE_NAME, TransactionType::Schema, transaction_options.clone()) + .await + .expect("Expected schema transaction"); + + transaction.query("define entity person;").await.expect("Expected schema query"); + transaction.query("insert $p1 isa person; $p2 isa person;").await.expect("Expected data query"); + transaction.commit().await.expect("Expected schema tx commit"); + + // Read transaction will be opened using the consistency level from the options + let transaction = driver + .transaction_with_options(DATABASE_NAME, TransactionType::Read, transaction_options) + .await + .expect("Expected schema transaction"); + let answer = transaction.query("match $p isa person;").await.expect("Expected read query"); + let rows: Vec = answer.into_rows().try_collect().await.unwrap(); + println!("Persons found: {}", rows.len()); + + println!("Done!"); + }); +} + +async fn setup_cluster(driver: &TypeDBDriver) { + for (i, address) in CLUSTERING_ADDRESSES[1..].iter().enumerate() { + driver.register_replica((i + 2) as u64, address.to_string()).await.unwrap(); + } +} diff --git a/rust/tests/integration/driver.rs b/rust/tests/integration/driver.rs index d566140bf1..26189bfce0 100644 --- a/rust/tests/integration/driver.rs +++ b/rust/tests/integration/driver.rs @@ -23,13 +23,13 @@ use std::sync::{ }; use serial_test::serial; -use typedb_driver::{Credentials, DriverOptions, TransactionType, TypeDBDriver}; +use typedb_driver::{Addresses, Credentials, DriverOptions, DriverTlsConfig, TransactionType, TypeDBDriver}; async fn cleanup() { let driver = TypeDBDriver::new( - TypeDBDriver::DEFAULT_ADDRESS, + Addresses::try_from_address_str(TypeDBDriver::DEFAULT_ADDRESS).unwrap(), Credentials::new("admin", "password"), - DriverOptions::new(false, None).unwrap(), + DriverOptions::new(DriverTlsConfig::disabled()), ) .await .unwrap(); @@ -44,9 +44,9 @@ fn transaction_callback() { async_std::task::block_on(async { cleanup().await; let driver = TypeDBDriver::new( - TypeDBDriver::DEFAULT_ADDRESS, + Addresses::try_from_address_str(TypeDBDriver::DEFAULT_ADDRESS).unwrap(), Credentials::new("admin", "password"), - DriverOptions::new(false, None).unwrap(), + DriverOptions::new(DriverTlsConfig::disabled()), ) .await .unwrap(); diff --git a/rust/tests/integration/example.rs b/rust/tests/integration/example.rs index b6932e8952..2141ae5b27 100644 --- a/rust/tests/integration/example.rs +++ b/rust/tests/integration/example.rs @@ -30,16 +30,17 @@ use typedb_driver::{ ConceptRow, QueryAnswer, }, concept::{Concept, ValueType}, - Credentials, DriverOptions, Error, QueryOptions, TransactionOptions, TransactionType, TypeDBDriver, + Addresses, Credentials, DriverOptions, DriverTlsConfig, Error, QueryOptions, TransactionOptions, TransactionType, + TypeDBDriver, }; // EXAMPLE END MARKER async fn cleanup() { let driver = TypeDBDriver::new( - TypeDBDriver::DEFAULT_ADDRESS, + Addresses::try_from_address_str(TypeDBDriver::DEFAULT_ADDRESS).unwrap(), Credentials::new("admin", "password"), - DriverOptions::new(false, None).unwrap(), + DriverOptions::new(DriverTlsConfig::disabled()), ) .await .unwrap(); @@ -62,9 +63,9 @@ fn example() { // EXAMPLE START MARKER // Open a driver connection. Specify your parameters if needed let driver = TypeDBDriver::new( - TypeDBDriver::DEFAULT_ADDRESS, + Addresses::try_from_address_str(TypeDBDriver::DEFAULT_ADDRESS).unwrap(), Credentials::new("admin", "password"), - DriverOptions::new(false, None).unwrap(), + DriverOptions::new(DriverTlsConfig::disabled()), ) .await .unwrap(); @@ -233,7 +234,7 @@ fn example() { // just call `commit`, which will wait for all ongoing operations to finish before executing. let queries = ["insert $a isa person, has name \"Alice\";", "insert $b isa person, has name \"Bob\";"]; for query in queries { - transaction.query(query); + let _unawaited_future = transaction.query(query); } transaction.commit().await.unwrap(); diff --git a/tool/docs/rust/RustDocsParser.kt b/tool/docs/rust/RustDocsParser.kt index cec083a78c..ad8afd897e 100644 --- a/tool/docs/rust/RustDocsParser.kt +++ b/tool/docs/rust/RustDocsParser.kt @@ -116,11 +116,11 @@ class RustDocParser : Callable { val html = it.readText(Charsets.UTF_8) val parsed = Jsoup.parse(html) val anchor = getAnchorFromUrl(it.toString()) - val parsedClass = if (!parsed.select(".main-heading h1 a.struct").isNullOrEmpty()) { + val parsedClass = if (!parsed.select(".main-heading h1 .struct").isNullOrEmpty()) { parseClass(parsed, anchor, mode) - } else if (!parsed.select(".main-heading h1 a.trait").isNullOrEmpty()) { + } else if (!parsed.select(".main-heading h1 .trait").isNullOrEmpty()) { parseTrait(parsed, anchor, mode) - } else if (!parsed.select(".main-heading h1 a.enum").isNullOrEmpty()) { + } else if (!parsed.select(".main-heading h1 .enum").isNullOrEmpty()) { parseEnum(parsed, anchor, mode) } else { null @@ -135,7 +135,7 @@ class RustDocParser : Callable { } private fun parseClass(document: Element, classAnchor: String, mode: String): Class { - val className = document.selectFirst(".main-heading h1 a.struct")!!.text() + val className = document.selectFirst(".main-heading h1 .struct")!!.text() val classDescr = document.select(".item-decl + details.top-doc .docblock p").map { reformatTextWithCode(it.html()) } @@ -167,7 +167,7 @@ class RustDocParser : Callable { } private fun parseTrait(document: Element, classAnchor: String, mode: String): Class { - val className = document.selectFirst(".main-heading h1 a.trait")!!.text() + val className = document.selectFirst(".main-heading h1 .trait")!!.text() val classDescr = document.select(".item-decl + details.top-doc .docblock p").map { reformatTextWithCode(it.html()) } val examples = document.select(".top-doc .docblock .example-wrap").map { it.text() } @@ -198,7 +198,7 @@ class RustDocParser : Callable { } private fun parseEnum(document: Element, classAnchor: String, mode: String): Class { - val className = document.selectFirst(".main-heading h1 a.enum")!!.text() + val className = document.selectFirst(".main-heading h1 .enum")!!.text() val classDescr = document.select(".item-decl + details.top-doc .docblock p").map { it.html() } val variants = document.select("section.variant").map { parseEnumConstant(it) } @@ -218,7 +218,7 @@ class RustDocParser : Callable { private fun parseMethod(element: Element, classAnchor: String, mode: String): Method { val methodSignature = enhanceSignature(element.selectFirst("summary section h4")!!.wholeText()) - val methodName = element.selectFirst("summary section h4 a.fn")!!.text() + val methodName = element.selectFirst("summary section h4 .fn")!!.text() val allArgs = getArgsFromSignature(methodSignature) val methodReturnType = if (methodSignature.contains(" -> ")) methodSignature.split(" -> ").last() else null val methodDescr = if (element.select("div.docblock p").isNotEmpty()) { diff --git a/tool/test/BUILD b/tool/test/BUILD index a2c8e02cc9..f8eecee4ec 100644 --- a/tool/test/BUILD +++ b/tool/test/BUILD @@ -26,13 +26,6 @@ checkstyle_test( license_type = "apache-header", ) -java_binary( - name = "echo-java-home", - srcs = ["EchoJavaHome.java"], - deps = [], - main_class = "com.typedb.driver.tool.test.EchoJavaHome" -) - native_typedb_artifact( name = "native-typedb-artifact", native_artifacts = { @@ -40,24 +33,25 @@ native_typedb_artifact( "@typedb_bazel_distribution//platform:is_linux_x86_64": ["@typedb_artifact_linux-x86_64//file"], "@typedb_bazel_distribution//platform:is_mac_arm64": ["@typedb_artifact_mac-arm64//file"], "@typedb_bazel_distribution//platform:is_mac_x86_64": ["@typedb_artifact_mac-x86_64//file"], -# "@typedb_bazel_distribution//platform:is_windows_x86_64": ["@typedb_artifact_windows-x86_64//file"], + "@typedb_bazel_distribution//platform:is_windows_x86_64": ["@typedb_artifact_windows-x86_64//file"], }, output = "typedb-artifact.tar.gz", visibility = ["//visibility:public"], ) -#native_typedb_artifact( -# name = "native-typedb-cloud-artifact", -# native_artifacts = { -# "@typedb_bazel_distribution//platform:is_linux_arm64": ["@typedb_cloud_artifact_linux-arm64//file"], -# "@typedb_bazel_distribution//platform:is_linux_x86_64": ["@typedb_cloud_artifact_linux-x86_64//file"], -# "@typedb_bazel_distribution//platform:is_mac_arm64": ["@typedb_cloud_artifact_mac-arm64//file"], -# "@typedb_bazel_distribution//platform:is_mac_x86_64": ["@typedb_cloud_artifact_mac-x86_64//file"], -# "@typedb_bazel_distribution//platform:is_windows_x86_64": ["@typedb_cloud_artifact_windows-x86_64//file"], -# }, -# output = "typedb-cloud-artifact.tar.gz", -# visibility = ["//visibility:public"], -#) +native_typedb_artifact( + name = "native-typedb-cluster-artifact", + native_artifacts = { + # TODO: Uncomment all platforms + "@typedb_bazel_distribution//platform:is_linux_arm64": ["@typedb_cluster_artifact_linux-arm64//file"], + "@typedb_bazel_distribution//platform:is_linux_x86_64": ["@typedb_cluster_artifact_linux-x86_64//file"], + "@typedb_bazel_distribution//platform:is_mac_arm64": ["@typedb_cluster_artifact_mac-arm64//file"], + "@typedb_bazel_distribution//platform:is_mac_x86_64": ["@typedb_cluster_artifact_mac-x86_64//file"], +# "@typedb_bazel_distribution//platform:is_windows_x86_64": ["@typedb_cluster_artifact_windows-x86_64//file"], + }, + output = "typedb-cluster-artifact.tar.gz", + visibility = ["//visibility:public"], +) artifact_extractor( name = "typedb-extractor", @@ -65,6 +59,6 @@ artifact_extractor( ) artifact_extractor( - name = "typedb-cloud-extractor", - artifact = ":native-typedb-cloud-artifact", + name = "typedb-cluster-extractor", + artifact = ":native-typedb-cluster-artifact", ) diff --git a/tool/test/resources/BUILD b/tool/test/resources/BUILD index 78998a4854..858eb50b96 100644 --- a/tool/test/resources/BUILD +++ b/tool/test/resources/BUILD @@ -26,20 +26,19 @@ filegroup( ":encryption/int-grpc-root-ca.pem", ":encryption/int-grpc-private-key.pem", ":encryption/int-grpc-certificate.pem", - ":encryption/int-zmq-private-key", - ":encryption/int-zmq-public-key", ":encryption/keystore.pkcs12" ], visibility = [ "//cpp/test:__subpackages__", "//csharp/Test:__subpackages__", - "//common/test/encryption:__subpackages__" + "//common/test/encryption:__subpackages__", + "//http-ts/tests:__subpackages__", ], ) checkstyle_test( name = "checkstyle", include = glob(["*"]), - exclude = glob(["encryption/*"]), + exclude = glob(["encryption/*", "config.yml"]), license_type = "apache-header", ) diff --git a/tool/test/resources/config.yml b/tool/test/resources/config.yml new file mode 100644 index 0000000000..ac9d2a9404 --- /dev/null +++ b/tool/test/resources/config.yml @@ -0,0 +1,32 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. + +server: + address: 0.0.0.0:1729 + http: + enabled: true + address: 0.0.0.0:8000 + + authentication: + token-expiration-seconds: 5000 + + encryption: + enabled: false + certificate: + certificate-key: + ca-certificate: + +storage: + data-directory: "data" + +logging: + directory: "logs" + +diagnostics: + monitoring: + enabled: true + port: 4104 + reporting: + metrics: true + errors: true diff --git a/tool/test/resources/encryption/ext-grpc-certificate.pem b/tool/test/resources/encryption/ext-grpc-certificate.pem index a422cc3f9d..64509bbf3a 100644 --- a/tool/test/resources/encryption/ext-grpc-certificate.pem +++ b/tool/test/resources/encryption/ext-grpc-certificate.pem @@ -1,42 +1,26 @@ -----BEGIN CERTIFICATE----- -MIIDwDCCAqigAwIBAgIGIvTsxFdYMA0GCSqGSIb3DQEBCwUAMCoxKDAmBgNVBAMT -H2VuY3J5cHRpb24tdGVzdHMtY2EtZXh0ZXJuYWwtY2EwHhcNMjMxMDA2MTU1NjEw -WhcNMjUxMDA1MTU1NjEwWjAnMSUwIwYDVQQDExx0eXBlZGItZW50ZXJwcmlzZS0y -LmV4dGVybmFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA32v7/RUf -4zPGgD/TX9o3rsJSZIXtnChubznJ89mQleJh0Fnc5N3OoWoGmQ32Lky7odAFFmFM -rVM9KMo3lwrDhYtwNcPdnAtXZWDF/gjYbs66KoZ6YxAO9/qNPs8fvY6hFiKta50j -DlsO0LQ/bKtr5WB9JQU8dVFSY7g3eaQC8XT+Gqwvp1ykHN/pjWQ1DQoB/5H6U65a -zYS1e/4b/kO7jNRjwnp4OZgcQM/k5YpkygbgIo8LA4YfC6x6n0hdJXWzJll+Vaay -oJZDbNH/EtxkcCQnPwEZonUZhATbnOZro+D/P6+7e9vm/dCdfoSNAc95udUcuDSU -zhQ/rujPNjyzGwIDAQABo4HuMIHrMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQD -AgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUIJTZ -4oOuMrLvvWLb12fnLJLhXI8wHwYDVR0jBBgwFoAUU7osc03EU3j/h2NuMjH4TwY6 -VmMwbAYDVR0RAQH/BGIwYIIcdHlwZWRiLWVudGVycHJpc2UtMi5leHRlcm5hbIIJ -bG9jYWxob3N0ggsqLmxvY2FsaG9zdIINKi4qLmxvY2FsaG9zdIITKi50eXBlZGIt -ZW50ZXJwcmlzZYcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAE1wPIT4g8A7J4K8N -+sk7aQ5fSWlbqtD0WG297eyr84APG7ezl8Hnpx+EmXSSsqi6Nmu/Tgpe0ftV+CfX -cbgppttsejgV6Tz0SZlrDAOkAlnU9jqe/581XsZxURP66Yz6XHc3OEh4bNPoU1WL -RcnAr+ydZKqexrFudPy9O2qP6UfAIOBxdO8ugFBqQFFz1aVZkLXXFwJiKXTq1Pr7 -gKPdZ6fuMtyUg60Ga/4WVJE/SvFjuwGi8BGxlTQWzhyjhHGCSb9fWkStUWCrAFW3 -a4sid3bRc7G9PSmbsb5C5vPeSgfLwn+tjLh6GCGA2eWx0/1zYZOIP2m2N5NPE/Ru -+5I3VA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDFjCCAf6gAwIBAgIGIvTKkDclMA0GCSqGSIb3DQEBCwUAMCoxKDAmBgNVBAMT -H2VuY3J5cHRpb24tdGVzdHMtY2EtZXh0ZXJuYWwtY2EwHhcNMjMxMDA2MTU1NjA5 -WhcNMjUxMDA1MTU1NjA5WjAqMSgwJgYDVQQDEx9lbmNyeXB0aW9uLXRlc3RzLWNh -LWV4dGVybmFsLWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4iBw -NzgEQG//jCfRpHtIsZggHB4AWTfCzr69zrFTUFejcF21uZJ1Y2YGYPbUVTDspWI4 -8k/N0qlw7nd69EjpEfd/DDk7fYbGEhAMVsEpBtR3+BTP9sQ2tj9YUExaSEpkdOSD -s0+qrhgoisVyhgmK3eg23A8afLWKs9U9HWp4vnJQ8gQBkrvMxXKjpE1lJE2L06c7 -Jnah1TcCzhsUF6aysnDW/hiXg3A3nO4w6QezuOvSGa87o63NkJ5h8n2BH/gdzj/H -ijMTpFWdmhYpOyw4Kxx8s1/eqO8W6ate/0lXWQadZnlMVQxKaZOYkhNCWzTq5w+l -yUSxQU1f410Wnn00KwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB -/wQEAwICBDAdBgNVHQ4EFgQUU7osc03EU3j/h2NuMjH4TwY6VmMwDQYJKoZIhvcN -AQELBQADggEBAGmgZ4eVfiP65BBAd4RW8LvcyQ6LqROz6HrzdhbaildhWE6Qam3U -aG8FcxLWNuk0z/vhHHTjusrYmu6qjX0HEVmYn3HHOKMXlgl3FANAenuufVKPtOlg -DUbkqsqq0X3bEpFuuCqhASc5tcIfBxnPbNcS1PmIepsj1EiobUik3/Wizsdi6KM7 -ayVtak915BX+dfITI1ahp6feT2GDJlMJHBwnVIZrhlj8Y7colsy+HaagZmG/wyL8 -La21heQGnB5o1jFvV9zQFpY7x/RkrtqFrl1ePMgsAAAF82j6pK/Fis/m8QE0J9+R -W+cjidCIQhuZU40UOUK+CeZN4rdg7v7JTO0= +MIIEdTCCAl2gAwIBAgIUUdkmu4X7HSRYcAh6BQkym7K9AvEwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCWFgxDTALBgNVBAoMBFRlc3QxDzANBgNVBAsMBlR5cGVE +QjEZMBcGA1UEAwwQZXh0LWdycGMtcm9vdC1jYTAeFw0yNTEyMTgxMTI2MDZaFw0z +NTEyMTYxMTI2MDZaMEExCzAJBgNVBAYTAlhYMQ0wCwYDVQQKDARUZXN0MQ8wDQYD +VQQLDAZUeXBlREIxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBALK/ukjp/1Bsh4chPD37rgVHlHdUqbg1/1a/xmeY7+71 +7ARQc9ZGtvsTJGhxp+zzJtcFWuFJRxAo4pz9dKsOYX8noAdQsObQVpDzpzcl1qKg +SdcZVAYUmYSE60QLPYmoaQCDUZMAfH4DpGAIWe8dH6ZXqc3bYVzCQCWCxUIVwVBQ +8Me1nPFe+lxcA0D2yj5I1LpZaPhWw/iOmjOTlwMuqH+X7dyffooSy7+EYblWvaCF +5hJS8D01iJ5PXgoWd4Gk+Lk4VWtXwbeli+agd60UYgvxogSJFXvYZHk3XDp2gJO8 +af1OO5l43lcFhbLvN0VyELNLhe2JThCXXUmNYV4IE/cCAwEAAaNeMFwwGgYDVR0R +BBMwEYIJbG9jYWxob3N0hwR/AAABMB0GA1UdDgQWBBRCVfdKvD7hYmpJ0ZzHLIEY +VdG3ozAfBgNVHSMEGDAWgBSU1tklqHzPakfK4w9Pq11isWAuYDANBgkqhkiG9w0B +AQsFAAOCAgEACYVC3tIBy3lSgTQ8hcgV5dqCo74mII61JkNYYOkVGmR6f67oumRQ +LzFORNf15rpafH8nucd/GsOYVW+xNOpn+kkanOZNvyC2Jt9tq40+kJF69c7EwkJz +iZUjT37H0y/Ch3VMhf9zrhdq0IEQNlaN4ZQ6oJ0qO7pqzXvhrOr7WLslKjPNyuBe +TqyMUdYTQQ9QfKcR4/56f6ZZwyb57g51+b1VDgmyoVLwru3ivaT0HC7Q1WEiCTHC +gqVudXr5vfK/U5k/poU5wEEOvoHnZUpzOp5qOcZN684yvq7dm+DLXepdvmF8EvRo +WNEdvx7ryyJ5N7cyaapUz9BdgBboQufAmUSiIEBUUwwASU09dKjujlwhdNN/Llkq +xYqsTY6J7mh2Qr+SpIhLI4k9LKqRudHo7981iCYlTDlfEA1x5Mpcqb/iuoBWAMme +2aqyzCyM1IBdGiHjwNKNDiJZH6b8+5dtbu0leToaQIp7IiuGF43xw6aOSFZCR1Sz +LDr9GexUGd0IhP5ykRciPCbMsmWRQhM9W/LJ25bZpZaRRe/PpVHbHAk354OYfkAo +QcNLli2Otr50RkkMiOXyuZl1G+YxLASo6SlhrMYYCji3VyzLrfGvZpz3vZLIprNa +OYuOcaJmuN7JlBNpN5XwIdrRb/zZMHCR+XJCy9pYj6uJNzE/VnASeXk= -----END CERTIFICATE----- diff --git a/tool/test/resources/encryption/ext-grpc-private-key.pem b/tool/test/resources/encryption/ext-grpc-private-key.pem index 33d9a59755..d2fc7f2ad3 100644 --- a/tool/test/resources/encryption/ext-grpc-private-key.pem +++ b/tool/test/resources/encryption/ext-grpc-private-key.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDfa/v9FR/jM8aA -P9Nf2jeuwlJkhe2cKG5vOcnz2ZCV4mHQWdzk3c6hagaZDfYuTLuh0AUWYUytUz0o -yjeXCsOFi3A1w92cC1dlYMX+CNhuzroqhnpjEA73+o0+zx+9jqEWIq1rnSMOWw7Q -tD9sq2vlYH0lBTx1UVJjuDd5pALxdP4arC+nXKQc3+mNZDUNCgH/kfpTrlrNhLV7 -/hv+Q7uM1GPCeng5mBxAz+TlimTKBuAijwsDhh8LrHqfSF0ldbMmWX5VprKglkNs -0f8S3GRwJCc/ARmidRmEBNuc5muj4P8/r7t72+b90J1+hI0Bz3m51Ry4NJTOFD+u -6M82PLMbAgMBAAECggEADIIKIHgPSfP7F/D6z3HzDhiY7kHFNKnazOVKVhmHC60Z -1sVBJZr5V3YNGoJ6lsr68isoLcGSvl1bni38ALu8iHxu8sOdY4ALC4TocLlkDIgM -ShcvQN6ESAPB5pNH7p/OiuO0G8M3VDVq1epRZq8OIlBNkUYCxXqhBy4oBOpWs9fD -HDbI2TLSrAKYkWtssBBn1xrFWbFClp1auOSQMvC5VSkMGden3Tl4YUyMtajtAoX+ -C3P1K8UeXN6EBls4Uf+VXHVjLomkqTviEe+N8o5GufmAOFWNZjCA47X2Z4/ryZjA -HveSx/bdvJOOONOcouuanqzoHGCgJXSEJx6BuxFi4QKBgQD15VkTtrX05tTf3s1S -ZLOyMWedXGuvV8w+iRd29R9IxI2sYXUbHj121lqup1iQgfEO/OHzsP1x4uJytV2t -QRamowLFJEpn0/p7phiLSbzaA2Hn5dhEYAAM+0VMCQXMftJRPXHjvqgmoPb9Z3VP -khRS5ix26Q2ItzW6sg9hkDO5ywKBgQDomjmRTPwYuIBbYtDKRb2Dirirf7ICVkGv -qFzVxb8MSu+e04llaxUKHZJyTbW5huGoBPO6ePWDpRCUYJW5pSm3dLQs8+brN746 -N8i9qxrYn62C1L6n7LZILQGPDXhszT6QccLrPPuI3JXjmrv3sf/XVcAJbSOFoS80 -kF/2b1MB8QKBgADTUEU8q8eyrqxBtza7l87VU5+3m7Tu+oSLOUTw9bXs0vztJtN8 -eoBXn95OOYHirch7GNcUlQU42cHA0huuyECu82duA8HteD3KBPMSwEuLD10T7HHu -UJG6ljT3IsnY8yPKrQMytKXMjIe1PTOTLfZJR4Tuq1j2JHwH9P1C2qmZAoGBAJDJ -58nNrSNKPgQk16kBjn2CbX+7xjf0L4FDgT5EkK77OnuYW+94n6kjTVS/kL5C+taW -9ox93P4sUsy57pmX+QbMq5dL39NNaKleriN6jgSIKP7GpUNscu8srMq6bNr1S9uo -JNg/pqfD/72lRRpjf8kwBJEZkcIN2o+Sy1lgZMBRAoGAE3Z7z4bizmWcp9p8kvbp -KKoE55nApUHBlPesaWFMqUkMvFhaWdqzfjagTxHAht0nFOHm37157+TMmtYmY/0F -XeHElrP7AqJD2/iaZme8vCjgdLZM1IHrbb+tlaX1sHii059mD9p5m/os01ulHoo0 -rMasBTPyfJtTlrcJU3yAU+A= +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCyv7pI6f9QbIeH +ITw9+64FR5R3VKm4Nf9Wv8ZnmO/u9ewEUHPWRrb7EyRocafs8ybXBVrhSUcQKOKc +/XSrDmF/J6AHULDm0FaQ86c3JdaioEnXGVQGFJmEhOtECz2JqGkAg1GTAHx+A6Rg +CFnvHR+mV6nN22FcwkAlgsVCFcFQUPDHtZzxXvpcXANA9so+SNS6WWj4VsP4jpoz +k5cDLqh/l+3cn36KEsu/hGG5Vr2gheYSUvA9NYieT14KFneBpPi5OFVrV8G3pYvm +oHetFGIL8aIEiRV72GR5N1w6doCTvGn9TjuZeN5XBYWy7zdFchCzS4XtiU4Ql11J +jWFeCBP3AgMBAAECggEAVRUz+57+O27dd/HW9f4FkFfJEKAJBTkWqFkyfH9svcbr +KAaPjNAuKwaqjtiCwSPgOfs/jfrOS5/adjWiwgVfXSIkZzb+bW9/tRF1Z6eoKdK4 +Mx3IQ/isNkr6nXHoQc0a5fab7qgNmgHrzRZMkKfBN/GETwt8paWE2RYNBO7MDIke +0puxM987BnGXpu2liLMZ7frpMGdMauTrXiKC0+1VJrvSL48ZDfpRFhsdQ8nvVTgT +jOi6oIL+KPgWJmXxieNOmbiSjb1/PTR3BKsWBq58P64SMK8gE04Fs4X17hl5qWoi +Bkt2XsiY7Y1u5kMXYVdFKopu5GqiLodGVaR/ZhV0sQKBgQDaY1VVcLz4vOOywb79 +JSfwkVwSMpPxcu9lGVIca74MMDtYs9GQ2dQkdPbPqee3b99XyDse7WTebgEkPWU3 +y7/KKs1XzvYrSFK9Bbk2JEqU2Sa+azGi8fGqckHTFGsS4TQG3plZlPkYTHTukHPd +op9Rbaj0ldWPuDLA1LYzfrXmuQKBgQDRiLfcKm/fv9j4Gd/IhCCIgG45s+Q/qGoZ +9Igg4iI0oRcAOcoXTX5Z80Jps6jOBAMs9gxuTqk+Zbo87jLSJ+ibr3Slu9Pvtxdb +2x3wIvNJI5M+Auo2ouW1gliEpI1F1vAv17NPW7N35fYK/NB4Zf/8MKNV6apy7T72 +C/z6TFx4LwKBgQDLcwrGZBbIK0B9AZ3puzmwFdsOYOwOXaLELoieTYlpVW2UP0EW +jrfhls1vvLtP2vrYjoL1VvdHeHe7yS6IgloT/zf5e6c9v0zFJ5XZ6IlKjdpYPwio +4nje7z5/ZGAz4HVViP6Xw/8jMeclcJFgguWlOGHUKdog39r4ZbGv23WekQKBgDsl +4ODhidsbiN/gTe+IfLaLqpHXWiMuI2VYReUicI1yu89wgL+7PGOf66ty77/YGh1j +B3dL9TKL/NqeUvJIGb149fCi6NzOTmW7oOPcudh3lmT25a6upTFrrhkjak3AsuSO +eyt3s12xKJdJbn/OK0jBYhoqb9cpaZCDKdJuI9w5AoGBAIGldn5om0hq7/jsDP+O +UbqQGQGtKBYSc6Z5NntW82BBh8gKzCs0q5VUskD+Ykj0w1SNtmtvVSsjQ1KX0pKR +jHOpvdu18Iwyn7+Z/94laKJ5MT/OY6ZUo2VanzlzSCc/GpQbXlmTWAaOfK+6B5J8 +mO9gZGRrytS5b8qBsd0Y8OQD -----END PRIVATE KEY----- diff --git a/tool/test/resources/encryption/ext-grpc-root-ca.pem b/tool/test/resources/encryption/ext-grpc-root-ca.pem index 545185df10..92084cb23f 100644 --- a/tool/test/resources/encryption/ext-grpc-root-ca.pem +++ b/tool/test/resources/encryption/ext-grpc-root-ca.pem @@ -1,19 +1,32 @@ -----BEGIN CERTIFICATE----- -MIIDFjCCAf6gAwIBAgIGIvTKkDclMA0GCSqGSIb3DQEBCwUAMCoxKDAmBgNVBAMT -H2VuY3J5cHRpb24tdGVzdHMtY2EtZXh0ZXJuYWwtY2EwHhcNMjMxMDA2MTU1NjA5 -WhcNMjUxMDA1MTU1NjA5WjAqMSgwJgYDVQQDEx9lbmNyeXB0aW9uLXRlc3RzLWNh -LWV4dGVybmFsLWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4iBw -NzgEQG//jCfRpHtIsZggHB4AWTfCzr69zrFTUFejcF21uZJ1Y2YGYPbUVTDspWI4 -8k/N0qlw7nd69EjpEfd/DDk7fYbGEhAMVsEpBtR3+BTP9sQ2tj9YUExaSEpkdOSD -s0+qrhgoisVyhgmK3eg23A8afLWKs9U9HWp4vnJQ8gQBkrvMxXKjpE1lJE2L06c7 -Jnah1TcCzhsUF6aysnDW/hiXg3A3nO4w6QezuOvSGa87o63NkJ5h8n2BH/gdzj/H -ijMTpFWdmhYpOyw4Kxx8s1/eqO8W6ate/0lXWQadZnlMVQxKaZOYkhNCWzTq5w+l -yUSxQU1f410Wnn00KwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB -/wQEAwICBDAdBgNVHQ4EFgQUU7osc03EU3j/h2NuMjH4TwY6VmMwDQYJKoZIhvcN -AQELBQADggEBAGmgZ4eVfiP65BBAd4RW8LvcyQ6LqROz6HrzdhbaildhWE6Qam3U -aG8FcxLWNuk0z/vhHHTjusrYmu6qjX0HEVmYn3HHOKMXlgl3FANAenuufVKPtOlg -DUbkqsqq0X3bEpFuuCqhASc5tcIfBxnPbNcS1PmIepsj1EiobUik3/Wizsdi6KM7 -ayVtak915BX+dfITI1ahp6feT2GDJlMJHBwnVIZrhlj8Y7colsy+HaagZmG/wyL8 -La21heQGnB5o1jFvV9zQFpY7x/RkrtqFrl1ePMgsAAAF82j6pK/Fis/m8QE0J9+R -W+cjidCIQhuZU40UOUK+CeZN4rdg7v7JTO0= +MIIFcTCCA1mgAwIBAgIUaS2D4aHVnbqekFwOQCNWNPxHXz8wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCWFgxDTALBgNVBAoMBFRlc3QxDzANBgNVBAsMBlR5cGVE +QjEZMBcGA1UEAwwQZXh0LWdycGMtcm9vdC1jYTAeFw0yNTEyMTgxMTI0NTBaFw00 +NTEyMTMxMTI0NTBaMEgxCzAJBgNVBAYTAlhYMQ0wCwYDVQQKDARUZXN0MQ8wDQYD +VQQLDAZUeXBlREIxGTAXBgNVBAMMEGV4dC1ncnBjLXJvb3QtY2EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCYFZhVkZt7Xl9s/9SzKgadhfFs5bJToX+H +ViZ2mfx3yDXGdHh0ucjWckPck/sTRCOjPkVx+dLseWTllWMzYM0LYIok/JhkUvKu +5YZGa6otwGvD9N6PMGp4rjwnUa2Na03jo3ZN6WpS7tWH9PtHC2HDCxtI8Au6jIHr +6GxY/senmZPw45om6yr/Ayl+AkrtIZ06Lvzv4/aNPt99MHSp53BsM2uxP/1+z/2T +RxHEzHTAw1tBdMEf0zW1Qvwwkr3oUjTsg38WakhxsQqiatVgtmu+bTUamUC81aI9 +hpdFPWJIhAyB1vGX89dRkFx38ighyctsk24E01Fl80OJ1eQw7N6Ft0DROe7voOxm ++7ozrGvw11wE9dKnIYntZwAF2d7VeNDluHDTOgQQ2va1bSmRVJ37foYoUxUFkK1p +3NYvmUaU2fWn8eOcPvJsy45rjv0ikTMGjFBHneA5QNxEMjLIjNwA6aYCda4uYw4f +3psD2DnxYvMlLO31kzX5I6ofQaAXzFdtapDXLS3/sASMMq3pjIBP5FcX45QU/Wtk +8lLwGksrnz1WTaVc4MkgUG9ak7koqW5HJZnc/nSN/sZ3heVitAclc1UrPRbfbI+D +m2CDAVvF2Da3VgZNuQyTPsCxCzVQDYOPxCbUeoDcjMFiW4byo2jj98F0NDZ7HBXk +SdNhHyB6CQIDAQABo1MwUTAdBgNVHQ4EFgQUlNbZJah8z2pHyuMPT6tdYrFgLmAw +HwYDVR0jBBgwFoAUlNbZJah8z2pHyuMPT6tdYrFgLmAwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAPnjfjUhzW3RMbu/Mxkt2FJUS+IZdLfGvdxTU +bJA5nSjiTt11nMJUhc0BN7a/912x1fN75OKyG3OGsBmsJgkoa4HYuFTyUqOPwbWA +EXtvrkA2QEr/ux8vgGILL5xLYXnaczRBm6yvUVVq8G7JYH7bNzFlBkXJvU4E05Pj +bKEhPSghsnaGSvPzckkvT6JGbLzeYsqzEuED8JpM76A/ygYXh5z596YWqN+G+lRr +NGaWtbHEFyivriFwtEgnMyIMd4zvuCsua3RFFwLms0eqV4qJ5CtI1jrc5ZJpjmsS +EyoUfKhk7CR3VZxSRtYqfe0lTrMJcUGgk+U0z1AAXNr4wCYI6+GevJcZTBn0Kfbe +7312dnxnfNCL7DOAojEmG+mTQ6mUsSR3PXHouIvB6V0zi8ya8sE4I0M+W+dAbsP8 +fcrbQeVREcEwjHhymun7zbJL1Y/F0b1HtJZVQ2p9OmsurAhRe7F6ydyWTyU/735t +knTzf1TgWfcwyK6u9JF1CK+IIhSqY3gS9d0S4K74WQy5gW3lUsOnQEh+qOLZTml7 +7Y4bpcPZAXgGWCsJ0P2jrR50a6zoWky13jVZ4T7v9pHlaUrSXgdtnlACv1cFhDH2 +HZv3jyq5cIJpQBkL/ZLQIcwpSsT6sS9qtJhkiprfqsuhyL1G6vjRrOF5PvYZSoUM +NOst+aM= -----END CERTIFICATE----- diff --git a/tool/test/resources/encryption/int-grpc-certificate.pem b/tool/test/resources/encryption/int-grpc-certificate.pem index aa8e908c2d..940d5b98f8 100644 --- a/tool/test/resources/encryption/int-grpc-certificate.pem +++ b/tool/test/resources/encryption/int-grpc-certificate.pem @@ -1,42 +1,26 @@ -----BEGIN CERTIFICATE----- -MIIDwDCCAqigAwIBAgIGIvTvaVh+MA0GCSqGSIb3DQEBCwUAMCoxKDAmBgNVBAMT -H2VuY3J5cHRpb24tdGVzdHMtY2EtaW50ZXJuYWwtY2EwHhcNMjMxMDA2MTU1NjEw -WhcNMjUxMDA1MTU1NjEwWjAnMSUwIwYDVQQDExx0eXBlZGItZW50ZXJwcmlzZS0y -LmludGVybmFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5QuaAsDI -pWBlDiLFFlY1HX27VA7PdpmPQwjWV1eeX66nto8CY8tWk1MGegSk+g5s+M6oM+cT -4OYPyQJI/szRCI8ScEsp2N2cVfSmR+QOBWhQTKhWej2grRESMs2lRIn7hXXJU0ox -BLc003iPdyAyJtPzfugUutayLBnpS7wC39jVMyUZB+Ey66I1R911E9sdRsrM/vij -UMcOPMGA7S0LyMhh9aasmKRwFXXk8ClV3IkNgUWjycM3aL3MDiWwjQqz8NWN7q3Y -6bWV11KG7M/Gn4nj5MhLcK7/0OU8QgMI/IclcSZ0oKojwvx5MnBHMTkc6i0uub3R -Ue75q8tYShCNLQIDAQABo4HuMIHrMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQD -AgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUajJU -T5eTYl71OwAMBixd6VOFukIwHwYDVR0jBBgwFoAUMCttbOTJP+DErp6BZfyMpTjS -JjIwbAYDVR0RAQH/BGIwYIIcdHlwZWRiLWVudGVycHJpc2UtMi5pbnRlcm5hbIIJ -bG9jYWxob3N0ggsqLmxvY2FsaG9zdIINKi4qLmxvY2FsaG9zdIITKi50eXBlZGIt -ZW50ZXJwcmlzZYcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAJSga4tu1z7vah0Ib -HifAJpaVvbxGzbXJGWmVxTpRfB00M4uuprkElSRaYOzKe1HP4AAmejE6q8in5Snp -zOKic4cKZArkp/QV4f60Vy/+DTgXPp8zeWGijULXnNVHfP97UiVNGZGRLw16/FOs -fNHgcYmyswU0BiiAL7F17KOAWhA3f4cRJhzV+KNeK3NlNgpoT49unAeJwPPgDcee -UtzARxTO7M7d1w2cMRaup5v4sbsGked37h3GwhX9WfwBM2RqedstSF5p01H4fU5q -yck2vvp09VdRs48CGMT9o7hPqVuvQmNfpMHbDtZ5wDqN8p3zV95s4bs3biInNFWK -R4TYEg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDFjCCAf6gAwIBAgIGIvTTLeNUMA0GCSqGSIb3DQEBCwUAMCoxKDAmBgNVBAMT -H2VuY3J5cHRpb24tdGVzdHMtY2EtaW50ZXJuYWwtY2EwHhcNMjMxMDA2MTU1NjA5 -WhcNMjUxMDA1MTU1NjA5WjAqMSgwJgYDVQQDEx9lbmNyeXB0aW9uLXRlc3RzLWNh -LWludGVybmFsLWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj7Eq -XHM//xBc9cNDxb+NEF7XISqxkxbeDyTyDemLslN4eIjqfEEdlj121B4xlHttxo9N -CGhohirddqE+LD0EYEKnjNo5THY8zzmB3s+qMCvybS5ytqKNGMHy7eAbF2zsoMZt -P3PLaVQ+WEM5Dlyv7zPPJsEz/jxC89CARi1LqXqQwv7tDcFUaZMVKKDOLk6JouE7 -zZlezzoll2vzINBSfHfHC2J/37e8hvyQWHhvYhUTiap8pIaBs8mqW01t4YlR1Ckz -49u0DNKKMoGH0KjtmS+qmhwODlZlroRv4P3t4iYs3kNvBhVH1CRfcnyzLuFRGiin -h9kSJTYy861eHQ6JHQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB -/wQEAwICBDAdBgNVHQ4EFgQUMCttbOTJP+DErp6BZfyMpTjSJjIwDQYJKoZIhvcN -AQELBQADggEBAA58kPtGXMQ/NVUQMY45nUU25+MWQZJq+iGdhL3+XWQzsbgaLg55 -PviOFN5e6F/KtLFh/kutZRMrwma8HFaPIPKdZ0xMahh5GXoFSBV0fCk7A/mOKRgO -cf6717L7VB/oRVFt/5FRcJpCe57R7NpAD6dGS5d4p8XR7dhM8qf7u5ueasa5aNQl -3+tO9g+QhBUIwGQMohARF3bePN5nlLajrIbUnJmvCuT5GVN29suH0wvfeMi4uzWs -sww+oc01SoIsDW21/I2r6peVZaFlUsRT2Lcvz4YQ0wLoTHlvxbN12mfohRzJSYlm -jKksHe63Qbv6j7GpZBLei+O4H//UbY75EVQ= +MIIEdTCCAl2gAwIBAgIUGccZXoLx9GV+0YdwU6aLgZfcP/QwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCWFgxDTALBgNVBAoMBFRlc3QxDzANBgNVBAsMBlR5cGVE +QjEZMBcGA1UEAwwQaW50LWdycGMtcm9vdC1jYTAeFw0yNTEyMTgxMTI2MTFaFw0z +NTEyMTYxMTI2MTFaMEExCzAJBgNVBAYTAlhYMQ0wCwYDVQQKDARUZXN0MQ8wDQYD +VQQLDAZUeXBlREIxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAOk8b2plxMhiGB/BylHuRiSdjfDf7qGUVdoEFpKgWjQT +NQ+Gppw/toilN6ucbnfiLMLXvcvCfzUUnkCBxdcAFAocOuuPFDgeFv0Dw4uXEG0Q +Bey8kprUU9gMl026Rx+aLlxjI+jqMXa+58dc/ZmeYkw2XS0tfZbq7bX19z00nrJJ +bQ4JhwINyK61yOzmnLi8uBZMn6xPK+FchDMqwJVpCr3STf6BIR232WBXfJKJtaZW +m7qfkwf1tYOfr4TLPkuIBFVqgqYqKhOLry7hJf1W9U4Oc+eJa2w3R1Fy/GL/tASi +wEl17C+B/+cjIspBsfBxzfHFbGWHHF5U1b8j4C1Usg8CAwEAAaNeMFwwGgYDVR0R +BBMwEYIJbG9jYWxob3N0hwR/AAABMB0GA1UdDgQWBBTbDvrVYUje26Wqk96R7Q8b +7pAQ3TAfBgNVHSMEGDAWgBSRLd40Q28bKXwS224936iqYviTCTANBgkqhkiG9w0B +AQsFAAOCAgEAeJ4vExj054aA9CeWNkCjmNnYXjqTttzwXt8vpp4gLhzEEgnx2iw8 +DODK6pO+VdakNNrWTHFtqOybrG9vQfpXxEFs2c3LGIhssz1UA+SfOA2r+6996RUu +464ZrvZkyilaet9S9E3vuTpxBGjfp4Uzm3ogJ+fGTmbv5zfybPYRVmLyg6uf5/gn +3NXGjoLEMJdFI1A0t4djus789IxvXbypbG27R78wKsHQOA5DR4mQWJSuVvg1zaDK +QNfm2se3EvzDX29P78gk+fg5m+5a2qYBLe2JSrKaz1qGsehMi+lSpLJMYAmiMIik +KmC9VHskZh3ROKMf+sTuW22E5IRLpMCbq4Uj5nxbYNqhXASuZcLycfRLpy0jnpF6 +MZCycxVpNFAloctwKzqoPWrVqhDrhQ4R4YGnr+w3gzOkvok8HCjAGkd1Mux51Npk +CkhOLwUHFoZO0X7Pc27mn+PYTu9U9oha+P6yPtBxaaaaX5+7Y++muZ8rUzgLtTxD +DHP3qzqXOZKZqwgcbJ0OBkQ9Yiw3I9pOSareSRsoGAHVKsT//rUZWfxL2C6vKxbC +qZjEP+BxSKUgGTT+/pCX6Jj57R1nf9+FPU/nZJpPMU8zRKyUAVi41tmGsAgyFDfs +rE/2wRbugQFTY69pShgxsbi5mkteL7468Ba2bn+QvyMbd1tJ/+KpOWs= -----END CERTIFICATE----- diff --git a/tool/test/resources/encryption/int-grpc-private-key.pem b/tool/test/resources/encryption/int-grpc-private-key.pem index 70f7f1c90a..2340c2df36 100644 --- a/tool/test/resources/encryption/int-grpc-private-key.pem +++ b/tool/test/resources/encryption/int-grpc-private-key.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDlC5oCwMilYGUO -IsUWVjUdfbtUDs92mY9DCNZXV55frqe2jwJjy1aTUwZ6BKT6Dmz4zqgz5xPg5g/J -Akj+zNEIjxJwSynY3ZxV9KZH5A4FaFBMqFZ6PaCtERIyzaVEifuFdclTSjEEtzTT -eI93IDIm0/N+6BS61rIsGelLvALf2NUzJRkH4TLrojVH3XUT2x1Gysz++KNQxw48 -wYDtLQvIyGH1pqyYpHAVdeTwKVXciQ2BRaPJwzdovcwOJbCNCrPw1Y3urdjptZXX -Uobsz8afiePkyEtwrv/Q5TxCAwj8hyVxJnSgqiPC/HkycEcxORzqLS65vdFR7vmr -y1hKEI0tAgMBAAECggEACgrnrk44nfOriqKgpJmUC557K7TYiNkzzFsjVsILOiPE -y77aenisa5o80vXILASc543cFyZ/GyHLOGOGwtFFKwxm4RCSnaUd2TD4Z3eK29bW -in3pCMQR+vSgKSUWJXqtUg03jhTXMF8+DDWhiLYbLNOnPf28BvMp7cAXGBB+ycS5 -W4YL3EHqqlf3qwGDZHTJLP7gjnfr2nLf4f4bKRtU2RZNwzynY/tqMb6qXJzt5QO9 -L4Cs1fHoUaFQBnY6c/vOPiCFhMkPPWuigOrCPCAnSOf+1PVq/TK+bRY/V1SkPfJb -9sio10ontWZ02ZtVfQ/MIQqOEcNZ+XqxHuqasO36CwKBgQD2WlS9HwmLd0Jhsrik -vMAoN+/IZBnxQ6X3nKb17b+K3IDRg50L3voM/DBcuz5Ng6BqeQjtK/CWq+MqQWX+ -HZDVFs+mCA4IBuPG+BAjMGdGTRSHSG6Q1b1MTa60CE6EJD/c65MBkhOPWuezoOuW -adxxgHBtaIVJ3dN9skfLMWMqbwKBgQDuA8OKV8d9vL+CEVGt/7EyGqe9+GqVJzZZ -8dg/EvvUL05knA0L42vrWPvBjks/xClA95b50vzgqAoxNc7OKwgr66Or06+Jv9zo -FHebeNfqjnronqUDvN3eHNVL/l9uebNQFOkkksDlyQp1piu5yUCACmUJRgwNU4e4 -O//d2npAIwKBgDnORGgEKmcxWsA2AaGWMLi/N2KcKoI0T3NkrMC0QufAifGfonAw -qBf37Rk1To89vZx+Phv43YFdX/aAVgBky6FUsvDQnwo/I5+CgbbgGruiRpjf5CHU -JZEMAVx5PoM/RkT+egY6UqCmwguiTOWEfZecfcUOa4hDpuatuK7zLcO9AoGAazhw -1xpx+LeVge9xXzPnTA3r8M0+nlBa0Kv84XUY0t44r2QJEIjzrcKZLvl99ozUlLq0 -XXhpiH7KkJ6PuhpyhO6S/a3PzvsKddX6h6QpiDWFMtN8vLFRNWTBxYkizm6uk23I -FTyy/xDQ0Gz6F6iMkOGd4E6Y0UwGwLzup69rEQcCgYBlnzaQ5nB5tQ2rzumA4cLq -NxATTWapr0nj5tMIJt50/x8G/5CQBS2ftjhoM1nwP4Y+Qs2dTz5ZCFzoWxNXaFEN -JYDZHCOnhRetzkcQRcUR6FG/VAVLg4t3AdDY+iqMUayfqzZrMvmPKDDraTk5k19k -+KMEAtl+uZVWKijVd6MypA== +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDpPG9qZcTIYhgf +wcpR7kYknY3w3+6hlFXaBBaSoFo0EzUPhqacP7aIpTernG534izC173Lwn81FJ5A +gcXXABQKHDrrjxQ4Hhb9A8OLlxBtEAXsvJKa1FPYDJdNukcfmi5cYyPo6jF2vufH +XP2ZnmJMNl0tLX2W6u219fc9NJ6ySW0OCYcCDciutcjs5py4vLgWTJ+sTyvhXIQz +KsCVaQq90k3+gSEdt9lgV3ySibWmVpu6n5MH9bWDn6+Eyz5LiARVaoKmKioTi68u +4SX9VvVODnPniWtsN0dRcvxi/7QEosBJdewvgf/nIyLKQbHwcc3xxWxlhxxeVNW/ +I+AtVLIPAgMBAAECggEAFziyKxi4z+6cUkUcHK4pg6nAIRRakPHQ3mT7zltyv66N +4N7aJcJeLRquAUMQ6JS3Oir6tZfGzIUiAHArP229kQgggaV8MN4mEcjXJkXDF+i5 +fkmEGzA6rM8MHWwHeskCBqbEQ4NVq2n0b6/9e9b+GHJtMntN/sGjKzOzCv/7MOrX +6Y8xhk4RciVV81rmbgC7WilA8GQKVX/Zy9jUqglRbwJEEe1P4CUlp5+FNlOXo2jx +9lWjXi9HGVpYtZRbEkh8omMuhjtYcxUhRkbqcrLMKjoGvkiHLGkJHVgyKDnZ7n5H +wTwQCzWpgvqWXh0O36N9qf6aP8RQxPiu9WiT1NNYIQKBgQD6kvk66B7NC/ZFaPnw +nH0gtVx1cFmrflsPzhy8cy/du93ycTMmUi5QEl9+cv6Jlp+rOhypB0YZ35kU1U+X +wszeYwtZBj13IiumdmyDUhjiESa4+1hxqTKUmfA/W4vF93FoL3FJnusVigv8LLsJ +L1Ip7mmCzXVGH0yY6+xuJgw4sQKBgQDuSVmzRDRHi2mgmYJHZrUpLOP1mLVTcWWv +agNJCIak2pNeaJEdxgssIi1RWAxAnqjM/AjorPmhgEQy4D96zXxgpTTLLETKi3Zi +HkJ3XrojNIBt0PPU4m+1BEdlt7C8aEj+CkDZDLyNMpiv3dpESerR+dqguPbw1d44 +lY8zq5ZGvwKBgQCZO/QqL/VWE7ChNddTa3+h1wcZ0oEjvPvXKIauQArPoKnUL6HG +F4+26+V2IMDER1aRkdIhFA+slu64rNIlzr0Wap9v677+8eibveQSUsxgw3hYu2yU +5ZHHCnS/ai6J/A5gVlMDYKoG3AsERh6DOWsXtXLUyOyk21MuWWiW27GxoQKBgEUj +82sYtzKrORLod+zP2HECHYL9tF9p399uG1Xtq2PaKDiUjsbc2BEOOagIrEVzw/b2 +in848ZXy6db5SnIPfa9tQExTpAJBRTBjJ1YLnmborPswTg/PRCp5+12AVz/T4poT +z40rLOqra7Jb5SE7cW9L2Cwaf0ySQdCZVNvhRdFxAoGAIFQ7bTpknr6mc1o+1oC4 +VS0Pd8HW+RoE7VPAD9RKUAl01peh+ZQ17jwrnGFUEQt29KiPBh2Waxxey+V2/PFB ++b0jyylWPDyBcuZFX1O8sL4lNXcr1T4D20xqio4pofLcQ4cPuKOFrRpIDm7WzwQf +sTK02IwMXHl5dM6nXjAtmRI= -----END PRIVATE KEY----- diff --git a/tool/test/resources/encryption/int-grpc-root-ca.pem b/tool/test/resources/encryption/int-grpc-root-ca.pem index 5f59a3d079..3bba77e4cb 100644 --- a/tool/test/resources/encryption/int-grpc-root-ca.pem +++ b/tool/test/resources/encryption/int-grpc-root-ca.pem @@ -1,19 +1,32 @@ -----BEGIN CERTIFICATE----- -MIIDFjCCAf6gAwIBAgIGIvTTLeNUMA0GCSqGSIb3DQEBCwUAMCoxKDAmBgNVBAMT -H2VuY3J5cHRpb24tdGVzdHMtY2EtaW50ZXJuYWwtY2EwHhcNMjMxMDA2MTU1NjA5 -WhcNMjUxMDA1MTU1NjA5WjAqMSgwJgYDVQQDEx9lbmNyeXB0aW9uLXRlc3RzLWNh -LWludGVybmFsLWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj7Eq -XHM//xBc9cNDxb+NEF7XISqxkxbeDyTyDemLslN4eIjqfEEdlj121B4xlHttxo9N -CGhohirddqE+LD0EYEKnjNo5THY8zzmB3s+qMCvybS5ytqKNGMHy7eAbF2zsoMZt -P3PLaVQ+WEM5Dlyv7zPPJsEz/jxC89CARi1LqXqQwv7tDcFUaZMVKKDOLk6JouE7 -zZlezzoll2vzINBSfHfHC2J/37e8hvyQWHhvYhUTiap8pIaBs8mqW01t4YlR1Ckz -49u0DNKKMoGH0KjtmS+qmhwODlZlroRv4P3t4iYs3kNvBhVH1CRfcnyzLuFRGiin -h9kSJTYy861eHQ6JHQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB -/wQEAwICBDAdBgNVHQ4EFgQUMCttbOTJP+DErp6BZfyMpTjSJjIwDQYJKoZIhvcN -AQELBQADggEBAA58kPtGXMQ/NVUQMY45nUU25+MWQZJq+iGdhL3+XWQzsbgaLg55 -PviOFN5e6F/KtLFh/kutZRMrwma8HFaPIPKdZ0xMahh5GXoFSBV0fCk7A/mOKRgO -cf6717L7VB/oRVFt/5FRcJpCe57R7NpAD6dGS5d4p8XR7dhM8qf7u5ueasa5aNQl -3+tO9g+QhBUIwGQMohARF3bePN5nlLajrIbUnJmvCuT5GVN29suH0wvfeMi4uzWs -sww+oc01SoIsDW21/I2r6peVZaFlUsRT2Lcvz4YQ0wLoTHlvxbN12mfohRzJSYlm -jKksHe63Qbv6j7GpZBLei+O4H//UbY75EVQ= +MIIFcTCCA1mgAwIBAgIUQ3EE9MoLLzM3GmnpYENcG+YtsJAwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCWFgxDTALBgNVBAoMBFRlc3QxDzANBgNVBAsMBlR5cGVE +QjEZMBcGA1UEAwwQaW50LWdycGMtcm9vdC1jYTAeFw0yNTEyMTgxMTI0NTlaFw00 +NTEyMTMxMTI0NTlaMEgxCzAJBgNVBAYTAlhYMQ0wCwYDVQQKDARUZXN0MQ8wDQYD +VQQLDAZUeXBlREIxGTAXBgNVBAMMEGludC1ncnBjLXJvb3QtY2EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCcmliA92c8Rt5pOkMdXtmIRBMP+wbVXG/K +Sbx5gRTKOKlMYbarDWAOUj03gf1D4ALz3auJtwpe1p2lFcWj/qzkLIdYSROouGQS +umJ3nR67Xi6sA5zXFhm3FfEqj7tC8I6YahiOMCPqH++VDahFM91pEs/s/4H2ErYG +ZFf79BbghX4gtDlrlN7Vgj6iL0r/xupoGGgV5maGi5FWPS7W9fJaeutakpu87i14 +DpwmXZgls2vXmFhBN49Pe5ez8XLwZFkRTjwn0R9+eERVGsIfLAE29ddwbd6nEtu2 +cPOuZGM9rMWT8qJpfpfFeQB2s1DkWJI3tnrwMi5nFI7g5ugUXDBkg8HuOIy9rRtk +AOEb/PmUF0XMhODl2vu0yfykncDrwt9opfaK7nRJoYXAs6P4pXpX+sNXyvUl7NAK +ns7H7292UNEUHX26vw8uCgDVA0He5xN39+KY0A72+xxqAvS970UsxTKh1VbJHJWs +lNcFUWkcg13F33KEqHsJnKFUlzX2uh+JUp1HnDzjKS8kEgZeki2wJRQZSnfcMPt9 +KPNRN/RQoWKVAB2LDxzv68AvcohtQGF4qyeAb7nW62P8ZUOZ709s18dOMkLmAAcX +f/QEOPSh59sCk146ZjlwC9QAcJvfI2oVT7inIwlNisIv8+3BKkLdZIc9yXojMWQn +SZvJHjPiGQIDAQABo1MwUTAdBgNVHQ4EFgQUkS3eNENvGyl8EttuPd+oqmL4kwkw +HwYDVR0jBBgwFoAUkS3eNENvGyl8EttuPd+oqmL4kwkwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEANlkBcEEfcW7EaJg89OY8CNKbdvOOzrUkH2N1 +M6QZ7UcEpnZhKbVdHJG93DNJ7k+36TBpwX93Hf/KXcBPHByYsEpEz9D/s6wFLI+K +6oBsDOmxz2mc6X6rTj4LXXJ9SHwuILxOQI3aBHgvgVXdBElsXH0ozakW3/K4W4MU +G+CLGo8JOxms2Fqz7gtKCsVIXXgtPWuhJxQzCtX6zDcR9Zpbi7g1brLCeIvz6WEa +NQnHk4u+DOCs0c0HRiotkqxpkLkLhvYQZTJxp9or3lRRqiq7GH/8ELgVwtpEjCc2 +j8VTbw5uPQ4eJxFt3sGzGGOGjrOVcmmlixXK16n2sREqqZAOUXsUwIAsJk5Q1Fg1 +K0lZORkdrwZetPdfDXQ+DZ23F/Hw7bu+QMJ1/YAdapM/LkgNAiyA3M2i6zOO/T+s +6HDHpK25hvuC5kP7ynowPEl/b+TAgbYqjZQK9DXzKn8UWH+EDBQSAKSzE58qe6YM +ZwZ1MTFxyobnG9zgWUkNEYLpK/z/ghwwp3EHbjXUMefY/1id/ZSyp7eNj3ivpYQP +ja7MYjErIhEVgFvQIux3B48zmqxftnu6hPGu0cLUYjT4hKJuBlU+gJUo/ZNzr9u0 +p976Nu/p/xs4bl/E6jYR7xN/pajbFpyYvhvIQl0W9GhCnKZre693W7rn1oRzcoxT +Oz5qfYg= -----END CERTIFICATE----- diff --git a/tool/test/resources/encryption/int-zmq-private-key b/tool/test/resources/encryption/int-zmq-private-key deleted file mode 100644 index e4ee37b4de..0000000000 --- a/tool/test/resources/encryption/int-zmq-private-key +++ /dev/null @@ -1 +0,0 @@ -kt{E*P89LL8uG6GxUAo?%baTE}9dEqXVTLabY==m \ No newline at end of file diff --git a/tool/test/resources/encryption/int-zmq-public-key b/tool/test/resources/encryption/int-zmq-public-key deleted file mode 100644 index d79760bae6..0000000000 --- a/tool/test/resources/encryption/int-zmq-public-key +++ /dev/null @@ -1 +0,0 @@ -W-]2tG6]I]H}}t}1U9oa7wkw7t/4Wa[E8c/8N5>qnyK6wYVQ8hhJ0zq#hE!mr1O#aWk!}ze z1V6v^|Lc7(zl*cZ+IwG|yS<)uUUOx&{Mq07VFr3Lt`{Ur7jK1Cn@H(S8(=IAhiHiXv#K!%YIeo_UlKzy=ElfB;GKIY)$LVJENdB>5NZI_SQJBJe|% zHtJdJ*GDbQ@b;```ajfai>Oqz1V$qm_6H9;X->8z5;0MfQ#0zb&zGo{Wt)+7r(VX~ zi<=9f$H6x?j-^gM2gdJ)grHsHEX|>auEei)=`FP8p?Iolx=T9P?9Hk zPq;o!X-ha+Z7bW7ku6B-*fUJGJ>QD{!UkRVMdy*rInJT5yBV+)|9R$(vjDTui1D&BN*?o!GtHcRLr?l)myofymmJ z#PhyToCbroV53ji@LPG!;{_-pkFPj5Uvw?nFm^YkyKVJM9`14+qJT)KAx%TDCE0z; z(6@>4nyw4AkOKy|CeTPR??&Bvkm?qWa#Z`2SGdNoyH1>+vO9Ce3FvVZ6v0>b+Hr&JZWij5dYY*Ihjcuwgxl9`~EqXrj_>=+X~MOW?z~xm~nKwCa9QjU(17ID9IT zNccBS%>W%-aO8V~S~Ay9!1pkxL$GaLo2Z)a^T{u@KRuH8`FY{CyG|*@&=WsG3-A!i zP5(ha{v6e$nD;g-c5xv22p#s@Zru7S;YwtgshN02 zY#zqG0+#PTw$l7!e>_xY6#FRPrdzrS4C3aPrAtLzb9@9Jx{A$PcNf;J8i;9UXK(r8g_A;uQu2Im(QP|8f)NIYRnQu={W;M2$ zIs1d>aOa#}OXqeI8q+`L=NmDKFXQIThLqLG#7<8yUGVEbfEc@igdZ2kUQrH*Kd--p z`vC@uX!KnUdJkO~f3=)*8`#-SG8j6jh<7jNC> zsX=^DsyEb-i+)gkb5{AV87yuKT?&yZ<7W}EhxdIV(oKvBOPvKrj3VwXJGfvVkC4im zT;`Xs#%$ZAylS-&mc|+GZ!-jx^R@mAj(1HG?4Y6YpW9*M*c9{flu$itT5lln*Kijm zEhJWt?$Db7YF%?#G8E=%LqGSr+`uI!*>jicw645gzg7&#u9h>!)eJe5%X%>3d-(}A z+)t@=OYFZ>`@;kCvuJ_lCKN6+vJ<0v=|RYPqZKlB!93K|s^jI6Sg-F394Sb}j%7@6 zyaOdSEdm}f^X44s2<}2n2_#FI9YJ)uZ5bs#GS>Z^ljc0a7@4&2$cR%#s=(5lgaB9M zNfO_A1E9WJ-+s%U9B*bIb=~gfoS&6=-9?$bAN*SE-HM}M>xM6J)!GibrpXwmfQg(f zd!=lPFHPrrrGrLE4wXIIb~+0`ncQ0tvaY(8@hN&p+*BO733S*zk&vFv+*M-(2S!?L zgJrr{uZQ2?S#-tWtiaiSSb^!^T9cSHP03|PXFQ}ETiH^GkYn<+ZA#|wIOg~FTyYtr zO@1LL8S+;TR=fqabl4KjM^)Q3zF0c;V~f51{bL32;iRcT$iHbONlP`H-}6$xO5*bw zz@{?jh}c@*AdUifFj@JPUYA!*!JFc)v0HU~NOm`kvHk8|M@1;P{Apvogj%5I;v15H zg$BVHyF*>D3~DdL0K$WlKsY&wsmI+lOZDD+ozpmg67DB7K+{LgX2C05ll93;L?~a} z`_V`nr*T)(VVW@eMG84C6Nd=DDMkx}dn5ZLu3`C-#?4zTy($7>I=L&w$Rru*Emo4& z*%x%vJU7{tXbD?1Xsxo#mrGIGS-pE*PBp$)gjYb-0MY4iaM%ME0ETCHF>b>a4@;0A z9!(Ve@%2JZO?$B>7hy>0BX1aSSxE85qD`6RAXk8cnDx-Q!kZV16KBzh8d%(8#7<=u z{G0L_xrO7rHTKGR1sHx-QEpRTSTY^)*NrH2NuB;Q!vPFUUZtnH^}b@GlgE}NubNBi zjD#}{@?K%!=PWT9*O8{Kl}nk(C=FFB^ti{@s&JF>llzjvf7B5QS&DJ5Y+MD)hmSxO zmKIJSiEo+oXTx1Bly(vp8?j6;3^GKOS4F&bny20pkkiLh)9>H)r$zlhtqIspNS;kH zjIhl;dNz?`zt<80vA;w*r`3E4YiWI*igJu|Vd>FA$VTp+C}=-66x0a&A@w#KBb{T-QIBl}a_7tOL7E+wYTk=xCMBn*T18rklVa6n3igeF z@^V~@4XckJ@MO(y4|GV}x3FDRW5TH7d8R_aPM&4}yUOfIJbn%azPJK{l-68-;n~Oi z(GlM9O=x2){bwd_8!BA4)V%h(%Sv~f9)VPghQ0{tKpAOSiwFfPZ=XVcqQM?uqPL5V z1J7`6@j;7v2S2mlFKod`$J_>1hPM}^^0Q+iT@6Z}6z6XF9f|Ar!e&1e4$j91}Wk-4&0Agp0xgY>k7o&O2Ox0$PpPqboOFngWU z^>X~vfe7IAo3;23iJPiaCPr(?x2oE~MsP-rcCQm-i@YKEmlO~>O^4$&F!*@Yapxw> zoAKAt_51y^vovTGFPlYs`?&h2Qiupk8P%~}ks`w+M^Y$5)w9wZ$ z4RB$ktRFJIkU@<}C|iF}Xzn+2Iz?9BgmS)r^2bq6dwO5jE3xoi&kf>jf-`F-IFsJJGdI)R9=5>uB6vw-73-QVp?JQtZsgo5 zIJ@e8_Ze>}+m16&m9v+oXEj5H5QAFps;^useE@Dd0EAU!F({97uW9c(B-DM5OFX8H z%Ls{e4aQsoO$zbdr#ED(RR<$nuq& zAw_8{tW489iVsF?y_eQUbrQv0?aUg*saPmQgO@)4XDDv=qiM z*1R_<^HwaFI4mbts|$SOuL6ok-JpMjA1AyXb#{=uucggtqr&1>>62&&9>WxifbytzONGjt2VTWuA39_Z<{tqR8q$c9@(tYGpi@j;uscXJvn<# z&1t|9VQBqF(uR4uUPz0X%-bfo@i$Sk$;?-Ms&yL^%b=6h%55|;o=F#*ThO5X1h;2s zmCqLY;)*nB`}_QuZ|8PwB#~iqRn#R@BbskR9(-c_&X6#np>tqIjnJVH#t-FNnrRlE z3-qDROP8B1lR?gGxTO$R-dllm6<>U;4QoSj)7C}bB90+|X0S1<{Dr8JpL63{ymW9Z z(AUWEBC%NVLW&IyLx%b`i>QRMkOV;-Dm%t^(rDG;3HK^Vcq6LLdX8Du*xt|yR!HMx zf0|SkLf9eg+hsh((T$DFakr~;*FDOr+s29*fzhpB142DwBueNG@_4goorXBRrN0jsWxDQkpXQjxxfnm_%hY+2 zOXeiZ&&B`{A6%X&ZLflh*p*bAP$aoK#s?3)$FEd6)JG}G)UZVQ)S?&uvNUVf=I$69 z@OKt9>LD3DA(8&QltjbjoJU5Aw<_9>bnh9Qgpq`pqxe?uV zS!Z_o@u!5D$pvMfM!#`gA|cGbA5sve(=rH*jH{7*#Mu;S=u>FAH6z+?3{lG)R<*hM z)@>EiDQlldu{b*J-B0N@!oDo05s;0;efJe9w8xjf^s>CPFFVXh9wa-+#|~rtr)cpg z`KW*t=x&r$V_b(6?z|JYq%RZR{vr1xOc}-p1OM|jzyyFWfXpsSNz!(t72!o64+LAk rqEM3aDkJ@005kh2V+pFd@OvQ1Ek4m47Mdm-&Wf+e{H)3Uzm@wRY4!}9 literal 9373 zcmbW3RZu0owxBm|8+UiN4KxmoySux)yKmfG8+UhW+}*oz*9IDQXrSjmHBWdy+{4kG=p%OPN~VUVB!d;tys7XUNB z4Pfz4GY66XdjU2Z7Bq&sje`Xl8y7DZ7l@k&#K{ff1%Y8|{(B|BFv9;pf&WwpM|rND zlu^RdUR%wE&q;IrSeTy@|C2%(hjdxF{I$&~F{~6lDMzY+2174!)3r5(ps?h8+b!$& zrg>bl`hc}{RraEQaR;4Cg%xa$sN>Y#d)zw`HGO%jNf2I3`EV*nBT#VOEB~52emz#w zcq2Y7de^?^6eBpsPlH(@K){|ke6p|jirj*iq+iEE90KyRKO|YvG*A;7FJ5fbp09YC zP^~X}Hf)>Z3S8Zu6E4r43mU1+9CIlhC~_65KGUz$Nv+h|4ZbJb-^%(bXlq+_0leO( z9B?8xmdo#V?)x>1Skqr0aws;af~whN4%0~wpN)EG!93uOBisL{3dssM1#kH+6Rb4I zL$k)5PvM%0Ruhb|B7+Sp3oAOBCRP^B;EF(uqqPT_P8w@BjyB2RfQJ6^XQoqGdWg{Q zr6E)24l&$_cvu!M^l$$~rO0;ha{WkEq@Zzf(~!(Wl;wV zI@$q<&eipwxMd!H)K}s6uUNta5n^UB zPe+KAa{0U6?ZtkI9~Yd>BTWy54}F7D%*@{<8Qi4+>DEyewiGnO$cWjnwk8LY;kzF& zVHnFmWUJhaHNNlMqRmU}SEnk4kL{uRhFr-|85~LH9YXMY-TD}V`~DQnzyI2AB9uQ zdmB7P^f8KlAK3P3cebd{C_O880~cW`^2TH}sDPOrZ}eRPcX*kg+g@Eu!XC-~A8kq$ zh@?z*N$%!X+ba(HaNGGVbqr!x$6Xft?>R5u-&t7radS7l3E1pHXlw$WJi1P_sQFJF zVj$FLoEav^FYyEn2zu2?)pm>1O z!>?^i@A1pmiQ3jpv0tRHJ}lcu!k1zr>u1GH5w$C?z`%Y?L?8a27_Sr@Ta=`vqCt=Twu;eJw*Xvy!twtDfvp&=)fi>%@1bgB& zvLCtJ^=3wJJN4`1-(_I%u{^o;VYtNQ9rX3_oo^R1v--!aYR&TY5G0RxBo4F|GK#^l zC7LJYM(D`ovzqLSJdR!Mv)Nm|<7ReWmDsdF9RD^i78?x-6~G!_A=kTbEptpN)Q(jqQEFdS z>5P`8+|YlkA{&`laxt4)h80H^*M$|$KlEYoImkR}Jj%NKppuRk{X=N(^Rq*(E788QCaamnVvJ#}z6-|C4v{A3~=0X#R5F`hj(r|L!PiKKK zMV)r6IlhYh0s%vHEQMEMbI8a*e89lS+$OfMZ||bLvw^y`T+Rf8ac4d|PA%lFy3i41 zXo&e$;G*T_L5sRg56e4#?jn)IJmgu;)3*LjJ>pC9hcL#VJ;{yF>v1w1c5M)&EYxvH z3kg!w`8U+nS$L-A*I-et#=|2MJ3#{&*n<0+7v_kC8x%q$6?n|Wf-(`alacWWnybUL z-xipVP3j1lH;}rPy^6`B@>K~w>3u^z5AA*BPm_(hc?f_U$2VN}nAc%2W*_O&^YD3( z3F#SVfFF)`3gLx|7iNb;df$UT8L&T~UV{ZA-(3+{;=9xsM=k~Wq@r`ccx9_ zkAfIK39(tj*|ktJ{)`doRI>juX6dA)K`pm(qTKoIbgwMi6r)@AxABvG)lwPa!4n@GIE*eK&*OH$QnaOn zopX}U(e(kOEo4K3Q0GBGq}bz}9+OA+=*?J^j(v4f1hx(f0Cf{G-kn;*HqCb#=G-V~ z4Wklh8FGxyPOs}333?ibJiA_dBjLH`vM}whq-FRgS1a6k52vfeht_SVQukaJQrlg~sVO>Jx2rXL-qUD=(MM*5ObRTq~-2(aDz zUdF66OZ^RK^@aV#(fcd=rt`MFG!McaO^8pG%O>vW9b9ydhxYfC*zL<>A}LW~?#EAz zaXz-gRd2kXb!K*0{sib80mJ_14CSQz6b(Ew8k7ovShoHSvq0Xuxxua`XiwDa^gwgI z|Ey~pfaCwOuDRIQI6z?BqW^jb;9v{ExGDdj1V{+LKV9U%BM|@Tw@v?#djHH!V~`e1 zJ9l|4knkjijaKIpe`usJ2R%F;W3X6AZ>hBhkg1a83#3y6D5`gX%3whAA*X zzr(Ux3}lRazr`Q^l-T&I2eMnTrh~(e@B8uvhweS(cNXn7;iO;^11TX&Kx`O8Q4rGC zxqxuTHV;a;#gC#Zire+b$z-etB7JWolC};~uBfETna_6AWMP1y@bA{ezNaBBcbp+` zPO840L~GRXlBf+=3)Mw(OKlHsrTf!+VwZ|g+RZ%aEtz|dZ`KbKACGC}TIYHSl!$pj zFSlVvn-D$EbWhQoJcz*kEIt@LLpv&D3-M~u3WW{{Dz;Up!B=h!1{;wY87s0~pGFhj zK`|bk2nCpL_L^v6oTF36e=5oHRaa`CbstP0#=3jn1?j&JPX0dOB(az!8WFwcb#~jY zgkpM;H|inH6Z!%DVKd;RNJf}=@F_sdDEHyZ95uos0@90 zNGpq1+i8~-dyYUahdu=ejif`Gh_VWUCZFu`OOS=fH_Q^kw)3qI+mB3gCF?6#J#0@X zSEu-h!4SVG4Is>I_iXx#Bh=S1(lTd z%Gsrpd7y$+Hcy2?F=KP~q3yu|SJ~94{yC_5+CH1W--ycn2fk@F!t)Lr}?Ho7Zk4I6i>BfdSV_Ga+} z=bSSEsVs|4m?Lf2F&*XwBw3^>oNPKevWN>6%h|6wR0cr=Eu&^tT>~2)%Nu=M@pmHG zS8EzeP5UISB-`|bV>_VNebpv!*;pxL>`UrMc$D3lK@^%?&my6vKyvmRz2sH3_wN_q z$$6iEE7sN#XMEzu>OYX;efDz&e<`L&UY}~vxo{oV%$<^i1$jBBcIvfNw9K{)F1+{Utvnz-TqDMYKo{yg+s-u=VL8wP^Pu{c`aiKW54>Q9vC3c$r z5+V~2v5+J5Wc*4v>ViHLSqatm2(jgnZ8$QF-b@Oj6GWkgYK#A)HlRTQI*Q+`b;$`P zp=ACUXa0mj7?Q%~CJUL*J(_069;b~#nTrOisfmlpA7Aj|0%>Gg_+^H+>VkR>x2=`M z0y~%A+~DPwQYf(9Yp0_Fo~{2Tj_*X%z|o^OX%&}+D%>Y~i(_`qJ!8<5beJZ9-F^jmL&5Rm#sTu_#f16oS_>I$}n(0(d6HoqH@y`(ioXX zk^qU_hF!}>wvfvc$ zz>rrVZHTo#c)&{G%lG4o=rU~&t`Ps)&XGoRU|`3bZ=4VL4%3@HJnVf#)D#C!2DRJ1|SB*qblZir&af3XSc6iE$nb-+t;vUM!NYm6KW~ct+=1S^nBe;u&HC%e2MQU+l!92G5*kNBB-h5g;rL{U6(3n#bHDJH-?; z(mJ*~)_WuHcIx&de|x`vv$sAOb})%(mE42dX(Y1&@gYa+_C>q z%qH0$fVDUD)sXBUqD5icV>qLxiz7C+Jc`pcT<2Q#^!${kPiQ@a>U5aOO8L1yAWZjc zTi+6UK$$Z7`{&WCOGR&&a9a|J?5T)Ci6LV&AVkHK63bD#>eRqMcdaS9GbF&Wr89By z+S2ag?1KyHJ3e|W-O-x)937}W>r%oaW`67wLx~>tf z_(Oi%Qv~)mTW~UMoNc-wgk{6!ej{5Lz5^G7r1G82I19~`i#;s;^5vX#*3@Xm^XM!z z@36uJhIFFS9;$zOB;}EY9tIe@dje*~&h*L&_RR3Eb7*m973R-B!aIbRh^)W)#R%2$ zn+Z$ZNM)9z-jBK_=c|!=bY0->#C~~HWPO?`JwHX{v{Ich`mUdR2?&I!o^n2Gn^Y7t zx-!Vpb$(~uTZtaV^IJI>vkOmUk9Fk#@tGxZQ8z#7gX+;x81H1RGUzz)(zUtRl~|-R zEO$22H)W!EN{gWSIKUM?Mqz~)uHL^Z+Z0^UCgDt>S~l0ARqV6$t17{3(AuBy19$*O zWgAj^3kKyCRc_aiHN~IBTf_7}{2?XPy>w>uyJrk)Zj1EDQkf3&g2hS{bCrC`ArUpL z3gB&PEz`{i_IBR7Zk0^GgcK!<`T7|4_;KQwRn`dW3I>}|F1VW#C}z&Y`iAdr0Gi&w zuc6a-@zo1&ep2n-x_S&AQ+fiL^Rlcck?iD+z+dr}$ALkI8Zc&gRP>K9R|(9ZrxKu2 z>j1R*ykM3iYJy^MVCfGGNkhu&hQVlsaETL{v8sT-SJXIEF%xM%1l)_G+3fscSg*NM z9@u6lz|d*BQ>*w0irqCM|BNWX08>a)1WiBNDAyGAIJN@*Xwr2!m=Z#5rLx@#J~@#@ zs*GFd<;Vo&X5cMK!BG}B3#x`Mr^1-dUwQ-BDX6G4)WO%bALj(`gbgv}9lKd`O-M8I8-)+{{o3-Ysa|fbq3r3{AZV_qM9x+%YO^4yAaW+vmakWjER41XOse;vIQ3R!S zHVLcQt8VZcrcznFzp@hNVEw@v84+FTC} zsuX;W(!1ZmTM+l&!S~H|?vih$Q8JUcqinMPU-EyxR+^#wT77fHXh?OdrEbSeXsUBy zrF`h*=3eXfL3!6*7!BIGu@k<0jHh=a(3(42o1#qCq|^zxLvP|*y+@hRVG>qK*a=^U zAyf%=sci^xcR8%i^BYKLp_a@kd4qx(-|o z2Pg?nxzQhKUWppU2Gyb_bQR47q$1>^?mX*Z)X}8+XV#zf^)3@4JrL;NsrDxsTjD93=ckFsiGtr)< zETyZ`5nOqfKCyF=$7EJDcqT}xk2*IyOq$AEDUv3Fk@V})_+>q>Odul7S-kW`dFruJ zaF71&r*@LmQ~@IO#~5NrP2kAB1OuauANEp(f-BXdn9R2e~8`uG|K2gFs~J|u)#NYQ@{P2n^K2$Wk|ggs+_ARICB}F^cq`8 z2@)HJi>S2)7q+MbVm^~*5K0Avsi6BGalG*#FM;8*- z&Wtm#X%Xp-h$3o8?O44Mlh6&BH{yDHa!LI(zu58Vy#}Clxt$84`D*`2{Cfde{rHKTQilH zqH4$;E{}pOatNq;<@187WG9{Rsi$V?T}GvEq)8e!@}=Q z(qkdqf}#CKTc03TVUxJPP$H=#*yy|Kd(u}xqyyX8rnP=g zu}cN3XnR+_idxB6^O2dv0o*J~L@mUaDzbW*UZmt3PnQ`DKYOIg}bU|eqU zex7pH`eV7Px93m6`k2D|5gxD1#8VC3m!XT;dW^QRk~jx3mqN%t|@$ej!;b!Mcq+QU~IZ%iL6tesC`nRS@fh2*YqCK5O8@2RBLqS<^xS z(WU1|P!i{L4qJG6m4joIV=Srlv7|gQ@&Re>`BZv~*)`jHHr5jAx1rJ;&XO$joTPIg zg>?ie?t@$(=z}7V=NsW(~AKzN1);Vs* zKyTLIVduuvD!VlL;?m6}@oqd{ST@MeUZ5O}LYo}!=1fs$(ElFy0%s+XhRGXOLdS9b zV9GWTttAVR6|zZ^aUK%r4G82o*^mt({GO9UO{D2V;D|sqd3S;=P5_mgs(RuNO^j2`xfl)Xqp+K2t_|qK`d5%ks#n{0Ti$4fU^uzPNJ=eJaMI)ba&GGK(qSX4glI$gwKMApXu}u0zOp{7 z%9LHv+dgm61DQ55IGjsMJ-=%A2P-*$%KI4!1L0&!^ z4{n&HV>PJN_cy$}E`l#v$3qUw9wg3dm?vF$HWugynJ7bP7!{;?`{G;EOAgFHFDvne}S}Vvkk{M;?H?-Fb8F#8sYe?2?!i(22gk z^5L@ZLbdeeHyvsQap6kHXPUPgmhNq;PAxs93{}n2QtERCK^FVA0w$NCB9e0_plw4z zSs(#R*ZM|Bb7f&#mAK@d{T=%uucraJOzy$Wk~-8$Y-B;6AeJh}B^OcWiI6t z4bLgkG5t0hyaK}P;+kto75yFpLtA!LvPN$wndtsK0)y)lQ6^)O^q)&}6qvkb6-s!!# zqB1RtUWFX9IFi(U+3dWjs5s9dD5$jcD&RBnTC>)?QkCsP5C~~czV(nTcEMMv)|F;2k z0Kr?0!5^0qy;;?)Z?=~u0yo;+8Nx#cm zs=)=h9l}>seW{p3bqHkr)PdQKml_C)dKZE6tv@5A1Oi_NB!Gh|@N7oG0Z17EzTL8h zYf_@-fAcVQB4UE;RfA^VQ=cn!-m{-O*i#dzlk8d5A2LFBgykb4J-I14u@f{lXp&%M zze~++Rw+)`;3zeW(|f@j^nK@4Xvu;XYhPgY7M)+>4v`%;K6S1KR)sr?t{myJf6I6 zyD|DOIJwNZ2{h^JYZ;$fZ_*Fib-Go`-K+g<5;l0u*f zk3>`myN)u;$udClr5oOO3w7hXPbVa;F=9(-s%|#2>t-qt7v4PmGTc>%6H6M5H;Kwc zkY+kB7duBNqwGkC!}`Z;qSfs;1DvvCh6O1wL#`?jMYc2L=rwkj2Hn}2bY9M)@+~&7 zQ18qqE&FaLwc4vwf)$&)B-5U$cm;3F;l$oz=hl6EwWf=|K^skG_ZbJGdT%Gr)2}cb zPv5P%ytW(|Uj&8h?iQ#!5z~*3e$jWs!=+@x;D?hUq!H$=g%gZJXk8IQt5VnN8=xqg z88?)*_V+N^c6WW&J4FEna*G^lPT+0x;9mOIE%sXX0@KM{*bGxW;y#;Ds;B=J<{h;C z+_d_1?MgtD^9xCfbs}Q)L3X4DBjyGi-ZJxWTHeAr%QNHcpNH>RaoMk)A-qkcNsa+c z&9^$B(1B3AyjYe^iF|lw?R|xcyyRsX@txV&&m^rfH&J`$XNS{MffNZu&T{+0rpqRG zC92#La08G)LoJjkifw4`sm}_&CdTqW6Sr`-PA8X~u!Y;G8ZrE?)n7PDfN?V?Fi*qL zs?E1K{d(E<_kLY!7#Q>wL=HlLg<(X2f+T Date: Tue, 17 Feb 2026 13:35:53 +0000 Subject: [PATCH 02/10] Update Cargo files and docs after rebase --- .factory/automation.yml | 2 +- Cargo.lock | 37 +- c/Cargo.toml | 11 +- c/docs_structure.bzl | 6 + .../ROOT/partials/c/analyze/constraint.adoc | 84 +- .../c/analyze/constraintexactness.adoc | 4 +- .../partials/c/analyze/reduceassignment.adoc | 4 +- .../ROOT/partials/c/analyze/reducer.adoc | 4 +- .../ROOT/partials/c/answer/conceptrow.adoc | 4 +- .../ROOT/partials/c/answer/queryanswer.adoc | 2 +- .../ROOT/partials/c/concept/attribute.adoc | 2 +- .../ROOT/partials/c/concept/concept.adoc | 4 +- .../c/concept/datetimeandtimezone.adoc | 2 +- .../ROOT/partials/c/concept/entity.adoc | 2 +- .../ROOT/partials/c/concept/relation.adoc | 2 +- .../c/connection/consistencylevel.adoc | 87 + .../c/connection/consistencyleveltag.adoc | 36 + .../partials/c/connection/credential.adoc | 43 + .../ROOT/partials/c/connection/database.adoc | 270 +- .../ROOT/partials/c/connection/databases.adoc | 74 +- .../ROOT/partials/c/connection/driver.adoc | 460 ++- .../partials/c/connection/driveroptions.adoc | 221 +- .../partials/c/connection/replicarole.adoc | 36 + .../partials/c/connection/serverreplica.adoc | 141 + .../c/connection/serverreplicaiterator.adoc | 45 + .../partials/c/connection/serverversion.adoc | 29 + .../ROOT/partials/c/connection/user.adoc | 22 +- .../partials/c/connection/useriterator.adoc | 4 +- .../ROOT/partials/c/connection/users.adoc | 74 +- .../partials/c/transaction/queryoptions.adoc | 6 +- .../partials/c/transaction/transaction.adoc | 4 +- .../c/transaction/transactionoptions.adoc | 52 +- .../partials/http-ts/connection/Server.adoc | 3 + .../http-ts/connection/TypeDBHttpDriver.adoc | 2 +- .../http-ts/response/ServersListResponse.adoc | 3 + .../connection/ConsistencyLevel.Eventual.adoc | 13 +- .../ConsistencyLevel.ReplicaDependent.adoc | 15 +- .../connection/ConsistencyLevel.Strong.adoc | 13 +- .../java/connection/ConsistencyLevel.adoc | 11 +- .../partials/java/connection/Database.adoc | 8 +- .../java/connection/DatabaseManager.adoc | 8 +- .../ROOT/partials/java/connection/Driver.adoc | 18 +- .../java/connection/DriverOptions.adoc | 25 +- .../java/connection/DriverTlsConfig.adoc | 15 +- .../partials/java/connection/ReplicaRole.adoc | 17 +- .../java/connection/ServerReplica.adoc | 13 +- .../java/connection/ServerVersion.adoc | 7 +- .../ROOT/partials/java/connection/TypeDB.adoc | 4 +- .../ROOT/partials/java/connection/User.adoc | 4 +- .../partials/java/connection/UserManager.adoc | 23 +- .../java/transaction/TransactionOptions.adoc | 4 +- .../python/connection/ConsistencyLevel.adoc | 13 +- .../partials/python/connection/Database.adoc | 11 +- .../python/connection/DatabaseManager.adoc | 13 +- .../partials/python/connection/Driver.adoc | 12 +- .../python/connection/DriverTlsConfig.adoc | 9 +- .../partials/python/connection/Eventual.adoc | 3 + .../python/connection/ReplicaDependent.adoc | 3 + .../python/connection/ReplicaRole.adoc | 9 +- .../python/connection/ServerReplica.adoc | 5 +- .../python/connection/ServerVersion.adoc | 3 + .../partials/python/connection/Strong.adoc | 3 + .../partials/python/connection/TypeDB.adoc | 5 +- .../ROOT/partials/python/connection/User.adoc | 7 +- .../python/connection/UserManager.adoc | 13 +- .../partials/rust/connection/Address.adoc | 3 + .../partials/rust/connection/Addresses.adoc | 3 + .../connection/AvailableServerReplica.adoc | 3 + .../rust/connection/ConsistencyLevel.adoc | 3 + .../rust/connection/DriverTlsConfig.adoc | 3 + .../partials/rust/connection/ReplicaInfo.adoc | 26 - .../partials/rust/connection/ReplicaRole.adoc | 3 + .../rust/connection/ServerReplica.adoc | 3 + .../rust/connection/ServerVersion.adoc | 3 + .../rust/connection/Trait_Replica.adoc | 3 + rust/BUILD | 10 - rust/Cargo.lock | 2861 ----------------- rust/Cargo.toml | 9 +- rust/src/connection/server/server_manager.rs | 2 +- rust/tests/integration/mod.rs | 2 + 80 files changed, 1639 insertions(+), 3387 deletions(-) create mode 100644 docs/modules/ROOT/partials/c/connection/consistencylevel.adoc create mode 100644 docs/modules/ROOT/partials/c/connection/consistencyleveltag.adoc create mode 100644 docs/modules/ROOT/partials/c/connection/replicarole.adoc create mode 100644 docs/modules/ROOT/partials/c/connection/serverreplica.adoc create mode 100644 docs/modules/ROOT/partials/c/connection/serverreplicaiterator.adoc create mode 100644 docs/modules/ROOT/partials/c/connection/serverversion.adoc delete mode 100644 docs/modules/ROOT/partials/rust/connection/ReplicaInfo.adoc delete mode 100644 rust/Cargo.lock diff --git a/.factory/automation.yml b/.factory/automation.yml index b4020da8cf..5ce705481f 100644 --- a/.factory/automation.yml +++ b/.factory/automation.yml @@ -76,7 +76,7 @@ build: bazel run --config=ci @typedb_dependencies//tool/bazelinstall:remote_cache_setup.sh # TODO: Temporarily update only 3.0 drivers - DOCS_DIRS=("docs/modules/ROOT/partials/rust" "docs/modules/ROOT/partials/java" "docs/modules/ROOT/partials/python" "docs/modules/ROOT/partials/http-ts") + DOCS_DIRS=("docs/modules/ROOT/partials/rust" "docs/modules/ROOT/partials/java" "docs/modules/ROOT/partials/python" "docs/modules/ROOT/partials/http-ts" "docs/modules/ROOT/partials/c") find "${DOCS_DIRS[@]}" -type f ! -name 'api-reference.adoc' -exec rm -f {} \; tool/docs/update.sh git add "${DOCS_DIRS[@]}" diff --git a/Cargo.lock b/Cargo.lock index ad93018364..07e626b8cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -756,19 +756,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -1365,17 +1352,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "is-terminal" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" -dependencies = [ - "hermit-abi 0.5.2", - "libc", - "windows-sys 0.61.2", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -2526,15 +2502,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "terminal_size" version = "0.4.3" @@ -2842,7 +2809,6 @@ dependencies = [ "futures", "http", "itertools 0.10.5", - "log", "maybe-async", "prost", "rand 0.8.5", @@ -2877,10 +2843,9 @@ name = "typedb_driver_clib" version = "0.0.0" dependencies = [ "chrono", - "env_logger", "itertools 0.10.5", - "log", "tracing", + "tracing-subscriber", "typedb-driver", ] diff --git a/c/Cargo.toml b/c/Cargo.toml index cf3facadbd..195ace46f8 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -14,19 +14,14 @@ features = {} [dependencies] - [dependencies.env_logger] - features = ["auto-color", "color", "default", "humantime", "regex"] - version = "0.10.2" - default-features = false - [dependencies.tracing] features = ["attributes", "default", "log", "std", "tracing-attributes"] version = "0.1.41" default-features = false - [dependencies.log] - features = ["kv", "kv_unstable", "std", "value-bag"] - version = "0.4.28" + [dependencies.tracing-subscriber] + features = ["alloc", "ansi", "default", "env-filter", "fmt", "matchers", "nu-ansi-term", "once_cell", "registry", "sharded-slab", "smallvec", "std", "thread_local", "tracing", "tracing-log"] + version = "0.3.20" default-features = false [dependencies.typedb-driver] diff --git a/c/docs_structure.bzl b/c/docs_structure.bzl index 54522bbd03..39d5f12fd4 100644 --- a/c/docs_structure.bzl +++ b/c/docs_structure.bzl @@ -25,6 +25,12 @@ dir_mapping = { "driver": "connection", "credential": "connection", "driveroptions": "connection", + "consistencylevel": "connection", + "consistencyleveltag": "connection", + "serverreplica": "connection", + "serverreplicaiterator": "connection", + "serverversion": "connection", + "replicarole": "connection", # Database "database": "connection", diff --git a/docs/modules/ROOT/partials/c/analyze/constraint.adoc b/docs/modules/ROOT/partials/c/analyze/constraint.adoc index a510007f5b..48b618d5d1 100644 --- a/docs/modules/ROOT/partials/c/analyze/constraint.adoc +++ b/docs/modules/ROOT/partials/c/analyze/constraint.adoc @@ -11,7 +11,7 @@ enum Comparator constraint_comparison_get_comparator(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a ``Comparison`` constraint, and returns the comparator used in the comparison. Will panic if the Constraint is not a Comparison constraint. +Unwraps the ``Constraint`` instance as a Comparison constraint, and returns the comparator used in the comparison. Will panic if the Constraint is not a Comparison constraint. [caption=""] .Returns @@ -27,7 +27,7 @@ struct ConstraintVertex* constraint_comparison_get_lhs(const struct ConstraintWi -Unwraps the ``Constraint`` instance as a ``Comparison`` constraint, and returns the left-hand side vertex. Will panic if the Constraint is not a Comparison constraint. +Unwraps the ``Constraint`` instance as a Comparison constraint, and returns the left-hand side vertex. Will panic if the Constraint is not a Comparison constraint. [caption=""] .Returns @@ -43,7 +43,7 @@ struct ConstraintVertex* constraint_comparison_get_rhs(const struct ConstraintWi -Unwraps the ``Constraint`` instance as a ``Comparison`` constraint, and returns the right-hand side vertex. Will panic if the Constraint is not a Comparison constraint. +Unwraps the ``Constraint`` instance as a Comparison constraint, and returns the right-hand side vertex. Will panic if the Constraint is not a Comparison constraint. [caption=""] .Returns @@ -59,7 +59,7 @@ struct ConstraintVertexIterator* constraint_expression_get_arguments(const struc -Unwraps the ``Constraint`` instance as an ``Expression`` constraint, and returns the expression arguments - These are any variables used in the right-hand side of the expression. Will panic if the Constraint is not an Expression constraint. +Unwraps the ``Constraint`` instance as an Expression constraint, and returns the expression arguments - These are any variables used in the right-hand side of the expression. Will panic if the Constraint is not an Expression constraint. [caption=""] .Returns @@ -75,7 +75,7 @@ struct ConstraintVertex* constraint_expression_get_assigned(const struct Constra -Unwraps the ``Constraint`` instance as an ``Expression`` constraint, and returns the variable assigned by the expression. Will panic if the Constraint is not an Expression constraint. +Unwraps the ``Constraint`` instance as an Expression constraint, and returns the variable assigned by the expression. Will panic if the Constraint is not an Expression constraint. [caption=""] .Returns @@ -91,7 +91,7 @@ char* constraint_expression_get_text(const struct ConstraintWithSpan* constraint -Unwraps the ``Constraint`` instance as an ``Expression`` constraint, and returns the expression text. Will panic if the Constraint is not an Expression constraint. +Unwraps the ``Constraint`` instance as an Expression constraint, and returns the expression text. Will panic if the Constraint is not an Expression constraint. [caption=""] .Returns @@ -107,7 +107,7 @@ struct ConstraintVertexIterator* constraint_function_call_get_arguments(const st -Unwraps the ``Constraint`` instance as a ``FunctionCall`` constraint, and returns the variables passed as arguments to the function call . Will panic if the Constraint is not a FunctionCall constraint. +Unwraps the ``Constraint`` instance as a FunctionCall constraint, and returns the variables passed as arguments to the function call . Will panic if the Constraint is not a FunctionCall constraint. [caption=""] .Returns @@ -123,7 +123,7 @@ struct ConstraintVertexIterator* constraint_function_call_get_assigned(const str -Unwraps the ``Constraint`` instance as a ``FunctionCall`` constraint, and returns the variables assigned by the function call. Will panic if the Constraint is not a FunctionCall constraint. +Unwraps the ``Constraint`` instance as a FunctionCall constraint, and returns the variables assigned by the function call. Will panic if the Constraint is not a FunctionCall constraint. [caption=""] .Returns @@ -139,7 +139,7 @@ char* constraint_function_call_get_name(const struct ConstraintWithSpan* constra -Unwraps the ``Constraint`` instance as a ``FunctionCall`` constraint, and returns the function name. Will panic if the Constraint is not a FunctionCall constraint. +Unwraps the ``Constraint`` instance as a FunctionCall constraint, and returns the function name. Will panic if the Constraint is not a FunctionCall constraint. [caption=""] .Returns @@ -155,7 +155,7 @@ struct ConstraintVertex* constraint_has_get_attribute(const struct ConstraintWit -Unwraps the ``Constraint`` instance as a ``Has`` constraint, and returns the attribute vertex. Will panic if the Constraint is not a Has constraint. +Unwraps the ``Constraint`` instance as a Has constraint, and returns the attribute vertex. Will panic if the Constraint is not a Has constraint. [caption=""] .Returns @@ -171,7 +171,7 @@ enum ConstraintExactness constraint_has_get_exactness(const struct ConstraintWit -(FUTURE-USE: Currently always ConstraintExactness::Subtypes) Unwraps the ``Constraint`` instance as a ``Has`` constraint, and returns the exactness of the attribute match. Will panic if the Constraint is not a Has constraint. +(FUTURE-USE: Currently always ConstraintExactness::Subtypes) Unwraps the ``Constraint`` instance as a Has constraint, and returns the exactness of the attribute match. Will panic if the Constraint is not a Has constraint. [caption=""] .Returns @@ -187,7 +187,7 @@ struct ConstraintVertex* constraint_has_get_owner(const struct ConstraintWithSpa -Unwraps the ``Constraint`` instance as a ``Has`` constraint, and returns the owner vertex. Will panic if the Constraint is not a Has constraint. +Unwraps the ``Constraint`` instance as a Has constraint, and returns the owner vertex. Will panic if the Constraint is not a Has constraint. [caption=""] .Returns @@ -203,7 +203,7 @@ char* constraint_iid_get_iid(const struct ConstraintWithSpan* constraint) -Unwraps the ``Constraint`` instance as an ``Iid`` constraint, and returns the iid value as a string. Will panic if the Constraint is not an Iid constraint. +Unwraps the ``Constraint`` instance as an Iid constraint, and returns the iid value as a string. Will panic if the Constraint is not an Iid constraint. [caption=""] .Returns @@ -219,7 +219,7 @@ struct ConstraintVertex* constraint_iid_get_variable(const struct ConstraintWith -Unwraps the ``Constraint`` instance as an ``Iid`` constraint, and returns the concept (variable) the iid applies to. Will panic if the Constraint is not an Iid constraint. +Unwraps the ``Constraint`` instance as an Iid constraint, and returns the concept (variable) the iid applies to. Will panic if the Constraint is not an Iid constraint. [caption=""] .Returns @@ -235,7 +235,7 @@ struct ConstraintVertex* constraint_is_get_lhs(const struct ConstraintWithSpan* -Unwraps the ``Constraint`` instance as an ``Is`` constraint, and returns the left-hand side vertex. Will panic if the Constraint is not an Is constraint. +Unwraps the ``Constraint`` instance as an Is constraint, and returns the left-hand side vertex. Will panic if the Constraint is not an Is constraint. [caption=""] .Returns @@ -251,7 +251,7 @@ struct ConstraintVertex* constraint_is_get_rhs(const struct ConstraintWithSpan* -Unwraps the ``Constraint`` instance as an ``Is`` constraint, and returns the right-hand side vertex. Will panic if the Constraint is not an Is constraint. +Unwraps the ``Constraint`` instance as an Is constraint, and returns the right-hand side vertex. Will panic if the Constraint is not an Is constraint. [caption=""] .Returns @@ -267,7 +267,7 @@ enum ConstraintExactness constraint_isa_get_exactness(const struct ConstraintWit -Unwraps the ``Constraint`` instance as an ``Isa`` constraint, and returns the exactness of the type match. Will panic if the Constraint is not an Isa constraint. +Unwraps the ``Constraint`` instance as an Isa constraint, and returns the exactness of the type match. Will panic if the Constraint is not an Isa constraint. [caption=""] .Returns @@ -283,7 +283,7 @@ struct ConstraintVertex* constraint_isa_get_instance(const struct ConstraintWith -Unwraps the ``Constraint`` instance as an ``Isa`` constraint, and returns the instance vertex. Will panic if the Constraint is not an Isa constraint. +Unwraps the ``Constraint`` instance as an Isa constraint, and returns the instance vertex. Will panic if the Constraint is not an Isa constraint. [caption=""] .Returns @@ -299,7 +299,7 @@ struct ConstraintVertex* constraint_isa_get_type(const struct ConstraintWithSpan -Unwraps the ``Constraint`` instance as an ``Isa`` constraint, and returns the type vertex. Will panic if the Constraint is not an Isa constraint. +Unwraps the ``Constraint`` instance as an Isa constraint, and returns the type vertex. Will panic if the Constraint is not an Isa constraint. [caption=""] .Returns @@ -315,7 +315,7 @@ enum Kind constraint_kind_get_kind(const struct ConstraintWithSpan* constraint) -Unwraps the ``Constraint`` instance as a ``Kind`` constraint, and returns the ``Kind`` of the type-vertex. Will panic if the Constraint is not a Kind constraint. +Unwraps the ``Constraint`` instance as a Kind constraint, and returns the Kind of the type-vertex. Will panic if the Constraint is not a Kind constraint. [caption=""] .Returns @@ -331,7 +331,7 @@ struct ConstraintVertex* constraint_kind_get_type(const struct ConstraintWithSpa -Unwraps the ``Constraint`` instance as a ``Kind`` constraint, and returns the associated type vertex. Will panic if the Constraint is not a Kind constraint. +Unwraps the ``Constraint`` instance as a Kind constraint, and returns the associated type vertex. Will panic if the Constraint is not a Kind constraint. [caption=""] .Returns @@ -347,7 +347,7 @@ char* constraint_label_get_label(const struct ConstraintWithSpan* constraint) -Unwraps the ``Constraint`` instance as a ``Label`` constraint, and returns the label string. Will panic if the Constraint is not a Label constraint. +Unwraps the ``Constraint`` instance as a Label constraint, and returns the label string. Will panic if the Constraint is not a Label constraint. [caption=""] .Returns @@ -363,7 +363,7 @@ struct ConstraintVertex* constraint_label_get_variable(const struct ConstraintWi -Unwraps the ``Constraint`` instance as a ``Label`` constraint, and returns the type-vertex the label applies to. Will panic if the Constraint is not a Label constraint. +Unwraps the ``Constraint`` instance as a Label constraint, and returns the type-vertex the label applies to. Will panic if the Constraint is not a Label constraint. [caption=""] .Returns @@ -379,7 +379,7 @@ enum ConstraintExactness constraint_links_get_exactness(const struct ConstraintW -(FUTURE-USE: Currently always ConstraintExactness::Subtypes) Unwraps the ``Constraint`` instance as a ``Links`` constraint, and returns the exactness of the role-type match. Will panic if the Constraint is not a Links constraint. +(FUTURE-USE: Currently always ConstraintExactness::Subtypes) Unwraps the ``Constraint`` instance as a Links constraint, and returns the exactness of the role-type match. Will panic if the Constraint is not a Links constraint. [caption=""] .Returns @@ -395,7 +395,7 @@ struct ConstraintVertex* constraint_links_get_player(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a ``Links`` constraint, and returns the player vertex. Will panic if the Constraint is not a Links constraint. +Unwraps the ``Constraint`` instance as a Links constraint, and returns the player vertex. Will panic if the Constraint is not a Links constraint. [caption=""] .Returns @@ -411,7 +411,7 @@ struct ConstraintVertex* constraint_links_get_relation(const struct ConstraintWi -Unwraps the ``Constraint`` instance as a ``Links`` constraint, and returns the relation vertex. Will panic if the Constraint is not a Links constraint. +Unwraps the ``Constraint`` instance as a Links constraint, and returns the relation vertex. Will panic if the Constraint is not a Links constraint. [caption=""] .Returns @@ -427,7 +427,7 @@ struct ConstraintVertex* constraint_links_get_role(const struct ConstraintWithSp -Unwraps the ``Constraint`` instance as a ``Links`` constraint, and returns the role vertex. Will panic if the Constraint is not a Links constraint. +Unwraps the ``Constraint`` instance as a Links constraint, and returns the role vertex. Will panic if the Constraint is not a Links constraint. [caption=""] .Returns @@ -443,7 +443,7 @@ struct ConjunctionID* constraint_not_get_conjunction(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a ``Not`` constraint, and returns the ``ConjunctionID`` of the negated conjunction. Will panic if the Constraint is not a Not constraint. +Unwraps the ``Constraint`` instance as a Not constraint, and returns the ``ConjunctionID`` of the negated conjunction. Will panic if the Constraint is not a Not constraint. [caption=""] .Returns @@ -459,7 +459,7 @@ struct ConjunctionIDIterator* constraint_or_get_branches(const struct Constraint -Unwraps the ``Constraint`` instance as an ``Or`` constraint, and returns the ``ConjunctionID``s of the conjunction in each of the branches. Will panic if the Constraint is not an Or constraint. +Unwraps the ``Constraint`` instance as an Or constraint, and returns the ``ConjunctionID``s of the conjunction in each of the branches. Will panic if the Constraint is not an Or constraint. [caption=""] .Returns @@ -475,7 +475,7 @@ struct ConstraintVertex* constraint_owns_get_attribute(const struct ConstraintWi -Unwraps the ``Constraint`` instance as an ``Owns`` constraint, and returns the attribute-type vertex. Will panic if the Constraint is not an Owns constraint. +Unwraps the ``Constraint`` instance as an Owns constraint, and returns the attribute-type vertex. Will panic if the Constraint is not an Owns constraint. [caption=""] .Returns @@ -507,7 +507,7 @@ struct ConstraintVertex* constraint_owns_get_owner(const struct ConstraintWithSp -Unwraps the ``Constraint`` instance as an ``Owns`` constraint, and returns the owner-type vertex. Will panic if the Constraint is not an Owns constraint. +Unwraps the ``Constraint`` instance as an Owns constraint, and returns the owner-type vertex. Will panic if the Constraint is not an Owns constraint. [caption=""] .Returns @@ -539,7 +539,7 @@ struct ConstraintVertex* constraint_plays_get_player(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a ``Plays`` constraint, and returns the player type vertex. Will panic if the Constraint is not a Plays constraint. +Unwraps the ``Constraint`` instance as a Plays constraint, and returns the player type vertex. Will panic if the Constraint is not a Plays constraint. [caption=""] .Returns @@ -555,7 +555,7 @@ struct ConstraintVertex* constraint_plays_get_role(const struct ConstraintWithSp -Unwraps the ``Constraint`` instance as a ``Plays`` constraint, and returns the role-type vertex. Will panic if the Constraint is not a Plays constraint. +Unwraps the ``Constraint`` instance as a Plays constraint, and returns the role-type vertex. Will panic if the Constraint is not a Plays constraint. [caption=""] .Returns @@ -571,7 +571,7 @@ enum ConstraintExactness constraint_relates_get_exactness(const struct Constrain -Unwraps the ``Constraint`` instance as a ``Relates`` constraint, and returns the exactness of the relation match. Will panic if the Constraint is not a Relates constraint. +Unwraps the ``Constraint`` instance as a Relates constraint, and returns the exactness of the relation match. Will panic if the Constraint is not a Relates constraint. [caption=""] .Returns @@ -587,7 +587,7 @@ struct ConstraintVertex* constraint_relates_get_relation(const struct Constraint -Unwraps the ``Constraint`` instance as a ``Relates`` constraint, and returns the relation-type vertex. Will panic if the Constraint is not a Relates constraint. +Unwraps the ``Constraint`` instance as a Relates constraint, and returns the relation-type vertex. Will panic if the Constraint is not a Relates constraint. [caption=""] .Returns @@ -603,7 +603,7 @@ struct ConstraintVertex* constraint_relates_get_role(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a ``Relates`` constraint, and returns the role-type vertex. Will panic if the Constraint is not a Relates constraint. +Unwraps the ``Constraint`` instance as a Relates constraint, and returns the role-type vertex. Will panic if the Constraint is not a Relates constraint. [caption=""] .Returns @@ -635,7 +635,7 @@ enum ConstraintExactness constraint_sub_get_exactness(const struct ConstraintWit -Unwraps the ``Constraint`` instance as a ``Sub`` constraint, and returns the exactness of the subtype match. If Exact (i.e. ``sub!``), only the immediate subtype is returned else, (i.e. ``sub``) the type itself and all subtypes are returned. Will panic if the Constraint is not a Sub constraint. +Unwraps the ``Constraint`` instance as a Sub constraint, and returns the exactness of the subtype match. If Exact (i.e. sub!), only the immediate subtype is returned else, (i.e. sub) the type itself and all subtypes are returned. Will panic if the Constraint is not a Sub constraint. [caption=""] .Returns @@ -651,7 +651,7 @@ struct ConstraintVertex* constraint_sub_get_subtype(const struct ConstraintWithS -Unwraps the ``Constraint`` instance as a ``Sub`` constraint, and returns the subtype vertex. Will panic if the Constraint is not a Sub constraint. +Unwraps the ``Constraint`` instance as a Sub constraint, and returns the subtype vertex. Will panic if the Constraint is not a Sub constraint. [caption=""] .Returns @@ -667,7 +667,7 @@ struct ConstraintVertex* constraint_sub_get_supertype(const struct ConstraintWit -Unwraps the ``Constraint`` instance as a ``Sub`` constraint, and returns the supertype vertex. Will panic if the Constraint is not a Sub constraint. +Unwraps the ``Constraint`` instance as a Sub constraint, and returns the supertype vertex. Will panic if the Constraint is not a Sub constraint. [caption=""] .Returns @@ -683,7 +683,7 @@ struct ConjunctionID* constraint_try_get_conjunction(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a ``Try`` constraint, and returns the ``ConjunctionID`` of the optionally matched conjunction. Will panic if the Constraint is not a Try constraint. +Unwraps the ``Constraint`` instance as a Try constraint, and returns the ``ConjunctionID`` of the optionally matched conjunction. Will panic if the Constraint is not a Try constraint. [caption=""] .Returns @@ -699,7 +699,7 @@ struct ConstraintVertex* constraint_value_get_attribute_type(const struct Constr -Unwraps the ``Constraint`` instance as a ``Value`` constraint, and returns the attribute type vertex. Will panic if the Constraint is not a Value constraint. +Unwraps the ``Constraint`` instance as a Value constraint, and returns the attribute type vertex. Will panic if the Constraint is not a Value constraint. [caption=""] .Returns @@ -715,7 +715,7 @@ char* constraint_value_get_value_type(const struct ConstraintWithSpan* constrain -Unwraps the ``Constraint`` instance as a ``Value`` constraint, and returns the specified ValueType as a string. Will panic if the Constraint is not a Value constraint. +Unwraps the ``Constraint`` instance as a Value constraint, and returns the specified ValueType as a string. Will panic if the Constraint is not a Value constraint. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/analyze/constraintexactness.adoc b/docs/modules/ROOT/partials/c/analyze/constraintexactness.adoc index 5e55ba3384..157a9ce3b5 100644 --- a/docs/modules/ROOT/partials/c/analyze/constraintexactness.adoc +++ b/docs/modules/ROOT/partials/c/analyze/constraintexactness.adoc @@ -29,13 +29,13 @@ Tells apart exact variants of constraints from the ones allowing subtype-polymor Exact  -Indicates the constraint matches exactly the specified type - e.g. ``isa!`` or ``sub!`` +Indicates the constraint matches exactly the specified type - e.g. isa! or sub! Subtypes  -Indicates the constraint matches the specified type and its subtypes - e.g. ``isa!`` or ``sub!`` +Indicates the constraint matches the specified type and its subtypes - e.g. isa! or sub! diff --git a/docs/modules/ROOT/partials/c/analyze/reduceassignment.adoc b/docs/modules/ROOT/partials/c/analyze/reduceassignment.adoc index ae8bc1690a..71760bc372 100644 --- a/docs/modules/ROOT/partials/c/analyze/reduceassignment.adoc +++ b/docs/modules/ROOT/partials/c/analyze/reduceassignment.adoc @@ -37,7 +37,7 @@ struct Variable* reduce_assignment_get_assigned(const struct ReduceAssignment* r -The variable being assigned to in this ReduceAssignment. e.g. ``$c`` in ``$c = sum($x)`` +The variable being assigned to in this ReduceAssignment. e.g. $c in ``$c = sum($x)`` [caption=""] .Returns @@ -53,7 +53,7 @@ struct Reducer* reduce_assignment_get_reducer(const struct ReduceAssignment* red -The reducer applied in this ReduceAssignment. e.g. ``sum($x)`` in ``$c = sum($x)`` +The reducer applied in this ReduceAssignment. e.g. sum($x) in ``$c = sum($x)`` [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/analyze/reducer.adoc b/docs/modules/ROOT/partials/c/analyze/reducer.adoc index e4aab5dd8c..34f0088a76 100644 --- a/docs/modules/ROOT/partials/c/analyze/reducer.adoc +++ b/docs/modules/ROOT/partials/c/analyze/reducer.adoc @@ -37,7 +37,7 @@ struct VariableIterator* reducer_get_arguments(const struct Reducer* reducer) -The arguments to this Reducer. e.g. ``$x`` in ``sum($x)`` +The arguments to this Reducer. e.g. $x in ``sum($x)`` [caption=""] .Returns @@ -53,7 +53,7 @@ char* reducer_get_name(const struct Reducer* reducer) -The name of the operation applied by this Reducer. e.g. ``sum`` in ``sum($x)`` +The name of the operation applied by this Reducer. e.g. sum in ``sum($x)`` [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/answer/conceptrow.adoc b/docs/modules/ROOT/partials/c/answer/conceptrow.adoc index f623ea7594..cf6b05b405 100644 --- a/docs/modules/ROOT/partials/c/answer/conceptrow.adoc +++ b/docs/modules/ROOT/partials/c/answer/conceptrow.adoc @@ -117,7 +117,7 @@ struct Pipeline* concept_row_get_query_structure(const struct ConceptRow* concep -Retrieve the executed query's structure from the ``ConceptRow``'s header, if set. It must be requested via "include query structure" in ``QueryOptions`` +Retrieves the executed query's structure from the ``ConceptRow``'s header, if set. It must be requested via "include query structure" in ``QueryOptions`` [caption=""] .Returns @@ -133,7 +133,7 @@ enum QueryType concept_row_get_query_type(const struct ConceptRow* concept_row) -Retrieve the executed query's type of the ``ConceptRow``'s header. +Retrieves the executed query's type of the ``ConceptRow``'s header. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/answer/queryanswer.adoc b/docs/modules/ROOT/partials/c/answer/queryanswer.adoc index c75d775004..5c151f317c 100644 --- a/docs/modules/ROOT/partials/c/answer/queryanswer.adoc +++ b/docs/modules/ROOT/partials/c/answer/queryanswer.adoc @@ -27,7 +27,7 @@ enum QueryType query_answer_get_query_type(const struct QueryAnswer* query_answe -Retrieve the executed query's type of the ``QueryAnswer``. +Retrieves the executed query's type of the ``QueryAnswer``. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/concept/attribute.adoc b/docs/modules/ROOT/partials/c/concept/attribute.adoc index fd27cbe5da..83406cdc30 100644 --- a/docs/modules/ROOT/partials/c/concept/attribute.adoc +++ b/docs/modules/ROOT/partials/c/concept/attribute.adoc @@ -11,7 +11,7 @@ struct Concept* attribute_get_type(const struct Concept* attribute) -Retrieves the type which this ``Attribute`` belongs to. +Retrieves the type which this Attribute belongs to. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/concept/concept.adoc b/docs/modules/ROOT/partials/c/concept/concept.adoc index acc86c055f..88235798ad 100644 --- a/docs/modules/ROOT/partials/c/concept/concept.adoc +++ b/docs/modules/ROOT/partials/c/concept/concept.adoc @@ -96,7 +96,7 @@ Returns the value of this datetime value concept as seconds and nanoseconds part [source,c] ---- -struct DatetimeAndTimeZone concept_get_datetime_tz(const struct Concept* concept) +struct DatetimeAndTimeZone* concept_get_datetime_tz(const struct Concept* concept) ---- @@ -105,7 +105,7 @@ Returns the value of this datetime-tz value concept as seconds and nanoseconds p [caption=""] .Returns -`struct DatetimeAndTimeZone` +`struct DatetimeAndTimeZone*` [#_concept_get_decimal] ==== function ``concept_get_decimal`` diff --git a/docs/modules/ROOT/partials/c/concept/datetimeandtimezone.adoc b/docs/modules/ROOT/partials/c/concept/datetimeandtimezone.adoc index 484f617e22..f72ae2107c 100644 --- a/docs/modules/ROOT/partials/c/concept/datetimeandtimezone.adoc +++ b/docs/modules/ROOT/partials/c/concept/datetimeandtimezone.adoc @@ -9,7 +9,7 @@ -A ``DatetimeAndTimeZone`` used to represent time zoned datetime in FFI. Time zone can be represented either as an IANA ``Tz`` or as a ``FixedOffset``. Either the zone_name (is_fixed_offset == false) or offset (is_fixed_offset == true) is set. +``DatetimeAndTimeZone`` is used to represent time zoned datetime in FFI. Time zone can be represented either as an IANA ``Tz`` or as a ``FixedOffset``. Either the zone_name (is_fixed_offset == false) or offset (is_fixed_offset == true) is set. [#_datetime_and_time_zone_drop] ==== function ``datetime_and_time_zone_drop`` diff --git a/docs/modules/ROOT/partials/c/concept/entity.adoc b/docs/modules/ROOT/partials/c/concept/entity.adoc index 2c9dd61e4b..2a18395ede 100644 --- a/docs/modules/ROOT/partials/c/concept/entity.adoc +++ b/docs/modules/ROOT/partials/c/concept/entity.adoc @@ -11,7 +11,7 @@ struct Concept* entity_get_type(const struct Concept* entity) -Retrieves the type which this ``Entity`` belongs to. +Retrieves the type which this Entity belongs to. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/concept/relation.adoc b/docs/modules/ROOT/partials/c/concept/relation.adoc index c12ab91bae..ad9982a19f 100644 --- a/docs/modules/ROOT/partials/c/concept/relation.adoc +++ b/docs/modules/ROOT/partials/c/concept/relation.adoc @@ -11,7 +11,7 @@ struct Concept* relation_get_type(const struct Concept* relation) -Retrieves the type which this ``Relation`` belongs to. +Retrieves the type which this Relation belongs to. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/connection/consistencylevel.adoc b/docs/modules/ROOT/partials/c/connection/consistencylevel.adoc new file mode 100644 index 0000000000..b6913c449d --- /dev/null +++ b/docs/modules/ROOT/partials/c/connection/consistencylevel.adoc @@ -0,0 +1,87 @@ +[#_methods_connection_consistencylevel] +=== consistencylevel + +[#_Struct_ConsistencyLevel] +[.doc-api-reference-driver] +==== Struct ConsistencyLevel + +`rust struct (pointer)` + + + +``ConsistencyLevel`` is used to represent consistency levels in FFI. It combines ``ConsistencyLevelTag`` and optional fields to form an instance of the original enum. ``address`` is not null only when tag is ``ReplicaDependent``. + +[#_consistency_level_drop] +==== function ``consistency_level_drop`` + +[source,c] +---- +void consistency_level_drop(struct ConsistencyLevel* consistency_level) +---- + + + +Drops the ``ConsistencyLevel`` object. + +[caption=""] +.Returns +`void` + +[#_consistency_level_eventual] +==== function ``consistency_level_eventual`` + +[source,c] +---- +struct ConsistencyLevel* consistency_level_eventual(void) +---- + + + +Creates an eventual ``ConsistencyLevel`` object. + +[caption=""] +.Returns +`struct ConsistencyLevel*` + +[#_consistency_level_replica_dependent] +==== function ``consistency_level_replica_dependent`` + +[source,c] +---- +struct ConsistencyLevel* consistency_level_replica_dependent(const char* address) +---- + + + +Creates a replica dependent ``ConsistencyLevel`` object. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `address` a| The address of the replica to depend on. a| `const char*` +|=== + +[caption=""] +.Returns +`struct ConsistencyLevel*` + +[#_consistency_level_strong] +==== function ``consistency_level_strong`` + +[source,c] +---- +struct ConsistencyLevel* consistency_level_strong(void) +---- + + + +Creates a strong ``ConsistencyLevel`` object. + +[caption=""] +.Returns +`struct ConsistencyLevel*` + diff --git a/docs/modules/ROOT/partials/c/connection/consistencyleveltag.adoc b/docs/modules/ROOT/partials/c/connection/consistencyleveltag.adoc new file mode 100644 index 0000000000..a3d4fbc6b3 --- /dev/null +++ b/docs/modules/ROOT/partials/c/connection/consistencyleveltag.adoc @@ -0,0 +1,36 @@ +[#_methods_connection_consistencyleveltag] +=== consistencyleveltag + +[#_Struct_ConsistencyLevelTag] +[.doc-api-reference-driver] +==== Struct ConsistencyLevelTag + +`rust struct (pointer)` + + + +``ConsistencyLevelTag`` is used to represent consistency levels in FFI. It is the tag part, which is combined with optional fields to form an instance of the original enum. + +[#_Enum_ConsistencyLevelTag] +[.doc-api-reference-driver] +==== Enum ConsistencyLevelTag + +`rust enum (pointer)` + + + +``ConsistencyLevelTag`` is used to represent consistency levels in FFI. It is the tag part, which is combined with optional fields to form an instance of the original enum. + +[caption=""] +.Enum constants +// tag::enum_constants[] +[cols=""] +[options="header"] +|=== +|Name +a| `Eventual` +a| `ReplicaDependent` +a| `Strong` +|=== +// end::enum_constants[] + diff --git a/docs/modules/ROOT/partials/c/connection/credential.adoc b/docs/modules/ROOT/partials/c/connection/credential.adoc index f47021a916..251d5ee888 100644 --- a/docs/modules/ROOT/partials/c/connection/credential.adoc +++ b/docs/modules/ROOT/partials/c/connection/credential.adoc @@ -11,3 +11,46 @@ User credentials for connecting to TypeDB +[#_credentials_drop] +==== function ``credentials_drop`` + +[source,c] +---- +void credentials_drop(struct Credentials* credentials) +---- + + + +Frees the native rust ``Credentials`` object + +[caption=""] +.Returns +`void` + +[#_credentials_new] +==== function ``credentials_new`` + +[source,c] +---- +struct Credentials* credentials_new(const char* username, const char* password) +---- + + + +Creates a new ``Credentials`` for connecting to TypeDB Server. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `username` a| The name of the user to connect as a| `const char*` +a| `password` a| The password for the user a| `const char*` +|=== + +[caption=""] +.Returns +`struct Credentials*` + diff --git a/docs/modules/ROOT/partials/c/connection/database.adoc b/docs/modules/ROOT/partials/c/connection/database.adoc index 70c4b2d076..1f743b7018 100644 --- a/docs/modules/ROOT/partials/c/connection/database.adoc +++ b/docs/modules/ROOT/partials/c/connection/database.adoc @@ -2,295 +2,127 @@ === database [#_Struct_Database] +[.doc-api-reference-driver] ==== Struct Database +`rust struct (pointer)` -A TypeDB database -[#_Struct_DatabaseIterator] -==== Struct DatabaseIterator - - - -An ``Iterator`` over databases present on the TypeDB server - -[#_Struct_DatabaseManager] -==== Struct DatabaseManager - - - -Provides access to all database management methods. +A TypeDB database. [#_database_close] -==== database_close +==== function ``database_close`` -[source,cpp] +[source,c] ---- -void database_close(struct Database* database) +void database_close(const struct Database* database) ---- -Frees the native rust ``Database`` object +Frees the native rust ``Database`` object. [caption=""] .Returns `void` [#_database_delete] -==== database_delete +==== function ``database_delete`` -[source,cpp] +[source,c] ---- -void database_delete(struct Database* database) +void database_delete(const struct Database* database, const struct ConsistencyLevel* consistency_level) ---- Deletes this database. -[caption=""] -.Returns -`void` - -[#_database_get_name] -==== database_get_name - -[source,cpp] ----- -char* database_get_name(const struct Database* database) ----- - - - -The database name as a string. [caption=""] -.Returns -`char*` - -[#_database_get_preferred_replica_info] -==== database_get_preferred_replica_info - -[source,cpp] ----- -struct ReplicaInfo* database_get_preferred_replica_info(const struct Database* database) ----- - - - -Returns the preferred replica for this database. Operations which can be run on any replica will prefer to use this replica. _Only works in TypeDB Cloud_ - -[caption=""] -.Returns -`struct ReplicaInfo*` - -[#_database_get_primary_replica_info] -==== database_get_primary_replica_info - -[source,cpp] ----- -struct ReplicaInfo* database_get_primary_replica_info(const struct Database* database) ----- - - - -Returns the primary replica for this database. _Only works in TypeDB Cloud_ - -[caption=""] -.Returns -`struct ReplicaInfo*` - -[#_database_get_replicas_info] -==== database_get_replicas_info - -[source,cpp] ----- -struct ReplicaInfoIterator* database_get_replicas_info(const struct Database* database) ----- - - - -Set of ``ServerReplica`` instances for this database. Only works in TypeDB Cloud - -[caption=""] -.Returns -`struct ReplicaInfoIterator*` - -[#_database_iterator_drop] -==== database_iterator_drop - -[source,cpp] ----- -void database_iterator_drop(struct DatabaseIterator* it) ----- - - - -Frees the native rust ``DatabaseIterator`` object +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `database` a| The ``Database`` to delete. a| `const struct Database*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== [caption=""] .Returns `void` -[#_database_iterator_next] -==== database_iterator_next - -[source,cpp] ----- -struct Database* database_iterator_next(struct DatabaseIterator* it) ----- - - - -Forwards the ``DatabaseIterator`` and returns the next ``Database`` if it exists, or null if there are no more elements. - -[caption=""] -.Returns -`struct Database*` - -[#_database_manager_drop] -==== database_manager_drop +[#_database_export_to_file] +==== function ``database_export_to_file`` -[source,cpp] +[source,c] ---- -void database_manager_drop(struct DatabaseManager* databases) +void database_export_to_file(const struct Database* database, const char* schema_file, const char* data_file, const struct ConsistencyLevel* consistency_level) ---- -Frees the native rust ``DatabaseManager`` object +Export a database into a schema definition and a data files saved to the disk. This is a blocking operation and may take a significant amount of time depending on the database size. -[caption=""] -.Returns -`void` - -[#_database_manager_new] -==== database_manager_new - -[source,cpp] ----- -struct DatabaseManager* database_manager_new(const struct Connection* connection) ----- - - - -Creates and returns a native ``DatabaseManager`` for the connection [caption=""] -.Returns -`struct DatabaseManager*` - -[#_database_rule_schema] -==== database_rule_schema - -[source,cpp] ----- -char* database_rule_schema(struct Database* database) ----- - - - -The rules in the schema as a valid TypeQL define query string. +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `database` a| The ``Database`` object to export from. a| `const struct Database*` +a| `schema_file` a| The path to the schema definition file to be created. a| `const char*` +a| `data_file` a| The path to the data file to be created. a| `const char*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== [caption=""] .Returns -`char*` +`void` -[#_database_schema] -==== database_schema +[#_database_get_name] +==== function ``database_get_name`` -[source,cpp] +[source,c] ---- -char* database_schema(struct Database* database) +char* database_get_name(const struct Database* database) ---- -A full schema text as a valid TypeQL define query string. +The ``Database`` name as a string. [caption=""] .Returns `char*` [#_database_type_schema] -==== database_type_schema +==== function ``database_type_schema`` -[source,cpp] +[source,c] ---- -char* database_type_schema(struct Database* database) +char* database_type_schema(const struct Database* database, const struct ConsistencyLevel* consistency_level) ---- The types in the schema as a valid TypeQL define query string. -[caption=""] -.Returns -`char*` - -[#_databases_all] -==== databases_all - -[source,cpp] ----- -struct DatabaseIterator* databases_all(struct DatabaseManager* databases) ----- - - - -Returns a ``DatabaseIterator`` over all databases present on the TypeDB server - -[caption=""] -.Returns -`struct DatabaseIterator*` - -[#_databases_contains] -==== databases_contains - -[source,cpp] ----- -bool databases_contains(struct DatabaseManager* databases, const char* name) ----- - - - -Checks if a database with the given name exists - -[caption=""] -.Returns -`bool` - -[#_databases_create] -==== databases_create - -[source,cpp] ----- -void databases_create(struct DatabaseManager* databases, const char* name) ----- - - - -Create a database with the given name [caption=""] -.Returns -`void` - -[#_databases_get] -==== databases_get - -[source,cpp] ----- -struct Database* databases_get(struct DatabaseManager* databases, const char* name) ----- - - - -Retrieve the database with the given name. +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `database` a| The ``Database`` to get the type schema from. a| `const struct Database*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== [caption=""] .Returns -`struct Database*` +`char*` diff --git a/docs/modules/ROOT/partials/c/connection/databases.adoc b/docs/modules/ROOT/partials/c/connection/databases.adoc index 9f78d5c01a..8d87f7ea3d 100644 --- a/docs/modules/ROOT/partials/c/connection/databases.adoc +++ b/docs/modules/ROOT/partials/c/connection/databases.adoc @@ -6,13 +6,24 @@ [source,c] ---- -char* database_schema(const struct Database* database) +char* database_schema(const struct Database* database, const struct ConsistencyLevel* consistency_level) ---- A full schema text as a valid TypeQL define query string. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `database` a| The ``Database`` to get the schema from. a| `const struct Database*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== + [caption=""] .Returns `char*` @@ -22,13 +33,24 @@ A full schema text as a valid TypeQL define query string. [source,c] ---- -struct DatabaseIterator* databases_all(struct TypeDBDriver* driver) +struct DatabaseIterator* databases_all(struct TypeDBDriver* driver, const struct ConsistencyLevel* consistency_level) ---- Returns a ``DatabaseIterator`` over all databases present on the TypeDB server. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `struct TypeDBDriver*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== + [caption=""] .Returns `struct DatabaseIterator*` @@ -38,13 +60,25 @@ Returns a ``DatabaseIterator`` over all databases present on the TypeDB server. [source,c] ---- -bool databases_contains(struct TypeDBDriver* driver, const char* name) +bool databases_contains(struct TypeDBDriver* driver, const char* name, const struct ConsistencyLevel* consistency_level) ---- Checks if a database with the given name exists. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `struct TypeDBDriver*` +a| `name` a| The name of the database. a| `const char*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== + [caption=""] .Returns `bool` @@ -54,12 +88,24 @@ Checks if a database with the given name exists. [source,c] ---- -void databases_create(struct TypeDBDriver* driver, const char* name) +void databases_create(struct TypeDBDriver* driver, const char* name, const struct ConsistencyLevel* consistency_level) ---- -Create a database with the given name. +Creates a database with the given name. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `struct TypeDBDriver*` +a| `name` a| The name of the database to be created. a| `const char*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== [caption=""] .Returns @@ -70,12 +116,24 @@ Create a database with the given name. [source,c] ---- -const struct Database* databases_get(struct TypeDBDriver* driver, const char* name) +const struct Database* databases_get(struct TypeDBDriver* driver, const char* name, const struct ConsistencyLevel* consistency_level) ---- -Retrieve the database with the given name. +Retrieves the database with the given name. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `struct TypeDBDriver*` +a| `name` a| The name of the database. a| `const char*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== [caption=""] .Returns @@ -91,7 +149,7 @@ void databases_import_from_file(struct TypeDBDriver* driver, const char* name, c -Create a database with the given name based on previously exported another database's data loaded from a file. This is a blocking operation and may take a significant amount of time depending on the database size. +Creates a database with the given name based on previously exported another database's data loaded from a file. This is a blocking operation and may take a significant amount of time depending on the database size. [caption=""] diff --git a/docs/modules/ROOT/partials/c/connection/driver.adoc b/docs/modules/ROOT/partials/c/connection/driver.adoc index 40b6e67b2a..c91fe36f2e 100644 --- a/docs/modules/ROOT/partials/c/connection/driver.adoc +++ b/docs/modules/ROOT/partials/c/connection/driver.adoc @@ -1,6 +1,20 @@ [#_methods_connection_driver] === driver +[#_Struct_DriverTlsConfig] +[.doc-api-reference-driver] +==== Struct DriverTlsConfig + +`rust struct (pointer)` + + + +TLS configuration for the TypeDB driver. + +DriverTlsConfig represents a fully constructed and validated TLS configuration. If TLS is enabled, the underlying TLS config is built eagerly at construction time, ensuring that no connection attempt can observe a partially-configured TLS state. + +The driver defaults to using TLS with native system trust roots. This matches typical system and container deployments while still allowing explicit opt-out or custom PKI configuration. + [#_driver_close] ==== function ``driver_close`` @@ -11,7 +25,44 @@ void driver_close(struct TypeDBDriver* driver) -Closes the driver. Before instantiating a new driver, the driver that’s currently open should first be closed. Closing a driver frees the underlying Rust object. +Closes the ``TypeDBDriver``. Before instantiating a new driver, the driver that’s currently open should first be closed. Closing a driver frees the underlying Rust object. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `struct TypeDBDriver*` +|=== + +[caption=""] +.Returns +`void` + +[#_driver_deregister_replica] +==== function ``driver_deregister_replica`` + +[source,c] +---- +void driver_deregister_replica(const struct TypeDBDriver* driver, int64_t replica_id) +---- + + + +Deregisters a replica from the cluster the driver is currently connected to. This replica will no longer play a raft role in this cluster. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `const struct TypeDBDriver*` +a| `replica_id` a| The numeric identifier of the deregistered replica a| `int64_t` +|=== [caption=""] .Returns @@ -27,7 +78,17 @@ void driver_force_close(struct TypeDBDriver* driver) -Forcibly closes the driver. To be used in exceptional cases. +Forcibly closes the ``TypeDBDriver``. To be used in exceptional cases. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `struct TypeDBDriver*` +|=== [caption=""] .Returns @@ -45,16 +106,26 @@ bool driver_is_open(const struct TypeDBDriver* driver) Checks whether this connection is presently open. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `const struct TypeDBDriver*` +|=== + [caption=""] .Returns `bool` -[#_driver_open] -==== function ``driver_open`` +[#_driver_new] +==== function ``driver_new`` [source,c] ---- -struct TypeDBDriver* driver_open(const char* address, const struct Credentials* credentials, const struct DriverOptions* driver_options) +struct TypeDBDriver* driver_new(const char* address, const struct Credentials* credentials, const struct DriverOptions* driver_options) ---- @@ -68,7 +139,94 @@ Open a TypeDB C Driver to a TypeDB server available at the provided address. [options="header"] |=== |Name |Description |Type -a| `address` a| The address (host:port) on which the TypeDB Server is running a| `const char*` +a| `address` a| The address on which the TypeDB Server is running a| `const char*` +a| `credentials` a| The ``Credentials`` to connect with a| `const struct Credentials*` +a| `driver_options` a| The ``DriverOptions`` to connect with a| `const struct DriverOptions*` +|=== + +[caption=""] +.Returns +`struct TypeDBDriver*` + +[#_driver_new_with_address_translation] +==== function ``driver_new_with_address_translation`` + +[source,c] +---- +struct TypeDBDriver* driver_new_with_address_translation(const char*const* public_addresses, const char*const* private_addresses, const struct Credentials* credentials, const struct DriverOptions* driver_options) +---- + + + +Open a TypeDB C Driver to a TypeDB cluster, using the provided address translation. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `public_addresses` a| A null-terminated array holding the replica addresses on for connection. a| `const char*const*` +a| `private_addresses` a| A null-terminated array holding the private replica addresses, configured on the server side. This array _must_ have the same length as ``public_addresses``. a| `const char*const*` +a| `credentials` a| The ``Credentials`` to connect with a| `const struct Credentials*` +a| `driver_options` a| The ``DriverOptions`` to connect with a| `const struct DriverOptions*` +|=== + +[caption=""] +.Returns +`struct TypeDBDriver*` + +[#_driver_new_with_address_translation_with_description] +==== function ``driver_new_with_address_translation_with_description`` + +[source,c] +---- +struct TypeDBDriver* driver_new_with_address_translation_with_description(const char*const* public_addresses, const char*const* private_addresses, const struct Credentials* credentials, const struct DriverOptions* driver_options, const char* driver_lang) +---- + + + +Open a TypeDB Driver to a TypeDB cluster, using the provided address translation. This method allows driver language specification for drivers built on top of the native C layer. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `public_addresses` a| A null-terminated array holding the replica addresses on for connection. a| `const char*const*` +a| `private_addresses` a| A null-terminated array holding the private replica addresses, configured on the server side. This array _must_ have the same length as ``public_addresses``. a| `const char*const*` +a| `credentials` a| The ``Credentials`` to connect with a| `const struct Credentials*` +a| `driver_options` a| The ``DriverOptions`` to connect with a| `const struct DriverOptions*` +a| `driver_lang` a| The language of the driver connecting to the server a| `const char*` +|=== + +[caption=""] +.Returns +`struct TypeDBDriver*` + +[#_driver_new_with_addresses] +==== function ``driver_new_with_addresses`` + +[source,c] +---- +struct TypeDBDriver* driver_new_with_addresses(const char*const* addresses, const struct Credentials* credentials, const struct DriverOptions* driver_options) +---- + + + +Open a TypeDB C Driver to a TypeDB cluster available at the provided addresses. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `addresses` a| A null-terminated array holding the server addresses on for connection a| `const char*const*` a| `credentials` a| The ``Credentials`` to connect with a| `const struct Credentials*` a| `driver_options` a| The ``DriverOptions`` to connect with a| `const struct DriverOptions*` |=== @@ -77,12 +235,41 @@ a| `driver_options` a| The ``DriverOptions`` to connect with a| `const struct Dr .Returns `struct TypeDBDriver*` -[#_driver_open_with_description] -==== function ``driver_open_with_description`` +[#_driver_new_with_addresses_with_description] +==== function ``driver_new_with_addresses_with_description`` [source,c] ---- -struct TypeDBDriver* driver_open_with_description(const char* address, const struct Credentials* credentials, const struct DriverOptions* driver_options, const char* driver_lang) +struct TypeDBDriver* driver_new_with_addresses_with_description(const char*const* addresses, const struct Credentials* credentials, const struct DriverOptions* driver_options, const char* driver_lang) +---- + + + +Open a TypeDB Driver to a TypeDB cluster available at the provided addresses. This method allows driver language specification for drivers built on top of the native C layer. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `addresses` a| A null-terminated array holding the TypeDB cluster replica addresses on for connection a| `const char*const*` +a| `credentials` a| The ``Credentials`` to connect with a| `const struct Credentials*` +a| `driver_options` a| The ``DriverOptions`` to connect with a| `const struct DriverOptions*` +a| `driver_lang` a| The language of the driver connecting to the server a| `const char*` +|=== + +[caption=""] +.Returns +`struct TypeDBDriver*` + +[#_driver_new_with_description] +==== function ``driver_new_with_description`` + +[source,c] +---- +struct TypeDBDriver* driver_new_with_description(const char* address, const struct Credentials* credentials, const struct DriverOptions* driver_options, const char* driver_lang) ---- @@ -96,7 +283,7 @@ Open a TypeDB Driver to a TypeDB server available at the provided address. This [options="header"] |=== |Name |Description |Type -a| `address` a| The address (host:port) on which the TypeDB Server is running a| `const char*` +a| `address` a| The address on which the TypeDB Server is running a| `const char*` a| `credentials` a| The ``Credentials`` to connect with a| `const struct Credentials*` a| `driver_options` a| The ``DriverOptions`` to connect with a| `const struct DriverOptions*` a| `driver_lang` a| The language of the driver connecting to the server a| `const char*` @@ -106,6 +293,255 @@ a| `driver_lang` a| The language of the driver connecting to the server a| `cons .Returns `struct TypeDBDriver*` +[#_driver_primary_replica] +==== function ``driver_primary_replica`` + +[source,c] +---- +struct ServerReplica* driver_primary_replica(const struct TypeDBDriver* driver, const struct ConsistencyLevel* consistency_level) +---- + + + +Retrieves the server's primary replica, if exists. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `const struct TypeDBDriver*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== + +[caption=""] +.Returns +`struct ServerReplica*` + +[#_driver_register_replica] +==== function ``driver_register_replica`` + +[source,c] +---- +void driver_register_replica(const struct TypeDBDriver* driver, int64_t replica_id, const char* address) +---- + + + +Registers a new replica in the cluster the driver is currently connected to. The registered replica will become available eventually, depending on the behavior of the whole cluster. To register a replica, its clustering address should be passed, not the connection address. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `const struct TypeDBDriver*` +a| `replica_id` a| The numeric identifier of the new replica a| `int64_t` +a| `address` a| The address(es) of the TypeDB replica as a string a| `const char*` +|=== + +[caption=""] +.Returns +`void` + +[#_driver_replicas] +==== function ``driver_replicas`` + +[source,c] +---- +struct ServerReplicaIterator* driver_replicas(const struct TypeDBDriver* driver, const struct ConsistencyLevel* consistency_level) +---- + + + +Retrieves the server's replicas. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `const struct TypeDBDriver*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== + +[caption=""] +.Returns +`struct ServerReplicaIterator*` + +[#_driver_server_version] +==== function ``driver_server_version`` + +[source,c] +---- +struct ServerVersion* driver_server_version(const struct TypeDBDriver* driver, const struct ConsistencyLevel* consistency_level) +---- + + + +Retrieves the server version and distribution information. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `const struct TypeDBDriver*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== + +[caption=""] +.Returns +`struct ServerVersion*` + +[#_driver_tls_config_drop] +==== function ``driver_tls_config_drop`` + +[source,c] +---- +void driver_tls_config_drop(struct DriverTlsConfig* tls_config) +---- + + + +Frees the native rust ``DriverTlsConfig`` object. + +[caption=""] +.Returns +`void` + +[#_driver_tls_config_get_root_ca_path] +==== function ``driver_tls_config_get_root_ca_path`` + +[source,c] +---- +char* driver_tls_config_get_root_ca_path(const struct DriverTlsConfig* tls_config) +---- + + + +Returns the TLS root CA set in this ``DriverTlsConfig`` object. Panics if a custom root CA is absent. + +[caption=""] +.Returns +`char*` + +[#_driver_tls_config_has_root_ca_path] +==== function ``driver_tls_config_has_root_ca_path`` + +[source,c] +---- +bool driver_tls_config_has_root_ca_path(const struct DriverTlsConfig* tls_config) +---- + + + +Returns whether a custom root CA path is set. + +[caption=""] +.Returns +`bool` + +[#_driver_tls_config_is_enabled] +==== function ``driver_tls_config_is_enabled`` + +[source,c] +---- +bool driver_tls_config_is_enabled(const struct DriverTlsConfig* tls_config) +---- + + + +Returns whether TLS is enabled. + +[caption=""] +.Returns +`bool` + +[#_driver_tls_config_new_disabled] +==== function ``driver_tls_config_new_disabled`` + +[source,c] +---- +struct DriverTlsConfig* driver_tls_config_new_disabled(void) +---- + + + +Creates a new ``DriverTlsConfig`` with TLS disabled. + +[caption=""] +.Returns +`struct DriverTlsConfig*` + +[#_driver_tls_config_new_enabled_with_native_root_ca] +==== function ``driver_tls_config_new_enabled_with_native_root_ca`` + +[source,c] +---- +struct DriverTlsConfig* driver_tls_config_new_enabled_with_native_root_ca(void) +---- + + + +Creates a new ``DriverTlsConfig`` with TLS enabled using system native trust roots. + +[caption=""] +.Returns +`struct DriverTlsConfig*` + +[#_driver_tls_config_new_enabled_with_root_ca_path] +==== function ``driver_tls_config_new_enabled_with_root_ca_path`` + +[source,c] +---- +struct DriverTlsConfig* driver_tls_config_new_enabled_with_root_ca_path(const char* tls_root_ca) +---- + + + +Creates a new ``DriverTlsConfig`` with TLS enabled using a custom root CA certificate (PEM). + +[caption=""] +.Returns +`struct DriverTlsConfig*` + +[#_driver_update_address_translation] +==== function ``driver_update_address_translation`` + +[source,c] +---- +void driver_update_address_translation(const struct TypeDBDriver* driver, const char*const* public_addresses, const char*const* private_addresses) +---- + + + +Updates address translation of the driver. This lets you actualize new translation information without recreating the driver from scratch. Useful after registering new replicas requiring address translation. This operation will update existing connections using the provided addresses. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `const struct TypeDBDriver*` +a| `public_addresses` a| A null-terminated array holding the replica addresses on for connection. a| `const char*const*` +a| `private_addresses` a| A null-terminated array holding the private replica addresses, configured on the server side. This array _must_ have the same length as ``public_addresses``. a| `const char*const*` +|=== + +[caption=""] +.Returns +`void` + [#_init_logging] ==== function ``init_logging`` @@ -120,8 +556,8 @@ Enables logging in the TypeDB driver. This function sets up tracing with two environment variables: - ``TYPEDB_DRIVER_LOG``: Fine-grained control using the same syntax as ``RUST_LOG``. Example: ``TYPEDB_DRIVER_LOG=typedb_driver=debug,typedb_driver_clib=trace`` - ``TYPEDB_DRIVER_LOG_LEVEL``: Simple log level that applies to both ``typedb_driver`` and ``typedb_driver_clib`` crates. Overrides any settings from ``TYPEDB_DRIVER_LOG``. Example: ``TYPEDB_DRIVER_LOG_LEVEL=debug`` + TYPEDB_DRIVER_LOG: Fine-grained control using the same syntax as RUST_LOG. Example: TYPEDB_DRIVER_LOG=typedb_driver=debug,typedb_driver_clib=trace + TYPEDB_DRIVER_LOG_LEVEL: Simple log level that applies to both typedb_driver and typedb_driver_clib crates. Overrides any settings from TYPEDB_DRIVER_LOG. Example: TYPEDB_DRIVER_LOG_LEVEL=debug If neither is set, the default level is INFO for driver crates. diff --git a/docs/modules/ROOT/partials/c/connection/driveroptions.adoc b/docs/modules/ROOT/partials/c/connection/driveroptions.adoc index dd71acafbf..05a65c4bf9 100644 --- a/docs/modules/ROOT/partials/c/connection/driveroptions.adoc +++ b/docs/modules/ROOT/partials/c/connection/driveroptions.adoc @@ -9,5 +9,224 @@ -User connection settings for connecting to TypeDB. +TypeDB driver connection options. DriverOptions object can be used to override the default driver behavior while connecting to TypeDB. + + +[#_driver_options_drop] +==== function ``driver_options_drop`` + +[source,c] +---- +void driver_options_drop(struct DriverOptions* driver_options) +---- + + + +Frees the native rust ``DriverOptions`` object. + +[caption=""] +.Returns +`void` + +[#_driver_options_get_primary_failover_retries] +==== function ``driver_options_get_primary_failover_retries`` + +[source,c] +---- +int64_t driver_options_get_primary_failover_retries(const struct DriverOptions* options) +---- + + + +Returns the value set for the primary failover retries limit in this ``DriverOptions`` object. Limits the number of attempts to redirect a strongly consistent request to another primary replica in case of a failure due to the change of replica roles. + +[caption=""] +.Returns +`int64_t` + +[#_driver_options_get_replica_discovery_attempts] +==== function ``driver_options_get_replica_discovery_attempts`` + +[source,c] +---- +int64_t driver_options_get_replica_discovery_attempts(const struct DriverOptions* options) +---- + + + +Returns the value set for the replica discovery attempts limit in this ``DriverOptions`` object. Limits the number of driver attempts to discover a single working replica to perform an operation in case of a replica unavailability. Every replica is tested once, which means that at most: + + {limit} operations are performed if the limit <= the number of replicas. + {number of replicas} operations are performed if the limit > the number of replicas. + {number of replicas} operations are performed if the limit is None. Affects every eventually consistent operation, including redirect failover, when the new primary replica is unknown. + + +[caption=""] +.Returns +`int64_t` + +[#_driver_options_get_request_timeout_millis] +==== function ``driver_options_get_request_timeout_millis`` + +[source,c] +---- +int64_t driver_options_get_request_timeout_millis(const struct DriverOptions* options) +---- + + + +Returns the request timeout in milliseconds set for this ``DriverOptions`` object. Specifies the maximum time to wait for a response to a unary RPC request. This applies to operations like database creation, user management, and initial transaction opening. It does NOT apply to operations within transactions (queries, commits). + +[caption=""] +.Returns +`int64_t` + +[#_driver_options_get_tls_config] +==== function ``driver_options_get_tls_config`` + +[source,c] +---- +struct DriverTlsConfig* driver_options_get_tls_config(const struct DriverOptions* options) +---- + + + +Returns the TLS Config set for this ``DriverOptions`` object. Specifies the TLS configuration of the connection to TypeDB. + +[caption=""] +.Returns +`struct DriverTlsConfig*` + +[#_driver_options_get_use_replication] +==== function ``driver_options_get_use_replication`` + +[source,c] +---- +bool driver_options_get_use_replication(const struct DriverOptions* options) +---- + + + +Returns the value set for the replication usage flag in this ``DriverOptions`` object. Specifies whether the connection to TypeDB can use cluster replicas provided by the server or it should be limited to a single configured address. + +[caption=""] +.Returns +`bool` + +[#_driver_options_has_replica_discovery_attempts] +==== function ``driver_options_has_replica_discovery_attempts`` + +[source,c] +---- +bool driver_options_has_replica_discovery_attempts(const struct DriverOptions* options) +---- + + + +Checks whether the replica discovery attempts limit was explicitly set for this ``DriverOptions`` object. + +[caption=""] +.Returns +`bool` + +[#_driver_options_new] +==== function ``driver_options_new`` + +[source,c] +---- +struct DriverOptions* driver_options_new(const struct DriverTlsConfig* tls_config) +---- + + + +Creates a new ``DriverOptions`` for connecting to TypeDB Server using custom TLS settings. WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + +[caption=""] +.Returns +`struct DriverOptions*` + +[#_driver_options_set_primary_failover_retries] +==== function ``driver_options_set_primary_failover_retries`` + +[source,c] +---- +void driver_options_set_primary_failover_retries(struct DriverOptions* options, int64_t primary_failover_retries) +---- + + + +Limits the number of attempts to redirect a strongly consistent request to another primary replica in case of a failure due to the change of replica roles. Defaults to 1. + +[caption=""] +.Returns +`void` + +[#_driver_options_set_replica_discovery_attempts] +==== function ``driver_options_set_replica_discovery_attempts`` + +[source,c] +---- +void driver_options_set_replica_discovery_attempts(struct DriverOptions* options, int64_t replica_discovery_attempts) +---- + + + +Limits the number of driver attempts to discover a single working replica to perform an operation in case of a replica unavailability. Every replica is tested once, which means that at most: + + {limit} operations are performed if the limit <= the number of replicas. + {number of replicas} operations are performed if the limit > the number of replicas. + {number of replicas} operations are performed if the limit is None. Affects every eventually consistent operation, including redirect failover, when the new primary replica is unknown. If not set, the maximum (practically unlimited) value is used. + + +[caption=""] +.Returns +`void` + +[#_driver_options_set_request_timeout_millis] +==== function ``driver_options_set_request_timeout_millis`` + +[source,c] +---- +void driver_options_set_request_timeout_millis(struct DriverOptions* options, int64_t timeout_millis) +---- + + + +Sets the maximum time (in milliseconds) to wait for a response to a unary RPC request. This applies to operations like database creation, user management, and initial transaction opening. It does NOT apply to operations within transactions (queries, commits). Set to 0 to disable the timeout (not recommended for production use). Defaults to 2 hours (7200000 milliseconds). + +[caption=""] +.Returns +`void` + +[#_driver_options_set_tls_config] +==== function ``driver_options_set_tls_config`` + +[source,c] +---- +void driver_options_set_tls_config(struct DriverOptions* options, const struct DriverTlsConfig* tls_config) +---- + + + +Overrides the TLS configuration on ``DriverOptions``. WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. + +[caption=""] +.Returns +`void` + +[#_driver_options_set_use_replication] +==== function ``driver_options_set_use_replication`` + +[source,c] +---- +void driver_options_set_use_replication(struct DriverOptions* options, bool use_replication) +---- + + + +Specifies whether the connection to TypeDB can use cluster replicas provided by the server or it should be limited to a single configured address. Defaults to true. + +[caption=""] +.Returns +`void` diff --git a/docs/modules/ROOT/partials/c/connection/replicarole.adoc b/docs/modules/ROOT/partials/c/connection/replicarole.adoc new file mode 100644 index 0000000000..dd27b1680e --- /dev/null +++ b/docs/modules/ROOT/partials/c/connection/replicarole.adoc @@ -0,0 +1,36 @@ +[#_methods_connection_replicarole] +=== replicarole + +[#_Struct_ReplicaRole] +[.doc-api-reference-driver] +==== Struct ReplicaRole + +`rust struct (pointer)` + + + +This enum is used to specify the type of replica. + +[#_Enum_ReplicaRole] +[.doc-api-reference-driver] +==== Enum ReplicaRole + +`rust enum (pointer)` + + + +This enum is used to specify the type of replica. + +[caption=""] +.Enum constants +// tag::enum_constants[] +[cols=""] +[options="header"] +|=== +|Name +a| `Candidate` +a| `Primary` +a| `Secondary` +|=== +// end::enum_constants[] + diff --git a/docs/modules/ROOT/partials/c/connection/serverreplica.adoc b/docs/modules/ROOT/partials/c/connection/serverreplica.adoc new file mode 100644 index 0000000000..cc4fb22024 --- /dev/null +++ b/docs/modules/ROOT/partials/c/connection/serverreplica.adoc @@ -0,0 +1,141 @@ +[#_methods_connection_serverreplica] +=== serverreplica + +[#_Struct_ServerReplica] +[.doc-api-reference-driver] +==== Struct ServerReplica + +`rust struct (pointer)` + + + +The metadata and state of an individual raft replica of a driver connection. + +[#_server_replica_drop] +==== function ``server_replica_drop`` + +[source,c] +---- +void server_replica_drop(struct ServerReplica* replica_info) +---- + + + +Frees the native rust ``ServerReplica`` object. + +[caption=""] +.Returns +`void` + +[#_server_replica_get_address] +==== function ``server_replica_get_address`` + +[source,c] +---- +char* server_replica_get_address(const struct ServerReplica* replica_info) +---- + + + +Returns the address this replica is hosted at. + +[caption=""] +.Returns +`char*` + +[#_server_replica_get_id] +==== function ``server_replica_get_id`` + +[source,c] +---- +int64_t server_replica_get_id(const struct ServerReplica* replica_info) +---- + + + +Returns the id of this replica. + +[caption=""] +.Returns +`int64_t` + +[#_server_replica_get_role] +==== function ``server_replica_get_role`` + +[source,c] +---- +enum ReplicaRole server_replica_get_role(const struct ServerReplica* replica_info) +---- + + + +Returns whether this is the primary replica of the raft cluster or any of the supporting roles. + +[caption=""] +.Returns +`enum ReplicaRole` + +[#_server_replica_get_term] +==== function ``server_replica_get_term`` + +[source,c] +---- +int64_t server_replica_get_term(const struct ServerReplica* replica_info) +---- + + + +Returns the raft protocol ‘term’ of this replica. + +[caption=""] +.Returns +`int64_t` + +[#_server_replica_has_role] +==== function ``server_replica_has_role`` + +[source,c] +---- +bool server_replica_has_role(const struct ServerReplica* replica_info) +---- + + + +Returns whether the role of this replica is set. + +[caption=""] +.Returns +`bool` + +[#_server_replica_has_term] +==== function ``server_replica_has_term`` + +[source,c] +---- +bool server_replica_has_term(const struct ServerReplica* replica_info) +---- + + + +Returns whether the raft protocol ‘term’ of this replica exists. + +[caption=""] +.Returns +`bool` + +[#_server_replica_is_primary] +==== function ``server_replica_is_primary`` + +[source,c] +---- +bool server_replica_is_primary(const struct ServerReplica* replica_info) +---- + + + +Checks whether this is the primary replica of the raft cluster. + +[caption=""] +.Returns +`bool` + diff --git a/docs/modules/ROOT/partials/c/connection/serverreplicaiterator.adoc b/docs/modules/ROOT/partials/c/connection/serverreplicaiterator.adoc new file mode 100644 index 0000000000..834e4cf275 --- /dev/null +++ b/docs/modules/ROOT/partials/c/connection/serverreplicaiterator.adoc @@ -0,0 +1,45 @@ +[#_methods_connection_serverreplicaiterator] +=== serverreplicaiterator + +[#_Struct_ServerReplicaIterator] +[.doc-api-reference-driver] +==== Struct ServerReplicaIterator + +`rust struct (pointer)` + + + +Iterator over the ``ServerReplica`` corresponding to each replica of a TypeDB cluster. + +[#_server_replica_iterator_drop] +==== function ``server_replica_iterator_drop`` + +[source,c] +---- +void server_replica_iterator_drop(struct ServerReplicaIterator* it) +---- + + + +Frees the native rust ``ServerReplicaIterator`` object. + +[caption=""] +.Returns +`void` + +[#_server_replica_iterator_next] +==== function ``server_replica_iterator_next`` + +[source,c] +---- +struct ServerReplica* server_replica_iterator_next(struct ServerReplicaIterator* it) +---- + + + +Forwards the ``ServerReplicaIterator`` and returns the next ``ServerReplica`` if it exists, or null if there are no more elements. + +[caption=""] +.Returns +`struct ServerReplica*` + diff --git a/docs/modules/ROOT/partials/c/connection/serverversion.adoc b/docs/modules/ROOT/partials/c/connection/serverversion.adoc new file mode 100644 index 0000000000..f970fbcea6 --- /dev/null +++ b/docs/modules/ROOT/partials/c/connection/serverversion.adoc @@ -0,0 +1,29 @@ +[#_methods_connection_serverversion] +=== serverversion + +[#_Struct_ServerVersion] +[.doc-api-reference-driver] +==== Struct ServerVersion + +`rust struct (pointer)` + + + +``ServerVersion`` is an FFI representation of a full server's version specification. + +[#_server_version_drop] +==== function ``server_version_drop`` + +[source,c] +---- +void server_version_drop(struct ServerVersion* server_version) +---- + + + +Frees the native rust ``ServerVersion`` object + +[caption=""] +.Returns +`void` + diff --git a/docs/modules/ROOT/partials/c/connection/user.adoc b/docs/modules/ROOT/partials/c/connection/user.adoc index 2211b3bd05..50b1c953de 100644 --- a/docs/modules/ROOT/partials/c/connection/user.adoc +++ b/docs/modules/ROOT/partials/c/connection/user.adoc @@ -6,12 +6,23 @@ [source,c] ---- -void user_delete(struct User* user) +void user_delete(struct User* user, const struct ConsistencyLevel* consistency_level) ---- -Deletes this database. +Deletes this user. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `user` a| The ``User`` to delete. a| `struct User*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== [caption=""] .Returns @@ -54,7 +65,7 @@ Returns the name of this user. [source,c] ---- -void user_update_password(struct User* user, const char* password) +void user_update_password(struct User* user, const char* password, const struct ConsistencyLevel* consistency_level) ---- @@ -70,8 +81,9 @@ Updates the password for the current authenticated user. |Name |Description |Type a| `user` a| The user to update the password of - must be the current user. a| `struct User*` a| `user_manager` a| The ``UserManager`` object on this connection. a| -a| `password_old` a| The current password of this user a| -a| `password_new` a| The new password a| +a| `password_old` a| The current password of this user. a| +a| `password_new` a| The new password. a| +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` |=== [caption=""] diff --git a/docs/modules/ROOT/partials/c/connection/useriterator.adoc b/docs/modules/ROOT/partials/c/connection/useriterator.adoc index 58ebd01ca5..cdc480342e 100644 --- a/docs/modules/ROOT/partials/c/connection/useriterator.adoc +++ b/docs/modules/ROOT/partials/c/connection/useriterator.adoc @@ -9,7 +9,7 @@ -Iterator over a set of ``User``s +Iterator over a set of ``User``s. [#_user_iterator_drop] ==== function ``user_iterator_drop`` @@ -21,7 +21,7 @@ void user_iterator_drop(struct UserIterator* it) -Frees the native rust ``UserIterator`` object +Frees the native rust ``UserIterator`` object. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/connection/users.adoc b/docs/modules/ROOT/partials/c/connection/users.adoc index b939830696..a1075bdfaf 100644 --- a/docs/modules/ROOT/partials/c/connection/users.adoc +++ b/docs/modules/ROOT/partials/c/connection/users.adoc @@ -6,13 +6,24 @@ [source,c] ---- -struct UserIterator* users_all(const struct TypeDBDriver* driver) +struct UserIterator* users_all(const struct TypeDBDriver* driver, const struct ConsistencyLevel* consistency_level) ---- Retrieves all users which exist on the TypeDB server. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `const struct TypeDBDriver*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== + [caption=""] .Returns `struct UserIterator*` @@ -22,13 +33,25 @@ Retrieves all users which exist on the TypeDB server. [source,c] ---- -bool users_contains(const struct TypeDBDriver* driver, const char* username) +bool users_contains(const struct TypeDBDriver* driver, const char* username, const struct ConsistencyLevel* consistency_level) ---- Checks if a user with the given name exists. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `const struct TypeDBDriver*` +a| `username` a| The username of the user. a| `const char*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== + [caption=""] .Returns `bool` @@ -38,13 +61,25 @@ Checks if a user with the given name exists. [source,c] ---- -void users_create(const struct TypeDBDriver* driver, const char* username, const char* password) +void users_create(const struct TypeDBDriver* driver, const char* username, const char* password, const struct ConsistencyLevel* consistency_level) ---- Creates a user with the given name & password. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `username` a| The username of the created user. a| `const char*` +a| `password` a| The password of the created user. a| `const char*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== + [caption=""] .Returns `void` @@ -54,28 +89,51 @@ Creates a user with the given name & password. [source,c] ---- -struct User* users_get(const struct TypeDBDriver* driver, const char* username) +struct User* users_get(const struct TypeDBDriver* driver, const char* username, const struct ConsistencyLevel* consistency_level) ---- Retrieves a user with the given name. + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `const struct TypeDBDriver*` +a| `username` a| The username of the user. a| `const char*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== + [caption=""] .Returns `struct User*` -[#_users_get_current_user] -==== function ``users_get_current_user`` +[#_users_get_current] +==== function ``users_get_current`` [source,c] ---- -struct User* users_get_current_user(const struct TypeDBDriver* driver) +struct User* users_get_current(const struct TypeDBDriver* driver, const struct ConsistencyLevel* consistency_level) ---- -Retrieves the username of the user who opened this connection +Retrieves the username of the user who opened this connection. + + +[caption=""] +.Input parameters +[cols=",,"] +[options="header"] +|=== +|Name |Description |Type +a| `driver` a| The ``TypeDBDriver`` object. a| `const struct TypeDBDriver*` +a| `consistency_level` a| The consistency level to use for the operation. Strongest possible if null. a| `const struct ConsistencyLevel*` +|=== [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/transaction/queryoptions.adoc b/docs/modules/ROOT/partials/c/transaction/queryoptions.adoc index 08cc1cb0ba..1699c0c59d 100644 --- a/docs/modules/ROOT/partials/c/transaction/queryoptions.adoc +++ b/docs/modules/ROOT/partials/c/transaction/queryoptions.adoc @@ -9,7 +9,7 @@ -TypeDB query options. ``QueryOptions`` object can be used to override the default server behaviour for executed queries. +TypeDB query options. QueryOptions object can be used to override the default server behaviour for executed queries. [#_query_options_drop] @@ -150,7 +150,7 @@ void query_options_set_include_instance_types(struct QueryOptions* options, bool -Explicitly set the "include instance types" flag. If set, specifies if types should be included in instance structs returned in ConceptRow answers. This option allows reducing the amount of unnecessary data transmitted. +Explicitly setsthe "include instance types" flag. If set, specifies if types should be included in instance structs returned in ConceptRow answers. This option allows reducing the amount of unnecessary data transmitted. [caption=""] .Returns @@ -182,7 +182,7 @@ void query_options_set_prefetch_size(struct QueryOptions* options, int64_t prefe -Explicitly set the prefetch size. If set, specifies the number of extra query responses sent before the client side has to re-request more responses. Increasing this may increase performance for queries with a huge number of answers, as it can reduce the number of network round-trips at the cost of more resources on the server side. Minimal value: 1. +Explicitly setsthe prefetch size. If set, specifies the number of extra query responses sent before the client side has to re-request more responses. Increasing this may increase performance for queries with a huge number of answers, as it can reduce the number of network round-trips at the cost of more resources on the server side. Minimal value: 1. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/transaction/transaction.adoc b/docs/modules/ROOT/partials/c/transaction/transaction.adoc index 698ff57a3d..88aa8c556c 100644 --- a/docs/modules/ROOT/partials/c/transaction/transaction.adoc +++ b/docs/modules/ROOT/partials/c/transaction/transaction.adoc @@ -120,7 +120,7 @@ a| `options` a| ``TransactionOptions`` to configure the opened transaction. a| ` [source,c] ---- -struct VoidPromise* transaction_on_close(const struct Transaction* txn, uintptr_t callback_id, void(*)(uintptr_t, struct Error*) callback) +struct VoidPromise* transaction_on_close(const struct Transaction* txn, uintptr_t callback_id, void(* callback)(uintptr_t, struct Error*)) ---- @@ -136,7 +136,7 @@ Registers a callback function which will be executed when this transaction is cl |Name |Description |Type a| `txn` a| The transaction on which to register the callback a| `const struct Transaction*` a| `callback_id` a| The argument to be passed to the callback function when it is executed. a| `uintptr_t` -a| `callback` a| The function to be called a| +a| `callback` a| The function to be called a| `void(*` |=== [caption=""] diff --git a/docs/modules/ROOT/partials/c/transaction/transactionoptions.adoc b/docs/modules/ROOT/partials/c/transaction/transactionoptions.adoc index 19810be3ee..054a03054b 100644 --- a/docs/modules/ROOT/partials/c/transaction/transactionoptions.adoc +++ b/docs/modules/ROOT/partials/c/transaction/transactionoptions.adoc @@ -9,7 +9,7 @@ -TypeDB transaction options. ``TransactionOptions`` object can be used to override the default server behaviour for opened transactions. +TypeDB transaction options. TransactionOptions object can be used to override the default behaviour for opened transactions. [#_transaction_options_drop] @@ -28,6 +28,22 @@ Frees the native Rust ``TransactionOptions`` object. .Returns `void` +[#_transaction_options_get_read_consistency_level] +==== function ``transaction_options_get_read_consistency_level`` + +[source,c] +---- +struct ConsistencyLevel* transaction_options_get_read_consistency_level(const struct TransactionOptions* options) +---- + + + +Returns the value set for the read consistency level in this ``TransactionOptions`` object. If set, specifies the requested consistency level of the transaction opening operation. Affects only read transactions, as write and schema transactions require primary replicas. + +[caption=""] +.Returns +`struct ConsistencyLevel*` + [#_transaction_options_get_schema_lock_acquire_timeout_millis] ==== function ``transaction_options_get_schema_lock_acquire_timeout_millis`` @@ -60,6 +76,22 @@ Returns the value set for the transaction timeout in this ``TransactionOptions`` .Returns `int64_t` +[#_transaction_options_has_read_consistency_level] +==== function ``transaction_options_has_read_consistency_level`` + +[source,c] +---- +bool transaction_options_has_read_consistency_level(const struct TransactionOptions* options) +---- + + + +Checks whether the option for read consistency level was explicitly set for this ``TransactionOptions`` object. + +[caption=""] +.Returns +`bool` + [#_transaction_options_has_schema_lock_acquire_timeout_millis] ==== function ``transaction_options_has_schema_lock_acquire_timeout_millis`` @@ -108,6 +140,22 @@ Produces a new ``TransactionOptions`` object. .Returns `struct TransactionOptions*` +[#_transaction_options_set_read_consistency_level] +==== function ``transaction_options_set_read_consistency_level`` + +[source,c] +---- +void transaction_options_set_read_consistency_level(struct TransactionOptions* options, const struct ConsistencyLevel* read_consistency_level) +---- + + + +Explicitly sets read consistency level. If set, specifies the requested consistency level of the transaction opening operation. Affects only read transactions, as write and schema transactions require primary replicas. + +[caption=""] +.Returns +`void` + [#_transaction_options_set_schema_lock_acquire_timeout_millis] ==== function ``transaction_options_set_schema_lock_acquire_timeout_millis`` @@ -134,7 +182,7 @@ void transaction_options_set_transaction_timeout_millis(struct TransactionOption -Explicitly set a transaction timeout. If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. +Explicitly sets a transaction timeout. If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/http-ts/connection/Server.adoc b/docs/modules/ROOT/partials/http-ts/connection/Server.adoc index 065417054a..71131cecd4 100644 --- a/docs/modules/ROOT/partials/http-ts/connection/Server.adoc +++ b/docs/modules/ROOT/partials/http-ts/connection/Server.adoc @@ -1,6 +1,9 @@ [#_Server] +[.doc-api-reference-driver] === Server +`class` + [caption=""] .Fields // tag::properties[] diff --git a/docs/modules/ROOT/partials/http-ts/connection/TypeDBHttpDriver.adoc b/docs/modules/ROOT/partials/http-ts/connection/TypeDBHttpDriver.adoc index 4bd0c741c0..22ce403923 100644 --- a/docs/modules/ROOT/partials/http-ts/connection/TypeDBHttpDriver.adoc +++ b/docs/modules/ROOT/partials/http-ts/connection/TypeDBHttpDriver.adoc @@ -290,7 +290,7 @@ getDatabases(): Promise> `Promise>` [#_TypeDBHttpDriver_getServers_] -==== getServers +==== method ``getServers`` [source,typescript] ---- diff --git a/docs/modules/ROOT/partials/http-ts/response/ServersListResponse.adoc b/docs/modules/ROOT/partials/http-ts/response/ServersListResponse.adoc index f5d4d8831b..d20626fb1f 100644 --- a/docs/modules/ROOT/partials/http-ts/response/ServersListResponse.adoc +++ b/docs/modules/ROOT/partials/http-ts/response/ServersListResponse.adoc @@ -1,6 +1,9 @@ [#_ServersListResponse] +[.doc-api-reference-driver] === ServersListResponse +`class` + [caption=""] .Fields // tag::properties[] diff --git a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Eventual.adoc b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Eventual.adoc index 652c20cd14..2f32e9ecde 100644 --- a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Eventual.adoc +++ b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Eventual.adoc @@ -1,13 +1,16 @@ [#_ConsistencyLevel_Eventual] +[.doc-api-reference-driver] === ConsistencyLevel.Eventual +`class` + *Package*: `com.typedb.driver.api` Eventual consistency level. Allow stale reads from any replica and execution orchestration through a non-primary replica. Does not guarantee latest writes, but is eventually faster compared to other consistency levels. Note that the target replica can redirect the request, if needed. // tag::methods[] [#_ConsistencyLevel_Eventual_Eventual_] -==== Eventual +==== method ``Eventual`` [source,java] ---- @@ -21,7 +24,7 @@ public Eventual() `public` [#_ConsistencyLevel_Eventual_nativeValue_] -==== nativeValue +==== method ``nativeValue`` [source,java] ---- @@ -35,7 +38,7 @@ public com.typedb.driver.jni.ConsistencyLevel nativeValue() `public com.typedb.driver.jni.ConsistencyLevel` [#_ConsistencyLevel_Eventual_nativeValue_ConsistencyLevel] -==== nativeValue +==== method ``nativeValue`` [source,java] ---- @@ -49,7 +52,7 @@ public static com.typedb.driver.jni.ConsistencyLevel nativeValue​(ConsistencyL `public static com.typedb.driver.jni.ConsistencyLevel` [#_ConsistencyLevel_Eventual_of_com_typedb_driver_jni_ConsistencyLevel] -==== of +==== method ``of`` [source,java] ---- @@ -63,7 +66,7 @@ public static ConsistencyLevel of​(com.typedb.driver.jni.ConsistencyLevel nati `public static ConsistencyLevel` [#_ConsistencyLevel_Eventual_toString_] -==== toString +==== method ``toString`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.ReplicaDependent.adoc b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.ReplicaDependent.adoc index 06b76e32ac..e5d8747e62 100644 --- a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.ReplicaDependent.adoc +++ b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.ReplicaDependent.adoc @@ -1,13 +1,16 @@ [#_ConsistencyLevel_ReplicaDependent] +[.doc-api-reference-driver] === ConsistencyLevel.ReplicaDependent +`class` + *Package*: `com.typedb.driver.api` Replica dependent consistency level. The operation is executed against the provided replica address only. Its guarantees depend on the replica selected. Note that the target replica can redirect the request, if needed. // tag::methods[] [#_ConsistencyLevel_ReplicaDependent_ReplicaDependent_java_lang_String] -==== ReplicaDependent +==== method ``ReplicaDependent`` [source,java] ---- @@ -21,7 +24,7 @@ public ReplicaDependent​(java.lang.String address) `public` [#_ConsistencyLevel_ReplicaDependent_getAddress_] -==== getAddress +==== method ``getAddress`` [source,java] ---- @@ -35,7 +38,7 @@ Retrieves the address of the replica this consistency level depends on. `public java.lang.String` [#_ConsistencyLevel_ReplicaDependent_nativeValue_] -==== nativeValue +==== method ``nativeValue`` [source,java] ---- @@ -49,7 +52,7 @@ public com.typedb.driver.jni.ConsistencyLevel nativeValue() `public com.typedb.driver.jni.ConsistencyLevel` [#_ConsistencyLevel_ReplicaDependent_nativeValue_ConsistencyLevel] -==== nativeValue +==== method ``nativeValue`` [source,java] ---- @@ -63,7 +66,7 @@ public static com.typedb.driver.jni.ConsistencyLevel nativeValue​(ConsistencyL `public static com.typedb.driver.jni.ConsistencyLevel` [#_ConsistencyLevel_ReplicaDependent_of_com_typedb_driver_jni_ConsistencyLevel] -==== of +==== method ``of`` [source,java] ---- @@ -77,7 +80,7 @@ public static ConsistencyLevel of​(com.typedb.driver.jni.ConsistencyLevel nati `public static ConsistencyLevel` [#_ConsistencyLevel_ReplicaDependent_toString_] -==== toString +==== method ``toString`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Strong.adoc b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Strong.adoc index 9d0e9dfa4b..ecd3ef660b 100644 --- a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Strong.adoc +++ b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.Strong.adoc @@ -1,13 +1,16 @@ [#_ConsistencyLevel_Strong] +[.doc-api-reference-driver] === ConsistencyLevel.Strong +`class` + *Package*: `com.typedb.driver.api` Strong consistency level. Strongest consistency, always up-to-date due to the guarantee of the primary replica usage. May require more time for operation execution. // tag::methods[] [#_ConsistencyLevel_Strong_Strong_] -==== Strong +==== method ``Strong`` [source,java] ---- @@ -21,7 +24,7 @@ public Strong() `public` [#_ConsistencyLevel_Strong_nativeValue_] -==== nativeValue +==== method ``nativeValue`` [source,java] ---- @@ -35,7 +38,7 @@ public com.typedb.driver.jni.ConsistencyLevel nativeValue() `public com.typedb.driver.jni.ConsistencyLevel` [#_ConsistencyLevel_Strong_nativeValue_ConsistencyLevel] -==== nativeValue +==== method ``nativeValue`` [source,java] ---- @@ -49,7 +52,7 @@ public static com.typedb.driver.jni.ConsistencyLevel nativeValue​(ConsistencyL `public static com.typedb.driver.jni.ConsistencyLevel` [#_ConsistencyLevel_Strong_of_com_typedb_driver_jni_ConsistencyLevel] -==== of +==== method ``of`` [source,java] ---- @@ -63,7 +66,7 @@ public static ConsistencyLevel of​(com.typedb.driver.jni.ConsistencyLevel nati `public static ConsistencyLevel` [#_ConsistencyLevel_Strong_toString_] -==== toString +==== method ``toString`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.adoc b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.adoc index acb4c4c788..8860a8f986 100644 --- a/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.adoc +++ b/docs/modules/ROOT/partials/java/connection/ConsistencyLevel.adoc @@ -1,13 +1,16 @@ [#_ConsistencyLevel] +[.doc-api-reference-driver] === ConsistencyLevel +`class` + *Package*: `com.typedb.driver.api` Consistency levels of operations against a distributed server. All driver methods have default recommended values, however, most of the operations can be configured in order to potentially speed up the execution (introducing risks of stale data) or test a specific replica. This setting does not affect clusters with a single node. // tag::methods[] [#_ConsistencyLevel_ConsistencyLevel_] -==== ConsistencyLevel +==== method ``ConsistencyLevel`` [source,java] ---- @@ -21,7 +24,7 @@ public ConsistencyLevel() `public` [#_ConsistencyLevel_nativeValue_] -==== nativeValue +==== method ``nativeValue`` [source,java] ---- @@ -35,7 +38,7 @@ public abstract com.typedb.driver.jni.ConsistencyLevel nativeValue() `public abstract com.typedb.driver.jni.ConsistencyLevel` [#_ConsistencyLevel_nativeValue_ConsistencyLevel] -==== nativeValue +==== method ``nativeValue`` [source,java] ---- @@ -49,7 +52,7 @@ public static com.typedb.driver.jni.ConsistencyLevel nativeValue​(ConsistencyL `public static com.typedb.driver.jni.ConsistencyLevel` [#_ConsistencyLevel_of_com_typedb_driver_jni_ConsistencyLevel] -==== of +==== method ``of`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/Database.adoc b/docs/modules/ROOT/partials/java/connection/Database.adoc index 9c0202f746..995faf8d45 100644 --- a/docs/modules/ROOT/partials/java/connection/Database.adoc +++ b/docs/modules/ROOT/partials/java/connection/Database.adoc @@ -31,7 +31,7 @@ database.delete() ---- [#_Database_delete_ConsistencyLevel] -==== delete +==== method ``delete`` [source,java] ---- @@ -97,7 +97,7 @@ database.exportToFile("schema.typeql", "data.typedb") ---- [#_Database_exportToFile_java_lang_String_java_lang_String_ConsistencyLevel] -==== exportToFile +==== method ``exportToFile`` [source,java] ---- @@ -180,7 +180,7 @@ database.schema() ---- [#_Database_schema_ConsistencyLevel] -==== schema +==== method ``schema`` [source,java] ---- @@ -237,7 +237,7 @@ database.typeSchema() ---- [#_Database_typeSchema_ConsistencyLevel] -==== typeSchema +==== method ``typeSchema`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/DatabaseManager.adoc b/docs/modules/ROOT/partials/java/connection/DatabaseManager.adoc index d447871da8..735b942437 100644 --- a/docs/modules/ROOT/partials/java/connection/DatabaseManager.adoc +++ b/docs/modules/ROOT/partials/java/connection/DatabaseManager.adoc @@ -34,7 +34,7 @@ driver.databases().all() ---- [#_DatabaseManager_all_ConsistencyLevel] -==== all +==== method ``all`` [source,java] ---- @@ -100,7 +100,7 @@ driver.databases().contains(name) ---- [#_DatabaseManager_contains_java_lang_String_ConsistencyLevel] -==== contains +==== method ``contains`` [source,java] ---- @@ -167,7 +167,7 @@ driver.databases().create(name) ---- [#_DatabaseManager_create_java_lang_String_ConsistencyLevel] -==== create +==== method ``create`` [source,java] ---- @@ -234,7 +234,7 @@ driver.databases().get(name) ---- [#_DatabaseManager_get_java_lang_String_ConsistencyLevel] -==== get +==== method ``get`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/Driver.adoc b/docs/modules/ROOT/partials/java/connection/Driver.adoc index b07b956411..35ac4bb15f 100644 --- a/docs/modules/ROOT/partials/java/connection/Driver.adoc +++ b/docs/modules/ROOT/partials/java/connection/Driver.adoc @@ -68,7 +68,7 @@ driver.databases(); ---- [#_Driver_deregisterReplica_long] -==== deregisterReplica +==== method ``deregisterReplica`` [source,java] ---- @@ -122,7 +122,7 @@ driver.isOpen(); ---- [#_Driver_primaryReplica_] -==== primaryReplica +==== method ``primaryReplica`` [source,java] ---- @@ -145,7 +145,7 @@ driver.primaryReplica(); ---- [#_Driver_primaryReplica_ConsistencyLevel] -==== primaryReplica +==== method ``primaryReplica`` [source,java] ---- @@ -177,7 +177,7 @@ driver.primaryReplica(new ConsistencyLevel.Strong()); ---- [#_Driver_registerReplica_long_java_lang_String] -==== registerReplica +==== method ``registerReplica`` [source,java] ---- @@ -210,7 +210,7 @@ driver.registerReplica(2, "127.0.0.1:11729"); ---- [#_Driver_replicas_] -==== replicas +==== method ``replicas`` [source,java] ---- @@ -233,7 +233,7 @@ driver.replicas(); ---- [#_Driver_replicas_ConsistencyLevel] -==== replicas +==== method ``replicas`` [source,java] ---- @@ -265,7 +265,7 @@ driver.replicas(new ConsistencyLevel.Strong()); ---- [#_Driver_serverVersion_] -==== serverVersion +==== method ``serverVersion`` [source,java] ---- @@ -288,7 +288,7 @@ driver.serverVersion(); ---- [#_Driver_serverVersion_ConsistencyLevel] -==== serverVersion +==== method ``serverVersion`` [source,java] ---- @@ -391,7 +391,7 @@ driver.transaction(database, sessionType); ---- [#_Driver_updateAddressTranslation_java_util_Map_java_lang_String_​java_lang_String_] -==== updateAddressTranslation +==== method ``updateAddressTranslation`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/DriverOptions.adoc b/docs/modules/ROOT/partials/java/connection/DriverOptions.adoc index ffb115545d..f5647c55f9 100644 --- a/docs/modules/ROOT/partials/java/connection/DriverOptions.adoc +++ b/docs/modules/ROOT/partials/java/connection/DriverOptions.adoc @@ -1,13 +1,16 @@ [#_DriverOptions] +[.doc-api-reference-driver] === DriverOptions +`class` + *Package*: `com.typedb.driver.api` TypeDB driver options. ``DriverOptions`` are used to specify the driver's connection behavior. // tag::methods[] [#_DriverOptions_DriverOptions_DriverTlsConfig] -==== DriverOptions +==== method ``DriverOptions`` [source,java] ---- @@ -29,7 +32,7 @@ DriverOptions options = new DriverOptions(DriverTlsConfig.enabledWithNativeRootC ---- [#_DriverOptions_primaryFailoverRetries_] -==== primaryFailoverRetries +==== method ``primaryFailoverRetries`` [source,java] ---- @@ -52,7 +55,7 @@ options.primaryFailoverRetries(); ---- [#_DriverOptions_primaryFailoverRetries_int] -==== primaryFailoverRetries +==== method ``primaryFailoverRetries`` [source,java] ---- @@ -83,7 +86,7 @@ options.primaryFailoverRetries(1); ---- [#_DriverOptions_replicaDiscoveryAttempts_] -==== replicaDiscoveryAttempts +==== method ``replicaDiscoveryAttempts`` [source,java] ---- @@ -106,7 +109,7 @@ options.replicaDiscoveryAttempts(); ---- [#_DriverOptions_replicaDiscoveryAttempts_int] -==== replicaDiscoveryAttempts +==== method ``replicaDiscoveryAttempts`` [source,java] ---- @@ -137,7 +140,7 @@ options.primaryFailoverRetries(1); ---- [#_DriverOptions_requestTimeoutMillis_] -==== requestTimeoutMillis +==== method ``requestTimeoutMillis`` [source,java] ---- @@ -160,7 +163,7 @@ options.requestTimeoutMillis(); ---- [#_DriverOptions_requestTimeoutMillis_long] -==== requestTimeoutMillis +==== method ``requestTimeoutMillis`` [source,java] ---- @@ -191,7 +194,7 @@ options.requestTimeoutMillis(30000); // 30 seconds ---- [#_DriverOptions_tlsConfig_] -==== tlsConfig +==== method ``tlsConfig`` [source,java] ---- @@ -214,7 +217,7 @@ options.tlsConfig(); ---- [#_DriverOptions_tlsConfig_DriverTlsConfig] -==== tlsConfig +==== method ``tlsConfig`` [source,java] ---- @@ -236,7 +239,7 @@ options.tlsConfig(DriverTlsConfig.enabledWithNativeRootCA()); ---- [#_DriverOptions_useReplication_] -==== useReplication +==== method ``useReplication`` [source,java] ---- @@ -259,7 +262,7 @@ options.useReplication(); ---- [#_DriverOptions_useReplication_boolean] -==== useReplication +==== method ``useReplication`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/DriverTlsConfig.adoc b/docs/modules/ROOT/partials/java/connection/DriverTlsConfig.adoc index 6a885f7285..4811b69d04 100644 --- a/docs/modules/ROOT/partials/java/connection/DriverTlsConfig.adoc +++ b/docs/modules/ROOT/partials/java/connection/DriverTlsConfig.adoc @@ -1,6 +1,9 @@ [#_DriverTlsConfig] +[.doc-api-reference-driver] === DriverTlsConfig +`class` + *Package*: `com.typedb.driver.api` TLS configuration for the TypeDB driver. ``DriverTlsConfig`` represents a fully constructed and validated TLS configuration. If TLS is enabled, the underlying TLS config is built eagerly at construction time, ensuring that no connection attempt can observe a partially-configured TLS state. @@ -9,7 +12,7 @@ The driver defaults to using TLS with native system trust roots. This matches ty // tag::methods[] [#_DriverTlsConfig_DriverTlsConfig_com_typedb_driver_jni_DriverTlsConfig] -==== DriverTlsConfig +==== method ``DriverTlsConfig`` [source,java] ---- @@ -23,7 +26,7 @@ protected DriverTlsConfig​(com.typedb.driver.jni.DriverTlsConfig nativeObject) `protected` [#_DriverTlsConfig_disabled_] -==== disabled +==== method ``disabled`` [source,java] ---- @@ -46,7 +49,7 @@ DriverTlsConfig tlsConfig = DriverTlsConfig.disabled(); ---- [#_DriverTlsConfig_enabledWithNativeRootCA_] -==== enabledWithNativeRootCA +==== method ``enabledWithNativeRootCA`` [source,java] ---- @@ -69,7 +72,7 @@ DriverTlsConfig tlsConfig = DriverTlsConfig.enabledWithNativeRootCA(); ---- [#_DriverTlsConfig_enabledWithRootCA_java_lang_String] -==== enabledWithRootCA +==== method ``enabledWithRootCA`` [source,java] ---- @@ -100,7 +103,7 @@ Examples `public static DriverTlsConfig` [#_DriverTlsConfig_isEnabled_] -==== isEnabled +==== method ``isEnabled`` [source,java] ---- @@ -123,7 +126,7 @@ tlsConfig.isEnabled(); ---- [#_DriverTlsConfig_rootCAPath_] -==== rootCAPath +==== method ``rootCAPath`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/ReplicaRole.adoc b/docs/modules/ROOT/partials/java/connection/ReplicaRole.adoc index b040253dcc..30e270baf7 100644 --- a/docs/modules/ROOT/partials/java/connection/ReplicaRole.adoc +++ b/docs/modules/ROOT/partials/java/connection/ReplicaRole.adoc @@ -1,6 +1,9 @@ [#_ReplicaRole] +[.doc-api-reference-driver] === ReplicaRole +`class` + *Package*: `com.typedb.driver.api.server` This enum is used to specify the type of replica. @@ -27,7 +30,7 @@ a| `SECONDARY` // tag::methods[] [#_ReplicaRole_id_] -==== id +==== method ``id`` [source,java] ---- @@ -41,7 +44,7 @@ public int id() `public int` [#_ReplicaRole_isCandidate_] -==== isCandidate +==== method ``isCandidate`` [source,java] ---- @@ -55,7 +58,7 @@ Checks whether this is a candidate replica of the raft cluster. `public boolean` [#_ReplicaRole_isPrimary_] -==== isPrimary +==== method ``isPrimary`` [source,java] ---- @@ -69,7 +72,7 @@ Checks whether this is the primary replica of the raft cluster. `public boolean` [#_ReplicaRole_isSecondary_] -==== isSecondary +==== method ``isSecondary`` [source,java] ---- @@ -83,7 +86,7 @@ Checks whether this is a secondary replica of the raft cluster. `public boolean` [#_ReplicaRole_of_com_typedb_driver_jni_ReplicaRole] -==== of +==== method ``of`` [source,java] ---- @@ -97,7 +100,7 @@ public static ReplicaRole of​(com.typedb.driver.jni.ReplicaRole nativeType) `public static ReplicaRole` [#_ReplicaRole_valueOf_java_lang_String] -==== valueOf +==== method ``valueOf`` [source,java] ---- @@ -120,7 +123,7 @@ a| `name` a| the name of the enum constant to be returned. a| `java.lang.String` `public static ReplicaRole` [#_ReplicaRole_values_] -==== values +==== method ``values`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/ServerReplica.adoc b/docs/modules/ROOT/partials/java/connection/ServerReplica.adoc index 19b17e21f2..639fade75d 100644 --- a/docs/modules/ROOT/partials/java/connection/ServerReplica.adoc +++ b/docs/modules/ROOT/partials/java/connection/ServerReplica.adoc @@ -1,13 +1,16 @@ [#_ServerReplica] +[.doc-api-reference-driver] === ServerReplica +`class` + *Package*: `com.typedb.driver.api.server` The metadata and state of an individual raft replica of a driver connection. // tag::methods[] [#_ServerReplica_getAddress_] -==== getAddress +==== method ``getAddress`` [source,java] ---- @@ -22,7 +25,7 @@ Returns the address this replica is hosted at. `java.lang.String` [#_ServerReplica_getID_] -==== getID +==== method ``getID`` [source,java] ---- @@ -37,7 +40,7 @@ Returns the id of this replica. `long` [#_ServerReplica_getRole_] -==== getRole +==== method ``getRole`` [source,java] ---- @@ -52,7 +55,7 @@ Returns whether this is the primary replica of the raft cluster or any of the su `java.util.Optional` [#_ServerReplica_getTerm_] -==== getTerm +==== method ``getTerm`` [source,java] ---- @@ -67,7 +70,7 @@ Returns the raft protocol ‘term’ of this replica. `java.util.Optional` [#_ServerReplica_isPrimary_] -==== isPrimary +==== method ``isPrimary`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/ServerVersion.adoc b/docs/modules/ROOT/partials/java/connection/ServerVersion.adoc index 17b8e25def..d62e0bcb67 100644 --- a/docs/modules/ROOT/partials/java/connection/ServerVersion.adoc +++ b/docs/modules/ROOT/partials/java/connection/ServerVersion.adoc @@ -1,6 +1,9 @@ [#_ServerVersion] +[.doc-api-reference-driver] === ServerVersion +`class` + *Package*: `com.typedb.driver.api.server` A full TypeDB server's version specification. @@ -15,7 +18,7 @@ driver.serverVersion(); // tag::methods[] [#_ServerVersion_getDistribution_] -==== getDistribution +==== method ``getDistribution`` [source,java] ---- @@ -37,7 +40,7 @@ serverVersion.getDistribution(); ---- [#_ServerVersion_getVersion_] -==== getVersion +==== method ``getVersion`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/TypeDB.adoc b/docs/modules/ROOT/partials/java/connection/TypeDB.adoc index ad9d8361d9..4cde27087a 100644 --- a/docs/modules/ROOT/partials/java/connection/TypeDB.adoc +++ b/docs/modules/ROOT/partials/java/connection/TypeDB.adoc @@ -69,7 +69,7 @@ TypeDB.driver(address); ---- [#_TypeDB_driver_java_util_Set_java_lang_String_Credentials_DriverOptions] -==== driver +==== method ``driver`` [source,java] ---- @@ -105,7 +105,7 @@ TypeDB.driver(address); ---- [#_TypeDB_driver_java_util_Map_java_lang_String_​java_lang_String_Credentials_DriverOptions] -==== driver +==== method ``driver`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/User.adoc b/docs/modules/ROOT/partials/java/connection/User.adoc index ac16c86db9..3a44a1b3d6 100644 --- a/docs/modules/ROOT/partials/java/connection/User.adoc +++ b/docs/modules/ROOT/partials/java/connection/User.adoc @@ -32,7 +32,7 @@ user.delete(); ---- [#_User_delete_ConsistencyLevel] -==== delete +==== method ``delete`` [source,java] ---- @@ -109,7 +109,7 @@ user.updatePassword("new-password"); ---- [#_User_updatePassword_java_lang_String_ConsistencyLevel] -==== updatePassword +==== method ``updatePassword`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/connection/UserManager.adoc b/docs/modules/ROOT/partials/java/connection/UserManager.adoc index e6292d7b2c..3bea0ac8de 100644 --- a/docs/modules/ROOT/partials/java/connection/UserManager.adoc +++ b/docs/modules/ROOT/partials/java/connection/UserManager.adoc @@ -1,13 +1,16 @@ [#_UserManager] +[.doc-api-reference-driver] === UserManager +`class` + *Package*: `com.typedb.driver.api.user` Provides access to all user management methods. // tag::methods[] [#_UserManager_all_] -==== all +==== method ``all`` [source,java] ---- @@ -30,7 +33,7 @@ driver.users().all(); ---- [#_UserManager_all_ConsistencyLevel] -==== all +==== method ``all`` [source,java] ---- @@ -62,7 +65,7 @@ driver.users().all(new ConsistencyLevel.Strong()); ---- [#_UserManager_contains_java_lang_String] -==== contains +==== method ``contains`` [source,java] ---- @@ -95,7 +98,7 @@ driver.users().contains(username); ---- [#_UserManager_contains_java_lang_String_ConsistencyLevel] -==== contains +==== method ``contains`` [source,java] ---- @@ -130,7 +133,7 @@ driver.users().contains(username, new ConsistencyLevel.Strong()); ---- [#_UserManager_create_java_lang_String_java_lang_String] -==== create +==== method ``create`` [source,java] ---- @@ -164,7 +167,7 @@ driver.users().create(username, password); ---- [#_UserManager_create_java_lang_String_java_lang_String_ConsistencyLevel] -==== create +==== method ``create`` [source,java] ---- @@ -200,7 +203,7 @@ driver.users().create(username, password, new ConsistencyLevel.Strong()); ---- [#_UserManager_get_java_lang_String] -==== get +==== method ``get`` [source,java] ---- @@ -233,7 +236,7 @@ driver.users().get(username); ---- [#_UserManager_get_java_lang_String_ConsistencyLevel] -==== get +==== method ``get`` [source,java] ---- @@ -268,7 +271,7 @@ driver.users().get(username, new ConsistencyLevel.Strong()); ---- [#_UserManager_getCurrent_] -==== getCurrent +==== method ``getCurrent`` [source,java] ---- @@ -292,7 +295,7 @@ driver.users().getCurrent(); ---- [#_UserManager_getCurrent_ConsistencyLevel] -==== getCurrent +==== method ``getCurrent`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/java/transaction/TransactionOptions.adoc b/docs/modules/ROOT/partials/java/transaction/TransactionOptions.adoc index a9161f553b..0071c10048 100644 --- a/docs/modules/ROOT/partials/java/transaction/TransactionOptions.adoc +++ b/docs/modules/ROOT/partials/java/transaction/TransactionOptions.adoc @@ -32,7 +32,7 @@ TransactionOptions options = TransactionOptions(); ---- [#_TransactionOptions_readConsistencyLevel_] -==== readConsistencyLevel +==== method ``readConsistencyLevel`` [source,java] ---- @@ -54,7 +54,7 @@ options.readConsistencyLevel(); ---- [#_TransactionOptions_readConsistencyLevel_ConsistencyLevel] -==== readConsistencyLevel +==== method ``readConsistencyLevel`` [source,java] ---- diff --git a/docs/modules/ROOT/partials/python/connection/ConsistencyLevel.adoc b/docs/modules/ROOT/partials/python/connection/ConsistencyLevel.adoc index 17690c18b7..da2f905a80 100644 --- a/docs/modules/ROOT/partials/python/connection/ConsistencyLevel.adoc +++ b/docs/modules/ROOT/partials/python/connection/ConsistencyLevel.adoc @@ -1,13 +1,16 @@ [#_ConsistencyLevel] +[.doc-api-reference-driver] === ConsistencyLevel +`class` + *Package*: `typedb.api.connection.consistency_level` Consistency levels of operations against a distributed server. All driver methods have default recommended values, however, most of the operations can be configured in order to potentially speed up the execution (introducing risks of stale data) or test a specific replica. This setting does not affect clusters with a single node. // tag::methods[] [#_ConsistencyLevel_is_eventual_] -==== is_eventual +==== method ``is_eventual`` [source,python] ---- @@ -21,7 +24,7 @@ is_eventual() -> bool `bool` [#_ConsistencyLevel_is_replica_dependent_] -==== is_replica_dependent +==== method ``is_replica_dependent`` [source,python] ---- @@ -35,7 +38,7 @@ is_replica_dependent() -> bool `bool` [#_ConsistencyLevel_is_strong_] -==== is_strong +==== method ``is_strong`` [source,python] ---- @@ -49,7 +52,7 @@ is_strong() -> bool `bool` [#_ConsistencyLevel_native_value_] -==== native_value +==== method ``native_value`` [source,python] ---- @@ -63,7 +66,7 @@ static native_value(consistency_level: ConsistencyLevel | None) -> ConsistencyLe `ConsistencyLevel` [#_ConsistencyLevel_of_] -==== of +==== method ``of`` [source,python] ---- diff --git a/docs/modules/ROOT/partials/python/connection/Database.adoc b/docs/modules/ROOT/partials/python/connection/Database.adoc index f85b779f06..0e27b27a77 100644 --- a/docs/modules/ROOT/partials/python/connection/Database.adoc +++ b/docs/modules/ROOT/partials/python/connection/Database.adoc @@ -1,6 +1,9 @@ [#_Database] +[.doc-api-reference-driver] === Database +`class` + *Package*: `typedb.api.database.database` [caption=""] @@ -16,7 +19,7 @@ a| `name` a| `str` a| The database name as a string. // tag::methods[] [#_Database_delete_consistency_level_ConsistencyLevel_None] -==== delete +==== method ``delete`` [source,python] ---- @@ -47,7 +50,7 @@ database.delete(ConsistencyLevel.Strong()) ---- [#_Database_export_to_file_schema_file_path_str_data_file_path_str_consistency_level_ConsistencyLevel_None] -==== export_to_file +==== method ``export_to_file`` [source,python] ---- @@ -80,7 +83,7 @@ database.export_to_file("schema.typeql", "data.typedb", ConsistencyLevel.Strong( ---- [#_Database_schema_consistency_level_ConsistencyLevel_None] -==== schema +==== method ``schema`` [source,python] ---- @@ -111,7 +114,7 @@ database.schema(ConsistencyLevel.Strong()) ---- [#_Database_type_schema_consistency_level_ConsistencyLevel_None] -==== type_schema +==== method ``type_schema`` [source,python] ---- diff --git a/docs/modules/ROOT/partials/python/connection/DatabaseManager.adoc b/docs/modules/ROOT/partials/python/connection/DatabaseManager.adoc index ce964e454c..51130bbc5c 100644 --- a/docs/modules/ROOT/partials/python/connection/DatabaseManager.adoc +++ b/docs/modules/ROOT/partials/python/connection/DatabaseManager.adoc @@ -1,13 +1,16 @@ [#_DatabaseManager] +[.doc-api-reference-driver] === DatabaseManager +`class` + *Package*: `typedb.api.database.database_manager` Provides access to all database management methods. // tag::methods[] [#_DatabaseManager_all_consistency_level_ConsistencyLevel_None] -==== all +==== method ``all`` [source,python] ---- @@ -38,7 +41,7 @@ driver.databases.all(ConsistencyLevel.Strong()) ---- [#_DatabaseManager_contains_name_str_consistency_level_ConsistencyLevel_None] -==== contains +==== method ``contains`` [source,python] ---- @@ -70,7 +73,7 @@ driver.databases.contains(name, ConsistencyLevel.Strong()) ---- [#_DatabaseManager_create_name_str_consistency_level_ConsistencyLevel_None] -==== create +==== method ``create`` [source,python] ---- @@ -102,7 +105,7 @@ driver.databases.create(name, ConsistencyLevel.Strong()) ---- [#_DatabaseManager_get_name_str_consistency_level_ConsistencyLevel_None] -==== get +==== method ``get`` [source,python] ---- @@ -134,7 +137,7 @@ driver.databases.get(name, ConsistencyLevel.Strong()) ---- [#_DatabaseManager_import_from_file_name_str_schema_str_data_file_path_str] -==== import_from_file +==== method ``import_from_file`` [source,python] ---- diff --git a/docs/modules/ROOT/partials/python/connection/Driver.adoc b/docs/modules/ROOT/partials/python/connection/Driver.adoc index bce8f88d53..8dbfe6f12e 100644 --- a/docs/modules/ROOT/partials/python/connection/Driver.adoc +++ b/docs/modules/ROOT/partials/python/connection/Driver.adoc @@ -41,7 +41,7 @@ driver.close() ---- [#_Driver_deregister_replica_replica_id_int] -==== deregister_replica +==== method ``deregister_replica`` [source,python] ---- @@ -92,7 +92,7 @@ driver.is_open() ---- [#_Driver_primary_replica_consistency_level_ConsistencyLevel_None] -==== primary_replica +==== method ``primary_replica`` [source,python] ---- @@ -123,7 +123,7 @@ driver.primary_replica(ConsistencyLevel.Strong()) ---- [#_Driver_register_replica_replica_id_int_address_str] -==== register_replica +==== method ``register_replica`` [source,python] ---- @@ -154,7 +154,7 @@ driver.register_replica(2, "127.0.0.1:11729") ---- [#_Driver_replicas_consistency_level_ConsistencyLevel_None] -==== replicas +==== method ``replicas`` [source,python] ---- @@ -185,7 +185,7 @@ driver.replicas(ConsistencyLevel.Strong()) ---- [#_Driver_server_version_consistency_level_ConsistencyLevel_None] -==== server_version +==== method ``server_version`` [source,python] ---- @@ -248,7 +248,7 @@ driver.transaction(database, transaction_type, options) ---- [#_Driver_update_address_translation_address_translation_Mapping_str_str_] -==== update_address_translation +==== method ``update_address_translation`` [source,python] ---- diff --git a/docs/modules/ROOT/partials/python/connection/DriverTlsConfig.adoc b/docs/modules/ROOT/partials/python/connection/DriverTlsConfig.adoc index bd77bbc9c0..54500893f5 100644 --- a/docs/modules/ROOT/partials/python/connection/DriverTlsConfig.adoc +++ b/docs/modules/ROOT/partials/python/connection/DriverTlsConfig.adoc @@ -1,6 +1,9 @@ [#_DriverTlsConfig] +[.doc-api-reference-driver] === DriverTlsConfig +`class` + *Package*: `typedb.api.connection.driver_tls_config` TLS configuration for the TypeDB driver. @@ -23,7 +26,7 @@ a| `root_ca_path` a| `str \| None` a| Returns the configured custom root CA path // tag::methods[] [#_DriverTlsConfig_disabled_] -==== disabled +==== method ``disabled`` [source,python] ---- @@ -44,7 +47,7 @@ tls_config = DriverTlsConfig.disabled() ---- [#_DriverTlsConfig_enabled_with_native_root_ca_] -==== enabled_with_native_root_ca +==== method ``enabled_with_native_root_ca`` [source,python] ---- @@ -65,7 +68,7 @@ tls_config = DriverTlsConfig.enabled_with_native_root_ca() ---- [#_DriverTlsConfig_enabled_with_root_ca_tls_root_ca_path_str] -==== enabled_with_root_ca +==== method ``enabled_with_root_ca`` [source,python] ---- diff --git a/docs/modules/ROOT/partials/python/connection/Eventual.adoc b/docs/modules/ROOT/partials/python/connection/Eventual.adoc index 586934c0e2..83335c21ee 100644 --- a/docs/modules/ROOT/partials/python/connection/Eventual.adoc +++ b/docs/modules/ROOT/partials/python/connection/Eventual.adoc @@ -1,6 +1,9 @@ [#_Eventual] +[.doc-api-reference-driver] === Eventual +`class` + *Package*: `typedb.api.connection.consistency_level` *Supertypes:* diff --git a/docs/modules/ROOT/partials/python/connection/ReplicaDependent.adoc b/docs/modules/ROOT/partials/python/connection/ReplicaDependent.adoc index 44fcdf5311..b4126d3a7b 100644 --- a/docs/modules/ROOT/partials/python/connection/ReplicaDependent.adoc +++ b/docs/modules/ROOT/partials/python/connection/ReplicaDependent.adoc @@ -1,6 +1,9 @@ [#_ReplicaDependent] +[.doc-api-reference-driver] === ReplicaDependent +`class` + *Package*: `typedb.api.connection.consistency_level` *Supertypes:* diff --git a/docs/modules/ROOT/partials/python/connection/ReplicaRole.adoc b/docs/modules/ROOT/partials/python/connection/ReplicaRole.adoc index f6d6c6325d..65e0effc1e 100644 --- a/docs/modules/ROOT/partials/python/connection/ReplicaRole.adoc +++ b/docs/modules/ROOT/partials/python/connection/ReplicaRole.adoc @@ -1,6 +1,9 @@ [#_ReplicaRole] +[.doc-api-reference-driver] === ReplicaRole +`class` + *Package*: `typedb.api.server.replica_role` This class is used to specify the type of replica. @@ -27,7 +30,7 @@ a| `SECONDARY` a| `2` // tag::methods[] [#_ReplicaRole_is_candidate_] -==== is_candidate +==== method ``is_candidate`` [source,python] ---- @@ -41,7 +44,7 @@ is_candidate() -> bool `bool` [#_ReplicaRole_is_primary_] -==== is_primary +==== method ``is_primary`` [source,python] ---- @@ -55,7 +58,7 @@ is_primary() -> bool `bool` [#_ReplicaRole_is_secondary_] -==== is_secondary +==== method ``is_secondary`` [source,python] ---- diff --git a/docs/modules/ROOT/partials/python/connection/ServerReplica.adoc b/docs/modules/ROOT/partials/python/connection/ServerReplica.adoc index 24e2958e12..aa070ac034 100644 --- a/docs/modules/ROOT/partials/python/connection/ServerReplica.adoc +++ b/docs/modules/ROOT/partials/python/connection/ServerReplica.adoc @@ -1,6 +1,9 @@ [#_ServerReplica] +[.doc-api-reference-driver] === ServerReplica +`class` + *Package*: `typedb.api.server.server_replica` The metadata and state of an individual raft replica of a driver connection. @@ -21,7 +24,7 @@ a| `term` a| `int` a| Returns the raft protocol ‘term’ of this replica. // tag::methods[] [#_ServerReplica_is_primary_] -==== is_primary +==== method ``is_primary`` [source,python] ---- diff --git a/docs/modules/ROOT/partials/python/connection/ServerVersion.adoc b/docs/modules/ROOT/partials/python/connection/ServerVersion.adoc index 3427a63baf..b4f6a0554d 100644 --- a/docs/modules/ROOT/partials/python/connection/ServerVersion.adoc +++ b/docs/modules/ROOT/partials/python/connection/ServerVersion.adoc @@ -1,6 +1,9 @@ [#_ServerVersion] +[.doc-api-reference-driver] === ServerVersion +`class` + *Package*: `typedb.api.server.server_version` A full TypeDB server’s version specification. diff --git a/docs/modules/ROOT/partials/python/connection/Strong.adoc b/docs/modules/ROOT/partials/python/connection/Strong.adoc index 4b09a9684f..98a31b8a59 100644 --- a/docs/modules/ROOT/partials/python/connection/Strong.adoc +++ b/docs/modules/ROOT/partials/python/connection/Strong.adoc @@ -1,6 +1,9 @@ [#_Strong] +[.doc-api-reference-driver] === Strong +`class` + *Package*: `typedb.api.connection.consistency_level` *Supertypes:* diff --git a/docs/modules/ROOT/partials/python/connection/TypeDB.adoc b/docs/modules/ROOT/partials/python/connection/TypeDB.adoc index e5d7b3b14c..8c9fac549f 100644 --- a/docs/modules/ROOT/partials/python/connection/TypeDB.adoc +++ b/docs/modules/ROOT/partials/python/connection/TypeDB.adoc @@ -1,11 +1,14 @@ [#_TypeDB] +[.doc-api-reference-driver] === TypeDB +`class` + *Package*: `typedb.driver` // tag::methods[] [#_TypeDB_driver_addresses_Mapping_str_str_Iterable_str_str] -==== driver +==== method ``driver`` [source,python] ---- diff --git a/docs/modules/ROOT/partials/python/connection/User.adoc b/docs/modules/ROOT/partials/python/connection/User.adoc index e776bdee1f..aba2ca90d4 100644 --- a/docs/modules/ROOT/partials/python/connection/User.adoc +++ b/docs/modules/ROOT/partials/python/connection/User.adoc @@ -1,6 +1,9 @@ [#_User] +[.doc-api-reference-driver] === User +`class` + *Package*: `typedb.api.user.user` TypeDB user information @@ -18,7 +21,7 @@ a| `name` a| `str` a| Returns the name of this user. // tag::methods[] [#_User_delete_consistency_level_ConsistencyLevel_None] -==== delete +==== method ``delete`` [source,python] ---- @@ -49,7 +52,7 @@ user.delete(ConsistencyLevel.Strong()) ---- [#_User_update_password_password_str_consistency_level_ConsistencyLevel_None] -==== update_password +==== method ``update_password`` [source,python] ---- diff --git a/docs/modules/ROOT/partials/python/connection/UserManager.adoc b/docs/modules/ROOT/partials/python/connection/UserManager.adoc index 872e3bf248..3f3718f3fc 100644 --- a/docs/modules/ROOT/partials/python/connection/UserManager.adoc +++ b/docs/modules/ROOT/partials/python/connection/UserManager.adoc @@ -1,13 +1,16 @@ [#_UserManager] +[.doc-api-reference-driver] === UserManager +`class` + *Package*: `typedb.api.user.user_manager` Provides access to all user management methods. // tag::methods[] [#_UserManager_all_consistency_level_ConsistencyLevel_None] -==== all +==== method ``all`` [source,python] ---- @@ -38,7 +41,7 @@ driver.users.all(ConsistencyLevel.Strong()) ---- [#_UserManager_contains_username_str_consistency_level_ConsistencyLevel_None] -==== contains +==== method ``contains`` [source,python] ---- @@ -70,7 +73,7 @@ driver.users.contains(username, ConsistencyLevel.Strong()) ---- [#_UserManager_create_username_str_password_str_consistency_level_ConsistencyLevel_None] -==== create +==== method ``create`` [source,python] ---- @@ -103,7 +106,7 @@ driver.users.create(username, password, ConsistencyLevel.Strong()) ---- [#_UserManager_get_username_str_consistency_level_ConsistencyLevel_None] -==== get +==== method ``get`` [source,python] ---- @@ -135,7 +138,7 @@ driver.users.get(username, ConsistencyLevel.Strong()) ---- [#_UserManager_get_current_consistency_level_ConsistencyLevel_None] -==== get_current +==== method ``get_current`` [source,python] ---- diff --git a/docs/modules/ROOT/partials/rust/connection/Address.adoc b/docs/modules/ROOT/partials/rust/connection/Address.adoc index 1613501d34..c0fa2fd58b 100644 --- a/docs/modules/ROOT/partials/rust/connection/Address.adoc +++ b/docs/modules/ROOT/partials/rust/connection/Address.adoc @@ -1,6 +1,9 @@ [#_struct_Address] +[.doc-api-reference-driver] === Address +`struct` + *Implements traits:* * `Clone` diff --git a/docs/modules/ROOT/partials/rust/connection/Addresses.adoc b/docs/modules/ROOT/partials/rust/connection/Addresses.adoc index c77f300d74..49ff424dcc 100644 --- a/docs/modules/ROOT/partials/rust/connection/Addresses.adoc +++ b/docs/modules/ROOT/partials/rust/connection/Addresses.adoc @@ -1,6 +1,9 @@ [#_enum_Addresses] +[.doc-api-reference-driver] === Addresses +`enum` + A collection of server addresses used for connection. [caption=""] diff --git a/docs/modules/ROOT/partials/rust/connection/AvailableServerReplica.adoc b/docs/modules/ROOT/partials/rust/connection/AvailableServerReplica.adoc index 453e4f4834..d18eb54fc6 100644 --- a/docs/modules/ROOT/partials/rust/connection/AvailableServerReplica.adoc +++ b/docs/modules/ROOT/partials/rust/connection/AvailableServerReplica.adoc @@ -1,6 +1,9 @@ [#_struct_AvailableServerReplica] +[.doc-api-reference-driver] === AvailableServerReplica +`struct` + *Implements traits:* * `Clone` diff --git a/docs/modules/ROOT/partials/rust/connection/ConsistencyLevel.adoc b/docs/modules/ROOT/partials/rust/connection/ConsistencyLevel.adoc index fa19329bab..ff4d85af67 100644 --- a/docs/modules/ROOT/partials/rust/connection/ConsistencyLevel.adoc +++ b/docs/modules/ROOT/partials/rust/connection/ConsistencyLevel.adoc @@ -1,6 +1,9 @@ [#_enum_ConsistencyLevel] +[.doc-api-reference-driver] === ConsistencyLevel +`enum` + Consistency levels of operations against a distributed server. All driver methods have default recommended values, however, most of the operations can be configured in order to potentially speed up the execution (introducing risks of stale data) or test a specific replica. This setting does not affect clusters with a single node. [caption=""] diff --git a/docs/modules/ROOT/partials/rust/connection/DriverTlsConfig.adoc b/docs/modules/ROOT/partials/rust/connection/DriverTlsConfig.adoc index 320cc350a5..288b6cd37c 100644 --- a/docs/modules/ROOT/partials/rust/connection/DriverTlsConfig.adoc +++ b/docs/modules/ROOT/partials/rust/connection/DriverTlsConfig.adoc @@ -1,6 +1,9 @@ [#_struct_DriverTlsConfig] +[.doc-api-reference-driver] === DriverTlsConfig +`struct` + *Implements traits:* * `Clone` diff --git a/docs/modules/ROOT/partials/rust/connection/ReplicaInfo.adoc b/docs/modules/ROOT/partials/rust/connection/ReplicaInfo.adoc deleted file mode 100644 index badd5d5748..0000000000 --- a/docs/modules/ROOT/partials/rust/connection/ReplicaInfo.adoc +++ /dev/null @@ -1,26 +0,0 @@ -[#_struct_ReplicaInfo] -[.doc-api-reference-driver] -=== ReplicaInfo - -`struct` - -*Implements traits:* - -* `Debug` - -The metadata and state of an individual raft replica of a database. - -[caption=""] -.Fields -// tag::properties[] -[cols=",,"] -[options="header"] -|=== -|Name |Type |Description -a| `is_preferred` a| `bool` a| Whether this is the preferred replica of the raft cluster. If true, Operations which can be run on any replica will prefer to use this replica. -a| `is_primary` a| `bool` a| Whether this is the primary replica of the raft cluster. -a| `server` a| `Address` a| The server hosting this replica -a| `term` a| `i64` a| The raft protocol ‘term’ of this replica. -|=== -// end::properties[] - diff --git a/docs/modules/ROOT/partials/rust/connection/ReplicaRole.adoc b/docs/modules/ROOT/partials/rust/connection/ReplicaRole.adoc index b26bd431ee..9e0d88d669 100644 --- a/docs/modules/ROOT/partials/rust/connection/ReplicaRole.adoc +++ b/docs/modules/ROOT/partials/rust/connection/ReplicaRole.adoc @@ -1,6 +1,9 @@ [#_enum_ReplicaRole] +[.doc-api-reference-driver] === ReplicaRole +`enum` + This enum is used to specify the type of replica. [caption=""] diff --git a/docs/modules/ROOT/partials/rust/connection/ServerReplica.adoc b/docs/modules/ROOT/partials/rust/connection/ServerReplica.adoc index d106e4ebaf..8e7c98468c 100644 --- a/docs/modules/ROOT/partials/rust/connection/ServerReplica.adoc +++ b/docs/modules/ROOT/partials/rust/connection/ServerReplica.adoc @@ -1,6 +1,9 @@ [#_enum_ServerReplica] +[.doc-api-reference-driver] === ServerReplica +`enum` + The metadata and state of an individual raft replica of a driver connection. [caption=""] diff --git a/docs/modules/ROOT/partials/rust/connection/ServerVersion.adoc b/docs/modules/ROOT/partials/rust/connection/ServerVersion.adoc index 916ffbce46..b57ef1ce25 100644 --- a/docs/modules/ROOT/partials/rust/connection/ServerVersion.adoc +++ b/docs/modules/ROOT/partials/rust/connection/ServerVersion.adoc @@ -1,6 +1,9 @@ [#_struct_ServerVersion] +[.doc-api-reference-driver] === ServerVersion +`struct` + *Implements traits:* * `Clone` diff --git a/docs/modules/ROOT/partials/rust/connection/Trait_Replica.adoc b/docs/modules/ROOT/partials/rust/connection/Trait_Replica.adoc index e5020d8d8a..92efaa16d0 100644 --- a/docs/modules/ROOT/partials/rust/connection/Trait_Replica.adoc +++ b/docs/modules/ROOT/partials/rust/connection/Trait_Replica.adoc @@ -1,6 +1,9 @@ [#_trait_Replica] +[.doc-api-reference-driver] === Trait Replica +`struct` + *Implementors:* * `AvailableServerReplica` diff --git a/rust/BUILD b/rust/BUILD index 7830648315..947cd174fd 100644 --- a/rust/BUILD +++ b/rust/BUILD @@ -137,16 +137,6 @@ update_markdown_example( removed_header = "//", ) -rust_library( - name = "driver-example-lib", - srcs = ["example.rs"], - deps = [ - ":typedb_driver", - "@crates//:async-std", - "@crates//:futures", - ], -) - checkstyle_test( name = "checkstyle", size = "small", diff --git a/rust/Cargo.lock b/rust/Cargo.lock deleted file mode 100644 index d56b9e189e..0000000000 --- a/rust/Cargo.lock +++ /dev/null @@ -1,2861 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" - -[[package]] -name = "anstyle-parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "anstyle-wincon" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" -dependencies = [ - "anstyle", - "windows-sys 0.48.0", -] - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "async-attributes" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-executor" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" -dependencies = [ - "async-lock", - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" -dependencies = [ - "async-lock", - "autocfg", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-global-executor" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" -dependencies = [ - "async-channel", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "once_cell", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite", - "log", - "parking", - "polling", - "rustix 0.37.23", - "slab", - "socket2 0.4.9", - "waker-fn", -] - -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-net" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f" -dependencies = [ - "async-io", - "autocfg", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-process" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" -dependencies = [ - "async-io", - "async-lock", - "autocfg", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix 0.37.23", - "signal-hook", - "windows-sys 0.48.0", -] - -[[package]] -name = "async-std" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" -dependencies = [ - "async-attributes", - "async-channel", - "async-global-executor", - "async-io", - "async-lock", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.37", -] - -[[package]] -name = "async-task" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" - -[[package]] -name = "async-trait" -version = "0.1.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.37", -] - -[[package]] -name = "atomic-waker" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blocking" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" -dependencies = [ - "async-channel", - "async-lock", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "log", -] - -[[package]] -name = "bstr" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -[[package]] -name = "bytecount" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cc" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87d9d13be47a5b7c3907137f1290b0459a7f80efb26be8c52afb11963bccb02" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "time", - "wasm-bindgen", - "windows-targets 0.48.5", -] - -[[package]] -name = "clap" -version = "4.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", - "terminal_size", -] - -[[package]] -name = "clap_derive" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.37", -] - -[[package]] -name = "clap_lex" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "concurrent-queue" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "console" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "unicode-width", - "windows-sys 0.45.0", -] - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "cpufeatures" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cucumber" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a845da7c9fb958144700201d22e3f61f55114f9e269c13f03fe179d9da500984" -dependencies = [ - "anyhow", - "async-trait", - "atty", - "clap", - "console", - "cucumber-codegen", - "cucumber-expressions", - "derive_more", - "drain_filter_polyfill", - "either", - "futures", - "gherkin", - "globwalk", - "humantime", - "inventory", - "itertools", - "linked-hash-map", - "once_cell", - "regex", - "sealed 0.4.0", - "smart-default", -] - -[[package]] -name = "cucumber-codegen" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dfb841fe8742f57fbe94738a189022e7dc858f2560c7fba5da44dc945a139e1" -dependencies = [ - "cucumber-expressions", - "inflections", - "itertools", - "proc-macro2", - "quote", - "regex", - "syn 1.0.109", - "synthez", -] - -[[package]] -name = "cucumber-expressions" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40d2fdf5e1bb4ae7e6b25c97bf9b9d249a02243fc0fbd91075592b5f00a3bc1" -dependencies = [ - "derive_more", - "either", - "nom", - "nom_locate", - "regex", - "regex-syntax 0.6.29", -] - -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.2", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "drain_filter_polyfill" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", - "num_cpus", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.37", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "gherkin" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8f8f49b2b547ec22cc4d99f3bf30d4889ef0dbaa231c0736eeaf20efb5a38e" -dependencies = [ - "heck 0.4.1", - "peg", - "quote", - "serde", - "serde_json", - "syn 1.0.109", - "textwrap", - "thiserror", - "typed-builder", -] - -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - -[[package]] -name = "globset" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "globwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" -dependencies = [ - "bitflags 1.3.2", - "ignore", - "walkdir", -] - -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "h2" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 1.9.3", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "hyper" -version = "0.14.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.4.9", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ignore" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" -dependencies = [ - "globset", - "lazy_static", - "log", - "memchr", - "regex", - "same-file", - "thread_local", - "walkdir", - "winapi-util", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown 0.14.2", -] - -[[package]] -name = "inflections" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "inventory" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1be380c410bf0595e94992a648ea89db4dd3f3354ba54af206fd2a68cf5ac8e" - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.3", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "js-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" - -[[package]] -name = "lock_api" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -dependencies = [ - "value-bag", -] - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "maybe-async" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "memchr" -version = "2.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nom_locate" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e3c83c053b0713da60c5b8de47fe8e494fe3ece5267b2f23090a07a053ba8f3" -dependencies = [ - "bytecount", - "memchr", - "nom", -] - -[[package]] -name = "num-traits" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.3", - "libc", -] - -[[package]] -name = "object" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "parking" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "peg" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f76678828272f177ac33b7e2ac2e3e73cc6c1cd1e3e387928aa69562fa51367" -dependencies = [ - "peg-macros", - "peg-runtime", -] - -[[package]] -name = "peg-macros" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "636d60acf97633e48d266d7415a9355d4389cea327a193f87df395d88cd2b14d" -dependencies = [ - "peg-runtime", - "proc-macro2", - "quote", -] - -[[package]] -name = "peg-runtime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555b1514d2d99d78150d3c799d4c357a3e2c2a8062cd108e93a06d9057629c5" - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pest" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" -dependencies = [ - "memchr", - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.37", -] - -[[package]] -name = "pest_meta" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - -[[package]] -name = "pin-project" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.37", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "regex" -version = "1.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.7.5", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustix" -version = "0.37.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" -dependencies = [ - "bitflags 2.4.0", - "errno", - "libc", - "linux-raw-sys 0.4.7", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustls" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" -dependencies = [ - "log", - "ring", - "sct", - "webpki", -] - -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" -dependencies = [ - "base64 0.21.4", -] - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "sealed" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "636b9882a0f4cc2039488df89a10eb4b7976d4b6c1917fc0518f3f0f5e2c72ca" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "sealed" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b5e421024b5e5edfbaa8e60ecf90bda9dbffc602dbb230e6028763f85f0c68c" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.37", -] - -[[package]] -name = "serde_json" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" -dependencies = [ - "indexmap 2.1.0", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serial_test" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92761393ee4dc3ff8f4af487bd58f4307c9329bbedea02cac0089ad9c411e153" -dependencies = [ - "dashmap", - "futures", - "lazy_static", - "log", - "parking_lot", - "serial_test_derive", -] - -[[package]] -name = "serial_test_derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6f5d1c3087fb119617cff2966fe3808a80e5eb59a8c1601d5994d66f4346a5" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "sha2" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "smart-default" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "smawk" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" - -[[package]] -name = "smol" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1" -dependencies = [ - "async-channel", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-net", - "async-process", - "blocking", - "futures-lite", -] - -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "synthez" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033178d0acccffc5490021657006e6a8dd586ee9dc6f7c24e7608b125e568cb1" -dependencies = [ - "syn 1.0.109", - "synthez-codegen", - "synthez-core", -] - -[[package]] -name = "synthez-codegen" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69263462a40e46960f070618e20094ce69e783a41f86e54bc75545136afd597a" -dependencies = [ - "syn 1.0.109", - "synthez-core", -] - -[[package]] -name = "synthez-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb8b5a4089fe1723279f06302afda64a5dacaa11a82bcbb4d08759590d4389d9" -dependencies = [ - "proc-macro2", - "quote", - "sealed 0.3.0", - "syn 1.0.109", -] - -[[package]] -name = "terminal_size" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" -dependencies = [ - "rustix 0.38.14", - "windows-sys 0.48.0", -] - -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" -dependencies = [ - "smawk", - "unicode-linebreak", - "unicode-width", -] - -[[package]] -name = "thiserror" -version = "1.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.37", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "tokio" -version = "1.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.5.7", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-macros" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.37", -] - -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls", - "tokio", - "webpki", -] - -[[package]] -name = "tokio-stream" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tonic" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.13.1", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "prost-derive", - "rustls-native-certs", - "rustls-pemfile", - "tokio", - "tokio-rustls", - "tokio-stream", - "tokio-util", - "tower", - "tower-layer", - "tower-service", - "tracing", - "tracing-futures", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.37", -] - -[[package]] -name = "tracing-core" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "typed-builder" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "typedb-driver" -version = "0.0.0" -dependencies = [ - "async-std", - "chrono", - "crossbeam", - "cucumber", - "futures", - "http", - "itertools", - "log", - "maybe-async", - "prost", - "regex", - "serde_json", - "serial_test", - "smol", - "tokio", - "tokio-stream", - "tonic", - "typedb-protocol", - "typeql", - "uuid", -] - -[[package]] -name = "typedb-protocol" -version = "0.0.0" -dependencies = [ - "prost", - "tonic", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "typeql" -version = "0.0.0" -dependencies = [ - "chrono", - "itertools", - "pest", - "pest_derive", - "regex", -] - -[[package]] -name = "ucd-trie" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "uuid" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" -dependencies = [ - "getrandom", - "rand", - "serde", -] - -[[package]] -name = "value-bag" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92ccd67fb88503048c01b59152a04effd0782d035a83a6d256ce6085f08f4a3" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - -[[package]] -name = "walkdir" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.37", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.37", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" - -[[package]] -name = "web-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0e74f82d49d545ad128049b7e88f6576df2da6b02e9ce565c6f533be576957e" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 81d590b621..c34435be88 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -74,11 +74,6 @@ tag = "3.7.0-alpha-0" default-features = false - [dependencies.log] - features = ["kv", "kv_unstable", "std", "value-bag"] - version = "0.4.28" - default-features = false - [dependencies.serde] features = ["alloc", "default", "derive", "rc", "serde_derive", "std"] version = "1.0.228" @@ -189,6 +184,10 @@ path = "tests/behaviour/driver/user.rs" name = "test_user" +[[test]] + path = "tests/behaviour/driver/cluster.rs" + name = "test_cluster" + [[test]] path = "tests/behaviour/driver/migration.rs" name = "test_migration" diff --git a/rust/src/connection/server/server_manager.rs b/rust/src/connection/server/server_manager.rs index 640af2b7eb..c3f3c9484e 100644 --- a/rust/src/connection/server/server_manager.rs +++ b/rust/src/connection/server/server_manager.rs @@ -27,7 +27,7 @@ use std::{ }; use itertools::{enumerate, Itertools}; -use log::debug; +use tracing::debug; use crate::{ common::{ diff --git a/rust/tests/integration/mod.rs b/rust/tests/integration/mod.rs index f4890ab29f..0c44e074f9 100644 --- a/rust/tests/integration/mod.rs +++ b/rust/tests/integration/mod.rs @@ -18,3 +18,5 @@ */ mod cluster; +mod driver; +mod example; From ef286e23cf84271a3e96282dbc02c8fb38ac74b0 Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Tue, 17 Feb 2026 17:49:47 +0000 Subject: [PATCH 03/10] Fix build --- c/example.c | 8 +- c/src/common/error.rs | 2 +- c/src/driver_options.rs | 7 +- c/tests/integration/example.c | 8 +- .../ROOT/partials/c/session/options.adoc | 533 ------------------ 5 files changed, 11 insertions(+), 547 deletions(-) delete mode 100644 docs/modules/ROOT/partials/c/session/options.adoc diff --git a/c/example.c b/c/example.c index 7600841028..926ed03e40 100644 --- a/c/example.c +++ b/c/example.c @@ -7,8 +7,8 @@ int main() { // Open a driver connection Credentials* credentials = credentials_new("admin", "password"); - DriverOptions* driver_options = driver_options_new(false, NULL); - TypeDBDriver* driver = driver_open("127.0.0.1:1729", credentials, driver_options); + DriverOptions* driver_options = driver_options_new(driver_tls_config_new_disabled()); + TypeDBDriver* driver = driver_new("127.0.0.1:1729", credentials, driver_options); credentials_drop(credentials); driver_options_drop(driver_options); @@ -25,14 +25,14 @@ int main() { // Create a database const char* databaseName = "typedb"; - databases_create(driver, databaseName); + databases_create(driver, databaseName, NULL); if (check_error()) { printf("Failed to create database\n"); goto cleanup; } // Check if the database exists - if (databases_contains(driver, databaseName)) { + if (databases_contains(driver, databaseName, NULL)) { printf("Database '%s' created successfully\n", databaseName); } diff --git a/c/src/common/error.rs b/c/src/common/error.rs index e27775de7c..7144b243b0 100644 --- a/c/src/common/error.rs +++ b/c/src/common/error.rs @@ -24,7 +24,7 @@ use std::{ sync::Arc, }; -use tracing::{debug, warn}; +use tracing::debug; use typedb_driver::{Error, Result}; use super::memory::{free, release_arc, release_optional, release_string}; diff --git a/c/src/driver_options.rs b/c/src/driver_options.rs index 0ffdb9fbcb..3e01acafdb 100644 --- a/c/src/driver_options.rs +++ b/c/src/driver_options.rs @@ -17,14 +17,11 @@ * under the License. */ -use std::{ffi::c_char, path::Path, time::Duration}; +use std::time::Duration; use typedb_driver::{DriverOptions, DriverTlsConfig}; -use crate::common::{ - error::unwrap_void, - memory::{borrow, borrow_mut, borrow_optional, free, release, release_string, string_view}, -}; +use crate::common::memory::{borrow, borrow_mut, borrow_optional, free, release, release_string, string_view}; /// Creates a new DriverOptions for connecting to TypeDB Server using custom TLS settings. /// WARNING: Disabled TLS settings will make the driver sending passwords as plaintext. diff --git a/c/tests/integration/example.c b/c/tests/integration/example.c index 42b58d8b53..5b7526a31a 100644 --- a/c/tests/integration/example.c +++ b/c/tests/integration/example.c @@ -32,8 +32,8 @@ int TYPEDB_EXAMPLE_FUNC() { // Open a driver connection Credentials* credentials = credentials_new("admin", "password"); - DriverOptions* driver_options = driver_options_new(false, NULL); - TypeDBDriver* driver = driver_open("127.0.0.1:1729", credentials, driver_options); + DriverOptions* driver_options = driver_options_new(driver_tls_config_new_disabled()); + TypeDBDriver* driver = driver_new("127.0.0.1:1729", credentials, driver_options); credentials_drop(credentials); driver_options_drop(driver_options); @@ -54,14 +54,14 @@ int TYPEDB_EXAMPLE_FUNC() { delete_database_if_exists(driver, databaseName); if (FAILED()) goto cleanup; // EXAMPLE START MARKER - databases_create(driver, databaseName); + databases_create(driver, databaseName, NULL); if (check_error()) { printf("Failed to create database\n"); goto cleanup; } // Check if the database exists - if (databases_contains(driver, databaseName)) { + if (databases_contains(driver, databaseName, NULL)) { printf("Database '%s' created successfully\n", databaseName); } diff --git a/docs/modules/ROOT/partials/c/session/options.adoc b/docs/modules/ROOT/partials/c/session/options.adoc deleted file mode 100644 index 386380f351..0000000000 --- a/docs/modules/ROOT/partials/c/session/options.adoc +++ /dev/null @@ -1,533 +0,0 @@ -[#_methods_session_options] -=== options - -[#_Struct_Options] -==== Struct Options - - - -TypeDB session and transaction options. ``TypeDBOptions`` object can be used to override the default server behaviour. Options are specified using properties assignment. - - -[#_options_drop] -==== options_drop - -[source,cpp] ----- -void options_drop(struct Options* options) ----- - - - -Frees the native rust ``Options`` object. - -[caption=""] -.Returns -`void` - -[#_options_get_explain] -==== options_get_explain - -[source,cpp] ----- -bool options_get_explain(const struct Options* options) ----- - - - -Returns the value set for the explanation in this ``TypeDBOptions`` object. If set to ``true``, explanations for queries are enabled. - -[caption=""] -.Returns -`bool` - -[#_options_get_infer] -==== options_get_infer - -[source,cpp] ----- -bool options_get_infer(const struct Options* options) ----- - - - -Returns the value set for the inference in this ``TypeDBOptions`` object. - -[caption=""] -.Returns -`bool` - -[#_options_get_parallel] -==== options_get_parallel - -[source,cpp] ----- -bool options_get_parallel(const struct Options* options) ----- - - - -Returns the value set for the parallel execution in this ``TypeDBOptions`` object. If set to ``true``, the server uses parallel instead of single-threaded execution. - -[caption=""] -.Returns -`bool` - -[#_options_get_prefetch] -==== options_get_prefetch - -[source,cpp] ----- -bool options_get_prefetch(const struct Options* options) ----- - - - -Returns the value set for the prefetching in this ``TypeDBOptions`` object. If set to ``true``, the first batch of answers is streamed to the driver even without an explicit request for it. - -[caption=""] -.Returns -`bool` - -[#_options_get_prefetch_size] -==== options_get_prefetch_size - -[source,cpp] ----- -int32_t options_get_prefetch_size(const struct Options* options) ----- - - - -Returns the value set for the prefetch size in this ``TypeDBOptions`` object. If set, specifies a guideline number of answers that the server should send before the driver issues a fresh request. - -[caption=""] -.Returns -`int32_t` - -[#_options_get_read_any_replica] -==== options_get_read_any_replica - -[source,cpp] ----- -bool options_get_read_any_replica(const struct Options* options) ----- - - - -Returns the value set for reading data from any replica in this ``TypeDBOptions`` object. If set to ``True``, enables reading data from any replica, potentially boosting read throughput. - -[caption=""] -.Returns -`bool` - -[#_options_get_schema_lock_acquire_timeout_millis] -==== options_get_schema_lock_acquire_timeout_millis - -[source,cpp] ----- -int64_t options_get_schema_lock_acquire_timeout_millis(const struct Options* options) ----- - - - -Returns the value set for the schema lock acquire timeout in this ``TypeDBOptions`` object. If set, specifies how long the driver should wait if opening a session or transaction is blocked by a schema write lock. - -[caption=""] -.Returns -`int64_t` - -[#_options_get_session_idle_timeout_millis] -==== options_get_session_idle_timeout_millis - -[source,cpp] ----- -int64_t options_get_session_idle_timeout_millis(const struct Options* options) ----- - - - -Returns the value set for the session idle timeout in this ``TypeDBOptions`` object. If set, specifies a timeout that allows the server to close sessions if the driver terminates or becomes unresponsive. - -[caption=""] -.Returns -`int64_t` - -[#_options_get_trace_inference] -==== options_get_trace_inference - -[source,cpp] ----- -bool options_get_trace_inference(const struct Options* options) ----- - - - -Returns the value set for reasoning tracing in this ``TypeDBOptions`` object. If set to ``true``, reasoning tracing graphs are output in the logging directory. - -[caption=""] -.Returns -`bool` - -[#_options_get_transaction_timeout_millis] -==== options_get_transaction_timeout_millis - -[source,cpp] ----- -int64_t options_get_transaction_timeout_millis(const struct Options* options) ----- - - - -Returns the value set for the transaction timeout in this ``TypeDBOptions`` object. If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. - -[caption=""] -.Returns -`int64_t` - -[#_options_has_explain] -==== options_has_explain - -[source,cpp] ----- -bool options_has_explain(const struct Options* options) ----- - - - -Checks whether the option for explanation was explicitly set for this ``TypeDBOptions`` object. - -[caption=""] -.Returns -`bool` - -[#_options_has_infer] -==== options_has_infer - -[source,cpp] ----- -bool options_has_infer(const struct Options* options) ----- - - - -Checks whether the option for inference was explicitly set for this ``TypeDBOptions`` object. - -[caption=""] -.Returns -`bool` - -[#_options_has_parallel] -==== options_has_parallel - -[source,cpp] ----- -bool options_has_parallel(const struct Options* options) ----- - - - -Checks whether the option for parallel execution was explicitly set for this ``TypeDBOptions`` object. - -[caption=""] -.Returns -`bool` - -[#_options_has_prefetch] -==== options_has_prefetch - -[source,cpp] ----- -bool options_has_prefetch(const struct Options* options) ----- - - - -Checks whether the option for prefetching was explicitly set for this ``TypeDBOptions`` object. - -[caption=""] -.Returns -`bool` - -[#_options_has_prefetch_size] -==== options_has_prefetch_size - -[source,cpp] ----- -bool options_has_prefetch_size(const struct Options* options) ----- - - - -Checks whether the option for prefetch size was explicitly set for this ``TypeDBOptions`` object. - -[caption=""] -.Returns -`bool` - -[#_options_has_read_any_replica] -==== options_has_read_any_replica - -[source,cpp] ----- -bool options_has_read_any_replica(const struct Options* options) ----- - - - -Checks whether the option for reading data from any replica was explicitly set for this ``TypeDBOptions`` object. - -[caption=""] -.Returns -`bool` - -[#_options_has_schema_lock_acquire_timeout_millis] -==== options_has_schema_lock_acquire_timeout_millis - -[source,cpp] ----- -bool options_has_schema_lock_acquire_timeout_millis(const struct Options* options) ----- - - - -Checks whether the option for schema lock acquire timeout was explicitly set for this ``TypeDBOptions`` object. - -[caption=""] -.Returns -`bool` - -[#_options_has_session_idle_timeout_millis] -==== options_has_session_idle_timeout_millis - -[source,cpp] ----- -bool options_has_session_idle_timeout_millis(const struct Options* options) ----- - - - -Checks whether the option for the session idle timeout was explicitly set for this ``TypeDBOptions`` object. - -[caption=""] -.Returns -`bool` - -[#_options_has_trace_inference] -==== options_has_trace_inference - -[source,cpp] ----- -bool options_has_trace_inference(const struct Options* options) ----- - - - -Checks whether the option for reasoning tracing was explicitly set for this ``TypeDBOptions`` object. - -[caption=""] -.Returns -`bool` - -[#_options_has_transaction_timeout_millis] -==== options_has_transaction_timeout_millis - -[source,cpp] ----- -bool options_has_transaction_timeout_millis(const struct Options* options) ----- - - - -Checks whether the option for transaction timeout was explicitly set for this ``TypeDBOptions`` object. - -[caption=""] -.Returns -`bool` - -[#_options_new] -==== options_new - -[source,cpp] ----- -struct Options* options_new(void) ----- - - - -Produces a new ``TypeDBOptions`` object. - -[caption=""] -.Returns -`struct Options*` - -[#_options_set_explain] -==== options_set_explain - -[source,cpp] ----- -void options_set_explain(struct Options* options, bool explain) ----- - - - -Explicitly enables or disables explanations. If set to ``true``, enables explanations for queries. Only affects read transactions. - -[caption=""] -.Returns -`void` - -[#_options_set_infer] -==== options_set_infer - -[source,cpp] ----- -void options_set_infer(struct Options* options, bool infer) ----- - - - -Explicitly enables or disables inference. Only settable at transaction level and above. Only affects read transactions. - -[caption=""] -.Returns -`void` - -[#_options_set_parallel] -==== options_set_parallel - -[source,cpp] ----- -void options_set_parallel(struct Options* options, bool parallel) ----- - - - -Explicitly enables or disables parallel execution. If set to ``true``, the server uses parallel instead of single-threaded execution. - -[caption=""] -.Returns -`void` - -[#_options_set_prefetch] -==== options_set_prefetch - -[source,cpp] ----- -void options_set_prefetch(struct Options* options, bool prefetch) ----- - - - -Explicitly enables or disables prefetching. If set to ``true``, the first batch of answers is streamed to the driver even without an explicit request for it. - -[caption=""] -.Returns -`void` - -[#_options_set_prefetch_size] -==== options_set_prefetch_size - -[source,cpp] ----- -void options_set_prefetch_size(struct Options* options, int32_t prefetch_size) ----- - - - -Explicitly sets a prefetch size. If set, specifies a guideline number of answers that the server should send before the driver issues a fresh request. - - -[caption=""] -.Input parameters -[cols=",,"] -[options="header"] -|=== -|Name |Description |Type -a| `prefetchSize` a| Number of answers that the server should send before the driver issues a fresh request a| -|=== - -[caption=""] -.Returns -`void` - -[#_options_set_read_any_replica] -==== options_set_read_any_replica - -[source,cpp] ----- -void options_set_read_any_replica(struct Options* options, bool read_any_replica) ----- - - - -Explicitly enables or disables reading data from any replica. If set to ``True``, enables reading data from any replica, potentially boosting read throughput. Only settable in TypeDB Cloud. - -[caption=""] -.Returns -`void` - -[#_options_set_schema_lock_acquire_timeout_millis] -==== options_set_schema_lock_acquire_timeout_millis - -[source,cpp] ----- -void options_set_schema_lock_acquire_timeout_millis(struct Options* options, int64_t timeout_millis) ----- - - - -Explicitly sets schema lock acquire timeout. If set, specifies how long the driver should wait if opening a session or transaction is blocked by a schema write lock. - -[caption=""] -.Returns -`void` - -[#_options_set_session_idle_timeout_millis] -==== options_set_session_idle_timeout_millis - -[source,cpp] ----- -void options_set_session_idle_timeout_millis(struct Options* options, int64_t timeout_millis) ----- - - - -Explicitly sets a session idle timeout. If set, specifies a timeout that allows the server to close sessions if the driver terminates or becomes unresponsive. - -[caption=""] -.Returns -`void` - -[#_options_set_trace_inference] -==== options_set_trace_inference - -[source,cpp] ----- -void options_set_trace_inference(struct Options* options, bool trace_inference) ----- - - - -Explicitly enables or disables reasoning tracing. If set to ``true``, reasoning tracing graphs are output in the logging directory. Should be used with ``parallel = False``. - -[caption=""] -.Returns -`void` - -[#_options_set_transaction_timeout_millis] -==== options_set_transaction_timeout_millis - -[source,cpp] ----- -void options_set_transaction_timeout_millis(struct Options* options, int64_t timeout_millis) ----- - - - -Explicitly sets a transaction timeout. If set, specifies a timeout for killing transactions automatically, preventing memory leaks in unclosed transactions. - -[caption=""] -.Returns -`void` - From 84b8196fdaed88ade254f165ad6de389d7fcb03e Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Wed, 18 Feb 2026 11:27:39 +0000 Subject: [PATCH 04/10] Fix build again --- Cargo.lock | 31 ++++++++------------------- c/Cargo.toml | 4 ++-- c/example.c | 4 +++- c/tests/integration/example.c | 4 +++- rust/Cargo.toml | 4 ++-- rust/tests/behaviour/steps/Cargo.toml | 4 ++-- 6 files changed, 21 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07e626b8cf..98a7b413df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,12 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -473,17 +467,16 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-link 0.1.3", + "windows-link", ] [[package]] @@ -1621,7 +1614,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -3122,7 +3115,7 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.1", + "windows-link", "windows-result", "windows-strings", ] @@ -3149,12 +3142,6 @@ dependencies = [ "syn 2.0.116", ] -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - [[package]] name = "windows-link" version = "0.2.1" @@ -3167,7 +3154,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -3176,7 +3163,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -3221,7 +3208,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -3261,7 +3248,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.2.1", + "windows-link", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", diff --git a/c/Cargo.toml b/c/Cargo.toml index 195ace46f8..8a362c7a55 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -30,8 +30,8 @@ features = {} default-features = false [dependencies.chrono] - features = ["alloc", "android-tzdata", "clock", "default", "iana-time-zone", "js-sys", "now", "oldtime", "serde", "std", "wasm-bindgen", "wasmbind", "winapi", "windows-link"] - version = "0.4.40" + features = ["alloc", "clock", "default", "iana-time-zone", "js-sys", "now", "oldtime", "serde", "std", "wasm-bindgen", "wasmbind", "winapi", "windows-link"] + version = "0.4.43" default-features = false [dependencies.itertools] diff --git a/c/example.c b/c/example.c index 926ed03e40..dfcc60cf39 100644 --- a/c/example.c +++ b/c/example.c @@ -7,10 +7,12 @@ int main() { // Open a driver connection Credentials* credentials = credentials_new("admin", "password"); - DriverOptions* driver_options = driver_options_new(driver_tls_config_new_disabled()); + DriverTlsConfig* tls_config = driver_tls_config_new_disabled(); + DriverOptions* driver_options = driver_options_new(tls_config); TypeDBDriver* driver = driver_new("127.0.0.1:1729", credentials, driver_options); credentials_drop(credentials); driver_options_drop(driver_options); + driver_tls_config_drop(tls_config); if (check_error()) { Error* error = get_last_error(); diff --git a/c/tests/integration/example.c b/c/tests/integration/example.c index 5b7526a31a..a0ce57c1a2 100644 --- a/c/tests/integration/example.c +++ b/c/tests/integration/example.c @@ -32,10 +32,12 @@ int TYPEDB_EXAMPLE_FUNC() { // Open a driver connection Credentials* credentials = credentials_new("admin", "password"); - DriverOptions* driver_options = driver_options_new(driver_tls_config_new_disabled()); + DriverTlsConfig* tls_config = driver_tls_config_new_disabled(); + DriverOptions* driver_options = driver_options_new(tls_config); TypeDBDriver* driver = driver_new("127.0.0.1:1729", credentials, driver_options); credentials_drop(credentials); driver_options_drop(driver_options); + driver_tls_config_drop(tls_config); if (check_error()) { Error* error = get_last_error(); diff --git a/rust/Cargo.toml b/rust/Cargo.toml index c34435be88..e1ffee63dc 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -135,8 +135,8 @@ default-features = false [dependencies.chrono] - features = ["alloc", "android-tzdata", "clock", "default", "iana-time-zone", "js-sys", "now", "oldtime", "serde", "std", "wasm-bindgen", "wasmbind", "winapi", "windows-link"] - version = "0.4.40" + features = ["alloc", "clock", "default", "iana-time-zone", "js-sys", "now", "oldtime", "serde", "std", "wasm-bindgen", "wasmbind", "winapi", "windows-link"] + version = "0.4.43" default-features = false [dependencies.crossbeam] diff --git a/rust/tests/behaviour/steps/Cargo.toml b/rust/tests/behaviour/steps/Cargo.toml index 53452a3424..dadf66f8f4 100644 --- a/rust/tests/behaviour/steps/Cargo.toml +++ b/rust/tests/behaviour/steps/Cargo.toml @@ -55,8 +55,8 @@ features = {} default-features = false [dependencies.chrono] - features = ["alloc", "android-tzdata", "clock", "default", "iana-time-zone", "js-sys", "now", "oldtime", "serde", "std", "wasm-bindgen", "wasmbind", "winapi", "windows-link"] - version = "0.4.40" + features = ["alloc", "clock", "default", "iana-time-zone", "js-sys", "now", "oldtime", "serde", "std", "wasm-bindgen", "wasmbind", "winapi", "windows-link"] + version = "0.4.43" default-features = false [dependencies.uuid] From 4d8c3392e12fa688135cc997c6b77ea4f1e11af1 Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Wed, 18 Feb 2026 15:33:58 +0000 Subject: [PATCH 05/10] Fix docs and update dependencies --- .../ROOT/partials/c/analyze/constraint.adoc | 84 +++++++++---------- .../c/analyze/constraintexactness.adoc | 4 +- .../partials/c/analyze/reduceassignment.adoc | 4 +- .../ROOT/partials/c/analyze/reducer.adoc | 4 +- .../ROOT/partials/c/concept/attribute.adoc | 2 +- .../ROOT/partials/c/concept/entity.adoc | 2 +- .../ROOT/partials/c/concept/relation.adoc | 2 +- .../ROOT/partials/c/connection/driver.adoc | 6 +- .../partials/c/connection/driveroptions.adoc | 2 +- .../partials/c/transaction/queryoptions.adoc | 2 +- .../partials/c/transaction/transaction.adoc | 4 +- .../c/transaction/transactionoptions.adoc | 2 +- 12 files changed, 59 insertions(+), 59 deletions(-) diff --git a/docs/modules/ROOT/partials/c/analyze/constraint.adoc b/docs/modules/ROOT/partials/c/analyze/constraint.adoc index 48b618d5d1..a510007f5b 100644 --- a/docs/modules/ROOT/partials/c/analyze/constraint.adoc +++ b/docs/modules/ROOT/partials/c/analyze/constraint.adoc @@ -11,7 +11,7 @@ enum Comparator constraint_comparison_get_comparator(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a Comparison constraint, and returns the comparator used in the comparison. Will panic if the Constraint is not a Comparison constraint. +Unwraps the ``Constraint`` instance as a ``Comparison`` constraint, and returns the comparator used in the comparison. Will panic if the Constraint is not a Comparison constraint. [caption=""] .Returns @@ -27,7 +27,7 @@ struct ConstraintVertex* constraint_comparison_get_lhs(const struct ConstraintWi -Unwraps the ``Constraint`` instance as a Comparison constraint, and returns the left-hand side vertex. Will panic if the Constraint is not a Comparison constraint. +Unwraps the ``Constraint`` instance as a ``Comparison`` constraint, and returns the left-hand side vertex. Will panic if the Constraint is not a Comparison constraint. [caption=""] .Returns @@ -43,7 +43,7 @@ struct ConstraintVertex* constraint_comparison_get_rhs(const struct ConstraintWi -Unwraps the ``Constraint`` instance as a Comparison constraint, and returns the right-hand side vertex. Will panic if the Constraint is not a Comparison constraint. +Unwraps the ``Constraint`` instance as a ``Comparison`` constraint, and returns the right-hand side vertex. Will panic if the Constraint is not a Comparison constraint. [caption=""] .Returns @@ -59,7 +59,7 @@ struct ConstraintVertexIterator* constraint_expression_get_arguments(const struc -Unwraps the ``Constraint`` instance as an Expression constraint, and returns the expression arguments - These are any variables used in the right-hand side of the expression. Will panic if the Constraint is not an Expression constraint. +Unwraps the ``Constraint`` instance as an ``Expression`` constraint, and returns the expression arguments - These are any variables used in the right-hand side of the expression. Will panic if the Constraint is not an Expression constraint. [caption=""] .Returns @@ -75,7 +75,7 @@ struct ConstraintVertex* constraint_expression_get_assigned(const struct Constra -Unwraps the ``Constraint`` instance as an Expression constraint, and returns the variable assigned by the expression. Will panic if the Constraint is not an Expression constraint. +Unwraps the ``Constraint`` instance as an ``Expression`` constraint, and returns the variable assigned by the expression. Will panic if the Constraint is not an Expression constraint. [caption=""] .Returns @@ -91,7 +91,7 @@ char* constraint_expression_get_text(const struct ConstraintWithSpan* constraint -Unwraps the ``Constraint`` instance as an Expression constraint, and returns the expression text. Will panic if the Constraint is not an Expression constraint. +Unwraps the ``Constraint`` instance as an ``Expression`` constraint, and returns the expression text. Will panic if the Constraint is not an Expression constraint. [caption=""] .Returns @@ -107,7 +107,7 @@ struct ConstraintVertexIterator* constraint_function_call_get_arguments(const st -Unwraps the ``Constraint`` instance as a FunctionCall constraint, and returns the variables passed as arguments to the function call . Will panic if the Constraint is not a FunctionCall constraint. +Unwraps the ``Constraint`` instance as a ``FunctionCall`` constraint, and returns the variables passed as arguments to the function call . Will panic if the Constraint is not a FunctionCall constraint. [caption=""] .Returns @@ -123,7 +123,7 @@ struct ConstraintVertexIterator* constraint_function_call_get_assigned(const str -Unwraps the ``Constraint`` instance as a FunctionCall constraint, and returns the variables assigned by the function call. Will panic if the Constraint is not a FunctionCall constraint. +Unwraps the ``Constraint`` instance as a ``FunctionCall`` constraint, and returns the variables assigned by the function call. Will panic if the Constraint is not a FunctionCall constraint. [caption=""] .Returns @@ -139,7 +139,7 @@ char* constraint_function_call_get_name(const struct ConstraintWithSpan* constra -Unwraps the ``Constraint`` instance as a FunctionCall constraint, and returns the function name. Will panic if the Constraint is not a FunctionCall constraint. +Unwraps the ``Constraint`` instance as a ``FunctionCall`` constraint, and returns the function name. Will panic if the Constraint is not a FunctionCall constraint. [caption=""] .Returns @@ -155,7 +155,7 @@ struct ConstraintVertex* constraint_has_get_attribute(const struct ConstraintWit -Unwraps the ``Constraint`` instance as a Has constraint, and returns the attribute vertex. Will panic if the Constraint is not a Has constraint. +Unwraps the ``Constraint`` instance as a ``Has`` constraint, and returns the attribute vertex. Will panic if the Constraint is not a Has constraint. [caption=""] .Returns @@ -171,7 +171,7 @@ enum ConstraintExactness constraint_has_get_exactness(const struct ConstraintWit -(FUTURE-USE: Currently always ConstraintExactness::Subtypes) Unwraps the ``Constraint`` instance as a Has constraint, and returns the exactness of the attribute match. Will panic if the Constraint is not a Has constraint. +(FUTURE-USE: Currently always ConstraintExactness::Subtypes) Unwraps the ``Constraint`` instance as a ``Has`` constraint, and returns the exactness of the attribute match. Will panic if the Constraint is not a Has constraint. [caption=""] .Returns @@ -187,7 +187,7 @@ struct ConstraintVertex* constraint_has_get_owner(const struct ConstraintWithSpa -Unwraps the ``Constraint`` instance as a Has constraint, and returns the owner vertex. Will panic if the Constraint is not a Has constraint. +Unwraps the ``Constraint`` instance as a ``Has`` constraint, and returns the owner vertex. Will panic if the Constraint is not a Has constraint. [caption=""] .Returns @@ -203,7 +203,7 @@ char* constraint_iid_get_iid(const struct ConstraintWithSpan* constraint) -Unwraps the ``Constraint`` instance as an Iid constraint, and returns the iid value as a string. Will panic if the Constraint is not an Iid constraint. +Unwraps the ``Constraint`` instance as an ``Iid`` constraint, and returns the iid value as a string. Will panic if the Constraint is not an Iid constraint. [caption=""] .Returns @@ -219,7 +219,7 @@ struct ConstraintVertex* constraint_iid_get_variable(const struct ConstraintWith -Unwraps the ``Constraint`` instance as an Iid constraint, and returns the concept (variable) the iid applies to. Will panic if the Constraint is not an Iid constraint. +Unwraps the ``Constraint`` instance as an ``Iid`` constraint, and returns the concept (variable) the iid applies to. Will panic if the Constraint is not an Iid constraint. [caption=""] .Returns @@ -235,7 +235,7 @@ struct ConstraintVertex* constraint_is_get_lhs(const struct ConstraintWithSpan* -Unwraps the ``Constraint`` instance as an Is constraint, and returns the left-hand side vertex. Will panic if the Constraint is not an Is constraint. +Unwraps the ``Constraint`` instance as an ``Is`` constraint, and returns the left-hand side vertex. Will panic if the Constraint is not an Is constraint. [caption=""] .Returns @@ -251,7 +251,7 @@ struct ConstraintVertex* constraint_is_get_rhs(const struct ConstraintWithSpan* -Unwraps the ``Constraint`` instance as an Is constraint, and returns the right-hand side vertex. Will panic if the Constraint is not an Is constraint. +Unwraps the ``Constraint`` instance as an ``Is`` constraint, and returns the right-hand side vertex. Will panic if the Constraint is not an Is constraint. [caption=""] .Returns @@ -267,7 +267,7 @@ enum ConstraintExactness constraint_isa_get_exactness(const struct ConstraintWit -Unwraps the ``Constraint`` instance as an Isa constraint, and returns the exactness of the type match. Will panic if the Constraint is not an Isa constraint. +Unwraps the ``Constraint`` instance as an ``Isa`` constraint, and returns the exactness of the type match. Will panic if the Constraint is not an Isa constraint. [caption=""] .Returns @@ -283,7 +283,7 @@ struct ConstraintVertex* constraint_isa_get_instance(const struct ConstraintWith -Unwraps the ``Constraint`` instance as an Isa constraint, and returns the instance vertex. Will panic if the Constraint is not an Isa constraint. +Unwraps the ``Constraint`` instance as an ``Isa`` constraint, and returns the instance vertex. Will panic if the Constraint is not an Isa constraint. [caption=""] .Returns @@ -299,7 +299,7 @@ struct ConstraintVertex* constraint_isa_get_type(const struct ConstraintWithSpan -Unwraps the ``Constraint`` instance as an Isa constraint, and returns the type vertex. Will panic if the Constraint is not an Isa constraint. +Unwraps the ``Constraint`` instance as an ``Isa`` constraint, and returns the type vertex. Will panic if the Constraint is not an Isa constraint. [caption=""] .Returns @@ -315,7 +315,7 @@ enum Kind constraint_kind_get_kind(const struct ConstraintWithSpan* constraint) -Unwraps the ``Constraint`` instance as a Kind constraint, and returns the Kind of the type-vertex. Will panic if the Constraint is not a Kind constraint. +Unwraps the ``Constraint`` instance as a ``Kind`` constraint, and returns the ``Kind`` of the type-vertex. Will panic if the Constraint is not a Kind constraint. [caption=""] .Returns @@ -331,7 +331,7 @@ struct ConstraintVertex* constraint_kind_get_type(const struct ConstraintWithSpa -Unwraps the ``Constraint`` instance as a Kind constraint, and returns the associated type vertex. Will panic if the Constraint is not a Kind constraint. +Unwraps the ``Constraint`` instance as a ``Kind`` constraint, and returns the associated type vertex. Will panic if the Constraint is not a Kind constraint. [caption=""] .Returns @@ -347,7 +347,7 @@ char* constraint_label_get_label(const struct ConstraintWithSpan* constraint) -Unwraps the ``Constraint`` instance as a Label constraint, and returns the label string. Will panic if the Constraint is not a Label constraint. +Unwraps the ``Constraint`` instance as a ``Label`` constraint, and returns the label string. Will panic if the Constraint is not a Label constraint. [caption=""] .Returns @@ -363,7 +363,7 @@ struct ConstraintVertex* constraint_label_get_variable(const struct ConstraintWi -Unwraps the ``Constraint`` instance as a Label constraint, and returns the type-vertex the label applies to. Will panic if the Constraint is not a Label constraint. +Unwraps the ``Constraint`` instance as a ``Label`` constraint, and returns the type-vertex the label applies to. Will panic if the Constraint is not a Label constraint. [caption=""] .Returns @@ -379,7 +379,7 @@ enum ConstraintExactness constraint_links_get_exactness(const struct ConstraintW -(FUTURE-USE: Currently always ConstraintExactness::Subtypes) Unwraps the ``Constraint`` instance as a Links constraint, and returns the exactness of the role-type match. Will panic if the Constraint is not a Links constraint. +(FUTURE-USE: Currently always ConstraintExactness::Subtypes) Unwraps the ``Constraint`` instance as a ``Links`` constraint, and returns the exactness of the role-type match. Will panic if the Constraint is not a Links constraint. [caption=""] .Returns @@ -395,7 +395,7 @@ struct ConstraintVertex* constraint_links_get_player(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a Links constraint, and returns the player vertex. Will panic if the Constraint is not a Links constraint. +Unwraps the ``Constraint`` instance as a ``Links`` constraint, and returns the player vertex. Will panic if the Constraint is not a Links constraint. [caption=""] .Returns @@ -411,7 +411,7 @@ struct ConstraintVertex* constraint_links_get_relation(const struct ConstraintWi -Unwraps the ``Constraint`` instance as a Links constraint, and returns the relation vertex. Will panic if the Constraint is not a Links constraint. +Unwraps the ``Constraint`` instance as a ``Links`` constraint, and returns the relation vertex. Will panic if the Constraint is not a Links constraint. [caption=""] .Returns @@ -427,7 +427,7 @@ struct ConstraintVertex* constraint_links_get_role(const struct ConstraintWithSp -Unwraps the ``Constraint`` instance as a Links constraint, and returns the role vertex. Will panic if the Constraint is not a Links constraint. +Unwraps the ``Constraint`` instance as a ``Links`` constraint, and returns the role vertex. Will panic if the Constraint is not a Links constraint. [caption=""] .Returns @@ -443,7 +443,7 @@ struct ConjunctionID* constraint_not_get_conjunction(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a Not constraint, and returns the ``ConjunctionID`` of the negated conjunction. Will panic if the Constraint is not a Not constraint. +Unwraps the ``Constraint`` instance as a ``Not`` constraint, and returns the ``ConjunctionID`` of the negated conjunction. Will panic if the Constraint is not a Not constraint. [caption=""] .Returns @@ -459,7 +459,7 @@ struct ConjunctionIDIterator* constraint_or_get_branches(const struct Constraint -Unwraps the ``Constraint`` instance as an Or constraint, and returns the ``ConjunctionID``s of the conjunction in each of the branches. Will panic if the Constraint is not an Or constraint. +Unwraps the ``Constraint`` instance as an ``Or`` constraint, and returns the ``ConjunctionID``s of the conjunction in each of the branches. Will panic if the Constraint is not an Or constraint. [caption=""] .Returns @@ -475,7 +475,7 @@ struct ConstraintVertex* constraint_owns_get_attribute(const struct ConstraintWi -Unwraps the ``Constraint`` instance as an Owns constraint, and returns the attribute-type vertex. Will panic if the Constraint is not an Owns constraint. +Unwraps the ``Constraint`` instance as an ``Owns`` constraint, and returns the attribute-type vertex. Will panic if the Constraint is not an Owns constraint. [caption=""] .Returns @@ -507,7 +507,7 @@ struct ConstraintVertex* constraint_owns_get_owner(const struct ConstraintWithSp -Unwraps the ``Constraint`` instance as an Owns constraint, and returns the owner-type vertex. Will panic if the Constraint is not an Owns constraint. +Unwraps the ``Constraint`` instance as an ``Owns`` constraint, and returns the owner-type vertex. Will panic if the Constraint is not an Owns constraint. [caption=""] .Returns @@ -539,7 +539,7 @@ struct ConstraintVertex* constraint_plays_get_player(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a Plays constraint, and returns the player type vertex. Will panic if the Constraint is not a Plays constraint. +Unwraps the ``Constraint`` instance as a ``Plays`` constraint, and returns the player type vertex. Will panic if the Constraint is not a Plays constraint. [caption=""] .Returns @@ -555,7 +555,7 @@ struct ConstraintVertex* constraint_plays_get_role(const struct ConstraintWithSp -Unwraps the ``Constraint`` instance as a Plays constraint, and returns the role-type vertex. Will panic if the Constraint is not a Plays constraint. +Unwraps the ``Constraint`` instance as a ``Plays`` constraint, and returns the role-type vertex. Will panic if the Constraint is not a Plays constraint. [caption=""] .Returns @@ -571,7 +571,7 @@ enum ConstraintExactness constraint_relates_get_exactness(const struct Constrain -Unwraps the ``Constraint`` instance as a Relates constraint, and returns the exactness of the relation match. Will panic if the Constraint is not a Relates constraint. +Unwraps the ``Constraint`` instance as a ``Relates`` constraint, and returns the exactness of the relation match. Will panic if the Constraint is not a Relates constraint. [caption=""] .Returns @@ -587,7 +587,7 @@ struct ConstraintVertex* constraint_relates_get_relation(const struct Constraint -Unwraps the ``Constraint`` instance as a Relates constraint, and returns the relation-type vertex. Will panic if the Constraint is not a Relates constraint. +Unwraps the ``Constraint`` instance as a ``Relates`` constraint, and returns the relation-type vertex. Will panic if the Constraint is not a Relates constraint. [caption=""] .Returns @@ -603,7 +603,7 @@ struct ConstraintVertex* constraint_relates_get_role(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a Relates constraint, and returns the role-type vertex. Will panic if the Constraint is not a Relates constraint. +Unwraps the ``Constraint`` instance as a ``Relates`` constraint, and returns the role-type vertex. Will panic if the Constraint is not a Relates constraint. [caption=""] .Returns @@ -635,7 +635,7 @@ enum ConstraintExactness constraint_sub_get_exactness(const struct ConstraintWit -Unwraps the ``Constraint`` instance as a Sub constraint, and returns the exactness of the subtype match. If Exact (i.e. sub!), only the immediate subtype is returned else, (i.e. sub) the type itself and all subtypes are returned. Will panic if the Constraint is not a Sub constraint. +Unwraps the ``Constraint`` instance as a ``Sub`` constraint, and returns the exactness of the subtype match. If Exact (i.e. ``sub!``), only the immediate subtype is returned else, (i.e. ``sub``) the type itself and all subtypes are returned. Will panic if the Constraint is not a Sub constraint. [caption=""] .Returns @@ -651,7 +651,7 @@ struct ConstraintVertex* constraint_sub_get_subtype(const struct ConstraintWithS -Unwraps the ``Constraint`` instance as a Sub constraint, and returns the subtype vertex. Will panic if the Constraint is not a Sub constraint. +Unwraps the ``Constraint`` instance as a ``Sub`` constraint, and returns the subtype vertex. Will panic if the Constraint is not a Sub constraint. [caption=""] .Returns @@ -667,7 +667,7 @@ struct ConstraintVertex* constraint_sub_get_supertype(const struct ConstraintWit -Unwraps the ``Constraint`` instance as a Sub constraint, and returns the supertype vertex. Will panic if the Constraint is not a Sub constraint. +Unwraps the ``Constraint`` instance as a ``Sub`` constraint, and returns the supertype vertex. Will panic if the Constraint is not a Sub constraint. [caption=""] .Returns @@ -683,7 +683,7 @@ struct ConjunctionID* constraint_try_get_conjunction(const struct ConstraintWith -Unwraps the ``Constraint`` instance as a Try constraint, and returns the ``ConjunctionID`` of the optionally matched conjunction. Will panic if the Constraint is not a Try constraint. +Unwraps the ``Constraint`` instance as a ``Try`` constraint, and returns the ``ConjunctionID`` of the optionally matched conjunction. Will panic if the Constraint is not a Try constraint. [caption=""] .Returns @@ -699,7 +699,7 @@ struct ConstraintVertex* constraint_value_get_attribute_type(const struct Constr -Unwraps the ``Constraint`` instance as a Value constraint, and returns the attribute type vertex. Will panic if the Constraint is not a Value constraint. +Unwraps the ``Constraint`` instance as a ``Value`` constraint, and returns the attribute type vertex. Will panic if the Constraint is not a Value constraint. [caption=""] .Returns @@ -715,7 +715,7 @@ char* constraint_value_get_value_type(const struct ConstraintWithSpan* constrain -Unwraps the ``Constraint`` instance as a Value constraint, and returns the specified ValueType as a string. Will panic if the Constraint is not a Value constraint. +Unwraps the ``Constraint`` instance as a ``Value`` constraint, and returns the specified ValueType as a string. Will panic if the Constraint is not a Value constraint. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/analyze/constraintexactness.adoc b/docs/modules/ROOT/partials/c/analyze/constraintexactness.adoc index 157a9ce3b5..5e55ba3384 100644 --- a/docs/modules/ROOT/partials/c/analyze/constraintexactness.adoc +++ b/docs/modules/ROOT/partials/c/analyze/constraintexactness.adoc @@ -29,13 +29,13 @@ Tells apart exact variants of constraints from the ones allowing subtype-polymor Exact  -Indicates the constraint matches exactly the specified type - e.g. isa! or sub! +Indicates the constraint matches exactly the specified type - e.g. ``isa!`` or ``sub!`` Subtypes  -Indicates the constraint matches the specified type and its subtypes - e.g. isa! or sub! +Indicates the constraint matches the specified type and its subtypes - e.g. ``isa!`` or ``sub!`` diff --git a/docs/modules/ROOT/partials/c/analyze/reduceassignment.adoc b/docs/modules/ROOT/partials/c/analyze/reduceassignment.adoc index 71760bc372..ae8bc1690a 100644 --- a/docs/modules/ROOT/partials/c/analyze/reduceassignment.adoc +++ b/docs/modules/ROOT/partials/c/analyze/reduceassignment.adoc @@ -37,7 +37,7 @@ struct Variable* reduce_assignment_get_assigned(const struct ReduceAssignment* r -The variable being assigned to in this ReduceAssignment. e.g. $c in ``$c = sum($x)`` +The variable being assigned to in this ReduceAssignment. e.g. ``$c`` in ``$c = sum($x)`` [caption=""] .Returns @@ -53,7 +53,7 @@ struct Reducer* reduce_assignment_get_reducer(const struct ReduceAssignment* red -The reducer applied in this ReduceAssignment. e.g. sum($x) in ``$c = sum($x)`` +The reducer applied in this ReduceAssignment. e.g. ``sum($x)`` in ``$c = sum($x)`` [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/analyze/reducer.adoc b/docs/modules/ROOT/partials/c/analyze/reducer.adoc index 34f0088a76..e4aab5dd8c 100644 --- a/docs/modules/ROOT/partials/c/analyze/reducer.adoc +++ b/docs/modules/ROOT/partials/c/analyze/reducer.adoc @@ -37,7 +37,7 @@ struct VariableIterator* reducer_get_arguments(const struct Reducer* reducer) -The arguments to this Reducer. e.g. $x in ``sum($x)`` +The arguments to this Reducer. e.g. ``$x`` in ``sum($x)`` [caption=""] .Returns @@ -53,7 +53,7 @@ char* reducer_get_name(const struct Reducer* reducer) -The name of the operation applied by this Reducer. e.g. sum in ``sum($x)`` +The name of the operation applied by this Reducer. e.g. ``sum`` in ``sum($x)`` [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/concept/attribute.adoc b/docs/modules/ROOT/partials/c/concept/attribute.adoc index 83406cdc30..fd27cbe5da 100644 --- a/docs/modules/ROOT/partials/c/concept/attribute.adoc +++ b/docs/modules/ROOT/partials/c/concept/attribute.adoc @@ -11,7 +11,7 @@ struct Concept* attribute_get_type(const struct Concept* attribute) -Retrieves the type which this Attribute belongs to. +Retrieves the type which this ``Attribute`` belongs to. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/concept/entity.adoc b/docs/modules/ROOT/partials/c/concept/entity.adoc index 2a18395ede..2c9dd61e4b 100644 --- a/docs/modules/ROOT/partials/c/concept/entity.adoc +++ b/docs/modules/ROOT/partials/c/concept/entity.adoc @@ -11,7 +11,7 @@ struct Concept* entity_get_type(const struct Concept* entity) -Retrieves the type which this Entity belongs to. +Retrieves the type which this ``Entity`` belongs to. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/concept/relation.adoc b/docs/modules/ROOT/partials/c/concept/relation.adoc index ad9982a19f..c12ab91bae 100644 --- a/docs/modules/ROOT/partials/c/concept/relation.adoc +++ b/docs/modules/ROOT/partials/c/concept/relation.adoc @@ -11,7 +11,7 @@ struct Concept* relation_get_type(const struct Concept* relation) -Retrieves the type which this Relation belongs to. +Retrieves the type which this ``Relation`` belongs to. [caption=""] .Returns diff --git a/docs/modules/ROOT/partials/c/connection/driver.adoc b/docs/modules/ROOT/partials/c/connection/driver.adoc index c91fe36f2e..7a90ca5178 100644 --- a/docs/modules/ROOT/partials/c/connection/driver.adoc +++ b/docs/modules/ROOT/partials/c/connection/driver.adoc @@ -11,7 +11,7 @@ TLS configuration for the TypeDB driver. -DriverTlsConfig represents a fully constructed and validated TLS configuration. If TLS is enabled, the underlying TLS config is built eagerly at construction time, ensuring that no connection attempt can observe a partially-configured TLS state. +``DriverTlsConfig`` represents a fully constructed and validated TLS configuration. If TLS is enabled, the underlying TLS config is built eagerly at construction time, ensuring that no connection attempt can observe a partially-configured TLS state. The driver defaults to using TLS with native system trust roots. This matches typical system and container deployments while still allowing explicit opt-out or custom PKI configuration. @@ -556,8 +556,8 @@ Enables logging in the TypeDB driver. This function sets up tracing with two environment variables: - TYPEDB_DRIVER_LOG: Fine-grained control using the same syntax as RUST_LOG. Example: TYPEDB_DRIVER_LOG=typedb_driver=debug,typedb_driver_clib=trace - TYPEDB_DRIVER_LOG_LEVEL: Simple log level that applies to both typedb_driver and typedb_driver_clib crates. Overrides any settings from TYPEDB_DRIVER_LOG. Example: TYPEDB_DRIVER_LOG_LEVEL=debug + ``TYPEDB_DRIVER_LOG``: Fine-grained control using the same syntax as ``RUST_LOG``. Example: ``TYPEDB_DRIVER_LOG=typedb_driver=debug,typedb_driver_clib=trace`` + ``TYPEDB_DRIVER_LOG_LEVEL``: Simple log level that applies to both ``typedb_driver`` and ``typedb_driver_clib`` crates. Overrides any settings from ``TYPEDB_DRIVER_LOG``. Example: ``TYPEDB_DRIVER_LOG_LEVEL=debug`` If neither is set, the default level is INFO for driver crates. diff --git a/docs/modules/ROOT/partials/c/connection/driveroptions.adoc b/docs/modules/ROOT/partials/c/connection/driveroptions.adoc index 05a65c4bf9..091f13081f 100644 --- a/docs/modules/ROOT/partials/c/connection/driveroptions.adoc +++ b/docs/modules/ROOT/partials/c/connection/driveroptions.adoc @@ -9,7 +9,7 @@ -TypeDB driver connection options. DriverOptions object can be used to override the default driver behavior while connecting to TypeDB. +TypeDB driver connection options. ``DriverOptions`` object can be used to override the default driver behavior while connecting to TypeDB. [#_driver_options_drop] diff --git a/docs/modules/ROOT/partials/c/transaction/queryoptions.adoc b/docs/modules/ROOT/partials/c/transaction/queryoptions.adoc index 1699c0c59d..ed3a80dcc9 100644 --- a/docs/modules/ROOT/partials/c/transaction/queryoptions.adoc +++ b/docs/modules/ROOT/partials/c/transaction/queryoptions.adoc @@ -9,7 +9,7 @@ -TypeDB query options. QueryOptions object can be used to override the default server behaviour for executed queries. +TypeDB query options. ``QueryOptions`` object can be used to override the default server behaviour for executed queries. [#_query_options_drop] diff --git a/docs/modules/ROOT/partials/c/transaction/transaction.adoc b/docs/modules/ROOT/partials/c/transaction/transaction.adoc index 88aa8c556c..698ff57a3d 100644 --- a/docs/modules/ROOT/partials/c/transaction/transaction.adoc +++ b/docs/modules/ROOT/partials/c/transaction/transaction.adoc @@ -120,7 +120,7 @@ a| `options` a| ``TransactionOptions`` to configure the opened transaction. a| ` [source,c] ---- -struct VoidPromise* transaction_on_close(const struct Transaction* txn, uintptr_t callback_id, void(* callback)(uintptr_t, struct Error*)) +struct VoidPromise* transaction_on_close(const struct Transaction* txn, uintptr_t callback_id, void(*)(uintptr_t, struct Error*) callback) ---- @@ -136,7 +136,7 @@ Registers a callback function which will be executed when this transaction is cl |Name |Description |Type a| `txn` a| The transaction on which to register the callback a| `const struct Transaction*` a| `callback_id` a| The argument to be passed to the callback function when it is executed. a| `uintptr_t` -a| `callback` a| The function to be called a| `void(*` +a| `callback` a| The function to be called a| |=== [caption=""] diff --git a/docs/modules/ROOT/partials/c/transaction/transactionoptions.adoc b/docs/modules/ROOT/partials/c/transaction/transactionoptions.adoc index 054a03054b..e59ee91161 100644 --- a/docs/modules/ROOT/partials/c/transaction/transactionoptions.adoc +++ b/docs/modules/ROOT/partials/c/transaction/transactionoptions.adoc @@ -9,7 +9,7 @@ -TypeDB transaction options. TransactionOptions object can be used to override the default behaviour for opened transactions. +TypeDB transaction options. ``TransactionOptions`` object can be used to override the default behaviour for opened transactions. [#_transaction_options_drop] From cf2fd0e84c256d30b3881d412e891cf8ebd6fac2 Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Wed, 18 Feb 2026 18:16:43 +0000 Subject: [PATCH 06/10] Fix bdd tests --- java/test/behaviour/config/Parameters.java | 4 ++-- rust/tests/behaviour/steps/params.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/test/behaviour/config/Parameters.java b/java/test/behaviour/config/Parameters.java index c1d8c0e250..4696475132 100644 --- a/java/test/behaviour/config/Parameters.java +++ b/java/test/behaviour/config/Parameters.java @@ -44,8 +44,8 @@ public class Parameters { private static boolean clusterMode = false; - private static final int RETRY_ATTEMPTS = 3; - private static final int RETRY_DELAY_MS = 500; + private static final int RETRY_ATTEMPTS = 10; + private static final int RETRY_DELAY_MS = 1000; public static void setClusterMode(boolean isCluster) { clusterMode = isCluster; diff --git a/rust/tests/behaviour/steps/params.rs b/rust/tests/behaviour/steps/params.rs index 7b2669bcf4..b1b419b4fc 100644 --- a/rust/tests/behaviour/steps/params.rs +++ b/rust/tests/behaviour/steps/params.rs @@ -36,8 +36,8 @@ pub struct Value { impl Value { const DATETIME_FORMATS: [&'static str; 8] = [ - "%Y-%m-%dT%H:%M:%S%.9f", - "%Y-%m-%d %H:%M:%S%.9f", + "%Y-%m-%dT%H:%M:%S%.f", + "%Y-%m-%d %H:%M:%S%.f", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S", "%Y-%m-%dT%H:%M", From 71d2af87bf7eecba3d6b88da387042a751afdc8d Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Wed, 18 Feb 2026 19:00:43 +0000 Subject: [PATCH 07/10] Try fixing tests --- java/test/behaviour/config/Parameters.java | 4 ++-- rust/src/common/error.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java/test/behaviour/config/Parameters.java b/java/test/behaviour/config/Parameters.java index 4696475132..c1d8c0e250 100644 --- a/java/test/behaviour/config/Parameters.java +++ b/java/test/behaviour/config/Parameters.java @@ -44,8 +44,8 @@ public class Parameters { private static boolean clusterMode = false; - private static final int RETRY_ATTEMPTS = 10; - private static final int RETRY_DELAY_MS = 1000; + private static final int RETRY_ATTEMPTS = 3; + private static final int RETRY_DELAY_MS = 500; public static void setClusterMode(boolean isCluster) { clusterMode = isCluster; diff --git a/rust/src/common/error.rs b/rust/src/common/error.rs index d17cf8320c..0f16adb879 100644 --- a/rust/src/common/error.rs +++ b/rust/src/common/error.rs @@ -354,7 +354,7 @@ impl Error { fn try_extracting_connection_error_code(code: &str) -> Option { match code { - "AUT2" | "AUT3" => Some(ConnectionError::TokenCredentialInvalid {}), + "AUT1" | "AUT2" | "AUT3" => Some(ConnectionError::TokenCredentialInvalid {}), "SRV14" | "RFT1" | "CSV7" => Some(ConnectionError::ServerIsNotInitialised {}), "CSV8" => Some(ConnectionError::ClusterReplicaNotPrimary {}), _ => None, From 1bf0c0251d99df34872c19330580400b68272d39 Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Thu, 19 Feb 2026 10:35:23 +0000 Subject: [PATCH 08/10] Don't consider AUT1 error as invalid token cred --- rust/src/common/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/src/common/error.rs b/rust/src/common/error.rs index 0f16adb879..d17cf8320c 100644 --- a/rust/src/common/error.rs +++ b/rust/src/common/error.rs @@ -354,7 +354,7 @@ impl Error { fn try_extracting_connection_error_code(code: &str) -> Option { match code { - "AUT1" | "AUT2" | "AUT3" => Some(ConnectionError::TokenCredentialInvalid {}), + "AUT2" | "AUT3" => Some(ConnectionError::TokenCredentialInvalid {}), "SRV14" | "RFT1" | "CSV7" => Some(ConnectionError::ServerIsNotInitialised {}), "CSV8" => Some(ConnectionError::ClusterReplicaNotPrimary {}), _ => None, From 5cb7fa90e92b779bd0398c59e2f25e8cb32dd70f Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Thu, 19 Feb 2026 12:07:01 +0000 Subject: [PATCH 09/10] Register AUT1 as an auth error --- rust/src/common/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/src/common/error.rs b/rust/src/common/error.rs index d17cf8320c..5afe347199 100644 --- a/rust/src/common/error.rs +++ b/rust/src/common/error.rs @@ -157,7 +157,7 @@ error_messages! { ConnectionError UnknownDirectReplica { address: Address, configured_addresses: Addresses } = 16: "Could not execute operation against '{address}' since it's not a known replica of configured addresses ({configured_addresses}).", TokenCredentialInvalid = - 17: "Invalid token credentials.", + 17: "Invalid credential supplied.", EncryptionSettingsMismatch = 18: "Unable to connect to TypeDB: possible encryption settings mismatch.", SslCertificateNotValidated = @@ -354,7 +354,7 @@ impl Error { fn try_extracting_connection_error_code(code: &str) -> Option { match code { - "AUT2" | "AUT3" => Some(ConnectionError::TokenCredentialInvalid {}), + "AUT1" | "AUT2" | "AUT3" => Some(ConnectionError::TokenCredentialInvalid {}), "SRV14" | "RFT1" | "CSV7" => Some(ConnectionError::ServerIsNotInitialised {}), "CSV8" => Some(ConnectionError::ClusterReplicaNotPrimary {}), _ => None, From 3b742b61607526b0c767af5d8b496d26970784ba Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Thu, 19 Feb 2026 12:39:05 +0000 Subject: [PATCH 10/10] Prepare for release 3.8.0-alpha-1 --- RELEASE_NOTES_LATEST.md | 65 +++++------------------------------------ VERSION | 2 +- 2 files changed, 9 insertions(+), 58 deletions(-) diff --git a/RELEASE_NOTES_LATEST.md b/RELEASE_NOTES_LATEST.md index e0714e3a82..ce2202edbb 100644 --- a/RELEASE_NOTES_LATEST.md +++ b/RELEASE_NOTES_LATEST.md @@ -12,13 +12,13 @@ Documentation: https://typedb.com/docs/drivers/rust/overview ```sh -cargo add typedb-driver@3.7.0-alpha-3 +cargo add typedb-driver@3.8.0-alpha-1 ``` ### Java driver -Available through [https://repo.typedb.com](https://cloudsmith.io/~typedb/repos/public-release/packages/detail/maven/typedb-driver/3.7.0-alpha-3/a=noarch;xg=com.typedb/) +Available through [https://repo.typedb.com](https://cloudsmith.io/~typedb/repos/public-release/packages/detail/maven/typedb-driver/3.8.0-alpha-1/a=noarch;xg=com.typedb/) Documentation: https://typedb.com/docs/drivers/java/overview **ATTENTION:** since this is an alpha version of a clustered TypeDB, the API is unstable and can drastically change between versions. @@ -35,7 +35,7 @@ Use this driver only for the same `XYZ-alpha-A` version of the server. com.typedb typedb-driver - 3.7.0-alpha-3 + 3.8.0-alpha-1 ``` @@ -51,65 +51,16 @@ Use this driver only for the same `XYZ-alpha-A` version of the server. Available through https://pypi.org ``` -pip install typedb-driver==3.7.0a2 +pip install typedb-driver==3.8.0a1 ``` ### C driver -Compiled distributions comprising headers and shared libraries available at: https://cloudsmith.io/~typedb/repos/public-release/packages/?q=name:^typedb-driver-clib+version:3.7.0-alpha-3 +Compiled distributions comprising headers and shared libraries available at: https://cloudsmith.io/~typedb/repos/public-release/packages/?q=name:^typedb-driver-clib+version:3.8.0-alpha-1 -## New Features +## Bug fixes -### Refactor DriverOptions' TLS configuration +### Fix various build-related bugs -Introduce `DriverTlsConfig` with three possible constructors to eliminate ambiguity of TLS settings: - -- disabled -- enabled using default native root CA -- enabled using custom root CA - -Now, `DriverOptions` contain a separate `tls_config` field instead of `is_tls_enabled` and `tls_root_ca`, and every -`DriverOptions` object requires an instance of `DriverTlsConfig` on construction to provide explicit TLS connection -preferences. - -#### Examples - -Rust: -```rust -// Default: TLS enabled with native system trust roots -let options = DriverOptions::new(DriverTlsConfig::enabled_with_native_root_ca()).use_replication(true); - -// Custom CA (PEM) for private PKI / self-signed deployments -let options_custom_ca = DriverOptions::new( - DriverTlsConfig::enabled_with_root_ca(Path::new("path/to/ca-certificate.pem")).unwrap(), -); - -// Disable TLS (NOT recommended) -let options_insecure = DriverOptions::new(DriverTlsConfig::disabled()); -``` - -Java: -```java -// Default: TLS enabled with native system trust roots -DriverOptions options = new DriverOptions(DriverTlsConfig.enabledWithNativeRootCA()).useReplication(true); - -// Custom CA (PEM) for private PKI / self-signed deployments -DriverOptions optionsCustomCA = new DriverOptions(DriverTlsConfig.enabledWithRootCA("path/to/ca-certificate.pem")); - -// Disable TLS (NOT recommended) -DriverOptions optionsInsecure = new DriverOptions(DriverTlsConfig.disabled()); -``` - -Python: -```py -# Default/recommended: TLS enabled with native system trust roots -options = DriverOptions(DriverTlsConfig.enabled_with_native_root_ca(), use_replication=True) - -# Custom CA (PEM) for private PKI / self-signed deployments -options_custom_ca = DriverOptions(DriverTlsConfig.enabled_with_root_ca("path/to/ca-certificate.pem")) -options_custom_ca.use_replication = True # Post-construction setter - -# Disable TLS (NOT recommended) -options_insecure = DriverOptions(DriverTlsConfig.disabled()) -``` +Now, all features of the updated drivers must work correctly. Visit https://typedb.com/docs/reference/typedb-cluster/drivers/ for usage examples and more info. diff --git a/VERSION b/VERSION index c44e262d77..2f785341f6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.7.0-alpha-3 \ No newline at end of file +3.8.0-alpha-1 \ No newline at end of file