Skip to content

Commit 3e718c9

Browse files
committed
feat: Include displayed timestamp in default order by
1 parent 6587283 commit 3e718c9

File tree

4 files changed

+118
-25
lines changed

4 files changed

+118
-25
lines changed

.changeset/twelve-beers-buy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hyperdx/app": patch
3+
---
4+
5+
feat: Include displayed timestamp in default order by

packages/app/src/DBSearchPage.tsx

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -532,14 +532,26 @@ function useSearchedConfigToChartConfig({
532532

533533
function optimizeDefaultOrderBy(
534534
timestampExpr: string,
535+
displayedTimestampExpr: string | undefined,
535536
sortingKey: string | undefined,
536537
) {
537538
const defaultModifier = 'DESC';
538-
const fallbackOrderByItems = [
539-
getFirstTimestampValueExpression(timestampExpr ?? ''),
540-
defaultModifier,
541-
];
542-
const fallbackOrderBy = fallbackOrderByItems.join(' ');
539+
const firstTimestampValueExpression =
540+
getFirstTimestampValueExpression(timestampExpr ?? '') ?? '';
541+
const defaultOrderByItems = [firstTimestampValueExpression];
542+
const trimmedDisplayedTimestampExpr = displayedTimestampExpr?.trim();
543+
544+
if (
545+
trimmedDisplayedTimestampExpr &&
546+
trimmedDisplayedTimestampExpr !== firstTimestampValueExpression
547+
) {
548+
defaultOrderByItems.push(trimmedDisplayedTimestampExpr);
549+
}
550+
551+
const fallbackOrderBy =
552+
defaultOrderByItems.length > 1
553+
? `(${defaultOrderByItems.join(', ')}) ${defaultModifier}`
554+
: `${defaultOrderByItems[0]} ${defaultModifier}`;
543555

544556
if (!sortingKey) return fallbackOrderBy;
545557

@@ -562,6 +574,8 @@ function optimizeDefaultOrderBy(
562574
orderByArr.push(sortKey);
563575
break;
564576
}
577+
} else if (sortKey === trimmedDisplayedTimestampExpr) {
578+
orderByArr.push(sortKey);
565579
}
566580
}
567581

@@ -570,6 +584,13 @@ function optimizeDefaultOrderBy(
570584
return fallbackOrderBy;
571585
}
572586

587+
if (
588+
trimmedDisplayedTimestampExpr &&
589+
!orderByArr.includes(trimmedDisplayedTimestampExpr)
590+
) {
591+
orderByArr.push(trimmedDisplayedTimestampExpr);
592+
}
593+
573594
return `(${orderByArr.join(', ')}) ${defaultModifier}`;
574595
}
575596

@@ -582,6 +603,7 @@ export function useDefaultOrderBy(sourceID: string | undefined | null) {
582603
() =>
583604
optimizeDefaultOrderBy(
584605
source?.timestampValueExpression ?? '',
606+
source?.displayedTimestampValueExpression,
585607
tableMetadata?.sorting_key,
586608
),
587609
[source, tableMetadata],

packages/app/src/__tests__/DBSearchPage.test.tsx

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,82 +17,133 @@ describe('useDefaultOrderBy', () => {
1717

1818
describe('optimizeOrderBy function', () => {
1919
describe('should handle', () => {
20-
const mockSource = {
21-
timestampValueExpression: 'Timestamp',
22-
};
23-
2420
const testCases = [
2521
{
26-
input: undefined,
22+
sortingKey: undefined,
2723
expected: 'Timestamp DESC',
2824
},
2925
{
30-
input: '',
26+
sortingKey: '',
3127
expected: 'Timestamp DESC',
3228
},
3329
{
3430
// Traces Table
35-
input: 'ServiceName, SpanName, toDateTime(Timestamp)',
31+
sortingKey: 'ServiceName, SpanName, toDateTime(Timestamp)',
3632
expected: 'Timestamp DESC',
3733
},
3834
{
3935
// Optimized Traces Table
40-
input:
36+
sortingKey:
4137
'toStartOfHour(Timestamp), ServiceName, SpanName, toDateTime(Timestamp)',
4238
expected: '(toStartOfHour(Timestamp), toDateTime(Timestamp)) DESC',
4339
},
4440
{
4541
// Unsupported for now as it's not a great sort key, want to just
4642
// use default behavior for this
47-
input: 'toDateTime(Timestamp), ServiceName, SpanName, Timestamp',
43+
sortingKey: 'toDateTime(Timestamp), ServiceName, SpanName, Timestamp',
4844
expected: 'Timestamp DESC',
4945
},
5046
{
5147
// Unsupported prefix sort key
52-
input: 'toDateTime(Timestamp), ServiceName, SpanName',
48+
sortingKey: 'toDateTime(Timestamp), ServiceName, SpanName',
5349
expected: 'Timestamp DESC',
5450
},
5551
{
5652
// Inverted sort key order, we should not try to optimize this
57-
input:
53+
sortingKey:
5854
'ServiceName, toDateTime(Timestamp), SeverityText, toStartOfHour(Timestamp)',
5955
expected: 'Timestamp DESC',
6056
},
6157
{
62-
input: 'toStartOfHour(Timestamp), other_column, Timestamp',
58+
sortingKey: 'toStartOfHour(Timestamp), other_column, Timestamp',
6359
expected: '(toStartOfHour(Timestamp), Timestamp) DESC',
6460
},
6561
{
66-
input: 'Timestamp, other_column',
62+
sortingKey: 'Timestamp, other_column',
6763
expected: 'Timestamp DESC',
6864
},
6965
{
70-
input: 'user_id, toStartOfHour(Timestamp), status, Timestamp',
66+
sortingKey: 'user_id, toStartOfHour(Timestamp), status, Timestamp',
7167
expected: '(toStartOfHour(Timestamp), Timestamp) DESC',
7268
},
7369
{
74-
input:
70+
sortingKey:
7571
'toStartOfMinute(Timestamp), user_id, status, toUnixTimestamp(Timestamp)',
7672
expected:
7773
'(toStartOfMinute(Timestamp), toUnixTimestamp(Timestamp)) DESC',
7874
},
7975
{
8076
// test variation of toUnixTimestamp
81-
input:
77+
sortingKey:
8278
'toStartOfMinute(Timestamp), user_id, status, toUnixTimestamp64Nano(Timestamp)',
8379
expected:
8480
'(toStartOfMinute(Timestamp), toUnixTimestamp64Nano(Timestamp)) DESC',
8581
},
8682
{
87-
input:
83+
sortingKey:
8884
'toUnixTimestamp(toStartOfMinute(Timestamp)), user_id, status, Timestamp',
8985
expected:
9086
'(toUnixTimestamp(toStartOfMinute(Timestamp)), Timestamp) DESC',
9187
},
88+
{
89+
sortingKey: 'Timestamp',
90+
displayedTimestampValueExpression: 'Timestamp64',
91+
expected: '(Timestamp, Timestamp64) DESC',
92+
},
93+
{
94+
sortingKey: 'Timestamp',
95+
displayedTimestampValueExpression: 'Timestamp64 ',
96+
expected: '(Timestamp, Timestamp64) DESC',
97+
},
98+
{
99+
sortingKey: 'Timestamp',
100+
displayedTimestampValueExpression: 'Timestamp',
101+
expected: 'Timestamp DESC',
102+
},
103+
{
104+
sortingKey: 'Timestamp',
105+
displayedTimestampValueExpression: '',
106+
expected: 'Timestamp DESC',
107+
},
108+
{
109+
sortingKey: 'Timestamp, ServiceName, Timestamp64',
110+
displayedTimestampValueExpression: 'Timestamp64',
111+
expected: '(Timestamp, Timestamp64) DESC',
112+
},
113+
{
114+
sortingKey:
115+
'toStartOfMinute(Timestamp), Timestamp, ServiceName, Timestamp64',
116+
displayedTimestampValueExpression: 'Timestamp64',
117+
expected: '(toStartOfMinute(Timestamp), Timestamp, Timestamp64) DESC',
118+
},
119+
{
120+
sortingKey:
121+
'toStartOfMinute(Timestamp), Timestamp64, ServiceName, Timestamp',
122+
displayedTimestampValueExpression: 'Timestamp64',
123+
expected: '(toStartOfMinute(Timestamp), Timestamp64, Timestamp) DESC',
124+
},
125+
{
126+
sortingKey: 'SomeOtherTimeColumn',
127+
displayedTimestampValueExpression: 'Timestamp64',
128+
expected: '(Timestamp, Timestamp64) DESC',
129+
},
130+
{
131+
sortingKey: '',
132+
displayedTimestampValueExpression: 'Timestamp64',
133+
expected: '(Timestamp, Timestamp64) DESC',
134+
},
92135
];
93136
for (const testCase of testCases) {
94-
it(`${testCase.input}`, () => {
95-
const mockTableMetadata = { sorting_key: testCase.input };
137+
it(`${testCase.sortingKey}`, () => {
138+
const mockSource = {
139+
timestampValueExpression: 'Timestamp',
140+
displayedTimestampValueExpression:
141+
testCase.displayedTimestampValueExpression,
142+
};
143+
144+
const mockTableMetadata = {
145+
sorting_key: testCase.sortingKey,
146+
};
96147

97148
jest.spyOn(sourceModule, 'useSource').mockReturnValue({
98149
data: mockSource,

packages/app/src/components/SourceForm.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ export function LogTableModelForm({ control, watch }: TableModelProps) {
285285
</FormRow>
286286
<FormRow
287287
label={'Displayed Timestamp Column'}
288-
helpText="This DateTime column is used to display search results."
288+
helpText="This DateTime column is used to display and order search results."
289289
>
290290
<SQLInlineEditorControlled
291291
tableConnection={{
@@ -631,6 +631,21 @@ export function TraceTableModelForm({ control, watch }: TableModelProps) {
631631
placeholder="SpanName"
632632
/>
633633
</FormRow>
634+
<FormRow
635+
label={'Displayed Timestamp Column'}
636+
helpText="This DateTime column is used to display and order search results."
637+
>
638+
<SQLInlineEditorControlled
639+
tableConnection={{
640+
databaseName,
641+
tableName,
642+
connectionId,
643+
}}
644+
control={control}
645+
name="displayedTimestampValueExpression"
646+
disableKeywordAutocomplete
647+
/>
648+
</FormRow>
634649
</Stack>
635650
);
636651
}

0 commit comments

Comments
 (0)