brand-erp / rest-api /controllers /serializers.py
BinaryONe
initial Commit
f9dacfc
# -*- coding: utf-8 -*-
import datetime
from itertools import chain
from .parser import Parser
from .exceptions import QueryFormatError
class Serializer(object):
def __init__(self, record, query="{*}", many=False):
self.many = many
self._record = record
self._raw_query = query
super().__init__()
def get_parsed_restql_query(self):
parser = Parser(self._raw_query)
try:
parsed_restql_query = parser.get_parsed()
return parsed_restql_query
except SyntaxError as e:
msg = "QuerySyntaxError: " + e.msg + " on " + e.text
raise SyntaxError(msg) from None
except QueryFormatError as e:
msg = "QueryFormatError: " + str(e)
raise QueryFormatError(msg) from None
@property
def data(self):
parsed_restql_query = self.get_parsed_restql_query()
if self.many:
return [
self.serialize(rec, parsed_restql_query)
for rec
in self._record
]
return self.serialize(self._record, parsed_restql_query)
@classmethod
def build_flat_field(cls, rec, field_name):
all_fields = rec.fields_get()
if field_name not in all_fields:
msg = "'%s' field is not found" % field_name
raise LookupError(msg)
field_type = rec.fields_get(field_name).get(field_name).get('type')
if field_type in ['one2many', 'many2many']:
return {
field_name: [record.id for record in rec[field_name]]
}
elif field_type in ['many2one']:
return {field_name: rec[field_name].id}
elif field_type == 'datetime' and rec[field_name]:
return {
field_name: rec[field_name].strftime("%Y-%m-%d-%H-%M")
}
elif field_type == 'date' and rec[field_name]:
return {
field_name: rec[field_name].strftime("%Y-%m-%d")
}
elif field_type == 'time' and rec[field_name]:
return {
field_name: rec[field_name].strftime("%H-%M-%S")
}
elif field_type == "binary" and isinstance(rec[field_name], bytes) and rec[field_name]:
return {field_name: rec[field_name].decode("utf-8")}
else:
return {field_name: rec[field_name]}
@classmethod
def build_nested_field(cls, rec, field_name, nested_parsed_query):
all_fields = rec.fields_get()
if field_name not in all_fields:
msg = "'%s' field is not found" % field_name
raise LookupError(msg)
field_type = rec.fields_get(field_name).get(field_name).get('type')
if field_type in ['one2many', 'many2many']:
return {
field_name: [
cls.serialize(record, nested_parsed_query)
for record
in rec[field_name]
]
}
elif field_type in ['many2one']:
return {
field_name: cls.serialize(rec[field_name], nested_parsed_query)
}
else:
# Not a neste field
msg = "'%s' is not a nested field" % field_name
raise ValueError(msg)
@classmethod
def serialize(cls, rec, parsed_query):
data = {}
# NOTE: self.parsed_restql_query["include"] not being empty
# is not a guarantee that the exclude operator(-) has not been
# used because the same self.parsed_restql_query["include"]
# is used to store nested fields when the exclude operator(-) is used
if parsed_query["exclude"]:
# Exclude fields from a query
all_fields = rec.fields_get()
for field in parsed_query["include"]:
if field == "*":
continue
for nested_field, nested_parsed_query in field.items():
built_nested_field = cls.build_nested_field(
rec,
nested_field,
nested_parsed_query
)
data.update(built_nested_field)
flat_fields= set(all_fields).symmetric_difference(set(parsed_query['exclude']))
for field in flat_fields:
flat_field = cls.build_flat_field(rec, field)
data.update(flat_field)
elif parsed_query["include"]:
# Here we are sure that self.parsed_restql_query["exclude"]
# is empty which means the exclude operator(-) is not used,
# so self.parsed_restql_query["include"] contains only fields
# to include
all_fields = rec.fields_get()
if "*" in parsed_query['include']:
# Include all fields
parsed_query['include'] = filter(
lambda item: item != "*",
parsed_query['include']
)
fields = chain(parsed_query['include'], all_fields)
parsed_query['include'] = list(fields)
for field in parsed_query["include"]:
if isinstance(field, dict):
for nested_field, nested_parsed_query in field.items():
built_nested_field = cls.build_nested_field(
rec,
nested_field,
nested_parsed_query
)
data.update(built_nested_field)
else:
flat_field = cls.build_flat_field(rec, field)
data.update(flat_field)
else:
# The query is empty i.e query={}
# return nothing
return {}
return data