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

com.ptsmods.mysqlw.collection.DbList Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
package com.ptsmods.mysqlw.collection;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.ptsmods.mysqlw.Database;
import com.ptsmods.mysqlw.query.QueryCondition;
import com.ptsmods.mysqlw.query.QueryConditions;
import com.ptsmods.mysqlw.query.QueryOrder;
import com.ptsmods.mysqlw.query.SelectResults;
import com.ptsmods.mysqlw.table.ColumnType;
import com.ptsmods.mysqlw.table.TablePreset;

import javax.annotation.Nonnull;
import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

public class DbList extends AbstractList implements DbCollection {

    private static final TablePreset preset = TablePreset.create("list_")
            .putColumn("id", ColumnType.INT.createStructure()
                    .satiateSupplier(sup -> sup.apply(null))
                    .setAutoIncrement(true)
                    .setNullAllowed(false)
                    .setPrimary(true))
            .putColumn("val", ColumnType.TEXT.createStructure());
    private static final Map> cache = new HashMap<>();
    private final Database db;
    private final String table;
    private final String name;
    private final BiFunction elementToString;
    private final BiFunction elementFromString;

    /**
     * Parses a String representation of a DbList into a DbList.
     * @param db The database this list belongs to. Used when creating a new map.
     * @param s The String to parse.
     * @param elementToString The function used to convert an element of this list into a String. Used when creating a new list.
     * @param elementFromString The function used to convert an element of this list into a String. Used when creating a new list.
     * @param  The type of the elements in this set.
     * @return A new DbList or a cached one if available.
     */
    public static  DbList parseString(Database db, String s, BiFunction elementToString, BiFunction elementFromString) {
        return s.startsWith("DbList[name=") ? getList(db, Database.readQuotedString(s.substring("DbList[name=".length())), elementToString, elementFromString) : null;
    }

    /**
     * Parses a String representation of a DbList into a DbList.
     * @param db The database this list belongs to. Used when creating a new map.
     * @param name The name of this list.
     * @param type The Class of type E if you've registered a type converter on {@link DbCF}. Used when creating a new list.
     * @param  The type of the elements in this set.
     * @return A new DbList or a cached one if available.
     */
    public static  DbList getList(Database db, String name, Class type) {
        return getList(db, name, DbCF.getTo(type), DbCF.getFrom(type));
    }

    /**
     * Parses a String representation of a DbList into a DbList.
     * @param db The database this list belongs to. Used when creating a new map.
     * @param name The name of this list.
     * @param elementToString The function used to convert an element of this list into a String. Used when creating a new list.
     * @param elementFromString The function used to convert an element of this list into a String. Used when creating a new list.
     * @param  The type of the elements in this set.
     * @return A new DbList or a cached one if available.
     */
    public static  DbList getList(Database db, String name, BiFunction elementToString, BiFunction elementFromString) {
        if (cache.containsKey(name))
            try {
                return (DbList) cache.get(name);
            } catch (ClassCastException e) {
                throw new IllegalArgumentException("Wrong type! Cached DbList with the given name has a different type than requested.", e);
            }
        else return new DbList<>(db, name, elementToString, elementFromString);
    }

    private DbList(Database db, String name, BiFunction elementToString, BiFunction elementFromString) {
        if (cache.containsKey(name)) throw new IllegalArgumentException("A DbList by this name already exists.");
        Preconditions.checkNotNull(db, "database");
        Preconditions.checkNotNull(elementToString, "elementToString");
        Preconditions.checkNotNull(elementFromString, "elementFromString");
        this.db = db;
        this.table = "list_" + name;
        this.name = name;
        preset.setName(table);
        if (db.getType() == Database.RDBMS.SQLite) preset.getColumns().get("id").setTypeString(db.getType() == Database.RDBMS.SQLite ? "INTEGER" : "INT");
        preset.create(db);
        this.elementToString = elementToString;
        this.elementFromString = elementFromString;
        cache.put(name, this);
    }

    @Override
    public int size() {
        return db.count(table, "val", null);
    }

    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

    @Override
    public boolean contains(Object o) {
        return db.select(table, "val", QueryCondition.equals("val", elementToString.apply((E) o, this)), null, null).size() > 0;
    }

    @Nonnull
    @Override
    public Iterator iterator() {
        return toArrayList().iterator();
    }

    @Nonnull
    @Override
    public Object[] toArray() {
        return toArrayList().toArray();
    }

    @Nonnull
    @Override
    public  T[] toArray(@Nonnull T[] a) {
        return toArrayList().toArray(a);
    }

    @Override
    public boolean add(E e) {
        return db.insert(table, "val", elementToString.apply(e, this)) == 1;
    }

    @Override
    public boolean remove(Object o) {
        boolean b = db.delete(table, QueryCondition.equals("val", elementToString.apply((E) o, this))) > 0;
        fixIndexes();
        return b;
    }

    @Override
    public boolean containsAll(@Nonnull Collection c) {
        QueryConditions condition = QueryConditions.create();
        for (Object element : c)
            condition.or(QueryCondition.equals("val", elementToString.apply((E) element, this)));
        return db.select(table, new String[] {"val"}, condition, QueryOrder.by("id"), null).size() == c.size();
    }

    @Override
    public boolean addAll(@Nonnull Collection c) {
        List values = new ArrayList<>();
        for (E element : c)
            values.add(new Object[] {elementToString.apply(element, this)});
        return db.insert(table, new String[] {"val"}, values) > 0;
    }

    @Override
    public boolean addAll(int index, @Nonnull Collection c) {
        List list = toArrayList();
        boolean b = list.addAll(index, c);
        if (b) {
            clear();
            addAll(list);
        }
        return b;
    }

    @Override
    public boolean removeAll(@Nonnull Collection c) {
        QueryConditions condition = QueryConditions.create();
        for (Object o : c)
            condition.or(QueryCondition.equals("val", elementToString.apply((E) o, this)));
        int i = db.delete(table, condition);
        fixIndexes();
        return i > 0;
    }

    @Override
    public boolean retainAll(@Nonnull Collection c) {
        List list = toArrayList();
        boolean b = list.retainAll(c);
        clear();
        addAll(list);
        return b;
    }

    @Override
    public void clear() {
        db.truncate(table);
        if (db.getType() == Database.RDBMS.SQLite) db.delete("sqlite_sequence", QueryCondition.equals("name", table));
    }

    @Override
    public E get(int index) {
        SelectResults data = db.select(table, "val", QueryCondition.equals("id", index+1), QueryOrder.by("id"), null);
        if (data.isEmpty()) throw exception(index, size());
        else return elementFromString.apply(String.valueOf(data.get(0).get("val")), this);
    }

    @Override
    public E set(int index, E element) {
        checkIndex(index, size());
        E val = get(index);
        db.insertUpdate(table, new String[] {"id", "val"}, new Object[] {index+1, elementToString.apply(element, this)}, ImmutableMap.builder().put("val", elementToString.apply(element, this)).build(), "id");
        return val;
    }

    @Override
    public void add(int index, E element) {
        List list = toArrayList();
        list.add(index, element);
        clear();
        addAll(list);
    }

    @Override
    public E remove(int index) {
        checkIndex(index, size());
        E element = get(index);
        db.delete(table, QueryCondition.equals("id", index+1));
        fixIndexes();
        return element;
    }

    @Override
    public int indexOf(Object o) {
        SelectResults data = db.select(table, "id", QueryCondition.equals("val", elementToString.apply((E) o, this)), QueryOrder.by("id"), null);
        return data.isEmpty() ? -1 : (Integer) data.get(0).get("id") - 1;
    }

    @Override
    public int lastIndexOf(Object o) {
        SelectResults data = db.select(table, "id", QueryCondition.equals("val", elementToString.apply((E) o, this)), QueryOrder.by("id"), null);
        return data.isEmpty() ? -1 : (Integer) data.get(data.size()-1).get("id") - 1;
    }

    @Nonnull
    @Override
    public ListIterator listIterator() {
        return toArrayList().listIterator();
    }

    @Nonnull
    @Override
    public ListIterator listIterator(int index) {
        return toArrayList().listIterator(index);
    }

    @Nonnull
    @Override
    public List subList(int fromIndex, int toIndex) {
        int size = size();
        checkIndex(fromIndex, size);
        checkIndex(toIndex, size);
        List list = new ArrayList<>();
        for (int i = 0; i < toIndex; i++)
            list.add(get(i));
        return list;
    }

    @Override
    public String toString() {
        return "DbList[name='" + getName() + "',values=" + super.toString() + "]";
    }

    public Database getDb() {
        return db;
    }

    @Override
    public String getTable() {
        return table;
    }

    public String getName() {
        return name;
    }

    public List toArrayList() {
        return db.select(table, "val", null, QueryOrder.by("id"), null).stream().map(map -> elementFromString.apply(String.valueOf(map.get("val")), this)).collect(Collectors.toList());
    }

    private void fixIndexes() {
        List elements = toArrayList();
        clear();
        addAll(elements);
    }

    private static void checkIndex(int index, int size) {
        if (index >= size) throw exception(index, size);
    }

    private static IndexOutOfBoundsException exception(int index, int size) {
        return new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy