blob: 7ee2e45c41a9ce894ea289d07128a670a386e877 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from collections.abc import Mapping
from typing import Any, Dict, Iterable, List
import pyarrow as pa
from pypaimon.schema.data_types import DataField, PyarrowFieldParser, is_blob_file_field
from pypaimon.table.row.blob import Blob
from pypaimon.table.row.internal_row import InternalRow
from pypaimon.table.row.vector import Vector
def row_to_named_values(
row: InternalRow, table_fields: List[DataField]) -> Dict[str, Any]:
if hasattr(row, 'fields') and getattr(row, 'fields') is not None:
row_fields = getattr(row, 'fields')
return {
field.name: row.get_field(i)
for i, field in enumerate(row_fields)
}
if len(row) != len(table_fields):
raise ValueError(
"Rows without field metadata must have the same arity as the "
f"table schema: {len(row)} != {len(table_fields)}."
)
return {
field.name: row.get_field(i)
for i, field in enumerate(table_fields)
}
def require_columns(
values_by_name: Dict[str, Any],
column_names: Iterable[str],
context: str) -> None:
missing = [
column_name
for column_name in column_names
if column_name not in values_by_name
]
if missing:
raise ValueError(
f"{context} requires row field(s) {missing}, "
f"but row only contains {list(values_by_name.keys())}."
)
def value_for_arrow(value: Any, field: DataField) -> Any:
if isinstance(value, Vector):
return value.to_list()
if isinstance(value, Blob) or (
is_blob_file_field(field)
and _contains_blob_value(value)
):
raise ValueError(
"Blob values cannot be converted to Arrow without materializing "
"the stream. Use a Row-aware blob write path."
)
return value
def _contains_blob_value(value: Any) -> bool:
if isinstance(value, Blob):
return True
if isinstance(value, Mapping):
return any(_contains_blob_value(item) for item in value.values())
if isinstance(value, (list, tuple)):
return any(_contains_blob_value(item) for item in value)
return False
def row_values_to_arrow_table(
values_by_name: Dict[str, Any],
fields: List[DataField],
column_names: List[str]) -> pa.Table:
field_by_name = {field.name: field for field in fields}
selected_fields = [field_by_name[name] for name in column_names]
schema = PyarrowFieldParser.from_paimon_schema(selected_fields)
data = {
name: [value_for_arrow(values_by_name[name], field_by_name[name])]
for name in column_names
}
return pa.Table.from_pydict(data, schema=schema)