blob: 402a2e99d08e4593adbe5e01eb449774c56bf880 [file] [log] [blame]
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {RawQueryResult} from './protos';
import {
findColumnIndex,
iter,
NUM,
NUM_NULL,
slowlyCountRows,
STR,
STR_NULL
} from './query_iterator';
const COLUMN_TYPE_STR = RawQueryResult.ColumnDesc.Type.STRING;
const COLUMN_TYPE_DOUBLE = RawQueryResult.ColumnDesc.Type.DOUBLE;
const COLUMN_TYPE_LONG = RawQueryResult.ColumnDesc.Type.LONG;
test('Columnar iteration slowlyCountRows', () => {
const r = new RawQueryResult({
columnDescriptors: [{
name: 'string_column',
type: COLUMN_TYPE_STR,
}],
numRecords: 1,
columns: [{
stringValues: ['foo'],
isNulls: [false],
}],
});
expect(slowlyCountRows(r)).toBe(1);
});
test('Columnar iteration findColumnIndex', () => {
const r = new RawQueryResult({
columnDescriptors: [
{
name: 'strings',
type: COLUMN_TYPE_STR,
},
{
name: 'doubles',
type: COLUMN_TYPE_DOUBLE,
},
{
name: 'longs',
type: COLUMN_TYPE_LONG,
},
{
name: 'nullable_strings',
type: COLUMN_TYPE_STR,
},
{
name: 'nullable_doubles',
type: COLUMN_TYPE_DOUBLE,
},
{
name: 'nullable_longs',
type: COLUMN_TYPE_LONG,
},
{
name: 'twin',
type: COLUMN_TYPE_LONG,
},
{
name: 'twin',
type: COLUMN_TYPE_STR,
}
],
numRecords: 1,
columns: [
{
stringValues: ['foo'],
isNulls: [false],
},
{
doubleValues: [1],
isNulls: [false],
},
{
longValues: [1],
isNulls: [false],
},
{
stringValues: [''],
isNulls: [true],
},
{
doubleValues: [0],
isNulls: [true],
},
{
longValues: [0],
isNulls: [true],
},
{
doubleValues: [0],
isNulls: [false],
},
{
stringValues: [''],
isNulls: [false],
}
],
});
expect(findColumnIndex(r, 'strings', STR)).toBe(0);
expect(findColumnIndex(r, 'doubles', NUM)).toBe(1);
expect(findColumnIndex(r, 'longs', NUM)).toBe(2);
expect(findColumnIndex(r, 'nullable_strings', STR_NULL)).toBe(3);
expect(findColumnIndex(r, 'nullable_doubles', NUM_NULL)).toBe(4);
expect(findColumnIndex(r, 'nullable_longs', NUM_NULL)).toBe(5);
expect(() => findColumnIndex(r, 'no such col', NUM)).toThrow(Error);
// It's allowable to expect nulls but for the whole column to be non-null...
expect(findColumnIndex(r, 'strings', STR_NULL)).toBe(0);
expect(findColumnIndex(r, 'doubles', NUM_NULL)).toBe(1);
expect(findColumnIndex(r, 'longs', NUM_NULL)).toBe(2);
// ...but if we expect no-nulls there shouldn't be even one:
expect(() => findColumnIndex(r, 'nullable_strings', STR)).toThrow(Error);
expect(() => findColumnIndex(r, 'nullable_doubles', NUM)).toThrow(Error);
expect(() => findColumnIndex(r, 'nullable_longs', NUM)).toThrow(Error);
// If multiple columns have the desired name we error even if we could
// distinguish based on the type:
expect(() => findColumnIndex(r, 'twin', NUM)).toThrow(Error);
expect(() => findColumnIndex(r, 'strings', NUM)).toThrow(Error);
expect(() => findColumnIndex(r, 'longs', STR)).toThrow(Error);
expect(() => findColumnIndex(r, 'doubles', STR)).toThrow(Error);
});
test('Columnar iteration over two rows', () => {
const r = new RawQueryResult({
columnDescriptors: [{
name: 'name',
type: COLUMN_TYPE_STR,
}],
numRecords: 2,
columns: [{
stringValues: ['Alice', 'Bob'],
isNulls: [false, false],
}],
});
const it = iter({'name': STR}, r);
expect(it.valid()).toBe(true);
const name: string = it.row.name;
expect(name).toBe('Alice');
it.next();
expect(it.valid()).toBe(true);
expect(it.row.name).toBe('Bob');
it.next();
expect(it.valid()).toBe(false);
});
test('Columnar iteration over empty query set', () => {
const r = new RawQueryResult({
columnDescriptors: [{
name: 'emptyColumn',
type: COLUMN_TYPE_STR,
}],
numRecords: 0,
columns: [{
stringValues: [],
isNulls: [],
}],
});
{
const it = iter({'emptyColumn': STR}, r);
expect(it.valid()).toBe(false);
}
{
const it = iter({'emptyColumn': NUM}, r);
expect(it.valid()).toBe(false);
}
{
const it = iter({'emptyColumn': NUM_NULL}, r);
expect(it.valid()).toBe(false);
}
{
const it = iter({'emptyColumn': STR_NULL}, r);
expect(it.valid()).toBe(false);
}
});
test('Columnar iteration first row is null', () => {
const r = new RawQueryResult({
columnDescriptors: [{
name: 'numbers',
type: COLUMN_TYPE_STR,
}],
numRecords: 2,
columns: [{
stringValues: ['[NULL]'],
doubleValues: [0],
longValues: [0, 1],
isNulls: [true, false],
}],
});
const it = iter({'numbers': NUM_NULL}, r);
expect(it.valid()).toBe(true);
expect(it.row.numbers).toBe(null);
it.next();
expect(it.valid()).toBe(true);
expect(it.row.numbers).toBe(1);
it.next();
expect(it.valid()).toBe(false);
});