示例#1
0
    def into(self, table, schema=None):
        """
        Sets table name and schema
        if table is object, it will also set fields and values
        :param table: string or record object
        :param schema: optional string
        :return: self
        """
        if isinstance(table, str):
            pass
        elif isinstance(table, object):
            schema = getattr(table, ATTR_SCHEMA, schema)
            tname = getattr(table, ATTR_TABLE, None)
            if tname is None:
                raise SqlError("into(): invalid type for table name")
            if not isclass(table):
                self.values(table)
            table = tname
        else:
            raise SqlError("into(): invalid type for table name")

        if schema is not None and not isinstance(schema, str):
            raise SqlError("into(): Invalid type for schema name: %s" %
                           str(type(schema)))

        self._table = table
        self._schema = schema
        return self
示例#2
0
    def values(self, values: Union[list, dict, object]):
        """
        Set fields and/or values for insertion

        This method can be called multiple times; new field/value pairs will be added to the internal structure;
        Existing fields will have their value overridden

        :param values: list, dict or record object
        :return: self
        """
        # if list, replace values
        if isinstance(values, (list, tuple)):
            self._values = values

        elif isinstance(values, collections.abc.Mapping):
            self._fields = values.keys()
            self._values = list(values.values())

        elif isinstance(values, object):
            # support any object that has a method "asrecord"
            if not callable(getattr(values, 'asrecord', None)):
                raise SqlError(
                    "values(): invalid object type for data parameter")
            values = values.asrecord()
            self._fields = values.keys()
            self._values = list(values.values())
        else:
            raise SqlError("values(): Invalid data type")

        return self
示例#3
0
    def from_(self, table, schema=None):
        """
        DELETE FROM table name and schema
        :param table: string or record object
        :param schema: optional string
        :return: self

        Possible values for table:
            'table' -> string with table name
            <object_or_class> -> record class or object
        """
        if isinstance(table, str):
            pass
        elif isinstance(table, object):
            schema = getattr(table, ATTR_SCHEMA, schema)
            table = getattr(table, ATTR_TABLE, None)
            if table is None:
                raise SqlError("from_(): invalid type for table name")
        else:
            raise SqlError("from_(): invalid type for table name")

        if schema is not None and type(schema) is not str:
            raise SqlError("from_(): Invalid type for schema name: %s" %
                           str(type(schema)))

        self._table = table
        self._schema = schema
        return self
示例#4
0
    def field(self, field, field_alias=None, table=None, schema=None):
        """
        Quotes a field name, optimizing for PostgreSQL syntax

        :param field: field name or Literal
        :param field_alias: optional alias and/or cast information
        :param table: optional table
        :param schema: optional schema
        :return: str

        Examples:
            field('field', None) -> "field"
            field('field', 'alias') -> "field" AS "alias"
            field('field', ['text']) -> "field"::text
            field('field', ['text', 'alias']) -> "field"::text AS "alias"
            field(Literal('COUNT(*)'), ['int', 'total']) -> COUNT(*)::int AS "total"
            field('field', 'alias', 'table') -> "table"."field" AS "alias"
            field('field', 'alias', 'table', 'public') -> "public"."table"."field" AS "alias"
        """
        if table is not None:
            table = self._quote_table.format(table=table) + self._separator
            if schema is not None:
                table = self._quote_schema.format(
                    schema=schema) + self._separator + table
        else:
            table = ""

        if isinstance(field, Literal):
            field = str(field)
            table = ""
        elif field != "*":
            field = self._quote_field.format(field=field)
        field = table + field

        if field_alias is None:
            return field
        elif isinstance(field_alias, str):
            return self._as.join(
                [field, self._quote_field.format(field=field_alias)])
        elif isinstance(field_alias, (list, tuple)):
            _len = len(field_alias)
            if _len == 0:
                raise SqlError("Alias for field %s cannot be empty" % field)
            # generate pg-style cast with ::<type>
            cast = self._cast + field_alias[0]
            if _len > 1:
                return self._as.join([
                    field + cast,
                    self._quote_field.format(field=field_alias[1])
                ])
            else:
                return field + cast
        else:
            raise SqlError("Cannot parse fields")
示例#5
0
    def _where(self, field, operator=None, value=None, is_and=True):
        """
        Internal where handler

        :param field: expression
        :param operator: clause operator
        :param value: optional value
        :param is_and: True to interleave with AND, False to OR
        :return: self
        """
        concat = Sql.SQL_AND
        if is_and is False:
            concat = Sql.SQL_OR

        if isinstance(field, str):
            field = self._dialect.field(field)
        elif isinstance(field, Literal):
            field = str(field)
        else:
            raise SqlError("_where(): invalid field name type")

        if value is None:
            if operator is None:
                expression = "{fld}".format(fld=field)
            else:
                expression = "{fld} {op}".format(fld=field, op=operator)
            self._clauses.append([expression, concat])
        else:
            # sanity check, as we actually may have value list if subquery is in use
            if isinstance(value, (list, tuple, dict)):
                raise SqlError("_where(): invalid value type: %s" %
                               str(type(value)))

            if operator is None:
                expression = "{fld} {ph}".format(fld=field,
                                                 ph=self._dialect.placeholder)
            else:
                if isinstance(value, Select):
                    sql, value = value.assemble()
                    expression = "{fld} {op} ({query})".format(fld=field,
                                                               op=operator,
                                                               query=sql)
                else:
                    expression = "{fld} {op} {ph}".format(
                        fld=field, op=operator, ph=self._dialect.placeholder)

            self._clauses.append([expression, concat])
            if isinstance(value, list):
                self._clause_values.extend(value)
            else:
                self._clause_values.append(value)
        return self
示例#6
0
    def field(self, field, field_alias=None, table=None, schema=None):
        """
        Quotes a field name
        :param field: field name or Literal
        :param field_alias: optional alias and/or cast information
        :param table: optional table
        :param schema: optional schema (not supported)
        :return: str

        Examples:
            field('field', None) -> "field"
            field('field', 'alias') -> "field" AS "alias"
            field('field', ['text']) -> CAST("field" AS text)
            field('field', ['text', 'alias']) -> CAST("field" AS text) AS "alias"
            field(Literal('COUNT(*)'), ['int', 'total']) -> CAST(COUNT(*) AS int) AS "total"
            field('field', 'alias', 'table') -> "table"."field" AS "alias"
            field('field', 'alias', 'table', 'public') -> "public"."table"."field" AS "alias"
        """
        if table is not None:
            table = self._quote_table.format(table=table) + self._separator
            if schema is not None:
                table = self._quote_schema.format(
                    schema=schema) + self._separator + table
        else:
            table = ""

        if isinstance(field, Literal):
            field = str(field)
            table = ""
        elif field != "*":
            field = self._quote_field.format(field=field)
        field = table + field

        if field_alias is None:
            return field
        elif isinstance(field_alias, str):
            return self._as.join(
                [field, self._quote_field.format(field=field_alias)])
        elif isinstance(field_alias, (list, tuple)):
            _len = len(field_alias)
            if _len == 0:
                raise SqlError("Alias for field %s cannot be empty" % field)
            field = self._cast.format(field=field, cast=field_alias[0])
            if _len > 1:
                return self._as.join(
                    [field,
                     self._quote_field.format(field=field_alias[1])])
            else:
                return field
        else:
            raise SqlError("Cannot parse fields")
示例#7
0
    def returning(self, fields):
        """
        RETURNING clause
        :param fields: str or list with fields to be returned
        :return: self
        """
        if isinstance(fields, str):
            fields = [fields]

        if not isinstance(fields, (list, tuple)):
            raise SqlError("returning(): invalid return field type: %s" %
                           str(type(fields)))

        if len(fields) == 0:
            raise SqlError("returning(): field list cannot be empty")

        self._returning = fields
        return self
示例#8
0
    def fields(self, fields: list):
        """
        Set fields for insertion
        :param fields: list of field names
        :return: self
        """
        if not isinstance(fields, (list, tuple)):
            raise SqlError("fields(): invalid type for fields parameter")

        self._fields = fields
        return self
示例#9
0
    def assemble(self):
        """
        Assemble the UPDATE statement
        :return: tuple(str, list)
        """
        # simple validations
        lf = len(self._fields)
        if lf == 0:
            raise SqlError("assemble(): field list is empty")
        if lf != len(self._values):
            raise SqlError("assemble(): field and value count mismatch")

        parts = [
            Sql.SQL_UPDATE,
            self._dialect.table(self._table, None, schema=self._schema),
            Sql.SQL_SET,
        ]

        # generate field list and placeholder list
        fields = []
        for name in self._fields:
            fields.append("{field}={ph}".format(
                field=self._dialect.field(name), ph=self._dialect.placeholder))
        parts.append(", ".join(fields))
        values = self._values

        # where clause
        if len(self._clauses) > 0:
            c = 0
            parts.append(Sql.SQL_WHERE)
            values.extend(self._clause_values)

            for clause in self._clauses:
                expr, concat = clause
                if c > 0:
                    parts.append(concat)
                parts.append(expr)
                c += 1

        return " ".join(parts), values
示例#10
0
    def assemble(self):
        """
        Assemble the INSERT SQL
        :return: tuple(str, list)
        """
        # simple validations
        lf = len(self._fields)
        if lf == 0:
            raise SqlError("assemble(): field list is empty")
        if lf != len(self._values):
            raise SqlError("assemble(): field and value count mismatch")

        parts = [
            Sql.SQL_INSERT,
            self._dialect.table(self._table, None, schema=self._schema)
        ]

        # generate field list and placeholder list
        fields = []
        placeholders = []
        for name in self._fields:
            fields.append(self._dialect.field(name))
            placeholders.append(self._dialect.placeholder)

        parts.append("({})".format(", ".join(fields)))
        parts.append(Sql.SQL_VALUES)
        parts.append("({})".format(", ".join(placeholders)))

        # optional returning clause
        if self._returning:
            fields = []
            for name in self._returning:
                fields.append(self._dialect.field(name))

            parts.append(Sql.SQL_RETURNING)
            parts.append(", ".join(fields))

        return " ".join(parts), self._values