Changeset: 18a241a95c44 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=18a241a95c44 Modified Files: clients/iotapi/documentation/websockets_api.rst clients/iotapi/src/Settings/mapiconnection.py clients/iotapi/src/Streams/datatypes.py clients/iotapi/src/Streams/streampolling.py clients/iotclient/src/Streams/datatypes.py Branch: iot Log Message:
Changed polling SQL query. Added more information about streams' columns on Web API diffs (truncated from 358 to 300 lines): diff --git a/clients/iotapi/documentation/websockets_api.rst b/clients/iotapi/documentation/websockets_api.rst --- a/clients/iotapi/documentation/websockets_api.rst +++ b/clients/iotapi/documentation/websockets_api.rst @@ -185,11 +185,14 @@ Message with details about a stream incl "columns": [ { "name": "sensorid", - "type": "clob" + "type": "clob", + "nullable": false, + "default": "living room" }, { "name": "temperature", - "type": "real" + "type": "real", + "nullable": false } ], "baskets_count": 3, @@ -225,11 +228,14 @@ Returns a info message regarding all the "columns": [ { "name": "sensorid", - "type": "clob" + "type": "clob", + "nullable": false, + "default": "living room" }, { "name": "temperature", - "type": "real" + "type": "real", + "nullable": false } ], "baskets_count": 3, diff --git a/clients/iotapi/src/Settings/mapiconnection.py b/clients/iotapi/src/Settings/mapiconnection.py --- a/clients/iotapi/src/Settings/mapiconnection.py +++ b/clients/iotapi/src/Settings/mapiconnection.py @@ -1,4 +1,3 @@ -import getpass import sys import pymonetdb @@ -30,11 +29,12 @@ def close_monetdb_connection(): def fetch_streams(): try: # TODO paginate results? cursor = Connection.cursor() - sql_string = """SELECT storage."schema", storage."table", storage."column", storage."type", storage."typewidth" - FROM (SELECT "schema", "table", "column", "type", "typewidth" FROM sys.storage) AS storage - INNER JOIN (SELECT "name" FROM sys.tables WHERE type=4) AS tables ON (storage."table"=tables."name") - INNER JOIN (SELECT "name" FROM sys.schemas) AS schemas ON (storage."schema"=schemas."name");"""\ - .replace('\n', ' ') + sql_string = """SELECT schemas."name" as schema, tables."name" as table, columns."name" as column, + columns."type", columns."type_digits", columns."type_scale", columns."default", columns."null" FROM + (SELECT "id", "name", "schema_id" FROM sys.tables WHERE type=4) AS tables INNER JOIN (SELECT "id", "name" + FROM sys.schemas) AS schemas ON (tables."schema_id"=schemas."id") INNER JOIN (SELECT "table_id", "name", + "type", "type_digits", "type_scale", "default", "null" FROM sys.columns) AS columns ON + (columns."table_id"=tables."id");""".replace('\n', ' ') # important STREAM TABLES TYPE is 4 cursor.execute(sql_string) return cursor.fetchall() except BaseException as ex: diff --git a/clients/iotapi/src/Streams/datatypes.py b/clients/iotapi/src/Streams/datatypes.py --- a/clients/iotapi/src/Streams/datatypes.py +++ b/clients/iotapi/src/Streams/datatypes.py @@ -20,13 +20,17 @@ FLOAT_NAN = struct.unpack('f', '\xff\xff DOUBLE_NAN = struct.unpack('d', '\xff\xff\xff\xff\xff\xff\xef\xff')[0] +# elem[0] is column name, elem[1] is type, elem[2] is type_digits, elem[3] is type_scale elem[4] is default value +# elem[5] is nullable class StreamDataType(object): """MonetDB's data types for reading base class""" __metaclass__ = ABCMeta - def __init__(self, **kwargs): - self._column_name = kwargs['name'] # name of the column - self._data_type = kwargs['type'] # SQL name of the type + def __init__(self, *args): + self._column_name = args[0] # name of the column + self._data_type = args[1] # SQL name of the type + self._default_value = args[4] # default value text + self._is_nullable = args[5] # is nullable def is_file_mode_binary(self): return True @@ -53,14 +57,17 @@ class StreamDataType(object): return results def to_json_representation(self): # get a json representation of the data type while checking the stream's info - return {'name': self._column_name, 'type': self._data_type} + dic = {'name': self._column_name, 'type': self._data_type, 'nullable': self._is_nullable} + if self._default_value is not None: + dic['default'] = self._default_value + return dic class TextType(StreamDataType): - """Covers: CHAR, VARCHAR, CLOB and URL""" + """Covers: CLOB and Url""" - def __init__(self, **kwargs): - super(TextType, self).__init__(**kwargs) + def __init__(self, *args): + super(TextType, self).__init__(*args) self._nullable_constant = NIL_STRING def is_file_mode_binary(self): @@ -81,11 +88,24 @@ class TextType(StreamDataType): return array +class LimitedTextType(TextType): + """Covers: CHAR and VARCHAR""" + + def __init__(self, *args): + super(LimitedTextType, self).__init__(*args) + self._limit = args[2] + + def to_json_representation(self): + json_value = super(LimitedTextType, self).to_json_representation() + json_value['limit'] = self._limit + return json_value + + class INetType(StreamDataType): """Covers: Inet""" - def __init__(self, **kwargs): - super(INetType, self).__init__(**kwargs) + def __init__(self, *args): + super(INetType, self).__init__(*args) def skip_tuples(self, file_pointer, offset): file_pointer.seek(offset << 3) @@ -109,8 +129,8 @@ class INetType(StreamDataType): class UUIDType(StreamDataType): """Covers: UUID""" - def __init__(self, **kwargs): - super(UUIDType, self).__init__(**kwargs) + def __init__(self, *args): + super(UUIDType, self).__init__(*args) def skip_tuples(self, file_pointer, offset): file_pointer.seek(offset << 4) @@ -139,8 +159,8 @@ class UUIDType(StreamDataType): class BooleanType(StreamDataType): """Covers: BOOLEAN""" - def __init__(self, **kwargs): - super(BooleanType, self).__init__(**kwargs) + def __init__(self, *args): + super(BooleanType, self).__init__(*args) self._nullable_constant = INT8_MIN def skip_tuples(self, file_pointer, offset): @@ -154,8 +174,8 @@ class BooleanType(StreamDataType): class SmallIntegerType(StreamDataType): """Covers: TINYINT, SMALLINT, INTEGER, BIGINT""" - def __init__(self, **kwargs): - super(SmallIntegerType, self).__init__(**kwargs) + def __init__(self, *args): + super(SmallIntegerType, self).__init__(*args) self._pack_sym = {'tinyint': 'b', 'smallint': 'h', 'int': 'i', 'integer': 'i', 'bigint': 'q'} \ .get(self._data_type) self._size = struct.calcsize(self._pack_sym) @@ -174,8 +194,8 @@ class SmallIntegerType(StreamDataType): class HugeIntegerType(StreamDataType): """Covers: HUGEINT""" - def __init__(self, **kwargs): - super(HugeIntegerType, self).__init__(**kwargs) + def __init__(self, *args): + super(HugeIntegerType, self).__init__(*args) self._nullable_constant = INT128_MIN def skip_tuples(self, file_pointer, offset): @@ -197,8 +217,8 @@ class HugeIntegerType(StreamDataType): class FloatType(StreamDataType): """Covers: REAL, DOUBLE""" - def __init__(self, **kwargs): - super(FloatType, self).__init__(**kwargs) + def __init__(self, *args): + super(FloatType, self).__init__(*args) self._pack_sym = {'real': 'f', 'float': 'd', 'double': 'd'}.get(self._data_type) self._size = struct.calcsize(self._pack_sym) self._nullable_constant = {'real': FLOAT_NAN, 'float': DOUBLE_NAN, 'double': DOUBLE_NAN}.get(self._data_type) @@ -215,12 +235,24 @@ class FloatType(StreamDataType): class DecimalType(StreamDataType): """Covers: DECIMAL""" - def __init__(self, **kwargs): - super(DecimalType, self).__init__(**kwargs) + def __init__(self, *args): + super(DecimalType, self).__init__(*args) + self._precision = args[2] + self._scale = args[3] - self._pack_sym = {'1': 'b', '2': 'h', '4': 'i', '8': 'q', '16': 'Q'}.get(kwargs['typewidth']) - self._nullable_constant = {'1': INT8_MIN, '2': INT16_MIN, '4': INT32_MIN, '8': INT64_MIN, '16': INT128_MIN} \ - .get(kwargs['typewidth']) + if self._precision <= 2: # calculate the number of bytes to use according to the precision + self._pack_sym = 'b' + elif 2 < self._precision <= 4: + self._pack_sym = 'h' + elif 4 < self._precision <= 8: + self._pack_sym = 'i' + elif 8 < self._precision <= 18: + self._pack_sym = 'q' + elif 18 < self._precision <= 38: + self._pack_sym = 'Q' + + self._nullable_constant = {'b': INT8_MIN, 'h': INT16_MIN, 'i': INT32_MIN, 'q': INT64_MIN, 'Q': INT128_MIN} \ + .get(self._pack_sym) self._size = struct.calcsize(self._pack_sym) if self._pack_sym == 'Q': self._size <<= 1 # has to read two values at once @@ -244,12 +276,18 @@ class DecimalType(StreamDataType): results.append(next_huge_decimal) return results + def to_json_representation(self): + json_value = super(DecimalType, self).to_json_representation() + json_value['precision'] = self._precision + json_value['scale'] = self._scale + return json_value + class DateType(StreamDataType): # Stored as an uint with the number of days since day 1 of month 1 (Jan) from year 0 """Covers: DATE""" - def __init__(self, **kwargs): - super(DateType, self).__init__(**kwargs) + def __init__(self, *args): + super(DateType, self).__init__(*args) self._nullable_constant = INT32_MIN def skip_tuples(self, file_pointer, offset): @@ -269,8 +307,8 @@ class DateType(StreamDataType): # Store class TimeType(StreamDataType): # Stored as an uint with the number of milliseconds since hour 00:00:00 """Covers: TIME""" - def __init__(self, **kwargs): - super(TimeType, self).__init__(**kwargs) + def __init__(self, *args): + super(TimeType, self).__init__(*args) self._nullable_constant = INT32_MIN def skip_tuples(self, file_pointer, offset): @@ -290,12 +328,20 @@ class TimeType(StreamDataType): # Store .isoformat()) return results + def to_json_representation(self): + json_value = super(TimeType, self).to_json_representation() + if self._data_type == 'timez': + json_value['with_timezone'] = True + else: + json_value['with_timezone'] = False + return json_value + class TimestampType(StreamDataType): # it's represented with the two integers from time and date """Covers: TIMESTAMP""" - def __init__(self, **kwargs): - super(TimestampType, self).__init__(**kwargs) + def __init__(self, *args): + super(TimestampType, self).__init__(*args) def skip_tuples(self, file_pointer, offset): file_pointer.seek(offset << 3) @@ -317,3 +363,11 @@ class TimestampType(StreamDataType): # results.append(datetime.combine(read_date, time(hour=hour, minute=minute, second=second, microsecond=milliseconds * 1000)).isoformat()) return results + + def to_json_representation(self): + json_value = super(TimestampType, self).to_json_representation() + if self._data_type == 'timestamptz': + json_value['with_timezone'] = True + else: + json_value['with_timezone'] = False + return json_value diff --git a/clients/iotapi/src/Streams/streampolling.py b/clients/iotapi/src/Streams/streampolling.py --- a/clients/iotapi/src/Streams/streampolling.py +++ b/clients/iotapi/src/Streams/streampolling.py @@ -6,15 +6,16 @@ from datatypes import * from streams import IOTStream from streamscontext import Streams_Context -SWITCHER = [{'types': ['clob', 'char', 'varchar', 'url'], 'class': 'TextType'}, +SWITCHER = [{'types': ['clob', 'url'], 'class': 'TextType'}, + {'types': ['char', 'varchar'], 'class': 'LimitedTextType'}, {'types': ['tinyint', 'smallint', 'int', 'bigint'], 'class': 'SmallIntegerType'}, {'types': ['hugeint'], 'class': 'HugeIntegerType'}, _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list