feat: author generated column change jobs

This commit is contained in:
Xuanwo
2026-08-12 20:34:39 +08:00
parent 72767b17fa
commit e478b80985
6 changed files with 1198 additions and 4 deletions
+3
View File
@@ -373,6 +373,9 @@ class Table:
self, column_name: str
) -> Literal["complete", "incomplete"]: ...
async def _refresh_generated_column(self, column_name: str) -> Job: ...
async def _alter_generated_column(
self, column_name: str, new_call: _FunctionCall
) -> Job: ...
async def list_versions(self) -> List[Dict[str, Any]]: ...
async def version(self) -> int: ...
async def checkout(self, version: Union[int, str]): ...
+11
View File
@@ -602,6 +602,17 @@ class RemoteTable(Table):
"""
return Job(LOOP.run(self._table.refresh_generated_column(column_name)))
def alter_generated_column(
self, column_name: str, new_call: "_FunctionCall"
) -> Job:
"""Alter the Function call for an existing generated column.
Returns a :class:`~lancedb.job.Job` for the change operation. Acceptance
of the Job does not publish the new definition; callers must wait and
re-read the table to observe the updated column.
"""
return Job(LOOP.run(self._table.alter_generated_column(column_name, new_call)))
def _is_legacy_create_index_call(
self,
first_arg: str,
+30
View File
@@ -1036,6 +1036,15 @@ class Table(ABC):
"""
raise NotImplementedError
def alter_generated_column(self, column_name: str, new_call: _FunctionCall) -> Job:
"""Alter the Function call for an existing generated column.
Returns a :class:`~lancedb.job.Job` for the change operation. Acceptance
of the Job does not publish the new definition; callers must wait and
re-read the table to observe the updated column.
"""
raise NotImplementedError
def drop_index(self, name: str) -> None:
"""
Drop an index from the table.
@@ -2906,6 +2915,15 @@ class LanceTable(Table):
"""
return Job(LOOP.run(self._table.refresh_generated_column(column_name)))
def alter_generated_column(self, column_name: str, new_call: _FunctionCall) -> Job:
"""Alter the Function call for an existing generated column.
Returns a :class:`~lancedb.job.Job` for the change operation. Acceptance
of the Job does not publish the new definition; callers must wait and
re-read the table to observe the updated column.
"""
return Job(LOOP.run(self._table.alter_generated_column(column_name, new_call)))
def _is_legacy_create_index_call(
self,
first_arg: str,
@@ -5155,6 +5173,18 @@ class AsyncTable:
job = await self._inner._refresh_generated_column(column_name)
return AsyncJob(job)
async def alter_generated_column(
self, column_name: str, new_call: _FunctionCall
) -> AsyncJob:
"""Alter the Function call for an existing generated column.
Returns an :class:`~lancedb.job.AsyncJob` for the change operation.
Acceptance of the Job does not publish the new definition; callers must
wait and re-read the table to observe the updated column.
"""
job = await self._inner._alter_generated_column(column_name, new_call)
return AsyncJob(job)
async def drop_index(self, name: str) -> None:
"""
Drop an index from the table.
File diff suppressed because it is too large Load Diff
+7 -4
View File
@@ -255,10 +255,13 @@ impl AuthoredFunctionCall {
/// Resolve authoring bindings against an already-fetched binding snapshot.
///
/// Field names use exact case-sensitive top-level lookup; a name containing
/// `.` is literal, not a nested path. Used only by [`Self::bind_to_table`]
/// and narrowly scoped Rust tests that need a dotted top-level name Native
/// Lance cannot create on a real table.
fn bind_against_snapshot(
/// `.` is literal, not a nested path. Returns that same snapshot's version
/// plus the validated canonical [`FunctionCall`]. Used by
/// [`Self::bind_to_table`], the alter generated-column PyO3 bridge (one
/// shared snapshot with definition load), and narrowly scoped Rust tests
/// that need a dotted top-level name Native Lance cannot create on a real
/// table.
pub(crate) fn bind_against_snapshot(
&self,
snapshot: &lancedb::function::GeneratedColumnBindingSnapshot,
) -> lancedb::Result<(u64, FunctionCall)> {
+43
View File
@@ -1027,6 +1027,49 @@ impl Table {
})
}
/// Hidden bridge: one binding snapshot, bind new call, submit change.
///
/// Private native path for Python ``table.alter_generated_column``. Rejects
/// an empty ``column_name`` before reading the table handle. Fetches exactly
/// one binding snapshot, loads the expected definition from that same
/// object, binds the authored call against it, and submits change. Does not
/// expose source version, Function handles, field IDs, epochs, specs, or
/// request envelope.
#[doc(hidden)]
pub fn _alter_generated_column<'a>(
self_: PyRef<'a, Self>,
column_name: String,
new_call: Bound<'_, crate::function::AuthoredFunctionCall>,
) -> PyResult<Bound<'a, PyAny>> {
if column_name.is_empty() {
return Err(PyValueError::new_err("column_name must be non-empty"));
}
let inner = self_.inner_ref()?.clone();
let authored = new_call.get().clone();
future_into_py(self_.py(), async move {
let snapshot = inner
.generated_column_binding_snapshot()
.await
.infer_error()?;
let expected_definition = snapshot
.generated_column_definition(&column_name)
.infer_error()?;
let (source_table_version, bound_new_call) =
authored.bind_against_snapshot(&snapshot).infer_error()?;
let spec = lancedb::function::ChangeGeneratedColumnJobSpec::try_new(
expected_definition,
authored.function(),
bound_new_call,
)
.infer_error()?;
let job = inner
.submit_change_generated_column(source_table_version, spec)
.await
.infer_error()?;
Ok(crate::job::Job::new(job))
})
}
pub fn drop_index(self_: PyRef<'_, Self>, index_name: String) -> PyResult<Bound<'_, PyAny>> {
let inner = self_.inner_ref()?.clone();
future_into_py(self_.py(), async move {