blob: 3c36f93b7ea98631749719e44c856f96f4da079c [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.
import pyarrow as pa
from pypaimon import Schema
from pypaimon.catalog.catalog_exception import IllegalStateError, TableNotExistException
from pypaimon.common.identifier import Identifier
from pypaimon.table.format.format_table import FormatTable
from pypaimon.tests.rest.rest_base_test import RESTBaseTest
class RESTCreatePartitionsTest(RESTBaseTest):
def _create_table(self, table_name, partition_keys=None):
schema = Schema.from_pyarrow_schema(
pa.schema([("id", pa.int32()), ("dt", pa.string()), ("hh", pa.string())]),
partition_keys=partition_keys if partition_keys is not None else ["dt", "hh"],
options={"type": "format-table", "file.format": "parquet",
"metastore.partitioned-table": "true"},
)
self.rest_catalog.drop_table(table_name, True)
self.rest_catalog.create_table(table_name, schema, False)
return table_name
def _listed_specs(self, table_name):
return [p.spec for p in self.rest_catalog.list_partitions_paged(table_name).elements]
def test_created_partitions_come_back_from_list(self):
table_name = self._create_table("default.create_partitions_round_trip")
specs = [
{"dt": "20260807", "hh": "01"},
{"dt": "20260807", "hh": "02"},
]
self.rest_catalog.create_partitions(table_name, specs)
listed = self._listed_specs(table_name)
for spec in specs:
self.assertIn(spec, listed)
fresh = self.rest_catalog.list_partitions_paged(table_name).elements[0]
self.assertEqual(fresh.record_count, 0)
self.assertEqual(fresh.last_file_creation_time, 0)
def test_creating_twice_is_a_no_op_by_default(self):
table_name = self._create_table("default.create_partitions_idempotent")
specs = [{"dt": "20260807", "hh": "01"}]
self.rest_catalog.create_partitions(table_name, specs)
self.rest_catalog.create_partitions(table_name, specs)
listed = self._listed_specs(table_name)
self.assertEqual(listed.count({"dt": "20260807", "hh": "01"}), 1)
def test_creating_twice_raises_when_not_ignoring(self):
table_name = self._create_table("default.create_partitions_strict")
specs = [{"dt": "20260807", "hh": "01"}]
self.rest_catalog.create_partitions(table_name, specs)
with self.assertRaises(IllegalStateError):
self.rest_catalog.create_partitions(table_name, specs, ignore_if_exists=False)
def test_rejected_request_creates_nothing(self):
table_name = self._create_table("default.create_partitions_atomic")
self.rest_catalog.create_partitions(table_name, [{"dt": "20260807", "hh": "01"}])
before = self._listed_specs(table_name)
with self.assertRaises(IllegalStateError):
self.rest_catalog.create_partitions(
table_name,
[{"dt": "20260808", "hh": "00"}, {"dt": "20260807", "hh": "01"}],
ignore_if_exists=False,
)
self.assertEqual(self._listed_specs(table_name), before)
def test_empty_list_leaves_the_table_untouched(self):
table_name = self._create_table("default.create_partitions_empty")
before = self._listed_specs(table_name)
self.rest_catalog.create_partitions(table_name, [])
self.assertEqual(self._listed_specs(table_name), before)
def test_unknown_table_raises_table_not_exist(self):
with self.assertRaises(TableNotExistException):
self.rest_catalog.create_partitions(
"default.create_partitions_no_such_table", [{"dt": "20260807"}])
def test_unknown_table_raises_on_an_empty_list_too(self):
with self.assertRaises(TableNotExistException):
self.rest_catalog.create_partitions(
"default.create_partitions_no_such_table", [])
def test_registers_partitions_of_a_format_table(self):
table_name = self._create_table("default.create_partitions_format_table")
self.assertIsInstance(self.rest_catalog.get_table(table_name), FormatTable)
self.rest_catalog.create_partitions(table_name, [{"dt": "20260807", "hh": "01"}])
self.assertIn({"dt": "20260807", "hh": "01"}, self._listed_specs(table_name))
def test_response_separates_created_from_existed(self):
table_name = self._create_table("default.create_partitions_response")
old = {"dt": "20260807", "hh": "01"}
new = {"dt": "20260807", "hh": "02"}
self.rest_catalog.create_partitions(table_name, [old])
response = self.rest_catalog.rest_api.create_partitions(
Identifier.from_string(table_name), [old, new], True)
self.assertIsNotNone(response)
self.assertEqual(response.created, [new])
self.assertEqual(response.existed, [old])
def test_works_for_a_single_key_partitioned_table(self):
table_name = self._create_table(
"default.create_partitions_single_key", partition_keys=["dt"])
self.rest_catalog.create_partitions(table_name, [{"dt": "20260807"}])
self.assertIn({"dt": "20260807"}, self._listed_specs(table_name))