-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into refactoring-operation-helpers-1
- Loading branch information
Showing
6 changed files
with
260 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,65 @@ | ||
import Int64 from 'node-int64'; | ||
import { TSparkParameter, TSparkParameterValue } from '../thrift/TCLIService_types'; | ||
|
||
export type DBSQLParameterValue = boolean | number | bigint | Int64 | Date | string; | ||
|
||
interface DBSQLParameterOptions { | ||
type?: string; | ||
value: DBSQLParameterValue; | ||
} | ||
|
||
export default class DBSQLParameter { | ||
public readonly type?: string; | ||
|
||
public readonly value: DBSQLParameterValue; | ||
|
||
constructor({ type, value }: DBSQLParameterOptions) { | ||
this.type = type; | ||
this.value = value; | ||
} | ||
|
||
public toSparkParameter(): TSparkParameter { | ||
if (typeof this.value === 'boolean') { | ||
return new TSparkParameter({ | ||
type: this.type ?? 'BOOLEAN', | ||
value: new TSparkParameterValue({ | ||
stringValue: this.value ? 'TRUE' : 'FALSE', | ||
}), | ||
}); | ||
} | ||
|
||
if (typeof this.value === 'number') { | ||
return new TSparkParameter({ | ||
type: this.type ?? (Number.isInteger(this.value) ? 'INTEGER' : 'DOUBLE'), | ||
value: new TSparkParameterValue({ | ||
stringValue: Number(this.value).toString(), | ||
}), | ||
}); | ||
} | ||
|
||
if (this.value instanceof Int64 || typeof this.value === 'bigint') { | ||
return new TSparkParameter({ | ||
type: this.type ?? 'BIGINT', | ||
value: new TSparkParameterValue({ | ||
stringValue: this.value.toString(), | ||
}), | ||
}); | ||
} | ||
|
||
if (this.value instanceof Date) { | ||
return new TSparkParameter({ | ||
type: this.type ?? 'TIMESTAMP', | ||
value: new TSparkParameterValue({ | ||
stringValue: this.value.toISOString(), | ||
}), | ||
}); | ||
} | ||
|
||
return new TSparkParameter({ | ||
type: this.type ?? 'STRING', | ||
value: new TSparkParameterValue({ | ||
stringValue: this.value, | ||
}), | ||
}); | ||
} | ||
} |
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
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
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
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,104 @@ | ||
const { expect } = require('chai'); | ||
const Int64 = require('node-int64'); | ||
const config = require('./utils/config'); | ||
const { DBSQLClient, DBSQLParameter } = require('../..'); | ||
|
||
const openSession = async () => { | ||
const client = new DBSQLClient(); | ||
|
||
const connection = await client.connect({ | ||
host: config.host, | ||
path: config.path, | ||
token: config.token, | ||
}); | ||
|
||
return connection.openSession({ | ||
initialCatalog: config.database[0], | ||
initialSchema: config.database[1], | ||
}); | ||
}; | ||
|
||
describe('Query parameters', () => { | ||
it('should use named parameters', async () => { | ||
const session = await openSession(); | ||
const operation = await session.executeStatement( | ||
` | ||
SELECT | ||
:p_bool AS col_bool, | ||
:p_int AS col_int, | ||
:p_double AS col_double, | ||
:p_bigint_1 AS col_bigint_1, | ||
:p_bigint_2 AS col_bigint_2, | ||
:p_date as col_date, | ||
:p_timestamp as col_timestamp, | ||
:p_str AS col_str | ||
`, | ||
{ | ||
runAsync: true, | ||
namedParameters: { | ||
p_bool: new DBSQLParameter({ value: true }), | ||
p_int: new DBSQLParameter({ value: 1234 }), | ||
p_double: new DBSQLParameter({ value: 3.14 }), | ||
p_bigint_1: new DBSQLParameter({ value: BigInt(1234) }), | ||
p_bigint_2: new DBSQLParameter({ value: new Int64(1234) }), | ||
p_date: new DBSQLParameter({ value: new Date('2023-09-06T03:14:27.843Z'), type: 'DATE' }), | ||
p_timestamp: new DBSQLParameter({ value: new Date('2023-09-06T03:14:27.843Z') }), | ||
p_str: new DBSQLParameter({ value: 'Hello' }), | ||
}, | ||
}, | ||
); | ||
const result = await operation.fetchAll(); | ||
expect(result).to.deep.equal([ | ||
{ | ||
col_bool: true, | ||
col_int: 1234, | ||
col_double: 3.14, | ||
col_bigint_1: 1234, | ||
col_bigint_2: 1234, | ||
col_date: new Date('2023-09-06T00:00:00.000Z'), | ||
col_timestamp: new Date('2023-09-06T03:14:27.843Z'), | ||
col_str: 'Hello', | ||
}, | ||
]); | ||
}); | ||
|
||
it('should accept primitives as values for named parameters', async () => { | ||
const session = await openSession(); | ||
const operation = await session.executeStatement( | ||
` | ||
SELECT | ||
:p_bool AS col_bool, | ||
:p_int AS col_int, | ||
:p_double AS col_double, | ||
:p_bigint_1 AS col_bigint_1, | ||
:p_bigint_2 AS col_bigint_2, | ||
:p_timestamp as col_timestamp, | ||
:p_str AS col_str | ||
`, | ||
{ | ||
runAsync: true, | ||
namedParameters: { | ||
p_bool: true, | ||
p_int: 1234, | ||
p_double: 3.14, | ||
p_bigint_1: BigInt(1234), | ||
p_bigint_2: new Int64(1234), | ||
p_timestamp: new Date('2023-09-06T03:14:27.843Z'), | ||
p_str: 'Hello', | ||
}, | ||
}, | ||
); | ||
const result = await operation.fetchAll(); | ||
expect(result).to.deep.equal([ | ||
{ | ||
col_bool: true, | ||
col_int: 1234, | ||
col_double: 3.14, | ||
col_bigint_1: 1234, | ||
col_bigint_2: 1234, | ||
col_timestamp: new Date('2023-09-06T03:14:27.843Z'), | ||
col_str: 'Hello', | ||
}, | ||
]); | ||
}); | ||
}); |
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,66 @@ | ||
const { expect } = require('chai'); | ||
|
||
const Int64 = require('node-int64'); | ||
const { TSparkParameterValue, TSparkParameter } = require('../../thrift/TCLIService_types'); | ||
const { default: DBSQLParameter } = require('../../dist/DBSQLParameter'); | ||
|
||
describe('DBSQLParameter', () => { | ||
it('should infer types correctly', () => { | ||
const cases = [ | ||
[false, new TSparkParameter({ type: 'BOOLEAN', value: new TSparkParameterValue({ stringValue: 'FALSE' }) })], | ||
[true, new TSparkParameter({ type: 'BOOLEAN', value: new TSparkParameterValue({ stringValue: 'TRUE' }) })], | ||
[123, new TSparkParameter({ type: 'INTEGER', value: new TSparkParameterValue({ stringValue: '123' }) })], | ||
[3.14, new TSparkParameter({ type: 'DOUBLE', value: new TSparkParameterValue({ stringValue: '3.14' }) })], | ||
[BigInt(1234), new TSparkParameter({ type: 'BIGINT', value: new TSparkParameterValue({ stringValue: '1234' }) })], | ||
[ | ||
new Int64(1234), | ||
new TSparkParameter({ type: 'BIGINT', value: new TSparkParameterValue({ stringValue: '1234' }) }), | ||
], | ||
[ | ||
new Date('2023-09-06T03:14:27.843Z'), | ||
new TSparkParameter({ | ||
type: 'TIMESTAMP', | ||
value: new TSparkParameterValue({ stringValue: '2023-09-06T03:14:27.843Z' }), | ||
}), | ||
], | ||
['Hello', new TSparkParameter({ type: 'STRING', value: new TSparkParameterValue({ stringValue: 'Hello' }) })], | ||
]; | ||
|
||
for (const [value, expectedParam] of cases) { | ||
const dbsqlParam = new DBSQLParameter({ value }); | ||
expect(dbsqlParam.toSparkParameter()).to.deep.equal(expectedParam); | ||
} | ||
}); | ||
|
||
it('should use provided type', () => { | ||
const expectedType = '_CUSTOM_TYPE_'; // it doesn't have to be valid type name, just any string | ||
|
||
const cases = [ | ||
[false, new TSparkParameter({ type: expectedType, value: new TSparkParameterValue({ stringValue: 'FALSE' }) })], | ||
[true, new TSparkParameter({ type: expectedType, value: new TSparkParameterValue({ stringValue: 'TRUE' }) })], | ||
[123, new TSparkParameter({ type: expectedType, value: new TSparkParameterValue({ stringValue: '123' }) })], | ||
[3.14, new TSparkParameter({ type: expectedType, value: new TSparkParameterValue({ stringValue: '3.14' }) })], | ||
[ | ||
BigInt(1234), | ||
new TSparkParameter({ type: expectedType, value: new TSparkParameterValue({ stringValue: '1234' }) }), | ||
], | ||
[ | ||
new Int64(1234), | ||
new TSparkParameter({ type: expectedType, value: new TSparkParameterValue({ stringValue: '1234' }) }), | ||
], | ||
[ | ||
new Date('2023-09-06T03:14:27.843Z'), | ||
new TSparkParameter({ | ||
type: expectedType, | ||
value: new TSparkParameterValue({ stringValue: '2023-09-06T03:14:27.843Z' }), | ||
}), | ||
], | ||
['Hello', new TSparkParameter({ type: expectedType, value: new TSparkParameterValue({ stringValue: 'Hello' }) })], | ||
]; | ||
|
||
for (const [value, expectedParam] of cases) { | ||
const dbsqlParam = new DBSQLParameter({ type: expectedType, value }); | ||
expect(dbsqlParam.toSparkParameter()).to.deep.equal(expectedParam); | ||
} | ||
}); | ||
}); |