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

com.gkutiel.github.flip.graph.Db Maven / Gradle / Ivy

There is a newer version: 10-RELEASE
Show newest version
package com.gkutiel.github.flip.graph;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.h2.Driver;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;

class Db {

	private abstract class Command {
		private final Connection con;

		Command() {
			try {
				con = DriverManager.getConnection(url);
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}

		PreparedStatement ps(final String sql) {
			try {
				return con.prepareStatement(sql);
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private class DelEdge extends Command {
		private final PreparedStatement ps;

		@SuppressWarnings("unused")
		DelEdge() {
			ps = ps("DELETE FROM E WHERE V1 = ? AND V2 = ? AND LABEL = ?");
		}

		void execute(final String v1, final String v2, final String label) {
			try {
				ps.setString(1, v1);
				ps.setString(2, v2);
				ps.setString(3, label);
				ps.executeUpdate();
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private class DelVertex extends Command {
		private final PreparedStatement delV;
		private final PreparedStatement delE;

		@SuppressWarnings("unused")
		DelVertex() {
			delV = ps("DELETE FROM V WHERE ID = ?");
			delE = ps("DELETE FROM E WHERE V1 = ? OR V2 = ?");
		}

		void execute(final String id) {
			try {
				delV.setString(1, id);
				delV.executeUpdate();
				delE.setString(1, id);
				delE.setString(2, id);
				delE.executeUpdate();
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private class GetEdgeProperties extends Command {
		private final PreparedStatement ps;

		@SuppressWarnings("unused")
		GetEdgeProperties() {
			ps = ps("SELECT KEY, VAL FROM E WHERE V1 = ? AND V2 = ? AND LABEL = ?");
		}

		Map execute(final String v1, final String v2, final String label) {
			try {
				ps.setString(1, v1);
				ps.setString(2, v2);
				ps.setString(3, label);
				final ResultSet rs = ps.executeQuery();
				final Map properties = new HashMap<>();
				while (rs.next())
					properties.put(rs.getString(1), rs.getString(2));
				return properties;
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private class GetEdgeProperty extends Command {
		private final PreparedStatement ps;

		@SuppressWarnings("unused")
		GetEdgeProperty() {
			ps = ps("SELECT VAL FROM E WHERE V1 = ? AND V2 = ? AND LABEL = ? AND KEY = ?");
		}

		String execute(final String v1, final String v2, final String label, final String key) {
			try {
				ps.setString(1, v1);
				ps.setString(2, v2);
				ps.setString(3, label);
				ps.setString(4, key);
				final ResultSet rs = ps.executeQuery();
				if (!rs.next()) return null;
				return rs.getString(1);
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}

	}

	private class GetInEdges extends Command {
		private final PreparedStatement ps;

		@SuppressWarnings("unused")
		GetInEdges() {
			ps = ps("SELECT DISTINCT V1 FROM E WHERE V2 = ? AND LABEL = ?");
		}

		List execute(final String v, final String label) {
			try {
				ps.setString(1, v);
				ps.setString(2, label);
				final ResultSet rs = ps.executeQuery();
				final List edges = new ArrayList<>();
				while (rs.next())
					edges.add(new Edge(rs.getString(1), v, label, Db.this));
				return edges;
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private class GetOutEdges extends Command {
		private final PreparedStatement ps;

		@SuppressWarnings("unused")
		GetOutEdges() {
			ps = ps("SELECT DISTINCT V2 FROM E WHERE V1 = ? AND LABEL = ?");
		}

		List execute(final String v, final String label) {
			try {
				ps.setString(1, v);
				ps.setString(2, label);
				final ResultSet rs = ps.executeQuery();
				final List edges = new ArrayList<>();
				while (rs.next())
					edges.add(new Edge(v, rs.getString(1), label, Db.this));
				return edges;
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private class GetVertexProperties extends Command {
		private final PreparedStatement ps;

		@SuppressWarnings("unused")
		GetVertexProperties() {
			ps = ps("SELECT KEY, VAL FROM V WHERE ID = ?");
		}

		Map execute(final String id) {
			try {
				ps.setString(1, id);
				final ResultSet rs = ps.executeQuery();
				final Map properties = new HashMap<>();
				while (rs.next())
					properties.put(rs.getString(1), rs.getString(2));
				return properties;
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private class GetVertexProperty extends Command {
		private final PreparedStatement ps;

		@SuppressWarnings("unused")
		GetVertexProperty() {
			ps = ps("SELECT VAL FROM V WHERE ID = ? AND KEY = ?");
		}

		String execute(final String id, final String key) {
			try {
				ps.setString(1, id);
				ps.setString(2, key);
				final ResultSet rs = ps.executeQuery();
				if (!rs.next()) return null;
				return rs.getString(1);
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private class GetVertices extends Command {
		private final PreparedStatement ps;

		@SuppressWarnings("unused")
		GetVertices() {
			ps = ps("SELECT DISTINCT ID FROM V");
		}

		Iterable execute(final Db db) {
			try {
				final ResultSet rs = ps.executeQuery();
				final List vertices = new ArrayList<>();
				while (rs.next())
					vertices.add(new Vertex(rs.getString(1), db));
				return vertices;
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private class ObjectPool {
		private final ListMultimap, Object> objects = ArrayListMultimap.create();

		@SuppressWarnings("unchecked")
		synchronized  T get(final Class c) {
			try {
				final List list = objects.get(c);
				if (list.isEmpty()) return (T) c.getDeclaredConstructors()[0].newInstance(Db.this);
				return (T) list.remove(list.size() - 1);
			} catch (final Exception e) {
				throw new RuntimeException(e);
			}
		}
		synchronized void put(final Object o) {
			objects.put(o.getClass(), o);
		}
	}

	private class SetEdgeProperty extends Command {
		private final PreparedStatement ps;

		@SuppressWarnings("unused")
		SetEdgeProperty() {
			ps = ps("MERGE INTO E VALUES(?,?,?,?,?)");
		}

		void execute(final String v1, final String v2, final String label, final String key, final String val) {
			try {
				ps.setString(1, v1);
				ps.setString(2, v2);
				ps.setString(3, label);
				ps.setString(4, key);
				ps.setString(5, val);
				ps.executeUpdate();
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private class SetVertexProperty extends Command {
		private final PreparedStatement ps;

		@SuppressWarnings("unused")
		SetVertexProperty() {
			ps = ps("MERGE INTO V VALUES(?,?,?)");
		}

		void execute(final String id, final String key, final String val) {
			try {
				ps.setString(1, id);
				ps.setString(2, key);
				ps.setString(3, val);
				ps.executeUpdate();
			} catch (final SQLException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private final ObjectPool objectPool = new ObjectPool();

	private final String url;

	Db(final String folder) {
		new Driver();
		url = "jdbc:h2:" + folder;
		try (Connection con = DriverManager.getConnection(url)) {
			con.createStatement().execute("CREATE TABLE IF NOT EXISTS V (ID VARCHAR, KEY VARCHAR, VAL VARCHAR, PRIMARY KEY (ID, KEY))");
			con.createStatement().execute(
					"CREATE TABLE IF NOT EXISTS E (V1 VARCHAR, V2 VARCHAR, LABEL VARCHAR, KEY VARCHAR, VAL VARCHAR, PRIMARY KEY (V1, V2, LABEL, KEY))");
			con.createStatement().execute("CREATE INDEX IF NOT EXISTS i1 ON V(ID)");
			con.createStatement().execute("CREATE INDEX IF NOT EXISTS i2 ON E(V1)");
			con.createStatement().execute("CREATE INDEX IF NOT EXISTS i3 ON E(V2)");
		} catch (final SQLException e) {
			throw new RuntimeException(e);
		}
	}

	void addEdge(final String v1, final String v2, final String label) {
		setEdgeProperty(v1, v2, label, "", "");
	}

	void addVertex(final String id) {
		setVertexProperty(id, "", "");
	}

	void delEdge(final String v1, final String v2, final String label) {
		final DelEdge delEdge = objectPool.get(DelEdge.class);
		try {
			delEdge.execute(v1, v2, label);
		} finally {
			objectPool.put(delEdge);
		}
	}

	void delVertex(final String id) {
		final DelVertex delVertex = objectPool.get(DelVertex.class);
		try {
			delVertex.execute(id);
		} finally {
			objectPool.put(delVertex);
		}
	}

	Map getEdgeProperties(final String v1, final String v2, final String label) {
		final GetEdgeProperties edgeProperties = objectPool.get(GetEdgeProperties.class);
		try {
			return edgeProperties.execute(v1, v2, label);
		} finally {
			objectPool.put(edgeProperties);
		}
	}
	String getEdgeProperty(final String v1, final String v2, final String label, final String key) {
		final GetEdgeProperty getEdgeProperty = objectPool.get(GetEdgeProperty.class);
		try {
			return getEdgeProperty.execute(v1, v2, label, key);
		} finally {
			objectPool.put(getEdgeProperty);
		}
	}

	List getInEdges(final String v, final String label) {
		final GetInEdges getInEdges = objectPool.get(GetInEdges.class);
		try {
			return getInEdges.execute(v, label);
		} finally {
			objectPool.put(getInEdges);
		}
	}

	List getOutEdges(final String v, final String label) {
		final GetOutEdges getOutEdges = objectPool.get(GetOutEdges.class);
		try {
			return getOutEdges.execute(v, label);
		} finally {
			objectPool.put(getOutEdges);
		}
	}

	Map getVertexProperties(final String id) {
		final GetVertexProperties getVertexProperties = objectPool.get(GetVertexProperties.class);
		try {
			return getVertexProperties.execute(id);
		} finally {
			objectPool.put(getVertexProperties);
		}
	}

	String getVertexProperty(final String id, final String key) {
		final GetVertexProperty getVertexProperty = objectPool.get(GetVertexProperty.class);
		try {
			return getVertexProperty.execute(id, key);
		} finally {
			objectPool.put(getVertexProperty);
		}
	}

	Iterable getVertices() {
		final GetVertices getVertices = objectPool.get(GetVertices.class);
		try {
			return getVertices.execute(Db.this);
		} finally {
			objectPool.put(getVertices);
		}
	}

	void setEdgeProperty(final String v1, final String v2, final String label, final String key, final String val) {
		final SetEdgeProperty setEdgeProperty = objectPool.get(SetEdgeProperty.class);
		try {
			setEdgeProperty.execute(v1, v2, label, key, val);
		} finally {
			objectPool.put(setEdgeProperty);
		}
	}

	void setVertexProperty(final String id, final String key, final String val) {
		final SetVertexProperty setVertexProperty = objectPool.get(SetVertexProperty.class);
		try {
			setVertexProperty.execute(id, key, val);
		} finally {
			objectPool.put(setVertexProperty);
		}
	}
}