PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Wie füge ich mit JOOQ einen aktualisierbaren Datensatz mit JSON-Spalte in PostgreSQL ein?

Aktuelle jOOQ-Versionen

jOOQ bietet native Unterstützung für JSON und JSONB Datentypen, sodass Sie nichts Besonderes tun müssen.

Historische Antwort

Seit jOOQ 3.5 können Sie Ihre eigenen benutzerdefinierten Datentypbindungen beim Codegenerator registrieren, wie hier dokumentiert:

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

Im Gegensatz zu einem Converter , eine Binding bestimmt, wie Ihr Datentyp auf JDBC-Ebene innerhalb von jOOQ behandelt wird, ohne dass jOOQ etwas über Ihre Implementierung weiß. Das heißt, Sie definieren nicht nur, wie zwischen <T> konvertiert werden soll und <U> Typen (T =Datenbanktyp, U =Benutzertyp), aber Sie können auch definieren, wie solche Typen sind:

  • Als SQL gerendert
  • An PreparedStatements gebunden
  • An SQLOutput gebunden
  • In CallableStatements als OUT-Parameter registriert
  • Aus ResultSets abgerufen
  • Von SQLInput abgerufen
  • Von CallableStatements als OUT-Parameter abgerufen

Ein Beispiel für Binding zur Verwendung mit Jackson zur Erzeugung von JsonNode Typen ist hier angegeben:

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();
    }
}

Und der Converter die oben verwendet wird, kann hier eingesehen werden:

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;
    }
}

Sie können nun die obige Bindung über die Codegenerator-Konfiguration registrieren:

<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>