1 | import json |
---|
2 | from base64 import b64decode |
---|
3 | from datetime import datetime, date, time, timedelta |
---|
4 | from decimal import Decimal |
---|
5 | from .._compat import PY2, integer_types, basestring, to_bytes, to_native |
---|
6 | from ..adapters.base import SQLAdapter |
---|
7 | from ..helpers.classes import Reference |
---|
8 | from ..helpers.methods import bar_decode_string, bar_decode_integer |
---|
9 | from . import Parser, parsers, for_type, before_parse |
---|
10 | |
---|
11 | long = integer_types[-1] |
---|
12 | |
---|
13 | |
---|
14 | class BasicParser(Parser): |
---|
15 | @for_type("id") |
---|
16 | def _id(self, value): |
---|
17 | return long(value) |
---|
18 | |
---|
19 | @for_type("integer") |
---|
20 | def _integer(self, value): |
---|
21 | return long(value) |
---|
22 | |
---|
23 | @for_type("float") |
---|
24 | def _float(self, value): |
---|
25 | return float(value) |
---|
26 | |
---|
27 | @for_type("double") |
---|
28 | def _double(self, value): |
---|
29 | return self.registered["float"](value, "double") |
---|
30 | |
---|
31 | @for_type("boolean") |
---|
32 | def _boolean(self, value): |
---|
33 | return value == self.dialect.true or str(value)[:1].lower() == "t" |
---|
34 | |
---|
35 | @for_type("blob") |
---|
36 | def _blob(self, value): |
---|
37 | decoded = b64decode(to_bytes(value)) |
---|
38 | try: |
---|
39 | decoded = to_native(decoded) |
---|
40 | except: |
---|
41 | pass |
---|
42 | return decoded |
---|
43 | |
---|
44 | @before_parse("reference") |
---|
45 | def reference_extras(self, field_type): |
---|
46 | return {"referee": field_type[10:].strip()} |
---|
47 | |
---|
48 | @for_type("reference") |
---|
49 | def _reference(self, value, referee): |
---|
50 | if "." not in referee: |
---|
51 | value = Reference(value) |
---|
52 | value._table, value._record = self.adapter.db[referee], None |
---|
53 | return value |
---|
54 | |
---|
55 | @before_parse("list:reference") |
---|
56 | def referencelist_extras(self, field_type): |
---|
57 | return {"field_type": field_type} |
---|
58 | |
---|
59 | @for_type("list:reference") |
---|
60 | def _list_references(self, value, field_type): |
---|
61 | return [self.registered["reference"](el, field_type[5:]) for el in value] |
---|
62 | |
---|
63 | @for_type("bigint") |
---|
64 | def _bigint(self, value): |
---|
65 | return self.registered["integer"](value, "bigint") |
---|
66 | |
---|
67 | |
---|
68 | class DateParser(Parser): |
---|
69 | @for_type("date") |
---|
70 | def _date(self, value): |
---|
71 | if isinstance(value, datetime): |
---|
72 | return value.date() |
---|
73 | (y, m, d) = map(int, str(value)[:10].strip().split("-")) |
---|
74 | return date(y, m, d) |
---|
75 | |
---|
76 | |
---|
77 | class TimeParser(Parser): |
---|
78 | @for_type("time") |
---|
79 | def _time(self, value): |
---|
80 | if isinstance(value, datetime): |
---|
81 | return value.time() |
---|
82 | time_items = list(map(int, str(value)[:8].strip().split(":")[:3])) |
---|
83 | if len(time_items) == 3: |
---|
84 | (h, mi, s) = time_items |
---|
85 | else: |
---|
86 | (h, mi, s) = time_items + [0] |
---|
87 | return time(h, mi, s) |
---|
88 | |
---|
89 | |
---|
90 | class DateTimeParser(Parser): |
---|
91 | @for_type("datetime") |
---|
92 | def _datetime(self, value): |
---|
93 | value = str(value) |
---|
94 | date_part, time_part, timezone = value[:10], value[11:19], value[19:] |
---|
95 | if "+" in timezone: |
---|
96 | ms, tz = timezone.split("+") |
---|
97 | h, m = tz.split(":") |
---|
98 | dt = timedelta(seconds=3600 * int(h) + 60 * int(m)) |
---|
99 | elif "-" in timezone: |
---|
100 | ms, tz = timezone.split("-") |
---|
101 | h, m = tz.split(":") |
---|
102 | dt = -timedelta(seconds=3600 * int(h) + 60 * int(m)) |
---|
103 | else: |
---|
104 | ms = timezone.upper().split("Z")[0] |
---|
105 | dt = None |
---|
106 | (y, m, d) = map(int, date_part.split("-")) |
---|
107 | time_parts = time_part and time_part.split(":")[:3] or (0, 0, 0) |
---|
108 | while len(time_parts) < 3: |
---|
109 | time_parts.append(0) |
---|
110 | time_items = map(int, time_parts) |
---|
111 | (h, mi, s) = time_items |
---|
112 | if ms and ms[0] == ".": |
---|
113 | ms = int(float("0" + ms) * 1000000) |
---|
114 | else: |
---|
115 | ms = 0 |
---|
116 | value = datetime(y, m, d, h, mi, s, ms) |
---|
117 | if dt: |
---|
118 | value = value + dt |
---|
119 | return value |
---|
120 | |
---|
121 | |
---|
122 | class DecimalParser(Parser): |
---|
123 | @for_type("decimal") |
---|
124 | def _decimal(self, value): |
---|
125 | return Decimal(value) |
---|
126 | |
---|
127 | |
---|
128 | class JSONParser(Parser): |
---|
129 | @for_type("json") |
---|
130 | def _json(self, value): |
---|
131 | # if 'loads' not in self.driver_auto_json: |
---|
132 | if not isinstance(value, basestring): |
---|
133 | raise RuntimeError("json data not a string") |
---|
134 | if PY2 and isinstance(value, unicode): |
---|
135 | value = value.encode("utf-8") |
---|
136 | return json.loads(value) |
---|
137 | |
---|
138 | |
---|
139 | class ListsParser(BasicParser): |
---|
140 | @for_type("list:integer") |
---|
141 | def _list_integers(self, value): |
---|
142 | return bar_decode_integer(value) |
---|
143 | |
---|
144 | @for_type("list:string") |
---|
145 | def _list_strings(self, value): |
---|
146 | return bar_decode_string(value) |
---|
147 | |
---|
148 | @for_type("list:reference") |
---|
149 | def _list_references(self, value, field_type): |
---|
150 | value = bar_decode_integer(value) |
---|
151 | return [self.registered["reference"](el, field_type[5:]) for el in value] |
---|
152 | |
---|
153 | |
---|
154 | @parsers.register_for(SQLAdapter) |
---|
155 | class Commonparser( |
---|
156 | ListsParser, DateParser, TimeParser, DateTimeParser, DecimalParser, JSONParser |
---|
157 | ): |
---|
158 | pass |
---|