Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for fields on record api and ordering within facet groups #253

Merged
merged 6 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading