sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Cómo insertar un registro actualizable con columna JSON en PostgreSQL usando JOOQ?

Versiones actuales de jOOQ

jOOQ tiene soporte nativo para JSON y JSONB tipos de datos, por lo que no tiene que hacer nada específico.

Respuesta histórica

Desde jOOQ 3.5, puede registrar sus propios enlaces de tipo de datos personalizados al generador de código como se documenta aquí:

http://www.jooq.org/doc/latest/manual/code-generation/custom-data-type-bindings

A diferencia de un Converter , un Binding dicta cómo se maneja su tipo de datos en el nivel JDBC dentro de jOOQ, sin que jOOQ conozca su implementación. Es decir, no solo definirá cómo convertir entre <T> y <U> tipos (T =tipo de base de datos, U =tipo de usuario), pero también podrá definir cómo son dichos tipos:

  • Representado como SQL
  • Enlazado a declaraciones preparadas
  • Enlazado a SQLOutput
  • Registrado en CallableStatements como parámetros OUT
  • Obtenido de ResultSets
  • Obtenido de SQLInput
  • Obtenido de CallableStatements como parámetros OUT

Un ejemplo de Binding para usar con Jackson para producir JsonNode tipos se da aquí:

public class PostgresJSONJacksonJsonNodeBinding 
implements Binding<Object, JsonNode> {

    @Override
    public Converter<Object, JsonNode> converter() {
        return new PostgresJSONJacksonJsonNodeConverter();
    }

    @Override
    public void sql(BindingSQLContext<JsonNode> ctx) throws SQLException {

        // This ::json cast is explicitly needed by PostgreSQL:
        ctx.render().visit(DSL.val(ctx.convert(converter()).value())).sql("::json");
    }

    @Override
    public void register(BindingRegisterContext<JsonNode> ctx) throws SQLException {
        ctx.statement().registerOutParameter(ctx.index(), Types.VARCHAR);
    }

    @Override
    public void set(BindingSetStatementContext<JsonNode> ctx) throws SQLException {
        ctx.statement().setString(
            ctx.index(), 
            Objects.toString(ctx.convert(converter()).value()));
    }

    @Override
    public void get(BindingGetResultSetContext<JsonNode> ctx) throws SQLException {
        ctx.convert(converter()).value(ctx.resultSet().getString(ctx.index()));
    }

    @Override
    public void get(BindingGetStatementContext<JsonNode> ctx) throws SQLException {
        ctx.convert(converter()).value(ctx.statement().getString(ctx.index()));
    }

    // The below methods aren't needed in PostgreSQL:

    @Override
    public void set(BindingSetSQLOutputContext<JsonNode> ctx) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void get(BindingGetSQLInputContext<JsonNode> ctx) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }
}

Y el Converter que se usa arriba se puede ver aquí:

public class PostgresJSONJacksonJsonNodeConverter 
implements Converter<Object, JsonNode> {
    @Override
    public JsonNode from(Object t) {
        try {
            return t == null 
              ? NullNode.instance 
              : new ObjectMapper().readTree(t + "");
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Object to(JsonNode u) {
        try {
            return u == null || u.equals(NullNode.instance) 
              ? null 
              : new ObjectMapper().writeValueAsString(u);
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Class<Object> fromType() {
        return Object.class;
    }

    @Override
    public Class<JsonNode> toType() {
        return JsonNode.class;
    }
}

Ahora puede registrar el enlace anterior a través de la configuración del generador de código:

<customType>
    <name>com.example.PostgresJSONJacksonJsonNodeBinding</name>
    <type>com.fasterxml.jackson.databind.JsonNode</type>
    <binding>com.example.PostgresJSONJacksonJsonNodeBinding</binding>
</customType>

<forcedType>
    <name>com.example.PostgresJSONJacksonJsonNodeBinding</name>
    <expression>my_schema\.table\.json_field</expression>
</forcedType>