Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,9 @@ export class BaseQuery {
};

try {
const buildResult = nativeBuildSqlAndParams(queryParams);
// Establish the current query context, JS extensions like Funnels/RefreshKeys can resolve compiler.contextQuery()
// during the member-SQL callbacks the native planner makes back into JS.
const buildResult = this.compilers.compiler.withQuery(this, () => nativeBuildSqlAndParams(queryParams));

const [query, params, preAggResult] = buildResult;
const paramsArray = [...params];
Expand Down Expand Up @@ -4037,7 +4039,7 @@ export class BaseQuery {
}

inDbTimeZone(date) {
return localTimestampToUtc(this.timezone, this.timestampFormat(), date);
return localTimestampToUtc(this.timezone || 'UTC', this.timestampFormat(), date);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { PostgresQuery } from '../../../src/adapter/PostgresQuery';
import { prepareJsCompiler } from '../../unit/PrepareCompiler';
import { dbRunner } from './PostgresDBRunner';

describe('Extensions', () => {
jest.setTimeout(200 * 1000);

// A three-step funnel (View -> Cart -> Purchase). Event sources are inline
// `VALUES` selects so the test is fully self-contained and needs no fixture.
//
// Raw events (user_id, ts):
// View: 1@01-01, 2@01-02, 3@01-03, 4@01-04
// Cart: 1@01-03, 2@01-20, 3@2016-12-31, 4@01-06 (timeToConvert: 5 day)
// Purchase: 1@01-10
//
// Cart has `timeToConvert: '5 day'`, so a Cart event only counts when it
// happens after the View event and within 5 days of it:
// user 1: cart 01-03 is 2 days after view 01-01 -> converts
// user 2: cart 01-20 is 18 days after view 01-02 -> dropped (too late)
// user 3: cart 2016-12-31 is before view 01-03 -> dropped (before)
// user 4: cart 01-06 is 2 days after view 01-04 -> converts
// Purchase joins off Cart, so only users who reached Cart can reach it:
// user 1 purchases, user 4 does not.
//
// Expected conversions per step: View=4, Cart=2, Purchase=1.
const { compiler, joinGraph, cubeEvaluator } = prepareJsCompiler(`
const Funnels = require('Funnels');

cube('Funnel', {
extends: Funnels.eventFunnel({
userId: { sql: 'user_id' },
time: { sql: 'ts' },
steps: [
{
name: 'View',
eventsTable: {
sql: "select user_id, ts from (values (1, timestamp '2017-01-01'), (2, timestamp '2017-01-02'), (3, timestamp '2017-01-03'), (4, timestamp '2017-01-04')) as t(user_id, ts)"
}
},
{
name: 'Cart',
timeToConvert: '5 day',
eventsTable: {
sql: "select user_id, ts from (values (1, timestamp '2017-01-03'), (2, timestamp '2017-01-20'), (3, timestamp '2016-12-31'), (4, timestamp '2017-01-06')) as t(user_id, ts)"
}
},
{
name: 'Purchase',
eventsTable: {
sql: "select user_id, ts from (values (1, timestamp '2017-01-10')) as t(user_id, ts)"
}
}
]
})
})
`, { allowNodeRequire: true });

async function runQueryTest(q: any, expectedResult: any) {
await compiler.compile();
const query = new PostgresQuery(
{ joinGraph, cubeEvaluator, compiler },
{ ...q, timezone: 'UTC', preAggregationsSchema: '' }
);

const qp = query.buildSqlAndParams();
console.log(qp);

const res = await dbRunner.testQuery(qp);
console.log(JSON.stringify(res));

expect(res).toEqual(expectedResult);
}

describe('Funnels', () => {
it('conversions per step', async () => runQueryTest({
measures: ['Funnel.conversions'],
dimensions: ['Funnel.step'],
order: [{ id: 'Funnel.conversions', desc: true }],
}, [
{ funnel__step: 'View', funnel__conversions: '4' },
{ funnel__step: 'Cart', funnel__conversions: '2' },
{ funnel__step: 'Purchase', funnel__conversions: '1' },
]));

it('total conversions across all steps', async () => runQueryTest({
measures: ['Funnel.conversions'],
}, [
{ funnel__conversions: '7' },
]));
});
});
4 changes: 2 additions & 2 deletions packages/cubejs-schema-compiler/test/unit/extensions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe('Extensions', () => {
timeDimensions: [{
dimension: 'VisitorsFunnel.time',
granularity: 'day',
dateRange: { from: '2017-01-01', to: '2017-01-30' }
dateRange: ['2017-01-01', '2017-01-30']
}],
timezone: 'America/Los_Angeles'
});
Expand All @@ -92,7 +92,7 @@ describe('Extensions', () => {
timeDimensions: [{
dimension: 'FooBar.time',
granularity: 'day',
dateRange: { from: '2017-01-01', to: '2017-01-30' }
dateRange: ['2017-01-01', '2017-01-30']
}],
timezone: 'America/Los_Angeles'
});
Expand Down
1 change: 1 addition & 0 deletions packages/cubejs-testing-drivers/fixtures/athena.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"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}"
},
"ports" : ["4000", "5656"]
Expand Down
1 change: 1 addition & 0 deletions packages/cubejs-testing-drivers/fixtures/bigquery.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"CUBEJS_DB_EXPORT_BUCKET": "cube-open-source-export-bucket",
"CUBEJS_DB_EXPORT_BUCKET_TYPE": "gcp",
"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}"
},
"ports" : ["4000", "5656"]
Expand Down
1 change: 1 addition & 0 deletions packages/cubejs-testing-drivers/fixtures/clickhouse.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"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": ["data"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"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}"
},
"ports" : ["4000", "5656"]
Expand Down
1 change: 1 addition & 0 deletions packages/cubejs-testing-drivers/fixtures/mssql.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"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": ["data"],
Expand Down
1 change: 1 addition & 0 deletions packages/cubejs-testing-drivers/fixtures/mysql.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"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": ["data"],
Expand Down
1 change: 1 addition & 0 deletions packages/cubejs-testing-drivers/fixtures/oracle.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"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": ["data"],
Expand Down
1 change: 1 addition & 0 deletions packages/cubejs-testing-drivers/fixtures/postgres.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"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": ["data"],
Expand Down
1 change: 1 addition & 0 deletions packages/cubejs-testing-drivers/fixtures/redshift.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"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}"
},
"ports" : ["4000", "5656"]
Expand Down
1 change: 1 addition & 0 deletions packages/cubejs-testing-drivers/fixtures/snowflake.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
"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}"
},
"ports" : ["4000", "5656"]
Expand Down
Loading