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

org.rapidoid.jdbc.JdbcUtil Maven / Gradle / Ivy

The newest version!
/*-
 * #%L
 * rapidoid-sql
 * %%
 * Copyright (C) 2014 - 2018 Nikolche Mihajlovski and contributors
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

package org.rapidoid.jdbc;

import org.rapidoid.RapidoidThing;
import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.beany.Beany;
import org.rapidoid.beany.Prop;
import org.rapidoid.commons.StringRewriter;
import org.rapidoid.lambda.Mapper;
import org.rapidoid.u.U;
import org.rapidoid.util.Msc;
import org.rapidoid.util.TUUID;
import org.rapidoid.util.WebData;

import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.UUID;


@Authors("Nikolche Mihajlovski")
@Since("5.3.0")
public class JdbcUtil extends RapidoidThing {

	private static final StringRewriter NAMED_PARAMS_REWRITER = new StringRewriter(StringRewriter.ALL_QUOTES, "\\$(\\w+)\\b");

	public static PreparedStatement prepare(Connection conn, String sql, final Map namedArgs, Object[] args) {
		try {

			if (namedArgs != null) {
				U.must(args == null);

				List arguments = U.list();
				sql = substituteNamedParams(sql, namedArgs, arguments);
				args = arguments.toArray();
			}

			PreparedStatement stmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
			bind(stmt, args);

			return stmt;

		} catch (SQLException e) {
			throw new RuntimeException("Cannot create prepared statement!", e);
		}
	}

	private static String substituteNamedParams(String sql, final Map namedArgs, final List arguments) {
		return NAMED_PARAMS_REWRITER.rewrite(sql, new Mapper() {
			@Override
			public String map(String[] groups) throws Exception {
				String name = groups[1];

				if (namedArgs.containsKey(name)) {
					Object value = namedArgs.get(name);
					arguments.add(value);
					return "?";

				} else {
					return groups[0]; // not in the args -> leave it untouched
				}
			}
		});
	}

	public static void bind(PreparedStatement stmt, Object[] args) throws SQLException {
		for (int i = 0; i < args.length; i++) {
			Object arg = args[i];

			if (arg instanceof WebData) {
				// unwrap the arg to a real value represented by the web data
				arg = ((WebData) arg).unwrap();
			}

			if (arg instanceof byte[]) {
				byte[] bytes = (byte[]) arg;
				stmt.setBytes(i + 1, bytes);

			} else if (arg instanceof UUID) {
				UUID uuid = (UUID) arg;
				byte[] bytes = Msc.uuidToBytes(uuid);
				stmt.setBytes(i + 1, bytes);

			} else if (arg instanceof TUUID) {
				TUUID tuuid = (TUUID) arg;
				stmt.setBytes(i + 1, tuuid.toBytes());

			} else {
				stmt.setObject(i + 1, arg);
			}
		}
	}

	public static  List rows(Mapper resultMapper, ResultSet rs) throws Exception {
		List rows = U.list();

		while (rs.next()) {
			rows.add(resultMapper.map(rs));
		}

		return rows;
	}

	public static  List rows(Class resultType, ResultSet rs) throws Exception {
		List rows = U.list();

		ResultSetMetaData meta = rs.getMetaData();
		int columnsN = meta.getColumnCount();
		Prop[] props = new Prop[columnsN];

		for (int i = 0; i < props.length; i++) {
			String name = meta.getColumnLabel(i + 1);
			props[i] = Beany.property(resultType, name, false);
		}

		while (rs.next()) {
			T row = resultType.newInstance();

			for (int i = 0; i < columnsN; i++) {
				if (props[i] != null) {
					Object value = rs.getObject(i + 1); // 1-indexed
					props[i].set(row, value);
				}
			}

			rows.add(row);
		}

		return rows;
	}

	private static Object convertResultValue(String type, Object value) {
		byte[] bytes;

		switch (type) {

			case "TUUID":
				U.must(value instanceof byte[], "Expecting byte[] value to convert to TUUID!");
				bytes = (byte[]) value;
				return TUUID.fromBytes(bytes);

			case "UUID":
				U.must(value instanceof byte[], "Expecting byte[] value to convert to UUID!");
				bytes = (byte[]) value;
				return Msc.bytesToUUID(bytes);

			default:
				throw U.rte("Unknown type: '%s'", type);
		}
	}

	public static List> rows(ResultSet rs) throws SQLException {
		List> rows = U.list();

		while (rs.next()) {
			rows.add(row(rs));
		}

		return rows;
	}

	public static Map row(ResultSet rs) throws SQLException {
		Map row = U.map();

		ResultSetMetaData meta = rs.getMetaData();
		int columnsNumber = meta.getColumnCount();

		for (int i = 1; i <= columnsNumber; i++) {

			String name = meta.getColumnLabel(i);
			Object value = rs.getObject(i);

			String[] nameParts = name.split("__");

			if (nameParts.length == 2) {
				name = nameParts[0];
				value = convertResultValue(nameParts[1], value);
			}

			row.put(name, value);
		}

		return row;
	}

}