blob: 4202749bbab22af050a498ce8e18dd2b3b1fbeca [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 groovy.sql;
import groovy.lang.GroovyObjectSupport;
import groovy.lang.MissingPropertyException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* Represents an extent of objects.
* It's primarily used by methods of Groovy's {@link groovy.sql.Sql} class to return {@code ResultSet} data in map
* form; allowing access to the result of a SQL query by the name of the column, or by the column number.
*/
public class GroovyRowResult extends GroovyObjectSupport implements Map {
private final Map result;
public GroovyRowResult(Map result) {
this.result = result;
}
/**
* Retrieve the value of the property by its (case-insensitive) name.
*
* @param property is the name of the property to look at
* @return the value of the property
*/
public Object getProperty(String property) {
try {
Object key = lookupKeyIgnoringCase(property);
if (key != null) {
return result.get(key);
}
throw new MissingPropertyException(property, GroovyRowResult.class);
}
catch (Exception e) {
throw new MissingPropertyException(property, GroovyRowResult.class, e);
}
}
private Object lookupKeyIgnoringCase(Object key) {
// try some special cases first for efficiency
if (result.containsKey(key))
return key;
if (!(key instanceof CharSequence))
return null;
String keyStr = key.toString();
for (Object next : result.keySet()) {
if (!(next instanceof String))
continue;
if (keyStr.equalsIgnoreCase((String)next))
return next;
}
return null;
}
/**
* Retrieve the value of the property by its index.
* A negative index will count backwards from the last column.
*
* @param index is the number of the column to look at
* @return the value of the property
*/
public Object getAt(int index) {
try {
// a negative index will count backwards from the last column.
if (index < 0)
index += result.size();
Iterator it = result.values().iterator();
int i = 0;
Object obj = null;
while ((obj == null) && (it.hasNext())) {
if (i == index)
obj = it.next();
else
it.next();
i++;
}
return obj;
}
catch (Exception e) {
throw new MissingPropertyException(Integer.toString(index), GroovyRowResult.class, e);
}
}
public String toString() {
return result.toString();
}
/*
* The following methods are needed for implementing the Map interface.
* They are mostly delegating the request to the provided Map.
*/
public void clear() {
result.clear();
}
/**
* Checks if the result contains (ignoring case) the given key.
*
* @param key the property name to look for
* @return true if the result contains this property name
*/
public boolean containsKey(Object key) {
return lookupKeyIgnoringCase(key) != null;
}
public boolean containsValue(Object value) {
return result.containsValue(value);
}
public Set<Map.Entry> entrySet() {
return result.entrySet();
}
public boolean equals(Object o) {
return result.equals(o);
}
/**
* Find the property value for the given name (ignoring case).
*
* @param property the name of the property to get
* @return the property value
*/
public Object get(Object property) {
if (property instanceof String)
return getProperty((String)property);
return null;
}
public int hashCode() {
return result.hashCode();
}
public boolean isEmpty() {
return result.isEmpty();
}
public Set keySet() {
return result.keySet();
}
/**
* Associates the specified value with the specified property name in this result.
*
* @param key the property name for the result
* @param value the property value for the result
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
@SuppressWarnings("unchecked")
public Object put(Object key, Object value) {
// avoid different case keys being added by explicit remove
Object orig = remove(key);
result.put(key, value);
return orig;
}
/**
* Copies all of the mappings from the specified map to this result.
* If the map contains different case versions of the same (case-insensitive) key
* only the last (according to the natural ordering of the supplied map) will remain
* after the {@code putAll} method has returned.
*
* @param t the mappings to store in this result
*/
@SuppressWarnings("unchecked")
public void putAll(Map t) {
// don't delegate to putAll since we want case handling from put
for (Entry next : (Set<Entry>) t.entrySet()) {
put(next.getKey(), next.getValue());
}
}
public Object remove(Object rawKey) {
return result.remove(lookupKeyIgnoringCase(rawKey));
}
public int size() {
return result.size();
}
public Collection values() {
return result.values();
}
}