Example #1
0
    def parse_body_dict(self, model, allow_recursion, body_data):
        attributes = {}
        linked_attributes = {}
        mapper = inspect(model)

        for key, value in body_data.items():
            if isinstance(getattr(model, key, None), property):
                # Value is set using a function, so we cannot tell what type it will be
                attributes[key] = value
                continue
            try:
                column = mapper.columns[key]
            except KeyError:
                if not allow_recursion:
                    # Assume programmer has done their job of filtering out invalid
                    # columns, and that they are going to use this field for some
                    # custom purpose
                    continue
                try:
                    relationship = mapper.relationships[key]
                    if relationship.uselist:
                        linked_attributes[key] = [
                            self.parse_body_dict(relationship.mapper.entity,
                                                 False, entity)[0]
                            for entity in value
                        ]
                    else:
                        linked_attributes[key] = self.parse_body_dict(
                            relationship.mapper.entity, False, value)[0]
                    continue
                except KeyError:
                    # Assume programmer has done their job of filtering out invalid
                    # columns, and that they are going to use this field for some
                    # custom purpose
                    continue
            if isinstance(column.type, sqlalchemy.sql.sqltypes.DateTime):
                if value is None:
                    attributes[key] = None
                elif key in getattr(
                        self, 'datetime_in_ms', []
                ):  # List of datetime columns to keep as ms since Unix epoch
                    attributes[key] = datetime.fromtimestamp(value)
                elif key in getattr(self, 'naive_datetimes',
                                    []):  # List of naive datetime columns
                    attributes[key] = datetime.strptime(
                        value, '%Y-%m-%dT%H:%M:%S')
                else:
                    attributes[key] = datetime.strptime(
                        value, '%Y-%m-%dT%H:%M:%SZ')
            elif isinstance(column.type, sqlalchemy.sql.sqltypes.Date):
                attributes[key] = datetime.strptime(
                    value, '%Y-%m-%d').date() if value is not None else None
            elif isinstance(column.type, sqlalchemy.sql.sqltypes.Time):
                if value is not None:
                    hour, minute, second = value.split(':')
                    attributes[key] = time(int(hour), int(minute), int(second))
                else:
                    attributes[key] = None
            elif support_geo and isinstance(
                    column.type, Geometry) and column.type.geometry_type in [
                        'POINT', 'POINTZ'
                    ]:
                axes = getattr(self, 'geometry_axes', {}).get(
                    key, ['x', 'y', 'z']
                    if column.type.geometry_type == 'POINTZ' else ['x', 'y'])
                point = Point(*list(
                    value.get(axes[index], 0)
                    for index in range(0, len(axes))))
                # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail
                attributes[key] = WKBElement(point.wkb, srid=4326)
            elif support_geo and isinstance(
                    column.type, Geometry) and column.type.geometry_type in [
                        'LINESTRING', 'LINESTRINGZ'
                    ]:
                axes = getattr(self, 'geometry_axes', {}).get(
                    key, ['x', 'y', 'z'] if column.type.geometry_type
                    == 'LINESTRINGZ' else ['x', 'y'])
                line = LineString([
                    point.get(axes[index], 0) for index in range(0, len(axes))
                ] for point in value)
                # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail
                attributes[key] = WKBElement(line.wkb, srid=4326)
            elif support_geo and isinstance(
                    column.type, Geometry) and column.type.geometry_type in [
                        'POLYGON', 'POLYGONZ'
                    ]:
                axes = getattr(self, 'geometry_axes', {}).get(
                    key, ['x', 'y', 'z']
                    if column.type.geometry_type == 'POLYGONZ' else ['x', 'y'])
                polygon = Polygon([
                    point.get(axes[index], 0) for index in range(0, len(axes))
                ] for point in value)
                # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail
                attributes[key] = WKBElement(polygon.wkb, srid=4326)
            else:
                attributes[key] = value

        return (attributes, linked_attributes)
Example #2
0
    def deserialize(self, model, path_data, body_data, allow_recursion=False):
        mapper = inspect(model)
        attributes = {}
        naive_datetimes = getattr(self, 'naive_datetimes', [])

        for key, value in path_data.items():
            key = getattr(self, 'attr_map', {}).get(key, key)
            if getattr(model, key, None) is None or not isinstance(
                    inspect(model).attrs[key], ColumnProperty):
                self.logger.error(
                    "Programming error: {0}.attr_map['{1}'] does not exist or is not a column"
                    .format(model, key))
                raise falcon.errors.HTTPInternalServerError(
                    'Internal Server Error',
                    'An internal server error occurred')
            attributes[key] = value

        deserialized = [attributes, {}]

        for key, value in body_data.items():
            if isinstance(getattr(model, key, None), property):
                # Value is set using a function, so we cannot tell what type it will be
                attributes[key] = value
                continue
            try:
                column = mapper.columns[key]
            except KeyError:
                if not allow_recursion:
                    # Assume programmer has done their job of filtering out invalid
                    # columns, and that they are going to use this field for some
                    # custom purpose
                    continue
                try:
                    relationship = mapper.relationships[key]
                    if relationship.uselist:
                        for entity in value:
                            deserialized[1][key] = [
                                self.deserialize(relationship.mapper.entity,
                                                 {}, entity, False)[0]
                                for entity in value
                            ]
                    else:
                        deserialized[1][key] = self.deserialize(
                            relationship.mapper.entity, {}, value, False)[0]
                    continue
                except KeyError:
                    # Assume programmer has done their job of filtering out invalid
                    # columns, and that they are going to use this field for some
                    # custom purpose
                    continue
            if isinstance(column.type, sqlalchemy.sql.sqltypes.DateTime):
                if value is None:
                    attributes[key] = None
                elif key in naive_datetimes:
                    attributes[key] = datetime.strptime(
                        value, '%Y-%m-%dT%H:%M:%S')
                else:
                    attributes[key] = datetime.strptime(
                        value, '%Y-%m-%dT%H:%M:%SZ')
            elif isinstance(column.type, sqlalchemy.sql.sqltypes.Date):
                attributes[key] = datetime.strptime(
                    value, '%Y-%m-%d').date() if value is not None else None
            elif isinstance(column.type, sqlalchemy.sql.sqltypes.Time):
                if value is not None:
                    hour, minute, second = value.split(':')
                    attributes[key] = time(int(hour), int(minute), int(second))
                else:
                    attributes[key] = None
            elif support_geo and isinstance(
                    column.type, Geometry) and column.type.geometry_type in [
                        'POINT', 'POINTZ'
                    ]:
                axes = getattr(self, 'geometry_axes', {}).get(
                    key, ['x', 'y', 'z']
                    if column.type.geometry_type == 'POINTZ' else ['x', 'y'])
                point = Point(*list(
                    value.get(axes[index], 0)
                    for index in range(0, len(axes))))
                # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail
                attributes[key] = WKBElement(point.wkb, srid=4326)
            elif support_geo and isinstance(
                    column.type, Geometry) and column.type.geometry_type in [
                        'LINESTRING', 'LINESTRINGZ'
                    ]:
                axes = getattr(self, 'geometry_axes', {}).get(
                    key, ['x', 'y', 'z'] if column.type.geometry_type
                    == 'LINESTRINGZ' else ['x', 'y'])
                line = LineString([
                    point.get(axes[index], 0) for index in range(0, len(axes))
                ] for point in value)
                # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail
                attributes[key] = WKBElement(line.wkb, srid=4326)
            elif support_geo and isinstance(
                    column.type, Geometry) and column.type.geometry_type in [
                        'POLYGON', 'POLYGONZ'
                    ]:
                axes = getattr(self, 'geometry_axes', {}).get(
                    key, ['x', 'y', 'z']
                    if column.type.geometry_type == 'POLYGONZ' else ['x', 'y'])
                polygon = Polygon([
                    point.get(axes[index], 0) for index in range(0, len(axes))
                ] for point in value)
                # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail
                attributes[key] = WKBElement(polygon.wkb, srid=4326)
            else:
                attributes[key] = value
        return deserialized