oldaplib 0.3.10__py3-none-any.whl → 0.3.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oldaplib/src/datamodel.py +4 -1
- oldaplib/src/objectfactory.py +403 -102
- oldaplib/src/version.py +1 -1
- oldaplib/test/test_objectfactory.py +65 -36
- oldaplib/testdata/instances_test.trig +119 -0
- {oldaplib-0.3.10.dist-info → oldaplib-0.3.12.dist-info}/METADATA +1 -1
- {oldaplib-0.3.10.dist-info → oldaplib-0.3.12.dist-info}/RECORD +8 -7
- {oldaplib-0.3.10.dist-info → oldaplib-0.3.12.dist-info}/WHEEL +0 -0
oldaplib/src/datamodel.py
CHANGED
|
@@ -753,15 +753,18 @@ class DataModel(Model):
|
|
|
753
753
|
f.write('\n')
|
|
754
754
|
f.write(context.turtle_context)
|
|
755
755
|
f.write(f'\n{blank:{indent * indent_inc}}{self.__graph}:shacl {{\n')
|
|
756
|
-
f.write(f'{blank:{(indent +
|
|
756
|
+
f.write(f'{blank:{(indent + 1) * indent_inc}}{self.__graph}:shapes schema:version {self.__version.toRdf} .\n')
|
|
757
757
|
f.write('\n')
|
|
758
758
|
for qname, onto in self.__extontos.items():
|
|
759
759
|
f.write(onto.create_shacl(timestamp=timestamp, indent=1))
|
|
760
|
+
f.write('\n\n')
|
|
760
761
|
for iri, prop in self.__propclasses.items():
|
|
761
762
|
if not prop.internal:
|
|
762
763
|
f.write(prop.create_shacl(timestamp=timestamp, indent=1))
|
|
764
|
+
f.write('\n\n')
|
|
763
765
|
for iri, resclass in self.__resclasses.items():
|
|
764
766
|
f.write(resclass.create_shacl(timestamp=timestamp, indent=1))
|
|
767
|
+
f.write('\n\n')
|
|
765
768
|
f.write(f'\n{blank:{indent * indent_inc}}}}\n')
|
|
766
769
|
|
|
767
770
|
f.write(f'{blank:{indent * indent_inc}}{self.__graph}:onto {{\n')
|
oldaplib/src/objectfactory.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
+
from enum import Flag, auto
|
|
2
3
|
from functools import partial
|
|
3
4
|
from typing import Type, Any, Self, cast
|
|
4
5
|
|
|
@@ -31,6 +32,11 @@ from oldaplib.src.xsd.xsd_qname import Xsd_QName
|
|
|
31
32
|
|
|
32
33
|
ValueType = LangString | ObservableSet | Xsd
|
|
33
34
|
|
|
35
|
+
class SortBy(Flag):
|
|
36
|
+
PROPVAL = auto()
|
|
37
|
+
CREATED = auto()
|
|
38
|
+
LASTMOD = auto()
|
|
39
|
+
|
|
34
40
|
|
|
35
41
|
#@strict
|
|
36
42
|
class ResourceInstance:
|
|
@@ -463,6 +469,27 @@ class ResourceInstance:
|
|
|
463
469
|
return result['boolean']
|
|
464
470
|
|
|
465
471
|
def create(self, indent: int = 0, indent_inc: int = 4) -> str:
|
|
472
|
+
"""
|
|
473
|
+
Generates an RDF/SPARQL INSERT DATA query for creating a resource with associated
|
|
474
|
+
metadata and verifies permissions before execution.
|
|
475
|
+
|
|
476
|
+
This method first checks for the necessary permissions to create a resource.
|
|
477
|
+
It assigns metadata such as the creation and modification information if
|
|
478
|
+
the resource name matches specific criteria. It ensures that no resource
|
|
479
|
+
with the same IRI exists before proceeding with the resource creation.
|
|
480
|
+
If a conflict is detected, an error is raised. The method finalizes the
|
|
481
|
+
creation of the resource by executing a SPARQL query in a transactional context.
|
|
482
|
+
|
|
483
|
+
:param indent: The current level of indentation (default is 0).
|
|
484
|
+
:type indent: int
|
|
485
|
+
:param indent_inc: The incremental spaces per indentation level (default is 4).
|
|
486
|
+
:type indent_inc: int
|
|
487
|
+
:return: A string representing the RDF/SPARQL query for creation.
|
|
488
|
+
:rtype: str
|
|
489
|
+
:raises OldapErrorNoPermission: If the user does not have the required permissions to create the resource.
|
|
490
|
+
:raises OldapErrorAlreadyExists: If a resource with the same IRI already exists.
|
|
491
|
+
:raises OldapError: For errors encountered during the SPARQL transaction execution.
|
|
492
|
+
"""
|
|
466
493
|
result, message = self.check_for_permissions(AdminPermission.ADMIN_CREATE)
|
|
467
494
|
if not result:
|
|
468
495
|
raise OldapErrorNoPermission(message)
|
|
@@ -519,6 +546,19 @@ class ResourceInstance:
|
|
|
519
546
|
def read(cls,
|
|
520
547
|
con: IConnection,
|
|
521
548
|
iri: Iri) -> Self:
|
|
549
|
+
"""
|
|
550
|
+
Reads an object of the specific class type from the RDF data source using the provided connection
|
|
551
|
+
and IRI. Validates that the retrieved RDF data matches the expected class type and ensures proper
|
|
552
|
+
permissions have been granted to access the resource.
|
|
553
|
+
|
|
554
|
+
:param con: The connection object to the data source (IConnection).
|
|
555
|
+
:param iri: The IRI of the resource to read (Iri).
|
|
556
|
+
:return: An object of the invoking class loaded with data from the RDF resource.
|
|
557
|
+
|
|
558
|
+
:raises OldapErrorInconsistency: If an expected QName is not found or if the retrieved object type
|
|
559
|
+
does not match the expected class type.
|
|
560
|
+
:raises OldapErrorNotFound: If the resource associated with the provided IRI is not found.
|
|
561
|
+
"""
|
|
522
562
|
graph = cls.project.projectShortName
|
|
523
563
|
context = Context(name=con.context_name)
|
|
524
564
|
sparql = context.sparql_context
|
|
@@ -567,6 +607,26 @@ class ResourceInstance:
|
|
|
567
607
|
return cls(iri=iri, **kwargs)
|
|
568
608
|
|
|
569
609
|
def update(self, indent: int = 0, indent_inc: int = 4) -> None:
|
|
610
|
+
"""
|
|
611
|
+
Updates the current resource by creating and executing SPARQL queries to modify, insert, or
|
|
612
|
+
delete data based on the changeset. This method also verifies user permissions and ensures
|
|
613
|
+
data consistency using timestamps. It commits modifications within a transaction while
|
|
614
|
+
rolling back changes upon encountering errors.
|
|
615
|
+
|
|
616
|
+
The `update` method processes changes in resource attributes specified in a changeset. It
|
|
617
|
+
constructs appropriate SPARQL queries for CREATE, MODIFY, and DELETE actions for each
|
|
618
|
+
field. Additionally, it updates the last modification timestamp for the resource and records
|
|
619
|
+
the user performing the update. If permissions are insufficient or an update fails, the
|
|
620
|
+
transaction is aborted.
|
|
621
|
+
|
|
622
|
+
:param indent: The initial level of indentation for the generated SPARQL queries.
|
|
623
|
+
:type indent: int
|
|
624
|
+
:param indent_inc: The incremental level of indentation for nested sections in SPARQL
|
|
625
|
+
queries.
|
|
626
|
+
:type indent_inc: int
|
|
627
|
+
:return: None
|
|
628
|
+
:rtype: None
|
|
629
|
+
"""
|
|
570
630
|
admin_resources, message = self.check_for_permissions(AdminPermission.ADMIN_RESOURCES)
|
|
571
631
|
|
|
572
632
|
context = Context(name=self._con.context_name)
|
|
@@ -694,6 +754,22 @@ class ResourceInstance:
|
|
|
694
754
|
self.clear_changeset()
|
|
695
755
|
|
|
696
756
|
def delete(self) -> None:
|
|
757
|
+
"""
|
|
758
|
+
Deletes the specified resource represented by the object's IRI from the associated graph
|
|
759
|
+
if the proper permissions are granted and the resource is not in use. This method initiates
|
|
760
|
+
a transactional sequence to ensure data consistency and rollback in case of an error.
|
|
761
|
+
The process includes checking permissions, querying whether the resource is in use,
|
|
762
|
+
and finally issuing a SPARQL DELETE query to remove the resource.
|
|
763
|
+
|
|
764
|
+
Raises appropriate exceptions if the resource is in use, permissions are insufficient,
|
|
765
|
+
or any other transaction-related error occurs.
|
|
766
|
+
|
|
767
|
+
:raises OldapErrorNoPermission: If the user lacks the necessary permissions to
|
|
768
|
+
delete the resource.
|
|
769
|
+
:raises OldapErrorInUse: If the resource is currently in use and cannot be deleted.
|
|
770
|
+
:raises OldapError: If any error occurs during transaction start, query, update,
|
|
771
|
+
or commit phases.
|
|
772
|
+
"""
|
|
697
773
|
admin_resources, message = self.check_for_permissions(AdminPermission.ADMIN_RESOURCES)
|
|
698
774
|
|
|
699
775
|
context = Context(name=self._con.context_name)
|
|
@@ -739,6 +815,333 @@ class ResourceInstance:
|
|
|
739
815
|
self._con.transaction_abort()
|
|
740
816
|
raise
|
|
741
817
|
|
|
818
|
+
@staticmethod
|
|
819
|
+
def read_data(con: IConnection, projectShortName: Xsd_NCName | str, iri: Iri | str) -> dict[Xsd_QName, Any]:
|
|
820
|
+
"""
|
|
821
|
+
Reads and processes data from a given IConnection instance based on a specified
|
|
822
|
+
project short name and a resource IRI. This method fetches the data from a graph
|
|
823
|
+
in the RDF database, verifies user permissions, and returns selected data in a
|
|
824
|
+
dictionary format.
|
|
825
|
+
|
|
826
|
+
:param con: The connection object used to query the RDF data.
|
|
827
|
+
:type con: IConnection
|
|
828
|
+
:param projectShortName: The short name of the project used to identify the graph
|
|
829
|
+
in the RDF store. Accepts either Xsd_NCName or a string.
|
|
830
|
+
:param iri: The IRI of the resource being queried. Accepts either Iri or a string.
|
|
831
|
+
:return: A dictionary mapping predicates to their associated values from the
|
|
832
|
+
selected resource.
|
|
833
|
+
:rtype: dict[Xsd_QName, Any]
|
|
834
|
+
:raises OldapErrorInconsistency: If a non-QName predicate is found in the results.
|
|
835
|
+
:raises OldapErrorNotFound: If the resource with the given IRI is not found.
|
|
836
|
+
"""
|
|
837
|
+
if not isinstance(iri, Iri):
|
|
838
|
+
iri = Iri(iri, validate=True)
|
|
839
|
+
if not isinstance(projectShortName, Xsd_NCName):
|
|
840
|
+
graph = Xsd_NCName(projectShortName)
|
|
841
|
+
else:
|
|
842
|
+
graph = projectShortName
|
|
843
|
+
|
|
844
|
+
context = Context(name=con.context_name)
|
|
845
|
+
sparql = context.sparql_context
|
|
846
|
+
sparql += f'''
|
|
847
|
+
SELECT ?predicate ?value
|
|
848
|
+
WHERE {{
|
|
849
|
+
GRAPH {graph}:data {{
|
|
850
|
+
{iri.toRdf} ?predicate ?value .
|
|
851
|
+
{iri.toRdf} oldap:grantsPermission ?permset .
|
|
852
|
+
}}
|
|
853
|
+
GRAPH oldap:admin {{
|
|
854
|
+
{con.userIri.toRdf} oldap:hasPermissions ?permset .
|
|
855
|
+
?permset oldap:givesPermission ?DataPermission .
|
|
856
|
+
?DataPermission oldap:permissionValue ?permval .
|
|
857
|
+
}}
|
|
858
|
+
FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})
|
|
859
|
+
}}
|
|
860
|
+
'''
|
|
861
|
+
jsonres = con.query(sparql)
|
|
862
|
+
res = QueryProcessor(context, jsonres)
|
|
863
|
+
data = {}
|
|
864
|
+
for r in res:
|
|
865
|
+
if r['predicate'].is_qname:
|
|
866
|
+
if not data.get(r['predicate'].as_qname):
|
|
867
|
+
data[r['predicate'].as_qname] = []
|
|
868
|
+
data[str(r['predicate'].as_qname)].append(str(r['value']))
|
|
869
|
+
else:
|
|
870
|
+
raise OldapErrorInconsistency(f"Expected QName as predicate, got {r['predicate']}")
|
|
871
|
+
if not data.get('rdf:type'):
|
|
872
|
+
raise OldapErrorNotFound(f'Resource with iri <{iri}> not found.')
|
|
873
|
+
return data
|
|
874
|
+
|
|
875
|
+
@staticmethod
|
|
876
|
+
def search_fulltext(con: IConnection,
|
|
877
|
+
projectShortName: Xsd_NCName | str,
|
|
878
|
+
s: str,
|
|
879
|
+
resClass: Xsd_QName | str | None = None,
|
|
880
|
+
countOnly: bool = False,
|
|
881
|
+
sortBy: SortBy | None = None,
|
|
882
|
+
limit: int = 100,
|
|
883
|
+
offset: int = 0,
|
|
884
|
+
indent: int = 0, indent_inc: int = 4) -> int | dict[Iri, dict[str, Xsd]]:
|
|
885
|
+
"""
|
|
886
|
+
Search for entities in a project using a full-text search query, with optional filters and sorting
|
|
887
|
+
based on resource class and properties.
|
|
888
|
+
|
|
889
|
+
:param con: The connection instance to interact with the SPARQL endpoint or database.
|
|
890
|
+
:type con: IConnection
|
|
891
|
+
:param projectShortName: The project short name (identifier). Can be provided as an Xsd_NCName or a
|
|
892
|
+
string. If a string, it is automatically validated and converted to an Xsd_NCName.
|
|
893
|
+
:type projectShortName: Xsd_NCName | str
|
|
894
|
+
:param s: The full-text search query to identify entities matching the specified string values.
|
|
895
|
+
:type s: str
|
|
896
|
+
:param resClass: An optional entity class (Xsd_QName) used to filter results. If provided as a string,
|
|
897
|
+
it is validated and converted to Xsd_QName.
|
|
898
|
+
:type resClass: Xsd_QName | str | None
|
|
899
|
+
:param countOnly: If True, only the count of matching entities will be returned. Defaults to False.
|
|
900
|
+
:type countOnly: bool
|
|
901
|
+
:param sortBy: Optional sorting criterion for the results, such as creation date, last modification date,
|
|
902
|
+
or property values. Defaults to None.
|
|
903
|
+
:type sortBy: SortBy | None
|
|
904
|
+
:param limit: The maximum number of records to return when count_only is False. Defaults to 100.
|
|
905
|
+
:type limit: int
|
|
906
|
+
:param offset: The number of records to skip for paginated queries. Defaults to 0.
|
|
907
|
+
:type offset: int
|
|
908
|
+
:param indent: Initial indentation level for the generated SPARQL query. Defaults to 0.
|
|
909
|
+
:type indent: int
|
|
910
|
+
:param indent_inc: Incremental indentation used during SPARQL query generation. Defaults to 4.
|
|
911
|
+
:type indent_inc: int
|
|
912
|
+
:return: If count_only is True, an integer representing the count of matching entities. If count_only is
|
|
913
|
+
False, a dictionary with entity IRIs as keys and their respective property-to-value mappings
|
|
914
|
+
as values.
|
|
915
|
+
:rtype: int | dict[Iri, dict[str, Xsd]]
|
|
916
|
+
|
|
917
|
+
The SPARQL generated is as follows
|
|
918
|
+
|
|
919
|
+
```sparql
|
|
920
|
+
SELECT DISTINCT ?s ?t ?p ?o ?creationDate
|
|
921
|
+
WHERE {
|
|
922
|
+
GRAPH test:data {
|
|
923
|
+
?s oldap:creationDate ?creationDate .
|
|
924
|
+
?s ?p ?o .
|
|
925
|
+
?s rdf:type ?t .
|
|
926
|
+
?s rdf:type test:Book .
|
|
927
|
+
?s oldap:grantsPermission ?permset .
|
|
928
|
+
}
|
|
929
|
+
FILTER(isLiteral(?o) && (datatype(?o) = xsd:string || datatype(?o) = rdf:langString || lang(?o) != ""))
|
|
930
|
+
FILTER(CONTAINS(LCASE(STR(?o)), "gaga")) # case-insensitive substring match
|
|
931
|
+
GRAPH oldap:admin {
|
|
932
|
+
<https://orcid.org/0000-0003-1681-4036> oldap:hasPermissions ?permset .
|
|
933
|
+
?permset oldap:givesPermission ?DataPermission .
|
|
934
|
+
?DataPermission oldap:permissionValue ?permval .
|
|
935
|
+
}
|
|
936
|
+
FILTER(?permval >= "2"^^xsd:integer)
|
|
937
|
+
}
|
|
938
|
+
ORDER BY ASC(?creationDate)LIMIT 100 OFFSET 0
|
|
939
|
+
```
|
|
940
|
+
"""
|
|
941
|
+
if not isinstance(projectShortName, Xsd_NCName):
|
|
942
|
+
graph = Xsd_NCName(projectShortName, validate=True)
|
|
943
|
+
else:
|
|
944
|
+
graph = projectShortName
|
|
945
|
+
if resClass and not isinstance(resClass, Xsd_QName):
|
|
946
|
+
resClass = Xsd_QName(resClass, validate=True)
|
|
947
|
+
|
|
948
|
+
blank = ''
|
|
949
|
+
context = Context(name=con.context_name)
|
|
950
|
+
sparql = context.sparql_context
|
|
951
|
+
|
|
952
|
+
if (countOnly):
|
|
953
|
+
sparql += f'{blank:{indent * indent_inc}}SELECT (COUNT(DISTINCT ?s) as ?numResult)'
|
|
954
|
+
else:
|
|
955
|
+
sparql += f'{blank:{indent * indent_inc}}SELECT DISTINCT ?s ?t ?p ?o'
|
|
956
|
+
if sortBy:
|
|
957
|
+
if sortBy == SortBy.CREATED:
|
|
958
|
+
sparql += ' ?creationDate'
|
|
959
|
+
if sortBy == SortBy.LASTMOD:
|
|
960
|
+
sparql += '?lastModificationDate'
|
|
961
|
+
sparql += f'\n{blank:{indent * indent_inc}}WHERE {{'
|
|
962
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH {graph}:data {{'
|
|
963
|
+
if sortBy:
|
|
964
|
+
if sortBy == SortBy.CREATED:
|
|
965
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:creationDate ?creationDate .'
|
|
966
|
+
if sortBy == SortBy.LASTMOD:
|
|
967
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:lastModificationDate ?lastModificationDate .'
|
|
968
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s ?p ?o .'
|
|
969
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s rdf:type ?t .'
|
|
970
|
+
if resClass:
|
|
971
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s rdf:type {resClass} .'
|
|
972
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:grantsPermission ?permset .'
|
|
973
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
|
|
974
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(isLiteral(?o) && (datatype(?o) = xsd:string || datatype(?o) = rdf:langString || lang(?o) != ""))'
|
|
975
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(CONTAINS(LCASE(STR(?o)), "{s}")) # case-insensitive substring match'
|
|
976
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH oldap:admin {{'
|
|
977
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}{con.userIri.toRdf} oldap:hasPermissions ?permset .'
|
|
978
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?permset oldap:givesPermission ?DataPermission .'
|
|
979
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?DataPermission oldap:permissionValue ?permval .'
|
|
980
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
|
|
981
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})'
|
|
982
|
+
sparql += f'\n{blank:{indent * indent_inc}}}}'
|
|
983
|
+
|
|
984
|
+
if sortBy:
|
|
985
|
+
if sortBy == SortBy.CREATED:
|
|
986
|
+
sparql += f'\n{blank:{indent * indent_inc}}ORDER BY ASC(?creationDate)'
|
|
987
|
+
if sortBy == SortBy.LASTMOD:
|
|
988
|
+
sparql += f'\n{blank:{indent * indent_inc}}ORDER BY ASC(?lastModificationDate)'
|
|
989
|
+
if sortBy == SortBy.PROPVAL:
|
|
990
|
+
sparql += f'\n{blank:{indent * indent_inc}}ORDER BY ASC(LCASE(STR(?o)))'
|
|
991
|
+
|
|
992
|
+
if not countOnly:
|
|
993
|
+
sparql += f'\n{blank:{indent * indent_inc}}LIMIT {limit} OFFSET {offset}'
|
|
994
|
+
sparql += '\n'
|
|
995
|
+
|
|
996
|
+
|
|
997
|
+
try:
|
|
998
|
+
jsonres = con.query(sparql)
|
|
999
|
+
except OldapError:
|
|
1000
|
+
print(sparql)
|
|
1001
|
+
raise
|
|
1002
|
+
res = QueryProcessor(context, jsonres)
|
|
1003
|
+
if countOnly:
|
|
1004
|
+
return res[0]['numResult']
|
|
1005
|
+
else:
|
|
1006
|
+
result = {}
|
|
1007
|
+
for r in res:
|
|
1008
|
+
tmp = {
|
|
1009
|
+
r['p']: r['o'],
|
|
1010
|
+
Xsd_QName('owl:Class'): r['t']
|
|
1011
|
+
}
|
|
1012
|
+
if sortBy:
|
|
1013
|
+
if sortBy == SortBy.CREATED:
|
|
1014
|
+
tmp['oldap:creationDate'] = r['creationDate'],
|
|
1015
|
+
if sortBy == SortBy.LASTMOD:
|
|
1016
|
+
tmp['oldap:lastModificationDate'] = r['lastModificationDate']
|
|
1017
|
+
result[r['s']] = tmp
|
|
1018
|
+
return result
|
|
1019
|
+
|
|
1020
|
+
@staticmethod
|
|
1021
|
+
def all_resources(con: IConnection,
|
|
1022
|
+
projectShortName: Xsd_NCName | str,
|
|
1023
|
+
resClass: Xsd_QName | str,
|
|
1024
|
+
includeProperties: list[Xsd_QName] | None = None,
|
|
1025
|
+
count_only: bool = False,
|
|
1026
|
+
sortBy: SortBy | None = None,
|
|
1027
|
+
limit: int = 100,
|
|
1028
|
+
offset: int = 0,
|
|
1029
|
+
indent: int = 0, indent_inc: int = 4) -> dict[Iri, dict[str, Xsd]]:
|
|
1030
|
+
"""
|
|
1031
|
+
Retrieves all resources matching the specified parameters from a data store using a SPARQL query.
|
|
1032
|
+
Depending on the `count_only` flag, it can return either a count of matching resources or detailed
|
|
1033
|
+
information about each resource.
|
|
1034
|
+
|
|
1035
|
+
:param con: The connection object used to execute the SPARQL query.
|
|
1036
|
+
:type con: IConnection
|
|
1037
|
+
:param projectShortName: The short name of the project being queried.
|
|
1038
|
+
:type projectShortName: Xsd_NCName | str
|
|
1039
|
+
:param resClass: The resource class to filter the results by.
|
|
1040
|
+
:type resClass: Xsd_QName | str
|
|
1041
|
+
:param includeProperties: A list of resource properties to include in the query and results.
|
|
1042
|
+
:type includeProperties: list[Xsd_QName] | None
|
|
1043
|
+
:param count_only: If True, returns only the count of matching resources. Defaults to False.
|
|
1044
|
+
:type count_only: bool
|
|
1045
|
+
:param sortBy: The sorting criterion for the results. Defaults to None.
|
|
1046
|
+
:type sortBy: SortBy | None
|
|
1047
|
+
:param limit: The maximum number of results to retrieve. Defaults to 100.
|
|
1048
|
+
:type limit: int
|
|
1049
|
+
:param offset: The starting point for result retrieval in pagination. Defaults to 0.
|
|
1050
|
+
:type offset: int
|
|
1051
|
+
:param indent: The initial level of indentation for the SPARQL query strings. Defaults to 0.
|
|
1052
|
+
:type indent: int
|
|
1053
|
+
:param indent_inc: The incremental level of indentation for the SPARQL query strings. Defaults to 4.
|
|
1054
|
+
:type indent_inc: int
|
|
1055
|
+
:return: A dictionary where keys are resource IRIs and values are dictionaries containing resource
|
|
1056
|
+
properties and their corresponding values. If `count_only` is True, returns the total count of
|
|
1057
|
+
matching resources as an integer.
|
|
1058
|
+
:rtype: dict[Iri, dict[str, Xsd]]
|
|
1059
|
+
:raises OldapError: If there is an error during query execution in the connection object.
|
|
1060
|
+
"""
|
|
1061
|
+
if not isinstance(projectShortName, Xsd_NCName):
|
|
1062
|
+
graph = Xsd_NCName(projectShortName, validate=True)
|
|
1063
|
+
else:
|
|
1064
|
+
graph = projectShortName
|
|
1065
|
+
if not isinstance(resClass, Xsd_QName):
|
|
1066
|
+
resClass = Xsd_QName(resClass, validate=True)
|
|
1067
|
+
|
|
1068
|
+
blank = ''
|
|
1069
|
+
context = Context(name=con.context_name)
|
|
1070
|
+
sparql = context.sparql_context
|
|
1071
|
+
|
|
1072
|
+
if (count_only):
|
|
1073
|
+
sparql += f'{blank:{indent * indent_inc}}SELECT (COUNT(DISTINCT ?s) as ?numResult)'
|
|
1074
|
+
else:
|
|
1075
|
+
sparql += f'{blank:{indent * indent_inc}}SELECT DISTINCT ?s'
|
|
1076
|
+
if includeProperties:
|
|
1077
|
+
for index, item in enumerate(includeProperties):
|
|
1078
|
+
sparql += f' ?o{index}'
|
|
1079
|
+
if sortBy:
|
|
1080
|
+
if sortBy == SortBy.CREATED:
|
|
1081
|
+
sparql += ' ?creationDate'
|
|
1082
|
+
if sortBy == SortBy.LASTMOD:
|
|
1083
|
+
sparql += '?lastModificationDate'
|
|
1084
|
+
sparql += f'\n{blank:{indent * indent_inc}}WHERE {{'
|
|
1085
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH {graph}:data {{'
|
|
1086
|
+
if sortBy:
|
|
1087
|
+
if sortBy == SortBy.CREATED:
|
|
1088
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:creationDate ?creationDate .'
|
|
1089
|
+
if sortBy == SortBy.LASTMOD:
|
|
1090
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:lastModificationDate ?lastModificationDate .'
|
|
1091
|
+
if includeProperties:
|
|
1092
|
+
for index, prop in enumerate(includeProperties):
|
|
1093
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s {prop} ?o{index} .'
|
|
1094
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s rdf:type {resClass} .'
|
|
1095
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:grantsPermission ?permset .'
|
|
1096
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
|
|
1097
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH oldap:admin {{'
|
|
1098
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}{con.userIri.toRdf} oldap:hasPermissions ?permset .'
|
|
1099
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?permset oldap:givesPermission ?DataPermission .'
|
|
1100
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?DataPermission oldap:permissionValue ?permval .'
|
|
1101
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
|
|
1102
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})'
|
|
1103
|
+
sparql += f'\n{blank:{indent * indent_inc}}}}'
|
|
1104
|
+
|
|
1105
|
+
if sortBy:
|
|
1106
|
+
if sortBy == SortBy.CREATED:
|
|
1107
|
+
sparql += f'\n{blank:{indent * indent_inc}}ORDER BY ASC(?creationDate)'
|
|
1108
|
+
if sortBy == SortBy.LASTMOD:
|
|
1109
|
+
sparql += f'\n{blank:{indent * indent_inc}}ORDER BY ASC(?lastModificationDate)'
|
|
1110
|
+
if sortBy == SortBy.PROPVAL:
|
|
1111
|
+
sparql += f'\n{blank:{indent * indent_inc}}ORDER BY'
|
|
1112
|
+
if includeProperties:
|
|
1113
|
+
for index, item in enumerate(includeProperties):
|
|
1114
|
+
sparql += f'\n{blank:{indent * indent_inc}} ?o{index}'
|
|
1115
|
+
|
|
1116
|
+
if not count_only:
|
|
1117
|
+
sparql += f'\n{blank:{indent * indent_inc}}LIMIT {limit} OFFSET {offset}'
|
|
1118
|
+
sparql += '\n'
|
|
1119
|
+
|
|
1120
|
+
try:
|
|
1121
|
+
jsonres = con.query(sparql)
|
|
1122
|
+
except OldapError:
|
|
1123
|
+
print(sparql)
|
|
1124
|
+
raise
|
|
1125
|
+
res = QueryProcessor(context, jsonres)
|
|
1126
|
+
if count_only:
|
|
1127
|
+
return res[0]['numResult']
|
|
1128
|
+
else:
|
|
1129
|
+
result = {}
|
|
1130
|
+
for r in res:
|
|
1131
|
+
tmp = {}
|
|
1132
|
+
if includeProperties:
|
|
1133
|
+
for index, item in enumerate(includeProperties):
|
|
1134
|
+
tmp[item] = r[f'o{index}']
|
|
1135
|
+
|
|
1136
|
+
if sortBy:
|
|
1137
|
+
if sortBy == SortBy.CREATED:
|
|
1138
|
+
tmp[Xsd_QName('oldap:creationDate')] = r['creationDate']
|
|
1139
|
+
if sortBy == SortBy.LASTMOD:
|
|
1140
|
+
tmp[Xsd_QName('oldap:lastModificationDate')] = r['lastModificationDate']
|
|
1141
|
+
result[r['s']] = tmp
|
|
1142
|
+
return result
|
|
1143
|
+
|
|
1144
|
+
|
|
742
1145
|
def toJsonObject(self) -> dict[str, list[str] | str]:
|
|
743
1146
|
result = {'iri': str(self._iri)}
|
|
744
1147
|
for propiri, values in self._values.items():
|
|
@@ -797,45 +1200,6 @@ class ResourceInstanceFactory:
|
|
|
797
1200
|
'properties': resclass.properties,
|
|
798
1201
|
'superclass': resclass.superclass})
|
|
799
1202
|
|
|
800
|
-
@staticmethod
|
|
801
|
-
def read_data(con: IConnection, projectShortName: Xsd_NCName | str, iri: Iri | str) -> dict[Xsd_QName, Any]:
|
|
802
|
-
if not isinstance(iri, Iri):
|
|
803
|
-
iri = Iri(iri, validate=True)
|
|
804
|
-
if not isinstance(projectShortName, Xsd_NCName):
|
|
805
|
-
graph = Xsd_NCName(projectShortName)
|
|
806
|
-
else:
|
|
807
|
-
graph = projectShortName
|
|
808
|
-
|
|
809
|
-
context = Context(name=con.context_name)
|
|
810
|
-
sparql = context.sparql_context
|
|
811
|
-
sparql += f'''
|
|
812
|
-
SELECT ?predicate ?value
|
|
813
|
-
WHERE {{
|
|
814
|
-
GRAPH {graph}:data {{
|
|
815
|
-
{iri.toRdf} ?predicate ?value .
|
|
816
|
-
{iri.toRdf} oldap:grantsPermission ?permset .
|
|
817
|
-
}}
|
|
818
|
-
GRAPH oldap:admin {{
|
|
819
|
-
{con.userIri.toRdf} oldap:hasPermissions ?permset .
|
|
820
|
-
?permset oldap:givesPermission ?DataPermission .
|
|
821
|
-
?DataPermission oldap:permissionValue ?permval .
|
|
822
|
-
}}
|
|
823
|
-
FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})
|
|
824
|
-
}}
|
|
825
|
-
'''
|
|
826
|
-
jsonres = con.query(sparql)
|
|
827
|
-
res = QueryProcessor(context, jsonres)
|
|
828
|
-
data = {}
|
|
829
|
-
for r in res:
|
|
830
|
-
if r['predicate'].is_qname:
|
|
831
|
-
if not data.get(r['predicate'].as_qname):
|
|
832
|
-
data[r['predicate'].as_qname] = []
|
|
833
|
-
data[str(r['predicate'].as_qname)].append(str(r['value']))
|
|
834
|
-
else:
|
|
835
|
-
raise OldapErrorInconsistency(f"Expected QName as predicate, got {r['predicate']}")
|
|
836
|
-
if not data.get('rdf:type'):
|
|
837
|
-
raise OldapErrorNotFound(f'Resource with iri <{iri}> not found.')
|
|
838
|
-
return data
|
|
839
1203
|
|
|
840
1204
|
def read(self, iri: Iri | str) -> ResourceInstance:
|
|
841
1205
|
if not isinstance(iri, Iri):
|
|
@@ -888,69 +1252,6 @@ class ResourceInstanceFactory:
|
|
|
888
1252
|
Instance = self.createObjectInstance(objtype)
|
|
889
1253
|
return Instance(iri=iri, **kwargs)
|
|
890
1254
|
|
|
891
|
-
@staticmethod
|
|
892
|
-
def search_fulltext(con: IConnection,
|
|
893
|
-
projectShortName: Xsd_NCName | str,
|
|
894
|
-
s: str,
|
|
895
|
-
count_only: bool = False,
|
|
896
|
-
limit: int = 100,
|
|
897
|
-
offset: int = 0) -> int | dict[Iri, dict[str, Xsd]]:
|
|
898
|
-
if not isinstance(projectShortName, Xsd_NCName):
|
|
899
|
-
graph = Xsd_NCName(projectShortName)
|
|
900
|
-
else:
|
|
901
|
-
graph = projectShortName
|
|
902
|
-
context = Context(name=con.context_name)
|
|
903
|
-
sparql = context.sparql_context
|
|
904
|
-
if (count_only):
|
|
905
|
-
sparql += "SELECT (COUNT(DISTINCT ?s) as ?numResult)"
|
|
906
|
-
else:
|
|
907
|
-
sparql += "SELECT DISTINCT ?s ?t ?p ?o"
|
|
908
|
-
sparql += f'''
|
|
909
|
-
WHERE {{
|
|
910
|
-
GRAPH {graph}:data {{
|
|
911
|
-
?s ?p ?o .
|
|
912
|
-
?s rdf:type ?t .
|
|
913
|
-
?s oldap:grantsPermission ?permset .
|
|
914
|
-
}}
|
|
915
|
-
FILTER(isLiteral(?o) &&
|
|
916
|
-
(datatype(?o) = xsd:string || datatype(?o) = rdf:langString || lang(?o) != ""))
|
|
917
|
-
FILTER(CONTAINS(LCASE(STR(?o)), "{s}")) # case-insensitive substring match
|
|
918
|
-
GRAPH oldap:admin {{
|
|
919
|
-
{con.userIri.toRdf} oldap:hasPermissions ?permset .
|
|
920
|
-
?permset oldap:givesPermission ?DataPermission .
|
|
921
|
-
?DataPermission oldap:permissionValue ?permval .
|
|
922
|
-
}}
|
|
923
|
-
FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})
|
|
924
|
-
}}
|
|
925
|
-
'''
|
|
926
|
-
if not count_only:
|
|
927
|
-
sparql += f'LIMIT {limit} OFFSET {offset}'
|
|
928
|
-
try:
|
|
929
|
-
jsonres = con.query(sparql)
|
|
930
|
-
except OldapError:
|
|
931
|
-
print(sparql)
|
|
932
|
-
raise
|
|
933
|
-
res = QueryProcessor(context, jsonres)
|
|
934
|
-
if count_only:
|
|
935
|
-
return res[0]['numResult']
|
|
936
|
-
else:
|
|
937
|
-
return {Iri(r['s']): {r['p']: r['o']} for r in res}
|
|
938
|
-
# jsonres = con.query(sparql)
|
|
939
|
-
# res = QueryProcessor(context, jsonres)
|
|
940
|
-
# if count_only:
|
|
941
|
-
# if isinstance(res[0]['numResult'], Xsd_integer):
|
|
942
|
-
# tmp = cast(Xsd_integer, res[0]['numResult'])
|
|
943
|
-
# return int(tmp)
|
|
944
|
-
# else:
|
|
945
|
-
# raise OldapErrorInconsistency(f'Expected integer as value, got "{res[0]["numResult"]}"')
|
|
946
|
-
# else:
|
|
947
|
-
# result: dict[Iri, dict[str, Xsd]] = {}
|
|
948
|
-
# for r in res:
|
|
949
|
-
# iri = cast(Iri, r['s'])
|
|
950
|
-
# resclass = cast(Iri, r['t'])
|
|
951
|
-
# result[iri] = {'resclass': resclass, 'property': r['p'], 'value': r['o']}
|
|
952
|
-
# return result
|
|
953
|
-
|
|
954
1255
|
|
|
955
1256
|
|
|
956
1257
|
|
oldaplib/src/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.3.
|
|
1
|
+
__version__ = "0.3.12"
|
|
@@ -8,7 +8,7 @@ from time import sleep
|
|
|
8
8
|
|
|
9
9
|
from oldaplib.src.cachesingleton import CacheSingletonRedis
|
|
10
10
|
from oldaplib.src.datamodel import DataModel
|
|
11
|
-
from oldaplib.src.objectfactory import ResourceInstanceFactory
|
|
11
|
+
from oldaplib.src.objectfactory import ResourceInstanceFactory, SortBy, ResourceInstance
|
|
12
12
|
from oldaplib.src.connection import Connection
|
|
13
13
|
from oldaplib.src.enums.action import Action
|
|
14
14
|
from oldaplib.src.enums.datapermissions import DataPermission
|
|
@@ -105,6 +105,9 @@ class TestObjectFactory(unittest.TestCase):
|
|
|
105
105
|
file = project_root / 'oldaplib' / 'testdata' / 'objectfactory_test.trig'
|
|
106
106
|
cls._connection.upload_turtle(file)
|
|
107
107
|
|
|
108
|
+
file = project_root / 'oldaplib' / 'testdata' / 'instances_test.trig'
|
|
109
|
+
cls._connection.upload_turtle(file)
|
|
110
|
+
|
|
108
111
|
sleep(1) # upload may take a while...
|
|
109
112
|
|
|
110
113
|
user = User.read(cls._connection, "rosenth")
|
|
@@ -194,6 +197,9 @@ class TestObjectFactory(unittest.TestCase):
|
|
|
194
197
|
self.assertEqual(p2.lastModifiedBy, p1.lastModifiedBy)
|
|
195
198
|
self.assertEqual(p2.lastModificationDate, p1.lastModificationDate)
|
|
196
199
|
|
|
200
|
+
b2.delete()
|
|
201
|
+
p2.delete()
|
|
202
|
+
|
|
197
203
|
def test_constructor_B(self):
|
|
198
204
|
factory = ResourceInstanceFactory(con=self._connection, project='test')
|
|
199
205
|
AllTypes = factory.createObjectInstance('AllTypes')
|
|
@@ -341,6 +347,8 @@ class TestObjectFactory(unittest.TestCase):
|
|
|
341
347
|
grantsPermission=Iri('oldap:GenericView'))
|
|
342
348
|
b.create()
|
|
343
349
|
|
|
350
|
+
b.delete()
|
|
351
|
+
|
|
344
352
|
def test_constructor_D(self):
|
|
345
353
|
dm = DataModel.read(con=self._connection, project='test')
|
|
346
354
|
factory = ResourceInstanceFactory(con=self._connection, project='test')
|
|
@@ -357,11 +365,13 @@ class TestObjectFactory(unittest.TestCase):
|
|
|
357
365
|
pubDate="2001-01-01",
|
|
358
366
|
grantsPermission=Iri('oldap:GenericView'))
|
|
359
367
|
b.create()
|
|
360
|
-
data =
|
|
368
|
+
data = ResourceInstance.read_data(con=self._connection, iri=b.iri, projectShortName='test')
|
|
361
369
|
self.assertEqual(data['rdf:type'], ['test:Book'])
|
|
362
370
|
self.assertEqual(data['test:title'], ['The Life and Times of Scrooge'])
|
|
363
371
|
self.assertEqual(data['test:author'], ['test:TuomasHolopainen'])
|
|
364
372
|
|
|
373
|
+
b.delete()
|
|
374
|
+
|
|
365
375
|
def test_read_B(self):
|
|
366
376
|
factory = ResourceInstanceFactory(con=self._connection, project='test')
|
|
367
377
|
Book = factory.createObjectInstance('Book')
|
|
@@ -396,6 +406,7 @@ class TestObjectFactory(unittest.TestCase):
|
|
|
396
406
|
self.assertEqual(jsonobj['test:pubDate'], ['2001-01-01'])
|
|
397
407
|
self.assertEqual(jsonobj['test:title'], ['The Life and Times of Scrooge'])
|
|
398
408
|
|
|
409
|
+
bb.delete()
|
|
399
410
|
|
|
400
411
|
def test_value_setter(self):
|
|
401
412
|
factory = ResourceInstanceFactory(con=self._connection, project='test')
|
|
@@ -450,6 +461,8 @@ class TestObjectFactory(unittest.TestCase):
|
|
|
450
461
|
self.assertEqual(obj2.decimalSetter, {Xsd_decimal(3.14159), Xsd_decimal(2.71828), Xsd_decimal(1.61803)})
|
|
451
462
|
self.assertFalse(obj2.integerSetter)
|
|
452
463
|
|
|
464
|
+
obj2.delete()
|
|
465
|
+
|
|
453
466
|
def test_value_modifier_A(self):
|
|
454
467
|
factory = ResourceInstanceFactory(con=self._connection, project='test')
|
|
455
468
|
SetterTester = factory.createObjectInstance('SetterTester')
|
|
@@ -476,6 +489,8 @@ class TestObjectFactory(unittest.TestCase):
|
|
|
476
489
|
self.assertEqual(obj1.integerSetter, {Xsd_int(20), Xsd_int(42)})
|
|
477
490
|
self.assertFalse(obj1.booleanSetter)
|
|
478
491
|
|
|
492
|
+
obj1.delete()
|
|
493
|
+
|
|
479
494
|
def test_value_modifier_B(self):
|
|
480
495
|
factory = ResourceInstanceFactory(con=self._connection, project='test')
|
|
481
496
|
SetterTester = factory.createObjectInstance('SetterTester')
|
|
@@ -502,6 +517,8 @@ class TestObjectFactory(unittest.TestCase):
|
|
|
502
517
|
self.assertEqual(obj1.integerSetter, {Xsd_int(20), Xsd_int(42)})
|
|
503
518
|
self.assertFalse(obj1.booleanSetter)
|
|
504
519
|
|
|
520
|
+
obj1.delete()
|
|
521
|
+
|
|
505
522
|
def test_value_maxcount_mincount(self):
|
|
506
523
|
factory = ResourceInstanceFactory(con=self._connection, project='test')
|
|
507
524
|
Person = factory.createObjectInstance('Person')
|
|
@@ -519,25 +536,9 @@ class TestObjectFactory(unittest.TestCase):
|
|
|
519
536
|
with self.assertRaises(OldapErrorValue):
|
|
520
537
|
del obj1.familyName
|
|
521
538
|
|
|
522
|
-
|
|
523
|
-
# ps = PermissionSet(con=self._connection,
|
|
524
|
-
# permissionSetId="testNoUpdate",
|
|
525
|
-
# label=LangString("testNoUpdate@en"),
|
|
526
|
-
# comment=LangString("Testing PermissionSet@en"),
|
|
527
|
-
# givesPermission=DataPermission.DATA_VIEW,
|
|
528
|
-
# definedByProject="test")
|
|
529
|
-
# ps.create()
|
|
530
|
-
#
|
|
531
|
-
# user = User(con=self._connection,
|
|
532
|
-
# userId=Xsd_NCName("factorytestuser"),
|
|
533
|
-
# familyName="FactoryTest",
|
|
534
|
-
# givenName="FactoryTest",
|
|
535
|
-
# credentials="Waseliwas",
|
|
536
|
-
# inProject={'oldap:Test': {}},
|
|
537
|
-
# hasPermissions={ps.iri.as_qname},
|
|
538
|
-
# isActive=True)
|
|
539
|
-
# user.create()
|
|
539
|
+
obj1.delete()
|
|
540
540
|
|
|
541
|
+
def test_value_modifier_norights(self):
|
|
541
542
|
factory = ResourceInstanceFactory(con=self._connection, project='test')
|
|
542
543
|
SetterTester = factory.createObjectInstance('SetterTester')
|
|
543
544
|
obj1 = SetterTester(stringSetter="This is a test string",
|
|
@@ -564,6 +565,11 @@ class TestObjectFactory(unittest.TestCase):
|
|
|
564
565
|
with self.assertRaises(OldapErrorNoPermission):
|
|
565
566
|
obj.update()
|
|
566
567
|
|
|
568
|
+
factory = ResourceInstanceFactory(con=self._connection, project='test')
|
|
569
|
+
SetterTester = factory.createObjectInstance('SetterTester')
|
|
570
|
+
obj = SetterTester.read(con=self._connection, iri=obj1.iri)
|
|
571
|
+
obj.delete()
|
|
572
|
+
|
|
567
573
|
def test_delete_resource(self):
|
|
568
574
|
project = Project.read(con=self._connection, projectIri_SName='test')
|
|
569
575
|
factory = ResourceInstanceFactory(con=self._connection, project=project)
|
|
@@ -630,27 +636,50 @@ class TestObjectFactory(unittest.TestCase):
|
|
|
630
636
|
with self.assertRaises(OldapErrorNoPermission):
|
|
631
637
|
b.update()
|
|
632
638
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
def random_string(length=12):
|
|
636
|
-
chars = string.ascii_letters + string.digits
|
|
637
|
-
return ''.join(random.choices(chars, k=length))
|
|
639
|
+
with self.assertRaises(OldapErrorNoPermission):
|
|
640
|
+
b.delete()
|
|
638
641
|
|
|
639
|
-
project = Project.read(con=self._connection, projectIri_SName='test')
|
|
640
642
|
factory = ResourceInstanceFactory(con=self._connection, project=project)
|
|
641
643
|
Book = factory.createObjectInstance('Book')
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
644
|
+
b = Book.read(con=self._connection,
|
|
645
|
+
iri=b.iri)
|
|
646
|
+
b.delete()
|
|
647
|
+
|
|
648
|
+
def test_search_resource_A(self):
|
|
649
|
+
res = ResourceInstance.search_fulltext(con=self._connection,
|
|
650
|
+
projectShortName='test',
|
|
651
|
+
resClass='test:Book',
|
|
652
|
+
s='geschichte',
|
|
653
|
+
sortBy=SortBy.CREATED)
|
|
654
|
+
|
|
655
|
+
self.assertEqual(len(res), 2)
|
|
656
|
+
for x, y in res.items():
|
|
657
|
+
self.assertEqual(y[Xsd_QName("owl:Class")], Xsd_QName('test:Book'))
|
|
658
|
+
|
|
659
|
+
res = ResourceInstance.search_fulltext(con=self._connection,
|
|
660
|
+
projectShortName='test',
|
|
661
|
+
s='spez',
|
|
662
|
+
sortBy=SortBy.CREATED)
|
|
651
663
|
|
|
664
|
+
self.assertEqual(len(res), 5)
|
|
652
665
|
for x, y in res.items():
|
|
653
|
-
|
|
666
|
+
self.assertTrue(y[Xsd_QName("owl:Class")] in {Xsd_QName('test:Book'), Xsd_QName('test:Page')})
|
|
667
|
+
|
|
668
|
+
def test_search_resource_B(self):
|
|
669
|
+
res = ResourceInstance.all_resources(con=self._connection,
|
|
670
|
+
projectShortName='test',
|
|
671
|
+
resClass='test:Page',
|
|
672
|
+
includeProperties=[Xsd_QName('test:pageNum'), Xsd_QName('test:pageContent')],
|
|
673
|
+
sortBy = SortBy.CREATED)
|
|
674
|
+
self.assertEqual(len(res), 8)
|
|
675
|
+
for r in res:
|
|
676
|
+
self.assertEqual(len(res[r]), 3)
|
|
677
|
+
|
|
678
|
+
def test_search_resource_C(self):
|
|
679
|
+
res = ResourceInstance.all_resources(con=self._connection,
|
|
680
|
+
projectShortName='test',
|
|
681
|
+
resClass='test:Page')
|
|
682
|
+
self.assertEqual(len(res), 8)
|
|
654
683
|
|
|
655
684
|
|
|
656
685
|
if __name__ == '__main__':
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
@prefix : <http://oldap.org/base#> .
|
|
2
|
+
@prefix test: <http://oldap.org/test#> .
|
|
3
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
4
|
+
|
|
5
|
+
test:data {
|
|
6
|
+
<urn:uuid:7a1de6d7-de75-4875-ab24-74819057703f> a test:Book;
|
|
7
|
+
:createdBy <https://orcid.org/0000-0003-1681-4036>;
|
|
8
|
+
:creationDate "2025-11-13T16:43:21.284536+01:00"^^xsd:dateTimeStamp;
|
|
9
|
+
:lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
|
|
10
|
+
:lastModificationDate "2025-11-13T16:43:21.284536+01:00"^^xsd:dateTimeStamp;
|
|
11
|
+
:grantsPermission :GenericView;
|
|
12
|
+
test:title "Die Geschichte der Spez. tQh5OAgXOaK5"@de;
|
|
13
|
+
test:pubDate "2026-01-01"^^xsd:date .
|
|
14
|
+
|
|
15
|
+
<urn:uuid:57141a6b-46b5-4c82-a74c-d48a15437c4f> a test:Page;
|
|
16
|
+
:createdBy <https://orcid.org/0000-0003-1681-4036>;
|
|
17
|
+
:creationDate "2025-11-13T16:43:22.598149+01:00"^^xsd:dateTimeStamp;
|
|
18
|
+
:lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
|
|
19
|
+
:lastModificationDate "2025-11-13T16:43:22.598149+01:00"^^xsd:dateTimeStamp;
|
|
20
|
+
:grantsPermission :GenericView;
|
|
21
|
+
test:pageDesignation "Page 1";
|
|
22
|
+
test:pageNum "1"^^xsd:positiveInteger;
|
|
23
|
+
test:pageDescription "Description for page 1"@en;
|
|
24
|
+
test:pageContent "Content for page 1\\Spez. nXpVzpnoxhxZEhp0hRWWcBmOLA3h62KT4f8FLxwL3kpGUdhLWBveN9KiML34YXk86SW6PDnZgz4GELOiZOqMvo9chdXhR1e0W3FIn";
|
|
25
|
+
test:pageInBook <urn:uuid:7a1de6d7-de75-4875-ab24-74819057703f> .
|
|
26
|
+
|
|
27
|
+
<urn:uuid:b382c2bc-6a61-4f60-a963-ec1eb5bc7428> a test:Page;
|
|
28
|
+
:createdBy <https://orcid.org/0000-0003-1681-4036>;
|
|
29
|
+
:creationDate "2025-11-13T16:43:23.323339+01:00"^^xsd:dateTimeStamp;
|
|
30
|
+
:lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
|
|
31
|
+
:lastModificationDate "2025-11-13T16:43:23.323339+01:00"^^xsd:dateTimeStamp;
|
|
32
|
+
:grantsPermission :GenericView;
|
|
33
|
+
test:pageDesignation "Page 2";
|
|
34
|
+
test:pageNum "2"^^xsd:positiveInteger;
|
|
35
|
+
test:pageDescription "Description for page 2"@en;
|
|
36
|
+
test:pageContent "Waseliwas for page 2\\Spez. nP7OGEXPNRcM62O2gVVmTzp8xSjnMM0jNTdyFpDI3Cf1VTH1AcvrFt3AYSWCLEQIBttAs23DHkAXzaehFbA81TwkIKLKUSz9v1qAV";
|
|
37
|
+
test:pageInBook <urn:uuid:7a1de6d7-de75-4875-ab24-74819057703f> .
|
|
38
|
+
|
|
39
|
+
<urn:uuid:a8f0ec0c-28ed-449c-8f22-81ee20bfb0a3> a test:Page;
|
|
40
|
+
:createdBy <https://orcid.org/0000-0003-1681-4036>;
|
|
41
|
+
:creationDate "2025-11-13T16:43:24.013627+01:00"^^xsd:dateTimeStamp;
|
|
42
|
+
:lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
|
|
43
|
+
:lastModificationDate "2025-11-13T16:43:24.013627+01:00"^^xsd:dateTimeStamp;
|
|
44
|
+
:grantsPermission :GenericView;
|
|
45
|
+
test:pageDesignation "Page 3";
|
|
46
|
+
test:pageNum "3"^^xsd:positiveInteger;
|
|
47
|
+
test:pageDescription "Description for page 3"@en;
|
|
48
|
+
test:pageContent "Content for page 3\\Spez. nAdjA5kTzS7lT6W7F2bgLYtcXBkDxOAelvXThXNt5uranbB2WgsSsPu5uklCy8IVdRhqod6iWhMVWdqMhZWnv1NkgJQ2vjhHB57bh";
|
|
49
|
+
test:pageInBook <urn:uuid:7a1de6d7-de75-4875-ab24-74819057703f> .
|
|
50
|
+
|
|
51
|
+
<urn:uuid:098df661-de13-4fa7-b3aa-2ed5aa1180a8> a test:Page;
|
|
52
|
+
:createdBy <https://orcid.org/0000-0003-1681-4036>;
|
|
53
|
+
:creationDate "2025-11-13T16:43:24.742317+01:00"^^xsd:dateTimeStamp;
|
|
54
|
+
:lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
|
|
55
|
+
:lastModificationDate "2025-11-13T16:43:24.742317+01:00"^^xsd:dateTimeStamp;
|
|
56
|
+
:grantsPermission :GenericView;
|
|
57
|
+
test:pageDesignation "Page 4";
|
|
58
|
+
test:pageNum "4"^^xsd:positiveInteger;
|
|
59
|
+
test:pageDescription "Description for page 4"@en;
|
|
60
|
+
test:pageContent "Waseliwas for page 4\\nMc6l85dn7CMgYyL5qmQVRUpoICNxJ7f3GpydUY67gfXssGOokV3CPoSmre5MHWpcFaKHlHxWDSrL0qNEcECe28AS438654klipu4";
|
|
61
|
+
test:pageInBook <urn:uuid:7a1de6d7-de75-4875-ab24-74819057703f> .
|
|
62
|
+
|
|
63
|
+
<urn:uuid:9bf6ae23-bf2f-4466-abe3-65efe6afe589> a test:Book;
|
|
64
|
+
:createdBy <https://orcid.org/0000-0003-1681-4036>;
|
|
65
|
+
:creationDate "2025-11-13T16:43:25.444141+01:00"^^xsd:dateTimeStamp;
|
|
66
|
+
:lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
|
|
67
|
+
:lastModificationDate "2025-11-13T16:43:25.444141+01:00"^^xsd:dateTimeStamp;
|
|
68
|
+
:grantsPermission :GenericView;
|
|
69
|
+
test:title "Die Geschichte der fGqkycKqu4Fg"@de;
|
|
70
|
+
test:pubDate "2026-01-01"^^xsd:date .
|
|
71
|
+
|
|
72
|
+
<urn:uuid:cda5bacb-4082-4fef-9a17-990cf16e2f56> a test:Page;
|
|
73
|
+
:createdBy <https://orcid.org/0000-0003-1681-4036>;
|
|
74
|
+
:creationDate "2025-11-13T16:43:26.755559+01:00"^^xsd:dateTimeStamp;
|
|
75
|
+
:lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
|
|
76
|
+
:lastModificationDate "2025-11-13T16:43:26.755559+01:00"^^xsd:dateTimeStamp;
|
|
77
|
+
:grantsPermission :GenericView;
|
|
78
|
+
test:pageDesignation "Page 1";
|
|
79
|
+
test:pageNum "1"^^xsd:positiveInteger;
|
|
80
|
+
test:pageDescription "Description for page 1"@en;
|
|
81
|
+
test:pageContent "Content for page 1\\nSpez. TnfJDOE1D0hFuY9B2zKJW7g5oW48XTqKSd9nNYL0QrjxAk38Aka6g9zEr6q8OdAoxWePellSt4Ixq3jfaF1YlkOYBLyWft0LpzjS";
|
|
82
|
+
test:pageInBook <urn:uuid:9bf6ae23-bf2f-4466-abe3-65efe6afe589> .
|
|
83
|
+
|
|
84
|
+
<urn:uuid:674467a8-8fbe-425c-a2f6-06d2e52adc99> a test:Page;
|
|
85
|
+
:createdBy <https://orcid.org/0000-0003-1681-4036>;
|
|
86
|
+
:creationDate "2025-11-13T16:43:27.463742+01:00"^^xsd:dateTimeStamp;
|
|
87
|
+
:lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
|
|
88
|
+
:lastModificationDate "2025-11-13T16:43:27.463742+01:00"^^xsd:dateTimeStamp;
|
|
89
|
+
:grantsPermission :GenericView;
|
|
90
|
+
test:pageDesignation "Page 2";
|
|
91
|
+
test:pageNum "2"^^xsd:positiveInteger;
|
|
92
|
+
test:pageDescription "Description for page 2"@en;
|
|
93
|
+
test:pageContent "Waseliwas for page 2\\npwZym6JetP02VeGCX5cVddgaBGWwy2AStfs6W3elfpweFYdS5Z81dvPEPYAo1xDgBSQcAwqnP1pfVEj1YBkz2X7aNCob22SKCztw";
|
|
94
|
+
test:pageInBook <urn:uuid:9bf6ae23-bf2f-4466-abe3-65efe6afe589> .
|
|
95
|
+
|
|
96
|
+
<urn:uuid:dc2704cf-8352-43c1-94ef-a7a81e838532> a test:Page;
|
|
97
|
+
:createdBy <https://orcid.org/0000-0003-1681-4036>;
|
|
98
|
+
:creationDate "2025-11-13T16:43:28.161174+01:00"^^xsd:dateTimeStamp;
|
|
99
|
+
:lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
|
|
100
|
+
:lastModificationDate "2025-11-13T16:43:28.161174+01:00"^^xsd:dateTimeStamp;
|
|
101
|
+
:grantsPermission :GenericView;
|
|
102
|
+
test:pageDesignation "Page 3";
|
|
103
|
+
test:pageNum "3"^^xsd:positiveInteger;
|
|
104
|
+
test:pageDescription "Description for page 3"@en;
|
|
105
|
+
test:pageContent "Content for page 3\\nmEbj4wfY55KWkSqIlMkOK6LpHlHdlCa3vq3GtTkvvHhzieT0FIax7U489xSGJNOxPEdeNk8Ywhtk1ETo0AIBoNNywvyFV6jLxe5H";
|
|
106
|
+
test:pageInBook <urn:uuid:9bf6ae23-bf2f-4466-abe3-65efe6afe589> .
|
|
107
|
+
|
|
108
|
+
<urn:uuid:f46ea23a-65ab-47ce-908d-586d6c8091a6> a test:Page;
|
|
109
|
+
:createdBy <https://orcid.org/0000-0003-1681-4036>;
|
|
110
|
+
:creationDate "2025-11-13T16:43:28.861171+01:00"^^xsd:dateTimeStamp;
|
|
111
|
+
:lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
|
|
112
|
+
:lastModificationDate "2025-11-13T16:43:28.861171+01:00"^^xsd:dateTimeStamp;
|
|
113
|
+
:grantsPermission :GenericView;
|
|
114
|
+
test:pageDesignation "Page 4";
|
|
115
|
+
test:pageNum "4"^^xsd:positiveInteger;
|
|
116
|
+
test:pageDescription "Description for page 4"@en;
|
|
117
|
+
test:pageContent "Waseliwas for page 4\\n9pB6yFsJs7zcCkyF9j9flbGUcNczytEsw1nSUYCBLIN3P63wePvVQnWDX5dgUDXyeEwUwoBycRPcrp6kG2wsknVjfajQI30lZ73E";
|
|
118
|
+
test:pageInBook <urn:uuid:9bf6ae23-bf2f-4466-abe3-65efe6afe589> .
|
|
119
|
+
}
|
|
@@ -10,7 +10,7 @@ oldaplib/ontologies/standard/.gitsave,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
|
|
|
10
10
|
oldaplib/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
oldaplib/src/cachesingleton.py,sha256=WGhuFER-mTnOJmwaN17fXPAg7zn7GJBm-XadShNUBBk,3687
|
|
12
12
|
oldaplib/src/connection.py,sha256=LJMJO65QhSbheIEBnOCphRyAD1STwkO8zfNcYPcKwP8,29016
|
|
13
|
-
oldaplib/src/datamodel.py,sha256=
|
|
13
|
+
oldaplib/src/datamodel.py,sha256=HXur6vCFW4WGsQ8sKxVK0uz2I742_8xm1nVDJ8JNviY,35147
|
|
14
14
|
oldaplib/src/dtypes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
oldaplib/src/dtypes/bnode.py,sha256=7Swl77PJlzahov7d7ijJExmoVsTkR5JFOvFQf1jDmEg,1555
|
|
16
16
|
oldaplib/src/dtypes/languagein.py,sha256=6h3VrTH8IcTN6mvnWuGvzDoKX_Jh6h9w3wWrLuAWfVc,8593
|
|
@@ -59,7 +59,7 @@ oldaplib/src/helpers/tools.py,sha256=sNbiOLucTGNFzZmiWwPLFOb80VTXQH0Zd9uCGubhzAk
|
|
|
59
59
|
oldaplib/src/iconnection.py,sha256=XlOc2Kh4tK_UOHydLQwlWjUFLUze-Aq_vEZpf9KS1-s,3677
|
|
60
60
|
oldaplib/src/in_project.py,sha256=2KuhHPj8DNveFRBeImrRfxlCOYhBK-mcxXYUp6s--j8,10672
|
|
61
61
|
oldaplib/src/model.py,sha256=VACR3T6zJYFaE5J1PFFdP0OSwhbu4sahoLMWg6_L_rE,19267
|
|
62
|
-
oldaplib/src/objectfactory.py,sha256=
|
|
62
|
+
oldaplib/src/objectfactory.py,sha256=sc642TXVWi9mVo2xziNiy80lNCOv12E3SgN5lF6gkhs,63720
|
|
63
63
|
oldaplib/src/oldaplist.py,sha256=sGAvEEJukRCjM70G0NFaR-L9YPleQTOtdWGExj3oYL8,42933
|
|
64
64
|
oldaplib/src/oldaplist_helpers.py,sha256=1Gur0nS1PCKb9iUtCKPUFDOYjw6vvAwYpe-G3DdxlEc,14213
|
|
65
65
|
oldaplib/src/oldaplistnode.py,sha256=NnC2juEGTtEkDO6OlB9PjSw_zTF-wSsRUgEk-6VV9DA,87344
|
|
@@ -70,7 +70,7 @@ oldaplib/src/propertyclass.py,sha256=pnaDsmyGKQnJaaOHXA0XyLcp4zn1b1vC9sLbjXls4lM
|
|
|
70
70
|
oldaplib/src/resourceclass.py,sha256=EIxyd7Z_w59wDxWLXCaLvhhvh5SjLEUWb8gqmZz8LLM,102046
|
|
71
71
|
oldaplib/src/user.py,sha256=Z4GXPRkaHXx3glUpPXQdFqYMxQPOuqayDwkTAE5RGjU,48820
|
|
72
72
|
oldaplib/src/userdataclass.py,sha256=FbZkcRt0pKbOeqsZ7HbpwoKE-XPWH2AqpHG1GcsrBPo,12364
|
|
73
|
-
oldaplib/src/version.py,sha256=
|
|
73
|
+
oldaplib/src/version.py,sha256=4iZzCiPqmeFKHtJkBXOmC-Pq2LNrWPJ_kikeL675y7k,22
|
|
74
74
|
oldaplib/src/xsd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
75
75
|
oldaplib/src/xsd/floatingpoint.py,sha256=rDReKqh0mXyc4F5wslgTUxbeGf3-PGERyughj5_62YI,8852
|
|
76
76
|
oldaplib/src/xsd/iri.py,sha256=w1Dr0z-REi7yPe3GPGnyzGrLVMvLY03kEeK-AmZ9sxw,8383
|
|
@@ -126,7 +126,7 @@ oldaplib/test/test_hasproperty.py,sha256=r991g8kBTfv1CGs9Hf0fli-AUp7Ob7rOHWYD74h
|
|
|
126
126
|
oldaplib/test/test_in_project.py,sha256=DYT-guwRQ9crnfEt7cQZxoEMxThin7QeymNce3jaZx4,7779
|
|
127
127
|
oldaplib/test/test_langstring.py,sha256=37BeKiQzj63G-SyS_paK_SEG7ulRbGrE89Mz40UB_bE,15146
|
|
128
128
|
oldaplib/test/test_language_in.py,sha256=ELqHO-YIsZSCPF3E3rWde4J7rERL7En7sV_pzQ00zgs,8826
|
|
129
|
-
oldaplib/test/test_objectfactory.py,sha256=
|
|
129
|
+
oldaplib/test/test_objectfactory.py,sha256=JuEUQAOmMpWptJlk1o3hz48NlZ3CQbsEAYRK_-XL7tg,35487
|
|
130
130
|
oldaplib/test/test_observable_dict.py,sha256=GxD0sM0nsVfVRBu92SFGkJ6--YXq4ibBWI4IpjZZzDU,1396
|
|
131
131
|
oldaplib/test/test_observable_set.py,sha256=JWZSoAsr8XIEBXPVgSVJjQQEEc8uSAme5IrFYLYVVXw,6313
|
|
132
132
|
oldaplib/test/test_oldaplist.py,sha256=9wo3tEOHt5bIuXyvSSyTzjhtdKrQHiiAA6EfVBuq4wI,20114
|
|
@@ -145,6 +145,7 @@ oldaplib/testdata/connection_test.trig,sha256=LFTGLEae7SaTU67rwvgvg_epi09O7oPZwf
|
|
|
145
145
|
oldaplib/testdata/datamodel_test.trig,sha256=0n02awPthzi-Lx-_ABlrD9yZ3I1sWxp7eIbFwSxwKNA,802
|
|
146
146
|
oldaplib/testdata/event_type.yaml,sha256=wpXiheSEKh4xOoUZvAxWytJQ-sNK6oUYdVpOmyW9wPc,3083
|
|
147
147
|
oldaplib/testdata/hlist_schema.yaml,sha256=fgHiB-ZxOkE6OvkZKk9SL2kNn8Akj6dS6ySDFSpknTA,186
|
|
148
|
+
oldaplib/testdata/instances_test.trig,sha256=i1ouJhBGrFqIYX0A4wG6gU24Gtf9itITn-PRBiB6-tc,6883
|
|
148
149
|
oldaplib/testdata/institution_or_building_type.yaml,sha256=SA2rsQwoAdyn6eSIJU1ilmdIQf-f1XNApwBow-JlJTo,2439
|
|
149
150
|
oldaplib/testdata/language.yaml,sha256=YaQA77d7QyOydqNylR5RSb-0A6h9pLM4mgadJSrYC3A,451
|
|
150
151
|
oldaplib/testdata/location_type.yaml,sha256=amlhYNDc9qLv_if6urtAtBTnEXrVrb6_aulE180GYkc,1323
|
|
@@ -157,6 +158,6 @@ oldaplib/testdata/source_type.yaml,sha256=dSihKikw3O-IlGf6anj5KWMoBYLaweLVF1Zojm
|
|
|
157
158
|
oldaplib/testdata/test_move_left_of_toL.yaml,sha256=2m1OSQrQFlsCQxeJrjzBAO74LMprNDo_HuyrYGsOeXI,787
|
|
158
159
|
oldaplib/testdata/testlist.yaml,sha256=AT11nXEG81Sfyb-tr1gQV0H_dZBrOCcFuHf7YtL8P2g,1994
|
|
159
160
|
oldaplib/testit.http,sha256=qW7mnr6aNLXFG6lQdLgyhXILOPN6qc5iFVZclLyVvkY,303
|
|
160
|
-
oldaplib-0.3.
|
|
161
|
-
oldaplib-0.3.
|
|
162
|
-
oldaplib-0.3.
|
|
161
|
+
oldaplib-0.3.12.dist-info/METADATA,sha256=rp2Km2WJPtPKjKHaO7rz5GKxTXHfM_g4eWofRHEf0o0,2855
|
|
162
|
+
oldaplib-0.3.12.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
163
|
+
oldaplib-0.3.12.dist-info/RECORD,,
|
|
File without changes
|