Skip to content

Commit

Permalink
Merge pull request #253 from oarepo/synthetic-fields-group-ordering
Browse files Browse the repository at this point in the history
Support for fields on record api and ordering within facet groups
  • Loading branch information
mirekys authored Feb 26, 2024
2 parents 152d77c + 4e705f3 commit 3a37755
Show file tree
Hide file tree
Showing 12 changed files with 258 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class FacetDefinition:
dot_path: str
searchable: bool
imports: List[Dict[str, str]]
facet_groups: List[str]
facet_groups: Dict[str, int]
facet: Optional[bool]
field: Optional[str] = None

Expand Down
21 changes: 18 additions & 3 deletions oarepo_model_builder/datatypes/components/facets/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@
from . import FacetDefinition


class FacetGroupsDict(fields.Dict):
def _deserialize(self, value, attr, data, **kwargs):
transformed_value = {}
if isinstance(value, list):
for val in value:
if isinstance(val, str):
transformed_value[val] = 100000
else:
transformed_value.update(val)
else:
transformed_value = value
return super()._deserialize(transformed_value, attr, data, **kwargs)


class FacetsSchema(ma.Schema):
class Meta:
unknown = ma.RAISE
Expand All @@ -23,8 +37,9 @@ class Meta:
imports = fields.List(fields.Nested(ImportSchema), required=False)
path = fields.String(required=False)
keyword = fields.String(required=False)
facet_groups = fields.List(
fields.String(),
facet_groups = FacetGroupsDict(
keys=fields.String(),
values=fields.Integer(),
required=False,
data_key="facet-groups",
attribute="facet-groups",
Expand Down Expand Up @@ -60,7 +75,7 @@ def process_facets(self, datatype, section, **__kwargs):
searchable=facet_section.get("searchable"),
imports=facet_section.get("imports", []),
facet=facet_section.get("facet", None),
facet_groups=facet_section.get("facet-groups", ["_default"]),
facet_groups=facet_section.get("facet-groups", {"_default": 100000}),
)

# set the field on the definition
Expand Down
11 changes: 11 additions & 0 deletions oarepo_model_builder/datatypes/components/model/facets.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ class Meta:
)
generate = ma.fields.Boolean()
skip = ma.fields.Boolean()
facet_groups = ma.fields.Dict(
attribute="facet-groups",
data_key="facet-groups",
keys=ma.fields.String(),
values=ma.fields.Dict(keys=ma.fields.String(), values=ma.fields.Integer()),
metadata={
"doc": "Groups of facets in the form of {group_name: {facet_path: priority}}. Will merge with facet "
"groups declared on the individual fields."
},
)


class FacetsModelComponent(ObjectFacetsComponent):
Expand All @@ -45,6 +55,7 @@ def before_model_prepare(self, datatype, *, context, **__kwargs):
facets.setdefault("module", f"{module}.services.{profile_module}.facets")

facets.setdefault("extra-code", "")
facets.setdefault("groups", True)

def build_facet_definition(
self,
Expand Down
6 changes: 6 additions & 0 deletions oarepo_model_builder/datatypes/components/model/record.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ class Meta:
ma.fields.Nested(ImportSchema), metadata={"doc": "List of python imports"}
)
skip = ma.fields.Boolean()
fields = ma.fields.Dict(
attribute="fields",
data_key="fields",
metadata={"doc": "Extra fields to add to the class"},
)


class RecordModelComponent(DataTypeComponent):
Expand Down Expand Up @@ -65,4 +70,5 @@ def before_model_prepare(self, datatype, *, context, **kwargs):
[],
)
record.setdefault("extra-code", "")
record.setdefault("fields", {})
convert_config_to_qualified_name(record)
10 changes: 10 additions & 0 deletions oarepo_model_builder/datatypes/components/model/search_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ class Meta:
data_key="sort-options-field",
)

fields = ma.fields.Dict(
keys=ma.fields.Str(),
values=ma.fields.Str(),
metadata={"doc": "Fields to be used in search options"},
)


class SearchOptionsModelComponent(DataTypeComponent):
eligible_datatypes = [ModelDataType]
Expand Down Expand Up @@ -77,4 +83,8 @@ def before_model_prepare(self, datatype, *, context, **kwargs):
"imports",
[],
)
record_search_options.setdefault(
"fields",
{},
)
record_search_options.setdefault("sort-options-field", "sort_options")
54 changes: 49 additions & 5 deletions oarepo_model_builder/invenio/invenio_record_search_options.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from collections import defaultdict
from typing import List

from ..datatypes.components.facets import FacetDefinition
Expand All @@ -15,19 +16,62 @@ def finish(self, **extra_kwargs):
facet_groups = {}
default_group = []
search_data = []

# gather all facet group names
facet_group_names = set()
for f in facets:
facet_group_names.update(f.facet_groups.keys())

# there might be a definition of facet groups on the model's facets -> facet-groups
# if there is, we need to merge those
top_level_facet_groups = self.current_model.definition.get("facets", {}).get(
"facet-groups", {}
)
facet_group_names.update(top_level_facet_groups.keys())
path_to_facet_group = defaultdict(dict)

for group, group_def in top_level_facet_groups.items():
for path, priority in group_def.items():
path_to_facet_group[group][path] = priority

# for each group name, gather all facets with that group name
# sort them by their order in the group
# and add them to the facet_groups dict
for group in sorted(facet_group_names):
# skip the default group
if group == "_default":
continue

# gather all facets with this facet_group_name
group_members = []
for f in facets:
if group in f.facet_groups:
group_members.append((f, f.facet_groups[group]))

# if there is a definition of facet groups on the model's facets -> add the selected facets as well
for path, priority in path_to_facet_group.get(group, {}).items():
if f.dot_path.startswith(path):
group_members.append((f, priority))

# sort the group members by their order in the facet_group
group_members.sort(key=lambda x: x[1])

if group not in facet_groups.keys():
facet_groups[group] = {}

for f, _ in group_members:
facet_groups[group][f.path] = "facets." + f.path

for f in facets:
for group in f.facet_groups:
if group != "_default":
if group not in facet_groups.keys():
facet_groups[group] = {}
facet_groups[group][f.path] = "facets." + f.path
if len(f.facet_groups) > 0:
default_group.append({f.path: "facets." + f.path})
search_data.append({f.path: "facets." + f.path})

if "sortable" in self.current_model.definition:
sort_options = self.current_model.definition["sortable"]
else:
sort_options = {}

extra_kwargs["facet_groups"] = facet_groups
extra_kwargs["default_group"] = default_group
extra_kwargs["sort_definition"] = sort_options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from oarepo_runtime.i18n import lazy_gettext as _
from . import facets

{% for extra_field_value in vars.search_options.fields.values() %}
{{ extra_field_value|code_imports }}
{% endfor %}


class {{ vars.search_options| class_header }}:
"""{{ vars.record.class|base_name }} search options."""
Expand Down Expand Up @@ -49,5 +53,8 @@ class {{ vars.search_options| class_header }}:
{% endfor %}
}
{% endif %}
{% for extra_field_name, extra_field_value in vars.search_options.fields.items() %}
{{ extra_field_name }} = {{ extra_field_value|extra_code }}
{% endfor %}

{{ vars.search_options|extra_code }}
8 changes: 8 additions & 0 deletions oarepo_model_builder/invenio/templates/record.py.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ from invenio_records_resources.records.systemfields import IndexField
{{ vars.record_dumper.class|imports }}
{{ vars.record|imports }}

{% for extra_field_value in vars.record.fields.values() %}
{{ extra_field_value|code_imports }}
{% endfor %}


class {{ vars.record|class_header }}:
{% if not vars.record_metadata.skip %}
model_cls = {{ vars.record_metadata.class|base_name }}
Expand All @@ -30,5 +35,8 @@ class {{ vars.record|class_header }}:
{% if not vars.record_dumper.skip %}
dumper = {{ vars.record_dumper.class|base_name }}()
{% endif %}
{% for extra_field_name, extra_field_value in vars.record.fields.items() %}
{{ extra_field_name }} = {{ extra_field_value|extra_code }}
{% endfor %}

{{ vars.record|extra_code }}
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = oarepo-model-builder
version = 4.0.74
version = 4.0.75
description = A utility library that generates OARepo required data model files from a JSON specification file
authors = Miroslav Bauer <[email protected]>, Miroslav Simek <[email protected]>
readme = README.md
Expand Down
3 changes: 3 additions & 0 deletions tests/test_datatype_prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def test_prepare_datatype():
"invenio_records_resources.services.SearchOptions{InvenioSearchOptions}"
],
"imports": [],
"fields": {},
"sort-options-field": "sort_options",
},
"config": {
Expand Down Expand Up @@ -112,6 +113,7 @@ def test_prepare_datatype():
"facets": {
"generate": True,
"module": "my.test.services.records.facets",
'groups': True,
"extra-code": "",
},
"record": {
Expand All @@ -123,6 +125,7 @@ def test_prepare_datatype():
],
"imports": [],
"extra-code": "",
"fields": {},
},
"resource": {
"generate": True,
Expand Down
6 changes: 6 additions & 0 deletions tests/test_model_saver.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def test_model_saver():
"invenio_records_resources.services.SearchOptions{InvenioSearchOptions}"
],
"imports": [],
"fields": {},
"sort-options-field": "sort_options",
},
"config": {
Expand Down Expand Up @@ -106,6 +107,7 @@ def test_model_saver():
"facets": {
"generate": True,
"module": "test.services.records.facets",
'groups': True,
"extra-code": "",
},
"record": {
Expand All @@ -117,6 +119,7 @@ def test_model_saver():
],
"imports": [],
"extra-code": "",
"fields": {},
},
"resource": {
"generate": True,
Expand Down Expand Up @@ -438,6 +441,7 @@ def test_model_saver_invenio():
"invenio_records_resources.services.SearchOptions{InvenioSearchOptions}"
],
"imports": [],
"fields": {},
"sort-options-field": "sort_options",
},
"config": {
Expand Down Expand Up @@ -474,6 +478,7 @@ def test_model_saver_invenio():
"facets": {
"generate": True,
"module": "test.services.records.facets",
"groups": True,
"extra-code": "",
},
"record": {
Expand All @@ -485,6 +490,7 @@ def test_model_saver_invenio():
],
"imports": [],
"extra-code": "",
"fields": {},
},
"resource": {
"generate": True,
Expand Down
Loading

0 comments on commit 3a37755

Please sign in to comment.