diff --git a/.github/workflows/drivers-tests.yml b/.github/workflows/drivers-tests.yml
index 11f6bcb41c6e9..3daac8a937fd2 100644
--- a/.github/workflows/drivers-tests.yml
+++ b/.github/workflows/drivers-tests.yml
@@ -22,6 +22,7 @@ on:
- 'packages/cubejs-databricks-jdbc-driver/**'
- 'packages/cubejs-mssql-driver/**'
- 'packages/cubejs-mysql-driver/**'
+ - 'packages/cubejs-pinot-driver/**'
- 'packages/cubejs-postgres-driver/**'
- 'packages/cubejs-redshift-driver/**'
- 'packages/cubejs-snowflake-driver/**'
@@ -49,6 +50,7 @@ on:
- 'packages/cubejs-databricks-jdbc-driver/**'
- 'packages/cubejs-mssql-driver/**'
- 'packages/cubejs-mysql-driver/**'
+ - 'packages/cubejs-pinot-driver/**'
- 'packages/cubejs-postgres-driver/**'
- 'packages/cubejs-redshift-driver/**'
- 'packages/cubejs-snowflake-driver/**'
@@ -266,6 +268,7 @@ jobs:
- mssql
- mysql
- oracle
+ - pinot
- postgres
- postgres-pre-agg-credentials
- redshift
diff --git a/docs-mintlify/docs/explore-analyze/workbooks/index.mdx b/docs-mintlify/docs/explore-analyze/workbooks/index.mdx
index 3a2e3b6337ca5..af3ccae67122d 100644
--- a/docs-mintlify/docs/explore-analyze/workbooks/index.mdx
+++ b/docs-mintlify/docs/explore-analyze/workbooks/index.mdx
@@ -10,6 +10,74 @@ analysis, and share trusted insights with your team.
Workbooks can contain one or more tabs, each providing a different way to query and analyze your data. Tabs enable you to organize multiple analyses within a single workbook, making it easy to explore different aspects of your data or combine insights from different sources.
+## New tab page
+
+When you open [Explore](/docs/explore-analyze/explore) or add a new tab in a workbook, Cube shows
+the **new tab page** — a single launchpad for starting a report. From here you can search across
+your data model, browse starting points by type, or jump straight to pasting a query, asking an AI
+agent, or uploading a file.
+
+### Searching and browsing
+
+A search box sits at the top of the launchpad. Typing filters every category at once; categories
+with no matches appear disabled, so you can tell at a glance which ones hold results.
+
+The category selector lets you switch between starting-point types:
+
+- **View groups** — browse [view groups](/docs/data-modeling/view-groups) as folders. Drilling
+ into a group reveals its sub-groups and views.
+- **Views** — every [view](/docs/data-modeling/views) in the model. Search also matches a view's
+ measures and dimensions; when a view matches through a member, the row notes which one.
+- **Workbooks** — drill into an existing workbook and pick one of its reports to reuse its query
+ as the starting point for the new report. The workbook you are currently in and empty tabs
+ (which have no query to reuse) appear disabled.
+- **Source tables** — raw tables from your connected
+ [data sources](/admin/connect-to-data/data-sources/index), browsable by data source and schema.
+
+Click through the list to drill down to an individual view, report, or table. Once you reach a
+starting point, the data model sidebar activates so you can continue building your query there.
+
+### Starting from a pasted query, an agent, or a file
+
+The launchpad also offers shortcuts at the bottom:
+
+- **Paste semantic SQL query** — opens the SQL panel so you can paste a semantic SQL query. The
+ dropdown adds **Paste source SQL query** (raw data-source SQL), **Paste JSON query** (a
+ [REST API query](/reference/core-data-apis/rest-api/query-format)), and **Paste GraphQL query** (a
+ [GraphQL API query](/reference/core-data-apis/graphql-api)) — the JSON and GraphQL queries are
+ converted to a semantic query for you.
+- **Ask Cube agent** — opens the chat sidebar so you can describe the report you want in natural
+ language.
+- **Upload file** — opens the file upload flow.
+
+### Configuring the launchpad
+
+Administrators can tailor the launchpad per deployment under **Settings → Configuration**, in the
+**Workbooks and Explore** section. Two settings are available.
+
+**Available tabs** — choose which categories appear on the launchpad. **View groups** and **Views**
+are always shown and cannot be turned off; **Workbooks** and **Source tables** can each be enabled
+or disabled to simplify the starting points your users see.
+
+**Default view group** — set a default view group so the launchpad opens inside a specific
+top-level view group instead of listing all of them, useful for steering users toward a curated set
+of governed starting points.
+
+
+
+ Go to **Settings → Configuration** for your deployment.
+
+
+ In the **Workbooks and Explore** section, select the tabs to show and, optionally, enter the
+ **name** of the view group the launchpad should open inside. Leave the group empty to show all
+ view groups. Save your changes.
+
+
+
+When a default view group is set, new Explore and workbook tabs open inside that group. You can
+still navigate up to **All view groups** to browse everything. If the configured group no longer
+exists, the launchpad falls back to showing all categories.
+
## Tab types
Workbooks support two types of tabs, each designed for different querying approaches:
diff --git a/packages/cubejs-backend-native/js/ColumnarChunkBuilder.ts b/packages/cubejs-backend-native/js/ColumnarChunkBuilder.ts
new file mode 100644
index 0000000000000..e9dd1d8fc0408
--- /dev/null
+++ b/packages/cubejs-backend-native/js/ColumnarChunkBuilder.ts
@@ -0,0 +1,69 @@
+import { JsRawColumnarData } from './ResultWrapper';
+
+/**
+ * Incremental columnar accumulator for streaming.
+ *
+ * Rows are pivoted into per-column arrays as they arrive, so we never
+ * hold the chunk's row objects and the transposed columns alive at the
+ * same time (as buffering rows and calling `rowsToColumnar` at the
+ * boundary does). Measured on 8192-row chunks this trims ~22% off the
+ * live heap retained at the serialization boundary — the row-object
+ * shells the buffered path keeps until flush.
+ */
+export class ColumnarChunkBuilder {
+ private members: string[] | null = null;
+
+ protected columns: any[][] = [];
+
+ protected rowCount = 0;
+
+ public constructor(private readonly capacity: number) {
+ //
+ }
+
+ public push(row: T): void {
+ if (this.members === null) {
+ this.members = Object.keys(row);
+ this.columns = this.members.map(() => new Array(this.capacity));
+ }
+
+ const { members, columns, rowCount } = this;
+ for (let j = 0; j < members.length; j++) {
+ columns[j][rowCount] = row[members[j] as keyof T];
+ }
+
+ this.rowCount++;
+ }
+
+ public count(): number {
+ return this.rowCount;
+ }
+
+ public isEmpty(): boolean {
+ return this.rowCount === 0;
+ }
+
+ public toRawColumnar(): JsRawColumnarData {
+ if (this.members) {
+ // A full chunk uses its columns as-is; a short final chunk is sliced
+ // to length so preallocated tail slots are not serialized.
+ const columns = this.rowCount < this.capacity
+ ? this.columns.map((col) => col.slice(0, this.rowCount))
+ : this.columns;
+
+ return { members: this.members, columns };
+ }
+
+ return { members: [], columns: [] };
+ }
+
+ public toBuffer(): Buffer {
+ return Buffer.from(JSON.stringify(this.toRawColumnar()));
+ }
+
+ public reset(): void {
+ this.members = null;
+ this.columns = [];
+ this.rowCount = 0;
+ }
+}
diff --git a/packages/cubejs-backend-native/js/ResultWrapper.ts b/packages/cubejs-backend-native/js/ResultWrapper.ts
index 8cfd378118b2e..b5a1b5d15d417 100644
--- a/packages/cubejs-backend-native/js/ResultWrapper.ts
+++ b/packages/cubejs-backend-native/js/ResultWrapper.ts
@@ -54,6 +54,24 @@ export function rowsToColumnar(rawData: any): JsRawColumnarData {
return { members, columns };
}
+/**
+ * Pivot to columnar before serializing: the row-oriented form repeats
+ * every column name on every row, which inflates JSON size and forces
+ * the Rust side to allocate a per-row map before transposing back to
+ * its native columnar `QueryResult` representation.
+ *
+ * Serialize to a Buffer so the Rust side can decode via
+ * serde_json::from_slice instead of walking a JsValue through the
+ * Neon bridge with JsValueDeserializer. On 5 MB of AoO rows
+ * (~21k rows × 8 fields) the JsValue walk costs ~80 ms locally;
+ * Buffer + serde_json is ~7× faster (M3 MAX) and tracks V8's JSON.parse
+ * (~11 ms on the same payload). On a real server it should be 3-6× slower,
+ * so avoiding the JsValue walk matters even more there.
+ */
+export function rowsToColumnarBuffer(rawData: any): Buffer {
+ return Buffer.from(JSON.stringify(rowsToColumnar(rawData)));
+}
+
class BaseWrapper {
public readonly isWrapper: boolean = true;
}
@@ -191,19 +209,7 @@ export class ResultWrapper extends BaseWrapper implements DataResult {
return [this[NATIVE_REFERENCE]];
}
- // Pivot to columnar before serializing: the row-oriented form repeats
- // every column name on every row, which inflates JSON size and forces
- // the Rust side to allocate a per-row map before transposing back to
- // its native columnar `QueryResult` representation.
- //
- // Serialize to a Buffer so the Rust side can decode via
- // serde_json::from_slice instead of walking a JsValue through the
- // Neon bridge with JsValueDeserializer. On 5 MB of AoO rows
- // (~21k rows × 8 fields) the JsValue walk costs ~80 ms locally;
- // Buffer + serde_json is ~7× faster (M3 MAX) and tracks V8's JSON.parse
- // (~11 ms on the same payload). On a real server it should be 3-6× slower,
- // so avoiding the JsValue walk matters even more there.
- return [Buffer.from(JSON.stringify(rowsToColumnar(this.jsResult)))];
+ return [rowsToColumnarBuffer(this.jsResult)];
}
public setTransformData(td: any) {
diff --git a/packages/cubejs-backend-native/js/index.ts b/packages/cubejs-backend-native/js/index.ts
index 24715c926b0e0..0178709a8f5b7 100644
--- a/packages/cubejs-backend-native/js/index.ts
+++ b/packages/cubejs-backend-native/js/index.ts
@@ -5,6 +5,7 @@ import { Writable } from 'stream';
import type { Request as ExpressRequest } from 'express';
import { CacheMode } from '@cubejs-backend/shared';
import { NativeQueryResultRef, ResultWrapper } from './ResultWrapper';
+import { ColumnarChunkBuilder } from './ColumnarChunkBuilder';
export * from './ResultWrapper';
@@ -285,17 +286,17 @@ function wrapNativeFunctionWithStream(
if (response && response.stream) {
writerOrChannel.start();
- let chunkBuffer: any[] = [];
+ const chunkBuilder = new ColumnarChunkBuilder(chunkLength);
const writable = new Writable({
objectMode: true,
highWaterMark: chunkLength,
write(row: any, encoding: BufferEncoding, callback: (error?: (Error | null)) => void) {
- chunkBuffer.push(row);
- if (chunkBuffer.length < chunkLength) {
+ chunkBuilder.push(row);
+ if (chunkBuilder.count() < chunkLength) {
callback(null);
} else {
- const toSend = chunkBuffer;
- chunkBuffer = [];
+ const toSend = chunkBuilder.toBuffer();
+ chunkBuilder.reset();
writerOrChannel.chunk(toSend, callback);
}
},
@@ -307,9 +308,9 @@ function wrapNativeFunctionWithStream(
writerOrChannel.end(callback);
}
};
- if (chunkBuffer.length > 0) {
- const toSend = chunkBuffer;
- chunkBuffer = [];
+ if (!chunkBuilder.isEmpty()) {
+ const toSend = chunkBuilder.toBuffer();
+ chunkBuilder.reset();
writerOrChannel.chunk(toSend, end);
} else {
end(null);
diff --git a/packages/cubejs-backend-native/src/orchestrator.rs b/packages/cubejs-backend-native/src/orchestrator.rs
index cce0910fed1c5..4524a7e502b62 100644
--- a/packages/cubejs-backend-native/src/orchestrator.rs
+++ b/packages/cubejs-backend-native/src/orchestrator.rs
@@ -2,11 +2,10 @@ use crate::node_obj_deserializer::JsValueDeserializer;
use crate::transport::MapCubeErrExt;
use cubeorchestrator::query_message_parser::QueryResult;
use cubeorchestrator::query_result_transform::{
- DBResponsePrimitive, InternedKeyLookup, RequestResultData, RequestResultDataMulti,
- TransformedData,
+ DBResponsePrimitive, RequestResultData, RequestResultDataMulti, TransformedData,
};
use cubeorchestrator::transport::{JsRawColumnarData, TransformDataRequest};
-use cubesql::compile::engine::df::scan::{ColumnarValueObject, FieldValue, ValueObject};
+use cubesql::compile::engine::df::scan::{ColumnarValueObject, FieldValue};
use cubesql::CubeError;
use neon::context::{Context, FunctionContext, ModuleContext};
use neon::handle::Handle;
@@ -144,89 +143,6 @@ fn db_primitive_to_field_value(value: &DBResponsePrimitive) -> FieldValue<'_> {
}
}
-impl ValueObject for ResultWrapper {
- fn len(&mut self) -> Result {
- if self.transformed_data.is_none() {
- self.transform_result()?;
- }
-
- let data = self.transformed_data.as_ref().unwrap();
-
- match data {
- TransformedData::Compact {
- members: _members,
- dataset,
- } => Ok(dataset.len()),
- TransformedData::Columnar {
- members: _members,
- columns,
- } => Ok(columns.first().map(|c| c.len()).unwrap_or(0)),
- TransformedData::Vanilla(dataset) => Ok(dataset.len()),
- }
- }
-
- fn get(&mut self, index: usize, field_name: &str) -> Result, CubeError> {
- if self.transformed_data.is_none() {
- self.transform_result()?;
- }
-
- let data = self.transformed_data.as_ref().unwrap();
-
- let value = match data {
- TransformedData::Compact { members, dataset } => {
- let Some(row) = dataset.get(index) else {
- return Err(CubeError::internal(format!(
- "Unexpected response from Cube, can't get {} row",
- index
- )));
- };
-
- let Some(member_index) = members.iter().position(|m| m == field_name) else {
- // Missing field → NULL, matching `Vanilla` semantics below.
- return Ok(FieldValue::Null);
- };
-
- row.get(member_index).unwrap_or(&DBResponsePrimitive::Null)
- }
- TransformedData::Columnar { members, columns } => {
- let Some(member_index) = members.iter().position(|m| m == field_name) else {
- // Missing field → NULL, matching `Vanilla` semantics below.
- return Ok(FieldValue::Null);
- };
-
- let Some(column) = columns.get(member_index) else {
- return Err(CubeError::internal(format!(
- "Unexpected response from Cube, missing column for '{}'",
- field_name
- )));
- };
-
- let Some(value) = column.get(index) else {
- return Err(CubeError::user(format!(
- "Unexpected response from Cube, can't get {} row",
- index
- )));
- };
-
- value
- }
- TransformedData::Vanilla(dataset) => {
- let Some(row) = dataset.get(index) else {
- return Err(CubeError::internal(format!(
- "Unexpected response from Cube, can't get {} row",
- index
- )));
- };
-
- row.get(&InternedKeyLookup::new(field_name))
- .unwrap_or(&DBResponsePrimitive::Null)
- }
- };
-
- Ok(db_primitive_to_field_value(value))
- }
-}
-
impl ColumnarValueObject for ResultWrapper {
fn len(&mut self) -> Result {
if self.transformed_data.is_none() {
diff --git a/packages/cubejs-backend-native/src/stream.rs b/packages/cubejs-backend-native/src/stream.rs
index 9bc270ed1d01a..38b907ed84f6f 100644
--- a/packages/cubejs-backend-native/src/stream.rs
+++ b/packages/cubejs-backend-native/src/stream.rs
@@ -1,7 +1,6 @@
use cubesql::compile::engine::df::scan::{
- transform_response, FieldValue, MemberField, RecordBatch, SchemaRef, ValueObject,
+ transform_response, JsonColumnarValueObject, MemberField, RecordBatch, SchemaRef,
};
-use std::borrow::Cow;
use std::cell::RefCell;
use std::future::Future;
@@ -15,13 +14,12 @@ use crate::channel::call_js_fn;
use cubesql::CubeError;
use neon::prelude::*;
+use neon::types::buffer::TypedArray;
use tokio::sync::{oneshot, Semaphore};
#[cfg(feature = "neon-debug")]
use log::trace;
-use neon::types::JsDate;
-
use crate::utils::bind_method;
use tokio::sync::mpsc::{channel as mpsc_channel, Receiver, Sender};
@@ -256,83 +254,6 @@ fn wait_for_future_and_execute_callback(
});
}
-pub struct JsValueObject<'a> {
- pub cx: FunctionContext<'a>,
- pub handle: Handle<'a, JsArray>,
-}
-
-fn js_value_to_json_string<'a, C: Context<'a>>(
- cx: &mut C,
- value: Handle<'a, JsValue>,
-) -> Result {
- let global = cx.global_object();
- let json = global
- .get::(cx, "JSON")
- .map_err(|e| CubeError::internal(format!("Can't get JSON global: {}", e)))?;
- let stringify = json
- .get::(cx, "stringify")
- .map_err(|e| CubeError::internal(format!("Can't get JSON.stringify: {}", e)))?;
- let undefined = cx.undefined().upcast::();
- let result = stringify
- .call(cx, undefined, [value])
- .map_err(|e| CubeError::internal(format!("JSON.stringify failed: {}", e)))?;
- let s = result.downcast::(cx).map_err(|e| {
- CubeError::internal(format!("JSON.stringify did not return a string: {}", e))
- })?;
- Ok(s.value(cx))
-}
-
-impl ValueObject for JsValueObject<'_> {
- fn len(&mut self) -> Result {
- Ok(self.handle.len(&mut self.cx) as usize)
- }
-
- fn get(&mut self, index: usize, field_name: &str) -> Result, CubeError> {
- let value = self
- .handle
- .get::(&mut self.cx, index as u32)
- .map_err(|e| {
- CubeError::internal(format!("Can't get object at array index {}: {}", index, e))
- })?
- .get::(&mut self.cx, field_name)
- .map_err(|e| {
- CubeError::internal(format!("Can't get '{}' field value: {}", field_name, e))
- })?;
- if let Ok(s) = value.downcast::(&mut self.cx) {
- Ok(FieldValue::String(Cow::Owned(s.value(&mut self.cx))))
- } else if let Ok(n) = value.downcast::(&mut self.cx) {
- Ok(FieldValue::Number(n.value(&mut self.cx)))
- } else if let Ok(b) = value.downcast::(&mut self.cx) {
- Ok(FieldValue::Bool(b.value(&mut self.cx)))
- } else if value.downcast::(&mut self.cx).is_ok()
- || value.downcast::(&mut self.cx).is_ok()
- {
- Ok(FieldValue::Null)
- } else if value.is_a::(&mut self.cx) {
- Ok(FieldValue::String(Cow::Owned(js_value_to_json_string(
- &mut self.cx,
- value,
- )?)))
- } else if let Ok(b) = value.downcast::(&mut self.cx) {
- // TODO: Support it?
- Err(CubeError::internal(format!(
- "Expected primitive value but found JsDate({:?})",
- b
- )))
- } else if value.is_a::(&mut self.cx) {
- Ok(FieldValue::String(Cow::Owned(js_value_to_json_string(
- &mut self.cx,
- value,
- )?)))
- } else {
- Err(CubeError::internal(format!(
- "Expected primitive value but found: {:?}",
- value
- )))
- }
- }
-}
-
fn js_stream_push_chunk(mut cx: FunctionContext) -> JsResult {
#[cfg(feature = "neon-debug")]
trace!("JsWriteStream.push_chunk");
@@ -340,26 +261,24 @@ fn js_stream_push_chunk(mut cx: FunctionContext) -> JsResult {
let this = cx
.this::()?
.downcast_or_throw::, _>(&mut cx)?;
- let chunk_array = cx.argument::(0)?;
let callback = cx.argument::(1)?.root(&mut cx);
- let mut value_object = JsValueObject {
- cx,
- handle: chunk_array,
- };
+
+ let chunk_buffer = cx.argument::(0)?;
+ let mut value_object =
+ match serde_json::from_slice::(chunk_buffer.as_slice(&cx)) {
+ Ok(v) => v,
+ Err(e) => return cx.throw_error(format!("Can't parse columnar chunk JSON: {}", e)),
+ };
let value =
match transform_response(&mut value_object, this.schema.clone(), &this.member_fields) {
Ok(value) => value,
- Err(e) => return value_object.cx.throw_error(e.message),
+ Err(e) => return cx.throw_error(e.message),
};
+
let future = this.push_chunk(value);
- wait_for_future_and_execute_callback(
- this.tokio_handle.clone(),
- value_object.cx.channel(),
- callback,
- future,
- );
-
- Ok(value_object.cx.undefined())
+ wait_for_future_and_execute_callback(this.tokio_handle.clone(), cx.channel(), callback, future);
+
+ Ok(cx.undefined())
}
fn js_stream_start(mut cx: FunctionContext) -> JsResult {
diff --git a/packages/cubejs-backend-native/src/transport.rs b/packages/cubejs-backend-native/src/transport.rs
index be4f17623b66e..f6bca69f71deb 100644
--- a/packages/cubejs-backend-native/src/transport.rs
+++ b/packages/cubejs-backend-native/src/transport.rs
@@ -15,8 +15,8 @@ use crate::{
use async_trait::async_trait;
use cubeorchestrator::query_result_transform::RequestResultData;
use cubesql::compile::engine::df::scan::{
- build_response_schema, convert_transport_response_columnar, transform_columnar_response,
- CacheMode, MemberField, RecordBatch, SchemaRef,
+ build_response_schema, convert_transport_response, transform_response, CacheMode, MemberField,
+ RecordBatch, SchemaRef,
};
use cubesql::compile::engine::df::wrapper::SqlQuery;
use cubesql::transport::{
@@ -524,11 +524,7 @@ impl TransportService for NodeBridgeTransport {
}
};
- break convert_transport_response_columnar(
- response,
- schema.clone(),
- member_fields,
- );
+ break convert_transport_response(response, schema.clone(), member_fields);
}
ValueFromJs::ResultWrapper(result_wrappers) => {
break result_wrappers
@@ -540,11 +536,7 @@ impl TransportService for NodeBridgeTransport {
wrapper.external,
);
- transform_columnar_response(
- &mut wrapper,
- updated_schema,
- &member_fields,
- )
+ transform_response(&mut wrapper, updated_schema, &member_fields)
})
.collect::, _>>();
}
diff --git a/packages/cubejs-pinot-driver/src/PinotDriver.ts b/packages/cubejs-pinot-driver/src/PinotDriver.ts
index e5016cd02f32a..77b9420eeaeb0 100644
--- a/packages/cubejs-pinot-driver/src/PinotDriver.ts
+++ b/packages/cubejs-pinot-driver/src/PinotDriver.ts
@@ -1,12 +1,8 @@
-/**
- * @copyright Cube Dev, Inc.
- * @license Apache-2.0
- * @fileoverview The `PinotDriver` and related types declaration.
- */
-
import {
DriverInterface,
StreamTableData,
+ DownloadQueryResultsOptions,
+ DownloadQueryResultsResult,
BaseDriver
} from '@cubejs-backend/base-driver';
import {
@@ -68,20 +64,27 @@ type PinotResponse = {
traceInfo: any
};
-/**
- * Presto driver class.
- */
+const PinotTypeToGenericType: Record = {
+ string: 'text',
+ int: 'int',
+ long: 'bigint',
+ float: 'double',
+ double: 'double',
+ big_decimal: 'decimal',
+ boolean: 'boolean',
+ timestamp: 'timestamp',
+ json: 'text',
+ bytes: 'text',
+};
+
export class PinotDriver extends BaseDriver implements DriverInterface {
- /**
- * Returns default concurrency value.
- */
public static getDefaultConcurrency() {
return 10;
}
- private config: PinotDriverConfiguration;
+ protected readonly config: PinotDriverConfiguration;
- private url: string;
+ protected readonly url: string;
public static dialectClass() {
return PinotQuery;
@@ -116,7 +119,16 @@ export class PinotDriver extends BaseDriver implements DriverInterface {
...config
};
- this.url = `${this.config.host}:${this.config.port}/query/sql`;
+ const useSsl = getEnv('dbSsl', { dataSource, preAggregations });
+ const rawHost = this.config.host || '';
+ const host = /^https?:\/\//i.test(rawHost)
+ ? rawHost
+ : `${useSsl ? 'https' : 'http'}://${rawHost}`;
+ this.url = `${host}:${this.config.port}/query/sql`;
+ }
+
+ public readOnly(): boolean {
+ return true;
}
public testConnection() {
@@ -160,7 +172,7 @@ export class PinotDriver extends BaseDriver implements DriverInterface {
return { Authorization: `Basic ${encodedCredentials}` };
}
- public queryPromised(query: string): Promise {
+ protected async request(query: string): Promise {
const toError = (error: any) => new Error(error.error ? `${error.message}\n${error.error}` : error.message);
const request: Request = new Request(this.url, {
@@ -175,26 +187,51 @@ export class PinotDriver extends BaseDriver implements DriverInterface {
})
});
- return new Promise((resolve, reject) => {
- fetch(request)
- .then(async (response: Response) => {
- if (!response.ok) {
- if (response.status === 401) {
- return reject(toError({ message: 'Unauthorized request' }));
- }
-
- return reject(toError({ message: 'Unexpected error' }));
- }
- const pinotResponse: PinotResponse = await response.json();
-
- if (pinotResponse?.exceptions?.length) {
- return reject(toError(pinotResponse.exceptions[0]));
- }
-
- return resolve(this.normalizeResultOverColumns(pinotResponse.resultTable.rows, pinotResponse.resultTable.dataSchema.columnNames));
- })
- .catch((error: any) => reject(toError(error)));
- });
+ let response: Response;
+
+ try {
+ response = await fetch(request);
+ } catch (error: any) {
+ throw toError(error);
+ }
+
+ if (!response.ok) {
+ throw toError({ message: response.status === 401 ? 'Unauthorized request' : 'Unexpected error' });
+ }
+
+ const result: PinotResponse = await response.json();
+
+ if (result?.exceptions?.length) {
+ throw toError(result.exceptions[0]);
+ }
+
+ return result;
+ }
+
+ public async queryPromised(query: string): Promise {
+ const { resultTable } = await this.request(query);
+ return this.normalizeResultOverColumns(resultTable.rows, resultTable.dataSchema.columnNames);
+ }
+
+ public async downloadQueryResults(
+ query: string,
+ values: unknown[],
+ _options: DownloadQueryResultsOptions,
+ ): Promise {
+ const { resultTable } = await this.request(this.prepareQueryWithParams(query, values));
+ const { rows, dataSchema } = resultTable;
+
+ return {
+ rows: this.normalizeResultOverColumns(rows, dataSchema.columnNames),
+ types: dataSchema.columnNames.map((name, index) => ({
+ name,
+ type: this.toGenericType(dataSchema.columnDataTypes[index]),
+ })),
+ };
+ }
+
+ protected override toGenericType(columnType: string): string {
+ return PinotTypeToGenericType[columnType.toLowerCase()] || super.toGenericType(columnType);
}
protected override quoteIdentifier(identifier: string): string {
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot.json b/packages/cubejs-testing-drivers/fixtures/pinot.json
new file mode 100644
index 0000000000000..11eaa5aebb583
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot.json
@@ -0,0 +1,363 @@
+{
+ "cube": {
+ "environment": {
+ "CUBEJS_API_SECRET": "mysupersecret",
+ "CUBEJS_CACHE_AND_QUEUE_DRIVER": "cubestore",
+ "CUBEJS_CUBESTORE_HOST": "store",
+ "CUBEJS_DB_TYPE": "pinot",
+ "CUBEJS_DB_HOST": "pinot-broker",
+ "CUBEJS_DB_PORT": "8099",
+ "CUBEJS_DB_USER": "admin",
+ "CUBEJS_DB_PASS": "mysecret",
+ "CUBEJS_DB_PINOT_NULL_HANDLING": "true",
+ "CUBEJS_PG_SQL_PORT": "5656",
+ "CUBEJS_SQL_USER": "admin",
+ "CUBEJS_SQL_PASSWORD": "admin_password",
+ "CUBESQL_SQL_PUSH_DOWN": "true",
+ "CUBEJS_TESSERACT_SQL_PLANNER": "${DRIVERS_TESTS_CUBEJS_TESSERACT_SQL_PLANNER}",
+ "CUBEJS_TESSERACT_PRE_AGGREGATIONS": "${DRIVERS_TESTS_CUBEJS_TESSERACT_SQL_PLANNER}",
+ "CUBEJS_TRANSPILATION_NATIVE": "${DRIVERS_TESTS_CUBEJS_TRANSPILATION_NATIVE}"
+ },
+ "depends_on": ["pinot-broker"],
+ "links": ["pinot-broker"],
+ "ports" : ["4000", "5656"]
+ },
+ "services": {
+ "zookeeper": {
+ "image": "zookeeper:latest",
+ "hostname": "zookeeper",
+ "ports": ["2181"],
+ "environment": {
+ "ZOO_MY_ID": "1",
+ "ZOO_PORT": "2181",
+ "ZOO_SERVERS": "server.1=zookeeper:2888:3888;2181"
+ },
+ "healthcheck": {
+ "test": "nc -z localhost 2181 || exit -1",
+ "interval": "10s",
+ "timeout": "5s",
+ "retries": 3,
+ "start_period": "2s"
+ }
+ },
+ "pinot-controller": {
+ "image": "apachepinot/pinot:1.1.0",
+ "hostname": "pinot-controller",
+ "restart": "unless-stopped",
+ "command": "StartController -configFileName /tmp/data/test-resources/controller.conf",
+ "ports": ["9000"],
+ "depends_on": { "zookeeper": { "condition": "service_healthy" } },
+ "healthcheck": {
+ "test": "curl -f \"http://localhost:9000/health\"",
+ "interval": "5s",
+ "timeout": "5s",
+ "retries": 3,
+ "start_period": "10s"
+ },
+ "volumes": ["../fixtures/pinot:/tmp/data/test-resources:ro"]
+ },
+ "pinot-broker": {
+ "image": "apachepinot/pinot:1.1.0",
+ "hostname": "pinot-broker",
+ "restart": "unless-stopped",
+ "command": "StartBroker -zkAddress zookeeper:2181 -configFileName /tmp/data/test-resources/broker.conf",
+ "ports": ["8099"],
+ "depends_on": { "pinot-controller": { "condition": "service_healthy" } },
+ "healthcheck": {
+ "test": "curl -f \"http://localhost:8099/health\"",
+ "interval": "5s",
+ "timeout": "5s",
+ "retries": 3,
+ "start_period": "10s"
+ },
+ "volumes": ["../fixtures/pinot:/tmp/data/test-resources:ro"]
+ },
+ "pinot-server": {
+ "image": "apachepinot/pinot:1.1.0",
+ "hostname": "pinot-server",
+ "restart": "unless-stopped",
+ "command": "StartServer -zkAddress zookeeper:2181",
+ "ports": ["8098", "8097"],
+ "depends_on": { "pinot-broker": { "condition": "service_healthy" } },
+ "healthcheck": {
+ "test": "curl -f \"http://localhost:8097/health\"",
+ "interval": "5s",
+ "timeout": "5s",
+ "retries": 3,
+ "start_period": "10s"
+ }
+ }
+ },
+ "cast": {
+ "SELECT_PREFIX": "",
+ "SELECT_SUFFIX": "",
+ "DATE_PREFIX": "",
+ "DATE_SUFFIX": "",
+ "CREATE_TBL_PREFIX": "",
+ "CREATE_TBL_SUFFIX": "",
+ "CREATE_SUB_PREFIX": "",
+ "CREATE_SUB_SUFFIX": "",
+ "USE_SCHEMA": ""
+ },
+ "tables": {
+ "products": "products",
+ "customers": "customers",
+ "ecommerce": "ecommerce",
+ "bigecommerce": "bigecommerce",
+ "retailcalendar": "retailcalendar"
+ },
+ "preAggregations": {
+ "Products": [],
+ "Customers": [
+ {
+ "name": "RA",
+ "measures": ["CUBE.count", "CUBE.runningTotal"]
+ }
+ ],
+ "ECommerce": [
+ {
+ "name": "SA",
+ "dimensions": ["CUBE.productName"],
+ "measures": [
+ "CUBE.totalQuantity",
+ "CUBE.avgDiscount",
+ "CUBE.totalSales",
+ "CUBE.totalProfit"
+ ]
+ },
+ {
+ "name": "TA",
+ "time_dimension": "CUBE.orderDate",
+ "granularity": "month",
+ "partition_granularity": "month",
+ "dimensions": ["CUBE.productName"],
+ "measures": [
+ "CUBE.totalQuantity",
+ "CUBE.avgDiscount",
+ "CUBE.totalSales",
+ "CUBE.totalProfit"
+ ]
+ }
+ ],
+ "BigECommerce": [
+ {
+ "name": "TA",
+ "time_dimension": "CUBE.orderDate",
+ "granularity": "month",
+ "partition_granularity": "year",
+ "dimensions": ["CUBE.productName", "CUBE.id"],
+ "measures": [
+ "CUBE.totalQuantity",
+ "CUBE.avgDiscount",
+ "CUBE.totalSales",
+ "CUBE.totalProfit"
+ ]
+ },
+ {
+ "name": "CategoryFlat",
+ "dimensions": ["CUBE.productName", "CUBE.id", "CUBE.category"],
+ "measures": [
+ "CUBE.totalProfit"
+ ]
+ }
+ ]
+ },
+ "skip": [
+ "---------------------------------------",
+ "SKIPPED FOR PINOT (query-only driver: no SQL DDL, no streaming download).",
+ "Seeding + teardown are handled by controller ingestion in runEnvironment.",
+ "---------------------------------------",
+ "must creates a data source",
+ "must download query from the data source via stream",
+ "must delete the data source",
+
+ "---------------------------------------",
+ "Internal (source-materialized) pre-aggregations: Pinot cannot CREATE TABLE,",
+ "so only the External (Cube Store) rollups are exercised.",
+ "---------------------------------------",
+ "for the Customers.RollingInternal",
+ "for the ECommerce.SimpleAnalysisInternal",
+ "for the ECommerce.TimeAnalysisInternal",
+
+ "---------------------------------------",
+ "SKIPPED FOR ALL ",
+ "---------------------------------------",
+ "querying Products: dimensions -- doesn't work wo ordering",
+ "querying ECommerce: total quantity, avg discount, total sales, total profit by product + order + total -- rounding in athena",
+ "querying ECommerce: total quantity, avg discount, total sales, total profit by product + order + total -- noisy test",
+
+ "---------------------------------------",
+ "Requires Tesseract (planner-level, not driver-specific).",
+ "---------------------------------------",
+ "querying BigECommerce: rolling window by 2 day without date range",
+ "querying BigECommerce: rolling window by 2 month without date range",
+ "querying BigECommerce: rolling window YTD without date range",
+ "querying custom granularities ECommerce: count by two_mo_by_feb + no dimension + rollingCountByLeading without date range",
+ "querying BigECommerce with Retail Calendar: totalCountRetailYearAgo",
+ "querying BigECommerce with Retail Calendar: totalCountRetailMonthAgo",
+ "querying BigECommerce with Retail Calendar: totalCountRetailWeekAgo",
+ "Tesseract: querying BigECommerce with Retail Calendar: totalCountRetailMonthAgo",
+ "Tesseract: querying BigECommerce with Retail Calendar: totalCountRetailWeekAgo",
+ "Tesseract: SQL API: Timeshift measure from cube",
+ "querying BigECommerce: multi-stage group by time dimension",
+ "querying SwitchSourceTest: simple cross join",
+ "querying SwitchSourceTest: full cross join",
+ "querying SwitchSourceTest: filter by switch dimensions",
+ "querying BigECommerce: SeveralMultiStageMeasures",
+ "querying BigECommerce: two multi-stage branches sharing one pre-aggregation",
+ "querying BigECommerce: base measure plus multi-stage over non-partitioned pre-aggregation",
+
+ "---------------------------------------",
+ "TODO(pinot): driver-specific skips to be finalized after the first local",
+ "`yarn pinot-full --mode=local` run against a live Pinot cluster (rolling",
+ "windows / window functions, multi-stage & time-shift measures, month/quarter/",
+ "year interval arithmetic, and any timestamp/timezone rendering differences the",
+ "Pinot dialect does not yet cover).",
+ "---------------------------------------"
+ ],
+ "tesseractSkip": [
+ "---------------------------------------",
+ "SKIPPED FOR ALL ",
+ "---------------------------------------",
+ "querying Products: dimensions -- doesn't work wo ordering",
+ "querying ECommerce: total quantity, avg discount, total sales, total profit by product + order + total -- rounding in athena",
+ "querying ECommerce: total quantity, avg discount, total sales, total profit by product + order + total -- noisy test",
+
+ "---------------------------------------",
+ "Pinot dialect has no ILIKE (case-insensitive LIKE). Cube/Tesseract renders",
+ "contains/startsWith/endsWith filters as `col ILIKE '%'||?||'%'`, which Pinot",
+ "rejects (`No match found for function signature ILIKE`). Needs a PinotQuery",
+ "Tesseract template (lower()+LIKE or TEXT_MATCH) -- driver follow-up.",
+ "---------------------------------------",
+ "filtering Customers: contains + dimensions, first",
+ "filtering Customers: contains + dimensions, second",
+ "filtering Customers: contains + dimensions, third",
+ "filtering Customers: startsWith + dimensions, first",
+ "filtering Customers: startsWith + dimensions, second",
+ "filtering Customers: startsWith + dimensions, third",
+ "filtering Customers: notStartsWith + dimensions, first",
+ "filtering Customers: notStartsWith + dimensions, second",
+ "filtering Customers: notStartsWith + dimensions, third",
+ "filtering Customers: endsWith filter + dimensions, first",
+ "filtering Customers: endsWith filter + dimensions, second",
+ "filtering Customers: endsWith filter + dimensions, third",
+ "filtering Customers: notEndsWith filter + dimensions, first",
+ "filtering Customers: notEndsWith filter + dimensions, second",
+ "filtering Customers: notEndsWith filter + dimensions, third",
+ "filtering ECommerce: contains dimensions, first",
+ "filtering ECommerce: contains dimensions, second",
+ "filtering ECommerce: contains dimensions, third",
+ "filtering ECommerce: startsWith + dimensions, first",
+ "filtering ECommerce: startsWith + dimensions, second",
+ "filtering ECommerce: startsWith + dimensions, third",
+ "filtering ECommerce: endsWith + dimensions, first",
+ "filtering ECommerce: endsWith + dimensions, second",
+ "filtering ECommerce: endsWith + dimensions, third",
+ "filtering Products: contains + dimensions + order, first",
+ "filtering Products: contains + dimensions + order, second",
+ "filtering Products: contains + dimensions + order, third",
+ "filtering Products: contains with special chars + dimensions",
+ "filtering Products: startsWith filter + dimensions + order, first",
+ "filtering Products: startsWith filter + dimensions + order, second",
+ "filtering Products: startsWith filter + dimensions + order, third",
+ "filtering Products: endsWith filter + dimensions + order, first",
+ "filtering Products: endsWith filter + dimensions + order, second",
+ "filtering Products: endsWith filter + dimensions + order, third",
+
+ "---------------------------------------",
+ "Tesseract renders OFFSET before LIMIT; Pinot's multi-stage engine rejects that",
+ "ordering (expects LIMIT ... OFFSET ...) -- driver/dialect follow-up.",
+ "---------------------------------------",
+ "querying Customers: dimensions + order + total + offset",
+ "querying Customers: dimensions + order + limit + total + offset",
+ "querying ECommerce: dimensions + order + total + offset",
+ "querying ECommerce: dimensions + order + limit + total + offset",
+
+ "---------------------------------------",
+ "Rolling windows / time series: the generated Pinot SQL is rejected by Pinot's",
+ "parser (rolling-window and YTD constructs) -- Pinot Tesseract dialect follow-up.",
+ "---------------------------------------",
+ "querying BigECommerce: time series in rolling window",
+ "querying BigECommerce: rolling window by 2 day",
+ "querying BigECommerce: rolling window by 2 day without date range",
+ "querying BigECommerce: rolling window by 2 week",
+ "querying BigECommerce: rolling window by 2 month",
+ "querying BigECommerce: rolling window by 2 month without date range",
+ "querying BigECommerce: rolling window YTD (month)",
+ "querying BigECommerce: rolling window YTD (month + week)",
+ "querying BigECommerce: rolling window YTD (month + week + no gran)",
+ "querying BigECommerce: rolling window YTD (month + week + day)",
+ "querying BigECommerce: rolling window YTD (month + week + day + no gran)",
+ "querying BigECommerce: rolling window YTD without date range",
+
+ "---------------------------------------",
+ "Custom granularities (half_year / three_months / two_mo rolling): unsupported",
+ "granularity/interval SQL under the Pinot dialect -- follow-up.",
+ "---------------------------------------",
+ "querying custom granularities ECommerce: count by half_year + dimension",
+ "querying custom granularities ECommerce: count by half_year + no dimension",
+ "querying custom granularities ECommerce: count by half_year_by_1st_april + dimension",
+ "querying custom granularities ECommerce: count by half_year_by_1st_april + no dimension",
+ "querying custom granularities ECommerce: count by three_months_by_march + dimension",
+ "querying custom granularities ECommerce: count by three_months_by_march + no dimension",
+ "querying custom granularities ECommerce: count by two_mo_by_feb + no dimension + rollingCountByLeading",
+ "querying custom granularities ECommerce: count by two_mo_by_feb + no dimension + rollingCountByLeading without date range",
+ "querying custom granularities ECommerce: count by two_mo_by_feb + no dimension + rollingCountByTrailing",
+ "querying custom granularities ECommerce: count by two_mo_by_feb + no dimension + rollingCountByUnbounded",
+
+ "---------------------------------------",
+ "Multi-stage & time-shift measures -- not yet supported by the Pinot dialect.",
+ "---------------------------------------",
+ "querying BigECommerce: SeveralMultiStageMeasures",
+ "querying BigECommerce: base measure plus multi-stage over non-partitioned pre-aggregation",
+ "querying BigECommerce with Retail Calendar: totalCountRetailMonthAgo",
+ "querying BigECommerce with Retail Calendar: totalCountRetailWeekAgo",
+ "Tesseract: querying BigECommerce with Retail Calendar: totalCountRetailWeekAgo",
+
+ "---------------------------------------",
+ "SQL API push-down (rollups / rolling windows / window functions) not supported",
+ "on Pinot yet.",
+ "---------------------------------------",
+ "SQL API: Timeshift measure from cube",
+ "SQL API: Simple Rollup",
+ "SQL API: Complex Rollup",
+ "SQL API: Rollup with aliases",
+ "SQL API: Rollup over exprs",
+ "SQL API: Nested Rollup",
+ "SQL API: Nested Rollup with aliases",
+ "SQL API: Nested Rollup over asterisk",
+ "SQL API: Extended nested Rollup over asterisk",
+ "SQL API: SQL push down push to cube quoted alias",
+ "SQL API: Rolling Window YTD (year + month + day + date_trunc equal)",
+ "SQL API: Rolling Window YTD (year + month + day + date_trunc IN)",
+ "SQL API: Window function over measure (running total)",
+
+ "---------------------------------------",
+ "Pre-aggregation build via the HTTP API does not complete for Pinot (builds fine",
+ "in-process -- see the green pinot-core tier); the build test times out, and with",
+ "no rollups built the pre-agg-backed query tests below can't be served. Skipped",
+ "together as a pre-agg-over-API follow-up. Raw-source query coverage still runs.",
+ "---------------------------------------",
+ "must built pre-aggregations",
+ "pre-aggregations Customers: running total without time dimension",
+ "querying ECommerce: partitioned pre-agg",
+ "querying ECommerce: partitioned pre-agg higher granularity",
+ "querying BigECommerce: partitioned pre-agg",
+ "querying custom granularities (with preaggregation) ECommerce: totalQuantity by half_year + no dimension",
+ "querying custom granularities (with preaggregation) ECommerce: totalQuantity by half_year + dimension",
+ "SQL API: ungrouped pre-agg",
+
+ "---------------------------------------",
+ "Additional advanced-query dialect gaps surfaced under Tesseract on Pinot.",
+ "---------------------------------------",
+ "querying ECommerce: total sales, total profit by month + order (date) + total -- doesn't work with the BigQuery",
+ "querying BigECommerce: null sum",
+ "querying BigECommerce: multi-stage group by time dimension",
+ "querying BigECommerce: totalProfitYearAgo",
+ "querying BigECommerce: two multi-stage branches sharing one pre-aggregation",
+ "SQL API: post-aggregate percentage of total",
+ "SQL API: reuse params",
+ "SQL API: metabase count cast to float32 from push down",
+ "Tesseract: SQL API: Timeshift measure from cube"
+ ]
+}
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/bigecommerce_pinot.jobspec.yml b/packages/cubejs-testing-drivers/fixtures/pinot/bigecommerce_pinot.jobspec.yml
new file mode 100644
index 0000000000000..25af78c8211e1
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/bigecommerce_pinot.jobspec.yml
@@ -0,0 +1,23 @@
+executionFrameworkSpec:
+ name: 'standalone'
+ segmentGenerationJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentGenerationJobRunner'
+ segmentTarPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentTarPushJobRunner'
+ segmentUriPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentUriPushJobRunner'
+jobType: SegmentCreationAndTarPush
+inputDirURI: '/tmp/data/test-resources/rawdata/bigecommerce_pinot/'
+includeFileNamePattern: 'glob:**/*.csv'
+outputDirURI: '/tmp/data/segments/bigecommerce_pinot/'
+overwriteOutput: true
+pinotFSSpecs:
+ - scheme: file
+ className: org.apache.pinot.spi.filesystem.LocalPinotFS
+recordReaderSpec:
+ dataFormat: 'csv'
+ className: 'org.apache.pinot.plugin.inputformat.csv.CSVRecordReader'
+ configClassName: 'org.apache.pinot.plugin.inputformat.csv.CSVRecordReaderConfig'
+tableSpec:
+ tableName: 'bigecommerce_pinot'
+pinotClusterSpecs:
+ - controllerURI: 'http://localhost:9000'
+pushJobSpec:
+ pushAttempts: 1
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/bigecommerce_pinot.schema.json b/packages/cubejs-testing-drivers/fixtures/pinot/bigecommerce_pinot.schema.json
new file mode 100644
index 0000000000000..d5ea94ed78629
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/bigecommerce_pinot.schema.json
@@ -0,0 +1,73 @@
+{
+ "schemaName": "bigecommerce_pinot",
+ "dimensionFieldSpecs": [
+ {
+ "name": "order_id",
+ "dataType": "STRING"
+ },
+ {
+ "name": "customer_id",
+ "dataType": "STRING"
+ },
+ {
+ "name": "city",
+ "dataType": "STRING"
+ },
+ {
+ "name": "category",
+ "dataType": "STRING"
+ },
+ {
+ "name": "sub_category",
+ "dataType": "STRING"
+ },
+ {
+ "name": "product_name",
+ "dataType": "STRING"
+ },
+ {
+ "name": "id",
+ "dataType": "INT"
+ },
+ {
+ "name": "row_id",
+ "dataType": "INT"
+ },
+ {
+ "name": "is_returning",
+ "dataType": "BOOLEAN"
+ }
+ ],
+ "metricFieldSpecs": [
+ {
+ "name": "quantity",
+ "dataType": "LONG"
+ },
+ {
+ "name": "sales",
+ "dataType": "DOUBLE"
+ },
+ {
+ "name": "discount",
+ "dataType": "DOUBLE"
+ },
+ {
+ "name": "profit",
+ "dataType": "DOUBLE"
+ }
+ ],
+ "dateTimeFieldSpecs": [
+ {
+ "name": "order_date",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ },
+ {
+ "name": "completed_date",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ }
+ ]
+}
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/bigecommerce_pinot.table.json b/packages/cubejs-testing-drivers/fixtures/pinot/bigecommerce_pinot.table.json
new file mode 100644
index 0000000000000..09d51873a5143
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/bigecommerce_pinot.table.json
@@ -0,0 +1,24 @@
+{
+ "tableName": "bigecommerce_pinot",
+ "tableType": "OFFLINE",
+ "segmentsConfig": {
+ "schemaName": "bigecommerce_pinot",
+ "replication": "1",
+ "timeColumnName": "order_date"
+ },
+ "tenants": {
+ "broker": "DefaultTenant",
+ "server": "DefaultTenant"
+ },
+ "tableIndexConfig": {
+ "loadMode": "MMAP",
+ "nullHandlingEnabled": true
+ },
+ "metadata": {},
+ "ingestionConfig": {
+ "batchIngestionConfig": {
+ "segmentIngestionType": "REFRESH",
+ "segmentIngestionFrequency": "DAILY"
+ }
+ }
+}
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/broker.conf b/packages/cubejs-testing-drivers/fixtures/pinot/broker.conf
new file mode 100644
index 0000000000000..dffabb32f2cce
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/broker.conf
@@ -0,0 +1,3 @@
+pinot.broker.access.control.class=org.apache.pinot.broker.broker.BasicAuthAccessControlFactory
+pinot.broker.access.control.principals=admin
+pinot.broker.access.control.principals.admin.password=mysecret
\ No newline at end of file
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/controller.conf b/packages/cubejs-testing-drivers/fixtures/pinot/controller.conf
new file mode 100644
index 0000000000000..6b06b2a9b3d4c
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/controller.conf
@@ -0,0 +1,9 @@
+controller.helix.cluster.name=PinotCluster
+controller.port=9000
+controller.vip.host=pinot-controller
+controller.vip.port=9000
+controller.data.dir=/var/pinot/controller/data
+controller.zk.str=zookeeper:2181
+pinot.set.instance.id.to.hostname=true
+controller.admin.access.control.principals=admin
+controller.admin.access.control.principals.admin.password=mysecret
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/customers_pinot.jobspec.yml b/packages/cubejs-testing-drivers/fixtures/pinot/customers_pinot.jobspec.yml
new file mode 100644
index 0000000000000..a4c372217b529
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/customers_pinot.jobspec.yml
@@ -0,0 +1,23 @@
+executionFrameworkSpec:
+ name: 'standalone'
+ segmentGenerationJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentGenerationJobRunner'
+ segmentTarPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentTarPushJobRunner'
+ segmentUriPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentUriPushJobRunner'
+jobType: SegmentCreationAndTarPush
+inputDirURI: '/tmp/data/test-resources/rawdata/customers_pinot/'
+includeFileNamePattern: 'glob:**/*.csv'
+outputDirURI: '/tmp/data/segments/customers_pinot/'
+overwriteOutput: true
+pinotFSSpecs:
+ - scheme: file
+ className: org.apache.pinot.spi.filesystem.LocalPinotFS
+recordReaderSpec:
+ dataFormat: 'csv'
+ className: 'org.apache.pinot.plugin.inputformat.csv.CSVRecordReader'
+ configClassName: 'org.apache.pinot.plugin.inputformat.csv.CSVRecordReaderConfig'
+tableSpec:
+ tableName: 'customers_pinot'
+pinotClusterSpecs:
+ - controllerURI: 'http://localhost:9000'
+pushJobSpec:
+ pushAttempts: 1
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/customers_pinot.schema.json b/packages/cubejs-testing-drivers/fixtures/pinot/customers_pinot.schema.json
new file mode 100644
index 0000000000000..2a0f15eb114bf
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/customers_pinot.schema.json
@@ -0,0 +1,16 @@
+{
+ "schemaName": "customers_pinot",
+ "dimensionFieldSpecs": [
+ {
+ "name": "customer_id",
+ "dataType": "STRING"
+ },
+ {
+ "name": "customer_name",
+ "dataType": "STRING"
+ }
+ ],
+ "primaryKeyColumns": [
+ "customer_id"
+ ]
+}
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/customers_pinot.table.json b/packages/cubejs-testing-drivers/fixtures/pinot/customers_pinot.table.json
new file mode 100644
index 0000000000000..54abcfdb08d4e
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/customers_pinot.table.json
@@ -0,0 +1,27 @@
+{
+ "tableName": "customers_pinot",
+ "tableType": "OFFLINE",
+ "segmentsConfig": {
+ "schemaName": "customers_pinot",
+ "replication": "1"
+ },
+ "tenants": {
+ "broker": "DefaultTenant",
+ "server": "DefaultTenant"
+ },
+ "tableIndexConfig": {
+ "loadMode": "MMAP",
+ "nullHandlingEnabled": true
+ },
+ "metadata": {},
+ "ingestionConfig": {
+ "batchIngestionConfig": {
+ "segmentIngestionType": "REFRESH",
+ "segmentIngestionFrequency": "DAILY"
+ }
+ },
+ "isDimTable": true,
+ "dimensionTableConfig": {
+ "disablePreload": false
+ }
+}
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/ecommerce_pinot.jobspec.yml b/packages/cubejs-testing-drivers/fixtures/pinot/ecommerce_pinot.jobspec.yml
new file mode 100644
index 0000000000000..16ffb4335dd33
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/ecommerce_pinot.jobspec.yml
@@ -0,0 +1,23 @@
+executionFrameworkSpec:
+ name: 'standalone'
+ segmentGenerationJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentGenerationJobRunner'
+ segmentTarPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentTarPushJobRunner'
+ segmentUriPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentUriPushJobRunner'
+jobType: SegmentCreationAndTarPush
+inputDirURI: '/tmp/data/test-resources/rawdata/ecommerce_pinot/'
+includeFileNamePattern: 'glob:**/*.csv'
+outputDirURI: '/tmp/data/segments/ecommerce_pinot/'
+overwriteOutput: true
+pinotFSSpecs:
+ - scheme: file
+ className: org.apache.pinot.spi.filesystem.LocalPinotFS
+recordReaderSpec:
+ dataFormat: 'csv'
+ className: 'org.apache.pinot.plugin.inputformat.csv.CSVRecordReader'
+ configClassName: 'org.apache.pinot.plugin.inputformat.csv.CSVRecordReaderConfig'
+tableSpec:
+ tableName: 'ecommerce_pinot'
+pinotClusterSpecs:
+ - controllerURI: 'http://localhost:9000'
+pushJobSpec:
+ pushAttempts: 1
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/ecommerce_pinot.schema.json b/packages/cubejs-testing-drivers/fixtures/pinot/ecommerce_pinot.schema.json
new file mode 100644
index 0000000000000..a160137030318
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/ecommerce_pinot.schema.json
@@ -0,0 +1,65 @@
+{
+ "schemaName": "ecommerce_pinot",
+ "dimensionFieldSpecs": [
+ {
+ "name": "order_id",
+ "dataType": "STRING"
+ },
+ {
+ "name": "customer_id",
+ "dataType": "STRING"
+ },
+ {
+ "name": "city",
+ "dataType": "STRING"
+ },
+ {
+ "name": "category",
+ "dataType": "STRING"
+ },
+ {
+ "name": "sub_category",
+ "dataType": "STRING"
+ },
+ {
+ "name": "product_name",
+ "dataType": "STRING"
+ },
+ {
+ "name": "row_id",
+ "dataType": "INT"
+ }
+ ],
+ "metricFieldSpecs": [
+ {
+ "name": "quantity",
+ "dataType": "LONG"
+ },
+ {
+ "name": "sales",
+ "dataType": "DOUBLE"
+ },
+ {
+ "name": "discount",
+ "dataType": "DOUBLE"
+ },
+ {
+ "name": "profit",
+ "dataType": "DOUBLE"
+ }
+ ],
+ "dateTimeFieldSpecs": [
+ {
+ "name": "order_date",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ },
+ {
+ "name": "completed_date",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ }
+ ]
+}
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/ecommerce_pinot.table.json b/packages/cubejs-testing-drivers/fixtures/pinot/ecommerce_pinot.table.json
new file mode 100644
index 0000000000000..89017b54b11c8
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/ecommerce_pinot.table.json
@@ -0,0 +1,24 @@
+{
+ "tableName": "ecommerce_pinot",
+ "tableType": "OFFLINE",
+ "segmentsConfig": {
+ "schemaName": "ecommerce_pinot",
+ "replication": "1",
+ "timeColumnName": "order_date"
+ },
+ "tenants": {
+ "broker": "DefaultTenant",
+ "server": "DefaultTenant"
+ },
+ "tableIndexConfig": {
+ "loadMode": "MMAP",
+ "nullHandlingEnabled": true
+ },
+ "metadata": {},
+ "ingestionConfig": {
+ "batchIngestionConfig": {
+ "segmentIngestionType": "REFRESH",
+ "segmentIngestionFrequency": "DAILY"
+ }
+ }
+}
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/products_pinot.jobspec.yml b/packages/cubejs-testing-drivers/fixtures/pinot/products_pinot.jobspec.yml
new file mode 100644
index 0000000000000..782c68e41baf9
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/products_pinot.jobspec.yml
@@ -0,0 +1,23 @@
+executionFrameworkSpec:
+ name: 'standalone'
+ segmentGenerationJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentGenerationJobRunner'
+ segmentTarPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentTarPushJobRunner'
+ segmentUriPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentUriPushJobRunner'
+jobType: SegmentCreationAndTarPush
+inputDirURI: '/tmp/data/test-resources/rawdata/products_pinot/'
+includeFileNamePattern: 'glob:**/*.csv'
+outputDirURI: '/tmp/data/segments/products_pinot/'
+overwriteOutput: true
+pinotFSSpecs:
+ - scheme: file
+ className: org.apache.pinot.spi.filesystem.LocalPinotFS
+recordReaderSpec:
+ dataFormat: 'csv'
+ className: 'org.apache.pinot.plugin.inputformat.csv.CSVRecordReader'
+ configClassName: 'org.apache.pinot.plugin.inputformat.csv.CSVRecordReaderConfig'
+tableSpec:
+ tableName: 'products_pinot'
+pinotClusterSpecs:
+ - controllerURI: 'http://localhost:9000'
+pushJobSpec:
+ pushAttempts: 1
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/products_pinot.schema.json b/packages/cubejs-testing-drivers/fixtures/pinot/products_pinot.schema.json
new file mode 100644
index 0000000000000..cee4bcb3fe7b6
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/products_pinot.schema.json
@@ -0,0 +1,22 @@
+{
+ "schemaName": "products_pinot",
+ "dimensionFieldSpecs": [
+ {
+ "name": "category",
+ "dataType": "STRING"
+ },
+ {
+ "name": "sub_category",
+ "dataType": "STRING"
+ },
+ {
+ "name": "product_name",
+ "dataType": "STRING"
+ }
+ ],
+ "primaryKeyColumns": [
+ "category",
+ "sub_category",
+ "product_name"
+ ]
+}
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/products_pinot.table.json b/packages/cubejs-testing-drivers/fixtures/pinot/products_pinot.table.json
new file mode 100644
index 0000000000000..c75af21601c96
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/products_pinot.table.json
@@ -0,0 +1,27 @@
+{
+ "tableName": "products_pinot",
+ "tableType": "OFFLINE",
+ "segmentsConfig": {
+ "schemaName": "products_pinot",
+ "replication": "1"
+ },
+ "tenants": {
+ "broker": "DefaultTenant",
+ "server": "DefaultTenant"
+ },
+ "tableIndexConfig": {
+ "loadMode": "MMAP",
+ "nullHandlingEnabled": true
+ },
+ "metadata": {},
+ "ingestionConfig": {
+ "batchIngestionConfig": {
+ "segmentIngestionType": "REFRESH",
+ "segmentIngestionFrequency": "DAILY"
+ }
+ },
+ "isDimTable": true,
+ "dimensionTableConfig": {
+ "disablePreload": false
+ }
+}
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/bigecommerce_pinot/bigecommerce_pinot.csv b/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/bigecommerce_pinot/bigecommerce_pinot.csv
new file mode 100644
index 0000000000000..e093c2fc6f857
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/bigecommerce_pinot/bigecommerce_pinot.csv
@@ -0,0 +1,45 @@
+id,row_id,order_id,order_date,completed_date,customer_id,city,category,sub_category,product_name,sales,quantity,discount,profit,is_returning
+3060,3060,CA-2017-131492,1603065600000,1603152000000,HH-15010,San Francisco,Furniture,Tables,Anderson Hickey Conga Table Tops & Accessories,24.36800,2,0.20000,-3.35060,false
+523,523,CA-2017-145142,1579737600000,1579824000000,MC-17605,Detroit,Furniture,Tables,Balt Solid Wood Rectangular Table,210.98000,2,0.00000,21.09800,false
+9584,9584,CA-2017-116127,1593043200000,1593129600000,SB-20185,New York City,Furniture,Bookcases,DMI Eclipse Executive Suite Bookcases,400.78400,1,0.20000,-5.00980,false
+8425,8425,CA-2017-150091,1602460800000,1602547200000,NP-18670,Lakewood,Furniture,Bookcases,"Global Adaptabilites Bookcase, Cherry/Storm Gray Finish",2154.90000,5,0.00000,129.29400,false
+2655,2655,CA-2017-112515,1600300800000,1600387200000,AS-10225,Provo,Furniture,Bookcases,"Global Adaptabilites Bookcase, Cherry/Storm Gray Finish",1292.94000,3,0.00000,77.57640,false
+2952,2952,CA-2017-134915,1605139200000,1605225600000,EM-14140,Glendale,Furniture,Chairs,Harbour Creations 67200 Series Stacking Chairs,113.88800,2,0.20000,9.96520,false
+9473,9473,CA-2017-102925,1604534400000,1604620800000,CD-12280,New York City,Furniture,Chairs,Harbour Creations 67200 Series Stacking Chairs,128.12400,2,0.10000,24.20120,false
+5220,5220,CA-2017-145653,1598918400000,1599004800000,CA-12775,Detroit,Furniture,Chairs,Harbour Creations 67200 Series Stacking Chairs,498.26000,7,0.00000,134.53020,false
+4031,4031,CA-2017-124296,1608768000000,1608854400000,CS-12355,Lafayette,Furniture,Chairs,"Iceberg Nesting Folding Chair, 19w x 6d x 43h",232.88000,4,0.00000,60.54880,true
+8621,8621,US-2017-119319,1604620800000,1604707200000,LC-17050,Dallas,Furniture,Furnishings,"Linden 10 Round Wall Clock, Black",30.56000,5,0.60000,-19.86400,false
+3059,3059,CA-2017-131492,1603065600000,1603152000000,HH-15010,San Francisco,Furniture,Furnishings,"Linden 10 Round Wall Clock, Black",30.56000,2,0.00000,10.39040,false
+7425,7425,CA-2017-135069,1586476800000,1586563200000,BS-11755,Philadelphia,Furniture,Furnishings,"Linden 10 Round Wall Clock, Black",36.67200,3,0.20000,6.41760,false
+849,849,CA-2017-107503,1577836800000,1577923200000,GA-14725,Lorain,Furniture,Furnishings,"Linden 10 Round Wall Clock, Black",48.89600,4,0.20000,8.55680,true
+6205,6205,CA-2017-145660,1606780800000,1606867200000,MG-17650,Marion,Furniture,Furnishings,Magna Visual Magnetic Picture Hangers,7.71200,2,0.20000,1.73520,false
+1494,1494,CA-2017-139661,1604016000000,1604188800000,JW-15220,Vancouver,Furniture,Furnishings,Magna Visual Magnetic Picture Hangers,9.64000,2,0.00000,3.66320,false
+3934,3934,CA-2017-123001,1599004800000,1599091200000,AW-10840,Bakersfield,Office Supplies,Art,"OIC #2 Pencils, Medium Soft",9.40000,5,0.00000,2.72600,false
+3448,3448,CA-2017-102554,1591833600000,1591920000000,KN-16705,Auburn,Office Supplies,Art,"OIC #2 Pencils, Medium Soft",3.76000,2,0.00000,1.09040,false
+6459,6459,US-2017-133361,1589414400000,1589500800000,AJ-10780,Baltimore,Office Supplies,Art,"OIC #2 Pencils, Medium Soft",3.76000,2,0.00000,1.09040,false
+6272,6272,CA-2017-102379,1606867200000,1606953600000,BB-11545,Oakland,Office Supplies,Art,Panasonic KP-380BK Classic Electric Pencil Sharpener,179.90000,5,0.00000,44.97500,false
+9619,9619,CA-2017-160633,1605484800000,1605571200000,BS-11380,Bowling,Office Supplies,Art,Panasonic KP-380BK Classic Electric Pencil Sharpener,86.35200,3,0.20000,5.39700,false
+1013,1013,CA-2017-118437,1592352000000,1592438400000,PF-19165,Olympia,Office Supplies,Storage,Project Tote Personal File,14.03000,1,0.00000,4.06870,false
+4012,4012,CA-2017-100811,1605916800000,1606003200000,CC-12475,Philadelphia,Office Supplies,Storage,Recycled Eldon Regeneration Jumbo File,39.29600,4,0.20000,3.92960,false
+2595,2595,CA-2017-149048,1589328000000,1589414400000,BM-11650,Columbus,Office Supplies,Envelopes,Tyvek Side-Opening Peel & Seel Expanding Envelopes,180.96000,2,0.00000,81.43200,false
+2329,2329,CA-2017-138422,1600819200000,1600905600000,KN-16705,Columbus,Office Supplies,Envelopes,Wausau Papers Astrobrights Colored Envelopes,14.35200,3,0.20000,5.20260,false
+4227,4227,CA-2017-120327,1605052800000,1605139200000,WB-21850,Columbus,Office Supplies,Fasteners,"Vinyl Coated Wire Paper Clips in Organizer Box, 800/Box",45.92000,4,0.00000,21.58240,false
+6651,6651,US-2017-124779,1599523200000,1599609600000,BF-11020,Arlington,Office Supplies,Fasteners,"Vinyl Coated Wire Paper Clips in Organizer Box, 800/Box",45.92000,5,0.20000,15.49800,false
+8673,8673,CA-2017-163265,1581811200000,1581897600000,JS-16030,Decatur,Office Supplies,Fasteners,"Vinyl Coated Wire Paper Clips in Organizer Box, 800/Box",18.36800,2,0.20000,6.19920,false
+1995,1995,CA-2017-133648,1593043200000,1593129600000,ML-17755,Columbus,Office Supplies,Fasteners,Plymouth Boxed Rubber Bands by Plymouth,11.30400,3,0.20000,-2.11950,false
+7310,7310,CA-2017-112172,1591747200000,1591833600000,MM-18280,New York City,Office Supplies,Fasteners,Plymouth Boxed Rubber Bands by Plymouth,14.13000,3,0.00000,0.70650,false
+3717,3717,CA-2017-144568,1590710400000,1590796800000,JO-15550,Omaha,Office Supplies,Fasteners,Plymouth Boxed Rubber Bands by Plymouth,23.55000,5,0.00000,1.17750,false
+4882,4882,CA-2017-143567,1604275200000,1604361600000,TB-21175,Columbus,Technology,Accessories,Logitech di_Novo Edge Keyboard,2249.91000,9,0.00000,517.47930,false
+5277,5277,CA-2017-147333,1607904000000,1607990400000,KL-16555,Columbus,Technology,Accessories,Kingston Digital DataTraveler 16GB USB 2.0,44.75000,5,0.00000,8.50250,false
+6125,6125,CA-2017-145772,1591142400000,1591228800000,SS-20140,Los Angeles,Technology,Accessories,Kingston Digital DataTraveler 16GB USB 2.1,44.75000,5,0.00000,8.50250,false
+2455,2455,CA-2017-140949,1584403200000,1584489600000,DB-13405,New York City,Technology,Accessories,Kingston Digital DataTraveler 16GB USB 2.2,71.60000,8,0.00000,13.60400,false
+2661,2661,CA-2017-123372,1606521600000,1606608000000,DG-13300,Columbus,Technology,Phones,Google Nexus 5,1979.89000,11,0.00000,494.97250,false
+3083,3083,US-2017-132297,1590537600000,1590624000000,DW-13480,Louisville,Technology,Phones,Google Nexus 6,539.97000,3,0.00000,134.99250,false
+4161,4161,CA-2017-115546,1589414400000,1589500800000,AH-10465,New York City,Technology,Phones,Google Nexus 7,539.97000,3,0.00000,134.99250,false
+8697,8697,CA-2017-119284,1592179200000,1592265600000,TS-21205,Columbus,Technology,Phones,HTC One,239.97600,3,0.20000,26.99730,false
+7698,7698,CA-2017-151799,1607904000000,1607990400000,BF-11170,Columbus,Technology,Copiers,Canon PC1080F Personal Copier,1199.98000,2,0.00000,467.99220,false
+7174,7174,US-2017-141677,1585180800000,1585267200000,HK-14890,Houston,Technology,Copiers,Canon PC1080F Personal Copier,2399.96000,5,0.20000,569.99050,false
+9618,9618,CA-2017-160633,1605484800000,1605571200000,BS-11380,Columbus,Technology,Copiers,Hewlett Packard 610 Color Digital Copier / Printer,899.98200,3,0.40000,74.99850,false
+8958,8958,CA-2017-105620,1608854400000,1608940800000,JH-15430,Columbus,Technology,Machines,Lexmark 20R1285 X6650 Wireless All-in-One Printer,,2,0.50000,-7.20000,
+8878,8878,CA-2017-126928,1600300800000,1600387200000,GZ-14470,Morristown,Technology,Machines,Lexmark 20R1285 X6650 Wireless All-in-One Printer,600.00000,4,0.00000,225.60000,false
+7293,7293,CA-2017-109183,1607040000000,1607126400000,LR-16915,Columbus,Technology,Machines,Okidata C610n Printer,649.00000,2,0.50000,-272.58000,false
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/customers_pinot/customers_pinot.csv b/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/customers_pinot/customers_pinot.csv
new file mode 100644
index 0000000000000..2b0eae732cea0
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/customers_pinot/customers_pinot.csv
@@ -0,0 +1,42 @@
+customer_id,customer_name
+AH-10465,Customer 1
+AJ-10780,Customer 2
+AS-10225,Customer 3
+AW-10840,Customer 4
+BB-11545,Customer 5
+BF-11020,Customer 6
+BF-11170,Customer 7
+BM-11650,Customer 8
+BS-11380,Customer 9
+BS-11755,Customer 10
+CA-12775,Customer 11
+CC-12475,Customer 12
+CD-12280,Customer 13
+CS-12355,Customer 14
+DB-13405,Customer 15
+DG-13300,Customer 16
+DW-13480,Customer 17
+EM-14140,Customer 18
+GA-14725,Customer 19
+GZ-14470,Customer 20
+HH-15010,Customer 21
+HK-14890,Customer 22
+JH-15430,Customer 23
+JO-15550,Customer 24
+JS-16030,Customer 25
+JW-15220,Customer 26
+KL-16555,Customer 27
+KN-16705,Customer 28
+LC-17050,Customer 29
+LR-16915,Customer 30
+MC-17605,Customer 31
+MG-17650,Customer 32
+ML-17755,Customer 33
+MM-18280,Customer 34
+NP-18670,Customer 35
+PF-19165,Customer 36
+SB-20185,Customer 37
+SS-20140,Customer 38
+TB-21175,Customer 39
+TS-21205,Customer 40
+WB-21850,Customer 41
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/ecommerce_pinot/ecommerce_pinot.csv b/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/ecommerce_pinot/ecommerce_pinot.csv
new file mode 100644
index 0000000000000..61de4fb42c443
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/ecommerce_pinot/ecommerce_pinot.csv
@@ -0,0 +1,45 @@
+row_id,order_id,order_date,completed_date,customer_id,city,category,sub_category,product_name,sales,quantity,discount,profit
+3060,CA-2017-131492,1603065600000,1603152000000,HH-15010,San Francisco,Furniture,Tables,Anderson Hickey Conga Table Tops & Accessories,24.36800,2,0.20000,-3.35060
+523,CA-2017-145142,1579737600000,1579824000000,MC-17605,Detroit,Furniture,Tables,Balt Solid Wood Rectangular Table,210.98000,2,0.00000,21.09800
+9584,CA-2017-116127,1593043200000,1593129600000,SB-20185,New York City,Furniture,Bookcases,DMI Eclipse Executive Suite Bookcases,400.78400,1,0.20000,-5.00980
+8425,CA-2017-150091,1602460800000,1602547200000,NP-18670,Lakewood,Furniture,Bookcases,"Global Adaptabilites Bookcase, Cherry/Storm Gray Finish",2154.90000,5,0.00000,129.29400
+2655,CA-2017-112515,1600300800000,1600387200000,AS-10225,Provo,Furniture,Bookcases,"Global Adaptabilites Bookcase, Cherry/Storm Gray Finish",1292.94000,3,0.00000,77.57640
+2952,CA-2017-134915,1605139200000,1605225600000,EM-14140,Glendale,Furniture,Chairs,Harbour Creations 67200 Series Stacking Chairs,113.88800,2,0.20000,9.96520
+9473,CA-2017-102925,1604534400000,1604620800000,CD-12280,New York City,Furniture,Chairs,Harbour Creations 67200 Series Stacking Chairs,128.12400,2,0.10000,24.20120
+5220,CA-2017-145653,1598918400000,1599004800000,CA-12775,Detroit,Furniture,Chairs,Harbour Creations 67200 Series Stacking Chairs,498.26000,7,0.00000,134.53020
+4031,CA-2017-124296,1608768000000,1608854400000,CS-12355,Lafayette,Furniture,Chairs,"Iceberg Nesting Folding Chair, 19w x 6d x 43h",232.88000,4,0.00000,60.54880
+8621,US-2017-119319,1604620800000,1604707200000,LC-17050,Dallas,Furniture,Furnishings,"Linden 10 Round Wall Clock, Black",30.56000,5,0.60000,-19.86400
+3059,CA-2017-131492,1603065600000,1603152000000,HH-15010,San Francisco,Furniture,Furnishings,"Linden 10 Round Wall Clock, Black",30.56000,2,0.00000,10.39040
+7425,CA-2017-135069,1586476800000,1586563200000,BS-11755,Philadelphia,Furniture,Furnishings,"Linden 10 Round Wall Clock, Black",36.67200,3,0.20000,6.41760
+849,CA-2017-107503,1577836800000,1577923200000,GA-14725,Lorain,Furniture,Furnishings,"Linden 10 Round Wall Clock, Black",48.89600,4,0.20000,8.55680
+6205,CA-2017-145660,1606780800000,1606867200000,MG-17650,Marion,Furniture,Furnishings,Magna Visual Magnetic Picture Hangers,7.71200,2,0.20000,1.73520
+1494,CA-2017-139661,1604016000000,1604188800000,JW-15220,Vancouver,Furniture,Furnishings,Magna Visual Magnetic Picture Hangers,9.64000,2,0.00000,3.66320
+3934,CA-2017-123001,1599004800000,1599091200000,AW-10840,Bakersfield,Office Supplies,Art,"OIC #2 Pencils, Medium Soft",9.40000,5,0.00000,2.72600
+3448,CA-2017-102554,1591833600000,1591920000000,KN-16705,Auburn,Office Supplies,Art,"OIC #2 Pencils, Medium Soft",3.76000,2,0.00000,1.09040
+6459,US-2017-133361,1589414400000,1589500800000,AJ-10780,Baltimore,Office Supplies,Art,"OIC #2 Pencils, Medium Soft",3.76000,2,0.00000,1.09040
+6272,CA-2017-102379,1606867200000,1606953600000,BB-11545,Oakland,Office Supplies,Art,Panasonic KP-380BK Classic Electric Pencil Sharpener,179.90000,5,0.00000,44.97500
+9619,CA-2017-160633,1605484800000,1605571200000,BS-11380,Bowling,Office Supplies,Art,Panasonic KP-380BK Classic Electric Pencil Sharpener,86.35200,3,0.20000,5.39700
+1013,CA-2017-118437,1592352000000,1592438400000,PF-19165,Olympia,Office Supplies,Storage,Project Tote Personal File,14.03000,1,0.00000,4.06870
+4012,CA-2017-100811,1605916800000,1606003200000,CC-12475,Philadelphia,Office Supplies,Storage,Recycled Eldon Regeneration Jumbo File,39.29600,4,0.20000,3.92960
+2595,CA-2017-149048,1589328000000,1589414400000,BM-11650,Columbus,Office Supplies,Envelopes,Tyvek Side-Opening Peel & Seel Expanding Envelopes,180.96000,2,0.00000,81.43200
+2329,CA-2017-138422,1600819200000,1600905600000,KN-16705,Columbus,Office Supplies,Envelopes,Wausau Papers Astrobrights Colored Envelopes,14.35200,3,0.20000,5.20260
+4227,CA-2017-120327,1605052800000,1605139200000,WB-21850,Columbus,Office Supplies,Fasteners,"Vinyl Coated Wire Paper Clips in Organizer Box, 800/Box",45.92000,4,0.00000,21.58240
+6651,US-2017-124779,1599523200000,1599609600000,BF-11020,Arlington,Office Supplies,Fasteners,"Vinyl Coated Wire Paper Clips in Organizer Box, 800/Box",45.92000,5,0.20000,15.49800
+8673,CA-2017-163265,1581811200000,1581897600000,JS-16030,Decatur,Office Supplies,Fasteners,"Vinyl Coated Wire Paper Clips in Organizer Box, 800/Box",18.36800,2,0.20000,6.19920
+1995,CA-2017-133648,1593043200000,1593129600000,ML-17755,Columbus,Office Supplies,Fasteners,Plymouth Boxed Rubber Bands by Plymouth,11.30400,3,0.20000,-2.11950
+7310,CA-2017-112172,1591747200000,1591833600000,MM-18280,New York City,Office Supplies,Fasteners,Plymouth Boxed Rubber Bands by Plymouth,14.13000,3,0.00000,0.70650
+3717,CA-2017-144568,1590710400000,1590796800000,JO-15550,Omaha,Office Supplies,Fasteners,Plymouth Boxed Rubber Bands by Plymouth,23.55000,5,0.00000,1.17750
+4882,CA-2017-143567,1604275200000,1604361600000,TB-21175,Columbus,Technology,Accessories,Logitech di_Novo Edge Keyboard,2249.91000,9,0.00000,517.47930
+5277,CA-2017-147333,1607904000000,1607990400000,KL-16555,Columbus,Technology,Accessories,Kingston Digital DataTraveler 16GB USB 2.0,44.75000,5,0.00000,8.50250
+6125,CA-2017-145772,1591142400000,1591228800000,SS-20140,Los Angeles,Technology,Accessories,Kingston Digital DataTraveler 16GB USB 2.1,44.75000,5,0.00000,8.50250
+2455,CA-2017-140949,1584403200000,1584489600000,DB-13405,New York City,Technology,Accessories,Kingston Digital DataTraveler 16GB USB 2.2,71.60000,8,0.00000,13.60400
+2661,CA-2017-123372,1606521600000,1606608000000,DG-13300,Columbus,Technology,Phones,Google Nexus 5,1979.89000,11,0.00000,494.97250
+3083,US-2017-132297,1590537600000,1590624000000,DW-13480,Louisville,Technology,Phones,Google Nexus 6,539.97000,3,0.00000,134.99250
+4161,CA-2017-115546,1589414400000,1589500800000,AH-10465,New York City,Technology,Phones,Google Nexus 7,539.97000,3,0.00000,134.99250
+8697,CA-2017-119284,1592179200000,1592265600000,TS-21205,Columbus,Technology,Phones,HTC One,239.97600,3,0.20000,26.99730
+7698,CA-2017-151799,1607904000000,1608163200000,BF-11170,Columbus,Technology,Copiers,Canon PC1080F Personal Copier,1199.98000,2,0.00000,467.99220
+7174,US-2017-141677,1585180800000,1585267200000,HK-14890,Houston,Technology,Copiers,Canon PC1080F Personal Copier,2399.96000,5,0.20000,569.99050
+9618,CA-2017-160633,1605484800000,1605571200000,BS-11380,Columbus,Technology,Copiers,Hewlett Packard 610 Color Digital Copier / Printer,899.98200,3,0.40000,74.99850
+8958,CA-2017-105620,1608854400000,1608940800000,JH-15430,Columbus,Technology,Machines,Lexmark 20R1285 X6650 Wireless All-in-One Printer,120.00000,2,0.50000,-7.20000
+8878,CA-2017-126928,1600300800000,1600387200000,GZ-14470,Morristown,Technology,Machines,Lexmark 20R1285 X6650 Wireless All-in-One Printer,480.00000,4,0.00000,225.60000
+7293,CA-2017-109183,1607040000000,1607126400000,LR-16915,Columbus,Technology,Machines,Okidata C610n Printer,649.00000,2,0.50000,-272.58000
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/products_pinot/products_pinot.csv b/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/products_pinot/products_pinot.csv
new file mode 100644
index 0000000000000..e2d327dbac3c9
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/products_pinot/products_pinot.csv
@@ -0,0 +1,29 @@
+category,sub_category,product_name
+Furniture,Tables,Anderson Hickey Conga Table Tops & Accessories
+Furniture,Tables,Balt Solid Wood Rectangular Table
+Furniture,Bookcases,DMI Eclipse Executive Suite Bookcases
+Furniture,Bookcases,"Global Adaptabilites Bookcase, Cherry/Storm Gray Finish"
+Furniture,Chairs,Harbour Creations 67200 Series Stacking Chairs
+Furniture,Chairs,"Iceberg Nesting Folding Chair, 19w x 6d x 43h"
+Furniture,Furnishings,"Linden 10 Round Wall Clock, Black"
+Furniture,Furnishings,Magna Visual Magnetic Picture Hangers
+Office Supplies,Art,"OIC #2 Pencils, Medium Soft"
+Office Supplies,Art,Panasonic KP-380BK Classic Electric Pencil Sharpener
+Office Supplies,Storage,Project Tote Personal File
+Office Supplies,Storage,Recycled Eldon Regeneration Jumbo File
+Office Supplies,Envelopes,Tyvek Side-Opening Peel & Seel Expanding Envelopes
+Office Supplies,Envelopes,Wausau Papers Astrobrights Colored Envelopes
+Office Supplies,Fasteners,"Vinyl Coated Wire Paper Clips in Organizer Box, 800/Box"
+Office Supplies,Fasteners,Plymouth Boxed Rubber Bands by Plymouth
+Technology,Accessories,Logitech di_Novo Edge Keyboard
+Technology,Accessories,Kingston Digital DataTraveler 16GB USB 2.0
+Technology,Accessories,Kingston Digital DataTraveler 16GB USB 2.1
+Technology,Accessories,Kingston Digital DataTraveler 16GB USB 2.2
+Technology,Phones,Google Nexus 5
+Technology,Phones,Google Nexus 6
+Technology,Phones,Google Nexus 7
+Technology,Phones,HTC One
+Technology,Copiers,Canon PC1080F Personal Copier
+Technology,Copiers,Hewlett Packard 610 Color Digital Copier / Printer
+Technology,Machines,Lexmark 20R1285 X6650 Wireless All-in-One Printer
+Technology,Machines,Okidata C610n Printer
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/retailcalendar_pinot/retailcalendar_pinot.csv b/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/retailcalendar_pinot/retailcalendar_pinot.csv
new file mode 100644
index 0000000000000..e292da15b620e
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/rawdata/retailcalendar_pinot/retailcalendar_pinot.csv
@@ -0,0 +1,457 @@
+date_val,retail_year_name,retail_quarter_name,retail_month_name,retail_week_name,retail_year_begin_date,retail_quarter_begin_date,retail_month_begin_date,retail_week_begin_date,retail_date_prev_month,retail_date_prev_quarter,retail_date_prev_year
+1549152000000,2019,2019-Q1,2019-M01,2019-W01,1549152000000,1549152000000,1549152000000,1549152000000,1546732800000,1541289600000,1517702400000
+1572739200000,2019,2019-Q4,2019-M10,2019-W40,1549152000000,1572739200000,1572739200000,1572739200000,1570320000000,1564876800000,1541289600000
+1572825600000,2019,2019-Q4,2019-M10,2019-W40,1549152000000,1572739200000,1572739200000,1572739200000,1570406400000,1564963200000,1541376000000
+1572912000000,2019,2019-Q4,2019-M10,2019-W40,1549152000000,1572739200000,1572739200000,1572739200000,1570492800000,1565049600000,1541462400000
+1572998400000,2019,2019-Q4,2019-M10,2019-W40,1549152000000,1572739200000,1572739200000,1572739200000,1570579200000,1565136000000,1541548800000
+1573084800000,2019,2019-Q4,2019-M10,2019-W40,1549152000000,1572739200000,1572739200000,1572739200000,1570665600000,1565222400000,1541635200000
+1573171200000,2019,2019-Q4,2019-M10,2019-W40,1549152000000,1572739200000,1572739200000,1572739200000,1570752000000,1565308800000,1541721600000
+1573257600000,2019,2019-Q4,2019-M10,2019-W40,1549152000000,1572739200000,1572739200000,1572739200000,1570838400000,1565395200000,1541808000000
+1573344000000,2019,2019-Q4,2019-M10,2019-W41,1549152000000,1572739200000,1572739200000,1573344000000,1570924800000,1565481600000,1541894400000
+1573430400000,2019,2019-Q4,2019-M10,2019-W41,1549152000000,1572739200000,1572739200000,1573344000000,1571011200000,1565568000000,1541980800000
+1573516800000,2019,2019-Q4,2019-M10,2019-W41,1549152000000,1572739200000,1572739200000,1573344000000,1571097600000,1565654400000,1542067200000
+1573603200000,2019,2019-Q4,2019-M10,2019-W41,1549152000000,1572739200000,1572739200000,1573344000000,1571184000000,1565740800000,1542153600000
+1573689600000,2019,2019-Q4,2019-M10,2019-W41,1549152000000,1572739200000,1572739200000,1573344000000,1571270400000,1565827200000,1542240000000
+1573776000000,2019,2019-Q4,2019-M10,2019-W41,1549152000000,1572739200000,1572739200000,1573344000000,1571356800000,1565913600000,1542326400000
+1573862400000,2019,2019-Q4,2019-M10,2019-W41,1549152000000,1572739200000,1572739200000,1573344000000,1571443200000,1566000000000,1542412800000
+1573948800000,2019,2019-Q4,2019-M10,2019-W42,1549152000000,1572739200000,1572739200000,1573948800000,1571529600000,1566086400000,1542499200000
+1574035200000,2019,2019-Q4,2019-M10,2019-W42,1549152000000,1572739200000,1572739200000,1573948800000,1571616000000,1566172800000,1542585600000
+1574121600000,2019,2019-Q4,2019-M10,2019-W42,1549152000000,1572739200000,1572739200000,1573948800000,1571702400000,1566259200000,1542672000000
+1574208000000,2019,2019-Q4,2019-M10,2019-W42,1549152000000,1572739200000,1572739200000,1573948800000,1571788800000,1566345600000,1542758400000
+1574294400000,2019,2019-Q4,2019-M10,2019-W42,1549152000000,1572739200000,1572739200000,1573948800000,1571875200000,1566432000000,1542844800000
+1574380800000,2019,2019-Q4,2019-M10,2019-W42,1549152000000,1572739200000,1572739200000,1573948800000,1571961600000,1566518400000,1542931200000
+1574467200000,2019,2019-Q4,2019-M10,2019-W42,1549152000000,1572739200000,1572739200000,1573948800000,1572048000000,1566604800000,1543017600000
+1574553600000,2019,2019-Q4,2019-M10,2019-W43,1549152000000,1572739200000,1572739200000,1574553600000,1572134400000,1566691200000,1543104000000
+1574640000000,2019,2019-Q4,2019-M10,2019-W43,1549152000000,1572739200000,1572739200000,1574553600000,1572220800000,1566777600000,1543190400000
+1574726400000,2019,2019-Q4,2019-M10,2019-W43,1549152000000,1572739200000,1572739200000,1574553600000,1572307200000,1566864000000,1543276800000
+1574812800000,2019,2019-Q4,2019-M10,2019-W43,1549152000000,1572739200000,1572739200000,1574553600000,1572393600000,1566950400000,1543363200000
+1574899200000,2019,2019-Q4,2019-M10,2019-W43,1549152000000,1572739200000,1572739200000,1574553600000,1572480000000,1567036800000,1543449600000
+1574985600000,2019,2019-Q4,2019-M10,2019-W43,1549152000000,1572739200000,1572739200000,1574553600000,1572566400000,1567123200000,1543536000000
+1575072000000,2019,2019-Q4,2019-M10,2019-W43,1549152000000,1572739200000,1572739200000,1574553600000,1572652800000,1567209600000,1543622400000
+1575158400000,2019,2019-Q4,2019-M11,2019-W44,1549152000000,1572739200000,1575158400000,1575158400000,1572739200000,1567296000000,1543708800000
+1575244800000,2019,2019-Q4,2019-M11,2019-W44,1549152000000,1572739200000,1575158400000,1575158400000,1572825600000,1567382400000,1543795200000
+1575331200000,2019,2019-Q4,2019-M11,2019-W44,1549152000000,1572739200000,1575158400000,1575158400000,1572912000000,1567468800000,1543881600000
+1575417600000,2019,2019-Q4,2019-M11,2019-W44,1549152000000,1572739200000,1575158400000,1575158400000,1572998400000,1567555200000,1543968000000
+1575504000000,2019,2019-Q4,2019-M11,2019-W44,1549152000000,1572739200000,1575158400000,1575158400000,1573084800000,1567641600000,1544054400000
+1575590400000,2019,2019-Q4,2019-M11,2019-W44,1549152000000,1572739200000,1575158400000,1575158400000,1573171200000,1567728000000,1544140800000
+1575676800000,2019,2019-Q4,2019-M11,2019-W44,1549152000000,1572739200000,1575158400000,1575158400000,1573257600000,1567814400000,1544227200000
+1575763200000,2019,2019-Q4,2019-M11,2019-W45,1549152000000,1572739200000,1575158400000,1575763200000,1573344000000,1567900800000,1544313600000
+1575849600000,2019,2019-Q4,2019-M11,2019-W45,1549152000000,1572739200000,1575158400000,1575763200000,1573430400000,1567987200000,1544400000000
+1575936000000,2019,2019-Q4,2019-M11,2019-W45,1549152000000,1572739200000,1575158400000,1575763200000,1573516800000,1568073600000,1544486400000
+1576022400000,2019,2019-Q4,2019-M11,2019-W45,1549152000000,1572739200000,1575158400000,1575763200000,1573603200000,1568160000000,1544572800000
+1576108800000,2019,2019-Q4,2019-M11,2019-W45,1549152000000,1572739200000,1575158400000,1575763200000,1573689600000,1568246400000,1544659200000
+1576195200000,2019,2019-Q4,2019-M11,2019-W45,1549152000000,1572739200000,1575158400000,1575763200000,1573776000000,1568332800000,1544745600000
+1576281600000,2019,2019-Q4,2019-M11,2019-W45,1549152000000,1572739200000,1575158400000,1575763200000,1573862400000,1568419200000,1544832000000
+1576368000000,2019,2019-Q4,2019-M11,2019-W46,1549152000000,1572739200000,1575158400000,1576368000000,1573948800000,1568505600000,1544918400000
+1576454400000,2019,2019-Q4,2019-M11,2019-W46,1549152000000,1572739200000,1575158400000,1576368000000,1574035200000,1568592000000,1545004800000
+1576540800000,2019,2019-Q4,2019-M11,2019-W46,1549152000000,1572739200000,1575158400000,1576368000000,1574121600000,1568678400000,1545091200000
+1576627200000,2019,2019-Q4,2019-M11,2019-W46,1549152000000,1572739200000,1575158400000,1576368000000,1574208000000,1568764800000,1545177600000
+1576713600000,2019,2019-Q4,2019-M11,2019-W46,1549152000000,1572739200000,1575158400000,1576368000000,1574294400000,1568851200000,1545264000000
+1576800000000,2019,2019-Q4,2019-M11,2019-W46,1549152000000,1572739200000,1575158400000,1576368000000,1574380800000,1568937600000,1545350400000
+1576886400000,2019,2019-Q4,2019-M11,2019-W46,1549152000000,1572739200000,1575158400000,1576368000000,1574467200000,1569024000000,1545436800000
+1576972800000,2019,2019-Q4,2019-M11,2019-W47,1549152000000,1572739200000,1575158400000,1576972800000,1574553600000,1569110400000,1545523200000
+1577059200000,2019,2019-Q4,2019-M11,2019-W47,1549152000000,1572739200000,1575158400000,1576972800000,1574640000000,1569196800000,1545609600000
+1577145600000,2019,2019-Q4,2019-M11,2019-W47,1549152000000,1572739200000,1575158400000,1576972800000,1574726400000,1569283200000,1545696000000
+1577232000000,2019,2019-Q4,2019-M11,2019-W47,1549152000000,1572739200000,1575158400000,1576972800000,1574812800000,1569369600000,1545782400000
+1577318400000,2019,2019-Q4,2019-M11,2019-W47,1549152000000,1572739200000,1575158400000,1576972800000,1574899200000,1569456000000,1545868800000
+1577404800000,2019,2019-Q4,2019-M11,2019-W47,1549152000000,1572739200000,1575158400000,1576972800000,1574985600000,1569542400000,1545955200000
+1577491200000,2019,2019-Q4,2019-M11,2019-W47,1549152000000,1572739200000,1575158400000,1576972800000,1575072000000,1569628800000,1546041600000
+1577577600000,2019,2019-Q4,2019-M11,2019-W48,1549152000000,1572739200000,1575158400000,1577577600000,,1569715200000,1546128000000
+1577664000000,2019,2019-Q4,2019-M11,2019-W48,1549152000000,1572739200000,1575158400000,1577577600000,,1569801600000,1546214400000
+1577750400000,2019,2019-Q4,2019-M11,2019-W48,1549152000000,1572739200000,1575158400000,1577577600000,,1569888000000,1546300800000
+1577836800000,2019,2019-Q4,2019-M11,2019-W48,1549152000000,1572739200000,1575158400000,1577577600000,,1569974400000,1546387200000
+1577923200000,2019,2019-Q4,2019-M11,2019-W48,1549152000000,1572739200000,1575158400000,1577577600000,,1570060800000,1546473600000
+1578009600000,2019,2019-Q4,2019-M11,2019-W48,1549152000000,1572739200000,1575158400000,1577577600000,,1570147200000,1546560000000
+1578096000000,2019,2019-Q4,2019-M11,2019-W48,1549152000000,1572739200000,1575158400000,1577577600000,,1570233600000,1546646400000
+1578182400000,2019,2019-Q4,2019-M12,2019-W49,1549152000000,1572739200000,1578182400000,1578182400000,1575158400000,1570320000000,1546732800000
+1578268800000,2019,2019-Q4,2019-M12,2019-W49,1549152000000,1572739200000,1578182400000,1578182400000,1575244800000,1570406400000,1546819200000
+1578355200000,2019,2019-Q4,2019-M12,2019-W49,1549152000000,1572739200000,1578182400000,1578182400000,1575331200000,1570492800000,1546905600000
+1578441600000,2019,2019-Q4,2019-M12,2019-W49,1549152000000,1572739200000,1578182400000,1578182400000,1575417600000,1570579200000,1546992000000
+1578528000000,2019,2019-Q4,2019-M12,2019-W49,1549152000000,1572739200000,1578182400000,1578182400000,1575504000000,1570665600000,1547078400000
+1578614400000,2019,2019-Q4,2019-M12,2019-W49,1549152000000,1572739200000,1578182400000,1578182400000,1575590400000,1570752000000,1547164800000
+1578700800000,2019,2019-Q4,2019-M12,2019-W49,1549152000000,1572739200000,1578182400000,1578182400000,1575676800000,1570838400000,1547251200000
+1578787200000,2019,2019-Q4,2019-M12,2019-W50,1549152000000,1572739200000,1578182400000,1578787200000,1575763200000,1570924800000,1547337600000
+1578873600000,2019,2019-Q4,2019-M12,2019-W50,1549152000000,1572739200000,1578182400000,1578787200000,1575849600000,1571011200000,1547424000000
+1578960000000,2019,2019-Q4,2019-M12,2019-W50,1549152000000,1572739200000,1578182400000,1578787200000,1575936000000,1571097600000,1547510400000
+1579046400000,2019,2019-Q4,2019-M12,2019-W50,1549152000000,1572739200000,1578182400000,1578787200000,1576022400000,1571184000000,1547596800000
+1579132800000,2019,2019-Q4,2019-M12,2019-W50,1549152000000,1572739200000,1578182400000,1578787200000,1576108800000,1571270400000,1547683200000
+1579219200000,2019,2019-Q4,2019-M12,2019-W50,1549152000000,1572739200000,1578182400000,1578787200000,1576195200000,1571356800000,1547769600000
+1579305600000,2019,2019-Q4,2019-M12,2019-W50,1549152000000,1572739200000,1578182400000,1578787200000,1576281600000,1571443200000,1547856000000
+1579392000000,2019,2019-Q4,2019-M12,2019-W51,1549152000000,1572739200000,1578182400000,1579392000000,1576368000000,1571529600000,1547942400000
+1579478400000,2019,2019-Q4,2019-M12,2019-W51,1549152000000,1572739200000,1578182400000,1579392000000,1576454400000,1571616000000,1548028800000
+1579564800000,2019,2019-Q4,2019-M12,2019-W51,1549152000000,1572739200000,1578182400000,1579392000000,1576540800000,1571702400000,1548115200000
+1579651200000,2019,2019-Q4,2019-M12,2019-W51,1549152000000,1572739200000,1578182400000,1579392000000,1576627200000,1571788800000,1548201600000
+1579737600000,2019,2019-Q4,2019-M12,2019-W51,1549152000000,1572739200000,1578182400000,1579392000000,1576713600000,1571875200000,1548288000000
+1579824000000,2019,2019-Q4,2019-M12,2019-W51,1549152000000,1572739200000,1578182400000,1579392000000,1576800000000,1571961600000,1548374400000
+1579910400000,2019,2019-Q4,2019-M12,2019-W51,1549152000000,1572739200000,1578182400000,1579392000000,1576886400000,1572048000000,1548460800000
+1579996800000,2019,2019-Q4,2019-M12,2019-W52,1549152000000,1572739200000,1578182400000,1579996800000,1576972800000,1572134400000,1548547200000
+1580083200000,2019,2019-Q4,2019-M12,2019-W52,1549152000000,1572739200000,1578182400000,1579996800000,1577059200000,1572220800000,1548633600000
+1580169600000,2019,2019-Q4,2019-M12,2019-W52,1549152000000,1572739200000,1578182400000,1579996800000,1577145600000,1572307200000,1548720000000
+1580256000000,2019,2019-Q4,2019-M12,2019-W52,1549152000000,1572739200000,1578182400000,1579996800000,1577232000000,1572393600000,1548806400000
+1580342400000,2019,2019-Q4,2019-M12,2019-W52,1549152000000,1572739200000,1578182400000,1579996800000,1577318400000,1572480000000,1548892800000
+1580428800000,2019,2019-Q4,2019-M12,2019-W52,1549152000000,1572739200000,1578182400000,1579996800000,1577404800000,1572566400000,1548979200000
+1580515200000,2019,2019-Q4,2019-M12,2019-W52,1549152000000,1572739200000,1578182400000,1579996800000,1577491200000,1572652800000,1549065600000
+1580601600000,2020,2020-Q1,2020-M01,2020-W01,1580601600000,1580601600000,1580601600000,1580601600000,1578182400000,1572739200000,1549152000000
+1580688000000,2020,2020-Q1,2020-M01,2020-W01,1580601600000,1580601600000,1580601600000,1580601600000,1578268800000,1572825600000,1549238400000
+1580774400000,2020,2020-Q1,2020-M01,2020-W01,1580601600000,1580601600000,1580601600000,1580601600000,1578355200000,1572912000000,1549324800000
+1580860800000,2020,2020-Q1,2020-M01,2020-W01,1580601600000,1580601600000,1580601600000,1580601600000,1578441600000,1572998400000,1549411200000
+1580947200000,2020,2020-Q1,2020-M01,2020-W01,1580601600000,1580601600000,1580601600000,1580601600000,1578528000000,1573084800000,1549497600000
+1581033600000,2020,2020-Q1,2020-M01,2020-W01,1580601600000,1580601600000,1580601600000,1580601600000,1578614400000,1573171200000,1549584000000
+1581120000000,2020,2020-Q1,2020-M01,2020-W01,1580601600000,1580601600000,1580601600000,1580601600000,1578700800000,1573257600000,1549670400000
+1581206400000,2020,2020-Q1,2020-M01,2020-W02,1580601600000,1580601600000,1580601600000,1581206400000,1578787200000,1573344000000,1549756800000
+1581292800000,2020,2020-Q1,2020-M01,2020-W02,1580601600000,1580601600000,1580601600000,1581206400000,1578873600000,1573430400000,1549843200000
+1581379200000,2020,2020-Q1,2020-M01,2020-W02,1580601600000,1580601600000,1580601600000,1581206400000,1578960000000,1573516800000,1549929600000
+1581465600000,2020,2020-Q1,2020-M01,2020-W02,1580601600000,1580601600000,1580601600000,1581206400000,1579046400000,1573603200000,1550016000000
+1581552000000,2020,2020-Q1,2020-M01,2020-W02,1580601600000,1580601600000,1580601600000,1581206400000,1579132800000,1573689600000,1550102400000
+1581638400000,2020,2020-Q1,2020-M01,2020-W02,1580601600000,1580601600000,1580601600000,1581206400000,1579219200000,1573776000000,1550188800000
+1581724800000,2020,2020-Q1,2020-M01,2020-W02,1580601600000,1580601600000,1580601600000,1581206400000,1579305600000,1573862400000,1550275200000
+1581811200000,2020,2020-Q1,2020-M01,2020-W03,1580601600000,1580601600000,1580601600000,1581811200000,1579392000000,1573948800000,1550361600000
+1581897600000,2020,2020-Q1,2020-M01,2020-W03,1580601600000,1580601600000,1580601600000,1581811200000,1579478400000,1574035200000,1550448000000
+1581984000000,2020,2020-Q1,2020-M01,2020-W03,1580601600000,1580601600000,1580601600000,1581811200000,1579564800000,1574121600000,1550534400000
+1582070400000,2020,2020-Q1,2020-M01,2020-W03,1580601600000,1580601600000,1580601600000,1581811200000,1579651200000,1574208000000,1550620800000
+1582156800000,2020,2020-Q1,2020-M01,2020-W03,1580601600000,1580601600000,1580601600000,1581811200000,1579737600000,1574294400000,1550707200000
+1582243200000,2020,2020-Q1,2020-M01,2020-W03,1580601600000,1580601600000,1580601600000,1581811200000,1579824000000,1574380800000,1550793600000
+1582329600000,2020,2020-Q1,2020-M01,2020-W03,1580601600000,1580601600000,1580601600000,1581811200000,1579910400000,1574467200000,1550880000000
+1582416000000,2020,2020-Q1,2020-M01,2020-W04,1580601600000,1580601600000,1580601600000,1582416000000,1579996800000,1574553600000,1550966400000
+1582502400000,2020,2020-Q1,2020-M01,2020-W04,1580601600000,1580601600000,1580601600000,1582416000000,1580083200000,1574640000000,1551052800000
+1582588800000,2020,2020-Q1,2020-M01,2020-W04,1580601600000,1580601600000,1580601600000,1582416000000,1580169600000,1574726400000,1551139200000
+1582675200000,2020,2020-Q1,2020-M01,2020-W04,1580601600000,1580601600000,1580601600000,1582416000000,1580256000000,1574812800000,1551225600000
+1582761600000,2020,2020-Q1,2020-M01,2020-W04,1580601600000,1580601600000,1580601600000,1582416000000,1580342400000,1574899200000,1551312000000
+1582848000000,2020,2020-Q1,2020-M01,2020-W04,1580601600000,1580601600000,1580601600000,1582416000000,1580428800000,1574985600000,1551398400000
+1582934400000,2020,2020-Q1,2020-M01,2020-W04,1580601600000,1580601600000,1580601600000,1582416000000,1580515200000,1575072000000,1551484800000
+1583020800000,2020,2020-Q1,2020-M02,2020-W05,1580601600000,1580601600000,1583020800000,1583020800000,1580601600000,1575158400000,1551571200000
+1583107200000,2020,2020-Q1,2020-M02,2020-W05,1580601600000,1580601600000,1583020800000,1583020800000,1580688000000,1575244800000,1551657600000
+1583193600000,2020,2020-Q1,2020-M02,2020-W05,1580601600000,1580601600000,1583020800000,1583020800000,1580774400000,1575331200000,1551744000000
+1583280000000,2020,2020-Q1,2020-M02,2020-W05,1580601600000,1580601600000,1583020800000,1583020800000,1580860800000,1575417600000,1551830400000
+1583366400000,2020,2020-Q1,2020-M02,2020-W05,1580601600000,1580601600000,1583020800000,1583020800000,1580947200000,1575504000000,1551916800000
+1583452800000,2020,2020-Q1,2020-M02,2020-W05,1580601600000,1580601600000,1583020800000,1583020800000,1581033600000,1575590400000,1552003200000
+1583539200000,2020,2020-Q1,2020-M02,2020-W05,1580601600000,1580601600000,1583020800000,1583020800000,1581120000000,1575676800000,1552089600000
+1583625600000,2020,2020-Q1,2020-M02,2020-W06,1580601600000,1580601600000,1583020800000,1583625600000,1581206400000,1575763200000,1552176000000
+1583712000000,2020,2020-Q1,2020-M02,2020-W06,1580601600000,1580601600000,1583020800000,1583625600000,1581292800000,1575849600000,1552262400000
+1583798400000,2020,2020-Q1,2020-M02,2020-W06,1580601600000,1580601600000,1583020800000,1583625600000,1581379200000,1575936000000,1552348800000
+1583884800000,2020,2020-Q1,2020-M02,2020-W06,1580601600000,1580601600000,1583020800000,1583625600000,1581465600000,1576022400000,1552435200000
+1583971200000,2020,2020-Q1,2020-M02,2020-W06,1580601600000,1580601600000,1583020800000,1583625600000,1581552000000,1576108800000,1552521600000
+1584057600000,2020,2020-Q1,2020-M02,2020-W06,1580601600000,1580601600000,1583020800000,1583625600000,1581638400000,1576195200000,1552608000000
+1584144000000,2020,2020-Q1,2020-M02,2020-W06,1580601600000,1580601600000,1583020800000,1583625600000,1581724800000,1576281600000,1552694400000
+1584230400000,2020,2020-Q1,2020-M02,2020-W07,1580601600000,1580601600000,1583020800000,1584230400000,1581811200000,1576368000000,1552780800000
+1584316800000,2020,2020-Q1,2020-M02,2020-W07,1580601600000,1580601600000,1583020800000,1584230400000,1581897600000,1576454400000,1552867200000
+1584403200000,2020,2020-Q1,2020-M02,2020-W07,1580601600000,1580601600000,1583020800000,1584230400000,1581984000000,1576540800000,1552953600000
+1584489600000,2020,2020-Q1,2020-M02,2020-W07,1580601600000,1580601600000,1583020800000,1584230400000,1582070400000,1576627200000,1553040000000
+1584576000000,2020,2020-Q1,2020-M02,2020-W07,1580601600000,1580601600000,1583020800000,1584230400000,1582156800000,1576713600000,1553126400000
+1584662400000,2020,2020-Q1,2020-M02,2020-W07,1580601600000,1580601600000,1583020800000,1584230400000,1582243200000,1576800000000,1553212800000
+1584748800000,2020,2020-Q1,2020-M02,2020-W07,1580601600000,1580601600000,1583020800000,1584230400000,1582329600000,1576886400000,1553299200000
+1584835200000,2020,2020-Q1,2020-M02,2020-W08,1580601600000,1580601600000,1583020800000,1584835200000,1582416000000,1576972800000,1553385600000
+1584921600000,2020,2020-Q1,2020-M02,2020-W08,1580601600000,1580601600000,1583020800000,1584835200000,1582502400000,1577059200000,1553472000000
+1585008000000,2020,2020-Q1,2020-M02,2020-W08,1580601600000,1580601600000,1583020800000,1584835200000,1582588800000,1577145600000,1553558400000
+1585094400000,2020,2020-Q1,2020-M02,2020-W08,1580601600000,1580601600000,1583020800000,1584835200000,1582675200000,1577232000000,1553644800000
+1585180800000,2020,2020-Q1,2020-M02,2020-W08,1580601600000,1580601600000,1583020800000,1584835200000,1582761600000,1577318400000,1553731200000
+1585267200000,2020,2020-Q1,2020-M02,2020-W08,1580601600000,1580601600000,1583020800000,1584835200000,1582848000000,1577404800000,1553817600000
+1585353600000,2020,2020-Q1,2020-M02,2020-W08,1580601600000,1580601600000,1583020800000,1584835200000,1582934400000,1577491200000,1553904000000
+1585440000000,2020,2020-Q1,2020-M02,2020-W09,1580601600000,1580601600000,1583020800000,1585440000000,,1577577600000,1553990400000
+1585526400000,2020,2020-Q1,2020-M02,2020-W09,1580601600000,1580601600000,1583020800000,1585440000000,,1577664000000,1554076800000
+1585612800000,2020,2020-Q1,2020-M02,2020-W09,1580601600000,1580601600000,1583020800000,1585440000000,,1577750400000,1554163200000
+1585699200000,2020,2020-Q1,2020-M02,2020-W09,1580601600000,1580601600000,1583020800000,1585440000000,,1577836800000,1554249600000
+1585785600000,2020,2020-Q1,2020-M02,2020-W09,1580601600000,1580601600000,1583020800000,1585440000000,,1577923200000,1554336000000
+1585872000000,2020,2020-Q1,2020-M02,2020-W09,1580601600000,1580601600000,1583020800000,1585440000000,,1578009600000,1554422400000
+1585958400000,2020,2020-Q1,2020-M02,2020-W09,1580601600000,1580601600000,1583020800000,1585440000000,,1578096000000,1554508800000
+1586044800000,2020,2020-Q1,2020-M03,2020-W10,1580601600000,1580601600000,1586044800000,1586044800000,1583020800000,1578182400000,1554595200000
+1586131200000,2020,2020-Q1,2020-M03,2020-W10,1580601600000,1580601600000,1586044800000,1586044800000,1583107200000,1578268800000,1554681600000
+1586217600000,2020,2020-Q1,2020-M03,2020-W10,1580601600000,1580601600000,1586044800000,1586044800000,1583193600000,1578355200000,1554768000000
+1586304000000,2020,2020-Q1,2020-M03,2020-W10,1580601600000,1580601600000,1586044800000,1586044800000,1583280000000,1578441600000,1554854400000
+1586390400000,2020,2020-Q1,2020-M03,2020-W10,1580601600000,1580601600000,1586044800000,1586044800000,1583366400000,1578528000000,1554940800000
+1586476800000,2020,2020-Q1,2020-M03,2020-W10,1580601600000,1580601600000,1586044800000,1586044800000,1583452800000,1578614400000,1555027200000
+1586563200000,2020,2020-Q1,2020-M03,2020-W10,1580601600000,1580601600000,1586044800000,1586044800000,1583539200000,1578700800000,1555113600000
+1586649600000,2020,2020-Q1,2020-M03,2020-W11,1580601600000,1580601600000,1586044800000,1586649600000,1583625600000,1578787200000,1555200000000
+1586736000000,2020,2020-Q1,2020-M03,2020-W11,1580601600000,1580601600000,1586044800000,1586649600000,1583712000000,1578873600000,1555286400000
+1586822400000,2020,2020-Q1,2020-M03,2020-W11,1580601600000,1580601600000,1586044800000,1586649600000,1583798400000,1578960000000,1555372800000
+1586908800000,2020,2020-Q1,2020-M03,2020-W11,1580601600000,1580601600000,1586044800000,1586649600000,1583884800000,1579046400000,1555459200000
+1586995200000,2020,2020-Q1,2020-M03,2020-W11,1580601600000,1580601600000,1586044800000,1586649600000,1583971200000,1579132800000,1555545600000
+1587081600000,2020,2020-Q1,2020-M03,2020-W11,1580601600000,1580601600000,1586044800000,1586649600000,1584057600000,1579219200000,1555632000000
+1587168000000,2020,2020-Q1,2020-M03,2020-W11,1580601600000,1580601600000,1586044800000,1586649600000,1584144000000,1579305600000,1555718400000
+1587254400000,2020,2020-Q1,2020-M03,2020-W12,1580601600000,1580601600000,1586044800000,1587254400000,1584230400000,1579392000000,1555804800000
+1587340800000,2020,2020-Q1,2020-M03,2020-W12,1580601600000,1580601600000,1586044800000,1587254400000,1584316800000,1579478400000,1555891200000
+1587427200000,2020,2020-Q1,2020-M03,2020-W12,1580601600000,1580601600000,1586044800000,1587254400000,1584403200000,1579564800000,1555977600000
+1587513600000,2020,2020-Q1,2020-M03,2020-W12,1580601600000,1580601600000,1586044800000,1587254400000,1584489600000,1579651200000,1556064000000
+1587600000000,2020,2020-Q1,2020-M03,2020-W12,1580601600000,1580601600000,1586044800000,1587254400000,1584576000000,1579737600000,1556150400000
+1587686400000,2020,2020-Q1,2020-M03,2020-W12,1580601600000,1580601600000,1586044800000,1587254400000,1584662400000,1579824000000,1556236800000
+1587772800000,2020,2020-Q1,2020-M03,2020-W12,1580601600000,1580601600000,1586044800000,1587254400000,1584748800000,1579910400000,1556323200000
+1587859200000,2020,2020-Q1,2020-M03,2020-W13,1580601600000,1580601600000,1586044800000,1587859200000,1584835200000,1579996800000,1556409600000
+1587945600000,2020,2020-Q1,2020-M03,2020-W13,1580601600000,1580601600000,1586044800000,1587859200000,1584921600000,1580083200000,1556496000000
+1588032000000,2020,2020-Q1,2020-M03,2020-W13,1580601600000,1580601600000,1586044800000,1587859200000,1585008000000,1580169600000,1556582400000
+1588118400000,2020,2020-Q1,2020-M03,2020-W13,1580601600000,1580601600000,1586044800000,1587859200000,1585094400000,1580256000000,1556668800000
+1588204800000,2020,2020-Q1,2020-M03,2020-W13,1580601600000,1580601600000,1586044800000,1587859200000,1585180800000,1580342400000,1556755200000
+1588291200000,2020,2020-Q1,2020-M03,2020-W13,1580601600000,1580601600000,1586044800000,1587859200000,1585267200000,1580428800000,1556841600000
+1588377600000,2020,2020-Q1,2020-M03,2020-W13,1580601600000,1580601600000,1586044800000,1587859200000,1585353600000,1580515200000,1556928000000
+1588464000000,2020,2020-Q2,2020-M04,2020-W14,1580601600000,1588464000000,1588464000000,1588464000000,1586044800000,1580601600000,1557014400000
+1588550400000,2020,2020-Q2,2020-M04,2020-W14,1580601600000,1588464000000,1588464000000,1588464000000,1586131200000,1580688000000,1557100800000
+1588636800000,2020,2020-Q2,2020-M04,2020-W14,1580601600000,1588464000000,1588464000000,1588464000000,1586217600000,1580774400000,1557187200000
+1588723200000,2020,2020-Q2,2020-M04,2020-W14,1580601600000,1588464000000,1588464000000,1588464000000,1586304000000,1580860800000,1557273600000
+1588809600000,2020,2020-Q2,2020-M04,2020-W14,1580601600000,1588464000000,1588464000000,1588464000000,1586390400000,1580947200000,1557360000000
+1588896000000,2020,2020-Q2,2020-M04,2020-W14,1580601600000,1588464000000,1588464000000,1588464000000,1586476800000,1581033600000,1557446400000
+1588982400000,2020,2020-Q2,2020-M04,2020-W14,1580601600000,1588464000000,1588464000000,1588464000000,1586563200000,1581120000000,1557532800000
+1589068800000,2020,2020-Q2,2020-M04,2020-W15,1580601600000,1588464000000,1588464000000,1589068800000,1586649600000,1581206400000,1557619200000
+1589155200000,2020,2020-Q2,2020-M04,2020-W15,1580601600000,1588464000000,1588464000000,1589068800000,1586736000000,1581292800000,1557705600000
+1589241600000,2020,2020-Q2,2020-M04,2020-W15,1580601600000,1588464000000,1588464000000,1589068800000,1586822400000,1581379200000,1557792000000
+1589328000000,2020,2020-Q2,2020-M04,2020-W15,1580601600000,1588464000000,1588464000000,1589068800000,1586908800000,1581465600000,1557878400000
+1589414400000,2020,2020-Q2,2020-M04,2020-W15,1580601600000,1588464000000,1588464000000,1589068800000,1586995200000,1581552000000,1557964800000
+1589500800000,2020,2020-Q2,2020-M04,2020-W15,1580601600000,1588464000000,1588464000000,1589068800000,1587081600000,1581638400000,1558051200000
+1589587200000,2020,2020-Q2,2020-M04,2020-W15,1580601600000,1588464000000,1588464000000,1589068800000,1587168000000,1581724800000,1558137600000
+1589673600000,2020,2020-Q2,2020-M04,2020-W16,1580601600000,1588464000000,1588464000000,1589673600000,1587254400000,1581811200000,1558224000000
+1589760000000,2020,2020-Q2,2020-M04,2020-W16,1580601600000,1588464000000,1588464000000,1589673600000,1587340800000,1581897600000,1558310400000
+1589846400000,2020,2020-Q2,2020-M04,2020-W16,1580601600000,1588464000000,1588464000000,1589673600000,1587427200000,1581984000000,1558396800000
+1589932800000,2020,2020-Q2,2020-M04,2020-W16,1580601600000,1588464000000,1588464000000,1589673600000,1587513600000,1582070400000,1558483200000
+1590019200000,2020,2020-Q2,2020-M04,2020-W16,1580601600000,1588464000000,1588464000000,1589673600000,1587600000000,1582156800000,1558569600000
+1590105600000,2020,2020-Q2,2020-M04,2020-W16,1580601600000,1588464000000,1588464000000,1589673600000,1587686400000,1582243200000,1558656000000
+1590192000000,2020,2020-Q2,2020-M04,2020-W16,1580601600000,1588464000000,1588464000000,1589673600000,1587772800000,1582329600000,1558742400000
+1590278400000,2020,2020-Q2,2020-M04,2020-W17,1580601600000,1588464000000,1588464000000,1590278400000,1587859200000,1582416000000,1558828800000
+1590364800000,2020,2020-Q2,2020-M04,2020-W17,1580601600000,1588464000000,1588464000000,1590278400000,1587945600000,1582502400000,1558915200000
+1590451200000,2020,2020-Q2,2020-M04,2020-W17,1580601600000,1588464000000,1588464000000,1590278400000,1588032000000,1582588800000,1559001600000
+1590537600000,2020,2020-Q2,2020-M04,2020-W17,1580601600000,1588464000000,1588464000000,1590278400000,1588118400000,1582675200000,1559088000000
+1590624000000,2020,2020-Q2,2020-M04,2020-W17,1580601600000,1588464000000,1588464000000,1590278400000,1588204800000,1582761600000,1559174400000
+1590710400000,2020,2020-Q2,2020-M04,2020-W17,1580601600000,1588464000000,1588464000000,1590278400000,1588291200000,1582848000000,1559260800000
+1590796800000,2020,2020-Q2,2020-M04,2020-W17,1580601600000,1588464000000,1588464000000,1590278400000,1588377600000,1582934400000,1559347200000
+1590883200000,2020,2020-Q2,2020-M05,2020-W18,1580601600000,1588464000000,1590883200000,1590883200000,1588464000000,1583020800000,1559433600000
+1590969600000,2020,2020-Q2,2020-M05,2020-W18,1580601600000,1588464000000,1590883200000,1590883200000,1588550400000,1583107200000,1559520000000
+1591056000000,2020,2020-Q2,2020-M05,2020-W18,1580601600000,1588464000000,1590883200000,1590883200000,1588636800000,1583193600000,1559606400000
+1591142400000,2020,2020-Q2,2020-M05,2020-W18,1580601600000,1588464000000,1590883200000,1590883200000,1588723200000,1583280000000,1559692800000
+1591228800000,2020,2020-Q2,2020-M05,2020-W18,1580601600000,1588464000000,1590883200000,1590883200000,1588809600000,1583366400000,1559779200000
+1591315200000,2020,2020-Q2,2020-M05,2020-W18,1580601600000,1588464000000,1590883200000,1590883200000,1588896000000,1583452800000,1559865600000
+1591401600000,2020,2020-Q2,2020-M05,2020-W18,1580601600000,1588464000000,1590883200000,1590883200000,1588982400000,1583539200000,1559952000000
+1591488000000,2020,2020-Q2,2020-M05,2020-W19,1580601600000,1588464000000,1590883200000,1591488000000,1589068800000,1583625600000,1560038400000
+1591574400000,2020,2020-Q2,2020-M05,2020-W19,1580601600000,1588464000000,1590883200000,1591488000000,1589155200000,1583712000000,1560124800000
+1591660800000,2020,2020-Q2,2020-M05,2020-W19,1580601600000,1588464000000,1590883200000,1591488000000,1589241600000,1583798400000,1560211200000
+1591747200000,2020,2020-Q2,2020-M05,2020-W19,1580601600000,1588464000000,1590883200000,1591488000000,1589328000000,1583884800000,1560297600000
+1591833600000,2020,2020-Q2,2020-M05,2020-W19,1580601600000,1588464000000,1590883200000,1591488000000,1589414400000,1583971200000,1560384000000
+1591920000000,2020,2020-Q2,2020-M05,2020-W19,1580601600000,1588464000000,1590883200000,1591488000000,1589500800000,1584057600000,1560470400000
+1592006400000,2020,2020-Q2,2020-M05,2020-W19,1580601600000,1588464000000,1590883200000,1591488000000,1589587200000,1584144000000,1560556800000
+1592092800000,2020,2020-Q2,2020-M05,2020-W20,1580601600000,1588464000000,1590883200000,1592092800000,1589673600000,1584230400000,1560643200000
+1592179200000,2020,2020-Q2,2020-M05,2020-W20,1580601600000,1588464000000,1590883200000,1592092800000,1589760000000,1584316800000,1560729600000
+1592265600000,2020,2020-Q2,2020-M05,2020-W20,1580601600000,1588464000000,1590883200000,1592092800000,1589846400000,1584403200000,1560816000000
+1592352000000,2020,2020-Q2,2020-M05,2020-W20,1580601600000,1588464000000,1590883200000,1592092800000,1589932800000,1584489600000,1560902400000
+1592438400000,2020,2020-Q2,2020-M05,2020-W20,1580601600000,1588464000000,1590883200000,1592092800000,1590019200000,1584576000000,1560988800000
+1592524800000,2020,2020-Q2,2020-M05,2020-W20,1580601600000,1588464000000,1590883200000,1592092800000,1590105600000,1584662400000,1561075200000
+1592611200000,2020,2020-Q2,2020-M05,2020-W20,1580601600000,1588464000000,1590883200000,1592092800000,1590192000000,1584748800000,1561161600000
+1592697600000,2020,2020-Q2,2020-M05,2020-W21,1580601600000,1588464000000,1590883200000,1592697600000,1590278400000,1584835200000,1561248000000
+1592784000000,2020,2020-Q2,2020-M05,2020-W21,1580601600000,1588464000000,1590883200000,1592697600000,1590364800000,1584921600000,1561334400000
+1592870400000,2020,2020-Q2,2020-M05,2020-W21,1580601600000,1588464000000,1590883200000,1592697600000,1590451200000,1585008000000,1561420800000
+1592956800000,2020,2020-Q2,2020-M05,2020-W21,1580601600000,1588464000000,1590883200000,1592697600000,1590537600000,1585094400000,1561507200000
+1593043200000,2020,2020-Q2,2020-M05,2020-W21,1580601600000,1588464000000,1590883200000,1592697600000,1590624000000,1585180800000,1561593600000
+1593129600000,2020,2020-Q2,2020-M05,2020-W21,1580601600000,1588464000000,1590883200000,1592697600000,1590710400000,1585267200000,1561680000000
+1593216000000,2020,2020-Q2,2020-M05,2020-W21,1580601600000,1588464000000,1590883200000,1592697600000,1590796800000,1585353600000,1561766400000
+1593302400000,2020,2020-Q2,2020-M05,2020-W22,1580601600000,1588464000000,1590883200000,1593302400000,,1585440000000,1561852800000
+1593388800000,2020,2020-Q2,2020-M05,2020-W22,1580601600000,1588464000000,1590883200000,1593302400000,,1585526400000,1561939200000
+1593475200000,2020,2020-Q2,2020-M05,2020-W22,1580601600000,1588464000000,1590883200000,1593302400000,,1585612800000,1562025600000
+1593561600000,2020,2020-Q2,2020-M05,2020-W22,1580601600000,1588464000000,1590883200000,1593302400000,,1585699200000,1562112000000
+1593648000000,2020,2020-Q2,2020-M05,2020-W22,1580601600000,1588464000000,1590883200000,1593302400000,,1585785600000,1562198400000
+1593734400000,2020,2020-Q2,2020-M05,2020-W22,1580601600000,1588464000000,1590883200000,1593302400000,,1585872000000,1562284800000
+1593820800000,2020,2020-Q2,2020-M05,2020-W22,1580601600000,1588464000000,1590883200000,1593302400000,,1585958400000,1562371200000
+1593907200000,2020,2020-Q2,2020-M06,2020-W23,1580601600000,1588464000000,1593907200000,1593907200000,1590883200000,1586044800000,1562457600000
+1593993600000,2020,2020-Q2,2020-M06,2020-W23,1580601600000,1588464000000,1593907200000,1593907200000,1590969600000,1586131200000,1562544000000
+1594080000000,2020,2020-Q2,2020-M06,2020-W23,1580601600000,1588464000000,1593907200000,1593907200000,1591056000000,1586217600000,1562630400000
+1594166400000,2020,2020-Q2,2020-M06,2020-W23,1580601600000,1588464000000,1593907200000,1593907200000,1591142400000,1586304000000,1562716800000
+1594252800000,2020,2020-Q2,2020-M06,2020-W23,1580601600000,1588464000000,1593907200000,1593907200000,1591228800000,1586390400000,1562803200000
+1594339200000,2020,2020-Q2,2020-M06,2020-W23,1580601600000,1588464000000,1593907200000,1593907200000,1591315200000,1586476800000,1562889600000
+1594425600000,2020,2020-Q2,2020-M06,2020-W23,1580601600000,1588464000000,1593907200000,1593907200000,1591401600000,1586563200000,1562976000000
+1594512000000,2020,2020-Q2,2020-M06,2020-W24,1580601600000,1588464000000,1593907200000,1594512000000,1591488000000,1586649600000,1563062400000
+1594598400000,2020,2020-Q2,2020-M06,2020-W24,1580601600000,1588464000000,1593907200000,1594512000000,1591574400000,1586736000000,1563148800000
+1594684800000,2020,2020-Q2,2020-M06,2020-W24,1580601600000,1588464000000,1593907200000,1594512000000,1591660800000,1586822400000,1563235200000
+1594771200000,2020,2020-Q2,2020-M06,2020-W24,1580601600000,1588464000000,1593907200000,1594512000000,1591747200000,1586908800000,1563321600000
+1594857600000,2020,2020-Q2,2020-M06,2020-W24,1580601600000,1588464000000,1593907200000,1594512000000,1591833600000,1586995200000,1563408000000
+1594944000000,2020,2020-Q2,2020-M06,2020-W24,1580601600000,1588464000000,1593907200000,1594512000000,1591920000000,1587081600000,1563494400000
+1595030400000,2020,2020-Q2,2020-M06,2020-W24,1580601600000,1588464000000,1593907200000,1594512000000,1592006400000,1587168000000,1563580800000
+1595116800000,2020,2020-Q2,2020-M06,2020-W25,1580601600000,1588464000000,1593907200000,1595116800000,1592092800000,1587254400000,1563667200000
+1595203200000,2020,2020-Q2,2020-M06,2020-W25,1580601600000,1588464000000,1593907200000,1595116800000,1592179200000,1587340800000,1563753600000
+1595289600000,2020,2020-Q2,2020-M06,2020-W25,1580601600000,1588464000000,1593907200000,1595116800000,1592265600000,1587427200000,1563840000000
+1595376000000,2020,2020-Q2,2020-M06,2020-W25,1580601600000,1588464000000,1593907200000,1595116800000,1592352000000,1587513600000,1563926400000
+1595462400000,2020,2020-Q2,2020-M06,2020-W25,1580601600000,1588464000000,1593907200000,1595116800000,1592438400000,1587600000000,1564012800000
+1595548800000,2020,2020-Q2,2020-M06,2020-W25,1580601600000,1588464000000,1593907200000,1595116800000,1592524800000,1587686400000,1564099200000
+1595635200000,2020,2020-Q2,2020-M06,2020-W25,1580601600000,1588464000000,1593907200000,1595116800000,1592611200000,1587772800000,1564185600000
+1595721600000,2020,2020-Q2,2020-M06,2020-W26,1580601600000,1588464000000,1593907200000,1595721600000,1592697600000,1587859200000,1564272000000
+1595808000000,2020,2020-Q2,2020-M06,2020-W26,1580601600000,1588464000000,1593907200000,1595721600000,1592784000000,1587945600000,1564358400000
+1595894400000,2020,2020-Q2,2020-M06,2020-W26,1580601600000,1588464000000,1593907200000,1595721600000,1592870400000,1588032000000,1564444800000
+1595980800000,2020,2020-Q2,2020-M06,2020-W26,1580601600000,1588464000000,1593907200000,1595721600000,1592956800000,1588118400000,1564531200000
+1596067200000,2020,2020-Q2,2020-M06,2020-W26,1580601600000,1588464000000,1593907200000,1595721600000,1593043200000,1588204800000,1564617600000
+1596153600000,2020,2020-Q2,2020-M06,2020-W26,1580601600000,1588464000000,1593907200000,1595721600000,1593129600000,1588291200000,1564704000000
+1596240000000,2020,2020-Q2,2020-M06,2020-W26,1580601600000,1588464000000,1593907200000,1595721600000,1593216000000,1588377600000,1564790400000
+1596326400000,2020,2020-Q3,2020-M07,2020-W27,1580601600000,1596326400000,1596326400000,1596326400000,1593907200000,1588464000000,1564876800000
+1596412800000,2020,2020-Q3,2020-M07,2020-W27,1580601600000,1596326400000,1596326400000,1596326400000,1593993600000,1588550400000,1564963200000
+1596499200000,2020,2020-Q3,2020-M07,2020-W27,1580601600000,1596326400000,1596326400000,1596326400000,1594080000000,1588636800000,1565049600000
+1596585600000,2020,2020-Q3,2020-M07,2020-W27,1580601600000,1596326400000,1596326400000,1596326400000,1594166400000,1588723200000,1565136000000
+1596672000000,2020,2020-Q3,2020-M07,2020-W27,1580601600000,1596326400000,1596326400000,1596326400000,1594252800000,1588809600000,1565222400000
+1596758400000,2020,2020-Q3,2020-M07,2020-W27,1580601600000,1596326400000,1596326400000,1596326400000,1594339200000,1588896000000,1565308800000
+1596844800000,2020,2020-Q3,2020-M07,2020-W27,1580601600000,1596326400000,1596326400000,1596326400000,1594425600000,1588982400000,1565395200000
+1596931200000,2020,2020-Q3,2020-M07,2020-W28,1580601600000,1596326400000,1596326400000,1596931200000,1594512000000,1589068800000,1565481600000
+1597017600000,2020,2020-Q3,2020-M07,2020-W28,1580601600000,1596326400000,1596326400000,1596931200000,1594598400000,1589155200000,1565568000000
+1597104000000,2020,2020-Q3,2020-M07,2020-W28,1580601600000,1596326400000,1596326400000,1596931200000,1594684800000,1589241600000,1565654400000
+1597190400000,2020,2020-Q3,2020-M07,2020-W28,1580601600000,1596326400000,1596326400000,1596931200000,1594771200000,1589328000000,1565740800000
+1597276800000,2020,2020-Q3,2020-M07,2020-W28,1580601600000,1596326400000,1596326400000,1596931200000,1594857600000,1589414400000,1565827200000
+1597363200000,2020,2020-Q3,2020-M07,2020-W28,1580601600000,1596326400000,1596326400000,1596931200000,1594944000000,1589500800000,1565913600000
+1597449600000,2020,2020-Q3,2020-M07,2020-W28,1580601600000,1596326400000,1596326400000,1596931200000,1595030400000,1589587200000,1566000000000
+1597536000000,2020,2020-Q3,2020-M07,2020-W29,1580601600000,1596326400000,1596326400000,1597536000000,1595116800000,1589673600000,1566086400000
+1597622400000,2020,2020-Q3,2020-M07,2020-W29,1580601600000,1596326400000,1596326400000,1597536000000,1595203200000,1589760000000,1566172800000
+1597708800000,2020,2020-Q3,2020-M07,2020-W29,1580601600000,1596326400000,1596326400000,1597536000000,1595289600000,1589846400000,1566259200000
+1597795200000,2020,2020-Q3,2020-M07,2020-W29,1580601600000,1596326400000,1596326400000,1597536000000,1595376000000,1589932800000,1566345600000
+1597881600000,2020,2020-Q3,2020-M07,2020-W29,1580601600000,1596326400000,1596326400000,1597536000000,1595462400000,1590019200000,1566432000000
+1597968000000,2020,2020-Q3,2020-M07,2020-W29,1580601600000,1596326400000,1596326400000,1597536000000,1595548800000,1590105600000,1566518400000
+1598054400000,2020,2020-Q3,2020-M07,2020-W29,1580601600000,1596326400000,1596326400000,1597536000000,1595635200000,1590192000000,1566604800000
+1598140800000,2020,2020-Q3,2020-M07,2020-W30,1580601600000,1596326400000,1596326400000,1598140800000,1595721600000,1590278400000,1566691200000
+1598227200000,2020,2020-Q3,2020-M07,2020-W30,1580601600000,1596326400000,1596326400000,1598140800000,1595808000000,1590364800000,1566777600000
+1598313600000,2020,2020-Q3,2020-M07,2020-W30,1580601600000,1596326400000,1596326400000,1598140800000,1595894400000,1590451200000,1566864000000
+1598400000000,2020,2020-Q3,2020-M07,2020-W30,1580601600000,1596326400000,1596326400000,1598140800000,1595980800000,1590537600000,1566950400000
+1598486400000,2020,2020-Q3,2020-M07,2020-W30,1580601600000,1596326400000,1596326400000,1598140800000,1596067200000,1590624000000,1567036800000
+1598572800000,2020,2020-Q3,2020-M07,2020-W30,1580601600000,1596326400000,1596326400000,1598140800000,1596153600000,1590710400000,1567123200000
+1598659200000,2020,2020-Q3,2020-M07,2020-W30,1580601600000,1596326400000,1596326400000,1598140800000,1596240000000,1590796800000,1567209600000
+1598745600000,2020,2020-Q3,2020-M08,2020-W31,1580601600000,1596326400000,1598745600000,1598745600000,1596326400000,1590883200000,1567296000000
+1598832000000,2020,2020-Q3,2020-M08,2020-W31,1580601600000,1596326400000,1598745600000,1598745600000,1596412800000,1590969600000,1567382400000
+1598918400000,2020,2020-Q3,2020-M08,2020-W31,1580601600000,1596326400000,1598745600000,1598745600000,1596499200000,1591056000000,1567468800000
+1599004800000,2020,2020-Q3,2020-M08,2020-W31,1580601600000,1596326400000,1598745600000,1598745600000,1596585600000,1591142400000,1567555200000
+1599091200000,2020,2020-Q3,2020-M08,2020-W31,1580601600000,1596326400000,1598745600000,1598745600000,1596672000000,1591228800000,1567641600000
+1599177600000,2020,2020-Q3,2020-M08,2020-W31,1580601600000,1596326400000,1598745600000,1598745600000,1596758400000,1591315200000,1567728000000
+1599264000000,2020,2020-Q3,2020-M08,2020-W31,1580601600000,1596326400000,1598745600000,1598745600000,1596844800000,1591401600000,1567814400000
+1599350400000,2020,2020-Q3,2020-M08,2020-W32,1580601600000,1596326400000,1598745600000,1599350400000,1596931200000,1591488000000,1567900800000
+1599436800000,2020,2020-Q3,2020-M08,2020-W32,1580601600000,1596326400000,1598745600000,1599350400000,1597017600000,1591574400000,1567987200000
+1599523200000,2020,2020-Q3,2020-M08,2020-W32,1580601600000,1596326400000,1598745600000,1599350400000,1597104000000,1591660800000,1568073600000
+1599609600000,2020,2020-Q3,2020-M08,2020-W32,1580601600000,1596326400000,1598745600000,1599350400000,1597190400000,1591747200000,1568160000000
+1599696000000,2020,2020-Q3,2020-M08,2020-W32,1580601600000,1596326400000,1598745600000,1599350400000,1597276800000,1591833600000,1568246400000
+1599782400000,2020,2020-Q3,2020-M08,2020-W32,1580601600000,1596326400000,1598745600000,1599350400000,1597363200000,1591920000000,1568332800000
+1599868800000,2020,2020-Q3,2020-M08,2020-W32,1580601600000,1596326400000,1598745600000,1599350400000,1597449600000,1592006400000,1568419200000
+1599955200000,2020,2020-Q3,2020-M08,2020-W33,1580601600000,1596326400000,1598745600000,1599955200000,1597536000000,1592092800000,1568505600000
+1600041600000,2020,2020-Q3,2020-M08,2020-W33,1580601600000,1596326400000,1598745600000,1599955200000,1597622400000,1592179200000,1568592000000
+1600128000000,2020,2020-Q3,2020-M08,2020-W33,1580601600000,1596326400000,1598745600000,1599955200000,1597708800000,1592265600000,1568678400000
+1600214400000,2020,2020-Q3,2020-M08,2020-W33,1580601600000,1596326400000,1598745600000,1599955200000,1597795200000,1592352000000,1568764800000
+1600300800000,2020,2020-Q3,2020-M08,2020-W33,1580601600000,1596326400000,1598745600000,1599955200000,1597881600000,1592438400000,1568851200000
+1600387200000,2020,2020-Q3,2020-M08,2020-W33,1580601600000,1596326400000,1598745600000,1599955200000,1597968000000,1592524800000,1568937600000
+1600473600000,2020,2020-Q3,2020-M08,2020-W33,1580601600000,1596326400000,1598745600000,1599955200000,1598054400000,1592611200000,1569024000000
+1600560000000,2020,2020-Q3,2020-M08,2020-W34,1580601600000,1596326400000,1598745600000,1600560000000,1598140800000,1592697600000,1569110400000
+1600646400000,2020,2020-Q3,2020-M08,2020-W34,1580601600000,1596326400000,1598745600000,1600560000000,1598227200000,1592784000000,1569196800000
+1600732800000,2020,2020-Q3,2020-M08,2020-W34,1580601600000,1596326400000,1598745600000,1600560000000,1598313600000,1592870400000,1569283200000
+1600819200000,2020,2020-Q3,2020-M08,2020-W34,1580601600000,1596326400000,1598745600000,1600560000000,1598400000000,1592956800000,1569369600000
+1600905600000,2020,2020-Q3,2020-M08,2020-W34,1580601600000,1596326400000,1598745600000,1600560000000,1598486400000,1593043200000,1569456000000
+1600992000000,2020,2020-Q3,2020-M08,2020-W34,1580601600000,1596326400000,1598745600000,1600560000000,1598572800000,1593129600000,1569542400000
+1601078400000,2020,2020-Q3,2020-M08,2020-W34,1580601600000,1596326400000,1598745600000,1600560000000,1598659200000,1593216000000,1569628800000
+1601164800000,2020,2020-Q3,2020-M08,2020-W35,1580601600000,1596326400000,1598745600000,1601164800000,,1593302400000,1569715200000
+1601251200000,2020,2020-Q3,2020-M08,2020-W35,1580601600000,1596326400000,1598745600000,1601164800000,,1593388800000,1569801600000
+1601337600000,2020,2020-Q3,2020-M08,2020-W35,1580601600000,1596326400000,1598745600000,1601164800000,,1593475200000,1569888000000
+1601424000000,2020,2020-Q3,2020-M08,2020-W35,1580601600000,1596326400000,1598745600000,1601164800000,,1593561600000,1569974400000
+1601510400000,2020,2020-Q3,2020-M08,2020-W35,1580601600000,1596326400000,1598745600000,1601164800000,,1593648000000,1570060800000
+1601596800000,2020,2020-Q3,2020-M08,2020-W35,1580601600000,1596326400000,1598745600000,1601164800000,,1593734400000,1570147200000
+1601683200000,2020,2020-Q3,2020-M08,2020-W35,1580601600000,1596326400000,1598745600000,1601164800000,,1593820800000,1570233600000
+1601769600000,2020,2020-Q3,2020-M09,2020-W36,1580601600000,1596326400000,1601769600000,1601769600000,1598745600000,1593907200000,1570320000000
+1601856000000,2020,2020-Q3,2020-M09,2020-W36,1580601600000,1596326400000,1601769600000,1601769600000,1598832000000,1593993600000,1570406400000
+1601942400000,2020,2020-Q3,2020-M09,2020-W36,1580601600000,1596326400000,1601769600000,1601769600000,1598918400000,1594080000000,1570492800000
+1602028800000,2020,2020-Q3,2020-M09,2020-W36,1580601600000,1596326400000,1601769600000,1601769600000,1599004800000,1594166400000,1570579200000
+1602115200000,2020,2020-Q3,2020-M09,2020-W36,1580601600000,1596326400000,1601769600000,1601769600000,1599091200000,1594252800000,1570665600000
+1602201600000,2020,2020-Q3,2020-M09,2020-W36,1580601600000,1596326400000,1601769600000,1601769600000,1599177600000,1594339200000,1570752000000
+1602288000000,2020,2020-Q3,2020-M09,2020-W36,1580601600000,1596326400000,1601769600000,1601769600000,1599264000000,1594425600000,1570838400000
+1602374400000,2020,2020-Q3,2020-M09,2020-W37,1580601600000,1596326400000,1601769600000,1602374400000,1599350400000,1594512000000,1570924800000
+1602460800000,2020,2020-Q3,2020-M09,2020-W37,1580601600000,1596326400000,1601769600000,1602374400000,1599436800000,1594598400000,1571011200000
+1602547200000,2020,2020-Q3,2020-M09,2020-W37,1580601600000,1596326400000,1601769600000,1602374400000,1599523200000,1594684800000,1571097600000
+1602633600000,2020,2020-Q3,2020-M09,2020-W37,1580601600000,1596326400000,1601769600000,1602374400000,1599609600000,1594771200000,1571184000000
+1602720000000,2020,2020-Q3,2020-M09,2020-W37,1580601600000,1596326400000,1601769600000,1602374400000,1599696000000,1594857600000,1571270400000
+1602806400000,2020,2020-Q3,2020-M09,2020-W37,1580601600000,1596326400000,1601769600000,1602374400000,1599782400000,1594944000000,1571356800000
+1602892800000,2020,2020-Q3,2020-M09,2020-W37,1580601600000,1596326400000,1601769600000,1602374400000,1599868800000,1595030400000,1571443200000
+1602979200000,2020,2020-Q3,2020-M09,2020-W38,1580601600000,1596326400000,1601769600000,1602979200000,1599955200000,1595116800000,1571529600000
+1603065600000,2020,2020-Q3,2020-M09,2020-W38,1580601600000,1596326400000,1601769600000,1602979200000,1600041600000,1595203200000,1571616000000
+1603152000000,2020,2020-Q3,2020-M09,2020-W38,1580601600000,1596326400000,1601769600000,1602979200000,1600128000000,1595289600000,1571702400000
+1603238400000,2020,2020-Q3,2020-M09,2020-W38,1580601600000,1596326400000,1601769600000,1602979200000,1600214400000,1595376000000,1571788800000
+1603324800000,2020,2020-Q3,2020-M09,2020-W38,1580601600000,1596326400000,1601769600000,1602979200000,1600300800000,1595462400000,1571875200000
+1603411200000,2020,2020-Q3,2020-M09,2020-W38,1580601600000,1596326400000,1601769600000,1602979200000,1600387200000,1595548800000,1571961600000
+1603497600000,2020,2020-Q3,2020-M09,2020-W38,1580601600000,1596326400000,1601769600000,1602979200000,1600473600000,1595635200000,1572048000000
+1603584000000,2020,2020-Q3,2020-M09,2020-W39,1580601600000,1596326400000,1601769600000,1603584000000,1600560000000,1595721600000,1572134400000
+1603670400000,2020,2020-Q3,2020-M09,2020-W39,1580601600000,1596326400000,1601769600000,1603584000000,1600646400000,1595808000000,1572220800000
+1603756800000,2020,2020-Q3,2020-M09,2020-W39,1580601600000,1596326400000,1601769600000,1603584000000,1600732800000,1595894400000,1572307200000
+1603843200000,2020,2020-Q3,2020-M09,2020-W39,1580601600000,1596326400000,1601769600000,1603584000000,1600819200000,1595980800000,1572393600000
+1603929600000,2020,2020-Q3,2020-M09,2020-W39,1580601600000,1596326400000,1601769600000,1603584000000,1600905600000,1596067200000,1572480000000
+1604016000000,2020,2020-Q3,2020-M09,2020-W39,1580601600000,1596326400000,1601769600000,1603584000000,1600992000000,1596153600000,1572566400000
+1604102400000,2020,2020-Q3,2020-M09,2020-W39,1580601600000,1596326400000,1601769600000,1603584000000,1601078400000,1596240000000,1572652800000
+1604188800000,2020,2020-Q4,2020-M10,2020-W40,1580601600000,1604188800000,1604188800000,1604188800000,1601769600000,1596326400000,1572739200000
+1604275200000,2020,2020-Q4,2020-M10,2020-W40,1580601600000,1604188800000,1604188800000,1604188800000,1601856000000,1596412800000,1572825600000
+1604361600000,2020,2020-Q4,2020-M10,2020-W40,1580601600000,1604188800000,1604188800000,1604188800000,1601942400000,1596499200000,1572912000000
+1604448000000,2020,2020-Q4,2020-M10,2020-W40,1580601600000,1604188800000,1604188800000,1604188800000,1602028800000,1596585600000,1572998400000
+1604534400000,2020,2020-Q4,2020-M10,2020-W40,1580601600000,1604188800000,1604188800000,1604188800000,1602115200000,1596672000000,1573084800000
+1604620800000,2020,2020-Q4,2020-M10,2020-W40,1580601600000,1604188800000,1604188800000,1604188800000,1602201600000,1596758400000,1573171200000
+1604707200000,2020,2020-Q4,2020-M10,2020-W40,1580601600000,1604188800000,1604188800000,1604188800000,1602288000000,1596844800000,1573257600000
+1604793600000,2020,2020-Q4,2020-M10,2020-W41,1580601600000,1604188800000,1604188800000,1604793600000,1602374400000,1596931200000,1573344000000
+1604880000000,2020,2020-Q4,2020-M10,2020-W41,1580601600000,1604188800000,1604188800000,1604793600000,1602460800000,1597017600000,1573430400000
+1604966400000,2020,2020-Q4,2020-M10,2020-W41,1580601600000,1604188800000,1604188800000,1604793600000,1602547200000,1597104000000,1573516800000
+1605052800000,2020,2020-Q4,2020-M10,2020-W41,1580601600000,1604188800000,1604188800000,1604793600000,1602633600000,1597190400000,1573603200000
+1605139200000,2020,2020-Q4,2020-M10,2020-W41,1580601600000,1604188800000,1604188800000,1604793600000,1602720000000,1597276800000,1573689600000
+1605225600000,2020,2020-Q4,2020-M10,2020-W41,1580601600000,1604188800000,1604188800000,1604793600000,1602806400000,1597363200000,1573776000000
+1605312000000,2020,2020-Q4,2020-M10,2020-W41,1580601600000,1604188800000,1604188800000,1604793600000,1602892800000,1597449600000,1573862400000
+1605398400000,2020,2020-Q4,2020-M10,2020-W42,1580601600000,1604188800000,1604188800000,1605398400000,1602979200000,1597536000000,1573948800000
+1605484800000,2020,2020-Q4,2020-M10,2020-W42,1580601600000,1604188800000,1604188800000,1605398400000,1603065600000,1597622400000,1574035200000
+1605571200000,2020,2020-Q4,2020-M10,2020-W42,1580601600000,1604188800000,1604188800000,1605398400000,1603152000000,1597708800000,1574121600000
+1605657600000,2020,2020-Q4,2020-M10,2020-W42,1580601600000,1604188800000,1604188800000,1605398400000,1603238400000,1597795200000,1574208000000
+1605744000000,2020,2020-Q4,2020-M10,2020-W42,1580601600000,1604188800000,1604188800000,1605398400000,1603324800000,1597881600000,1574294400000
+1605830400000,2020,2020-Q4,2020-M10,2020-W42,1580601600000,1604188800000,1604188800000,1605398400000,1603411200000,1597968000000,1574380800000
+1605916800000,2020,2020-Q4,2020-M10,2020-W42,1580601600000,1604188800000,1604188800000,1605398400000,1603497600000,1598054400000,1574467200000
+1606003200000,2020,2020-Q4,2020-M10,2020-W43,1580601600000,1604188800000,1604188800000,1606003200000,1603584000000,1598140800000,1574553600000
+1606089600000,2020,2020-Q4,2020-M10,2020-W43,1580601600000,1604188800000,1604188800000,1606003200000,1603670400000,1598227200000,1574640000000
+1606176000000,2020,2020-Q4,2020-M10,2020-W43,1580601600000,1604188800000,1604188800000,1606003200000,1603756800000,1598313600000,1574726400000
+1606262400000,2020,2020-Q4,2020-M10,2020-W43,1580601600000,1604188800000,1604188800000,1606003200000,1603843200000,1598400000000,1574812800000
+1606348800000,2020,2020-Q4,2020-M10,2020-W43,1580601600000,1604188800000,1604188800000,1606003200000,1603929600000,1598486400000,1574899200000
+1606435200000,2020,2020-Q4,2020-M10,2020-W43,1580601600000,1604188800000,1604188800000,1606003200000,1604016000000,1598572800000,1574985600000
+1606521600000,2020,2020-Q4,2020-M10,2020-W43,1580601600000,1604188800000,1604188800000,1606003200000,1604102400000,1598659200000,1575072000000
+1606608000000,2020,2020-Q4,2020-M11,2020-W44,1580601600000,1604188800000,1606608000000,1606608000000,1604188800000,1598745600000,1575158400000
+1606694400000,2020,2020-Q4,2020-M11,2020-W44,1580601600000,1604188800000,1606608000000,1606608000000,1604275200000,1598832000000,1575244800000
+1606780800000,2020,2020-Q4,2020-M11,2020-W44,1580601600000,1604188800000,1606608000000,1606608000000,1604361600000,1598918400000,1575331200000
+1606867200000,2020,2020-Q4,2020-M11,2020-W44,1580601600000,1604188800000,1606608000000,1606608000000,1604448000000,1599004800000,1575417600000
+1606953600000,2020,2020-Q4,2020-M11,2020-W44,1580601600000,1604188800000,1606608000000,1606608000000,1604534400000,1599091200000,1575504000000
+1607040000000,2020,2020-Q4,2020-M11,2020-W44,1580601600000,1604188800000,1606608000000,1606608000000,1604620800000,1599177600000,1575590400000
+1607126400000,2020,2020-Q4,2020-M11,2020-W44,1580601600000,1604188800000,1606608000000,1606608000000,1604707200000,1599264000000,1575676800000
+1607212800000,2020,2020-Q4,2020-M11,2020-W45,1580601600000,1604188800000,1606608000000,1607212800000,1604793600000,1599350400000,1575763200000
+1607299200000,2020,2020-Q4,2020-M11,2020-W45,1580601600000,1604188800000,1606608000000,1607212800000,1604880000000,1599436800000,1575849600000
+1607385600000,2020,2020-Q4,2020-M11,2020-W45,1580601600000,1604188800000,1606608000000,1607212800000,1604966400000,1599523200000,1575936000000
+1607472000000,2020,2020-Q4,2020-M11,2020-W45,1580601600000,1604188800000,1606608000000,1607212800000,1605052800000,1599609600000,1576022400000
+1607558400000,2020,2020-Q4,2020-M11,2020-W45,1580601600000,1604188800000,1606608000000,1607212800000,1605139200000,1599696000000,1576108800000
+1607644800000,2020,2020-Q4,2020-M11,2020-W45,1580601600000,1604188800000,1606608000000,1607212800000,1605225600000,1599782400000,1576195200000
+1607731200000,2020,2020-Q4,2020-M11,2020-W45,1580601600000,1604188800000,1606608000000,1607212800000,1605312000000,1599868800000,1576281600000
+1607817600000,2020,2020-Q4,2020-M11,2020-W46,1580601600000,1604188800000,1606608000000,1607817600000,1605398400000,1599955200000,1576368000000
+1607904000000,2020,2020-Q4,2020-M11,2020-W46,1580601600000,1604188800000,1606608000000,1607817600000,1605484800000,1600041600000,1576454400000
+1607990400000,2020,2020-Q4,2020-M11,2020-W46,1580601600000,1604188800000,1606608000000,1607817600000,1605571200000,1600128000000,1576540800000
+1608076800000,2020,2020-Q4,2020-M11,2020-W46,1580601600000,1604188800000,1606608000000,1607817600000,1605657600000,1600214400000,1576627200000
+1608163200000,2020,2020-Q4,2020-M11,2020-W46,1580601600000,1604188800000,1606608000000,1607817600000,1605744000000,1600300800000,1576713600000
+1608249600000,2020,2020-Q4,2020-M11,2020-W46,1580601600000,1604188800000,1606608000000,1607817600000,1605830400000,1600387200000,1576800000000
+1608336000000,2020,2020-Q4,2020-M11,2020-W46,1580601600000,1604188800000,1606608000000,1607817600000,1605916800000,1600473600000,1576886400000
+1608422400000,2020,2020-Q4,2020-M11,2020-W47,1580601600000,1604188800000,1606608000000,1608422400000,1606003200000,1600560000000,1576972800000
+1608508800000,2020,2020-Q4,2020-M11,2020-W47,1580601600000,1604188800000,1606608000000,1608422400000,1606089600000,1600646400000,1577059200000
+1608595200000,2020,2020-Q4,2020-M11,2020-W47,1580601600000,1604188800000,1606608000000,1608422400000,1606176000000,1600732800000,1577145600000
+1608681600000,2020,2020-Q4,2020-M11,2020-W47,1580601600000,1604188800000,1606608000000,1608422400000,1606262400000,1600819200000,1577232000000
+1608768000000,2020,2020-Q4,2020-M11,2020-W47,1580601600000,1604188800000,1606608000000,1608422400000,1606348800000,1600905600000,1577318400000
+1608854400000,2020,2020-Q4,2020-M11,2020-W47,1580601600000,1604188800000,1606608000000,1608422400000,1606435200000,1600992000000,1577404800000
+1608940800000,2020,2020-Q4,2020-M11,2020-W47,1580601600000,1604188800000,1606608000000,1608422400000,1606521600000,1601078400000,1577491200000
+1609027200000,2020,2020-Q4,2020-M11,2020-W48,1580601600000,1604188800000,1606608000000,1609027200000,,1601164800000,1577577600000
+1609113600000,2020,2020-Q4,2020-M11,2020-W48,1580601600000,1604188800000,1606608000000,1609027200000,,1601251200000,1577664000000
+1609200000000,2020,2020-Q4,2020-M11,2020-W48,1580601600000,1604188800000,1606608000000,1609027200000,,1601337600000,1577750400000
+1609286400000,2020,2020-Q4,2020-M11,2020-W48,1580601600000,1604188800000,1606608000000,1609027200000,,1601424000000,1577836800000
+1609372800000,2020,2020-Q4,2020-M11,2020-W48,1580601600000,1604188800000,1606608000000,1609027200000,,1601510400000,1577923200000
+1609459200000,2020,2020-Q4,2020-M11,2020-W48,1580601600000,1604188800000,1606608000000,1609027200000,,1601596800000,1578009600000
+1609545600000,2020,2020-Q4,2020-M11,2020-W48,1580601600000,1604188800000,1606608000000,1609027200000,,1601683200000,1578096000000
+1609632000000,2020,2020-Q4,2020-M12,2020-W49,1580601600000,1604188800000,1609632000000,1609632000000,1606608000000,1601769600000,1578182400000
+1609718400000,2020,2020-Q4,2020-M12,2020-W49,1580601600000,1604188800000,1609632000000,1609632000000,1606694400000,1601856000000,1578268800000
+1609804800000,2020,2020-Q4,2020-M12,2020-W49,1580601600000,1604188800000,1609632000000,1609632000000,1606780800000,1601942400000,1578355200000
+1609891200000,2020,2020-Q4,2020-M12,2020-W49,1580601600000,1604188800000,1609632000000,1609632000000,1606867200000,1602028800000,1578441600000
+1609977600000,2020,2020-Q4,2020-M12,2020-W49,1580601600000,1604188800000,1609632000000,1609632000000,1606953600000,1602115200000,1578528000000
+1610064000000,2020,2020-Q4,2020-M12,2020-W49,1580601600000,1604188800000,1609632000000,1609632000000,1607040000000,1602201600000,1578614400000
+1610150400000,2020,2020-Q4,2020-M12,2020-W49,1580601600000,1604188800000,1609632000000,1609632000000,1607126400000,1602288000000,1578700800000
+1610236800000,2020,2020-Q4,2020-M12,2020-W50,1580601600000,1604188800000,1609632000000,1610236800000,1607212800000,1602374400000,1578787200000
+1610323200000,2020,2020-Q4,2020-M12,2020-W50,1580601600000,1604188800000,1609632000000,1610236800000,1607299200000,1602460800000,1578873600000
+1610409600000,2020,2020-Q4,2020-M12,2020-W50,1580601600000,1604188800000,1609632000000,1610236800000,1607385600000,1602547200000,1578960000000
+1610496000000,2020,2020-Q4,2020-M12,2020-W50,1580601600000,1604188800000,1609632000000,1610236800000,1607472000000,1602633600000,1579046400000
+1610582400000,2020,2020-Q4,2020-M12,2020-W50,1580601600000,1604188800000,1609632000000,1610236800000,1607558400000,1602720000000,1579132800000
+1610668800000,2020,2020-Q4,2020-M12,2020-W50,1580601600000,1604188800000,1609632000000,1610236800000,1607644800000,1602806400000,1579219200000
+1610755200000,2020,2020-Q4,2020-M12,2020-W50,1580601600000,1604188800000,1609632000000,1610236800000,1607731200000,1602892800000,1579305600000
+1610841600000,2020,2020-Q4,2020-M12,2020-W51,1580601600000,1604188800000,1609632000000,1610841600000,1607817600000,1602979200000,1579392000000
+1610928000000,2020,2020-Q4,2020-M12,2020-W51,1580601600000,1604188800000,1609632000000,1610841600000,1607904000000,1603065600000,1579478400000
+1611014400000,2020,2020-Q4,2020-M12,2020-W51,1580601600000,1604188800000,1609632000000,1610841600000,1607990400000,1603152000000,1579564800000
+1611100800000,2020,2020-Q4,2020-M12,2020-W51,1580601600000,1604188800000,1609632000000,1610841600000,1608076800000,1603238400000,1579651200000
+1611187200000,2020,2020-Q4,2020-M12,2020-W51,1580601600000,1604188800000,1609632000000,1610841600000,1608163200000,1603324800000,1579737600000
+1611273600000,2020,2020-Q4,2020-M12,2020-W51,1580601600000,1604188800000,1609632000000,1610841600000,1608249600000,1603411200000,1579824000000
+1611360000000,2020,2020-Q4,2020-M12,2020-W51,1580601600000,1604188800000,1609632000000,1610841600000,1608336000000,1603497600000,1579910400000
+1611446400000,2020,2020-Q4,2020-M12,2020-W52,1580601600000,1604188800000,1609632000000,1611446400000,1608422400000,1603584000000,1579996800000
+1611532800000,2020,2020-Q4,2020-M12,2020-W52,1580601600000,1604188800000,1609632000000,1611446400000,1608508800000,1603670400000,1580083200000
+1611619200000,2020,2020-Q4,2020-M12,2020-W52,1580601600000,1604188800000,1609632000000,1611446400000,1608595200000,1603756800000,1580169600000
+1611705600000,2020,2020-Q4,2020-M12,2020-W52,1580601600000,1604188800000,1609632000000,1611446400000,1608681600000,1603843200000,1580256000000
+1611792000000,2020,2020-Q4,2020-M12,2020-W52,1580601600000,1604188800000,1609632000000,1611446400000,1608768000000,1603929600000,1580342400000
+1611878400000,2020,2020-Q4,2020-M12,2020-W52,1580601600000,1604188800000,1609632000000,1611446400000,1608854400000,1604016000000,1580428800000
+1611964800000,2020,2020-Q4,2020-M12,2020-W52,1580601600000,1604188800000,1609632000000,1611446400000,1608940800000,1604102400000,1580515200000
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/retailcalendar_pinot.jobspec.yml b/packages/cubejs-testing-drivers/fixtures/pinot/retailcalendar_pinot.jobspec.yml
new file mode 100644
index 0000000000000..db1600ec22943
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/retailcalendar_pinot.jobspec.yml
@@ -0,0 +1,23 @@
+executionFrameworkSpec:
+ name: 'standalone'
+ segmentGenerationJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentGenerationJobRunner'
+ segmentTarPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentTarPushJobRunner'
+ segmentUriPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentUriPushJobRunner'
+jobType: SegmentCreationAndTarPush
+inputDirURI: '/tmp/data/test-resources/rawdata/retailcalendar_pinot/'
+includeFileNamePattern: 'glob:**/*.csv'
+outputDirURI: '/tmp/data/segments/retailcalendar_pinot/'
+overwriteOutput: true
+pinotFSSpecs:
+ - scheme: file
+ className: org.apache.pinot.spi.filesystem.LocalPinotFS
+recordReaderSpec:
+ dataFormat: 'csv'
+ className: 'org.apache.pinot.plugin.inputformat.csv.CSVRecordReader'
+ configClassName: 'org.apache.pinot.plugin.inputformat.csv.CSVRecordReaderConfig'
+tableSpec:
+ tableName: 'retailcalendar_pinot'
+pinotClusterSpecs:
+ - controllerURI: 'http://localhost:9000'
+pushJobSpec:
+ pushAttempts: 1
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/retailcalendar_pinot.schema.json b/packages/cubejs-testing-drivers/fixtures/pinot/retailcalendar_pinot.schema.json
new file mode 100644
index 0000000000000..29bab9d9dba46
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/retailcalendar_pinot.schema.json
@@ -0,0 +1,74 @@
+{
+ "schemaName": "retailcalendar_pinot",
+ "dimensionFieldSpecs": [
+ {
+ "name": "retail_year_name",
+ "dataType": "STRING"
+ },
+ {
+ "name": "retail_quarter_name",
+ "dataType": "STRING"
+ },
+ {
+ "name": "retail_month_name",
+ "dataType": "STRING"
+ },
+ {
+ "name": "retail_week_name",
+ "dataType": "STRING"
+ }
+ ],
+ "dateTimeFieldSpecs": [
+ {
+ "name": "date_val",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ },
+ {
+ "name": "retail_year_begin_date",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ },
+ {
+ "name": "retail_quarter_begin_date",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ },
+ {
+ "name": "retail_month_begin_date",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ },
+ {
+ "name": "retail_week_begin_date",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ },
+ {
+ "name": "retail_date_prev_month",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ },
+ {
+ "name": "retail_date_prev_quarter",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ },
+ {
+ "name": "retail_date_prev_year",
+ "dataType": "TIMESTAMP",
+ "format": "1:MILLISECONDS:EPOCH",
+ "granularity": "1:MILLISECONDS"
+ }
+ ],
+ "primaryKeyColumns": [
+ "date_val"
+ ]
+}
diff --git a/packages/cubejs-testing-drivers/fixtures/pinot/retailcalendar_pinot.table.json b/packages/cubejs-testing-drivers/fixtures/pinot/retailcalendar_pinot.table.json
new file mode 100644
index 0000000000000..a0445d0f78846
--- /dev/null
+++ b/packages/cubejs-testing-drivers/fixtures/pinot/retailcalendar_pinot.table.json
@@ -0,0 +1,27 @@
+{
+ "tableName": "retailcalendar_pinot",
+ "tableType": "OFFLINE",
+ "segmentsConfig": {
+ "schemaName": "retailcalendar_pinot",
+ "replication": "1"
+ },
+ "tenants": {
+ "broker": "DefaultTenant",
+ "server": "DefaultTenant"
+ },
+ "tableIndexConfig": {
+ "loadMode": "MMAP",
+ "nullHandlingEnabled": true
+ },
+ "metadata": {},
+ "ingestionConfig": {
+ "batchIngestionConfig": {
+ "segmentIngestionType": "REFRESH",
+ "segmentIngestionFrequency": "DAILY"
+ }
+ },
+ "isDimTable": true,
+ "dimensionTableConfig": {
+ "disablePreload": false
+ }
+}
diff --git a/packages/cubejs-testing-drivers/package.json b/packages/cubejs-testing-drivers/package.json
index 2d3215b16d8e1..ea63d30b63fec 100644
--- a/packages/cubejs-testing-drivers/package.json
+++ b/packages/cubejs-testing-drivers/package.json
@@ -69,6 +69,10 @@
"redshift-core": "yarn test-driver -i dist/test/redshift-core.test.js",
"redshift-full": "yarn test-driver -i dist/test/redshift-full.test.js",
"redshift-export-bucket-s3-full": "yarn test-driver -i dist/test/redshift-export-bucket-s3-full.test.js",
+ "pinot-driver": "yarn test-driver -i dist/test/pinot-driver.test.js",
+ "pinot-core": "yarn test-driver -i dist/test/pinot-core.test.js",
+ "pinot-full": "yarn test-driver -i dist/test/pinot-full.test.js",
+ "generate-pinot-fixtures": "node dist/test/generatePinotFixtures.js",
"update-all-snapshots-local": "yarn run oracle-full --mode=local -u; yarn run athena-export-bucket-s3-full --mode=local -u; yarn run bigquery-export-bucket-gcs-full --mode=local -u; yarn run clickhouse-full --mode=local -u; yarn run clickhouse-export-bucket-s3-full --mode=local -u; yarn run clickhouse-export-bucket-s3-prefix-full --mode=local -u; yarn run databricks-jdbc-export-bucket-azure-full --mode=local -u; yarn run databricks-jdbc-export-bucket-azure-prefix-full --mode=local -u; yarn run databricks-jdbc-export-bucket-gcs-full --mode=local -u; yarn run databricks-jdbc-export-bucket-gcs-prefix-full --mode=local -u; yarn run databricks-jdbc-export-bucket-s3-full --mode=local -u; yarn run databricks-jdbc-export-bucket-s3-prefix-full --mode=local -u; yarn run databricks-jdbc-full --mode=local -u; yarn run mssql-full --mode=local -u; yarn run mysql-full --mode=local -u; yarn run postgres-full --mode=local -u; yarn run redshift-export-bucket-s3-full --mode=local -u; yarn run redshift-full --mode=local -u; yarn run snowflake-encrypted-pk-full --mode=local -u; yarn run snowflake-export-bucket-azure-full --mode=local -u; yarn run snowflake-export-bucket-azure-prefix-full --mode=local -u; yarn run snowflake-export-bucket-azure-via-storage-integration-full --mode=local -u; yarn run snowflake-export-bucket-gcs-full --mode=local -u; yarn run snowflake-export-bucket-gcs-prefix-full --mode=local -u; yarn run snowflake-export-bucket-s3-full --mode=local -u; yarn run snowflake-export-bucket-s3-via-storage-integration-iam-roles-full --mode=local -u; yarn run snowflake-export-bucket-s3-prefix-full --mode=local -u; yarn run snowflake-export-bucket-azure-prefix-full --mode=local -u; yarn run snowflake-export-bucket-azure-full --mode=local -u; yarn run snowflake-full --mode=local -u",
"tst": "clear && yarn tsc && yarn bigquery-core"
},
@@ -87,6 +91,7 @@
"@cubejs-backend/mssql-driver": "1.7.1",
"@cubejs-backend/mysql-driver": "1.7.1",
"@cubejs-backend/oracle-driver": "1.7.1",
+ "@cubejs-backend/pinot-driver": "1.7.1",
"@cubejs-backend/postgres-driver": "1.7.1",
"@cubejs-backend/query-orchestrator": "1.7.1",
"@cubejs-backend/server-core": "1.7.1",
diff --git a/packages/cubejs-testing-drivers/src/helpers/getComposePath.ts b/packages/cubejs-testing-drivers/src/helpers/getComposePath.ts
index 5c0f895100251..60cfba5a19e9c 100644
--- a/packages/cubejs-testing-drivers/src/helpers/getComposePath.ts
+++ b/packages/cubejs-testing-drivers/src/helpers/getComposePath.ts
@@ -57,6 +57,16 @@ export function getComposePath(type: string, fixture: Fixture, isLocal: boolean)
};
}
+ // Multi-container backends (e.g. Pinot) declare their data-plane services here.
+ if (fixture.services) {
+ Object.keys(fixture.services).forEach((name) => {
+ compose.services[name] = {
+ ...fixture.services![name],
+ container_name: name,
+ };
+ });
+ }
+
fs.writeFileSync(
path.resolve(_path, _file),
YAML.stringify(compose),
diff --git a/packages/cubejs-testing-drivers/src/helpers/index.ts b/packages/cubejs-testing-drivers/src/helpers/index.ts
index 99196d94af287..c9b5d735eb270 100644
--- a/packages/cubejs-testing-drivers/src/helpers/index.ts
+++ b/packages/cubejs-testing-drivers/src/helpers/index.ts
@@ -11,6 +11,7 @@ import { getCore } from './getCore';
import { getDriver } from './getDriver';
import { patchDriver } from './patchDriver';
import { runEnvironment } from './runEnvironment';
+import { seedPinot } from './seedPinot';
export {
buildCube,
@@ -27,4 +28,5 @@ export {
getDriver,
patchDriver,
runEnvironment,
+ seedPinot,
};
diff --git a/packages/cubejs-testing-drivers/src/helpers/runEnvironment.ts b/packages/cubejs-testing-drivers/src/helpers/runEnvironment.ts
index 3e690be7243b8..03cbe8424a5a7 100644
--- a/packages/cubejs-testing-drivers/src/helpers/runEnvironment.ts
+++ b/packages/cubejs-testing-drivers/src/helpers/runEnvironment.ts
@@ -11,6 +11,7 @@ import { getComposePath } from './getComposePath';
import { getCubeJsPath } from './getCubeJsPath';
import { getPackageJsonPath } from './getPackageJsonPath';
import { getSchemaPath } from './getSchemaPath';
+import { seedPinot } from './seedPinot';
import { Environment } from '../types/Environment';
interface CubeEnvironment {
@@ -167,6 +168,11 @@ export async function runEnvironment(
if (type === 'oracle') {
compose.withWaitStrategy('data', Wait.forHealthCheck().withStartupTimeout(240 * 1000));
}
+ // Pinot is a 4-container cluster (zookeeper/controller/broker/server). Wait on the
+ // server HEALTHCHECK (last in the dependency chain) before seeding/connecting.
+ if (type === 'pinot') {
+ compose.withWaitStrategy('pinot-server', Wait.forHealthCheck().withStartupTimeout(180 * 1000));
+ }
const environment = await compose.up();
@@ -175,10 +181,24 @@ export async function runEnvironment(
logs: await environment.getContainer('store').logs(),
};
+ // Pinot has no SQL DDL: register tables + ingest CSV via the controller before
+ // anything queries, and expose the broker as the driver connection endpoint.
+ let data: Environment['data'];
+ if (type === 'pinot') {
+ await seedPinot(environment);
+ data = {
+ port: environment.getContainer('pinot-broker').getMappedPort(8099),
+ logs: await environment.getContainer('pinot-broker').logs(),
+ };
+ }
+
const cliEnv = isLocal ? new CubeCliEnvironment(composePath) : null;
- const mappedDataPort = fixture.data ? environment.getContainer('data').getMappedPort(
- parseInt(fixture.data.ports[0], 10),
- ) : null;
+ let mappedDataPort: number | null = null;
+ if (fixture.data) {
+ mappedDataPort = environment.getContainer('data').getMappedPort(parseInt(fixture.data.ports[0], 10));
+ } else if (data) {
+ mappedDataPort = data.port;
+ }
if (cliEnv) {
cliEnv.withEnvironment({
CUBEJS_CUBESTORE_HOST: '127.0.0.1',
@@ -213,25 +233,16 @@ export async function runEnvironment(
};
if (fixture.data) {
- const data = {
+ data = {
port: mappedDataPort!,
logs: await environment.getContainer('data').logs(),
};
- return {
- cube,
- store,
- data,
- stop: async () => {
- await environment.down({ timeout: 30 * 1000 });
- if (cliEnv) {
- await cliEnv.down();
- }
- },
- };
}
+
return {
cube,
store,
+ ...(data ? { data } : {}),
stop: async () => {
await environment.down({ timeout: 30 * 1000 });
if (cliEnv) {
diff --git a/packages/cubejs-testing-drivers/src/helpers/seedPinot.ts b/packages/cubejs-testing-drivers/src/helpers/seedPinot.ts
new file mode 100644
index 0000000000000..a9c93a585ff9c
--- /dev/null
+++ b/packages/cubejs-testing-drivers/src/helpers/seedPinot.ts
@@ -0,0 +1,65 @@
+import { pausePromise } from '@cubejs-backend/shared';
+
+import type { StartedDockerComposeEnvironment } from 'testcontainers';
+
+const PINOT_TABLES = [
+ 'customers_pinot',
+ 'products_pinot',
+ 'ecommerce_pinot',
+ 'bigecommerce_pinot',
+ 'retailcalendar_pinot',
+];
+
+// Directory the committed fixtures/pinot resources are mounted at inside the
+// controller container (see fixtures/pinot.json `services.pinot-controller.volumes`).
+const RESOURCE_DIR = '/tmp/data/test-resources';
+const ADMIN = '/opt/pinot/bin/pinot-admin.sh';
+const CONTROLLER_URL = 'http://localhost:9000';
+const AUTH = 'admin:mysecret';
+
+async function waitForSegmentsOnline(controller: any, table: string): Promise {
+ const url = `${CONTROLLER_URL}/tables/${table}/externalview`;
+
+ for (let attempt = 0; attempt < 60; attempt += 1) {
+ // eslint-disable-next-line no-await-in-loop
+ const { output } = await controller.exec(['curl', '-s', '-u', AUTH, url]);
+ if (output.includes('ERROR')) {
+ throw new Error(`Pinot segment load failed for ${table}: ${output}`);
+ }
+
+ if (output.includes('ONLINE')) {
+ return;
+ }
+
+ // eslint-disable-next-line no-await-in-loop
+ await pausePromise(2 * 1000);
+ }
+
+ throw new Error(`Timed out waiting for ${table} segments to come ONLINE`);
+}
+
+export async function seedPinot(environment: StartedDockerComposeEnvironment): Promise {
+ const controller = environment.getContainer('pinot-controller');
+
+ for (const table of PINOT_TABLES) {
+ await controller.exec([
+ ADMIN, 'AddTable',
+ '-controllerPort', '9000',
+ '-schemaFile', `${RESOURCE_DIR}/${table}.schema.json`,
+ '-tableConfigFile', `${RESOURCE_DIR}/${table}.table.json`,
+ '-exec',
+ ]);
+ }
+
+ for (const table of PINOT_TABLES) {
+ await controller.exec([
+ ADMIN, 'LaunchDataIngestionJob',
+ '-jobSpecFile', `${RESOURCE_DIR}/${table}.jobspec.yml`,
+ ]);
+ }
+
+ // Wait until every table's segments have been loaded by the server.
+ for (const table of PINOT_TABLES) {
+ await waitForSegmentsOnline(controller, table);
+ }
+}
diff --git a/packages/cubejs-testing-drivers/src/tests/testConnection.ts b/packages/cubejs-testing-drivers/src/tests/testConnection.ts
index e10a5fe3f6b3b..54cd65269dc2a 100644
--- a/packages/cubejs-testing-drivers/src/tests/testConnection.ts
+++ b/packages/cubejs-testing-drivers/src/tests/testConnection.ts
@@ -24,6 +24,11 @@ export function testConnection(type: string): void {
jest.setTimeout(60 * 5 * 1000);
const fixtures = getFixtures(type);
+ // Pinot cannot be seeded via SQL DDL; runEnvironment ingests fixed-name
+ // `_pinot` tables via the controller. Every other driver uses the
+ // per-suite 'driver' suffix. The SQL create/stream/drop cases are skipped for
+ // Pinot through fixtures.skip (see fixtures/pinot.json).
+ const suffix = type === 'pinot' ? 'pinot' : 'driver';
let driver: BaseDriver & {
stream?: (
query: string,
@@ -43,7 +48,7 @@ export function testConnection(type: string): void {
}
beforeAll(async () => {
- env = await runEnvironment(type, 'driver');
+ env = await runEnvironment(type, suffix);
if (env.data) {
process.env.CUBEJS_DB_HOST = '127.0.0.1';
process.env.CUBEJS_DB_PORT = `${env.data.port}`;
@@ -61,14 +66,14 @@ export function testConnection(type: string): void {
});
execute('must creates a data source', async () => {
- query = getCreateQueries(type, 'driver');
+ query = getCreateQueries(type, suffix);
await Promise.all(query.map(async (q) => {
await driver.query(q);
}));
});
execute('must select from the data source', async () => {
- query = getSelectQueries(type, 'driver');
+ query = getSelectQueries(type, suffix);
const response = await Promise.all(
query.map(async (q) => {
const res = await driver.query(q);
@@ -173,7 +178,7 @@ export function testConnection(type: string): void {
});
execute('must download query from the data source via memory', async () => {
- query = getSelectQueries(type, 'driver');
+ query = getSelectQueries(type, suffix);
expect(driver.downloadQueryResults).toBeDefined();
const response = await Promise.all(
@@ -200,7 +205,7 @@ export function testConnection(type: string): void {
});
execute('must download query from the data source via stream', async () => {
- query = getSelectQueries(type, 'driver');
+ query = getSelectQueries(type, suffix);
expect(driver.downloadQueryResults).toBeDefined();
const response = await Promise.all(
@@ -240,7 +245,7 @@ export function testConnection(type: string): void {
execute('must delete the data source', async () => {
const tables = Object
.keys(fixtures.tables)
- .map((key: string) => `${fixtures.tables[key]}_driver`);
+ .map((key: string) => `${fixtures.tables[key]}_${suffix}`);
await Promise.all(
tables.map(async (t) => {
await driver.dropTable(t);
diff --git a/packages/cubejs-testing-drivers/src/tests/testQueries.ts b/packages/cubejs-testing-drivers/src/tests/testQueries.ts
index d3c70c26d1364..6a9b623399c9b 100644
--- a/packages/cubejs-testing-drivers/src/tests/testQueries.ts
+++ b/packages/cubejs-testing-drivers/src/tests/testQueries.ts
@@ -113,7 +113,9 @@ export function testQueries(type: string, { includeIncrementalSchemaSuite, exten
const apiToken = sign({}, 'mysupersecret');
- const suffix = randomBytes(8).toString('hex');
+ // Pinot uses a fixed suffix so the model lines up with the committed
+ // `_pinot` resources; every other driver isolates runs with random hex.
+ const suffix = type === 'pinot' ? 'pinot' : randomBytes(8).toString('hex');
const tables = Object
.keys(fixtures.tables)
.map((key: string) => `${fixtures.tables[key]}_${suffix}`);
@@ -127,36 +129,44 @@ export function testQueries(type: string, { includeIncrementalSchemaSuite, exten
process.env.CUBEJS_CUBESTORE_PASS = 'root';
process.env.CUBEJS_CACHE_AND_QUEUE_DRIVER = 'cubestore'; // memory
if (env.data) {
- process.env.CUBEJS_DB_HOST = '127.0.0.1';
+ process.env.CUBEJS_DB_HOST = type === 'pinot' ? 'http://127.0.0.1' : '127.0.0.1';
process.env.CUBEJS_DB_PORT = `${env.data.port}`;
}
client = cubejs(apiToken, {
apiUrl: `http://127.0.0.1:${env.cube.port}/cubejs-api/v1`,
});
driver = (await getDriver(type)).source;
- queries = getCreateQueries(type, suffix);
- console.log(`Creating ${queries.length} fixture tables`);
- try {
- for (const q of queries) {
- await driver.createTableRaw(q);
- if (type.includes('redshift')) {
- await delay(10 * OP_DELAY);
+
+ // Pinot has no SQL DDL — runEnvironment already ingested the fixture tables
+ // via the controller. Every other driver seeds via CREATE TABLE here.
+ if (type !== 'pinot') {
+ queries = getCreateQueries(type, suffix);
+ console.log(`Creating ${queries.length} fixture tables`);
+ try {
+ for (const q of queries) {
+ await driver.createTableRaw(q);
+ if (type.includes('redshift')) {
+ await delay(10 * OP_DELAY);
+ }
}
+ console.log(`Creating ${queries.length} fixture tables completed`);
+ } catch (e: any) {
+ console.log('Error creating fixtures', e.stack);
+ throw e;
}
- console.log(`Creating ${queries.length} fixture tables completed`);
- } catch (e: any) {
- console.log('Error creating fixtures', e.stack);
- throw e;
}
});
afterAll(async () => {
try {
- console.log(`Dropping ${tables.length} fixture tables`);
- for (const t of tables) {
- await driver.dropTable(t);
+ // Pinot has no dropTable; the cluster is torn down with the environment.
+ if (type !== 'pinot') {
+ console.log(`Dropping ${tables.length} fixture tables`);
+ for (const t of tables) {
+ await driver.dropTable(t);
+ }
+ console.log(`Dropping ${tables.length} fixture tables completed`);
}
- console.log(`Dropping ${tables.length} fixture tables completed`);
} finally {
await driver.release();
await env.stop();
diff --git a/packages/cubejs-testing-drivers/src/tests/testSequence.ts b/packages/cubejs-testing-drivers/src/tests/testSequence.ts
index ec544fdffb928..7d338e78f245d 100644
--- a/packages/cubejs-testing-drivers/src/tests/testSequence.ts
+++ b/packages/cubejs-testing-drivers/src/tests/testSequence.ts
@@ -17,6 +17,10 @@ export function testSequence(type: string): void {
jest.setTimeout(60 * 5 * 1000);
const fixtures = getFixtures(type);
+ // Pinot is seeded by runEnvironment (controller ingestion) with fixed
+ // `_pinot` names; the Internal pre-agg cases are skipped via
+ // fixtures.skip since Pinot cannot materialize source-side rollups.
+ const suffix = type === 'pinot' ? 'pinot' : 'core';
let core: CubejsServerCoreExposed;
let source: PatchedDriver;
let storage: PatchedDriver;
@@ -32,7 +36,7 @@ export function testSequence(type: string): void {
}
beforeAll(async () => {
- env = await runEnvironment(type, 'core');
+ env = await runEnvironment(type, suffix);
process.env.CUBEJS_REFRESH_WORKER = 'true';
process.env.CUBEJS_CUBESTORE_HOST = '127.0.0.1';
process.env.CUBEJS_CUBESTORE_PORT = process.env.CUBEJS_CUBESTORE_PORT ? process.env.CUBEJS_CUBESTORE_PORT : `${env.store.port}`;
@@ -40,30 +44,36 @@ export function testSequence(type: string): void {
process.env.CUBEJS_CUBESTORE_PASS = 'root';
process.env.CUBEJS_CACHE_AND_QUEUE_DRIVER = 'memory'; // memory, cubestore
if (env.data) {
- process.env.CUBEJS_DB_HOST = '127.0.0.1';
+ process.env.CUBEJS_DB_HOST = type === 'pinot' ? 'http://127.0.0.1' : '127.0.0.1';
process.env.CUBEJS_DB_PORT = `${env.data.port}`;
}
const drivers = await getDriver(type);
source = drivers.source;
storage = drivers.storage;
- query = getCreateQueries(type, 'core');
- await Promise.all(query.map(async (q) => {
- await source.query(q);
- }));
+ // Pinot has no SQL DDL — it is seeded by runEnvironment (controller ingestion).
+ if (type !== 'pinot') {
+ query = getCreateQueries(type, suffix);
+ await Promise.all(query.map(async (q) => {
+ await source.query(q);
+ }));
+ }
patchDriver(source);
patchDriver(storage);
core = getCore(type, 'cubestore', source, storage);
});
afterAll(async () => {
- const tables = Object
- .keys(fixtures.tables)
- .map((key: string) => `${fixtures.tables[key]}_core`);
- await Promise.all(
- tables.map(async (t) => {
- await source.dropTable(t);
- })
- );
+ // Pinot has no dropTable; the cluster is torn down with the environment.
+ if (type !== 'pinot') {
+ const tables = Object
+ .keys(fixtures.tables)
+ .map((key: string) => `${fixtures.tables[key]}_${suffix}`);
+ await Promise.all(
+ tables.map(async (t) => {
+ await source.dropTable(t);
+ })
+ );
+ }
await source.release();
await storage.release();
await core.shutdown();
diff --git a/packages/cubejs-testing-drivers/src/types/Fixture.ts b/packages/cubejs-testing-drivers/src/types/Fixture.ts
index f85b5304cb396..75fdd939b4d5a 100644
--- a/packages/cubejs-testing-drivers/src/types/Fixture.ts
+++ b/packages/cubejs-testing-drivers/src/types/Fixture.ts
@@ -23,6 +23,15 @@ export type Fixture = {
ports: string[],
[key: string]: any,
},
+ // Extra data-plane compose services for drivers whose backend is not a single
+ // container (e.g. Apache Pinot: zookeeper + controller + broker + server). Each
+ // entry is spread verbatim into the generated docker-compose (see getComposePath).
+ services?: {
+ [name: string]: {
+ image: string,
+ [key: string]: any,
+ },
+ },
cast: Cast,
tables: {
[table: string]: string,
diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/pinot-core.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/pinot-core.test.ts.snap
new file mode 100644
index 0000000000000..5ba4b406f88f0
--- /dev/null
+++ b/packages/cubejs-testing-drivers/test/__snapshots__/pinot-core.test.ts.snap
@@ -0,0 +1,57 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Sequence with the @cubejs-backend/pinot-driver for the Customers.RollingExternal 1`] = `
+Array [
+ Array [
+ "downloadQueryResults",
+ ],
+ Array [
+ "createSchemaIfNotExists",
+ "uploadTableWithIndexes",
+ ],
+]
+`;
+
+exports[`Sequence with the @cubejs-backend/pinot-driver for the ECommerce.SimpleAnalysisExternal 1`] = `
+Array [
+ Array [
+ "downloadQueryResults",
+ ],
+ Array [
+ "uploadTableWithIndexes",
+ ],
+]
+`;
+
+exports[`Sequence with the @cubejs-backend/pinot-driver for the ECommerce.TimeAnalysisExternal 1`] = `
+Array [
+ Array [
+ "downloadQueryResults",
+ "downloadQueryResults",
+ "downloadQueryResults",
+ "downloadQueryResults",
+ "downloadQueryResults",
+ "downloadQueryResults",
+ "downloadQueryResults",
+ "downloadQueryResults",
+ "downloadQueryResults",
+ "downloadQueryResults",
+ "downloadQueryResults",
+ "downloadQueryResults",
+ ],
+ Array [
+ "uploadTableWithIndexes",
+ "uploadTableWithIndexes",
+ "uploadTableWithIndexes",
+ "uploadTableWithIndexes",
+ "uploadTableWithIndexes",
+ "uploadTableWithIndexes",
+ "uploadTableWithIndexes",
+ "uploadTableWithIndexes",
+ "uploadTableWithIndexes",
+ "uploadTableWithIndexes",
+ "uploadTableWithIndexes",
+ "uploadTableWithIndexes",
+ ],
+]
+`;
diff --git a/packages/cubejs-testing-drivers/test/__snapshots__/pinot-driver.test.ts.snap b/packages/cubejs-testing-drivers/test/__snapshots__/pinot-driver.test.ts.snap
new file mode 100644
index 0000000000000..36f53a1641b46
--- /dev/null
+++ b/packages/cubejs-testing-drivers/test/__snapshots__/pinot-driver.test.ts.snap
@@ -0,0 +1,9936 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 1`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 2`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 3`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 4`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 5`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 6`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 7`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 8`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 9`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 10`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 11`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 12`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 13`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 14`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 15`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 16`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 17`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 18`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 19`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 20`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 21`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 22`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 23`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 24`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 25`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 26`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 27`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 28`] = `
+Object {
+ "category": Any,
+ "product_name": Any,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 29`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 30`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 31`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 32`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 33`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 34`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 35`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 36`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 37`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 38`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 39`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 40`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 41`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 42`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 43`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 44`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 45`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 46`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 47`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 48`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 49`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 50`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 51`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 52`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 53`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 54`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 55`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 56`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 57`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 58`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 59`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 60`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 61`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 62`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 63`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 64`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 65`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 66`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 67`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 68`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 69`] = `
+Object {
+ "customer_id": Any,
+ "customer_name": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 70`] = `
+Object {
+ "category": Any,
+ "city": Any,
+ "completed_date": "2020-10-20 00:00:00.0",
+ "customer_id": Any,
+ "discount": Anything,
+ "order_date": Anything,
+ "order_id": Any,
+ "product_name": Any,
+ "profit": Anything,
+ "quantity": Anything,
+ "row_id": Anything,
+ "sales": Anything,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 71`] = `
+Object {
+ "category": Any,
+ "city": Any,
+ "completed_date": "2020-01-24 00:00:00.0",
+ "customer_id": Any,
+ "discount": Anything,
+ "order_date": Anything,
+ "order_id": Any,
+ "product_name": Any,
+ "profit": Anything,
+ "quantity": Anything,
+ "row_id": Anything,
+ "sales": Anything,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 72`] = `
+Object {
+ "category": Any,
+ "city": Any,
+ "completed_date": "2020-06-26 00:00:00.0",
+ "customer_id": Any,
+ "discount": Anything,
+ "order_date": Anything,
+ "order_id": Any,
+ "product_name": Any,
+ "profit": Anything,
+ "quantity": Anything,
+ "row_id": Anything,
+ "sales": Anything,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 73`] = `
+Object {
+ "category": Any,
+ "city": Any,
+ "completed_date": "2020-10-13 00:00:00.0",
+ "customer_id": Any,
+ "discount": Anything,
+ "order_date": Anything,
+ "order_id": Any,
+ "product_name": Any,
+ "profit": Anything,
+ "quantity": Anything,
+ "row_id": Anything,
+ "sales": Anything,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 74`] = `
+Object {
+ "category": Any,
+ "city": Any,
+ "completed_date": "2020-09-18 00:00:00.0",
+ "customer_id": Any,
+ "discount": Anything,
+ "order_date": Anything,
+ "order_id": Any,
+ "product_name": Any,
+ "profit": Anything,
+ "quantity": Anything,
+ "row_id": Anything,
+ "sales": Anything,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 75`] = `
+Object {
+ "category": Any,
+ "city": Any,
+ "completed_date": "2020-11-13 00:00:00.0",
+ "customer_id": Any,
+ "discount": Anything,
+ "order_date": Anything,
+ "order_id": Any,
+ "product_name": Any,
+ "profit": Anything,
+ "quantity": Anything,
+ "row_id": Anything,
+ "sales": Anything,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 76`] = `
+Object {
+ "category": Any,
+ "city": Any,
+ "completed_date": "2020-11-06 00:00:00.0",
+ "customer_id": Any,
+ "discount": Anything,
+ "order_date": Anything,
+ "order_id": Any,
+ "product_name": Any,
+ "profit": Anything,
+ "quantity": Anything,
+ "row_id": Anything,
+ "sales": Anything,
+ "sub_category": Any,
+}
+`;
+
+exports[`Raw @cubejs-backend/pinot-driver must select from the data source 77`] = `
+Object {
+ "category": Any,
+ "city": Any,
+ "completed_date": "2020-09-02 00:00:00.0",
+ "customer_id": Any,
+ "discount": Anything,
+ "order_date": Anything,
+ "order_id": Any,
+ "product_name": Any,
+ "profit": Anything,
+ "quantity": Anything,
+ "row_id": Anything,
+ "sales": Anything,
+ "sub_category": Any