diff --git a/src/caosadvancedtools/json_schema_exporter.py b/src/caosadvancedtools/json_schema_exporter.py index ca0e6489b0411b0b22f25065a6e6349ec06be06f..536282d5092f9d19ca6e192f2f69703fef437830 100644 --- a/src/caosadvancedtools/json_schema_exporter.py +++ b/src/caosadvancedtools/json_schema_exporter.py @@ -22,8 +22,8 @@ """Module for converting a data model into a json schema compatible dictionary. """ -from typing import Any, List, Optional from collections import OrderedDict +from typing import Any, Iterable, List, Optional, Union import linkahead as db from linkahead.common.datatype import get_list_datatype, is_list_datatype @@ -318,3 +318,93 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T do_not_create=do_not_create, ) return exporter.recordtype_to_json_schema(rt) + + +def make_array(schema: dict) -> dict: + """Create an array of the given schema. + +The result will look like this: + +.. code:: js + + { "type": "array", + "items": { + // the schema + } + } + +Parameters +---------- + +schema : dict + The JSON schema which shall be packed into an array. + +Returns +------- + +out : dict + A JSON schema dict with a top-level array which contains instances of the given schema. + """ + result = { + "type": "array", + "items": schema, + "$schema": "https://json-schema.org/draft/2019-09/schema", + } + return result + + +def merge_schemas(schemas: Union[dict[str, dict], Iterable[dict]]) -> dict: + """Merge the given schemata into a single schema. + +The result will look like this: + +.. code:: js + + { + "type": "object", + "properties": { + // A, B, C + }, + "required": [ + // "A", "B", "C" + ], + "additionalProperties": false + } + + +Parameters +---------- + +schemas : dict[str, dict] | Iterable[dict] + A dict or iterable of schemata which shall be merged together. If this is a dict, the keys will + be used as property names, otherwise the titles of the submitted schemata. If they have no title, + numbers will be used as a fallback. Note that even with a dict, the original schema's "title" is + not changed. + +Returns +------- + +out : dict + A JSON schema dict with a top-level object which contains the given schemata as properties. + """ + sub_schemas: dict[str, dict] = OrderedDict() + required = [] + + if isinstance(schemas, dict): + sub_schemas = schemas + required = [str(k) for k in schemas.keys()] + else: + for i, schema in enumerate(schemas, start=1): + title = schema.get("title", str(i)) + sub_schemas[title] = schema + required.append(title) + + result = { + "type": "object", + "properties": sub_schemas, + "required": required, + "additionalProperties": False, + "$schema": "https://json-schema.org/draft/2019-09/schema", + } + + return result diff --git a/unittests/test_json_schema_exporter.py b/unittests/test_json_schema_exporter.py index 597c86a9a375e05fdc6b85fad4e0cb1a44b125e9..edb5c4e1645310db8503d1a35aa31e633fbd6aec 100644 --- a/unittests/test_json_schema_exporter.py +++ b/unittests/test_json_schema_exporter.py @@ -25,6 +25,7 @@ import json import linkahead as db +import caosadvancedtools.json_schema_exporter as jsex from jsonschema import FormatChecker, validate, ValidationError from pytest import raises @@ -681,3 +682,44 @@ RT2: "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "RT2" }""" + + +def test_schema_modification(): + """Testing functions which modify json schema dicts: + +- make_array() +- merge_schemas(). + """ + + model_str = """ +some_date: + datatype: DATETIME +RT1: + obligatory_properties: + some_date: + +some_text: + datatype: TEXT +RT2: + obligatory_properties: + some_text: + """ + model = parse_model_from_string(model_str) + schema_RT1 = rtjs(model.get_deep("RT1"), additional_properties=False) + schema_RT2 = rtjs(model.get_deep("RT2"), additional_properties=False) + + # Merge the schemata + merged_list = jsex.merge_schemas([schema_RT1, schema_RT2]) + assert merged_list["type"] == "object" + assert merged_list["properties"]["RT1"]["title"] == "RT1" + assert merged_list["properties"]["RT2"]["properties"]["some_text"]["type"] == "string" + + merged_dict = jsex.merge_schemas({"schema1": schema_RT1, "schema2": schema_RT2}) + assert merged_dict["type"] == "object" + assert merged_dict["properties"]["schema1"]["title"] == "RT1" + assert merged_dict["properties"]["schema2"]["properties"]["some_text"]["type"] == "string" + + # Make an array + array = jsex.make_array(schema_RT1) + assert array["type"] == "array" + assert array["items"] == schema_RT1