Skip to content
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/installation.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Every wheel is platform-specific and built on a native runner of its platform, s

Engine modules the bindings do not use are left out to keep the wheel small. These include the gRPC and MongoDB wire protocols, Raft HA, and Gremlin.

NOTE: *JavaScript is not available.* The GraalJS jars are left out, so `DEFINE FUNCTION ... LANGUAGE js` fails. Define functions in SQL or openCypher. Registering a Python function is planned in https://github.com/ArcadeData/arcadedb-python/pull/29[#29].
NOTE: *JavaScript is not available.* The GraalJS jars are left out, so `DEFINE FUNCTION ... LANGUAGE js` fails. Define functions in SQL or openCypher, or register a Python function with `Database.register_function` (it works on both packages).

// REMOVE WHEN: the old arcadedb-embedded* shims are retired and two releases have shipped with the two-package layout allow-old-name
NOTE: *The Studio web UI is in the JVM wheels from 26.11.1.* Studio used to bundle ApexCharts, which is no longer open source (https://github.com/ArcadeData/arcadedb/issues/10579[ArcadeData/arcadedb#10579]). https://github.com/ArcadeData/arcadedb/pull/10627[ArcadeData/arcadedb#10627] replaced it with Apache ECharts. The earlier 26.10.x wheels on PyPI do not contain Studio. The HTTP API of the in-process server works in all of them.
Expand Down
370 changes: 338 additions & 32 deletions native/src/main/java/org/humemai/nativelib/NativeExtras.java

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/arcadedb/_native/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
library (``libarcadedb``) that Python loads with ``ctypes``: no JVM, no JPype. The surface is the DSL-first core:
databases, ``query``/``command`` for SQL and openCypher, transactions, results and the in-process server.

What is not on native yet (each raises :class:`NotOnNativeYet`): Python UDFs and record callbacks, ``GraphBatch``, the
What is not on native yet (each raises :class:`NotOnNativeYet`): ``GraphBatch``, the
async executor, the Java-object APIs (``Document``/``Vertex``/``Edge`` wrappers, ``new_vertex``, ``new_document``,
``schema``, ``get_java_database``), the columnar/Arrow readers other than a simple row conversion, importers and
exporters that go through Java objects, and every JVM setting (``jvm_kwargs``, ``start_jvm``).
Expand Down
48 changes: 41 additions & 7 deletions src/arcadedb/_native/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from ..exceptions import ArcadeDBError
from ..transactions import TransactionContext
from ..type_conversion import json_bulk_dumps
from . import lib, not_yet
from . import interrupts, lib, not_yet
from .codec import _prep as _prep_row
from .codec import encode_params, json_native, loads, row_default

Expand All @@ -39,7 +39,9 @@ def _error(prefix: str, reply: dict) -> ArcadeDBError:
exc = ArcadeDBError(f"{prefix}: {head}" if prefix else head)
exc.native = reply
exc.java_chain = chain
return exc
return interrupts.convert(
exc
) # a Ctrl-C in a Python function is a KeyboardInterrupt chained from this error


def _read_error(reply: dict) -> ArcadeDBError:
Expand All @@ -48,7 +50,7 @@ def _read_error(reply: dict) -> ArcadeDBError:
)
exc.native = reply
exc.java_chain = reply.get("chain") or []
return exc
return interrupts.convert(exc)


def _call(prefix: str, name: str, *args) -> dict:
Expand Down Expand Up @@ -392,6 +394,7 @@ def __init__(self, handle: int, owned_by_server: bool = False):
self._closed = False
self._server_owned = owned_by_server
self._async_executors: list = []
self._registry = None # Python functions and event callbacks, once one is registered (extras.Registrations)
self._vector_meta: dict = {}
self._vector_dimensions: dict = {}
self._vector_id_properties: dict = {}
Expand All @@ -412,6 +415,8 @@ def close(self):
if self._closed:
return
self._close_async_executors()
if self._registry is not None:
self._registry.clear() # before the engine closes: the functions are process-wide, the listeners die with the database
if self._server_owned:
# owned by the server: the engine refuses the close, and this handle is done either way
self._closed = True
Expand Down Expand Up @@ -481,6 +486,7 @@ def _exec(
refuse_surplus_positionals(
"command" if flags & 1 else "query", language, command, args
)
interrupts.clear()
if flags & 1 and _LAZY_COMMAND_ROWS and lib.CMD_PATH:
# phase 8: the cursor id comes back as a long (no reply text to free and decode); the rows are read late or never
text, buf, count = encode_params(args, binary=True)
Expand Down Expand Up @@ -876,11 +882,39 @@ def async_executor(self):
self._async_executors.append(executor)
return executor

def register_function(self, name, fn, min_args=0, max_args=-1):
"""Make a Python callable available to SQL (process-wide, see ``extras.register_function``)."""
from .extras import register_function
def _registrations(self):
from .extras import Registrations

register_function(name, fn, min_args, max_args)
if self._registry is None:
self._registry = Registrations(self)
return self._registry

def register_function(
self,
name,
fn,
*,
min_args=None,
max_args=None,
deterministic=False,
replace=False,
):
"""Make a Python callable available to SQL and openCypher (``Database.register_function``: process-wide, the Python
function is called from the engine thread that runs the statement)."""
self._check_not_closed()
self._registrations().register_function(
name, fn, min_args, max_args, deterministic, replace
)

def unregister_function(self, name):
"""Remove a Python function registered through this database."""
self._check_not_closed()
self._registrations().unregister_function(name)

def on(self, event, fn, type_name=None):
"""Call a Python function when a record is created, updated or deleted (``Database.on``)."""
self._check_not_closed()
return self._registrations().on(event, fn, type_name)

@property
def schema(self):
Expand Down
Loading
Loading