All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fluentjdbc.DatabaseSaveBuilder Maven / Gradle / Ivy

There is a newer version: 0.5.3
Show newest version
package org.fluentjdbc;

import org.fluentjdbc.DatabaseTable.RowMapper;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;

@ParametersAreNonnullByDefault
public abstract class DatabaseSaveBuilder extends DatabaseStatement {

    protected List uniqueKeyFields = new ArrayList<>();
    protected List uniqueKeyValues = new ArrayList<>();

    protected List fields = new ArrayList<>();
    protected List values = new ArrayList<>();

    protected final DatabaseTable table;
    protected String idField;

    @Nullable protected T idValue;

    DatabaseSaveBuilder(DatabaseTable table, String idField, @Nullable T id) {
        this.table = table;
        this.idField = idField;
        this.idValue = id;
    }

    public DatabaseSaveBuilder uniqueKey(String fieldName, @Nullable Object fieldValue) {
        uniqueKeyFields.add(fieldName);
        uniqueKeyValues.add(fieldValue);
        return this;
    }

    public DatabaseSaveBuilder setField(String fieldName, @Nullable Object fieldValue) {
        fields.add(fieldName);
        values.add(fieldValue);
        return this;
    }

    @Nullable
    public T execute(Connection connection) {
        T idValue = this.idValue;
        if (idValue != null) {
            Boolean isSame = table.where(idField, this.idValue).singleObject(connection, new RowMapper() {
                @Override
                public Boolean mapRow(DatabaseRow row) throws SQLException {
                    return shouldSkipRow(row);
                }
            });
            if (isSame != null && !isSame) {
                update(connection, idValue);
            } else if (isSame == null) {
                insert(connection);
            }
            return idValue;
        } else if (hasUniqueKey()) {
            Boolean isSame = table.whereAll(uniqueKeyFields, uniqueKeyValues).singleObject(connection, new RowMapper() {
                @Override
                public Boolean mapRow(DatabaseRow row) throws SQLException {
                    DatabaseSaveBuilder.this.idValue = getId(row);
                    return shouldSkipRow(row);
                }
            });
            idValue = this.idValue;
            if (idValue == null) {
                idValue = insert(connection);
            } else if (isSame != null && !isSame) {
                update(connection, idValue);
            }
            return idValue;
        } else {
            return insert(connection);
        }
    }

    private boolean shouldSkipRow(DatabaseRow row) throws SQLException {
        for (int i = 0; i < fields.size(); i++) {
            String field = fields.get(i);
            if (!equal(values.get(i), row.getObject(field))) return false;
        }
        return true;
    }

    private boolean equal(Object o, Object db) {
        return Objects.equals(o, db);
    }

    private boolean hasUniqueKey() {
        if (uniqueKeyFields.isEmpty()) return false;
        for (Object o : uniqueKeyValues) {
            if (o == null) return false;
        }
        return true;
    }

    @Nullable
    protected abstract T insert(Connection connection);

    private T update(Connection connection, T idValue) {
        table.where("id", idValue)
                .update()
                .setFields(this.fields, this.values)
                .setFields(uniqueKeyFields, uniqueKeyValues)
                .execute(connection);
        return idValue;
    }

    @SuppressWarnings("unchecked")
    protected T getId(DatabaseRow row) throws SQLException {
        return (T) row.getObject(idField);
    }

}