Skip to content
Draft
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
62 changes: 44 additions & 18 deletions src/bigquery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,17 +376,17 @@
private _universeDomain: string;
private _defaultJobCreationMode: JobCreationMode;

createQueryStream(options?: Query | string): ResourceStream<RowMetadata> {

Check warning on line 379 in src/bigquery.ts

View workflow job for this annotation

GitHub Actions / lint

'options' is defined but never used
// placeholder body, overwritten in constructor
return new ResourceStream<RowMetadata>({}, () => {});
}

getDatasetsStream(options?: GetDatasetsOptions): ResourceStream<Dataset> {

Check warning on line 384 in src/bigquery.ts

View workflow job for this annotation

GitHub Actions / lint

'options' is defined but never used
// placeholder body, overwritten in constructor
return new ResourceStream<Dataset>({}, () => {});
}

getJobsStream(options?: GetJobsOptions): ResourceStream<Job> {

Check warning on line 389 in src/bigquery.ts

View workflow job for this annotation

GitHub Actions / lint

'options' is defined but never used
// placeholder body, overwritten in constructor
return new ResourceStream<Job>({}, () => {});
}
Expand Down Expand Up @@ -602,24 +602,8 @@
let schemaFields: TableField[] = extend(true, [], schema?.fields);
let selectedFields: string[] = extend(true, [], options.selectedFields);
if (options.selectedFields && options.selectedFields!.length > 0) {
const selectedFieldsArray = options.selectedFields!.map(c => {
return c.split('.');
});

const currentFields = selectedFieldsArray
.map(c => c.shift())
.filter(c => c !== undefined);

//filter schema fields based on selected fields.
schemaFields = schemaFields.filter(
field =>
currentFields
.map(c => c!.toLowerCase())
.indexOf(field.name!.toLowerCase()) >= 0,
);
selectedFields = selectedFieldsArray
.filter(c => c.length > 0)
.map(c => c.join('.'));
schemaFields = this.filterSchema_(schemaFields, selectedFields);
selectedFields = this.nextFields_(selectedFields);
}

return toArray(rows).map(mergeSchema).map(flattenRows);
Expand Down Expand Up @@ -658,6 +642,48 @@
}
}

/**
* Filter table schema fields based on selectedFields.
*
* @private
*
* @param {TableField[]} tableFields
* @param {string[]} selected
* @returns Subset of fields that match selectedFields param.
*/
static filterSchema_(
tableFields: TableField[],
selected: string[],
): TableField[] {
const currentFields = selected
.map(c => c.split('.'))
.map(c => c.shift())
.filter(c => c !== undefined)
.map(c => c.trim());

//filter schema fields based on selected fields.
return tableFields.filter(
field =>
currentFields
.map(c => c!.toLowerCase())
.indexOf(field.name!.toLowerCase()) >= 0,
);
}

/**
* Move selected fields one level for filtering schema.
*
* @private
*
* @param {string[]} fields
*/
static nextFields_(fields: string[]): string[] {
const splitFields = fields.map(c => c.split('.'));
splitFields.forEach(c => c.shift());

return splitFields.filter(c => c.length > 0).map(c => c.join('.'));
}

/**
* The `DATE` type represents a logical calendar date, independent of time
* zone. It does not represent a specific 24-hour time period. Rather, a given
Expand Down Expand Up @@ -1596,7 +1622,7 @@
const parameterMode = isArray(params) ? 'positional' : 'named';
const queryParameters: bigquery.IQueryParameter[] = [];
if (parameterMode === 'named') {
const namedParams = params as {[param: string]: any};

Check warning on line 1625 in src/bigquery.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
for (const namedParameter of Object.getOwnPropertyNames(namedParams)) {
const value = namedParams[namedParameter];
let queryParameter;
Expand Down Expand Up @@ -2244,7 +2270,7 @@

options = extend({job}, queryOpts, options);
if (res && res.jobComplete) {
let rows: any = [];

Check warning on line 2273 in src/bigquery.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
if (res.schema && res.rows) {
rows = BigQuery.mergeSchemaWithRows_(res.schema, res.rows, {
wrapIntegers: options.wrapIntegers || false,
Expand Down
2 changes: 1 addition & 1 deletion src/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1853,7 +1853,7 @@ class Table extends ServiceObject {
const parseJSON = options.parseJSON ? options.parseJSON : false;
delete options.parseJSON;
const selectedFields = options.selectedFields
? options.selectedFields.split(',')
? options.selectedFields.split(',').map(c => c.trim())
: [];
const onComplete = (
err: Error | null,
Expand Down
120 changes: 120 additions & 0 deletions system-test/bigquery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,126 @@ describe('BigQuery', () => {
assert.equal(rows.length, 0);
});

it('should get rows from a query via table.getRows', async () => {
const query = `
SELECT STRUCT([STRUCT(STRUCT('1' as a, '2' as b) as object)] as nested) as data, 10 as age
UNION ALL
SELECT STRUCT([STRUCT(STRUCT('3' as a, '4' as b) as object)] as nested) as data, 20 as age
UNION ALL
SELECT STRUCT([STRUCT(STRUCT('5' as a, '6' as b) as object)] as nested) as data, 30 as age
UNION ALL
SELECT STRUCT([STRUCT(STRUCT('7' as a, '8' as b) as object)] as nested) as data, 40 as age
`;
const [_a, _b, res] = await bigquery.query(query);
const jobRef = res?.jobReference;
console.log('jobRef', jobRef);
const job = bigquery.job(jobRef!.jobId!, {
projectId: jobRef?.projectId,
location: jobRef?.location,
});
const [jobMd] = await job.getMetadata();
const tableRef = jobMd.configuration.query.destinationTable;
console.log('tableRef', tableRef);
const table = bigquery
.dataset(tableRef!.datasetId!)
.table(tableRef!.tableId!);

let [rows] = await table.getRows({
selectedFields: ['data.nested.object.a', 'data.nested.object.b'].join(
',',
),
});
console.log('rows', rows);
assert.deepEqual(rows[0], {
data: {
nested: [
{
object: {
a: '1',
b: '2',
},
},
],
},
});

[rows] = await table.getRows({
selectedFields: 'data.nested.object.b,age',
});
console.log('rows 2', rows);
assert.deepEqual(rows[0], {
data: {
nested: [
{
object: {
b: '2',
},
},
],
},
age: 10,
});

[rows] = await table.getRows({
selectedFields: 'age',
});
console.log('rows 3', rows);
assert.deepEqual(rows, [{age: 10}, {age: 20}, {age: 30}, {age: 40}]);

[rows] = await table.getRows({
selectedFields: [
'data.nested.object.a',
'data.nested.object.b',
'age',
].join(','),
});
console.log('rows 4', rows);
assert.deepEqual(rows[0], {
data: {
nested: [
{
object: {
a: '1',
b: '2',
},
},
],
},
age: 10,
});

[rows] = await table.getRows({
selectedFields: 'data.nested.object.a, age',
});
console.log('rows filter with space', rows);
assert.deepEqual(rows[0], {
data: {
nested: [
{
object: {
a: '1',
},
},
],
},
age: 10,
});

[rows] = await table.getRows({
selectedFields: undefined,
startIndex: '1',
maxResults: 1,
});
console.log('rows start index 1 and max results 1', JSON.stringify(rows));

[rows] = await table.getRows({
selectedFields: undefined,
startIndex: '2',
maxResults: 2,
});
console.log('rows start index 2 and max results 2', JSON.stringify(rows));
});

it('should get the rows in a table via stream', done => {
table
.createReadStream()
Expand Down
60 changes: 60 additions & 0 deletions test/bigquery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
TableField,
Query,
QueryResultsOptions,
TableSchema,
} from '../src';
import {SinonStub} from 'sinon';
import {PreciseDate} from '@google-cloud/precise-date';
Expand Down Expand Up @@ -428,6 +429,65 @@ describe('BigQuery', () => {
});
});

describe('filterSchema_ and nextFields_', () => {
const schema: TableSchema = {
fields: [
{
name: 'data',
type: 'RECORD',
mode: 'NULLABLE',
fields: [
{
name: 'nested',
type: 'RECORD',
mode: 'REPEATED',
fields: [
{
name: 'object',
type: 'RECORD',
mode: 'NULLABLE',
fields: [
{name: 'a', type: 'STRING', mode: 'NULLABLE'},
{name: 'b', type: 'STRING', mode: 'NULLABLE'},
],
},
],
},
],
},
{name: 'age', type: 'INTEGER', mode: 'NULLABLE'},
],
};

it('should filter nested fields', () => {
let selectedFields = ['data.nested.object.b', 'age'];
let schemaFields = BigQuery.filterSchema_(schema.fields, selectedFields);
let nextFields = BigQuery.nextFields_(selectedFields);

assert.deepEqual(schemaFields, schema.fields);
assert.deepEqual(nextFields, ['nested.object.b']);

selectedFields = ['age'];
schemaFields = BigQuery.filterSchema_(schema.fields, selectedFields);
nextFields = BigQuery.nextFields_(selectedFields);

assert.deepEqual(schemaFields, [schema.fields![1]]);
assert.deepEqual(nextFields, []);
});

it('should filter fields having spaces', () => {
const selectedFields = [' age'];
const schemaFields = BigQuery.filterSchema_(
schema.fields,
selectedFields,
);
const nextFields = BigQuery.nextFields_(selectedFields);

assert.deepEqual(schemaFields, [schema.fields![1]]);
assert.deepEqual(nextFields, []);
});
});

describe('mergeSchemaWithRows_', () => {
const SCHEMA_OBJECT = {
fields: [
Expand Down
Loading