Initial checkin

This commit is contained in:
2023-06-16 08:36:17 -05:00
parent 599aff3487
commit 9fe5067374
6 changed files with 1410 additions and 183 deletions

View File

@ -0,0 +1,410 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.actions.tables.helpers;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.querystats.QueryStat;
import com.kingsrook.qqq.backend.core.model.querystats.QueryStatCriteriaField;
import com.kingsrook.qqq.backend.core.model.querystats.QueryStatJoinTable;
import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.model.tables.QQQTable;
import com.kingsrook.qqq.backend.core.model.tables.QQQTablesMetaDataProvider;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/*******************************************************************************
**
*******************************************************************************/
public class QueryStatManager
{
private static QueryStatManager queryStatManager = null;
// todo - support multiple qInstances?
private QInstance qInstance;
private Supplier<QSession> sessionSupplier;
private boolean active = false;
private List<QueryStat> queryStats = new ArrayList<>();
private ScheduledExecutorService executorService;
/*******************************************************************************
** Singleton constructor
*******************************************************************************/
private QueryStatManager()
{
}
/*******************************************************************************
** Singleton accessor
*******************************************************************************/
public static QueryStatManager getInstance()
{
if(queryStatManager == null)
{
queryStatManager = new QueryStatManager();
}
return (queryStatManager);
}
/*******************************************************************************
**
*******************************************************************************/
public void start(QInstance qInstance, Supplier<QSession> sessionSupplier)
{
this.qInstance = qInstance;
this.sessionSupplier = sessionSupplier;
active = true;
queryStats = new ArrayList<>();
executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(new QueryStatManagerInsertJob(), 6, 6, TimeUnit.SECONDS); // todo - 60s
}
/*******************************************************************************
**
*******************************************************************************/
public void stop()
{
active = false;
queryStats.clear();
if(executorService != null)
{
executorService.shutdown();
executorService = null;
}
}
/*******************************************************************************
**
*******************************************************************************/
public void add(QueryStat queryStat)
{
if(active)
{
////////////////////////////////////////////////////////////////////////////////////////
// set fields that we need to capture now (rather than when the thread to store runs) //
////////////////////////////////////////////////////////////////////////////////////////
if(queryStat.getFirstResultTimestamp() == null)
{
queryStat.setFirstResultTimestamp(Instant.now());
}
if(queryStat.getSessionId() == null && QContext.getQSession() != null)
{
queryStat.setSessionId(QContext.getQSession().getUuid());
}
if(queryStat.getAction() == null)
{
if(!QContext.getActionStack().isEmpty())
{
queryStat.setAction(QContext.getActionStack().peek().getActionIdentity());
}
else
{
boolean expected = false;
Exception e = new Exception("Unexpected empty action stack");
for(StackTraceElement stackTraceElement : e.getStackTrace())
{
String className = stackTraceElement.getClassName();
if(className.contains(QueryStatManagerInsertJob.class.getName()))
{
expected = true;
}
}
if(!expected)
{
e.printStackTrace();
}
}
}
synchronized(this)
{
queryStats.add(queryStat);
}
}
}
/*******************************************************************************
**
*******************************************************************************/
private List<QueryStat> getListAndReset()
{
if(queryStats.isEmpty())
{
return Collections.emptyList();
}
synchronized(this)
{
List<QueryStat> returnList = queryStats;
queryStats = new ArrayList<>();
return (returnList);
}
}
/*******************************************************************************
**
*******************************************************************************/
public void storeStatsNow()
{
new QueryStatManagerInsertJob().run();
}
/*******************************************************************************
**
*******************************************************************************/
private static class QueryStatManagerInsertJob implements Runnable
{
private static final QLogger LOG = QLogger.getLogger(QueryStatManagerInsertJob.class);
/*******************************************************************************
**
*******************************************************************************/
@Override
public void run()
{
try
{
QContext.init(getInstance().qInstance, getInstance().sessionSupplier.get());
List<QueryStat> list = getInstance().getListAndReset();
LOG.info(logPair("queryStatListSize", list.size()));
if(list.isEmpty())
{
return;
}
////////////////////////////////////
// prime the entities for storing //
////////////////////////////////////
List<QRecord> queryStatQRecordsToInsert = new ArrayList<>();
for(QueryStat queryStat : list)
{
try
{
///////////////////////////////////////////////
// compute the millis (so you don't have to) //
///////////////////////////////////////////////
if(queryStat.getStartTimestamp() != null && queryStat.getFirstResultTimestamp() != null && queryStat.getFirstResultMillis() == null)
{
long millis = queryStat.getFirstResultTimestamp().toEpochMilli() - queryStat.getStartTimestamp().toEpochMilli();
queryStat.setFirstResultMillis((int) millis);
}
//////////////////////
// set the table id //
//////////////////////
Integer qqqTableId = getQQQTableId(queryStat.getTableName());
queryStat.setQqqTableId(qqqTableId);
//////////////////////////////
// build join-table records //
//////////////////////////////
if(CollectionUtils.nullSafeHasContents(queryStat.getJoinTableNames()))
{
List<QueryStatJoinTable> queryStatJoinTableList = new ArrayList<>();
for(String joinTableName : queryStat.getJoinTableNames())
{
queryStatJoinTableList.add(new QueryStatJoinTable().withQqqTableId(getQQQTableId(joinTableName)));
}
queryStat.setQueryStatJoinTableList(queryStatJoinTableList);
}
////////////////////////////
// build criteria records //
////////////////////////////
if(queryStat.getQueryFilter() != null && queryStat.getQueryFilter().hasAnyCriteria())
{
List<QueryStatCriteriaField> queryStatCriteriaFieldList = new ArrayList<>();
QQueryFilter queryFilter = queryStat.getQueryFilter();
processCriteriaFromFilter(qqqTableId, queryStatCriteriaFieldList, queryFilter);
queryStat.setQueryStatCriteriaFieldList(queryStatCriteriaFieldList);
}
// todo - orderbys
queryStatQRecordsToInsert.add(queryStat.toQRecord());
}
catch(Exception e)
{
//////////////////////
// skip this record //
//////////////////////
LOG.warn("Error priming a query stat for storing", e);
}
}
try
{
InsertInput insertInput = new InsertInput();
insertInput.setTableName(QueryStat.TABLE_NAME);
insertInput.setRecords(queryStatQRecordsToInsert);
new InsertAction().execute(insertInput);
}
catch(Exception e)
{
LOG.error("Error inserting query stats", e);
}
}
catch(Exception e)
{
LOG.warn("Error storing query stats", e);
}
finally
{
QContext.clear();
}
}
/*******************************************************************************
**
*******************************************************************************/
private static void processCriteriaFromFilter(Integer qqqTableId, List<QueryStatCriteriaField> queryStatCriteriaFieldList, QQueryFilter queryFilter) throws QException
{
for(QFilterCriteria criteria : CollectionUtils.nonNullList(queryFilter.getCriteria()))
{
String fieldName = criteria.getFieldName();
QueryStatCriteriaField queryStatCriteriaField = new QueryStatCriteriaField();
queryStatCriteriaField.setOperator(String.valueOf(criteria.getOperator()));
if(criteria.getValues() != null)
{
queryStatCriteriaField.setValues(StringUtils.join(",", criteria.getValues()));
}
if(fieldName.contains("."))
{
String[] parts = fieldName.split("\\.");
if(parts.length > 1)
{
queryStatCriteriaField.setQqqTableId(getQQQTableId(parts[0]));
queryStatCriteriaField.setName(parts[1]);
}
}
else
{
queryStatCriteriaField.setQqqTableId(qqqTableId);
queryStatCriteriaField.setName(fieldName);
}
queryStatCriteriaFieldList.add(queryStatCriteriaField);
}
for(QQueryFilter subFilter : CollectionUtils.nonNullList(queryFilter.getSubFilters()))
{
processCriteriaFromFilter(qqqTableId, queryStatCriteriaFieldList, subFilter);
}
}
/*******************************************************************************
**
*******************************************************************************/
private static Integer getQQQTableId(String tableName) throws QException
{
/////////////////////////////
// look in the cache table //
/////////////////////////////
GetInput getInput = new GetInput();
getInput.setTableName(QQQTablesMetaDataProvider.QQQ_TABLE_CACHE_TABLE_NAME);
getInput.setUniqueKey(MapBuilder.of("name", tableName));
GetOutput getOutput = new GetAction().execute(getInput);
////////////////////////
// upon cache miss... //
////////////////////////
if(getOutput.getRecord() == null)
{
///////////////////////////////////////////////////////
// insert the record (into the table, not the cache) //
///////////////////////////////////////////////////////
QTableMetaData tableMetaData = getInstance().qInstance.getTable(tableName);
InsertInput insertInput = new InsertInput();
insertInput.setTableName(QQQTable.TABLE_NAME);
insertInput.setRecords(List.of(new QRecord().withValue("name", tableName).withValue("label", tableMetaData.getLabel())));
InsertOutput insertOutput = new InsertAction().execute(insertInput);
///////////////////////////////////
// repeat the get from the cache //
///////////////////////////////////
getOutput = new GetAction().execute(getInput);
}
return getOutput.getRecord().getValueInteger("id");
}
}
}

View File

@ -19,37 +19,31 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.kingsrook.qqq.backend.core.actions.tables.helpers.querystats; package com.kingsrook.qqq.backend.core.model.querystats;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.Set;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.data.QAssociation; import com.kingsrook.qqq.backend.core.model.data.QAssociation;
import com.kingsrook.qqq.backend.core.model.data.QField; import com.kingsrook.qqq.backend.core.model.data.QField;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior; import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.core.model.tables.QQQTable;
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
/******************************************************************************* /*******************************************************************************
** ** QRecord Entity for QueryStat table
*******************************************************************************/ *******************************************************************************/
public class QueryStat extends QRecordEntity public class QueryStat extends QRecordEntity
{ {
public static final String TABLE_NAME = "queryStat"; public static final String TABLE_NAME = "queryStat";
@QField() @QField(isEditable = false)
private Integer id; private Integer id;
@QField()
private String tableName;
@QField() @QField()
private Instant startTimestamp; private Instant startTimestamp;
@ -59,121 +53,81 @@ public class QueryStat extends QRecordEntity
@QField() @QField()
private Integer firstResultMillis; private Integer firstResultMillis;
@QField(maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE) @QField(label = "Table", possibleValueSourceName = QQQTable.TABLE_NAME)
private String joinTables; private Integer qqqTableId;
@QField(maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE) @QField(maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
private String orderBys; private String action;
@QAssociation(name = "queryStatFilterCriteria") @QField(maxLength = 36, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
private List<QueryStatFilterCriteria> queryStatFilterCriteriaList; private String sessionId;
@QField(maxLength = 64 * 1024 - 1, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
private String queryText;
@QAssociation(name = "queryStatJoinTables")
private List<QueryStatJoinTable> queryStatJoinTableList;
@QAssociation(name = "queryStatCriteriaFields")
private List<QueryStatCriteriaField> queryStatCriteriaFieldList;
@QAssociation(name = "queryStatOrderByFields")
private List<QueryStatOrderByField> queryStatOrderByFieldList;
///////////////////////////////////////////////////////////
// non-persistent fields - used to help build the record //
///////////////////////////////////////////////////////////
private String tableName;
private Set<String> joinTableNames;
private QQueryFilter queryFilter;
/******************************************************************************* /*******************************************************************************
** ** Default constructor
*******************************************************************************/ *******************************************************************************/
public void setJoinTables(Collection<String> joinTableNames) public QueryStat()
{ {
if(CollectionUtils.nullSafeIsEmpty(joinTableNames))
{
setJoinTables((String) null);
}
setJoinTables(joinTableNames.stream().sorted().collect(Collectors.joining(",")));
} }
/******************************************************************************* /*******************************************************************************
** ** Constructor that takes a QRecord
*******************************************************************************/ *******************************************************************************/
public void setQQueryFilter(QQueryFilter filter) public QueryStat(QRecord record)
{ {
if(filter == null) populateFromQRecord(record);
{
setQueryStatFilterCriteriaList(null);
setOrderBys(null);
}
else
{
/////////////////////////////////////////////
// manage list of sub-records for criteria //
/////////////////////////////////////////////
if(CollectionUtils.nullSafeIsEmpty(filter.getCriteria()) && CollectionUtils.nullSafeIsEmpty(filter.getSubFilters()))
{
setQueryStatFilterCriteriaList(null);
}
else
{
ArrayList<QueryStatFilterCriteria> criteriaList = new ArrayList<>();
setQueryStatFilterCriteriaList(criteriaList);
processFilterCriteria(filter, criteriaList);
}
//////////////////////////////////////////////////////////////
// set orderBys (comma-delimited concatenated string field) //
//////////////////////////////////////////////////////////////
if(CollectionUtils.nullSafeIsEmpty(filter.getOrderBys()))
{
setOrderBys(null);
}
else
{
setOrderBys(filter.getOrderBys().stream().map(ob -> ob.getFieldName()).collect(Collectors.joining(",")));
}
}
} }
/******************************************************************************* /*******************************************************************************
** ** Getter for id
*******************************************************************************/ *******************************************************************************/
private static void processFilterCriteria(QQueryFilter filter, ArrayList<QueryStatFilterCriteria> criteriaList) public Integer getId()
{ {
for(QFilterCriteria criterion : CollectionUtils.nonNullList(filter.getCriteria())) return (this.id);
{
criteriaList.add(new QueryStatFilterCriteria()
.withFieldName(criterion.getFieldName())
.withOperator(criterion.getOperator().name())
.withValues(CollectionUtils.nonNullList(criterion.getValues()).stream().map(v -> ValueUtils.getValueAsString(v)).collect(Collectors.joining(","))));
}
for(QQueryFilter subFilter : CollectionUtils.nonNullList(filter.getSubFilters()))
{
processFilterCriteria(subFilter, criteriaList);
}
} }
/******************************************************************************* /*******************************************************************************
** Getter for tableName ** Setter for id
*******************************************************************************/ *******************************************************************************/
public String getTableName() public void setId(Integer id)
{ {
return (this.tableName); this.id = id;
} }
/******************************************************************************* /*******************************************************************************
** Setter for tableName ** Fluent setter for id
*******************************************************************************/ *******************************************************************************/
public void setTableName(String tableName) public QueryStat withId(Integer id)
{ {
this.tableName = tableName; this.id = id;
}
/*******************************************************************************
** Fluent setter for tableName
*******************************************************************************/
public QueryStat withTableName(String tableName)
{
this.tableName = tableName;
return (this); return (this);
} }
@ -273,124 +227,310 @@ public class QueryStat extends QRecordEntity
/******************************************************************************* /*******************************************************************************
** Getter for joinTables ** Getter for queryText
*******************************************************************************/ *******************************************************************************/
public String getJoinTables() public String getQueryText()
{ {
return (this.joinTables); return (this.queryText);
} }
/******************************************************************************* /*******************************************************************************
** Setter for joinTables ** Setter for queryText
*******************************************************************************/ *******************************************************************************/
public void setJoinTables(String joinTables) public void setQueryText(String queryText)
{ {
this.joinTables = joinTables; this.queryText = queryText;
} }
/******************************************************************************* /*******************************************************************************
** Fluent setter for joinTables ** Fluent setter for queryText
*******************************************************************************/ *******************************************************************************/
public QueryStat withJoinTables(String joinTables) public QueryStat withQueryText(String queryText)
{ {
this.joinTables = joinTables; this.queryText = queryText;
return (this); return (this);
} }
/******************************************************************************* /*******************************************************************************
** Getter for queryStatFilterCriteriaList ** Getter for queryStatJoinTableList
*******************************************************************************/ *******************************************************************************/
public List<QueryStatFilterCriteria> getQueryStatFilterCriteriaList() public List<QueryStatJoinTable> getQueryStatJoinTableList()
{ {
return (this.queryStatFilterCriteriaList); return (this.queryStatJoinTableList);
} }
/******************************************************************************* /*******************************************************************************
** Setter for queryStatFilterCriteriaList ** Setter for queryStatJoinTableList
*******************************************************************************/ *******************************************************************************/
public void setQueryStatFilterCriteriaList(List<QueryStatFilterCriteria> queryStatFilterCriteriaList) public void setQueryStatJoinTableList(List<QueryStatJoinTable> queryStatJoinTableList)
{ {
this.queryStatFilterCriteriaList = queryStatFilterCriteriaList; this.queryStatJoinTableList = queryStatJoinTableList;
} }
/******************************************************************************* /*******************************************************************************
** Fluent setter for queryStatFilterCriteriaList ** Fluent setter for queryStatJoinTableList
*******************************************************************************/ *******************************************************************************/
public QueryStat withQueryStatFilterCriteriaList(List<QueryStatFilterCriteria> queryStatFilterCriteriaList) public QueryStat withQueryStatJoinTableList(List<QueryStatJoinTable> queryStatJoinTableList)
{ {
this.queryStatFilterCriteriaList = queryStatFilterCriteriaList; this.queryStatJoinTableList = queryStatJoinTableList;
return (this); return (this);
} }
/******************************************************************************* /*******************************************************************************
** Getter for orderBys ** Getter for queryStatCriteriaFieldList
*******************************************************************************/ *******************************************************************************/
public String getOrderBys() public List<QueryStatCriteriaField> getQueryStatCriteriaFieldList()
{ {
return (this.orderBys); return (this.queryStatCriteriaFieldList);
} }
/******************************************************************************* /*******************************************************************************
** Setter for orderBys ** Setter for queryStatCriteriaFieldList
*******************************************************************************/ *******************************************************************************/
public void setOrderBys(String orderBys) public void setQueryStatCriteriaFieldList(List<QueryStatCriteriaField> queryStatCriteriaFieldList)
{ {
this.orderBys = orderBys; this.queryStatCriteriaFieldList = queryStatCriteriaFieldList;
} }
/******************************************************************************* /*******************************************************************************
** Fluent setter for orderBys ** Fluent setter for queryStatCriteriaFieldList
*******************************************************************************/ *******************************************************************************/
public QueryStat withOrderBys(String orderBys) public QueryStat withQueryStatCriteriaFieldList(List<QueryStatCriteriaField> queryStatCriteriaFieldList)
{ {
this.orderBys = orderBys; this.queryStatCriteriaFieldList = queryStatCriteriaFieldList;
return (this); return (this);
} }
/******************************************************************************* /*******************************************************************************
** Getter for id ** Getter for queryStatOrderByFieldList
*******************************************************************************/ *******************************************************************************/
public Integer getId() public List<QueryStatOrderByField> getQueryStatOrderByFieldList()
{ {
return (this.id); return (this.queryStatOrderByFieldList);
} }
/******************************************************************************* /*******************************************************************************
** Setter for id ** Setter for queryStatOrderByFieldList
*******************************************************************************/ *******************************************************************************/
public void setId(Integer id) public void setQueryStatOrderByFieldList(List<QueryStatOrderByField> queryStatOrderByFieldList)
{ {
this.id = id; this.queryStatOrderByFieldList = queryStatOrderByFieldList;
} }
/******************************************************************************* /*******************************************************************************
** Fluent setter for id ** Fluent setter for queryStatOrderByFieldList
*******************************************************************************/ *******************************************************************************/
public QueryStat withId(Integer id) public QueryStat withQueryStatOrderByFieldList(List<QueryStatOrderByField> queryStatOrderByFieldList)
{ {
this.id = id; this.queryStatOrderByFieldList = queryStatOrderByFieldList;
return (this);
}
/*******************************************************************************
** Getter for tableName
*******************************************************************************/
public String getTableName()
{
return (this.tableName);
}
/*******************************************************************************
** Setter for tableName
*******************************************************************************/
public void setTableName(String tableName)
{
this.tableName = tableName;
}
/*******************************************************************************
** Fluent setter for tableName
*******************************************************************************/
public QueryStat withTableName(String tableName)
{
this.tableName = tableName;
return (this);
}
/*******************************************************************************
** Getter for queryFilter
*******************************************************************************/
public QQueryFilter getQueryFilter()
{
return (this.queryFilter);
}
/*******************************************************************************
** Setter for queryFilter
*******************************************************************************/
public void setQueryFilter(QQueryFilter queryFilter)
{
this.queryFilter = queryFilter;
}
/*******************************************************************************
** Fluent setter for queryFilter
*******************************************************************************/
public QueryStat withQueryFilter(QQueryFilter queryFilter)
{
this.queryFilter = queryFilter;
return (this);
}
/*******************************************************************************
** Getter for qqqTableId
*******************************************************************************/
public Integer getQqqTableId()
{
return (this.qqqTableId);
}
/*******************************************************************************
** Setter for qqqTableId
*******************************************************************************/
public void setQqqTableId(Integer qqqTableId)
{
this.qqqTableId = qqqTableId;
}
/*******************************************************************************
** Fluent setter for qqqTableId
*******************************************************************************/
public QueryStat withQqqTableId(Integer qqqTableId)
{
this.qqqTableId = qqqTableId;
return (this);
}
/*******************************************************************************
** Getter for joinTableNames
*******************************************************************************/
public Set<String> getJoinTableNames()
{
return (this.joinTableNames);
}
/*******************************************************************************
** Setter for joinTableNames
*******************************************************************************/
public void setJoinTableNames(Set<String> joinTableNames)
{
this.joinTableNames = joinTableNames;
}
/*******************************************************************************
** Fluent setter for joinTableNames
*******************************************************************************/
public QueryStat withJoinTableNames(Set<String> joinTableNames)
{
this.joinTableNames = joinTableNames;
return (this);
}
/*******************************************************************************
** Getter for action
*******************************************************************************/
public String getAction()
{
return (this.action);
}
/*******************************************************************************
** Setter for action
*******************************************************************************/
public void setAction(String action)
{
this.action = action;
}
/*******************************************************************************
** Fluent setter for action
*******************************************************************************/
public QueryStat withAction(String action)
{
this.action = action;
return (this);
}
/*******************************************************************************
** Getter for sessionId
*******************************************************************************/
public String getSessionId()
{
return (this.sessionId);
}
/*******************************************************************************
** Setter for sessionId
*******************************************************************************/
public void setSessionId(String sessionId)
{
this.sessionId = sessionId;
}
/*******************************************************************************
** Fluent setter for sessionId
*******************************************************************************/
public QueryStat withSessionId(String sessionId)
{
this.sessionId = sessionId;
return (this); return (this);
} }

View File

@ -0,0 +1,262 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.querystats;
import com.kingsrook.qqq.backend.core.model.data.QField;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
import com.kingsrook.qqq.backend.core.model.tables.QQQTable;
/*******************************************************************************
** QRecord Entity for QueryStatCriteriaField table
*******************************************************************************/
public class QueryStatCriteriaField extends QRecordEntity
{
public static final String TABLE_NAME = "queryStatCriteriaField";
@QField(isEditable = false)
private Integer id;
@QField(possibleValueSourceName = QueryStat.TABLE_NAME)
private Integer queryStatId;
@QField(label = "Table", possibleValueSourceName = QQQTable.TABLE_NAME)
private Integer qqqTableId;
@QField(maxLength = 50, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
private String name;
@QField(maxLength = 30, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
private String operator;
@QField(maxLength = 50, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
private String values;
/*******************************************************************************
** Default constructor
*******************************************************************************/
public QueryStatCriteriaField()
{
}
/*******************************************************************************
** Constructor that takes a QRecord
*******************************************************************************/
public QueryStatCriteriaField(QRecord record)
{
populateFromQRecord(record);
}
/*******************************************************************************
** Getter for id
*******************************************************************************/
public Integer getId()
{
return (this.id);
}
/*******************************************************************************
** Setter for id
*******************************************************************************/
public void setId(Integer id)
{
this.id = id;
}
/*******************************************************************************
** Fluent setter for id
*******************************************************************************/
public QueryStatCriteriaField withId(Integer id)
{
this.id = id;
return (this);
}
/*******************************************************************************
** Getter for queryStatId
*******************************************************************************/
public Integer getQueryStatId()
{
return (this.queryStatId);
}
/*******************************************************************************
** Setter for queryStatId
*******************************************************************************/
public void setQueryStatId(Integer queryStatId)
{
this.queryStatId = queryStatId;
}
/*******************************************************************************
** Fluent setter for queryStatId
*******************************************************************************/
public QueryStatCriteriaField withQueryStatId(Integer queryStatId)
{
this.queryStatId = queryStatId;
return (this);
}
/*******************************************************************************
** Getter for qqqTableId
*******************************************************************************/
public Integer getQqqTableId()
{
return (this.qqqTableId);
}
/*******************************************************************************
** Setter for qqqTableId
*******************************************************************************/
public void setQqqTableId(Integer qqqTableId)
{
this.qqqTableId = qqqTableId;
}
/*******************************************************************************
** Fluent setter for qqqTableId
*******************************************************************************/
public QueryStatCriteriaField withQqqTableId(Integer qqqTableId)
{
this.qqqTableId = qqqTableId;
return (this);
}
/*******************************************************************************
** Getter for name
*******************************************************************************/
public String getName()
{
return (this.name);
}
/*******************************************************************************
** Setter for name
*******************************************************************************/
public void setName(String name)
{
this.name = name;
}
/*******************************************************************************
** Fluent setter for name
*******************************************************************************/
public QueryStatCriteriaField withName(String name)
{
this.name = name;
return (this);
}
/*******************************************************************************
** Getter for operator
*******************************************************************************/
public String getOperator()
{
return (this.operator);
}
/*******************************************************************************
** Setter for operator
*******************************************************************************/
public void setOperator(String operator)
{
this.operator = operator;
}
/*******************************************************************************
** Fluent setter for operator
*******************************************************************************/
public QueryStatCriteriaField withOperator(String operator)
{
this.operator = operator;
return (this);
}
/*******************************************************************************
** Getter for values
*******************************************************************************/
public String getValues()
{
return (this.values);
}
/*******************************************************************************
** Setter for values
*******************************************************************************/
public void setValues(String values)
{
this.values = values;
}
/*******************************************************************************
** Fluent setter for values
*******************************************************************************/
public QueryStatCriteriaField withValues(String values)
{
this.values = values;
return (this);
}
}

View File

@ -0,0 +1,194 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.querystats;
import com.kingsrook.qqq.backend.core.model.data.QField;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
import com.kingsrook.qqq.backend.core.model.tables.QQQTable;
/*******************************************************************************
** QRecord Entity for QueryStatJoinTable table
*******************************************************************************/
public class QueryStatJoinTable extends QRecordEntity
{
public static final String TABLE_NAME = "queryStatJoinTable"; // todo - lowercase the first letter
@QField(isEditable = false)
private Integer id;
@QField(possibleValueSourceName = QueryStat.TABLE_NAME)
private Integer queryStatId;
@QField(label = "Table", possibleValueSourceName = QQQTable.TABLE_NAME)
private Integer qqqTableId;
@QField(maxLength = 10, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
private String type;
/*******************************************************************************
** Default constructor
*******************************************************************************/
public QueryStatJoinTable()
{
}
/*******************************************************************************
** Constructor that takes a QRecord
*******************************************************************************/
public QueryStatJoinTable(QRecord record)
{
populateFromQRecord(record);
}
/*******************************************************************************
** Getter for id
*******************************************************************************/
public Integer getId()
{
return (this.id);
}
/*******************************************************************************
** Setter for id
*******************************************************************************/
public void setId(Integer id)
{
this.id = id;
}
/*******************************************************************************
** Fluent setter for id
*******************************************************************************/
public QueryStatJoinTable withId(Integer id)
{
this.id = id;
return (this);
}
/*******************************************************************************
** Getter for queryStatId
*******************************************************************************/
public Integer getQueryStatId()
{
return (this.queryStatId);
}
/*******************************************************************************
** Setter for queryStatId
*******************************************************************************/
public void setQueryStatId(Integer queryStatId)
{
this.queryStatId = queryStatId;
}
/*******************************************************************************
** Fluent setter for queryStatId
*******************************************************************************/
public QueryStatJoinTable withQueryStatId(Integer queryStatId)
{
this.queryStatId = queryStatId;
return (this);
}
/*******************************************************************************
** Getter for qqqTableId
*******************************************************************************/
public Integer getQqqTableId()
{
return (this.qqqTableId);
}
/*******************************************************************************
** Setter for qqqTableId
*******************************************************************************/
public void setQqqTableId(Integer qqqTableId)
{
this.qqqTableId = qqqTableId;
}
/*******************************************************************************
** Fluent setter for qqqTableId
*******************************************************************************/
public QueryStatJoinTable withQqqTableId(Integer qqqTableId)
{
this.qqqTableId = qqqTableId;
return (this);
}
/*******************************************************************************
** Getter for type
*******************************************************************************/
public String getType()
{
return (this.type);
}
/*******************************************************************************
** Setter for type
*******************************************************************************/
public void setType(String type)
{
this.type = type;
}
/*******************************************************************************
** Fluent setter for type
*******************************************************************************/
public QueryStatJoinTable withType(String type)
{
this.type = type;
return (this);
}
}

View File

@ -0,0 +1,189 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.querystats;
import java.util.List;
import java.util.function.Consumer;
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.ChildRecordListRenderer;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.audits.AuditLevel;
import com.kingsrook.qqq.backend.core.model.metadata.audits.QAuditRules;
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat;
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment;
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSourceType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.Association;
import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability;
import com.kingsrook.qqq.backend.core.model.metadata.tables.ExposedJoin;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier;
/*******************************************************************************
**
*******************************************************************************/
public class QueryStatMetaDataProvider
{
/*******************************************************************************
**
*******************************************************************************/
public void defineAll(QInstance instance, String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
{
addJoins(instance);
defineQueryStatTable(instance, backendName, backendDetailEnricher);
instance.addTable(defineStandardTable(QueryStatJoinTable.TABLE_NAME, QueryStatJoinTable.class, backendName, backendDetailEnricher));
instance.addTable(defineStandardTable(QueryStatCriteriaField.TABLE_NAME, QueryStatCriteriaField.class, backendName, backendDetailEnricher)
.withExposedJoin(new ExposedJoin().withJoinTable(QueryStat.TABLE_NAME))
);
instance.addTable(defineStandardTable(QueryStatOrderByField.TABLE_NAME, QueryStatOrderByField.class, backendName, backendDetailEnricher));
instance.addPossibleValueSource(defineQueryStatPossibleValueSource());
}
/*******************************************************************************
**
*******************************************************************************/
private void addJoins(QInstance instance)
{
instance.addJoin(new QJoinMetaData()
.withLeftTable(QueryStat.TABLE_NAME)
.withRightTable(QueryStatJoinTable.TABLE_NAME)
.withInferredName()
.withType(JoinType.ONE_TO_MANY)
.withJoinOn(new JoinOn("id", "queryStatId")));
instance.addJoin(new QJoinMetaData()
.withLeftTable(QueryStat.TABLE_NAME)
.withRightTable(QueryStatCriteriaField.TABLE_NAME)
.withInferredName()
.withType(JoinType.ONE_TO_MANY)
.withJoinOn(new JoinOn("id", "queryStatId")));
instance.addJoin(new QJoinMetaData()
.withLeftTable(QueryStat.TABLE_NAME)
.withRightTable(QueryStatOrderByField.TABLE_NAME)
.withInferredName()
.withType(JoinType.ONE_TO_MANY)
.withJoinOn(new JoinOn("id", "queryStatId")));
}
/*******************************************************************************
**
*******************************************************************************/
private QTableMetaData defineQueryStatTable(QInstance instance, String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
{
String joinTablesJoinName = QJoinMetaData.makeInferredJoinName(QueryStat.TABLE_NAME, QueryStatJoinTable.TABLE_NAME);
String criteriaFieldsJoinName = QJoinMetaData.makeInferredJoinName(QueryStat.TABLE_NAME, QueryStatCriteriaField.TABLE_NAME);
String orderByFieldsJoinName = QJoinMetaData.makeInferredJoinName(QueryStat.TABLE_NAME, QueryStatOrderByField.TABLE_NAME);
QTableMetaData table = new QTableMetaData()
.withName(QueryStat.TABLE_NAME)
.withBackendName(backendName)
.withAuditRules(new QAuditRules().withAuditLevel(AuditLevel.NONE))
.withRecordLabelFormat("%s")
.withRecordLabelFields("id")
.withPrimaryKeyField("id")
.withFieldsFromEntity(QueryStat.class)
.withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "action", "qqqTableId", "sessionId")))
.withSection(new QFieldSection("data", new QIcon().withName("dataset"), Tier.T2, List.of("queryText", "startTimestamp", "firstResultTimestamp", "firstResultMillis")))
.withSection(new QFieldSection("joins", new QIcon().withName("merge"), Tier.T2).withWidgetName(joinTablesJoinName + "Widget"))
.withSection(new QFieldSection("criteria", new QIcon().withName("filter_alt"), Tier.T2).withWidgetName(criteriaFieldsJoinName + "Widget"))
.withSection(new QFieldSection("orderBys", new QIcon().withName("sort_by_alpha"), Tier.T2).withWidgetName(orderByFieldsJoinName + "Widget"))
.withoutCapabilities(Capability.TABLE_INSERT, Capability.TABLE_UPDATE, Capability.TABLE_DELETE);
if(backendDetailEnricher != null)
{
backendDetailEnricher.accept(table);
}
instance.addWidget(ChildRecordListRenderer.widgetMetaDataBuilder(instance.getJoin(joinTablesJoinName)).withName(joinTablesJoinName + "Widget").withLabel("Join Tables").getWidgetMetaData());
instance.addWidget(ChildRecordListRenderer.widgetMetaDataBuilder(instance.getJoin(criteriaFieldsJoinName)).withName(criteriaFieldsJoinName + "Widget").withLabel("Criteria Fields").getWidgetMetaData());
instance.addWidget(ChildRecordListRenderer.widgetMetaDataBuilder(instance.getJoin(orderByFieldsJoinName)).withName(orderByFieldsJoinName + "Widget").withLabel("Order by Fields").getWidgetMetaData());
table.withAssociation(new Association().withName("queryStatJoinTables").withJoinName(joinTablesJoinName).withAssociatedTableName(QueryStatJoinTable.TABLE_NAME))
.withAssociation(new Association().withName("queryStatCriteriaFields").withJoinName(criteriaFieldsJoinName).withAssociatedTableName(QueryStatCriteriaField.TABLE_NAME))
.withAssociation(new Association().withName("queryStatOrderByFields").withJoinName(orderByFieldsJoinName).withAssociatedTableName(QueryStatOrderByField.TABLE_NAME));
table.getField("queryText").withFieldAdornment(new FieldAdornment(AdornmentType.CODE_EDITOR).withValue(AdornmentType.CodeEditorValues.languageMode("sql")));
table.getField("firstResultMillis").withDisplayFormat(DisplayFormat.COMMAS);
instance.addTable(table);
return (table);
}
/*******************************************************************************
**
*******************************************************************************/
private QTableMetaData defineStandardTable(String tableName, Class<? extends QRecordEntity> entityClass, String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
{
QTableMetaData table = new QTableMetaData()
.withName(tableName)
.withBackendName(backendName)
.withAuditRules(new QAuditRules().withAuditLevel(AuditLevel.NONE))
.withRecordLabelFormat("%d")
.withRecordLabelFields("id")
.withPrimaryKeyField("id")
.withFieldsFromEntity(entityClass)
.withoutCapabilities(Capability.TABLE_INSERT, Capability.TABLE_UPDATE, Capability.TABLE_DELETE);
if(backendDetailEnricher != null)
{
backendDetailEnricher.accept(table);
}
return (table);
}
/*******************************************************************************
**
*******************************************************************************/
public QPossibleValueSource defineQueryStatPossibleValueSource()
{
return (new QPossibleValueSource()
.withType(QPossibleValueSourceType.TABLE)
.withName(QueryStat.TABLE_NAME)
.withTableName(QueryStat.TABLE_NAME));
}
}

View File

@ -19,21 +19,84 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.kingsrook.qqq.backend.core.actions.tables.helpers.querystats; package com.kingsrook.qqq.backend.core.model.querystats;
import com.kingsrook.qqq.backend.core.model.data.QField;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
import com.kingsrook.qqq.backend.core.model.tables.QQQTable;
/******************************************************************************* /*******************************************************************************
** ** QRecord Entity for QueryStatOrderByField table
*******************************************************************************/ *******************************************************************************/
public class QueryStatFilterCriteria extends QRecordEntity public class QueryStatOrderByField extends QRecordEntity
{ {
public static final String TABLE_NAME = "queryStatOrderByField";
@QField(isEditable = false)
private Integer id;
@QField(possibleValueSourceName = QueryStat.TABLE_NAME)
private Integer queryStatId; private Integer queryStatId;
private String fieldName;
private String operator; @QField(label = "Table", possibleValueSourceName = QQQTable.TABLE_NAME)
private String values; private Integer qqqTableId;
@QField(maxLength = 50, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
private String name;
/*******************************************************************************
** Default constructor
*******************************************************************************/
public QueryStatOrderByField()
{
}
/*******************************************************************************
** Constructor that takes a QRecord
*******************************************************************************/
public QueryStatOrderByField(QRecord record)
{
populateFromQRecord(record);
}
/*******************************************************************************
** Getter for id
*******************************************************************************/
public Integer getId()
{
return (this.id);
}
/*******************************************************************************
** Setter for id
*******************************************************************************/
public void setId(Integer id)
{
this.id = id;
}
/*******************************************************************************
** Fluent setter for id
*******************************************************************************/
public QueryStatOrderByField withId(Integer id)
{
this.id = id;
return (this);
}
@ -60,7 +123,7 @@ public class QueryStatFilterCriteria extends QRecordEntity
/******************************************************************************* /*******************************************************************************
** Fluent setter for queryStatId ** Fluent setter for queryStatId
*******************************************************************************/ *******************************************************************************/
public QueryStatFilterCriteria withQueryStatId(Integer queryStatId) public QueryStatOrderByField withQueryStatId(Integer queryStatId)
{ {
this.queryStatId = queryStatId; this.queryStatId = queryStatId;
return (this); return (this);
@ -69,93 +132,62 @@ public class QueryStatFilterCriteria extends QRecordEntity
/******************************************************************************* /*******************************************************************************
** Getter for fieldName ** Getter for qqqTableId
*******************************************************************************/ *******************************************************************************/
public String getFieldName() public Integer getQqqTableId()
{ {
return (this.fieldName); return (this.qqqTableId);
} }
/******************************************************************************* /*******************************************************************************
** Setter for fieldName ** Setter for qqqTableId
*******************************************************************************/ *******************************************************************************/
public void setFieldName(String fieldName) public void setQqqTableId(Integer qqqTableId)
{ {
this.fieldName = fieldName; this.qqqTableId = qqqTableId;
} }
/******************************************************************************* /*******************************************************************************
** Fluent setter for fieldName ** Fluent setter for qqqTableId
*******************************************************************************/ *******************************************************************************/
public QueryStatFilterCriteria withFieldName(String fieldName) public QueryStatOrderByField withQqqTableId(Integer qqqTableId)
{ {
this.fieldName = fieldName; this.qqqTableId = qqqTableId;
return (this); return (this);
} }
/******************************************************************************* /*******************************************************************************
** Getter for operator ** Getter for name
*******************************************************************************/ *******************************************************************************/
public String getOperator() public String getName()
{ {
return (this.operator); return (this.name);
} }
/******************************************************************************* /*******************************************************************************
** Setter for operator ** Setter for name
*******************************************************************************/ *******************************************************************************/
public void setOperator(String operator) public void setName(String name)
{ {
this.operator = operator; this.name = name;
} }
/******************************************************************************* /*******************************************************************************
** Fluent setter for operator ** Fluent setter for name
*******************************************************************************/ *******************************************************************************/
public QueryStatFilterCriteria withOperator(String operator) public QueryStatOrderByField withName(String name)
{ {
this.operator = operator; this.name = name;
return (this);
}
/*******************************************************************************
** Getter for values
*******************************************************************************/
public String getValues()
{
return (this.values);
}
/*******************************************************************************
** Setter for values
*******************************************************************************/
public void setValues(String values)
{
this.values = values;
}
/*******************************************************************************
** Fluent setter for values
*******************************************************************************/
public QueryStatFilterCriteria withValues(String values)
{
this.values = values;
return (this); return (this);
} }