package divconq.db.proc; import java.util.HashMap; import java.util.function.Consumer; import divconq.db.DatabaseInterface; import divconq.db.DatabaseTask; import divconq.db.ICollector; import divconq.db.TablesAdapter; import divconq.hub.Hub; import divconq.lang.BigDateTime; import divconq.lang.op.OperationResult; import divconq.schema.DbCollector; import divconq.struct.ListStruct; import divconq.struct.RecordStruct; import divconq.struct.Struct; import divconq.struct.builder.ICompositeBuilder; import divconq.util.StringUtil; public class SelectDirect extends LoadRecord { /* ; Table name ; When "" = now ; [stamp] = on or before this time ; ; Where ; "Name" expression name: "And", "Or", "Equal", etc. -or- field name -or- "Filter" ; "A" value to compare against, or param to Filter ; "Field" if from database ; "Format" ; "Value" if literal ; "Composer" composer script to generate content ; "B" value to compare against, or param to Filter ; "C" value to compare against, or param to Filter ; "Children" ; 0,"Name" ; 1... ; ; Select list of fields to query ; 0, ; "Field" name ; "Format" format of field if scalar ; "Name" display name of field ; "ForeignField" value field in fk relationship ; "Table" for reverse foreign ; "Composer" composer script to generate content ; "Select" list of fields to query, see above ; 0, ; 1... ; 1... ; ; Collector ; "Name" code to execute to get collection ; "Values" ; 0 value to match ; 1... ; "From" value to start at, inclusive ; "To" value to end at, exclusive ; "Field" if not using Code to get collection, use a Field instead ; ; Historical true / false - ignore the To field in Record and in Field - meaning we can see back in time, but not in future, From is still obeyed ; ; Result ; List of records, content based on Select */ @Override public void execute(DatabaseInterface conn, DatabaseTask task, OperationResult log) { RecordStruct params = task.getParamsAsRecord(); String table = params.getFieldAsString("Table"); BigDateTime when = params.getFieldAsBigDateTime("When"); boolean compact = params.hasField("Compact") ? params.getFieldAsBooleanOrFalse("Compact") : true; boolean historical = params.getFieldAsBooleanOrFalse("Historical"); ListStruct select = params.getFieldAsList("Select"); RecordStruct where = params.getFieldAsRecord("Where"); if (when == null) when = BigDateTime.nowDateTime(); BigDateTime fwhen = when; // TODO add db filter option //d runFilter("Query") quit:Errors ; if any violations in filter then do not proceed TablesAdapter db = new TablesAdapter(conn, task); ICompositeBuilder out = task.getBuilder(); RecordStruct collector = params.getFieldAsRecord("Collector"); if (collector != null) { try { out.startList(); // TODO make sure we produce only unique records // enhance by making this use ^dcTemp for large number of records HashMap<String, Boolean> unique = new HashMap<>(); String func = collector.getFieldAsString("Func"); String fname = collector.getFieldAsString("Field"); String subid = collector.getFieldAsString("SubId"); ListStruct values = collector.getFieldAsList("Values"); Consumer<Object> uniqueConsumer = new Consumer<Object>() { @Override public void accept(Object t) { try { String id = t.toString(); // we have already returned this one if (unique.containsKey(id)) return; if (db.checkSelect(table, id, fwhen, where, historical)) { unique.put(id, true); SelectDirect.this.writeRecord(conn, task, log, out, db, table, id, fwhen, select, compact, false, historical); } } catch (Exception x) { log.error("Issue with select direct: " + x); } } }; if (StringUtil.isNotEmpty(func)) { DbCollector proc = Hub.instance.getSchema().getDbCollector(func); if (proc != null) { ICollector sp = proc.getCollector(); if (sp != null) { sp.collect(conn, task, log, collector, uniqueConsumer); } else { log.error("Stored func not found or bad: " + func); } } else { log.error("Stored func not found or bad: " + func); } } else if (values != null) { for (Struct s : values.getItems()) { if ("Id".equals(fname)) uniqueConsumer.accept(s); else db.traverseIndex(table, fname, Struct.objectToCore(s), subid, when, historical, uniqueConsumer); } } else { Object from = Struct.objectToCore(collector.getField("From")); Object to = Struct.objectToCore(collector.getField("To")); db.traverseIndexRange(table, fname, from, to, when, historical, uniqueConsumer); } out.endList(); } catch (Exception x) { log.error("Issue with select direct: " + x); } task.complete(); return; } /* // TODO support collector // m collector=Params("Collector") * i collector("Name")'="" d quit . s cname=collector("Name") ; "cstate" is a variable available to the collector for state across calls . i ^dcProg("collector",cname)="" q . w StartList . f x "s id=$$"_^dcProg("collector",cname)_"()" q:id="" d q:Errors . . d:$$check^dcDbSelect(table,id,when,.where,historical) writeRec(table,id,when,.select,5,1,0,historical) . w EndList ; i collector("Field")'="" d quit . i $d(collector("Values")) d q . . n values m values=collector("Values") . . w StartList . . f s id=$$loopValues^dcDb(table,collector("Field"),.values,.cstate,when,historical) q:id="" d . . . d:$$check^dcDbSelect(table,id,when,.where,historical) writeRec(table,id,when,.select,5,1,0,historical) . . w EndList . ; . w StartList . f s id=$$loopRange^dcDb(table,collector("Field"),collector("From"),collector("To"),.cstate,when,historical) q:id="" d . . d:$$check^dcDbSelect(table,id,when,.where,historical) writeRec(table,id,when,.select,5,1,0,historical) . w EndList ; w StartList */ try { out.startList(); db.traverseRecords(table, when, historical, new Consumer<Object>() { @Override public void accept(Object t) { try { String id = t.toString(); if (db.checkSelect(table, id, fwhen, where, historical)) SelectDirect.this.writeRecord(conn, task, log, out, db, table, id, fwhen, select, compact, false, historical); } catch (Exception x) { log.error("Issue with select direct: " + x); } } }); out.endList(); } catch (Exception x) { log.error("Issue with select direct: " + x); } task.complete(); } }