diff --git a/examples/query-service/data-helpers.ts b/examples/query-service/data-helpers.ts new file mode 100644 index 00000000..d14a5f66 --- /dev/null +++ b/examples/query-service/data-helpers.ts @@ -0,0 +1,25 @@ +import {declareType, TypedData, Types} from "ydb-sdk"; + +interface IRow { + id: number; + rowTitle: string; + time: Date; +} + +export class Row extends TypedData { + @declareType(Types.UINT64) + public id: number; + + @declareType(Types.UTF8) + public rowTitle: string; + + @declareType(Types.DATETIME) + public time: Date; + + constructor(data: IRow) { + super(data); + this.id = data.id; + this.rowTitle = data.rowTitle; + this.time = data.time; + } +} diff --git a/examples/query-service/index.ts b/examples/query-service/index.ts new file mode 100644 index 00000000..8d9840a9 --- /dev/null +++ b/examples/query-service/index.ts @@ -0,0 +1,145 @@ +process.env.YDB_SDK_PRETTY_LOGS = '1'; + +import {Driver, getCredentialsFromEnv, Logger, TypedValues, RowType} from 'ydb-sdk'; +import {Row} from './data-helpers'; +import {main} from '../utils'; + +const TABLE = 'query_service_table'; + +async function createTestTable(driver: Driver) { + await driver.queryClient.do({ + fn: async (session) => { + await session.execute({ + text: ` + DROP TABLE IF EXISTS ${TABLE}; + + CREATE TABLE ${TABLE} + ( + id UInt64, + rowTitle Utf8, + time Timestamp, + PRIMARY KEY (id) + );`, + }); + } + }); +} + +async function insert(driver: Driver) { + await driver.queryClient.do({ + fn: async (session) => { + await session.execute({ + parameters: { + '$id1': TypedValues.uint64(1), + '$title1': TypedValues.text('Some title1'), + '$id2': TypedValues.uint64(2), + '$title2': TypedValues.text('Some title2'), + '$timestamp': TypedValues.timestamp(new Date()), + }, + text: ` + INSERT INTO ${TABLE} (id, rowTitle, time) + VALUES ($id1, $title1, $timestamp); + INSERT INTO ${TABLE} (id, rowTitle, time) + VALUES ($id2, $title2, $timestamp);`, + }); + } + }); + return 2; +} + +async function select(driver: Driver) { + const res = await driver.queryClient.do({ + fn: async (session) => { + const res = await session.execute({ + text: ` + SELECT * + FROM ${TABLE}; + SELECT * -- double + FROM ${TABLE}; ` + }); + let rowsCount = 0; + for await (const resultSet of res.resultSets) { + console.info(`ResultSet index: ${resultSet.index}`) + for await (const row of resultSet.rows) { + rowsCount++; + console.info(`row: ${JSON.stringify(row)}`); + } + } + return rowsCount; + } + }); + console.info(`rowCount: ${res}`); +} + +async function typedSelect(driver: Driver) { + const res = await driver.queryClient.do({ + fn: async (session) => { + // @ts-ignore + const res = await session.execute({ + rowMode: RowType.Ydb, + text: ` + SELECT * + FROM ${TABLE}; + SELECT * -- double + FROM ${TABLE}; ` + }); + let rowsCount = 0; + for await (const resultSet of res.resultSets) { + console.info(`ResultSet index: ${resultSet.index}`) + for await (const row of resultSet.typedRows(Row)) { + rowsCount++; + console.info(`row: ${JSON.stringify(row)}`); + } + } + return rowsCount; + } + }); + console.info(`rowCount: ${res}`); +} + +async function bulkUpsert(driver: Driver) { + await driver.queryClient.do({ + fn: async (session) => { + let arr: Row[] = []; + + for (let id = 1; id <= 20; id++) + arr.push(new Row({ + id, + rowTitle: `title_${id}`, + time: new Date(), + })); + + await session.execute({ + text: ` + UPSERT INTO ${TABLE} (id, rowTitle, time) + SELECT id, rowTitle, time FROM AS_TABLE($table)`, + parameters: { + '$table': Row.asTypedCollection(arr), + } + }); + }, + }); +} + +async function run(logger: Logger, endpoint: string, database: string) { + const authService = getCredentialsFromEnv(); + logger.info('Driver initializing...'); + const driver = new Driver({endpoint, database, authService}); + const timeout = 10000; + if (!await driver.ready(timeout)) { + logger.fatal(`Driver has not become ready in ${timeout}ms!`); + process.exit(1); + } + await createTestTable(driver); + await insert(driver); + await select(driver); + await bulkUpsert(driver); + await typedSelect(driver); + + // TODO: Add samples for transactions Right now, details of usage can be seen in src/__tests__/e2e/query-service/transactions.ts + // TODO: Add samples for queryClient.doTx() Right now, details of usage can be seen in src/__tests__/e2e/query-service/query-service-client.ts + + await driver.destroy(); +} + +main(run); diff --git a/src/__tests__/e2e/query-service/method-execute.ts b/src/__tests__/e2e/query-service/method-execute.ts index 5eb007df..749bc2e2 100644 --- a/src/__tests__/e2e/query-service/method-execute.ts +++ b/src/__tests__/e2e/query-service/method-execute.ts @@ -1,10 +1,3 @@ -// number of operations under one transaction -// doTx - txControl -// convert to native type -// update / insert -// error -// timeout - import DiscoveryService from "../../../discovery/discovery-service"; import {ENDPOINT_DISCOVERY_PERIOD} from "../../../constants"; import {AnonymousAuthService} from "../../../credentials/anonymous-auth-service"; diff --git a/src/__tests__/e2e/query-service/query-service-client.ts b/src/__tests__/e2e/query-service/query-service-client.ts index 441ea9a9..0728136d 100644 --- a/src/__tests__/e2e/query-service/query-service-client.ts +++ b/src/__tests__/e2e/query-service/query-service-client.ts @@ -9,7 +9,6 @@ import {QuerySession} from "../../../query/query-session"; const DATABASE = '/local'; const ENDPOINT = 'grpcs://localhost:2135'; -// const TABLE_NAME = 'test_table_20240313' describe('Query client', () => { diff --git a/src/__tests__/e2e/query-service/transactions.ts b/src/__tests__/e2e/query-service/transactions.ts index b173ae26..c3e52255 100644 --- a/src/__tests__/e2e/query-service/transactions.ts +++ b/src/__tests__/e2e/query-service/transactions.ts @@ -1,6 +1,3 @@ -// session should autocimmit at the end -// doTx locks manipulations with tx - import {getLogger} from "../../../logging"; import {AnonymousAuthService} from "../../../credentials/anonymous-auth-service"; import DiscoveryService from "../../../discovery/discovery-service"; diff --git a/src/driver.ts b/src/driver.ts index 1c85dcb0..57c08048 100644 --- a/src/driver.ts +++ b/src/driver.ts @@ -9,7 +9,7 @@ import {IAuthService} from "./credentials/i-auth-service"; import SchemeService from "./schema/scheme-client"; import SchemeClient from "./schema/scheme-client"; import {parseConnectionString} from "./utils/parse-connection-string"; -import {QueryClient} from "./query/query-client"; +import {QueryClient} from "./query"; export interface IPoolSettings { minLimit?: number; diff --git a/src/index.ts b/src/index.ts index e97340e9..fb236acf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -82,3 +82,5 @@ export {RemoveDirectorySettings} from "./schema/scheme-service"; export {MakeDirectorySettings} from "./schema/scheme-service"; export {ParsedConnectionString, parseConnectionString} from "./utils/parse-connection-string"; + +export {QueryClient, ResultSet, RowType} from "./query"; diff --git a/src/query/index.ts b/src/query/index.ts new file mode 100644 index 00000000..1f8d30a4 --- /dev/null +++ b/src/query/index.ts @@ -0,0 +1,4 @@ +export * from './query-client'; +export * from './query-session'; +export * from './query-session-execute'; +export * from './ResultSet';