From 9fe5067374d8a9e04e63fb3580b580b3e788a1e7 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Fri, 16 Jun 2023 08:36:17 -0500 Subject: [PATCH] Initial checkin --- .../tables/helpers/QueryStatManager.java | 410 ++++++++++++++++++ .../querystats/QueryStat.java | 394 +++++++++++------ .../querystats/QueryStatCriteriaField.java | 262 +++++++++++ .../model/querystats/QueryStatJoinTable.java | 194 +++++++++ .../querystats/QueryStatMetaDataProvider.java | 189 ++++++++ .../querystats/QueryStatOrderByField.java} | 144 +++--- 6 files changed, 1410 insertions(+), 183 deletions(-) create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/QueryStatManager.java rename qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/{actions/tables/helpers => model}/querystats/QueryStat.java (50%) create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatCriteriaField.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatJoinTable.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatMetaDataProvider.java rename qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/{actions/tables/helpers/querystats/QueryStatFilterCriteria.java => model/querystats/QueryStatOrderByField.java} (61%) diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/QueryStatManager.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/QueryStatManager.java new file mode 100644 index 00000000..59ee1db6 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/QueryStatManager.java @@ -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 . + */ + +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 sessionSupplier; + + private boolean active = false; + private List 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 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 getListAndReset() + { + if(queryStats.isEmpty()) + { + return Collections.emptyList(); + } + + synchronized(this) + { + List 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 list = getInstance().getListAndReset(); + LOG.info(logPair("queryStatListSize", list.size())); + + if(list.isEmpty()) + { + return; + } + + //////////////////////////////////// + // prime the entities for storing // + //////////////////////////////////// + List 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 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 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 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"); + } + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/querystats/QueryStat.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStat.java similarity index 50% rename from qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/querystats/QueryStat.java rename to qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStat.java index 2c35f9f4..a0e5f513 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/querystats/QueryStat.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStat.java @@ -19,37 +19,31 @@ * along with this program. If not, see . */ -package com.kingsrook.qqq.backend.core.actions.tables.helpers.querystats; +package com.kingsrook.qqq.backend.core.model.querystats; import java.time.Instant; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; -import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; +import java.util.Set; 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.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.utils.CollectionUtils; -import com.kingsrook.qqq.backend.core.utils.ValueUtils; +import com.kingsrook.qqq.backend.core.model.tables.QQQTable; /******************************************************************************* - ** + ** QRecord Entity for QueryStat table *******************************************************************************/ public class QueryStat extends QRecordEntity { public static final String TABLE_NAME = "queryStat"; - @QField() + @QField(isEditable = false) private Integer id; - @QField() - private String tableName; - @QField() private Instant startTimestamp; @@ -59,121 +53,81 @@ public class QueryStat extends QRecordEntity @QField() private Integer firstResultMillis; - @QField(maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE) - private String joinTables; + @QField(label = "Table", possibleValueSourceName = QQQTable.TABLE_NAME) + private Integer qqqTableId; - @QField(maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE) - private String orderBys; + @QField(maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS) + private String action; - @QAssociation(name = "queryStatFilterCriteria") - private List queryStatFilterCriteriaList; + @QField(maxLength = 36, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS) + private String sessionId; + + @QField(maxLength = 64 * 1024 - 1, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS) + private String queryText; + + @QAssociation(name = "queryStatJoinTables") + private List queryStatJoinTableList; + + @QAssociation(name = "queryStatCriteriaFields") + private List queryStatCriteriaFieldList; + + @QAssociation(name = "queryStatOrderByFields") + private List queryStatOrderByFieldList; + + /////////////////////////////////////////////////////////// + // non-persistent fields - used to help build the record // + /////////////////////////////////////////////////////////// + private String tableName; + private Set joinTableNames; + private QQueryFilter queryFilter; /******************************************************************************* - ** + ** Default constructor *******************************************************************************/ - public void setJoinTables(Collection 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) - { - 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 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(","))); - } - } + populateFromQRecord(record); } /******************************************************************************* - ** + ** Getter for id *******************************************************************************/ - private static void processFilterCriteria(QQueryFilter filter, ArrayList criteriaList) + public Integer getId() { - for(QFilterCriteria criterion : CollectionUtils.nonNullList(filter.getCriteria())) - { - 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); - } + return (this.id); } /******************************************************************************* - ** 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; - } - - - - /******************************************************************************* - ** Fluent setter for tableName - *******************************************************************************/ - public QueryStat withTableName(String tableName) - { - this.tableName = tableName; + this.id = id; 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); } /******************************************************************************* - ** Getter for queryStatFilterCriteriaList + ** Getter for queryStatJoinTableList *******************************************************************************/ - public List getQueryStatFilterCriteriaList() + public List getQueryStatJoinTableList() { - return (this.queryStatFilterCriteriaList); + return (this.queryStatJoinTableList); } /******************************************************************************* - ** Setter for queryStatFilterCriteriaList + ** Setter for queryStatJoinTableList *******************************************************************************/ - public void setQueryStatFilterCriteriaList(List queryStatFilterCriteriaList) + public void setQueryStatJoinTableList(List queryStatJoinTableList) { - this.queryStatFilterCriteriaList = queryStatFilterCriteriaList; + this.queryStatJoinTableList = queryStatJoinTableList; } /******************************************************************************* - ** Fluent setter for queryStatFilterCriteriaList + ** Fluent setter for queryStatJoinTableList *******************************************************************************/ - public QueryStat withQueryStatFilterCriteriaList(List queryStatFilterCriteriaList) + public QueryStat withQueryStatJoinTableList(List queryStatJoinTableList) { - this.queryStatFilterCriteriaList = queryStatFilterCriteriaList; + this.queryStatJoinTableList = queryStatJoinTableList; return (this); } /******************************************************************************* - ** Getter for orderBys + ** Getter for queryStatCriteriaFieldList *******************************************************************************/ - public String getOrderBys() + public List getQueryStatCriteriaFieldList() { - return (this.orderBys); + return (this.queryStatCriteriaFieldList); } /******************************************************************************* - ** Setter for orderBys + ** Setter for queryStatCriteriaFieldList *******************************************************************************/ - public void setOrderBys(String orderBys) + public void setQueryStatCriteriaFieldList(List queryStatCriteriaFieldList) { - this.orderBys = orderBys; + this.queryStatCriteriaFieldList = queryStatCriteriaFieldList; } /******************************************************************************* - ** Fluent setter for orderBys + ** Fluent setter for queryStatCriteriaFieldList *******************************************************************************/ - public QueryStat withOrderBys(String orderBys) + public QueryStat withQueryStatCriteriaFieldList(List queryStatCriteriaFieldList) { - this.orderBys = orderBys; + this.queryStatCriteriaFieldList = queryStatCriteriaFieldList; return (this); } /******************************************************************************* - ** Getter for id + ** Getter for queryStatOrderByFieldList *******************************************************************************/ - public Integer getId() + public List getQueryStatOrderByFieldList() { - return (this.id); + return (this.queryStatOrderByFieldList); } /******************************************************************************* - ** Setter for id + ** Setter for queryStatOrderByFieldList *******************************************************************************/ - public void setId(Integer id) + public void setQueryStatOrderByFieldList(List queryStatOrderByFieldList) { - this.id = id; + this.queryStatOrderByFieldList = queryStatOrderByFieldList; } /******************************************************************************* - ** Fluent setter for id + ** Fluent setter for queryStatOrderByFieldList *******************************************************************************/ - public QueryStat withId(Integer id) + public QueryStat withQueryStatOrderByFieldList(List 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 getJoinTableNames() + { + return (this.joinTableNames); + } + + + + /******************************************************************************* + ** Setter for joinTableNames + *******************************************************************************/ + public void setJoinTableNames(Set joinTableNames) + { + this.joinTableNames = joinTableNames; + } + + + + /******************************************************************************* + ** Fluent setter for joinTableNames + *******************************************************************************/ + public QueryStat withJoinTableNames(Set 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); } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatCriteriaField.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatCriteriaField.java new file mode 100644 index 00000000..bd25a51f --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatCriteriaField.java @@ -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 . + */ + +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); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatJoinTable.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatJoinTable.java new file mode 100644 index 00000000..47686a17 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatJoinTable.java @@ -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 . + */ + +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); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatMetaDataProvider.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatMetaDataProvider.java new file mode 100644 index 00000000..85d5f079 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatMetaDataProvider.java @@ -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 . + */ + +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 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 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 entityClass, String backendName, Consumer 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)); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/querystats/QueryStatFilterCriteria.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatOrderByField.java similarity index 61% rename from qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/querystats/QueryStatFilterCriteria.java rename to qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatOrderByField.java index ffb29a8b..353221c1 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/querystats/QueryStatFilterCriteria.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/querystats/QueryStatOrderByField.java @@ -19,21 +19,84 @@ * along with this program. If not, see . */ -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.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 String fieldName; - private String operator; - private String values; + + @QField(label = "Table", possibleValueSourceName = QQQTable.TABLE_NAME) + 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 *******************************************************************************/ - public QueryStatFilterCriteria withQueryStatId(Integer queryStatId) + public QueryStatOrderByField withQueryStatId(Integer queryStatId) { this.queryStatId = queryStatId; 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); } /******************************************************************************* - ** 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; - 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; + this.name = name; return (this); }