blob: 24cfaee88c923d3167d7f291b973fee849a58863 [file] [log] [blame]
# Copyright (c) 2023 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from pathlib import Path
import json
from api.client import Client
from typing import Dict, List
class JSONClient(Client):
def __init__(self, file_path):
super().__init__()
self.file_path = Path("database/") / file_path
self.resources = self._get_resources(self.file_path)
def _get_resources(self, path: Path) -> List[Dict]:
"""
Retrieves the resources from the JSON file.
:param path: The path to the JSON file.
:return: The resources as a JSON string.
"""
with open(path) as f:
return json.load(f)
def find_resource(self, query: Dict) -> Dict:
"""
Finds a resource within a list of resources based on the
provided query.
:param query: The query object containing the search criteria.
:return: The resource that matches the query.
"""
found_resources = []
for resource in self.resources:
if (
"resource_version" not in query
or query["resource_version"] == ""
or query["resource_version"] == "Latest"
):
if resource["id"] == query["id"]:
found_resources.append(resource)
else:
if (
resource["id"] == query["id"]
and resource["resource_version"]
== query["resource_version"]
):
return resource
if not found_resources:
return {"exists": False}
return max(
found_resources,
key=lambda resource: tuple(
map(int, resource["resource_version"].split("."))
),
)
def get_versions(self, query: Dict) -> List[Dict]:
"""
Retrieves all versions of a resource with the given ID from the
list of resources.
:param query: The query object containing the search criteria.
:return: A list of all versions of the resource.
"""
versions = []
for resource in self.resources:
if resource["id"] == query["id"]:
versions.append(
{"resource_version": resource["resource_version"]}
)
versions.sort(
key=lambda resource: tuple(
map(int, resource["resource_version"].split("."))
),
reverse=True,
)
return versions
def update_resource(self, query: Dict) -> Dict:
"""
Updates a resource within a list of resources based on the
provided query.
The function iterates over the resources and checks if the "id" and
"resource_version" of a resource match the values in the query.
If there is a match, it removes the existing resource from the list
and appends the updated resource.
After updating the resources, the function saves the updated list to
the specified file path.
:param query: The query object containing the resource
identification criteria.
:return: A dictionary indicating that the resource was updated.
"""
original_resource = query["original_resource"]
modified_resource = query["resource"]
if (
original_resource["id"] != modified_resource["id"]
and original_resource["resource_version"]
!= modified_resource["resource_version"]
):
return {"status": "Cannot change resource id"}
for resource in self.resources:
if (
resource["id"] == original_resource["id"]
and resource["resource_version"]
== original_resource["resource_version"]
):
self.resources.remove(resource)
self.resources.append(modified_resource)
self.write_to_file()
return {"status": "Updated"}
def check_resource_exists(self, query: Dict) -> Dict:
"""
Checks if a resource exists within a list of resources based on the
provided query.
The function iterates over the resources and checks if the "id" and
"resource_version" of a resource match the values in the query.
If a matching resource is found, it returns a dictionary indicating
that the resource exists.
If no matching resource is found, it returns a dictionary indicating
that the resource does not exist.
:param query: The query object containing the resource identification
criteria.
:return: A dictionary indicating whether the resource exists.
"""
for resource in self.resources:
if (
resource["id"] == query["id"]
and resource["resource_version"] == query["resource_version"]
):
return {"exists": True}
return {"exists": False}
def insert_resource(self, query: Dict) -> Dict:
"""
Inserts a new resource into a list of resources.
The function appends the query (new resource) to the resources list,
indicating the insertion.
It then writes the updated resources to the specified file path.
:param query: The query object containing the resource identification
criteria.
:return: A dictionary indicating that the resource was inserted.
"""
if self.check_resource_exists(query)["exists"]:
return {"status": "Resource already exists"}
self.resources.append(query)
self.write_to_file()
return {"status": "Inserted"}
def delete_resource(self, query: Dict) -> Dict:
"""
This function deletes a resource from the list of resources based on
the provided query.
:param query: The query object containing the resource identification
criteria.
:return: A dictionary indicating that the resource was deleted.
"""
for resource in self.resources:
if (
resource["id"] == query["id"]
and resource["resource_version"] == query["resource_version"]
):
self.resources.remove(resource)
self.write_to_file()
return {"status": "Deleted"}
def write_to_file(self) -> None:
"""
This function writes the list of resources to a file at the specified
file path.
:return: None
"""
with Path(self.file_path).open("w") as outfile:
json.dump(self.resources, outfile, indent=4)
def save_session(self) -> Dict:
"""
This function saves the client session to a dictionary.
:return: A dictionary containing the client session.
"""
session = {
"client": "json",
"filename": self.file_path.name,
}
return session