data_service_i.py
ofrak.service.data_service_i
DataServiceInterface (AbstractOfrakService)
create_root(self, data_id, data)
async
Create a root data model with its own data bytes.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data_id |
bytes |
Unique ID for the new data model |
required |
data |
bytes |
Binary data belonging to the new data model |
required |
Returns:
Type | Description |
---|---|
DataModel |
The new data model object |
Exceptions:
Type | Description |
---|---|
AlreadyExistError |
if |
Source code in ofrak/service/data_service_i.py
@abstractmethod
async def create_root(self, data_id: bytes, data: bytes) -> DataModel:
"""
Create a root data model with its own data bytes.
:param data_id: Unique ID for the new data model
:param data: Binary data belonging to the new data model
:return: The new data model object
:raises AlreadyExistError: if `data_id` is already associated with a model
"""
raise NotImplementedError()
create_mapped(self, data_id, parent_id, range_in_parent)
async
Create a new data model which is mapped into another data model. That is, it does not hold
its own data, but defines its own data as a subsection of another model's data. The model
it maps from (parent_id
) may be a root model or another mapped model; if parent_id
is
another mapped node, the new mapped node created here will be mapped to the same root as
parent_id
at a range translated to be within parent_id
as defined by range_in_parent
.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data_id |
bytes |
Unique ID for the new data model |
required |
parent_id |
bytes |
ID of the data model to map the new model into |
required |
range_in_parent |
Range |
Range in |
required |
Returns:
Type | Description |
---|---|
DataModel |
The new data model object |
Exceptions:
Type | Description |
---|---|
AlreadyExistError |
if |
NotFoundError |
if |
Source code in ofrak/service/data_service_i.py
@abstractmethod
async def create_mapped(
self,
data_id: bytes,
parent_id: bytes,
range_in_parent: Range,
) -> DataModel:
"""
Create a new data model which is mapped into another data model. That is, it does not hold
its own data, but defines its own data as a subsection of another model's data. The model
it maps from (`parent_id`) may be a root model or another mapped model; if `parent_id` is
another mapped node, the new mapped node created here will be mapped to the same root as
`parent_id` at a range translated to be within `parent_id` as defined by `range_in_parent`.
:param data_id: Unique ID for the new data model
:param parent_id: ID of the data model to map the new model into
:param range_in_parent: Range in `parent_id` which the new model will map
:return: The new data model object
:raises AlreadyExistError: if `data_id` is already associated with a model
:raises NotFoundError: if `parent_id` is not associated with any known model
"""
raise NotImplementedError()
get_by_id(self, data_id)
async
Get the data model object associated with the given ID.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data_id |
bytes |
A unique ID for a data model |
required |
Returns:
Type | Description |
---|---|
DataModel |
The model associated with |
Exceptions:
Type | Description |
---|---|
NotFoundError |
if |
Source code in ofrak/service/data_service_i.py
@abstractmethod
async def get_by_id(self, data_id: bytes) -> DataModel:
"""
Get the data model object associated with the given ID.
:param data_id: A unique ID for a data model
:return: The model associated with `data_id`
:raises NotFoundError: if `data_id` is not associated with any known model
"""
raise NotImplementedError()
get_by_ids(self, data_ids)
async
Get the data models object associated with the given IDs.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data_ids |
Iterable[bytes] |
Multiple unique IDs for data models |
required |
Returns:
Type | Description |
---|---|
Iterable[ofrak.model.data_model.DataModel] |
The models associated with each ID in |
Exceptions:
Type | Description |
---|---|
NotFoundError |
if any ID in |
Source code in ofrak/service/data_service_i.py
@abstractmethod
async def get_by_ids(self, data_ids: Iterable[bytes]) -> Iterable[DataModel]:
"""
Get the data models object associated with the given IDs.
:param data_ids: Multiple unique IDs for data models
:return: The models associated with each ID in `data_ids`, in the same order their IDs were
provided
:raises NotFoundError: if any ID in `data_ids` is not associated with any known model
"""
raise NotImplementedError()
get_data_length(self, data_id)
async
Return the length of a single data model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data_id |
bytes |
A unique ID for a data model |
required |
Returns:
Type | Description |
---|---|
int |
The length of the data included in the model |
Exceptions:
Type | Description |
---|---|
NotFoundError |
if |
Source code in ofrak/service/data_service_i.py
@abstractmethod
async def get_data_length(self, data_id: bytes) -> int:
"""
Return the length of a single data model.
:param data_id: A unique ID for a data model
:return: The length of the data included in the model
:raises NotFoundError: if `data_id` is not associated with any known model
"""
raise NotImplementedError()
get_data_range_within_root(self, data_id)
async
Get the range that a model maps in its root. If the model specified by data_id
is itself
a root, returns a range covering that whole root (i.e. Range(0, length)).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data_id |
bytes |
A unique ID for a data model |
required |
Returns:
Type | Description |
---|---|
Range |
Range that |
Exceptions:
Type | Description |
---|---|
NotFoundError |
if |
Source code in ofrak/service/data_service_i.py
@abstractmethod
async def get_data_range_within_root(self, data_id: bytes) -> Range:
"""
Get the range that a model maps in its root. If the model specified by `data_id` is itself
a root, returns a range covering that whole root (i.e. Range(0, length)).
:param data_id: A unique ID for a data model
:return: Range that `data_id` maps in its root
:raises NotFoundError: if `data_id` is not associated with any known model
"""
raise NotImplementedError()
get_range_within_other(self, data_id, within_data_id)
async
Get the range representing the intersection between two data models, assuming they are both
mapped into the same root data. Either of data_id
or within_data_id
may be roots, but
they cannot both be roots (unless they are the same).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data_id |
bytes |
A unique ID for a data model |
required |
within_data_id |
bytes |
A unique ID for a data model |
required |
Returns:
Type | Description |
---|---|
Range |
The range where |
Exceptions:
Type | Description |
---|---|
NotFoundError |
if |
ValueError |
if |
Source code in ofrak/service/data_service_i.py
@abstractmethod
async def get_range_within_other(self, data_id: bytes, within_data_id: bytes) -> Range:
"""
Get the range representing the intersection between two data models, assuming they are both
mapped into the same root data. Either of `data_id` or `within_data_id` may be roots, but
they cannot both be roots (unless they are the same).
:param data_id: A unique ID for a data model
:param within_data_id: A unique ID for a data model
:return: The range where `data_id`'s model intersects `within_data_id`'s model
:raises NotFoundError: if `data_id` or `within_data_id` is not associated with any known
model
:raises ValueError: if `data_id` is not mapped into `within_data_id` or they do not share
the same root
"""
raise NotImplementedError()
get_data(self, data_id, data_range=None)
async
Get the data (or section of data) of a model. The optional data_range
parameter specifies
which a range within data_id
's data to return; if this range actually falls outside the
boundaries of data_id
's data, an empty bytestring is returned.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data_id |
bytes |
A unique ID for a data model |
required |
data_range |
Optional[ofrak_type.range.Range] |
An optional range within the model's data to return |
None |
Returns:
Type | Description |
---|---|
bytes |
Bytes of data from the model associated with |
Exceptions:
Type | Description |
---|---|
NotFoundError |
if |
Source code in ofrak/service/data_service_i.py
@abstractmethod
async def get_data(self, data_id: bytes, data_range: Optional[Range] = None) -> bytes:
"""
Get the data (or section of data) of a model. The optional `data_range` parameter specifies
which a range within `data_id`'s data to return; if this range actually falls outside the
boundaries of `data_id`'s data, an empty bytestring is returned.
:param data_id: A unique ID for a data model
:param data_range: An optional range within the model's data to return
:return: Bytes of data from the model associated with `data_id` - all bytes by default, a
specific slice if `data_range` is provided, and empty bytes if `data_range` is provided but
is outside the modeled data.
:raises NotFoundError: if `data_id` is not associated with any known model
"""
raise NotImplementedError()
apply_patches(self, patches)
async
Modify the data of a number of models, modeled as a list of DataPatch
structures each
specifying: a target data model (by ID), new data, and a range to overwrite with the new
data. The listed patches are applied in order, so that subsequent patches may effectively
'erase' an earlier patch. Patches may resize data if the new data is not the same size as
the range it is overwriting. Such patches create additional restrictions:
- If
patches
contains a patch that resizes a range of data, no subsequent patch inpatches
is allowed to modify that resized range. - Resizing patches are not allowed to overwrite ranges that contain the borders of any data models. For example, if model B maps Range(0, 6) of model A, a patch that resizes Range(4, 10) of model A is not allowed (whether it increases or decreases the size).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
patches |
List[ofrak.model.data_model.DataPatch] |
A list of patch data structures to be applied, in order |
required |
Returns:
Type | Description |
---|---|
List[ofrak.model.data_model.DataPatchesResult] |
A list of data structures describing all modified ranges of each data model affected by |
Exceptions:
Type | Description |
---|---|
NotFoundError |
if any data ID in the |
PatchOverlapError |
if a patch targets a region of data which has already been modified by a patch which resized that region |
PatchOverlapError |
if a patch would resize a region of data which contains the start or end of one or more data models |
Source code in ofrak/service/data_service_i.py
@abstractmethod
async def apply_patches(
self,
patches: List[DataPatch],
) -> List[DataPatchesResult]:
"""
Modify the data of a number of models, modeled as a list of `DataPatch` structures each
specifying: a target data model (by ID), new data, and a range to overwrite with the new
data. The listed patches are applied in order, so that subsequent patches may effectively
'erase' an earlier patch. Patches may resize data if the new data is not the same size as
the range it is overwriting. Such patches create additional restrictions:
1. If `patches` contains a patch that resizes a range of data, no subsequent patch in
`patches` is allowed to modify that resized range.
2. Resizing patches are not allowed to overwrite ranges that contain the borders of any
data models. For example, if model B maps Range(0, 6) of model A, a patch that resizes
Range(4, 10) of model A is not allowed (whether it increases or decreases the size).
:param patches: A list of patch data structures to be applied, in order
:return: A list of data structures describing all modified ranges of each data model
affected by `patches`
:raises NotFoundError: if any data ID in the `patches` list is not associated with any
known model
:raises PatchOverlapError: if a patch targets a region of data which has already been
modified by a patch which resized that region
:raises PatchOverlapError: if a patch would resize a region of data which contains the
start or end of one or more data models
"""
raise NotImplementedError()
delete_models(self, data_ids)
async
Delete one or more data models. If a root model is deleted, all models mapped into that root are also deleted.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data_ids |
Iterable[bytes] |
Multiple unique IDs for data models |
required |
Exceptions:
Type | Description |
---|---|
NotFoundError |
if any ID in |
Source code in ofrak/service/data_service_i.py
@abstractmethod
async def delete_models(self, data_ids: Iterable[bytes]) -> None:
"""
Delete one or more data models. If a root model is deleted, all models mapped into that
root are also deleted.
:param data_ids: Multiple unique IDs for data models
:raises NotFoundError: if any ID in `data_ids` is not associated with any known model
"""
raise NotImplementedError()
search(self, data_id, query, start=None, end=None, max_matches=None)
async
Search for some data in one of the models. The query may be a regex pattern (a return value
of re.compile
). If the query is a regex pattern, returns a tuple of pairs with both the
offset of the match and the contents of the match itself. If the query is plain bytes, a
list of only the match offsets are returned.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data_id |
Data model to search |
required | |
query |
Plain bytes to exactly match or a regex pattern to search for |
required | |
start |
Start offset in the data model to begin searching |
None |
|
end |
End offset in the data model to stop searching |
None |
|
max_matches |
Maximum number of matches to return |
None |
Returns:
Type | Description |
---|---|
A tuple of offsets matching a plain bytes query, or a list of (offset, match) pairs for a regex pattern query |
Source code in ofrak/service/data_service_i.py
@abstractmethod
async def search(self, data_id, query, start=None, end=None, max_matches=None):
"""
Search for some data in one of the models. The query may be a regex pattern (a return value
of `re.compile`). If the query is a regex pattern, returns a tuple of pairs with both the
offset of the match and the contents of the match itself. If the query is plain bytes, a
list of only the match offsets are returned.
:param data_id: Data model to search
:param query: Plain bytes to exactly match or a regex pattern to search for
:param start: Start offset in the data model to begin searching
:param end: End offset in the data model to stop searching
:param max_matches: Maximum number of matches to return
:return: A tuple of offsets matching a plain bytes query, or a list of (offset, match) pairs
for a regex pattern query
"""
raise NotImplementedError()