Skip to content

Commit 1e4896d

Browse files
committed
Merge branch 'tesseract-ci' of github.com:cube-js/cube into tesseract-ci
2 parents bfbfc94 + fe9b0b9 commit 1e4896d

File tree

23 files changed

+1015
-298
lines changed

23 files changed

+1015
-298
lines changed

docs/pages/product/deployment/cloud/vpc/aws/private-link.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ for creating and managing an Endpoint Service.
2121

2222
Cube Cloud needs to be added to the list of principals allowed to discover your Endpoint Service.
2323
To do so, please go to <Btn>AWS Console</Btn> -> <Btn>VPC</Btn> -> <Btn>Endpoint Services</Btn> -> <Btn>Your service</Btn> -> <Btn>Allow principals</Btn>
24-
and add `arn:aws:iam::331376342520` to the list.
24+
and add `arn:aws:iam::331376342520:root` to the list.
2525

2626
## Gathering required information
2727

@@ -31,8 +31,8 @@ To request establishing a PrivateLink connection, please share the following inf
3131
- **Reference Name** for the record (such as "Snowflake-prod" or "clickhouse-dev")
3232
- **Ports**: a list of ports that will be accessed through this connection
3333
- **DNS Name** (optional): an internal DNS name of the upstream service in case SSL needs to be supported
34-
- **Dedicated Infrastructure Region:** VPC Peering requires Cube to be hosted in
35-
[dedicated infrastructure][dedicated-infra]. Please specify what region the Cube Cloud
34+
- **Dedicated Infrastructure Region:** VPC Peering requires Cube to be hosted in
35+
[dedicated infrastructure][dedicated-infra]. Please specify what region the Cube Cloud
3636
dedicated infrastructure should be hosted in.
3737

3838

@@ -52,4 +52,4 @@ supplied DNS Name or an AWS internal DNS name returned to you by the Cube team.
5252

5353
[aws-docs-private-link]: https://aws.amazon.com/privatelink/
5454
[aws-docs-endpoint-service]: https://docs.aws.amazon.com/vpc/latest/privatelink/configure-endpoint-service.html
55-
[dedicated-infra]: /product/deployment/cloud/infrastructure#dedicated-infrastructure
55+
[dedicated-infra]: /product/deployment/cloud/infrastructure#dedicated-infrastructure

packages/cubejs-api-gateway/src/query.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ const evaluatedPatchMeasureExpression = parsedPatchMeasureExpression.keys({
5656
});
5757

5858
const id = Joi.string().regex(/^[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+$/);
59-
const idOrMemberExpressionName = Joi.string().regex(/^[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+$|^[a-zA-Z0-9_]+$/);
59+
// It might be member name, td+granularity or member expression
60+
const idOrMemberExpressionName = Joi.string().regex(/^[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+$|^[a-zA-Z0-9_]+$|^[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+$/);
6061
const dimensionWithTime = Joi.string().regex(/^[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)?$/);
6162
const parsedMemberExpression = Joi.object().keys({
6263
expression: Joi.alternatives(

packages/cubejs-backend-shared/src/FileRepository.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export interface FileContent {
55
fileName: string;
66
content: string;
77
readOnly?: boolean;
8+
isModule?: boolean;
89
}
910

1011
export interface SchemaFileRepository {
@@ -24,7 +25,7 @@ export class FileRepository implements SchemaFileRepository {
2425

2526
protected async getFiles(dir: string, fileList: string[] = []): Promise<string[]> {
2627
let files: string[] = [];
27-
28+
2829
try {
2930
const fullPath = path.join(this.localPath(), dir);
3031
await fs.ensureDir(fullPath);

packages/cubejs-backend-shared/src/time.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,67 @@ export type TimeSeriesOptions = {
1212
};
1313
type ParsedInterval = Partial<Record<unitOfTime.DurationConstructor, number>>;
1414

15+
const GRANULARITY_LEVELS: Record<string, number> = {
16+
second: 1,
17+
minute: 2,
18+
hour: 3,
19+
day: 4,
20+
week: 5,
21+
month: 6,
22+
quarter: 7,
23+
year: 8,
24+
MAX: 1000,
25+
};
26+
27+
export type DimensionToCompareGranularity = {
28+
dimension: string;
29+
expressionName?: string;
30+
granularityObj?: {
31+
minGranularity(): string;
32+
}
33+
};
34+
35+
/**
36+
* Actually dimensions type is (BaseDimension|BaseTimeDimension)[], but can not ref due to cyclic dependencies refs.
37+
*/
38+
export function findMinGranularityDimension(id: string, dimensions: DimensionToCompareGranularity[]): { index: number, dimension: DimensionToCompareGranularity | undefined } | null {
39+
const equalIgnoreCase = (a: any, b: any): boolean => (
40+
typeof a === 'string' && typeof b === 'string' && a.toUpperCase() === b.toUpperCase()
41+
);
42+
43+
let minGranularity = GRANULARITY_LEVELS.MAX;
44+
let index = -1;
45+
let minGranularityIndex = -1;
46+
let field;
47+
let minGranularityField;
48+
49+
dimensions.forEach((d, i) => {
50+
if (equalIgnoreCase(d.dimension, id) || equalIgnoreCase(d.expressionName, id)) {
51+
field = d;
52+
index = i;
53+
54+
if ('granularityObj' in d && d.granularityObj) {
55+
const gr = GRANULARITY_LEVELS[d.granularityObj?.minGranularity()];
56+
if (gr < minGranularity) {
57+
minGranularityIndex = i;
58+
minGranularityField = d;
59+
minGranularity = gr;
60+
}
61+
}
62+
}
63+
});
64+
65+
if (minGranularityIndex > -1) {
66+
return { index: minGranularityIndex, dimension: minGranularityField };
67+
}
68+
69+
if (index > -1) {
70+
return { index, dimension: field };
71+
}
72+
73+
return null;
74+
}
75+
1576
export const TIME_SERIES: Record<string, (range: DateRange, timestampPrecision: number) => QueryDateRange[]> = {
1677
day: (range: DateRange, digits) => Array.from(range.snapTo('day').by('day'))
1778
.map(d => [d.format(`YYYY-MM-DDT00:00:00.${'0'.repeat(digits)}`), d.format(`YYYY-MM-DDT23:59:59.${'9'.repeat(digits)}`)]),

packages/cubejs-databricks-jdbc-driver/src/DatabricksQuery.ts

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -144,42 +144,19 @@ export class DatabricksQuery extends BaseQuery {
144144
return `\`${name}\``;
145145
}
146146

147-
public getFieldIndex(id: string) {
148-
const dimension = this.dimensionsForSelect().find((d: any) => d.dimension === id);
149-
if (dimension) {
150-
return super.getFieldIndex(id);
147+
public override getFieldIndex(id: string): string | number | null {
148+
const idx = super.getFieldIndex(id);
149+
if (idx !== null) {
150+
return idx;
151151
}
152+
152153
return this.escapeColumnName(this.aliasName(id, false));
153154
}
154155

155156
public unixTimestampSql() {
156157
return 'unix_timestamp()';
157158
}
158159

159-
public orderHashToString(hash: any) {
160-
if (!hash || !hash.id) {
161-
return null;
162-
}
163-
164-
const fieldIndex = this.getFieldIndex(hash.id);
165-
if (fieldIndex === null) {
166-
return null;
167-
}
168-
169-
const dimensionsForSelect = this.dimensionsForSelect();
170-
const dimensionColumns = R.flatten(
171-
dimensionsForSelect.map((s: any) => s.selectColumns() && s.aliasName())
172-
)
173-
.filter(s => !!s);
174-
175-
if (dimensionColumns.length) {
176-
const direction = hash.desc ? 'DESC' : 'ASC';
177-
return `${fieldIndex} ${direction}`;
178-
}
179-
180-
return null;
181-
}
182-
183160
public defaultRefreshKeyRenewalThreshold() {
184161
return 120;
185162
}

packages/cubejs-questdb-driver/src/QuestQuery.ts

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { BaseFilter, BaseQuery, ParamAllocator } from '@cubejs-backend/schema-compiler';
1+
import {
2+
BaseFilter,
3+
BaseQuery,
4+
ParamAllocator
5+
} from '@cubejs-backend/schema-compiler';
26

37
const GRANULARITY_TO_INTERVAL: Record<string, string> = {
48
second: 's',
@@ -109,7 +113,7 @@ export class QuestQuery extends BaseQuery {
109113
}
110114
}
111115

112-
public orderHashToString(hash: any): string | null {
116+
public orderHashToString(hash: { id: string, desc: boolean }): string | null {
113117
// QuestDB has partial support for order by index column, so map these to the alias names.
114118
// So, instead of:
115119
// SELECT col_a as "a", col_b as "b" FROM tab ORDER BY 2 ASC
@@ -131,32 +135,6 @@ export class QuestQuery extends BaseQuery {
131135
return `${fieldAlias} ${direction}`;
132136
}
133137

134-
private getFieldAlias(id: string): string | null {
135-
const equalIgnoreCase = (a: any, b: any) => (
136-
typeof a === 'string' && typeof b === 'string' && a.toUpperCase() === b.toUpperCase()
137-
);
138-
139-
let field;
140-
141-
field = this.dimensionsForSelect().find(
142-
(d: any) => equalIgnoreCase(d.dimension, id),
143-
);
144-
145-
if (field) {
146-
return field.aliasName();
147-
}
148-
149-
field = this.measures.find(
150-
(d: any) => equalIgnoreCase(d.measure, id) || equalIgnoreCase(d.expressionName, id),
151-
);
152-
153-
if (field) {
154-
return field.aliasName();
155-
}
156-
157-
return null;
158-
}
159-
160138
public groupByClause(): string {
161139
// QuestDB doesn't support group by index column, so map these to the alias names.
162140
// So, instead of:
Lines changed: 8 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import R from 'ramda';
21
import { BaseFilter } from './BaseFilter';
3-
import { BaseQuery } from './BaseQuery';
2+
import { ElasticSearchQuery } from './ElasticSearchQuery';
43

54
const GRANULARITY_TO_INTERVAL = {
65
day: (date) => `DATE_FORMAT(${date}, 'yyyy-MM-dd 00:00:00.000')`,
@@ -21,83 +20,24 @@ class AWSElasticSearchQueryFilter extends BaseFilter {
2120
}
2221
}
2322

24-
export class AWSElasticSearchQuery extends BaseQuery {
25-
public newFilter(filter) {
23+
export class AWSElasticSearchQuery extends ElasticSearchQuery {
24+
public override newFilter(filter) {
2625
return new AWSElasticSearchQueryFilter(this, filter);
2726
}
2827

29-
public convertTz(field) {
30-
return `${field}`; // TODO
31-
}
32-
33-
public timeStampCast(value) {
34-
return `${value}`;
35-
}
36-
37-
public dateTimeCast(value) {
38-
return `${value}`; // TODO
39-
}
40-
41-
public subtractInterval(date, interval) {
28+
public override subtractInterval(date, interval) {
4229
return `DATE_SUB(${date}, INTERVAL ${interval})`;
4330
}
4431

45-
public addInterval(date, interval) {
32+
public override addInterval(date, interval) {
4633
return `DATE_ADD(${date}, INTERVAL ${interval})`;
4734
}
4835

49-
public timeGroupedColumn(granularity, dimension) {
36+
public override timeGroupedColumn(granularity, dimension) {
5037
return GRANULARITY_TO_INTERVAL[granularity](dimension);
5138
}
5239

53-
public groupByClause() {
54-
if (this.ungrouped) {
55-
return '';
56-
}
57-
const dimensionsForSelect = this.dimensionsForSelect();
58-
const dimensionColumns = R.flatten(dimensionsForSelect.map(s => s.selectColumns() && s.dimensionSql()))
59-
.filter(s => !!s);
60-
return dimensionColumns.length ? ` GROUP BY ${dimensionColumns.join(', ')}` : '';
61-
}
62-
63-
public orderHashToString(hash) {
64-
if (!hash || !hash.id) {
65-
return null;
66-
}
67-
68-
const fieldAlias = this.getFieldAlias(hash.id);
69-
70-
if (fieldAlias === null) {
71-
return null;
72-
}
73-
74-
const direction = hash.desc ? 'DESC' : 'ASC';
75-
return `${fieldAlias} ${direction}`;
76-
}
77-
78-
public getFieldAlias(id) {
79-
const equalIgnoreCase = (a, b) => (
80-
typeof a === 'string' && typeof b === 'string' && a.toUpperCase() === b.toUpperCase()
81-
);
82-
83-
let field;
84-
85-
field = this.dimensionsForSelect().find(d => equalIgnoreCase(d.dimension, id));
86-
87-
if (field) {
88-
return field.dimensionSql();
89-
}
90-
91-
field = this.measures.find(d => equalIgnoreCase(d.measure, id) || equalIgnoreCase(d.expressionName, id));
92-
93-
if (field) {
94-
return field.aliasName(); // TODO isn't supported
95-
}
96-
97-
return null;
98-
}
99-
100-
public escapeColumnName(name) {
101-
return `${name}`; // TODO
40+
public override unixTimestampSql() {
41+
return 'EXTRACT(EPOCH FROM NOW())';
10242
}
10343
}

0 commit comments

Comments
 (0)