real-ladybug 0.0.1.dev1__cp311-cp311-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of real-ladybug might be problematic. Click here for more details.
- real_ladybug/__init__.py +83 -0
- real_ladybug/_lbug.cp311-win_amd64.pyd +0 -0
- real_ladybug/_lbug.exp +0 -0
- real_ladybug/_lbug.lib +0 -0
- real_ladybug/async_connection.py +226 -0
- real_ladybug/connection.py +323 -0
- real_ladybug/constants.py +7 -0
- real_ladybug/database.py +307 -0
- real_ladybug/prepared_statement.py +51 -0
- real_ladybug/py.typed +0 -0
- real_ladybug/query_result.py +511 -0
- real_ladybug/torch_geometric_feature_store.py +185 -0
- real_ladybug/torch_geometric_graph_store.py +131 -0
- real_ladybug/torch_geometric_result_converter.py +282 -0
- real_ladybug/types.py +39 -0
- real_ladybug-0.0.1.dev1.dist-info/METADATA +88 -0
- real_ladybug-0.0.1.dev1.dist-info/RECORD +114 -0
- real_ladybug-0.0.1.dev1.dist-info/WHEEL +5 -0
- real_ladybug-0.0.1.dev1.dist-info/licenses/LICENSE +21 -0
- real_ladybug-0.0.1.dev1.dist-info/top_level.txt +3 -0
- real_ladybug-0.0.1.dev1.dist-info/zip-safe +1 -0
- real_ladybug-source/scripts/antlr4/hash.py +2 -0
- real_ladybug-source/scripts/antlr4/keywordhandler.py +47 -0
- real_ladybug-source/scripts/collect-extensions.py +68 -0
- real_ladybug-source/scripts/collect-single-file-header.py +126 -0
- real_ladybug-source/scripts/export-dbs.py +101 -0
- real_ladybug-source/scripts/export-import-test.py +345 -0
- real_ladybug-source/scripts/extension/purge-beta.py +34 -0
- real_ladybug-source/scripts/generate-cpp-docs/collect_files.py +122 -0
- real_ladybug-source/scripts/generate-tinysnb.py +34 -0
- real_ladybug-source/scripts/get-clangd-diagnostics.py +233 -0
- real_ladybug-source/scripts/migrate-lbug-db.py +308 -0
- real_ladybug-source/scripts/multiplatform-test-helper/collect-results.py +71 -0
- real_ladybug-source/scripts/multiplatform-test-helper/notify-discord.py +68 -0
- real_ladybug-source/scripts/pip-package/package_tar.py +90 -0
- real_ladybug-source/scripts/pip-package/setup.py +130 -0
- real_ladybug-source/scripts/run-clang-format.py +408 -0
- real_ladybug-source/scripts/setup-extension-repo.py +67 -0
- real_ladybug-source/scripts/test-simsimd-dispatch.py +45 -0
- real_ladybug-source/scripts/update-nightly-build-version.py +81 -0
- real_ladybug-source/third_party/brotli/scripts/dictionary/step-01-download-rfc.py +16 -0
- real_ladybug-source/third_party/brotli/scripts/dictionary/step-02-rfc-to-bin.py +34 -0
- real_ladybug-source/third_party/brotli/scripts/dictionary/step-03-validate-bin.py +35 -0
- real_ladybug-source/third_party/brotli/scripts/dictionary/step-04-generate-java-literals.py +85 -0
- real_ladybug-source/third_party/pybind11/tools/codespell_ignore_lines_from_errors.py +35 -0
- real_ladybug-source/third_party/pybind11/tools/libsize.py +36 -0
- real_ladybug-source/third_party/pybind11/tools/make_changelog.py +63 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/__init__.py +83 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/async_connection.py +226 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/connection.py +323 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/constants.py +7 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/database.py +307 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/prepared_statement.py +51 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/py.typed +0 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/query_result.py +511 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/torch_geometric_feature_store.py +185 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/torch_geometric_graph_store.py +131 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/torch_geometric_result_converter.py +282 -0
- real_ladybug-source/tools/python_api/build/real_ladybug/types.py +39 -0
- real_ladybug-source/tools/python_api/src_py/__init__.py +83 -0
- real_ladybug-source/tools/python_api/src_py/async_connection.py +226 -0
- real_ladybug-source/tools/python_api/src_py/connection.py +323 -0
- real_ladybug-source/tools/python_api/src_py/constants.py +7 -0
- real_ladybug-source/tools/python_api/src_py/database.py +307 -0
- real_ladybug-source/tools/python_api/src_py/prepared_statement.py +51 -0
- real_ladybug-source/tools/python_api/src_py/py.typed +0 -0
- real_ladybug-source/tools/python_api/src_py/query_result.py +511 -0
- real_ladybug-source/tools/python_api/src_py/torch_geometric_feature_store.py +185 -0
- real_ladybug-source/tools/python_api/src_py/torch_geometric_graph_store.py +131 -0
- real_ladybug-source/tools/python_api/src_py/torch_geometric_result_converter.py +282 -0
- real_ladybug-source/tools/python_api/src_py/types.py +39 -0
- real_ladybug-source/tools/python_api/test/conftest.py +230 -0
- real_ladybug-source/tools/python_api/test/disabled_test_extension.py +73 -0
- real_ladybug-source/tools/python_api/test/ground_truth.py +430 -0
- real_ladybug-source/tools/python_api/test/test_arrow.py +694 -0
- real_ladybug-source/tools/python_api/test/test_async_connection.py +159 -0
- real_ladybug-source/tools/python_api/test/test_blob_parameter.py +145 -0
- real_ladybug-source/tools/python_api/test/test_connection.py +49 -0
- real_ladybug-source/tools/python_api/test/test_database.py +234 -0
- real_ladybug-source/tools/python_api/test/test_datatype.py +372 -0
- real_ladybug-source/tools/python_api/test/test_df.py +564 -0
- real_ladybug-source/tools/python_api/test/test_dict.py +112 -0
- real_ladybug-source/tools/python_api/test/test_exception.py +54 -0
- real_ladybug-source/tools/python_api/test/test_fsm.py +227 -0
- real_ladybug-source/tools/python_api/test/test_get_header.py +49 -0
- real_ladybug-source/tools/python_api/test/test_helper.py +8 -0
- real_ladybug-source/tools/python_api/test/test_issue.py +147 -0
- real_ladybug-source/tools/python_api/test/test_iteration.py +96 -0
- real_ladybug-source/tools/python_api/test/test_networkx.py +437 -0
- real_ladybug-source/tools/python_api/test/test_parameter.py +340 -0
- real_ladybug-source/tools/python_api/test/test_prepared_statement.py +117 -0
- real_ladybug-source/tools/python_api/test/test_query_result.py +54 -0
- real_ladybug-source/tools/python_api/test/test_query_result_close.py +44 -0
- real_ladybug-source/tools/python_api/test/test_scan_pandas.py +676 -0
- real_ladybug-source/tools/python_api/test/test_scan_pandas_pyarrow.py +714 -0
- real_ladybug-source/tools/python_api/test/test_scan_polars.py +165 -0
- real_ladybug-source/tools/python_api/test/test_scan_pyarrow.py +167 -0
- real_ladybug-source/tools/python_api/test/test_timeout.py +11 -0
- real_ladybug-source/tools/python_api/test/test_torch_geometric.py +640 -0
- real_ladybug-source/tools/python_api/test/test_torch_geometric_remote_backend.py +111 -0
- real_ladybug-source/tools/python_api/test/test_udf.py +207 -0
- real_ladybug-source/tools/python_api/test/test_version.py +6 -0
- real_ladybug-source/tools/python_api/test/test_wal.py +80 -0
- real_ladybug-source/tools/python_api/test/type_aliases.py +10 -0
- real_ladybug-source/tools/rust_api/update_version.py +47 -0
- real_ladybug-source/tools/shell/test/conftest.py +218 -0
- real_ladybug-source/tools/shell/test/test_helper.py +60 -0
- real_ladybug-source/tools/shell/test/test_shell_basics.py +325 -0
- real_ladybug-source/tools/shell/test/test_shell_commands.py +656 -0
- real_ladybug-source/tools/shell/test/test_shell_control_edit.py +438 -0
- real_ladybug-source/tools/shell/test/test_shell_control_search.py +468 -0
- real_ladybug-source/tools/shell/test/test_shell_esc_edit.py +232 -0
- real_ladybug-source/tools/shell/test/test_shell_esc_search.py +162 -0
- real_ladybug-source/tools/shell/test/test_shell_flags.py +645 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from type_aliases import ConnDB
|
|
8
|
+
|
|
9
|
+
# required by python-lint
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
import real_ladybug as lb
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_struct_param_access(conn_db_readwrite: ConnDB) -> None:
|
|
16
|
+
conn, _ = conn_db_readwrite
|
|
17
|
+
batch = [
|
|
18
|
+
{
|
|
19
|
+
"id": "1",
|
|
20
|
+
"name": "Christopher",
|
|
21
|
+
"age": "61",
|
|
22
|
+
"net_worth": "21561030.8",
|
|
23
|
+
"email": "wilcox@hotmail.com",
|
|
24
|
+
"address": "588 Campbell Well Suite 335, Lawrencemouth, VI 07241",
|
|
25
|
+
"phone": "358-202-1821x630",
|
|
26
|
+
"comments": "Stage modern card send point future serve. Hot month might pass dinner chance.\nPerformance become own spring from analysis commercial. Draw effort structure many drug first.",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "2",
|
|
30
|
+
"name": "Amanda",
|
|
31
|
+
"age": "42",
|
|
32
|
+
"net_worth": "31344480.2",
|
|
33
|
+
"email": "cook@hotmail.com",
|
|
34
|
+
"address": "6293 Bright Centers, Chenton, MO 36829",
|
|
35
|
+
"phone": "001-972-387-3913x966",
|
|
36
|
+
"comments": "None agent some if skill. Often onto dog wish. Listen live hair garden contain worry time. Economic or institution statement energy take sit.",
|
|
37
|
+
},
|
|
38
|
+
]
|
|
39
|
+
conn.execute(
|
|
40
|
+
"""
|
|
41
|
+
UNWIND $batch AS p
|
|
42
|
+
RETURN p.name,
|
|
43
|
+
p.age,
|
|
44
|
+
p.net_worth,
|
|
45
|
+
p.email,
|
|
46
|
+
p.address,
|
|
47
|
+
p.phone,
|
|
48
|
+
p.comments
|
|
49
|
+
""",
|
|
50
|
+
parameters={"batch": batch},
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_array_binding(conn_db_readwrite: ConnDB) -> None:
|
|
55
|
+
conn, _ = conn_db_readwrite
|
|
56
|
+
conn.execute("CREATE NODE TABLE node(id STRING, embedding DOUBLE[3], PRIMARY KEY(id))")
|
|
57
|
+
conn.execute("CREATE (d:node {id: 'test', embedding: $emb})", {"emb": [3, 5, 2]})
|
|
58
|
+
result = conn.execute(
|
|
59
|
+
"""
|
|
60
|
+
MATCH (d:node)
|
|
61
|
+
RETURN d.id, array_cosine_similarity(d.embedding, $emb)
|
|
62
|
+
""",
|
|
63
|
+
{"emb": [4.3, 5.2, 6.7]},
|
|
64
|
+
)
|
|
65
|
+
assert result.get_next() == ["test", pytest.approx(0.8922316795174099)]
|
|
66
|
+
# TODO(maxwell): fixme. The following case should be executed successfully.
|
|
67
|
+
# with pytest.raises(RuntimeError) as err:
|
|
68
|
+
# conn.execute(
|
|
69
|
+
# """
|
|
70
|
+
# MATCH (d:node)
|
|
71
|
+
# RETURN d.id, array_cosine_similarity($emb1, $emb)
|
|
72
|
+
# """, {"emb": [4.3, 5.2, 6.7], "emb1": [2.2, 3.3, 5.5]}
|
|
73
|
+
# )
|
|
74
|
+
# assert str(err.value) == "Binder exception: Left and right type are both ANY, which is not currently supported."
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_bool_param(conn_db_readonly: ConnDB) -> None:
|
|
78
|
+
conn, _ = conn_db_readonly
|
|
79
|
+
result = conn.execute(
|
|
80
|
+
"MATCH (a:person) WHERE a.isStudent = $1 AND a.isWorker = $k RETURN COUNT(*)", {"1": False, "k": False}
|
|
81
|
+
)
|
|
82
|
+
assert result.has_next()
|
|
83
|
+
assert result.get_next() == [1]
|
|
84
|
+
assert not result.has_next()
|
|
85
|
+
result.close()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_int_param(conn_db_readonly: ConnDB) -> None:
|
|
89
|
+
conn, _ = conn_db_readonly
|
|
90
|
+
result = conn.execute("MATCH (a:person) WHERE a.age < $AGE RETURN COUNT(*)", {"AGE": 1})
|
|
91
|
+
assert result.has_next()
|
|
92
|
+
assert result.get_next() == [0]
|
|
93
|
+
assert not result.has_next()
|
|
94
|
+
result.close()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_double_param(conn_db_readonly: ConnDB) -> None:
|
|
98
|
+
conn, _ = conn_db_readonly
|
|
99
|
+
result = conn.execute("MATCH (a:person) WHERE a.eyeSight = $E RETURN COUNT(*)", {"E": 5.0})
|
|
100
|
+
assert result.has_next()
|
|
101
|
+
assert result.get_next() == [2]
|
|
102
|
+
assert not result.has_next()
|
|
103
|
+
result.close()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_str_param(conn_db_readonly: ConnDB) -> None:
|
|
107
|
+
conn, _ = conn_db_readonly
|
|
108
|
+
result = conn.execute("MATCH (a:person) WHERE a.ID = 0 RETURN concat(a.fName, $S);", {"S": "HH"})
|
|
109
|
+
assert result.has_next()
|
|
110
|
+
assert result.get_next() == ["AliceHH"]
|
|
111
|
+
assert not result.has_next()
|
|
112
|
+
result.close()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_date_param(conn_db_readonly: ConnDB) -> None:
|
|
116
|
+
conn, _ = conn_db_readonly
|
|
117
|
+
result = conn.execute("MATCH (a:person) WHERE a.birthdate = $1 RETURN COUNT(*);", {"1": datetime.date(1900, 1, 1)})
|
|
118
|
+
assert result.has_next()
|
|
119
|
+
assert result.get_next() == [2]
|
|
120
|
+
assert not result.has_next()
|
|
121
|
+
result.close()
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def test_timestamp_param(conn_db_readonly: ConnDB) -> None:
|
|
125
|
+
conn, _ = conn_db_readonly
|
|
126
|
+
result = conn.execute(
|
|
127
|
+
"MATCH (a:person) WHERE a.registerTime = $1 RETURN COUNT(*);",
|
|
128
|
+
{"1": datetime.datetime(2011, 8, 20, 11, 25, 30)},
|
|
129
|
+
)
|
|
130
|
+
assert result.has_next()
|
|
131
|
+
assert result.get_next() == [1]
|
|
132
|
+
assert not result.has_next()
|
|
133
|
+
result.close()
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_int64_list_param(conn_db_readonly: ConnDB) -> None:
|
|
137
|
+
conn, _ = conn_db_readonly
|
|
138
|
+
result = conn.execute("MATCH (a:person {workedHours: $1}) RETURN COUNT(*);", {"1": [3, 4, 5, 6, 7]})
|
|
139
|
+
assert result.has_next()
|
|
140
|
+
assert result.get_next() == [1]
|
|
141
|
+
assert not result.has_next()
|
|
142
|
+
result.close()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def test_empty_list_param(conn_db_readonly: ConnDB) -> None:
|
|
146
|
+
conn, _ = conn_db_readonly
|
|
147
|
+
result = conn.execute("RETURN list_contains($list, $item)", {"list": [], "item": 5})
|
|
148
|
+
assert result.has_next()
|
|
149
|
+
assert result.get_next() == [False]
|
|
150
|
+
assert not result.has_next()
|
|
151
|
+
result.close()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def test_int64_list_list_param(conn_db_readonly: ConnDB) -> None:
|
|
155
|
+
conn, _ = conn_db_readonly
|
|
156
|
+
result = conn.execute(
|
|
157
|
+
"MATCH (a:person) WHERE a.courseScoresPerTerm = $1 OR a.courseScoresPerTerm = $2 RETURN COUNT(*);",
|
|
158
|
+
{"1": [[8, 10]], "2": [[7, 4], [8, 8], [9]]},
|
|
159
|
+
)
|
|
160
|
+
assert result.has_next()
|
|
161
|
+
assert result.get_next() == [2]
|
|
162
|
+
assert not result.has_next()
|
|
163
|
+
result.close()
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_string_list_param(conn_db_readonly: ConnDB) -> None:
|
|
167
|
+
conn, _ = conn_db_readonly
|
|
168
|
+
result = conn.execute("MATCH (a:person {usedNames: $1}) RETURN COUNT(*);", {"1": ["Carmen", "Fred"]})
|
|
169
|
+
assert result.has_next()
|
|
170
|
+
assert result.get_next() == [1]
|
|
171
|
+
assert not result.has_next()
|
|
172
|
+
result.close()
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_map_param(conn_db_empty: ConnDB) -> None:
|
|
176
|
+
conn, _ = conn_db_empty
|
|
177
|
+
conn.execute(
|
|
178
|
+
"CREATE NODE TABLE tab(id int64, mp MAP(double, int64), mp2 MAP(int64, double), mp3 MAP(string, string), mp4 MAP(string, string)[], primary key(id))"
|
|
179
|
+
)
|
|
180
|
+
result = conn.execute(
|
|
181
|
+
"MERGE (t:tab {id: 0, mp: $1, mp2: $2, mp3: $3, mp4: $4}) RETURN t.*",
|
|
182
|
+
{
|
|
183
|
+
"1": {"key": [1.0, 2, 2.2], "value": [5, 3, -1]},
|
|
184
|
+
"2": {"key": [5, 4, 0], "value": [-0.5, 0, 2.2]},
|
|
185
|
+
"3": {"key": ["a", "b", "c"], "value": [1, "2", "3"]},
|
|
186
|
+
"4": [{"key": ["a"], "value": ["b"]}],
|
|
187
|
+
},
|
|
188
|
+
)
|
|
189
|
+
assert result.has_next()
|
|
190
|
+
assert result.get_next() == [
|
|
191
|
+
0,
|
|
192
|
+
{1.0: 5, 2.0: 3, 2.2: -1},
|
|
193
|
+
{5: -0.5, 4: -0.0, 0: 2.2},
|
|
194
|
+
{"a": "1", "b": "2", "c": "3"},
|
|
195
|
+
[{"a": "b"}],
|
|
196
|
+
]
|
|
197
|
+
assert not result.has_next()
|
|
198
|
+
result.close()
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def test_general_list_param(conn_db_empty: ConnDB) -> None:
|
|
202
|
+
conn, _ = conn_db_empty
|
|
203
|
+
conn.execute(
|
|
204
|
+
"CREATE NODE TABLE tab(id int64, lst1 BOOL[], lst2 DOUBLE[], lst3 TIMESTAMP[], lst4 DATE[], lst5 INTERVAL[], lst6 STRING[], PRIMARY KEY(id))"
|
|
205
|
+
)
|
|
206
|
+
lst1 = [True, False]
|
|
207
|
+
lst2 = [1.0, 2.0]
|
|
208
|
+
lst3 = [datetime.datetime(2019, 11, 12, 11, 25, 30), datetime.datetime(1987, 2, 15, 3, 0, 2)]
|
|
209
|
+
lst4 = [datetime.date(2019, 11, 12), datetime.date(1987, 2, 15)]
|
|
210
|
+
lst5 = [lst3[0] - lst3[1]]
|
|
211
|
+
lst6 = [1, "2", "3"]
|
|
212
|
+
lst6ToString = ["1", "2", "3"]
|
|
213
|
+
result = conn.execute(
|
|
214
|
+
"MERGE (t:tab {id: 0, lst1: $1, lst2: $2, lst3: $3, lst4: $4, lst5: $5, lst6: $6}) RETURN t.*",
|
|
215
|
+
{"1": lst1, "2": lst2, "3": lst3, "4": lst4, "5": lst5, "6": lst6},
|
|
216
|
+
)
|
|
217
|
+
assert result.has_next()
|
|
218
|
+
assert result.get_next() == [0, lst1, lst2, lst3, lst4, lst5, lst6ToString]
|
|
219
|
+
assert not result.has_next()
|
|
220
|
+
result.close()
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def test_null_resolution(conn_db_empty: ConnDB) -> None:
|
|
224
|
+
conn, _ = conn_db_empty
|
|
225
|
+
conn.execute(
|
|
226
|
+
"CREATE NODE TABLE tab(id SERIAL, lst1 INT64[], mp1 MAP(STRING, STRING), "
|
|
227
|
+
"nest MAP(STRING, MAP(STRING, INT64))[], PRIMARY KEY(id))"
|
|
228
|
+
)
|
|
229
|
+
lst1 = [1, 2, 3, None]
|
|
230
|
+
mp1 = {"key": ["a", "b", "c", "o"], "value": ["x", "y", "z", None]}
|
|
231
|
+
nest = [
|
|
232
|
+
{"key": ["2"], "value": [{"key": ["foo", "bar"], "value": [1, 2]}]},
|
|
233
|
+
{"key": ["1"], "value": [{"key": [], "value": []}]},
|
|
234
|
+
]
|
|
235
|
+
result = conn.execute("MERGE (t:tab {lst1: $1, mp1: $2, nest: $3}) RETURN t.*", {"1": lst1, "2": mp1, "3": nest})
|
|
236
|
+
assert result.has_next()
|
|
237
|
+
assert result.get_next() == [
|
|
238
|
+
0,
|
|
239
|
+
lst1,
|
|
240
|
+
{"a": "x", "b": "y", "c": "z", "o": None},
|
|
241
|
+
[{"2": {"foo": 1, "bar": 2}}, {"1": {}}],
|
|
242
|
+
]
|
|
243
|
+
assert not result.has_next()
|
|
244
|
+
result.close()
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def test_param_error1(conn_db_readonly: ConnDB) -> None:
|
|
248
|
+
conn, _ = conn_db_readonly
|
|
249
|
+
with pytest.raises(RuntimeError, match="Parameter name must be of type string but got <class 'int'>"):
|
|
250
|
+
conn.execute("MATCH (a:person) WHERE a.registerTime = $1 RETURN COUNT(*);", {1: 1})
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def test_param_error2(conn_db_readonly: ConnDB) -> None:
|
|
254
|
+
conn, _ = conn_db_readonly
|
|
255
|
+
with pytest.raises(RuntimeError, match="Parameters must be a dict"):
|
|
256
|
+
conn.execute("MATCH (a:person) WHERE a.registerTime = $1 RETURN COUNT(*);", ["asd"])
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def test_param_error3(conn_db_readonly: ConnDB) -> None:
|
|
260
|
+
conn, _ = conn_db_readonly
|
|
261
|
+
with pytest.raises(RuntimeError, match="Parameters must be a dict"):
|
|
262
|
+
conn.execute("MATCH (a:person) WHERE a.registerTime = $1 RETURN COUNT(*);", [("asd", 1, 1)])
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def test_param(conn_db_readwrite: ConnDB) -> None:
|
|
266
|
+
conn, _ = conn_db_readwrite
|
|
267
|
+
conn.execute("CREATE NODE TABLE NodeOne(id INT64, name STRING, PRIMARY KEY(id));")
|
|
268
|
+
conn.execute("CREATE NODE TABLE NodeTwo(id INT64, name STRING, PRIMARY KEY(id));")
|
|
269
|
+
conn.execute("CREATE Rel TABLE RelA(from NodeOne to NodeOne);")
|
|
270
|
+
conn.execute("CREATE Rel TABLE RelB(from NodeTwo to NodeOne, id int64, name String);")
|
|
271
|
+
conn.execute('CREATE (t: NodeOne {id:1, name: "Alice"});')
|
|
272
|
+
conn.execute('CREATE (t: NodeOne {id:2, name: "Jack"});')
|
|
273
|
+
conn.execute('CREATE (t: NodeTwo {id:3, name: "Bob"});')
|
|
274
|
+
result = conn.execute(
|
|
275
|
+
"MATCH (a:NodeOne { id: $a_id }),"
|
|
276
|
+
"(b:NodeTwo { id: $b_id }),"
|
|
277
|
+
"(c: NodeOne{ id: $c_id } )"
|
|
278
|
+
" MERGE"
|
|
279
|
+
" (a)-[:RelA]->(c),"
|
|
280
|
+
" (b)-[r:RelB { id: 2, name: $my_param }]->(c)"
|
|
281
|
+
" return r.*;",
|
|
282
|
+
{"a_id": 1, "b_id": 3, "c_id": 2, "my_param": None},
|
|
283
|
+
)
|
|
284
|
+
assert result.has_next()
|
|
285
|
+
assert result.get_next() == [2, None]
|
|
286
|
+
result.close()
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def test_param_error4(conn_db_readonly: ConnDB) -> None:
|
|
290
|
+
conn, _ = conn_db_readonly
|
|
291
|
+
with pytest.raises(
|
|
292
|
+
RuntimeError,
|
|
293
|
+
match="Runtime exception: Cannot convert Python object to Lbug value : INT8 is incompatible with TIMESTAMP",
|
|
294
|
+
):
|
|
295
|
+
conn.execute(
|
|
296
|
+
"MATCH (a:person {workedHours: $1}) RETURN COUNT(*);", {"1": [1, 2, datetime.datetime(2023, 3, 25)]}
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def test_dict_conversion(conn_db_readwrite: ConnDB) -> None:
|
|
301
|
+
conn, _ = conn_db_readwrite
|
|
302
|
+
# Interpret as MAP.
|
|
303
|
+
result = conn.execute("RETURN $st", {"st": {"key": [1, 2, 3], "value": [3, 7, 98]}})
|
|
304
|
+
assert result.get_next() == [{1: 3, 2: 7, 3: 98}]
|
|
305
|
+
# Interpret as STRUCT since the first field name is not "key".
|
|
306
|
+
result = conn.execute("RETURN $st", {"st": {"key1": [1, 2, 3], "value": [3, 7, 98]}})
|
|
307
|
+
assert result.get_next() == [{"key1": [1, 2, 3], "value": [3, 7, 98]}]
|
|
308
|
+
# Interpret as STRUCT since the number of elements in key and value doesn't match.
|
|
309
|
+
result = conn.execute("RETURN $st", {"st": {"key": [1, 2], "value": [3, 7, 98, 4]}})
|
|
310
|
+
assert result.get_next() == [{"key": [1, 2], "value": [3, 7, 98, 4]}]
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def test_null_handling(conn_db_readwrite: ConnDB) -> None:
|
|
314
|
+
conn, _ = conn_db_readwrite
|
|
315
|
+
result = conn.execute(
|
|
316
|
+
"""
|
|
317
|
+
UNWIND $edges AS edge
|
|
318
|
+
WITH edge, size(edge.fact_embedding) AS score
|
|
319
|
+
ORDER BY score DESC
|
|
320
|
+
LIMIT $limit
|
|
321
|
+
RETURN edge.uuid;
|
|
322
|
+
""",
|
|
323
|
+
{
|
|
324
|
+
"edges": [
|
|
325
|
+
{
|
|
326
|
+
"uuid": "1c4e35a9-c6cb-4517-971f-37f209c71e64",
|
|
327
|
+
"fact_embedding": [
|
|
328
|
+
-0.010113425552845001,
|
|
329
|
+
-0.01922552101314068,
|
|
330
|
+
0.007402684073895216,
|
|
331
|
+
],
|
|
332
|
+
"expired_at": None,
|
|
333
|
+
}
|
|
334
|
+
],
|
|
335
|
+
"limit": 10,
|
|
336
|
+
},
|
|
337
|
+
)
|
|
338
|
+
assert result.has_next()
|
|
339
|
+
result.get_next()[0] = "1c4e35a9-c6cb-4517-971f-37f209c71e64"
|
|
340
|
+
assert not result.has_next()
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from type_aliases import ConnDB
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_read(conn_db_readonly: ConnDB) -> None:
|
|
11
|
+
conn, _ = conn_db_readonly
|
|
12
|
+
prepared_query = "MATCH (a:person) WHERE a.isStudent = $1 AND a.isWorker = $k RETURN COUNT(*)"
|
|
13
|
+
|
|
14
|
+
result = conn.execute(prepared_query, {"1": False, "k": False})
|
|
15
|
+
assert result.has_next()
|
|
16
|
+
assert result.get_next() == [1]
|
|
17
|
+
assert not result.has_next()
|
|
18
|
+
|
|
19
|
+
result = conn.execute(prepared_query, {"1": True, "k": False})
|
|
20
|
+
assert result.has_next()
|
|
21
|
+
assert result.get_next() == [3]
|
|
22
|
+
assert not result.has_next()
|
|
23
|
+
|
|
24
|
+
result = conn.execute(prepared_query, {"1": False, "k": True})
|
|
25
|
+
assert result.has_next()
|
|
26
|
+
assert result.get_next() == [4]
|
|
27
|
+
assert not result.has_next()
|
|
28
|
+
|
|
29
|
+
result = conn.execute(prepared_query, {"1": True, "k": True})
|
|
30
|
+
assert result.has_next()
|
|
31
|
+
assert result.get_next() == [0]
|
|
32
|
+
assert not result.has_next()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_null_value(conn_db_readonly: ConnDB) -> None:
|
|
36
|
+
conn, _ = conn_db_readonly
|
|
37
|
+
prepared_query = "RETURN [4, $1, 2, $3, 4]"
|
|
38
|
+
|
|
39
|
+
result = conn.execute(prepared_query, {"1": None, "3": 5})
|
|
40
|
+
assert result.has_next()
|
|
41
|
+
assert result.get_next() == [[4, None, 2, 5, 4]]
|
|
42
|
+
assert not result.has_next()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_write(conn_db_readwrite: ConnDB) -> None:
|
|
46
|
+
conn, _ = conn_db_readwrite
|
|
47
|
+
orgs = [
|
|
48
|
+
{
|
|
49
|
+
"ID": 1001,
|
|
50
|
+
"name": "org1",
|
|
51
|
+
"orgCode": 1,
|
|
52
|
+
"mark": 1.0,
|
|
53
|
+
"score": 1,
|
|
54
|
+
"history": "history1",
|
|
55
|
+
"licenseValidInterval": datetime.timedelta(days=1),
|
|
56
|
+
"rating": 1.0,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"ID": 1002,
|
|
60
|
+
"name": "org2",
|
|
61
|
+
"orgCode": 2,
|
|
62
|
+
"mark": 2.0,
|
|
63
|
+
"score": 2,
|
|
64
|
+
"history": "history2",
|
|
65
|
+
"licenseValidInterval": datetime.timedelta(days=2),
|
|
66
|
+
"rating": 2.0,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"ID": 1003,
|
|
70
|
+
"name": "org3",
|
|
71
|
+
"orgCode": 3,
|
|
72
|
+
"mark": 3.0,
|
|
73
|
+
"score": 3,
|
|
74
|
+
"history": "history3",
|
|
75
|
+
"licenseValidInterval": datetime.timedelta(days=3),
|
|
76
|
+
"rating": 3.0,
|
|
77
|
+
},
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
prepared_query = "CREATE (n:organisation {ID: $ID, name: $name, orgCode: $orgCode, mark: $mark, score: $score, history: $history, licenseValidInterval: $licenseValidInterval, rating: $rating})"
|
|
81
|
+
for org in orgs:
|
|
82
|
+
org_dict = {str(k): v for k, v in org.items()}
|
|
83
|
+
conn.execute(prepared_query, org_dict)
|
|
84
|
+
|
|
85
|
+
all_orgs_res = conn.execute("MATCH (n:organisation) RETURN n")
|
|
86
|
+
while all_orgs_res.has_next():
|
|
87
|
+
n = all_orgs_res.get_next()[0]
|
|
88
|
+
if n["ID"] not in [o["ID"] for o in orgs]:
|
|
89
|
+
continue
|
|
90
|
+
for expected_org in orgs:
|
|
91
|
+
if n["ID"] == expected_org["ID"]:
|
|
92
|
+
assert n["ID"] == expected_org["ID"]
|
|
93
|
+
assert n["name"] == expected_org["name"]
|
|
94
|
+
assert n["orgCode"] == expected_org["orgCode"]
|
|
95
|
+
assert n["mark"] == expected_org["mark"]
|
|
96
|
+
assert n["score"] == expected_org["score"]
|
|
97
|
+
assert n["history"] == expected_org["history"]
|
|
98
|
+
assert n["licenseValidInterval"] == expected_org["licenseValidInterval"]
|
|
99
|
+
assert n["rating"] == expected_org["rating"]
|
|
100
|
+
break
|
|
101
|
+
|
|
102
|
+
conn.execute("CREATE NODE TABLE uuid_table (id UUID, PRIMARY KEY(id));")
|
|
103
|
+
conn.execute("CREATE (:uuid_table {id: $1});", {"1": uuid.uuid5(uuid.NAMESPACE_DNS, "lbug")})
|
|
104
|
+
result = conn.execute("MATCH (n:uuid_table) RETURN n.id;")
|
|
105
|
+
assert result.get_next() == [uuid.uuid5(uuid.NAMESPACE_DNS, "lbug")]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_error(conn_db_readonly: ConnDB) -> None:
|
|
109
|
+
with pytest.raises(RuntimeError, match=r"Binder exception: Table dog does not exist."):
|
|
110
|
+
conn_db_readonly[0].execute("MATCH (d:dog) WHERE d.isServiceDog = $1 RETURN COUNT(*)")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_prepare_limit(conn_db_readonly: ConnDB) -> None:
|
|
114
|
+
result = conn_db_readonly[0].execute("MATCH (p:person) return p.ID limit $lt", {"lt": 3})
|
|
115
|
+
assert result.get_next() == [0]
|
|
116
|
+
assert result.get_next() == [2]
|
|
117
|
+
assert result.get_next() == [3]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from type_aliases import ConnDB
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_get_execution_time(conn_db_readonly: ConnDB) -> None:
|
|
7
|
+
conn, _ = conn_db_readonly
|
|
8
|
+
result = conn.execute("MATCH (a:person) WHERE a.ID = 0 RETURN a")
|
|
9
|
+
assert result.get_execution_time() > 0
|
|
10
|
+
result.close()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_get_compiling_time(conn_db_readonly: ConnDB) -> None:
|
|
14
|
+
conn, _ = conn_db_readonly
|
|
15
|
+
result = conn.execute("MATCH (a:person) WHERE a.ID = 0 RETURN a")
|
|
16
|
+
assert result.get_compiling_time() > 0
|
|
17
|
+
result.close()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_get_num_tuples(conn_db_readonly: ConnDB) -> None:
|
|
21
|
+
conn, _ = conn_db_readonly
|
|
22
|
+
result = conn.execute("MATCH (a:person) WHERE a.ID = 0 RETURN a")
|
|
23
|
+
assert result.get_num_tuples() == 1
|
|
24
|
+
result.close()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_explain(conn_db_readonly: ConnDB) -> None:
|
|
28
|
+
conn, _ = conn_db_readonly
|
|
29
|
+
result = conn.execute("EXPLAIN MATCH (a:person) WHERE a.ID = 0 RETURN a")
|
|
30
|
+
assert result.get_num_tuples() == 1
|
|
31
|
+
result.close()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_context_manager(conn_db_readonly: ConnDB) -> None:
|
|
35
|
+
conn, _ = conn_db_readonly
|
|
36
|
+
with conn.execute("MATCH (a:person) WHERE a.ID = 0 RETURN a") as result:
|
|
37
|
+
assert result.get_num_tuples() == 1
|
|
38
|
+
assert result.get_compiling_time() > 0
|
|
39
|
+
|
|
40
|
+
# context exit guarantees immediately 'close' of the underlying QueryResult
|
|
41
|
+
# (don't have to wait for __del__, which may not ever actually get called)
|
|
42
|
+
assert result.is_closed
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_multiple_query_results(conn_db_readonly: ConnDB) -> None:
|
|
46
|
+
conn, _ = conn_db_readonly
|
|
47
|
+
results = conn.execute("RETURN 1; RETURN 2; RETURN 3;")
|
|
48
|
+
assert len(results) == 3
|
|
49
|
+
i = 1
|
|
50
|
+
for result in results:
|
|
51
|
+
assert result.get_num_tuples() == 1
|
|
52
|
+
assert result.has_next()
|
|
53
|
+
assert result.get_next() == [i]
|
|
54
|
+
i += 1
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from textwrap import dedent
|
|
5
|
+
|
|
6
|
+
from test_helper import LBUG_ROOT
|
|
7
|
+
from conftest import get_db_file_path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_query_result_close(tmp_path: Path, build_dir: Path) -> None:
|
|
11
|
+
db_path = get_db_file_path(tmp_path)
|
|
12
|
+
code = dedent(f"""
|
|
13
|
+
import sys
|
|
14
|
+
sys.path.append(r"{build_dir!s}")
|
|
15
|
+
|
|
16
|
+
import real_ladybug as lb
|
|
17
|
+
db = lb.Database(r"{db_path!s}")
|
|
18
|
+
conn = lb.Connection(db)
|
|
19
|
+
conn.execute('''
|
|
20
|
+
CREATE NODE TABLE person (
|
|
21
|
+
ID INT64,
|
|
22
|
+
fName STRING,
|
|
23
|
+
gender INT64,
|
|
24
|
+
isStudent BOOLEAN,
|
|
25
|
+
isWorker BOOLEAN,
|
|
26
|
+
age INT64,
|
|
27
|
+
eyeSight DOUBLE,
|
|
28
|
+
birthdate DATE,
|
|
29
|
+
registerTime TIMESTAMP,
|
|
30
|
+
lastJobDuration INTERVAL,
|
|
31
|
+
workedHours INT64[],
|
|
32
|
+
usedNames STRING[],
|
|
33
|
+
courseScoresPerTerm INT64[][],
|
|
34
|
+
grades INT64[4],
|
|
35
|
+
height float,
|
|
36
|
+
u UUID,
|
|
37
|
+
PRIMARY KEY (ID))
|
|
38
|
+
''')
|
|
39
|
+
conn.execute('COPY person FROM "{LBUG_ROOT}/dataset/tinysnb/vPerson.csv" (HEADER=true)')
|
|
40
|
+
result = conn.execute("MATCH (a:person) WHERE a.ID = 0 RETURN a.isStudent;")
|
|
41
|
+
# result.close()
|
|
42
|
+
""")
|
|
43
|
+
result = subprocess.run([sys.executable, "-c", code])
|
|
44
|
+
assert result.returncode == 0
|