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

Added Object Query Language #553

Merged
merged 7 commits into from
Oct 16, 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
12 changes: 12 additions & 0 deletions gramps_webapi/api/resources/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from typing import Dict, List

import gramps_ql as gql
import object_ql as oql
from flask import Response, abort, request
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.db import DbTxn
Expand Down Expand Up @@ -350,6 +351,7 @@ class GrampsObjectsResource(GrampsObjectResourceHelper, Resource):
),
"format_options": fields.Str(validate=validate.Length(min=1)),
"gql": fields.Str(validate=validate.Length(min=1)),
"oql": fields.Str(validate=validate.Length(min=1)),
"gramps_id": fields.Str(validate=validate.Length(min=1)),
"keys": fields.DelimitedList(fields.Str(validate=validate.Length(min=1))),
"locale": fields.Str(
Expand Down Expand Up @@ -430,6 +432,16 @@ def get(self, args: Dict) -> Response:
except (ParseBaseException, ValueError, TypeError) as e:
abort_with_message(422, str(e))

if "oql" in args:
try:
objects = [
obj
for obj in objects
if oql.match(query=args["oql"], obj=obj, db=self.db_handle)
]
except (ParseBaseException, ValueError, TypeError) as e:
abort_with_message(422, str(e))

if self.gramps_class_name == "Media" and args.get("filemissing"):
objects = filter_missing_files(objects)

Expand Down
2 changes: 2 additions & 0 deletions gramps_webapi/api/resources/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"""Metadata API resource."""

import gramps_ql as gql
import object_ql as oql
import pytesseract
import sifts
from flask import Response, current_app
Expand Down Expand Up @@ -119,6 +120,7 @@ def get(self, args) -> Response:
"version": VERSION,
},
"gramps_ql": {"version": gql.__version__},
"object_ql": {"version": oql.__version__},
"locale": {
"lang": GRAMPS_LOCALE.lang,
"language": GRAMPS_LOCALE.language[0],
Expand Down
10 changes: 9 additions & 1 deletion gramps_webapi/data/apispec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9964,9 +9964,17 @@ definitions:
type: object
properties:
version:
description: "The version of the Gramps Gramps QL library."
description: "The version of the Gramps QL library."
type: string
example: "0.3.0"
object_ql:
description: "Information about the installed Object QL library."
type: object
properties:
version:
description: "The version of the Object QL library."
type: string
example: "0.1.1"
locale:
description: "The active locale."
type: object
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies = [
"Unidecode",
"pytesseract",
"gramps-ql>=0.3.0",
"object-ql>=0.1.2",
"sifts>=0.8.3",
]

Expand Down
33 changes: 33 additions & 0 deletions tests/test_endpoints/test_people.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,39 @@ def test_get_people_parameter_gql_or(self):
)
assert len(rv) == 20

def test_get_people_parameter_oql_validate_semantics(self):
"""Test invalid rules syntax."""
check_invalid_semantics(self, TEST_URL + "?oql=(")

def test_get_people_parameter_oql_handle(self):
"""Test equal field."""
rv = check_success(
self,
TEST_URL + "?oql=" + quote("person.gramps_id == 'I0044'"),
)
assert len(rv) == 1
assert rv[0]["gramps_id"] == "I0044"

def test_get_people_parameter_oql_like(self):
"""Test string in field."""
rv = check_success(
self,
TEST_URL + "?oql=" + quote("'I004' in person.gramps_id"),
)
assert len(rv) == 10

def test_get_people_parameter_oql_or(self):
"""Test two expr combined with or."""
rv = check_success(
self,
TEST_URL
+ "?oql="
+ quote(
"(person.gramps_id.startswith('I004') or person.gramps_id.startswith('I003'))"
),
)
assert len(rv) == 20

def test_get_people_parameter_extend_validate_semantics(self):
"""Test invalid extend parameter and values."""
check_invalid_semantics(self, TEST_URL + "?extend", check="list")
Expand Down