diff --git a/format-specs/geoparquet.md b/format-specs/geoparquet.md index dc5324e..d476139 100644 --- a/format-specs/geoparquet.md +++ b/format-specs/geoparquet.md @@ -227,7 +227,7 @@ Note: This technique to use the bounding box to improve spatial queries does not ### Bounding Box Columns -A bounding box column MUST be a Parquet group field with 4 child fields named `xmin`, `xmax`, `ymin`, and `ymax` representing the geometry's coordinate range. As with the top-level [`bbox`](#bbox) column, the values follow the GeoJSON specification (RFC 7946, section 5), which also describes how to represent the bbox for geometries that cross the antimeridian. For three dimensions the additional fields `zmin` and `zmax` MAY be present but are not required. The fields MUST be of Parquet type `FLOAT` or `DOUBLE` and all columns MUST use the same type. The repetition of a bounding box column MUST match the geometry column's [repetition](#repetition). A row MUST contain a bounding box value if and only if the row contains a geometry value. In cases where the geometry is optional and a row does not contain a geometry value, the row MUST NOT contain a bounding box value. +A bounding box column MUST be a Parquet group field with 4 or 6 child fields representing the geometry's coordinate range. For two-dimensional data, the child fields MUST be named `xmin`, `ymin`, `xmax`, and `ymax` and MUST be ordered in this same way. As with the top-level [`bbox`](#bbox) column, the values follow the GeoJSON specification (RFC 7946, section 5), which also describes how to represent the bbox for geometries that cross the antimeridian. For three dimensions the additional fields `zmin` and `zmax` MAY be present but are not required. If `zmin` is present then `zmax` MUST be present and vice versa. If `zmin` and `zmax` are present, the ordering of the child fields MUST be `xmin`, `ymin`, `zmin`, `xmax`, `ymax`, `zmax`. The fields MUST be of Parquet type `FLOAT` or `DOUBLE` and all columns MUST use the same type. The repetition of a bounding box column MUST match the geometry column's [repetition](#repetition). A row MUST contain a bounding box value if and only if the row contains a geometry value. In cases where the geometry is optional and a row does not contain a geometry value, the row MUST NOT contain a bounding box value. The bounding box column MUST be at the root of the schema. The bounding box column MUST NOT be nested in a group. diff --git a/format-specs/schema.json b/format-specs/schema.json index 7db7ab0..26cddec 100644 --- a/format-specs/schema.json +++ b/format-specs/schema.json @@ -74,7 +74,9 @@ }, "covering": { "type": "object", - "minProperties": 1, + "required": [ + "bbox" + ], "properties": { "bbox": { "type": "object", @@ -83,7 +85,7 @@ "xmin": { "type": "array", "items": [ - { "type": "string" }, + { "type": "string", "minLength": 1 }, { "const": "xmin" } ], "minItems": 2, @@ -92,7 +94,7 @@ "xmax": { "type": "array", "items": [ - { "type": "string" }, + { "type": "string", "minLength": 1 }, { "const": "xmax" } ], "minItems": 2, @@ -101,7 +103,7 @@ "ymin": { "type": "array", "items": [ - { "type": "string" }, + { "type": "string", "minLength": 1 }, { "const": "ymin" } ], "minItems": 2, @@ -110,7 +112,7 @@ "ymax": { "type": "array", "items": [ - { "type": "string" }, + { "type": "string", "minLength": 1 }, { "const": "ymax" } ], "minItems": 2, diff --git a/scripts/test_json_schema.py b/scripts/test_json_schema.py index be0888f..61a1b4b 100644 --- a/scripts/test_json_schema.py +++ b/scripts/test_json_schema.py @@ -221,7 +221,6 @@ def get_version() -> str: }, } - # Allow "any_column.xmin" etc. metadata = copy.deepcopy(metadata_covering_template) valid_cases["valid_default_bbox"] = metadata @@ -235,6 +234,15 @@ def get_version() -> str: } valid_cases["valid_but_not_bbox_struct_name"] = metadata +metadata = copy.deepcopy(metadata_covering_template) +metadata["columns"]["geometry"]["covering"]["bbox"] = { + "xmin": ["", "xmin"], + "ymin": ["", "ymin"], + "xmax": ["", "xmax"], + "ymax": ["", "ymax"], +} +invalid_cases["empty_column_name"] = metadata + metadata = copy.deepcopy(metadata_covering_template) metadata["columns"]["geometry"]["covering"]["bbox"]["xmin"] = [] invalid_cases["xmin_array_length_must_be_2_is_0"] = metadata