from functools import partial

from polecat.db.query import query as query_module
from psycopg2.sql import SQL, Placeholder

from .expression import Expression


class Values(Expression):
    def __init__(self, values, relation=None):
        self.values = values
        self.relation = relation
        self.keyword = 'VALUES'

    def to_sql(self):
        if isinstance(self.values, query_module.Values):
            get_values_sql = partial(
                self.get_values_sql_from_values, self.values
            )
        else:
            get_values_sql = partial(
                self.get_values_sql_from_dict, self.values
            )
        return self.get_values_sql(get_values_sql)

    def get_values_sql(self, get_values_sql):
        values_sql, values_args = get_values_sql()
        joined_sql = SQL(', ').join(
            SQL('({})').format(
                SQL(', ').join(row_sql)
            )
            for row_sql in values_sql
        )
        return SQL('%s {}' % self.keyword).format(joined_sql), values_args

    def get_values_sql_from_values(self, values):
        column_values_sql = []
        column_values = ()
        for row in values.iter_rows():
            row_values_sql = []
            for column_name, column_value in row:
                value_sql, value = self.value_to_sql(column_value, column_name)
                row_values_sql.append(value_sql)
                column_values += value
            column_values_sql.append(row_values_sql)
        return column_values_sql, column_values

    def get_values_sql_from_dict(self, values_dict):
        column_values_sql = []
        column_values = ()
        for column_name, column_value in values_dict.items():
            value_sql, value = self.value_to_sql(column_value, column_name)
            column_values_sql.append(value_sql)
            column_values += value
        return (column_values_sql,), column_values

    def value_to_sql(self, value, column_name=None):
        if isinstance(value, Expression):
            sql, args = value.to_sql()
            return SQL('{}').format(sql), args
        else:
            if self.relation and column_name:
                column = self.relation.get_column(column_name)
                value = column.to_db_value(value)
            return Placeholder(), (value,)

    def iter_column_names(self):
        if isinstance(self.values, dict):
            return self.values.keys()
        else:
            return self.values.iter_column_names()

[((438, 491), 'functools.partial', 'partial', (['self.get_values_sql_from_values', 'self.values'], {}), '(self.get_values_sql_from_values, self.values)\n', (445, 491), False, 'from functools import partial\n'), ((565, 616), 'functools.partial', 'partial', (['self.get_values_sql_from_dict', 'self.values'], {}), '(self.get_values_sql_from_dict, self.values)\n', (572, 616), False, 'from functools import partial\n'), ((817, 826), 'psycopg2.sql.SQL', 'SQL', (['""", """'], {}), "(', ')\n", (820, 826), False, 'from psycopg2.sql import SQL, Placeholder\n'), ((2299, 2312), 'psycopg2.sql.Placeholder', 'Placeholder', ([], {}), '()\n', (2310, 2312), False, 'from psycopg2.sql import SQL, Placeholder\n'), ((982, 1009), 'psycopg2.sql.SQL', 'SQL', (["('%s {}' % self.keyword)"], {}), "('%s {}' % self.keyword)\n", (985, 1009), False, 'from psycopg2.sql import SQL, Placeholder\n'), ((845, 856), 'psycopg2.sql.SQL', 'SQL', (['"""({})"""'], {}), "('({})')\n", (848, 856), False, 'from psycopg2.sql import SQL, Placeholder\n'), ((2079, 2088), 'psycopg2.sql.SQL', 'SQL', (['"""{}"""'], {}), "('{}')\n", (2082, 2088), False, 'from psycopg2.sql import SQL, Placeholder\n'), ((881, 890), 'psycopg2.sql.SQL', 'SQL', (['""", """'], {}), "(', ')\n", (884, 890), False, 'from psycopg2.sql import SQL, Placeholder\n')]