blob: 31a4515e865d8b117657a1dfbb5d72dd36829785 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.uima.ducc.database;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.uima.ducc.common.persistence.IDbProperty;
import org.apache.uima.ducc.common.persistence.IDbProperty.Type;
import com.datastax.driver.core.Row;
/**
* Static common helper methods.
*
* Not public at this point, would prefer to encapsulate all this entirely in DB.
*/
class DbUtil
{
static String mkSchema(IDbProperty[] props)
throws Exception
{
List<String> parts = new ArrayList<String>();
List<String> primaries = new ArrayList<String>();
for (IDbProperty n : props ) {
if ( n.isMeta() ) continue;
String s = n.columnName() + " " + typeToString(n.type());
if ( n.isPrimaryKey() ) {
primaries.add(n.columnName());
}
parts.add(s);
}
if ( primaries.size() == 0 ) {
throw new IllegalArgumentException("Schema properties must declare at least one primary key.");
}
StringBuffer buf = new StringBuffer();
for ( String p : parts ) {
buf.append(p);
buf.append(",");
}
int ncommas = primaries.size() - 1;
int c = 0;
buf.append(" PRIMARY KEY(");
for ( String s : primaries ) {
buf.append(s);
if ( c++ < ncommas ) {
buf.append(",");
}
}
buf.append(")");
return buf.toString();
}
static List<String> dropIndices(IDbProperty[] props, String tablename)
{
List<String> ret = new ArrayList<String>();
for ( IDbProperty p : props ) {
if ( p.isIndex() ) {
StringBuffer buf = new StringBuffer("DROP INDEX IF EXISTS ");
buf.append(tablename);
buf.append("_");
buf.append(p.pname());
buf.append("_idx;");
ret.add(buf.toString());
}
}
return ret;
}
static List<String> mkIndices(IDbProperty[] props, String tablename)
{
List<String> ret = new ArrayList<String>();
for ( IDbProperty p : props ) {
if ( p.isIndex() ) {
StringBuffer buf = new StringBuffer("CREATE INDEX IF NOT EXISTS ");
buf.append(tablename);
buf.append("_");
buf.append(p.pname());
buf.append("_idx ON ");
buf.append(tablename);
buf.append("(");
buf.append(p.pname());
buf.append(")");
ret.add(buf.toString());
}
}
return ret;
}
static String mkFields(StringBuffer buf, String[] fields)
{
int max = fields.length - 1;
int current = 0;
buf.append("(");
for (String s : fields) {
buf.append(s);
if ( current++ < max) buf.append(", ");
}
buf.append(")");
return buf.toString();
}
/**
* Generate a CREATE TABLE statement from the incoming fields. The preparer of the
* fields must qualify any fields in advance e.g. with types, key attributes, etc.
*
* @param tableName This is the name of the table to create.
* @param fields This is a string array of fields to generate the statement from.
*
* @return A string of valid SQL / CQL used to create the table.
*/
static String mkTableCreate(String tableName, String[] fields)
{
int max = fields.length - 1;
int current = 0;
StringBuffer buf = new StringBuffer("CREATE TABLE IF NOT EXISTS ");
buf.append(tableName);
buf.append(" (");
for (String s : fields) {
buf.append(s);
if ( current++ < max) buf.append(", ");
}
buf.append(")");
return buf.toString();
}
static String mkInsert(String tableName, Map<? extends IDbProperty, Object> props)
{
int max = props.size() - 1;
int current = 0;
StringBuffer buf = new StringBuffer("INSERT INTO ");
buf.append(tableName);
buf.append("(");
StringBuffer vals = new StringBuffer(") VALUES (");
for ( IDbProperty ok : props.keySet() ) {
String k = ok.columnName();
buf.append(k);
vals.append(rep(ok, props.get(ok)));
if ( current++ < max ) {
buf.append(",");
vals.append(",");
}
}
buf.append(vals.toString());
buf.append(")");
return buf.toString();
}
static String mkInsert(String tableName, Object key, Object keyval, Map<? extends IDbProperty, Object> props)
{
int max = props.size() + 1;
int current = 0;
StringBuffer buf = new StringBuffer("INSERT INTO ");
buf.append(tableName);
buf.append("(");
StringBuffer vals = new StringBuffer(") VALUES (");
buf.append(key.toString());
buf.append(",");
vals.append(keyval.toString());
vals.append(",");
for ( IDbProperty ok : props.keySet() ) {
String k = ok.columnName();
buf.append(k);
vals.append(rep(ok, props.get(ok)));
if ( current++ < max ) {
buf.append(",");
vals.append(",");
}
}
buf.append(vals.toString());
buf.append(")");
return buf.toString();
}
/**
* Imporant: do not pass key fields in the props or this will barf.
*/
static String mkUpdate(String table, String key, Object... props)
{
int len = props.length;
StringBuffer buf = new StringBuffer("UPDATE ");
buf.append(table);
buf.append(" SET ");
// NOTE: The property set must NOT contain any key fields or this is likely to barf. Caller
// must insure.
for ( int i = 0; i < len; i+=2) {
IDbProperty prop = (IDbProperty) props[i];
if ( prop.isPrimaryKey() ) {
throw new IllegalArgumentException("Primary key not allowed in UPDATE");
}
buf.append(prop.columnName());
buf.append("=");
buf.append(rep(prop, props[i+1]));
if ( i + 2 < len ) {
buf.append(",");
}
}
buf.append(" WHERE ");
buf.append(key);
return buf.toString();
}
/**
* Return the correct representation for CQL update, of val, for the indicated type, for this database.
*/
static String rep(IDbProperty p, Object val)
{
switch ( p.type() ) {
case String:
return "'" + val.toString() + "'";
default:
return val.toString();
}
}
/**
* Common code to pull things from a row according to the schema, into a map
*/
static Map<String, Object> getProperties(IDbProperty[] props, Row r)
{
Map<String, Object> ret = new HashMap<String, Object>();
for ( IDbProperty p : props ) {
if ( p.isPrivate() ) continue;
if ( p.isMeta() ) continue;
Object val = null;
switch ( p.type() ) {
case String:
val = r.getString(p.columnName());
break;
case Integer:
val = r.getInt(p.columnName());
break;
case Long:
val = r.getLong(p.columnName());
break;
case Double:
val = r.getDouble(p.columnName());
break;
case UUID:
val = r.getUUID(p.columnName());
break;
case Boolean:
val = r.getBool(p.columnName());
break;
case Blob:
val = r.getBytes(p.columnName());
break;
}
if ( val != null ) ret.put(p.pname(), val);
}
return ret;
}
/**
* Convert our generic "type" to the right name for this db implementation.
* We could make Type a magic enum but I want to hide DB specifics, in particular,
* how this database names various java types.
*/
static String typeToString(Type t)
{
switch ( t ) {
case Blob:
return "blob";
case String:
return "varchar";
case Boolean:
return "boolean";
case Integer:
return "int";
case Long:
return "bigint";
case Double:
return "double";
case UUID:
return "uuid";
}
throw new IllegalArgumentException("Unrecognized type for schema: " + t);
}
}