-
Notifications
You must be signed in to change notification settings - Fork 58
Query service client support #455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 52 commits
Commits
Show all changes
57 commits
Select commit
Hold shift + click to select a range
f4ebefc
Add query service to apis
vgvoleg 4a576b9
session create
vgvoleg 415c567
session delete
vgvoleg 8f345ac
temp
vgvoleg 0ffe545
Refactor wrappers to split UnaryStream and StreamStream wrappers
vgvoleg f266cbb
attach session
vgvoleg 1f9c728
Added base module and wrappers
vgvoleg 1b0d58e
refactor session
vgvoleg 8e80cac
added basic test for session
vgvoleg c4fb819
added test to double session create
vgvoleg ff59697
some more wrappers
vgvoleg 7a4f4e7
simple execute on session
vgvoleg 5eaeddc
temp
vgvoleg 4c85d76
wow tx begin works
vgvoleg 2ce3d6e
tx state handler
vgvoleg 75ea82d
refactor session
vgvoleg d9a0424
refactor transaction
vgvoleg e820764
codestyles fixes
vgvoleg 779950f
codestyle fixes
vgvoleg 66bfe09
more style fixes
vgvoleg 1195c4f
please tox im tired
vgvoleg 802c841
basic pool & retries & example
vgvoleg 16c1c06
style fixes
vgvoleg a11e42a
style fixes
vgvoleg f27658f
style fixes
vgvoleg e580dc2
add dunder all to query module
vgvoleg 424f831
style fix
vgvoleg c90ccf4
ability to execute ddl queries
vgvoleg 6a740e4
Revert "Refactor wrappers to split UnaryStream and StreamStream wrapp…
vgvoleg 825c462
new details to example
vgvoleg 49cdce0
style fixes
vgvoleg daea8a9
style fixes
vgvoleg 89846fd
omit flag in client side
vgvoleg 199e8d7
pass args to session execute
vgvoleg c3d1d2b
style fixes
vgvoleg ec7274f
interactive tx support
vgvoleg 6b07d63
fix test errors
vgvoleg 1d1e312
QuerySessionPool docstring
vgvoleg bbd47da
Fix tests naming
vgvoleg a1f513a
tx context manager tests
vgvoleg 68ce180
add typing to tests
vgvoleg 690c974
style fix
vgvoleg c8e74a8
move retry logic to standalone module
vgvoleg 249e569
response iterator as context manager
vgvoleg 8bb8a6f
make retries module public
vgvoleg 56f7b24
query session pool tests
vgvoleg aa76736
style fixes
vgvoleg 8f3b8af
docstrings for base interfaces
vgvoleg 24852f5
add logs about experimental api
vgvoleg b4eeb02
fixes after review
vgvoleg 6f980fe
fix review comments
vgvoleg c0b125a
review fixes
vgvoleg d0c9388
fix review
vgvoleg 2d8a2ff
style fixes
vgvoleg 630c188
fixes
vgvoleg 2336624
review fixes
vgvoleg 49e7471
review fixes
vgvoleg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import ydb | ||
|
||
|
||
def main(): | ||
driver_config = ydb.DriverConfig( | ||
endpoint="grpc://localhost:2136", | ||
database="/local", | ||
# credentials=ydb.credentials_from_env_variables(), | ||
# root_certificates=ydb.load_ydb_root_certificate(), | ||
) | ||
try: | ||
driver = ydb.Driver(driver_config) | ||
driver.wait(timeout=5) | ||
except TimeoutError: | ||
raise RuntimeError("Connect failed to YDB") | ||
|
||
pool = ydb.QuerySessionPool(driver) | ||
|
||
print("=" * 50) | ||
print("DELETE TABLE IF EXISTS") | ||
pool.execute_with_retries("drop table if exists example") | ||
|
||
print("=" * 50) | ||
print("CREATE TABLE") | ||
pool.execute_with_retries("CREATE TABLE example(key UInt64, value String, PRIMARY KEY (key))") | ||
|
||
pool.execute_with_retries("INSERT INTO example (key, value) VALUES (1, 'onepieceisreal')") | ||
|
||
def callee(session): | ||
print("=" * 50) | ||
with session.execute("delete from example"): | ||
pass | ||
|
||
print("BEFORE ACTION") | ||
with session.execute("SELECT COUNT(*) as rows_count FROM example") as results: | ||
for result_set in results: | ||
print(f"rows: {str(result_set.rows)}") | ||
|
||
print("=" * 50) | ||
print("INSERT WITH COMMIT TX") | ||
|
||
with session.transaction() as tx: | ||
tx.begin() | ||
|
||
with tx.execute("INSERT INTO example (key, value) VALUES (1, 'onepieceisreal')"): | ||
pass | ||
|
||
with tx.execute("SELECT COUNT(*) as rows_count FROM example") as results: | ||
for result_set in results: | ||
print(f"rows: {str(result_set.rows)}") | ||
|
||
tx.commit() | ||
|
||
print("=" * 50) | ||
print("AFTER COMMIT TX") | ||
|
||
with session.execute("SELECT COUNT(*) as rows_count FROM example") as results: | ||
for result_set in results: | ||
print(f"rows: {str(result_set.rows)}") | ||
|
||
print("=" * 50) | ||
print("INSERT WITH ROLLBACK TX") | ||
|
||
with session.transaction() as tx: | ||
tx.begin() | ||
|
||
with tx.execute("INSERT INTO example (key, value) VALUES (2, 'onepieceisreal')"): | ||
pass | ||
|
||
with tx.execute("SELECT COUNT(*) as rows_count FROM example") as results: | ||
for result_set in results: | ||
print(f"rows: {str(result_set.rows)}") | ||
|
||
tx.rollback() | ||
|
||
print("=" * 50) | ||
print("AFTER ROLLBACK TX") | ||
|
||
with session.execute("SELECT COUNT(*) as rows_count FROM example") as results: | ||
for result_set in results: | ||
print(f"rows: {str(result_set.rows)}") | ||
|
||
pool.retry_operation_sync(callee) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import pytest | ||
from ydb.query.session import QuerySessionSync | ||
from ydb.query.pool import QuerySessionPool | ||
|
||
|
||
@pytest.fixture | ||
def session(driver_sync): | ||
session = QuerySessionSync(driver_sync) | ||
|
||
yield session | ||
|
||
try: | ||
session.delete() | ||
except BaseException: | ||
pass | ||
|
||
|
||
@pytest.fixture | ||
def tx(session): | ||
session.create() | ||
transaction = session.transaction() | ||
|
||
yield transaction | ||
|
||
try: | ||
transaction.rollback() | ||
except BaseException: | ||
pass | ||
|
||
|
||
@pytest.fixture | ||
def pool(driver_sync): | ||
pool = QuerySessionPool(driver_sync) | ||
yield pool |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import pytest | ||
|
||
from ydb.query.session import QuerySessionSync | ||
|
||
|
||
def _check_session_state_empty(session: QuerySessionSync): | ||
assert session._state.session_id is None | ||
assert session._state.node_id is None | ||
assert not session._state.attached | ||
|
||
|
||
def _check_session_state_full(session: QuerySessionSync): | ||
assert session._state.session_id is not None | ||
assert session._state.node_id is not None | ||
assert session._state.attached | ||
|
||
|
||
class TestQuerySession: | ||
def test_session_normal_lifecycle(self, session: QuerySessionSync): | ||
_check_session_state_empty(session) | ||
|
||
session.create() | ||
_check_session_state_full(session) | ||
|
||
session.delete() | ||
_check_session_state_empty(session) | ||
|
||
def test_second_create_do_nothing(self, session: QuerySessionSync): | ||
session.create() | ||
_check_session_state_full(session) | ||
|
||
session_id_before = session._state.session_id | ||
node_id_before = session._state.node_id | ||
|
||
session.create() | ||
_check_session_state_full(session) | ||
|
||
assert session._state.session_id == session_id_before | ||
assert session._state.node_id == node_id_before | ||
|
||
def test_second_delete_do_nothing(self, session: QuerySessionSync): | ||
session.create() | ||
|
||
session.delete() | ||
session.delete() | ||
|
||
def test_delete_before_create_not_possible(self, session: QuerySessionSync): | ||
with pytest.raises(RuntimeError): | ||
session.delete() | ||
|
||
def test_create_after_delete_not_possible(self, session: QuerySessionSync): | ||
session.create() | ||
session.delete() | ||
with pytest.raises(RuntimeError): | ||
session.create() | ||
|
||
def test_transaction_before_create_raises(self, session: QuerySessionSync): | ||
with pytest.raises(RuntimeError): | ||
session.transaction() | ||
|
||
def test_transaction_after_delete_raises(self, session: QuerySessionSync): | ||
session.create() | ||
|
||
session.delete() | ||
|
||
with pytest.raises(RuntimeError): | ||
session.transaction() | ||
|
||
def test_transaction_after_create_not_raises(self, session: QuerySessionSync): | ||
session.create() | ||
session.transaction() | ||
|
||
def test_execute_before_create_raises(self, session: QuerySessionSync): | ||
with pytest.raises(RuntimeError): | ||
session.execute("select 1;") | ||
|
||
def test_execute_after_delete_raises(self, session: QuerySessionSync): | ||
session.create() | ||
session.delete() | ||
with pytest.raises(RuntimeError): | ||
session.execute("select 1;") | ||
|
||
def test_basic_execute(self, session: QuerySessionSync): | ||
session.create() | ||
it = session.execute("select 1;") | ||
result_sets = [result_set for result_set in it] | ||
|
||
assert len(result_sets) == 1 | ||
assert len(result_sets[0].rows) == 1 | ||
assert len(result_sets[0].columns) == 1 | ||
assert list(result_sets[0].rows[0].values()) == [1] | ||
rekby marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import pytest | ||
import ydb | ||
from ydb.query.pool import QuerySessionPool | ||
from ydb.query.session import QuerySessionSync, QuerySessionStateEnum | ||
|
||
|
||
class TestQuerySessionPool: | ||
def test_checkout_provides_created_session(self, pool: QuerySessionPool): | ||
with pool.checkout() as session: | ||
assert session._state._state == QuerySessionStateEnum.CREATED | ||
|
||
assert session._state._state == QuerySessionStateEnum.CLOSED | ||
|
||
def test_oneshot_query_normal(self, pool: QuerySessionPool): | ||
res = pool.execute_with_retries("select 1;") | ||
assert len(res) == 1 | ||
|
||
def test_oneshot_ddl_query(self, pool: QuerySessionPool): | ||
pool.execute_with_retries("create table Queen(key UInt64, PRIMARY KEY (key));") | ||
pool.execute_with_retries("drop table Queen;") | ||
|
||
def test_oneshot_query_raises(self, pool: QuerySessionPool): | ||
with pytest.raises(ydb.GenericError): | ||
pool.execute_with_retries("Is this the real life? Is this just fantasy?") | ||
vgvoleg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def test_retry_op_uses_created_session(self, pool: QuerySessionPool): | ||
def callee(session: QuerySessionSync): | ||
assert session._state._state == QuerySessionStateEnum.CREATED | ||
|
||
pool.retry_operation_sync(callee) | ||
|
||
def test_retry_op_normal(self, pool: QuerySessionPool): | ||
def callee(session: QuerySessionSync): | ||
with session.transaction() as tx: | ||
iterator = tx.execute("select 1;", commit_tx=True) | ||
return [result_set for result_set in iterator] | ||
|
||
res = pool.retry_operation_sync(callee) | ||
assert len(res) == 1 | ||
|
||
def test_retry_op_raises(self, pool: QuerySessionPool): | ||
class CustomException(Exception): | ||
pass | ||
|
||
def callee(session: QuerySessionSync): | ||
raise CustomException() | ||
|
||
with pytest.raises(CustomException): | ||
pool.retry_operation_sync(callee) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import pytest | ||
|
||
from ydb.query.transaction import BaseTxContext | ||
from ydb.query.transaction import QueryTxStateEnum | ||
|
||
|
||
class TestQueryTransaction: | ||
def test_tx_begin(self, tx: BaseTxContext): | ||
assert tx.tx_id is None | ||
|
||
tx.begin() | ||
assert tx.tx_id is not None | ||
|
||
def test_tx_allow_double_commit(self, tx: BaseTxContext): | ||
tx.begin() | ||
tx.commit() | ||
tx.commit() | ||
|
||
def test_tx_allow_double_rollback(self, tx: BaseTxContext): | ||
tx.begin() | ||
tx.rollback() | ||
tx.rollback() | ||
|
||
def test_tx_commit_before_begin(self, tx: BaseTxContext): | ||
tx.commit() | ||
assert tx._tx_state._state == QueryTxStateEnum.COMMITTED | ||
|
||
def test_tx_rollback_before_begin(self, tx: BaseTxContext): | ||
tx.rollback() | ||
assert tx._tx_state._state == QueryTxStateEnum.ROLLBACKED | ||
|
||
def test_tx_first_execute_begins_tx(self, tx: BaseTxContext): | ||
tx.execute("select 1;") | ||
tx.commit() | ||
|
||
def test_interactive_tx_commit(self, tx: BaseTxContext): | ||
tx.execute("select 1;", commit_tx=True) | ||
with pytest.raises(RuntimeError): | ||
tx.execute("select 1;") | ||
|
||
def test_tx_execute_raises_after_commit(self, tx: BaseTxContext): | ||
tx.begin() | ||
tx.commit() | ||
with pytest.raises(RuntimeError): | ||
tx.execute("select 1;") | ||
|
||
def test_tx_execute_raises_after_rollback(self, tx: BaseTxContext): | ||
tx.begin() | ||
tx.rollback() | ||
with pytest.raises(RuntimeError): | ||
tx.execute("select 1;") | ||
|
||
def test_context_manager_rollbacks_tx(self, tx: BaseTxContext): | ||
with tx: | ||
tx.begin() | ||
|
||
assert tx._tx_state._state == QueryTxStateEnum.ROLLBACKED | ||
|
||
def test_context_manager_normal_flow(self, tx: BaseTxContext): | ||
with tx: | ||
tx.begin() | ||
tx.execute("select 1;") | ||
tx.commit() | ||
|
||
assert tx._tx_state._state == QueryTxStateEnum.COMMITTED | ||
|
||
def test_context_manager_does_not_hide_exceptions(self, tx: BaseTxContext): | ||
class CustomException(Exception): | ||
pass | ||
|
||
with pytest.raises(CustomException): | ||
with tx: | ||
raise CustomException() | ||
|
||
def test_execute_as_context_manager(self, tx: BaseTxContext): | ||
tx.begin() | ||
|
||
with tx.execute("select 1;") as results: | ||
res = [result_set for result_set in results] | ||
|
||
assert len(res) == 1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need common style, with other example queries.
now
delete
, butCREATE
. I prefer capital case for SQL commands (as CREATE)