Tengo problemas para insertar datos en una tabla con una columna de matriz de tipos de datos personalizados en Python.
El esquema se parece a:
CREATE TYPE data_source AS ENUM ('smtp', 'ftp', 'http'); CREATE TABLE IF NOT EXISTS data( id BIGSERIAL PRIMARY KEY, foo TEXT NOT NULL, sources data_source[] );luego, quiero insertar algunos datos en dicha tabla desde Python usando psycopg2:
foo = "my_text" sources = ["ftp", "http"] cursor.execute( """ INSERT INTO data(foo, sources) VALUES (%s, %s) """, (foo, sources), )este código termina con una excepción de tiempo de ejecución:
LINE 3: ...('my text', ARRAY['ftp... ^ HINT: You will need to rewrite or cast the expression. Entiendo que necesito llamar a ::data_source type casting a cada uno de los elementos del ARRAY . ¿Cómo puedo conseguir esto?
Traté de aprovechar la función de adapt del paquete psycopg2.extensions
class Source: def __init__(self, source): self.string = source def adapt_source(source): quoted = psycopg2.extensions.adapt(source.string).getquoted() return psycopg2.extensions.AsIs(f"{quoted}::data_source'") psycopg2.extensions.register_adapter(Source, adapt_source) foo = "my_text" sources = [Source("ftp"), Source("http")] cursor.execute( """ INSERT INTO data(foo, sources) VALUES (%s, %s) """, (foo, sources), )pero este código termina con:
psycopg2.errors.SyntaxError: syntax error at or near ""'ftp'"" LINE 3: ...my text', (b"'ftp'"::... ^ Supongo que el problema está en la función AsIs que combina bytes de la función getquoted y la cadena formateada.
¿Alguien puede ayudarme o indicarme alguna solución?
Gracias
Extendiendo la respuesta de Adrian Klaver, también debe convertir al tipo de base de datos data_source que definió en el esquema.
cur.execute( """ INSERT INTO data(foo, sources) VALUES (%s, %s::data_source[]) """, (foo, sources), ) con.commit()Esto funciona para mí.
Un ejemplo completo de lo que propuse en mi comentario:
CREATE TYPE data_source AS ENUM ('smtp', 'ftp', 'http'); CREATE TABLE IF NOT EXISTS data( id BIGSERIAL PRIMARY KEY, foo TEXT NOT NULL, sources data_source[] ); import psycopg2 con = psycopg2.connect(database="test", host='localhost', user='postgres') cur = con.cursor() foo = "my_text" source_list = ["ftp", "http"] sources = '{' + ','.join(source_list) + '}' sources '{ftp,http}' cur.execute( """ INSERT INTO data(foo, sources) VALUES (%s, %s) """, (foo, sources), ) con.commit() select * from data; id | foo | sources ----+---------+------------ 1 | my_text | {ftp,http} Convierta una lista de fuentes en una representación de cadena de una matriz y utilícela como el valor de las sources .