/** * * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * **/ package lucee.runtime.functions.query; import java.util.Iterator; import java.util.Map.Entry; import lucee.commons.lang.StringUtil; import lucee.runtime.PageContext; import lucee.runtime.exp.FunctionException; import lucee.runtime.exp.PageException; import lucee.runtime.ext.function.BIF; import lucee.runtime.op.Caster; import lucee.runtime.op.Decision; import lucee.runtime.type.Array; import lucee.runtime.type.ArrayImpl; import lucee.runtime.type.Collection.Key; import lucee.runtime.type.Query; import lucee.runtime.type.QueryImpl; import lucee.runtime.type.Struct; import lucee.runtime.type.util.ListUtil; import lucee.runtime.type.util.QueryUtil; /** * Implements the CFML Function querynew */ public final class QueryNew extends BIF { private static final long serialVersionUID = -4313766961671090938L; /** @deprecated used by old lucee archives */ @Deprecated public static lucee.runtime.type.Query call(PageContext pc , String columnNames) throws PageException { return call(pc, (Object)columnNames); } /** @deprecated used by old lucee archives */ @Deprecated public static lucee.runtime.type.Query call(PageContext pc , String columnNames, String columnTypes) throws PageException { return call(pc, (Object)columnNames, (Object)columnTypes); } /** @deprecated used by old lucee archives */ @Deprecated public static lucee.runtime.type.Query call(PageContext pc , String columnNames, String columnTypes, Object data) throws PageException { return call(pc, (Object)columnNames, (Object)columnTypes,data); } public static lucee.runtime.type.Query call(PageContext pc , Object columnNames) throws PageException { return new QueryImpl(toArray(pc,columnNames,1),0,"query"); } public static lucee.runtime.type.Query call(PageContext pc , Object columnNames, Object columnTypes) throws PageException { if(StringUtil.isEmpty(columnTypes)) return call(pc, columnNames); return new QueryImpl(toArray(pc,columnNames,1),toArray(pc,columnTypes,2),0,"query"); } public static lucee.runtime.type.Query call(PageContext pc , Object columnNames, Object columnTypes, Object data) throws PageException { Array cn = toArray(pc, columnNames, 1); lucee.runtime.type.Query qry; if(StringUtil.isEmpty(columnTypes)) qry= new QueryImpl(cn,0,"query"); else qry= new QueryImpl(cn,toArray(pc, columnTypes, 2),0,"query"); if(data==null) return qry; return populate(pc, qry, data); } @Override public Object invoke(PageContext pc, Object[] args) throws PageException { if(args.length==1)return call(pc,Caster.toString(args[0])); if(args.length==2)return call(pc,Caster.toString(args[0]),Caster.toString(args[1])); return call(pc,Caster.toString(args[0]),Caster.toString(args[1]),args[2]); } public static Query populate(PageContext pc, Query qry,Object data) throws PageException { if(Decision.isArray(data)) return _populate(pc,qry,Caster.toArray(data)); else if(Decision.isStruct(data)) return _populate(pc,qry,Caster.toStruct(data)); else throw new FunctionException(pc, "QueryNew", 3, "data", "the date must be defined as array of structs , array of arrays or struct of arrays"); } private static Query _populate(PageContext pc, Query qry,Struct data) throws PageException { Iterator<Entry<Key, Object>> it = data.entryIterator(); Entry<Key, Object> e; Object v; Array arr; int rows = qry.getRecordcount(); while(it.hasNext()){ e = it.next(); if(qry.getColumn(e.getKey(),null)!=null) { v=e.getValue(); arr = Caster.toArray(v,null); if(arr==null) arr=new ArrayImpl(new Object[]{v}); populateColumn(qry,e.getKey(),arr,rows); } } return qry; } private static void populateColumn(Query qry, Key column, Array data,int rows) throws PageException { Iterator<?> it = data.valueIterator(); int row=rows; while(it.hasNext()){ row++; if(row>qry.getRecordcount()) qry.addRow(); qry.setAt(column, row, it.next()); } } private static Query _populate(PageContext pc, Query qry,Array data) throws PageException { // check if the array only contains simple values or mixed Iterator<?> it = data.valueIterator(); Object o; boolean hasSimpleValues=false; while(it.hasNext()){ o=it.next(); if(!Decision.isStruct(o) && !Decision.isArray(o)) hasSimpleValues=true; } if(hasSimpleValues) { qry.addRow(); populateRow(qry, data); } else { it = data.valueIterator(); while(it.hasNext()){ o=it.next(); qry.addRow(); if(Decision.isStruct(o))populateRow(qry,Caster.toStruct(o)); else if(Decision.isArray(o))populateRow(qry,Caster.toArray(o)); else { populateRow(qry,new ArrayImpl(new Object[]{o})); } } } return qry; } private static void populateRow(Query qry, Struct data) throws PageException { Key[] columns = QueryUtil.getColumnNames(qry); int row=qry.getRecordcount(); Object value; for(int i=0;i<columns.length;i++){ value=data.get(columns[i],null); if(value!=null) qry.setAt(columns[i], row, value); } } private static void populateRow(Query qry, Array data) throws PageException { Iterator<?> it = data.valueIterator(); Key[] columns = QueryUtil.getColumnNames(qry); int row=qry.getRecordcount(); int index=-1; while(it.hasNext()){ index++; if(index>=columns.length) break; qry.setAt(columns[index], row, it.next()); } } private static Array toArray(PageContext pc,Object columnNames, int index) throws PageException { if(Decision.isArray(columnNames)) return Caster.toArray(columnNames); String str=Caster.toString(columnNames,null); if(str==null) throw new FunctionException(pc, "QueryNew", index, index==1?"columnNames":"columnTypes", "cannot cast to a array or a string list"); return ListUtil.listToArrayTrim(str,","); } }