Skip to content

Commit 5b3cb8c

Browse files
committed
Add tests and examples for server mode and HTTP access in Python bindings
- Introduced new tests for HASH index schema, materialized views, and timeseries SQL. - Added example 21 demonstrating server mode and HTTP access, covering database creation, schema management, and mixed access patterns. - Updated documentation to include new examples and tests. - Improved code formatting for consistency across various Python scripts.
1 parent 15b63cb commit 5b3cb8c

33 files changed

Lines changed: 950 additions & 163 deletions

.github/workflows/test-python-examples.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ on:
2525
description: "Glob pattern(s) for examples to run (space-separated, relative to bindings/python/examples)."
2626
required: false
2727
type: string
28-
default: "0[1-9]_*.py 1[0-9]_*.py 20_*.py"
28+
default: "0[1-9]_*.py 1[0-9]_*.py 2[0-1]_*.py"
2929
build-version:
3030
description: "Override package version (PEP 440) for build.sh"
3131
required: false
@@ -37,10 +37,10 @@ on:
3737
examples:
3838
description: "Glob pattern(s) for examples to run (space-separated, relative to bindings/python/examples)."
3939
required: false
40-
default: "0[1-9]_*.py 1[0-9]_*.py 20_*.py"
40+
default: "0[1-9]_*.py 1[0-9]_*.py 2[0-1]_*.py"
4141

4242
env:
43-
EXAMPLES: ${{ inputs.examples || '0[1-9]_*.py 1[0-9]_*.py 20_*.py' }}
43+
EXAMPLES: ${{ inputs.examples || '0[1-9]_*.py 1[0-9]_*.py 2[0-1]_*.py' }}
4444

4545
permissions:
4646
contents: read
@@ -420,6 +420,12 @@ jobs:
420420
timeout_duration=900
421421
example_jvm_args=""
422422
;;
423+
"21_server_mode_http_access.py")
424+
example_args=""
425+
example_name="$example (server mode and HTTP access workflow)"
426+
timeout_duration=900
427+
example_jvm_args=""
428+
;;
423429
*)
424430
example_args=""
425431
example_name="$example"

bindings/python/docs/api/async_executor.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ Schedule asynchronous record deletion.
303303
```python
304304
# Delete old records
305305
to_delete = list(db.query("sql", "SELECT FROM LogEntry WHERE timestamp < ?",
306-
cutoff_date))
306+
cutoff_date))
307307

308308
async_exec = db.async_executor()
309309

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Citation API
2+
3+
The `cite()` helper returns the version-specific DOI URL for released ArcadeDB Embedded Python builds.
4+
5+
## Overview
6+
7+
Use this helper when you want a citable release URL for papers, reports, or reproducibility notes.
8+
9+
The helper is intentionally small:
10+
11+
- released versions return a Zenodo-backed DOI URL
12+
- unreleased development versions raise `ArcadeDBError`
13+
- unknown versions also raise `ArcadeDBError`
14+
15+
## Function
16+
17+
### `cite(version=None) -> str`
18+
19+
Return the DOI URL for a released package version.
20+
21+
**Parameters:**
22+
23+
- `version` (`str | None`): Version to cite. If omitted, the installed package version is used.
24+
25+
**Returns:**
26+
27+
- `str`: DOI URL such as `https://doi.org/10.5281/zenodo....`
28+
29+
**Raises:**
30+
31+
- `ArcadeDBError`: If the version is unreleased or missing from the citation map.
32+
33+
**Example:**
34+
35+
```python
36+
import arcadedb_embedded as arcadedb
37+
38+
doi_url = arcadedb.cite("26.1.1.post3")
39+
print(doi_url)
40+
```
41+
42+
## Notes
43+
44+
- This helper only covers released versions present in the package's internal DOI map.
45+
- Development builds intentionally do not pretend to be citable releases.
46+
- If a new release is missing here, the release metadata needs to be updated in the Python source.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# GraphBatch API
2+
3+
The `GraphBatch` helper exposes ArcadeDB's high-throughput graph-ingest path from Python.
4+
5+
## Overview
6+
7+
Use `GraphBatch` when you need to load many vertices and edges efficiently.
8+
9+
This is the repository's current recommended bulk graph-ingest path from Python.
10+
11+
You typically create it through `db.graph_batch(...)` rather than constructing the class directly.
12+
13+
## Entry Point
14+
15+
### `db.graph_batch(...) -> GraphBatch`
16+
17+
Create a configured batch helper tied to the current database.
18+
19+
**Common options:**
20+
21+
- `batch_size`: buffered edge batch size before flush
22+
- `expected_edge_count`: sizing hint for large runs
23+
- `light_edges`: create property-less light edges when appropriate
24+
- `commit_every`: commit cadence during batch work
25+
- `use_wal`: enable WAL for stronger durability
26+
- `wal_flush`: flush policy such as `no`, `yes_nometadata`, `yes_full`
27+
- `parallel_flush`: flush deferred work in parallel
28+
29+
**Example:**
30+
31+
```python
32+
with db.graph_batch(batch_size=1000, expected_edge_count=50000) as batch:
33+
alice = batch.create_vertex("Person", name="Alice")
34+
bob = batch.create_vertex("Person", name="Bob")
35+
batch.new_edge(alice, "Knows", bob, since=2024)
36+
```
37+
38+
## Common Operations
39+
40+
### `create_vertex(type_name, **properties)`
41+
42+
Create and persist a single vertex.
43+
44+
### `create_vertices(type_name, count_or_properties)`
45+
46+
Create many vertices efficiently and return their RIDs.
47+
48+
### `new_edge(source, edge_type, destination, **properties)`
49+
50+
Buffer an edge for creation during flush/close.
51+
52+
### `flush()`
53+
54+
Force buffered edge work to disk early.
55+
56+
### `close()`
57+
58+
Flush remaining work and finalize the batch.
59+
60+
### Counters
61+
62+
The helper also exposes counters such as:
63+
64+
- `get_total_edges_created()`
65+
- `get_buffered_edge_count()`
66+
- `get_deferred_incoming_edge_count()`
67+
68+
## Notes
69+
70+
- Prefer `GraphBatch` over importer-based graph loading for Python-managed bulk ingest.
71+
- `wal_flush` validation is intentionally strict and raises `ValueError` for invalid modes.
72+
- See the graph-ingest examples and tests for realistic usage patterns.

bindings/python/docs/api/schema.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ if not user_type.get("phoneNumber"):
470470

471471
# Add index to existing type (auto-transactional)
472472
if not any(idx.get_property_names() == ["email"]
473-
for idx in schema.get_type("User").get_indexes()):
473+
for idx in schema.get_type("User").get_indexes()):
474474
schema.create_index("User", ["email"], unique=True)
475475
print("✅ Added email index")
476476
```
@@ -615,7 +615,7 @@ def migrate_schema_v1_to_v2(db):
615615

616616
# Add new index
617617
if not any(idx.get_property_names() == ["status"]
618-
for idx in user_type.get_indexes()):
618+
for idx in user_type.get_indexes()):
619619
db.schema.create_index("User", ["status"])
620620
print("✅ Added status index")
621621

bindings/python/docs/api/transactions.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -426,13 +426,13 @@ with db.transaction():
426426
with db.transaction():
427427
# Debit from Alice
428428
db.command("sql",
429-
"UPDATE Account SET balance = balance - 100 "
430-
"WHERE name = 'Alice'")
429+
"UPDATE Account SET balance = balance - 100 "
430+
"WHERE name = 'Alice'")
431431

432432
# Credit to Bob
433433
db.command("sql",
434-
"UPDATE Account SET balance = balance + 100 "
435-
"WHERE name = 'Bob'")
434+
"UPDATE Account SET balance = balance + 100 "
435+
"WHERE name = 'Bob'")
436436

437437
# Both updates commit together or neither commits
438438
```

bindings/python/docs/api/vector.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -455,11 +455,11 @@ index = db.schema.get_vector_index("Document", "embedding")
455455
# Sample documents
456456
documents = [
457457
{"id": "doc1", "title": "Python Tutorial",
458-
"content": "Learn Python programming basics"},
458+
"content": "Learn Python programming basics"},
459459
{"id": "doc2", "title": "Machine Learning Guide",
460-
"content": "Introduction to ML algorithms"},
460+
"content": "Introduction to ML algorithms"},
461461
{"id": "doc3", "title": "Database Systems",
462-
"content": "Understanding relational databases"},
462+
"content": "Understanding relational databases"},
463463
]
464464

465465
# Index documents
@@ -536,11 +536,11 @@ index = db.schema.get_vector_index("Product", "features")
536536
# Add products with feature vectors
537537
products = [
538538
{"id": "p1", "name": "Laptop", "category": "Electronics",
539-
"price": 999.99, "features": np.random.rand(128)},
539+
"price": 999.99, "features": np.random.rand(128)},
540540
{"id": "p2", "name": "Mouse", "category": "Electronics",
541-
"price": 29.99, "features": np.random.rand(128)},
541+
"price": 29.99, "features": np.random.rand(128)},
542542
{"id": "p3", "name": "Desk", "category": "Furniture",
543-
"price": 299.99, "features": np.random.rand(128)},
543+
"price": 299.99, "features": np.random.rand(128)},
544544
]
545545

546546
with db.transaction():

bindings/python/docs/development/architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ if __name__ == "__main__":
354354

355355
with mp.Pool(processes=4) as pool:
356356
pool.starmap(process_chunk,
357-
[("./mydb", chunk) for chunk in chunks])
357+
[("./mydb", chunk) for chunk in chunks])
358358
```
359359

360360
## Performance Considerations

bindings/python/docs/development/testing.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,42 @@ Comprehensive testing documentation for ArcadeDB Python bindings.
5454

5555
Executable coverage for representative Python snippets in the MkDocs docs tree
5656

57+
- :material-source-branch: **[GraphBatch Tests](testing/test-graph-batch.md)**
58+
59+
---
60+
61+
Engine-backed bulk graph ingest helper coverage
62+
63+
- :material-map-marker-radius: **[Geo Predicate SQL Tests](testing/test-geo-predicate-sql.md)**
64+
65+
---
66+
67+
SQL `geo.within` and `geo.intersects` semantics
68+
69+
- :material-chart-timeline-variant: **[Timeseries SQL Tests](testing/test-timeseries-sql.md)**
70+
71+
---
72+
73+
SQL-first timeseries type creation, range queries, and bucketing
74+
75+
- :material-table-search: **[Materialized View SQL Tests](testing/test-materialized-view-sql.md)**
76+
77+
---
78+
79+
Materialized view lifecycle, refresh, and metadata coverage
80+
81+
- :material-map-search: **[Graph Algorithms SQL Tests](testing/test-graph-algorithms-sql.md)**
82+
83+
---
84+
85+
`shortestPath`, `dijkstra`, and `astar` runtime coverage
86+
87+
- :material-pound-box: **[Hash Index Schema Tests](testing/test-hash-index-schema.md)**
88+
89+
---
90+
91+
HASH index creation, discovery, and drop coverage
92+
5793
- :material-graph: **[OpenCypher Tests](testing/test-opencypher.md)**
5894

5995
---
@@ -101,7 +137,7 @@ pytest --cov=arcadedb_embedded --cov-report=html
101137
| **Server Patterns** | Embedded+HTTP combinations, lock management |
102138
| **Data Import** | SQL import workflows, type inference, batch commits |
103139
| **Query Languages** | SQL, OpenCypher |
104-
| **Advanced Features** | Unicode support, schema introspection, large datasets |
140+
| **Advanced Features** | Unicode support, schema introspection, geospatial SQL, timeseries SQL, graph algorithms, materialized views, HASH indexes |
105141

106142
## Key Concepts
107143

@@ -158,6 +194,12 @@ tests/
158194
├── test_server.py # Server mode (6 tests)
159195
├── test_concurrency.py # Concurrency (4 tests)
160196
├── test_server_patterns.py # Patterns (4 tests)
197+
├── test_graph_batch.py # Bulk graph ingest helper
198+
├── test_graph_algorithms_sql.py # shortestPath / dijkstra / astar
199+
├── test_geo_predicate_sql.py # Geospatial SQL predicates
200+
├── test_timeseries_sql.py # Timeseries SQL coverage
201+
├── test_materialized_view_sql.py # Materialized view lifecycle
202+
├── test_hash_index_schema.py # HASH index schema API coverage
161203
├── test_import_database.py # Import database tests
162204
├── test_docs_examples.py # Validates runnable docs examples
163205
├── test_cypher.py # OpenCypher (tests)

bindings/python/docs/development/testing/overview.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ The test suite covers:
1919
-**Query languages** - SQL, OpenCypher
2020
-**Vector search** - HNSW (JVector) based Vector indexes, similarity search
2121
-**Data import** - CSV with batch commits and type inference
22+
-**Graph ingest helper** - `GraphBatch` buffering and flush behavior
23+
-**Geospatial SQL** - `geo.within`, `geo.intersects`, null/boundary semantics
24+
-**Time series SQL** - `CREATE TIMESERIES TYPE`, range queries, bucketing
25+
-**Materialized views** - create, refresh, alter, drop lifecycle
26+
-**Graph algorithms** - `shortestPath`, `dijkstra`, `astar`
27+
-**HASH schema indexes** - create, discover, idempotent drop behavior
2228
-**Unicode support** - International characters, emoji
2329
-**Schema introspection** - Querying database metadata
2430
-**Type conversions** - Python/Java type mapping
@@ -68,14 +74,20 @@ pytest -v -s
6874
Test counts evolve over time. For the latest per-file counts, run `pytest -v -rs`.
6975

7076
| Test File | Description |
71-
|-----------|-------------|
77+
| --------- | ----------- |
7278
| [`test_core.py`](test-core.md) | Core database operations, CRUD, transactions, queries |
7379
| [`test_server.py`](test-server.md) | Server mode, HTTP API, configuration |
7480
| [`test_concurrency.py`](test-concurrency.md) | File locking, thread safety, multi-process behavior |
7581
| [`test_server_patterns.py`](test-server-patterns.md) | Best practices for embedded + server mode |
7682
| [`test_import_database.py`](test-importer.md) | SQL `IMPORT DATABASE` scenarios and format coverage |
7783
| [`test_docs_examples.py`](test-docs-examples.md) | Executes representative Python snippets from the documentation site |
7884
| [`test_cypher.py`](test-opencypher.md) | OpenCypher query language |
85+
| [`test_graph_batch.py`](test-graph-batch.md) | Bulk graph-ingest helper coverage |
86+
| [`test_geo_predicate_sql.py`](test-geo-predicate-sql.md) | Geospatial SQL predicate semantics |
87+
| [`test_timeseries_sql.py`](test-timeseries-sql.md) | Time-series SQL type creation, range filters, and bucketing |
88+
| [`test_materialized_view_sql.py`](test-materialized-view-sql.md) | Materialized view lifecycle and refresh behavior |
89+
| [`test_graph_algorithms_sql.py`](test-graph-algorithms-sql.md) | SQL graph algorithm runtime coverage |
90+
| [`test_hash_index_schema.py`](test-hash-index-schema.md) | HASH index schema API behavior |
7991
| [`test_jvm_args.py`](test-jvm-args.md) | JVM args handling |
8092
| [`test_vector_params_verification.py`](test-vector-params-verification.md) | Vector param validation |
8193

@@ -129,12 +141,10 @@ pytest -m "not slow"
129141

130142
When the current bindings test suite passes, you should see a clean all-green summary.
131143

132-
```
144+
```text
133145
======================== 290 passed ========================
134146
```
135147

136-
137-
138148
## Next Steps
139149

140150
- **New to testing?** Start with [Core Tests](test-core.md)

0 commit comments

Comments
 (0)