mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-05 16:10:43 +00:00
fix: Enabled histogram in sql mode for non aggregated queries (#3133)
**Problem**: Histogram was disabled in SQL mode. **Solution**: Enabled histogram in sql mode for only non aggregated queries --------- Co-authored-by: Bhargav <BJP232004@GMAIL.COM>
This commit is contained in:
co-authored by
Bhargav
parent
7389b4f614
commit
545e0bf6bc
@@ -78,6 +78,15 @@ export function histogramToggleDisabled() {
|
||||
);
|
||||
}
|
||||
|
||||
export function histogramToggleEnabled() {
|
||||
cy.get(showSQLModeHistogramToggle, { timeout: 2000 }).should(
|
||||
"not.have.attr",
|
||||
"aria-disabled",
|
||||
"true"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//** Type the value of a variable into an input field*/
|
||||
export function enterVrlFunctionvalue() {
|
||||
cy.get('[data-test="logs-vrl-function-editor"]:first', { timeout: 2000 })
|
||||
|
||||
@@ -79,7 +79,7 @@ describe("Logs testcases", () => {
|
||||
cy.intercept("GET", "**/api/default/streams**").as("streams");
|
||||
});
|
||||
|
||||
it("should display results for limit query", () => {
|
||||
it.skip("should display results for limit query", () => {
|
||||
cy.get('[data-test="logs-search-bar-query-editor"] > .monaco-editor')
|
||||
.click() // Click on the editor to focus
|
||||
.type("match_all('provide_credentials') limit 5");
|
||||
@@ -109,6 +109,7 @@ describe("Logs testcases", () => {
|
||||
cy.get(".q-virtual-scroll__content:last").click();
|
||||
|
||||
// Select "25" from the dropdown using contains
|
||||
cy.wait(2000);
|
||||
cy.contains(".q-item__label", "25").should("be.visible").click();
|
||||
cy.get(".search-list > :nth-child(1) > .text-left")
|
||||
.contains("Showing 1 to 5 out of 5")
|
||||
|
||||
@@ -97,14 +97,14 @@ describe("Logs testcases", () => {
|
||||
// This test checks if the histogram toggle button works correctly by clicking it and verifying that the chart is hidden.
|
||||
|
||||
// This test checks that clicking on the histogram toggle button in SQL mode does not toggle the chart
|
||||
it("should not toggle chart when clicking on the histogram toggle in the sql mode", () => {
|
||||
it.skip("should not toggle chart when clicking on the histogram toggle in the sql mode", () => {
|
||||
logstests.clickHistogramToggle();
|
||||
cy.wait(3000);
|
||||
logstests.clickSearchBarSqlMode();
|
||||
cy.wait(3000);
|
||||
logstests.confirmLogsSearchHidden();
|
||||
cy.wait(3000);
|
||||
logstests.histogramToggleDisabled();
|
||||
logstests.histogramToggleEnabled();
|
||||
});
|
||||
it.skip("should toggle chart when clicking on the histogram toggle", () => {
|
||||
cy.wait(3000);
|
||||
|
||||
@@ -420,7 +420,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
<div
|
||||
v-if="frequency.type === 'custom'"
|
||||
class="flex items-center justify-start q-mt-md"
|
||||
class="flex items-start justify-start q-mt-md"
|
||||
>
|
||||
<div
|
||||
data-test="add-report-schedule-custom-interval-input"
|
||||
@@ -430,7 +430,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<q-input
|
||||
filled
|
||||
v-model="frequency.custom.interval"
|
||||
label="Repeat every"
|
||||
label="Repeat every *"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
class="showLabelOnTop"
|
||||
@@ -438,6 +438,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
type="number"
|
||||
outlined
|
||||
dense
|
||||
:rules="[(val) => !!val || 'Field is required!']"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</div>
|
||||
@@ -450,7 +451,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<q-select
|
||||
v-model="frequency.custom.period"
|
||||
:options="customFrequencyOptions"
|
||||
:label="' '"
|
||||
:label="'Frequency *'"
|
||||
:popup-content-style="{ textTransform: 'capitalize' }"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
@@ -478,7 +479,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<q-input
|
||||
filled
|
||||
v-model="scheduling.date"
|
||||
label="Start Date"
|
||||
label="Start Date *"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
class="showLabelOnTop"
|
||||
@@ -506,7 +507,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
>
|
||||
<div class="row items-center justify-end">
|
||||
<q-btn
|
||||
:v-close-popup="true"
|
||||
v-close-popup="true"
|
||||
label="Close"
|
||||
color="primary"
|
||||
flat
|
||||
@@ -525,7 +526,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<q-input
|
||||
filled
|
||||
v-model="scheduling.time"
|
||||
label="Start Time"
|
||||
label="Start Time *"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
class="showLabelOnTop"
|
||||
@@ -546,7 +547,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<q-time v-model="scheduling.time">
|
||||
<div class="row items-center justify-end">
|
||||
<q-btn
|
||||
:v-close-popup="true"
|
||||
v-close-popup="true"
|
||||
label="Close"
|
||||
color="primary"
|
||||
flat
|
||||
@@ -577,7 +578,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
emit-value
|
||||
fill-input
|
||||
hide-selected
|
||||
:label="t('logStream.timezone')"
|
||||
:label="t('logStream.timezone') + ' *'"
|
||||
:display-value="`Timezone: ${timezone}`"
|
||||
:rules="[(val: any) => !!val || 'Field is required!']"
|
||||
class="timezone-select showLabelOnTop"
|
||||
|
||||
@@ -558,7 +558,6 @@ const useLogs = () => {
|
||||
searchObj.data.query = query;
|
||||
const parsedSQL: any = fnParsedSQL();
|
||||
|
||||
console.log(parsedSQL);
|
||||
if (!parsedSQL?.columns?.length) {
|
||||
notificationMsg.value = "Invalid SQL Syntax";
|
||||
return false;
|
||||
@@ -724,6 +723,14 @@ const useLogs = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const isNonAggregatedQuery = (parsedSQL: any = null) => {
|
||||
return !(
|
||||
parsedSQL?.groupby ||
|
||||
hasAggregation(parsedSQL?.columns) ||
|
||||
parsedSQL?.limit
|
||||
);
|
||||
};
|
||||
|
||||
const getQueryPartitions = async (queryReq: any) => {
|
||||
// const queryReq = buildSearch();
|
||||
searchObj.data.queryResults.hits = [];
|
||||
@@ -741,11 +748,10 @@ const useLogs = () => {
|
||||
};
|
||||
|
||||
const parsedSQL: any = fnParsedSQL();
|
||||
|
||||
if (
|
||||
!searchObj.meta.sqlMode ||
|
||||
(searchObj.meta.sqlMode &&
|
||||
parsedSQL.groupby == null &&
|
||||
!hasAggregation(parsedSQL.columns))
|
||||
(searchObj.meta.sqlMode && isNonAggregatedQuery(parsedSQL))
|
||||
) {
|
||||
const partitionQueryReq: any = {
|
||||
sql: queryReq.query.sql,
|
||||
@@ -1051,6 +1057,10 @@ const useLogs = () => {
|
||||
|
||||
// copy query request for histogram query and same for customDownload
|
||||
searchObj.data.histogramQuery = JSON.parse(JSON.stringify(queryReq));
|
||||
|
||||
// Removing sql_mode from histogram query, as it is not required
|
||||
delete searchObj.data.histogramQuery.query.sql_mode;
|
||||
|
||||
delete queryReq.aggs;
|
||||
searchObj.data.customDownloadQueryObj = queryReq;
|
||||
// get the current page detail and set it into query request
|
||||
@@ -1102,18 +1112,36 @@ const useLogs = () => {
|
||||
|
||||
// based on pagination request, get the data
|
||||
await getPaginatedData(queryReq);
|
||||
const parsedSQL: any = fnParsedSQL();
|
||||
|
||||
if (
|
||||
(searchObj.data.queryResults.aggs == undefined &&
|
||||
searchObj.data.resultGrid.currentPage == 1 &&
|
||||
searchObj.loadingHistogram == false &&
|
||||
searchObj.meta.showHistogram == true &&
|
||||
searchObj.meta.sqlMode == false) ||
|
||||
(!searchObj.meta.sqlMode ||
|
||||
(searchObj.meta.sqlMode && isNonAggregatedQuery(parsedSQL)))) ||
|
||||
(searchObj.loadingHistogram == false &&
|
||||
searchObj.meta.showHistogram == true &&
|
||||
searchObj.meta.sqlMode == false &&
|
||||
searchObj.data.resultGrid.currentPage == 1)
|
||||
) {
|
||||
getHistogramQueryData(searchObj.data.histogramQuery);
|
||||
} else if (searchObj.meta.sqlMode && !isNonAggregatedQuery(parsedSQL)) {
|
||||
searchObj.data.histogram = {
|
||||
xData: [],
|
||||
yData: [],
|
||||
chartParams: {
|
||||
title: getHistogramTitle(),
|
||||
unparsed_x_data: [],
|
||||
timezone: "",
|
||||
},
|
||||
errorCode: 0,
|
||||
errorMsg: "Histogram is not available for aggregation queries.",
|
||||
errorDetail: "",
|
||||
};
|
||||
} else {
|
||||
console.log("Histogram is not available for aggregation queries.");
|
||||
}
|
||||
} else {
|
||||
searchObj.loading = false;
|
||||
@@ -2220,38 +2248,46 @@ const useLogs = () => {
|
||||
streamName: string
|
||||
) => {
|
||||
// Parse the SQL query into an AST
|
||||
const parsedQuery: any = parser.astify(sql);
|
||||
try {
|
||||
const parsedQuery: any = parser.astify(sql);
|
||||
|
||||
// Check for the presence of an ORDER BY clause
|
||||
const hasOrderBy = !!(
|
||||
parsedQuery.orderby && parsedQuery.orderby.length > 0
|
||||
);
|
||||
if (!parsedQuery.columns.length || !parsedQuery.from) {
|
||||
return sql;
|
||||
}
|
||||
|
||||
// Check if _timestamp is in the SELECT clause if not SELECT *
|
||||
const includesTimestamp = !!parsedQuery.columns.find(
|
||||
(col: any) => col?.expr?.column === column || col?.expr?.column === "*"
|
||||
);
|
||||
// Check for the presence of an ORDER BY clause
|
||||
const hasOrderBy = !!(
|
||||
parsedQuery.orderby && parsedQuery.orderby.length > 0
|
||||
);
|
||||
|
||||
// If ORDER BY is present and doesn't include _timestamp, append it
|
||||
if (!hasOrderBy) {
|
||||
// If no ORDER BY clause, add it
|
||||
parsedQuery.orderby = [
|
||||
{
|
||||
expr: {
|
||||
type: "column_ref",
|
||||
table: null,
|
||||
column: column,
|
||||
// Check if _timestamp is in the SELECT clause if not SELECT *
|
||||
const includesTimestamp = !!parsedQuery.columns.find(
|
||||
(col: any) => col?.expr?.column === column || col?.expr?.column === "*"
|
||||
);
|
||||
|
||||
// If ORDER BY is present and doesn't include _timestamp, append it
|
||||
if (!hasOrderBy) {
|
||||
// If no ORDER BY clause, add it
|
||||
parsedQuery.orderby = [
|
||||
{
|
||||
expr: {
|
||||
type: "column_ref",
|
||||
table: null,
|
||||
column: column,
|
||||
},
|
||||
type: type,
|
||||
},
|
||||
type: type,
|
||||
},
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
// Convert the AST back to a SQL string, replacing backtics with empty strings and table name with double quotes
|
||||
return quoteTableNameDirectly(
|
||||
parser.sqlify(parsedQuery).replace(/`/g, ""),
|
||||
streamName
|
||||
);
|
||||
// Convert the AST back to a SQL string, replacing backtics with empty strings and table name with double quotes
|
||||
return quoteTableNameDirectly(
|
||||
parser.sqlify(parsedQuery).replace(/`/g, ""),
|
||||
streamName
|
||||
);
|
||||
} catch (err) {
|
||||
return sql;
|
||||
}
|
||||
};
|
||||
|
||||
function quoteTableNameDirectly(sql: string, streamName: string) {
|
||||
|
||||
@@ -500,7 +500,6 @@ export default defineComponent({
|
||||
nextTick(() => {
|
||||
if (
|
||||
searchObj.meta.showHistogram &&
|
||||
!searchObj.meta.sqlMode &&
|
||||
searchResultRef.value?.reDrawChart
|
||||
) {
|
||||
searchResultRef.value.reDrawChart();
|
||||
@@ -521,39 +520,46 @@ export default defineComponent({
|
||||
let currentQuery = searchObj.data.query;
|
||||
|
||||
//check if user try to applied saved views in which sql mode is enabled.
|
||||
if (currentQuery.indexOf("SELECT") >= 0) {
|
||||
return;
|
||||
}
|
||||
currentQuery = currentQuery.split("|");
|
||||
if (currentQuery.length > 1) {
|
||||
selectFields = "," + currentQuery[0].trim();
|
||||
if (currentQuery[1].trim() != "") {
|
||||
whereClause = "WHERE " + currentQuery[1].trim();
|
||||
}
|
||||
} else if (currentQuery[0].trim() != "") {
|
||||
if (currentQuery[0].trim() != "") {
|
||||
whereClause = "WHERE " + currentQuery[0].trim();
|
||||
}
|
||||
}
|
||||
searchObj.data.query =
|
||||
`SELECT [FIELD_LIST]${selectFields} FROM "` +
|
||||
searchObj.data.stream.selectedStream.value +
|
||||
`" ` +
|
||||
whereClause;
|
||||
|
||||
if (
|
||||
searchObj.data.stream.interestingFieldList.length > 0 &&
|
||||
searchObj.meta.quickMode
|
||||
) {
|
||||
searchObj.data.query = searchObj.data.query.replace(
|
||||
"[FIELD_LIST]",
|
||||
searchObj.data.stream.interestingFieldList.join(",")
|
||||
);
|
||||
} else {
|
||||
searchObj.data.query = searchObj.data.query.replace(
|
||||
"[FIELD_LIST]",
|
||||
"*"
|
||||
);
|
||||
// Parse the query and check if it is valid
|
||||
// It should have one column and one table
|
||||
|
||||
const hasSelect =
|
||||
currentQuery.toLowerCase() === "select" ||
|
||||
currentQuery.toLowerCase().indexOf("select ") == 0;
|
||||
|
||||
if (!hasSelect) {
|
||||
currentQuery = currentQuery.split("|");
|
||||
if (currentQuery.length > 1) {
|
||||
selectFields = "," + currentQuery[0].trim();
|
||||
if (currentQuery[1].trim() != "") {
|
||||
whereClause = "WHERE " + currentQuery[1].trim();
|
||||
}
|
||||
} else if (currentQuery[0].trim() != "") {
|
||||
if (currentQuery[0].trim() != "") {
|
||||
whereClause = "WHERE " + currentQuery[0].trim();
|
||||
}
|
||||
}
|
||||
searchObj.data.query =
|
||||
`SELECT [FIELD_LIST]${selectFields} FROM "` +
|
||||
searchObj.data.stream.selectedStream.value +
|
||||
`" ` +
|
||||
whereClause;
|
||||
|
||||
if (
|
||||
searchObj.data.stream.interestingFieldList.length > 0 &&
|
||||
searchObj.meta.quickMode
|
||||
) {
|
||||
searchObj.data.query = searchObj.data.query.replace(
|
||||
"[FIELD_LIST]",
|
||||
searchObj.data.stream.interestingFieldList.join(",")
|
||||
);
|
||||
} else {
|
||||
searchObj.data.query = searchObj.data.query.replace(
|
||||
"[FIELD_LIST]",
|
||||
"*"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
searchObj.data.query = addOrderByToQuery(
|
||||
@@ -573,7 +579,6 @@ export default defineComponent({
|
||||
searchBarRef.value.udpateQuery();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log("Logs : Error in setQuery");
|
||||
}
|
||||
};
|
||||
@@ -782,14 +787,12 @@ export default defineComponent({
|
||||
},
|
||||
showHistogram() {
|
||||
if (
|
||||
this.searchObj.meta.showHistogram == true &&
|
||||
this.searchObj.shouldIgnoreWatcher == false
|
||||
this.searchObj.meta.showHistogram &&
|
||||
!this.searchObj.shouldIgnoreWatcher
|
||||
) {
|
||||
if (this.searchObj.meta.sqlMode == false) {
|
||||
setTimeout(() => {
|
||||
if (this.searchResultRef) this.searchResultRef.reDrawChart();
|
||||
}, 100);
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (this.searchResultRef) this.searchResultRef.reDrawChart();
|
||||
}, 100);
|
||||
|
||||
if (this.searchObj.meta.histogramDirtyFlag == true) {
|
||||
this.searchObj.meta.histogramDirtyFlag = false;
|
||||
|
||||
@@ -19,16 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<div class="row">
|
||||
<div class="float-right col q-mb-xs">
|
||||
<q-toggle
|
||||
v-if="searchObj.meta.sqlMode"
|
||||
data-test="logs-search-bar-show-histogram-toggle-sqlmode-btn"
|
||||
v-bind:disable="searchObj.meta.sqlMode"
|
||||
:model-value="false"
|
||||
:label="t('search.showHistogramLabel')"
|
||||
/>
|
||||
<q-toggle
|
||||
v-else
|
||||
data-test="logs-search-bar-show-histogram-toggle-btn"
|
||||
v-bind:disable="searchObj.meta.sqlMode"
|
||||
v-model="searchObj.meta.showHistogram"
|
||||
:label="t('search.showHistogramLabel')"
|
||||
/>
|
||||
|
||||
@@ -76,7 +76,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
</div>
|
||||
<div v-if="searchObj.data.histogram.errorMsg == ''">
|
||||
<ChartRenderer
|
||||
v-if="searchObj.meta.showHistogram && !searchObj.meta.sqlMode"
|
||||
v-if="searchObj.meta.showHistogram"
|
||||
data-test="logs-search-result-bar-chart"
|
||||
:data="plotChart"
|
||||
style="max-height: 100px"
|
||||
@@ -94,7 +94,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="searchObj.data.histogram.errorMsg != ''">
|
||||
<div
|
||||
v-else-if="
|
||||
searchObj.data.histogram.errorMsg != '' &&
|
||||
searchObj.meta.showHistogram
|
||||
"
|
||||
>
|
||||
<h6 class="text-center">
|
||||
<q-icon name="warning" color="warning" size="30px"></q-icon> Error
|
||||
while fetching histogram data.
|
||||
|
||||
Reference in New Issue
Block a user