Skip to content

Commit a37ce99

Browse files
author
Evgenii Frolov
committed
REST ORM
1 parent 0dd0d32 commit a37ce99

File tree

8 files changed

+484
-4
lines changed

8 files changed

+484
-4
lines changed

restalchemy/api/resources.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,20 @@ def get_locator(cls, uri):
5151
@classmethod
5252
def get_resource(cls, request, uri):
5353
resource_locator = cls.get_locator(uri)
54-
return resource_locator.get_resource(request, uri)
54+
55+
# has parent resource?
56+
pstack = resource_locator.path_stack
57+
parent_resource = None
58+
59+
for pice in reversed(pstack[:-1]):
60+
if not isinstance(pice, six.string_types):
61+
parent_uri = '/'.join(uri.split('/')[:pstack.index(pice) + 2])
62+
parent_locator = cls.get_locator(parent_uri)
63+
parent_resource = parent_locator.get_resource(
64+
request, parent_uri)
65+
break
66+
67+
return resource_locator.get_resource(request, uri, parent_resource)
5568

5669
@classmethod
5770
def set_resource_map(cls, resource_map):
@@ -171,8 +184,8 @@ def get_resource_field_name(self, model_field_name):
171184
model_field_name, model_field_name).replace('_', '-')
172185

173186
def is_public_field(self, model_field_name):
174-
return not (model_field_name.startswith('_') or
175-
model_field_name in self._hidden_model_fields)
187+
return not (model_field_name.startswith('_')
188+
or model_field_name in self._hidden_model_fields)
176189

177190
def get_model(self):
178191
return self._model_class

restalchemy/api/routes.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,13 @@ def get_uri(self, model):
200200
# FIXME(Eugene Frolov): Header must be string. Not unicode.
201201
return str(posixpath.join('/', path))
202202

203-
def get_resource(self, request, uri):
203+
def get_resource(self, request, uri, parent_resource=None):
204204
uuid = posixpath.basename(uri)
205+
if parent_resource:
206+
return (self._controller(request=request)
207+
.get_resource_by_uuid(
208+
uuid=uuid,
209+
parent_resource=parent_resource))
205210
return self._controller(request=request).get_resource_by_uuid(
206211
uuid)
207212

restalchemy/storage/rest/__init__.py

Whitespace-only changes.

restalchemy/storage/rest/contexts.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2+
#
3+
# Copyright 2018 Mail.ru Group
4+
#
5+
# All Rights Reserved.
6+
#
7+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
8+
# not use this file except in compliance with the License. You may obtain
9+
# a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
# License for the specific language governing permissions and limitations
17+
# under the License.
18+
19+
import bazooka
20+
21+
from restalchemy.storage.rest import utils
22+
23+
24+
class Context(object):
25+
26+
def __init__(self, request_id=None, request_id_header_name=None,
27+
enable_cache=False):
28+
super(Context, self).__init__()
29+
self._http_client = {}
30+
self._request_id = request_id
31+
self._request_id_header_name = (
32+
request_id_header_name or 'correlation-id')
33+
self._cache = {}
34+
self._enable_cache = enable_cache
35+
36+
def _get_client(self, endpoint):
37+
if endpoint in self._http_client:
38+
return self._http_client[endpoint]
39+
cli = bazooka.Client(
40+
correlation_id=self._request_id,
41+
correlation_id_header_name=self._request_id_header_name)
42+
self._http_client[endpoint] = cli
43+
return cli
44+
45+
def make_post_request(self, endpoint, uri, params):
46+
cli = self._get_client(endpoint)
47+
url = utils.build_collection_uri(endpoint, uri)
48+
response = cli.post(url, json=params)
49+
response_dict = response.json()
50+
if self._enable_cache:
51+
location = response.headers['Location']
52+
self._cache[location] = response_dict
53+
return response_dict
54+
55+
def make_put_request(self, endpoint, uri, params):
56+
cli = self._get_client(endpoint)
57+
url = utils.build_resource_uri(endpoint, uri)
58+
response = cli.put(url, json=params)
59+
response_dict = response.json()
60+
if self._enable_cache:
61+
self._cache[url] = response_dict
62+
return response_dict
63+
64+
def make_list_request(self, endpoint, uri, params):
65+
cli = self._get_client(endpoint)
66+
url = utils.build_collection_uri(endpoint, uri)
67+
response = cli.get(url, params=params)
68+
response_dict = response.json()
69+
return response_dict
70+
71+
def make_get_request(self, endpoint, uri, params):
72+
url = utils.build_resource_uri(endpoint, uri)
73+
if self._enable_cache and url in self._cache:
74+
return self._cache[url]
75+
cli = self._get_client(endpoint)
76+
response = cli.get(url, params=params)
77+
response_dict = response.json()
78+
if self._enable_cache:
79+
self._cache[url] = response_dict
80+
return response_dict
81+
82+
def make_delete_request(self, endpoint, uri):
83+
url = utils.build_resource_uri(endpoint, uri)
84+
self._get_client(endpoint).delete(url)
85+
self._cache.pop(url, None)

restalchemy/storage/rest/engines.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2+
#
3+
# Copyright 2018 Mail.ru Group
4+
#
5+
# All Rights Reserved.
6+
#
7+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
8+
# not use this file except in compliance with the License. You may obtain
9+
# a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
# License for the specific language governing permissions and limitations
17+
# under the License.
18+
19+
from restalchemy.common import singletons
20+
21+
22+
class RESTEngine(object):
23+
24+
def __init__(self, api_endpoint, config=None):
25+
super(RESTEngine, self).__init__()
26+
self._api_endpoint = api_endpoint
27+
self._config = config or {}
28+
29+
def post(self, uri, params, context):
30+
return context.make_post_request(self._api_endpoint, uri, params)
31+
32+
def put(self, uri, params, context):
33+
return context.make_put_request(self._api_endpoint, uri, params)
34+
35+
def list(self, uri, params, context):
36+
return context.make_list_request(self._api_endpoint, uri, params)
37+
38+
def get(self, uri, params, context):
39+
return context.make_get_request(self._api_endpoint, uri, params)
40+
41+
def delete(self, uri, context):
42+
return context.make_delete_request(self._api_endpoint, uri)
43+
44+
45+
class EngineFactory(singletons.InheritSingleton):
46+
47+
def __init__(self):
48+
super(EngineFactory, self).__init__()
49+
self._engine = None
50+
self._engines_map = {
51+
'http': RESTEngine,
52+
'https': RESTEngine
53+
}
54+
55+
def configure_factory(self, api_endpoint, config=None):
56+
"""Configure_factory
57+
58+
@property db_url: str. For example driver://user:passwd@host:port/db
59+
"""
60+
schema = api_endpoint.split(':')[0]
61+
try:
62+
self._engine = self._engines_map[schema.lower()](api_endpoint,
63+
config)
64+
except KeyError:
65+
raise ValueError("Can not find driver for schema %s" % schema)
66+
67+
def get_engine(self):
68+
if self._engine:
69+
return self._engine
70+
raise ValueError("Can not return engine. Please configure "
71+
"EngineFactory")
72+
73+
74+
engine_factory = EngineFactory()

0 commit comments

Comments
 (0)