Skip to content

Commit 06dbd8b

Browse files
committed
fix: bump to pre release 1.4 for bignum support
1 parent aaa0fd2 commit 06dbd8b

File tree

5 files changed

+87
-58
lines changed

5 files changed

+87
-58
lines changed

pyproject.toml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
name = "query-farm-airport-test-server"
33
version = "0.1.1"
44
description = "An Apache Arrow Flight server that is used to test the Airport extension for DuckDB."
5-
authors = [
6-
{ name = "Rusty Conover", email = "[email protected]" }
7-
]
5+
authors = [{ name = "Rusty Conover", email = "[email protected]" }]
86
dependencies = [
97
"pyarrow>=20.0.0",
108
"query-farm-flight-server",
11-
"duckdb>=1.3.1",
12-
"query-farm-duckdb-json-serialization>=0.1.1",
9+
"duckdb>=1.4.0.dev165",
10+
"query-farm-duckdb-json-serialization>=0.1.4",
1311
]
1412
readme = "README.md"
1513
requires-python = ">= 3.12"

requirements-dev.lock

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# use `rye lock` or `rye sync` to update this lockfile
33
#
44
# last locked with the following flags:
5-
# pre: false
5+
# pre: true
66
# features: []
77
# all-features: false
88
# with-sources: false
@@ -12,24 +12,24 @@
1212
-e file:.
1313
annotated-types==0.7.0
1414
# via pydantic
15-
boto3==1.39.12
15+
boto3==1.40.21
1616
# via query-farm-flight-server
17-
botocore==1.39.12
17+
botocore==1.40.21
1818
# via boto3
1919
# via s3transfer
2020
cache3==0.4.3
2121
# via query-farm-flight-server
22-
certifi==2025.7.14
22+
certifi==2025.8.3
2323
# via sentry-sdk
2424
click==8.2.1
2525
# via query-farm-flight-server
26-
coverage==7.9.2
26+
coverage==7.10.6
2727
# via pytest-cov
28-
duckdb==1.3.2
28+
duckdb==1.4.0.dev165
2929
# via query-farm-airport-test-server
3030
execnet==2.1.1
3131
# via pytest-xdist
32-
filelock==3.18.0
32+
filelock==3.19.1
3333
# via pytest-mypy
3434
fuzzywuzzy==0.18.0
3535
# via query-farm-flight-server
@@ -42,11 +42,11 @@ levenshtein==0.27.1
4242
# via python-levenshtein
4343
msgpack==1.1.1
4444
# via query-farm-flight-server
45-
mypy==1.17.0
45+
mypy==1.17.1
4646
# via pytest-mypy
47-
mypy-boto3-dynamodb==1.39.0
47+
mypy-boto3-dynamodb==1.40.20
4848
# via query-farm-flight-server
49-
mypy-boto3-s3==1.39.5
49+
mypy-boto3-s3==1.40.0
5050
# via query-farm-flight-server
5151
mypy-extensions==1.1.0
5252
# via mypy
@@ -84,24 +84,24 @@ python-dateutil==2.9.0.post0
8484
# via botocore
8585
python-levenshtein==0.27.1
8686
# via query-farm-flight-server
87-
query-farm-duckdb-json-serialization==0.1.2
87+
query-farm-duckdb-json-serialization==0.1.4
8888
# via query-farm-airport-test-server
89-
query-farm-flight-server==0.1.12
89+
query-farm-flight-server==0.1.17
9090
# via query-farm-airport-test-server
91-
rapidfuzz==3.13.0
91+
rapidfuzz==3.14.0
9292
# via levenshtein
9393
ruff==0.11.2
9494
s3transfer==0.13.1
9595
# via boto3
96-
sentry-sdk==2.33.2
96+
sentry-sdk==2.35.1
9797
# via query-farm-flight-server
9898
six==1.17.0
9999
# via python-dateutil
100100
structlog==25.4.0
101101
# via query-farm-flight-server
102102
tblib==3.1.0
103103
# via pytest-parallel
104-
typing-extensions==4.14.1
104+
typing-extensions==4.15.0
105105
# via mypy
106106
# via pydantic
107107
# via pydantic-core
@@ -113,5 +113,5 @@ urllib3==2.5.0
113113
# via sentry-sdk
114114
wcwidth==0.2.13
115115
# via prettytable
116-
zstandard==0.23.0
116+
zstandard==0.24.0
117117
# via query-farm-flight-server

requirements.lock

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# use `rye lock` or `rye sync` to update this lockfile
33
#
44
# last locked with the following flags:
5-
# pre: false
5+
# pre: true
66
# features: []
77
# all-features: false
88
# with-sources: false
@@ -12,18 +12,18 @@
1212
-e file:.
1313
annotated-types==0.7.0
1414
# via pydantic
15-
boto3==1.39.12
15+
boto3==1.40.21
1616
# via query-farm-flight-server
17-
botocore==1.39.12
17+
botocore==1.40.21
1818
# via boto3
1919
# via s3transfer
2020
cache3==0.4.3
2121
# via query-farm-flight-server
22-
certifi==2025.7.14
22+
certifi==2025.8.3
2323
# via sentry-sdk
2424
click==8.2.1
2525
# via query-farm-flight-server
26-
duckdb==1.3.2
26+
duckdb==1.4.0.dev165
2727
# via query-farm-airport-test-server
2828
fuzzywuzzy==0.18.0
2929
# via query-farm-flight-server
@@ -34,9 +34,9 @@ levenshtein==0.27.1
3434
# via python-levenshtein
3535
msgpack==1.1.1
3636
# via query-farm-flight-server
37-
mypy-boto3-dynamodb==1.39.0
37+
mypy-boto3-dynamodb==1.40.20
3838
# via query-farm-flight-server
39-
mypy-boto3-s3==1.39.5
39+
mypy-boto3-s3==1.40.0
4040
# via query-farm-flight-server
4141
prettytable==3.16.0
4242
# via query-farm-flight-server
@@ -52,21 +52,21 @@ python-dateutil==2.9.0.post0
5252
# via botocore
5353
python-levenshtein==0.27.1
5454
# via query-farm-flight-server
55-
query-farm-duckdb-json-serialization==0.1.2
55+
query-farm-duckdb-json-serialization==0.1.4
5656
# via query-farm-airport-test-server
57-
query-farm-flight-server==0.1.11
57+
query-farm-flight-server==0.1.17
5858
# via query-farm-airport-test-server
59-
rapidfuzz==3.13.0
59+
rapidfuzz==3.14.0
6060
# via levenshtein
6161
s3transfer==0.13.1
6262
# via boto3
63-
sentry-sdk==2.33.2
63+
sentry-sdk==2.35.1
6464
# via query-farm-flight-server
6565
six==1.17.0
6666
# via python-dateutil
6767
structlog==25.4.0
6868
# via query-farm-flight-server
69-
typing-extensions==4.14.1
69+
typing-extensions==4.15.0
7070
# via pydantic
7171
# via pydantic-core
7272
# via typing-inspection
@@ -77,5 +77,5 @@ urllib3==2.5.0
7777
# via sentry-sdk
7878
wcwidth==0.2.13
7979
# via prettytable
80-
zstandard==0.23.0
80+
zstandard==0.24.0
8181
# via query-farm-flight-server

src/query_farm_airport_test_server/database_impl.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,22 @@ class ScalarFunction:
109109
# The function to call to process a chunk of rows.
110110
handler: Callable[[pa.Table], pa.Array]
111111

112+
stability: flight_inventory.ScalarFunctionStability
113+
112114
def flight_info(
113115
self, *, name: str, catalog_name: str, schema_name: str
114116
) -> tuple[flight.FlightInfo, flight_inventory.FlightSchemaMetadata]:
115117
"""
116118
Often its necessary to create a FlightInfo object
117119
standardize doing that here.
118120
"""
119-
metadata = flight_inventory.FlightSchemaMetadata(
120-
type="scalar_function",
121+
metadata = flight_inventory.ScalarFunctionMetadata(
121122
catalog=catalog_name,
122123
schema=schema_name,
123124
name=name,
124125
comment=None,
125126
input_schema=self.input_schema,
127+
stability=self.stability,
126128
)
127129
flight_info = flight.FlightInfo(
128130
self.output_schema,
@@ -520,6 +522,15 @@ def add_handler(table: pa.Table) -> pa.Array:
520522
return pc.add(table.column(0), table.column(1))
521523

522524

525+
def no_op_handler(table: pa.Table) -> pa.Array:
526+
return table.column(0)
527+
528+
529+
def time_handler(table: pa.Table) -> pa.Array:
530+
current_time = datetime.datetime.now(datetime.timezone.utc)
531+
return pa.array([current_time] * table.num_rows, type=pa.timestamp("us"))
532+
533+
523534
def uppercase_handler(table: pa.Table) -> pa.Array:
524535
assert table.num_columns == 1
525536
return pc.utf8_upper(table.column(0))
@@ -923,28 +934,51 @@ def collatz_steps(n: int) -> list[int]:
923934
input_schema=pa.schema([pa.field("a", pa.string())]),
924935
output_schema=pa.schema([pa.field("result", pa.string())]),
925936
handler=uppercase_handler,
937+
stability="consistent",
926938
),
927939
"test_any_type": ScalarFunction(
928940
input_schema=pa.schema([pa.field("a", pa.string(), metadata={"is_any_type": "1"})]),
929941
output_schema=pa.schema([pa.field("result", pa.string())]),
930942
handler=any_type_handler,
943+
stability="consistent",
944+
),
945+
"test_time": ScalarFunction(
946+
input_schema=pa.schema([]),
947+
output_schema=pa.schema([pa.field("result", pa.timestamp("us"))]),
948+
handler=time_handler,
949+
stability="consistent_within_query",
950+
),
951+
"test_no_op": ScalarFunction(
952+
input_schema=pa.schema([pa.field("a", pa.int64(), metadata={"is_any_type": "1"})]),
953+
output_schema=pa.schema([pa.field("result", pa.int64())]),
954+
handler=no_op_handler,
955+
stability="consistent",
956+
),
957+
"test_no_op_string": ScalarFunction(
958+
input_schema=pa.schema([pa.field("a", pa.string())]),
959+
output_schema=pa.schema([pa.field("result", pa.string())]),
960+
handler=no_op_handler,
961+
stability="consistent",
931962
),
932963
"test_add": ScalarFunction(
933964
input_schema=pa.schema([pa.field("a", pa.int64()), pa.field("b", pa.int64())]),
934965
output_schema=pa.schema([pa.field("result", pa.int64())]),
935966
handler=add_handler,
967+
stability="consistent",
936968
),
937969
"collatz": ScalarFunction(
938970
input_schema=pa.schema([pa.field("n", pa.int64())]),
939971
output_schema=pa.schema([pa.field("result", pa.int64())]),
940972
handler=lambda table: collatz(table.column(0)),
973+
stability="consistent",
941974
),
942975
"collatz_sequence": ScalarFunction(
943976
input_schema=pa.schema([pa.field("n", pa.int64())]),
944977
output_schema=pa.schema([pa.field("result", pa.list_(pa.int64()))]),
945978
handler=lambda table: pa.array(
946979
[collatz_steps(n) for n in table.column(0).to_pylist()], type=pa.list_(pa.int64())
947980
),
981+
stability="consistent",
948982
),
949983
}
950984
),

src/query_farm_airport_test_server/server.py

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,10 @@ def action_list_schemas(
211211
) -> base_server.AirportSerializedCatalogRoot:
212212
assert context.caller is not None
213213

214-
with DatabaseLibraryContext(context.caller.token.token, readonly=True) as library:
214+
with DatabaseLibraryContext(context.caller.token.token) as library:
215+
if parameters.catalog_name not in library.databases_by_name:
216+
library.databases_by_name[parameters.catalog_name] = DatabaseContents()
217+
215218
database = library.by_name(parameters.catalog_name)
216219

217220
dynamic_inventory: dict[str, dict[str, list[flight_inventory.FlightInventoryWithMetadata]]] = {}
@@ -239,7 +242,13 @@ def action_list_schemas(
239242
),
240243
flight_service_name=self.service_name,
241244
flight_inventory=dynamic_inventory,
242-
schema_details={},
245+
schema_details={
246+
"static_data": flight_inventory.SchemaInfo(
247+
description="Some example static data",
248+
tags={},
249+
is_default=True,
250+
)
251+
},
243252
skip_upload=True,
244253
serialize_inline=True,
245254
catalog_version=1,
@@ -650,14 +659,14 @@ def exchange_insert(
650659
rowid_index = existing_table.schema.get_field_index(self.ROWID_FIELD_NAME)
651660
assert rowid_index != -1
652661

662+
has_non_nullable_field = any(map(lambda field: not field.nullable, existing_table.schema))
663+
653664
# Check that the data being read matches the table without the rowid column.
654665

655666
# DuckDB won't send field metadata when it sends us the schema that it uses
656667
# to perform an insert, so we need some way to adapt the schema we
657668
check_schema_is_subset_of_schema(existing_table.schema, reader.schema)
658669

659-
# FIXME: need to handle the case of rowids.
660-
661670
for chunk in reader:
662671
if chunk.data is not None:
663672
new_rows = pa.Table.from_batches([chunk.data])
@@ -681,14 +690,10 @@ def exchange_insert(
681690

682691
# append the row id column to the new rows.
683692
chunk_length = new_rows.num_rows
684-
rowid_values = [
685-
x
686-
for x in range(
687-
table_info.row_id_counter,
688-
table_info.row_id_counter + chunk_length,
689-
)
690-
]
691-
new_rows = new_rows.append_column(self.rowid_field, [rowid_values])
693+
rowid_array = pa.array(
694+
range(table_info.row_id_counter, table_info.row_id_counter + chunk_length), type=pa.int64()
695+
)
696+
new_rows = new_rows.append_column(self.rowid_field, rowid_array)
692697
table_info.row_id_counter += chunk_length
693698
change_count += chunk_length
694699

@@ -699,16 +704,8 @@ def exchange_insert(
699704
# the ensure that the columns are aligned in the same order as the original table.
700705

701706
# So it turns out that DuckDB doesn't send the "not null" flag in the arrow schema.
702-
#
703-
# This means we can't concat the tables, without those flags matching.
704-
# for field_name in existing_table.schema.names:
705-
# field = existing_table.schema.field(field_name)
706-
# if not field.nullable:
707-
# field_index = new_rows.schema.get_field_index(field_name)
708-
# new_rows = new_rows.set_column(
709-
# field_index, field.with_nullable(False), new_rows.column(field_index)
710-
# )
711-
new_rows = conform_nullable(existing_table.schema, new_rows)
707+
if has_non_nullable_field:
708+
new_rows = conform_nullable(existing_table.schema, new_rows)
712709

713710
existing_table = pa.concat_tables([existing_table, new_rows.select(existing_table.schema.names)])
714711

0 commit comments

Comments
 (0)