-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #117 from lifeomic/LO-5734
LO-5734: Data Lake Query Commands
- Loading branch information
Showing
6 changed files
with
239 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
'use strict'; | ||
|
||
const options = require('../common-yargs'); | ||
|
||
exports.command = 'data-lake <command>'; | ||
exports.desc = 'Perform operations on the analytics data lake.'; | ||
exports.builder = yargs => { | ||
return options(yargs.commandDir('data_lake_cmds')); | ||
}; | ||
exports.handler = function (argv) {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
'use strict'; | ||
|
||
const { get } = require('../../api'); | ||
const print = require('../../print'); | ||
|
||
exports.command = 'get-query <queryId>'; | ||
exports.desc = 'Fetch a single query execution.'; | ||
exports.builder = yargs => { | ||
yargs.positional('queryId', { | ||
describe: 'Id of the query to fetch.', | ||
type: 'string' | ||
}); | ||
}; | ||
|
||
exports.handler = async argv => { | ||
const response = await get(argv, `/v1/analytics/query/${argv.queryId}`); | ||
print(response.data, argv); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
'use strict'; | ||
|
||
const { list } = require('../../api'); | ||
const print = require('../../print'); | ||
const querystring = require('querystring'); | ||
|
||
exports.command = 'list-queries <projectId>'; | ||
exports.desc = 'List the query executions in the project.'; | ||
exports.builder = yargs => { | ||
yargs.positional('projectId', { | ||
describe: 'The ID of the project to fetch queries of.', | ||
type: 'string' | ||
}).option('page-size', { | ||
alias: 'n', | ||
type: 'number', | ||
default: 25, | ||
describe: 'Maximum number of queries to return.' | ||
}).option('next-page-token', { | ||
alias: 't', | ||
type: 'string', | ||
describe: 'Token to retrieve the next page of results' | ||
}); | ||
}; | ||
|
||
exports.handler = async argv => { | ||
const query = { | ||
datasetId: argv.projectId, | ||
pageSize: argv.pageSize | ||
}; | ||
|
||
if (argv.nextPageToken) { | ||
query.nextPageToken = argv.nextPageToken; | ||
} | ||
|
||
const response = await list(argv, `/v1/analytics/query?${querystring.stringify(query)}`); | ||
print(response.data, argv); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
'use strict'; | ||
|
||
const { post } = require('../../api'); | ||
const print = require('../../print'); | ||
const read = require('../../read'); | ||
|
||
exports.command = 'query <projectId>'; | ||
exports.desc = 'Submits a query to the Lifeomic data-lake API. A SQL query string can also be read from stdin.'; | ||
exports.builder = yargs => { | ||
yargs.positional('projectId', { | ||
describe: 'The ID of the project to search within.', | ||
type: 'string' | ||
}).option('query', { | ||
alias: 'q', | ||
type: 'string', | ||
describe: 'The SQL query to run.' | ||
}).option('output-file-name', { | ||
alias: 'o', | ||
type: 'string', | ||
describe: 'Name of the results file.', | ||
demandOption: true | ||
}); | ||
}; | ||
|
||
exports.handler = async argv => { | ||
const request = { | ||
outputFileName: argv.outputFileName, | ||
datasetId: argv.projectId | ||
}; | ||
|
||
if (argv.query) { | ||
request.query = argv.query; | ||
} else { | ||
request.query = await read(argv); | ||
} | ||
|
||
const response = await post(argv, '/v1/analytics/query', request); | ||
print(response.data, argv); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"name": "@lifeomic/cli", | ||
"version": "9.6.0", | ||
"version": "9.7.0", | ||
"description": "CLI for interacting with the LifeOmic PHC API.", | ||
"main": "lo.js", | ||
"author": "LifeOmic <[email protected]>", | ||
|
@@ -43,6 +43,7 @@ | |
"stream-chain": "^2.1.0", | ||
"stream-csv-as-json": "^1.0.1", | ||
"stream-json": "^1.2.1", | ||
"uuid": "^3.3.2", | ||
"yargs": "^12.0.5" | ||
}, | ||
"devDependencies": { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
'use strict'; | ||
|
||
const uuid = require('uuid'); | ||
const yargs = require('yargs'); | ||
const sinon = require('sinon'); | ||
const test = require('ava'); | ||
const proxyquire = require('proxyquire'); | ||
|
||
const getStub = sinon.stub(); | ||
const postStub = sinon.stub(); | ||
const listStub = sinon.stub(); | ||
const printSpy = sinon.spy(); | ||
const readStub = sinon.stub(); | ||
let callback; | ||
|
||
const queryCmd = proxyquire('../../../lib/cmds/data_lake_cmds/query', { | ||
'../../api': { | ||
post: postStub | ||
}, | ||
'../../print': (data, opts) => { | ||
printSpy(data, opts); | ||
callback(); | ||
}, | ||
'../../read': async () => readStub() | ||
}); | ||
|
||
const listCmd = proxyquire('../../../lib/cmds/data_lake_cmds/list-queries', { | ||
'../../api': { | ||
list: listStub | ||
}, | ||
'../../print': (data, opts) => { | ||
printSpy(data, opts); | ||
callback(); | ||
} | ||
}); | ||
|
||
const getCmd = proxyquire('../../../lib/cmds/data_lake_cmds/get-query', { | ||
'../../api': { | ||
get: getStub | ||
}, | ||
'../../print': (data, opts) => { | ||
printSpy(data, opts); | ||
callback(); | ||
} | ||
}); | ||
|
||
test.afterEach.always(t => { | ||
getStub.resetHistory(); | ||
postStub.resetHistory(); | ||
listStub.resetHistory(); | ||
printSpy.resetHistory(); | ||
readStub.resetHistory(); | ||
callback = null; | ||
}); | ||
|
||
test.serial.cb('The "data-lake-query" command should accept a query as an optional argument', t => { | ||
const query = "SELECT sample_id, gene, impact, amino_acid_change, histology FROM variant WHERE tumor_site='breast'"; | ||
const datasetId = uuid(); | ||
const outputFileName = 'data-lake-test'; | ||
|
||
postStub.onFirstCall().returns({}); | ||
|
||
callback = () => { | ||
t.is(postStub.callCount, 1); | ||
t.is(postStub.getCall(0).args[1], '/v1/analytics/query'); | ||
t.deepEqual(postStub.getCall(0).args[2], { | ||
query: query, | ||
datasetId: datasetId, | ||
outputFileName: outputFileName | ||
}); | ||
t.is(printSpy.callCount, 1); | ||
t.end(); | ||
}; | ||
|
||
yargs.command(queryCmd).parse(`query ${datasetId} -q "${query}" -o ${outputFileName}`); | ||
}); | ||
|
||
test.serial.cb('The "data-lake-query" command should accept a query from stdin', t => { | ||
const query = "SELECT sample_id, gene, impact, amino_acid_change, histology FROM variant WHERE tumor_site='breast'"; | ||
const datasetId = uuid(); | ||
const outputFileName = 'data-lake-test'; | ||
|
||
postStub.onFirstCall().returns({}); | ||
readStub.onFirstCall().returns(query); | ||
|
||
callback = () => { | ||
t.is(postStub.callCount, 1); | ||
t.is(postStub.getCall(0).args[1], '/v1/analytics/query'); | ||
t.deepEqual(postStub.getCall(0).args[2], { | ||
query: query, | ||
datasetId: datasetId, | ||
outputFileName: outputFileName | ||
}); | ||
t.is(printSpy.callCount, 1); | ||
t.end(); | ||
}; | ||
|
||
yargs.command(queryCmd).parse(`query ${datasetId} -o ${outputFileName}`); | ||
}); | ||
|
||
test.serial.cb('The "data-lake-list-queries" should accept page-size and next-page-token', t => { | ||
const datasetId = uuid(); | ||
const pageSize = 30; | ||
const nextPageToken = uuid(); | ||
|
||
listStub.onFirstCall().returns({}); | ||
const expectedPath = `/v1/analytics/query?datasetId=${datasetId}&pageSize=${pageSize}&nextPageToken=${nextPageToken}`; | ||
|
||
callback = () => { | ||
t.is(listStub.callCount, 1); | ||
t.is(listStub.getCall(0).args[1], expectedPath); | ||
t.is(printSpy.callCount, 1); | ||
t.end(); | ||
}; | ||
|
||
yargs.command(listCmd).parse(`list-queries ${datasetId} -n ${pageSize} -t ${nextPageToken}`); | ||
}); | ||
|
||
test.serial.cb('The "data-lake-get-query" should add query-id to path', t => { | ||
const queryId = uuid(); | ||
|
||
getStub.onFirstCall().returns({}); | ||
const expectedPath = `/v1/analytics/query/${queryId}`; | ||
|
||
callback = () => { | ||
t.is(getStub.callCount, 1); | ||
t.is(getStub.getCall(0).args[1], expectedPath); | ||
t.is(printSpy.callCount, 1); | ||
t.end(); | ||
}; | ||
|
||
yargs.command(getCmd).parse(`get-query ${queryId}`); | ||
}); |