magnetodb/magnetodb/api/openstack/v1/data/query.py

145 lines
5.6 KiB
Python

# Copyright 2014 Mirantis Inc.
# Copyright 2014 Symantec Corporation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from magnetodb import api
from magnetodb.api.openstack.v1 import parser
from magnetodb.api import validation
from magnetodb.common import probe
from magnetodb.common.utils import request_context_decorator
from magnetodb.openstack.common import log as logging
from magnetodb import storage
from magnetodb.storage import models
LOG = logging.getLogger(__name__)
class QueryController(object):
"""Query for an items by primary or index key. """
@api.enforce_policy("mdb:query")
@probe.Probe(__name__)
@request_context_decorator.request_type("query")
def query(self, req, body, project_id, table_name):
with probe.Probe(__name__ + '.validation'):
validation.validate_object(body, "body")
# get attributes_to_get
attributes_to_get = body.pop(parser.Props.ATTRIBUTES_TO_GET, None)
if attributes_to_get is not None:
validation.validate_list(attributes_to_get,
parser.Props.ATTRIBUTES_TO_GET)
for attr_name in attributes_to_get:
validation.validate_attr_name(attr_name)
index_name = body.pop(parser.Props.INDEX_NAME, None)
if index_name is not None:
validation.validate_index_name(index_name)
select = body.pop(parser.Props.SELECT, None)
if select is None:
if attributes_to_get:
select = models.SelectType.SELECT_TYPE_SPECIFIC
else:
if index_name is not None:
select = models.SelectType.SELECT_TYPE_ALL_PROJECTED
else:
select = models.SelectType.SELECT_TYPE_ALL
else:
validation.validate_string(select, parser.Props.SELECT)
select_type = models.SelectType(select, attributes_to_get)
# parse exclusive_start_key_attributes
exclusive_start_key_attributes_json = body.pop(
parser.Props.EXCLUSIVE_START_KEY, None)
if exclusive_start_key_attributes_json is not None:
validation.validate_object(exclusive_start_key_attributes_json,
parser.Props.EXCLUSIVE_START_KEY)
exclusive_start_key_attributes = (
parser.Parser.parse_item_attributes(
exclusive_start_key_attributes_json
)
)
else:
exclusive_start_key_attributes = None
# parse indexed_condition_map
key_conditions = body.pop(parser.Props.KEY_CONDITIONS, None)
validation.validate_object(key_conditions,
parser.Props.KEY_CONDITIONS)
indexed_condition_map = parser.Parser.parse_attribute_conditions(
key_conditions, condition_class=models.IndexedCondition
)
# TODO(dukhlov):
# it would be nice to validate given table_name, key_attributes and
# attributes_to_get to schema expectation
consistent_read = body.pop(parser.Props.CONSISTENT_READ, False)
validation.validate_boolean(consistent_read,
parser.Props.CONSISTENT_READ)
limit = body.pop(parser.Props.LIMIT, None)
if limit is not None:
limit = validation.validate_integer(limit, parser.Props.LIMIT,
min_val=0)
scan_forward = body.pop(parser.Props.SCAN_INDEX_FORWARD, None)
if scan_forward is not None:
validation.validate_boolean(scan_forward,
parser.Props.SCAN_INDEX_FORWARD)
order_type = (
models.ORDER_TYPE_ASC if scan_forward else
models.ORDER_TYPE_DESC
)
else:
order_type = None
validation.validate_unexpected_props(body, "body")
# select item
result = storage.query(
req.context, table_name, indexed_condition_map,
select_type=select_type, index_name=index_name, limit=limit,
consistent=consistent_read, order_type=order_type,
exclusive_start_key=exclusive_start_key_attributes
)
# format response
if select_type.type == models.SelectType.SELECT_TYPE_COUNT:
response = {
parser.Props.COUNT: result.count
}
else:
response = {
parser.Props.COUNT: result.count,
parser.Props.ITEMS: [
parser.Parser.format_item_attributes(row)
for row in result.items
]
}
if limit == result.count:
response[parser.Props.LAST_EVALUATED_KEY] = (
parser.Parser.format_item_attributes(
result.last_evaluated_key)
)
return response