diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 0c8fe7d..643e1d7 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -6,7 +6,7 @@ on: - master - develop pull_request: - type: [opened, reopened, edited] + type: [opened, reopened, edited, synchronize] jobs: build: @@ -44,7 +44,7 @@ jobs: - name: Checkout YDB Java SDK if: ${{ env.NEED_SDK }} - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ydb-platform/ydb-java-sdk ref: develop @@ -61,7 +61,7 @@ jobs: - name: Checkout YDB YC Auth Provider if: ${{ env.NEED_SDK }} - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ydb-platform/ydb-java-yc ref: develop diff --git a/auth/access_token_credentials/src/main/java/tech/ydb/example/Main.java b/auth/access_token_credentials/src/main/java/tech/ydb/example/Main.java index 0721050..fd33e59 100644 --- a/auth/access_token_credentials/src/main/java/tech/ydb/example/Main.java +++ b/auth/access_token_credentials/src/main/java/tech/ydb/example/Main.java @@ -1,13 +1,12 @@ package tech.ydb.example; -import java.util.concurrent.CompletableFuture; import tech.ydb.auth.AuthProvider; import tech.ydb.auth.TokenAuthProvider; -import tech.ydb.core.Result; import tech.ydb.core.grpc.GrpcTransport; import tech.ydb.table.SessionRetryContext; import tech.ydb.table.TableClient; +import tech.ydb.table.query.DataQueryResult; import tech.ydb.table.result.ResultSetReader; import tech.ydb.table.transaction.TxControl; @@ -25,23 +24,20 @@ public static void main(String[] args) { // Access token credentials AuthProvider authProvider = new TokenAuthProvider(accessToken); - try ( GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) - .withAuthProvider(authProvider) // Or this method could not be called at all + try (GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) + .withAuthProvider(authProvider) .build()) { - try ( TableClient tableClient = TableClient - .newClient(transport) - .build()) { + try (TableClient tableClient = TableClient.newClient(transport).build()) { SessionRetryContext retryCtx = SessionRetryContext.create(tableClient).build(); - retryCtx.supplyResult(session -> { - ResultSetReader rsReader = session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) - .join().getValue().getResultSet(0); + DataQueryResult dataQueryResult = retryCtx.supplyResult( + session -> session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) + ).join().getValue(); - rsReader.next(); + ResultSetReader rsReader = dataQueryResult.getResultSet(0); + while (rsReader.next()) { System.out.println(rsReader.getColumn(0).getInt32()); - - return CompletableFuture.completedFuture(Result.success(Boolean.TRUE)); - }).join(); + } } } } diff --git a/auth/anonymous_credentials/src/main/java/tech/ydb/example/Main.java b/auth/anonymous_credentials/src/main/java/tech/ydb/example/Main.java index 243ef26..3d54e33 100644 --- a/auth/anonymous_credentials/src/main/java/tech/ydb/example/Main.java +++ b/auth/anonymous_credentials/src/main/java/tech/ydb/example/Main.java @@ -1,13 +1,12 @@ package tech.ydb.example; -import java.util.concurrent.CompletableFuture; import tech.ydb.auth.AuthProvider; import tech.ydb.auth.NopAuthProvider; -import tech.ydb.core.Result; import tech.ydb.core.grpc.GrpcTransport; import tech.ydb.table.SessionRetryContext; import tech.ydb.table.TableClient; +import tech.ydb.table.query.DataQueryResult; import tech.ydb.table.result.ResultSetReader; import tech.ydb.table.transaction.TxControl; @@ -22,24 +21,20 @@ public static void main(String[] args) { // Anonymous credentials AuthProvider authProvider = NopAuthProvider.INSTANCE; - try ( GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) - .withAuthProvider(authProvider) // Or this method could not be called at all + try (GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) + .withAuthProvider(authProvider) .build()) { - try ( TableClient tableClient = TableClient - .newClient(transport) - .build()) { - + try (TableClient tableClient = TableClient.newClient(transport).build()) { SessionRetryContext retryCtx = SessionRetryContext.create(tableClient).build(); - retryCtx.supplyResult(session -> { - ResultSetReader rsReader = session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) - .join().getValue().getResultSet(0); + DataQueryResult dataQueryResult = retryCtx.supplyResult( + session -> session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) + ).join().getValue(); - rsReader.next(); + ResultSetReader rsReader = dataQueryResult.getResultSet(0); + while (rsReader.next()) { System.out.println(rsReader.getColumn(0).getInt32()); - - return CompletableFuture.completedFuture(Result.success(Boolean.TRUE)); - }).join(); + } } } } diff --git a/auth/environ/src/main/java/tech/ydb/example/Main.java b/auth/environ/src/main/java/tech/ydb/example/Main.java index 21bfec8..3042d3e 100644 --- a/auth/environ/src/main/java/tech/ydb/example/Main.java +++ b/auth/environ/src/main/java/tech/ydb/example/Main.java @@ -1,13 +1,12 @@ package tech.ydb.example; -import java.util.concurrent.CompletableFuture; import tech.ydb.auth.AuthProvider; import tech.ydb.auth.iam.CloudAuthHelper; -import tech.ydb.core.Result; import tech.ydb.core.grpc.GrpcTransport; import tech.ydb.table.SessionRetryContext; import tech.ydb.table.TableClient; +import tech.ydb.table.query.DataQueryResult; import tech.ydb.table.result.ResultSetReader; import tech.ydb.table.transaction.TxControl; @@ -22,24 +21,20 @@ public static void main(String[] args) { // Construct authProvider from environment variables AuthProvider authProvider = CloudAuthHelper.getAuthProviderFromEnviron(); - try ( GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) - .withAuthProvider(authProvider) // Or this method could not be called at all + try (GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) + .withAuthProvider(authProvider) .build()) { - try ( TableClient tableClient = TableClient - .newClient(transport) - .build()) { - + try (TableClient tableClient = TableClient.newClient(transport).build()) { SessionRetryContext retryCtx = SessionRetryContext.create(tableClient).build(); - retryCtx.supplyResult(session -> { - ResultSetReader rsReader = session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) - .join().getValue().getResultSet(0); + DataQueryResult dataQueryResult = retryCtx.supplyResult( + session -> session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) + ).join().getValue(); - rsReader.next(); + ResultSetReader rsReader = dataQueryResult.getResultSet(0); + while (rsReader.next()) { System.out.println(rsReader.getColumn(0).getInt32()); - - return CompletableFuture.completedFuture(Result.success(Boolean.TRUE)); - }).join(); + } } } } diff --git a/auth/metadata_credentials/src/main/java/tech/ydb/example/Main.java b/auth/metadata_credentials/src/main/java/tech/ydb/example/Main.java index cdbc64b..67462de 100644 --- a/auth/metadata_credentials/src/main/java/tech/ydb/example/Main.java +++ b/auth/metadata_credentials/src/main/java/tech/ydb/example/Main.java @@ -1,13 +1,12 @@ package tech.ydb.example; -import java.util.concurrent.CompletableFuture; import tech.ydb.auth.AuthProvider; import tech.ydb.auth.iam.CloudAuthHelper; -import tech.ydb.core.Result; import tech.ydb.core.grpc.GrpcTransport; import tech.ydb.table.SessionRetryContext; import tech.ydb.table.TableClient; +import tech.ydb.table.query.DataQueryResult; import tech.ydb.table.result.ResultSetReader; import tech.ydb.table.transaction.TxControl; @@ -23,24 +22,20 @@ public static void main(String[] args) { // Use metadata credentials AuthProvider authProvider = CloudAuthHelper.getMetadataAuthProvider(); - try ( GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) - .withAuthProvider(authProvider) // Or this method could not be called at all + try (GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) + .withAuthProvider(authProvider) .build()) { - try ( TableClient tableClient = TableClient - .newClient(transport) - .build()) { - + try (TableClient tableClient = TableClient.newClient(transport).build()) { SessionRetryContext retryCtx = SessionRetryContext.create(tableClient).build(); - retryCtx.supplyResult(session -> { - ResultSetReader rsReader = session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) - .join().getValue().getResultSet(0); + DataQueryResult dataQueryResult = retryCtx.supplyResult( + session -> session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) + ).join().getValue(); - rsReader.next(); + ResultSetReader rsReader = dataQueryResult.getResultSet(0); + while (rsReader.next()) { System.out.println(rsReader.getColumn(0).getInt32()); - - return CompletableFuture.completedFuture(Result.success(Boolean.TRUE)); - }).join(); + } } } } diff --git a/auth/service_account_credentials/src/main/java/tech/ydb/example/Main.java b/auth/service_account_credentials/src/main/java/tech/ydb/example/Main.java index 57d88a5..8edf12e 100644 --- a/auth/service_account_credentials/src/main/java/tech/ydb/example/Main.java +++ b/auth/service_account_credentials/src/main/java/tech/ydb/example/Main.java @@ -1,13 +1,12 @@ package tech.ydb.example; -import java.util.concurrent.CompletableFuture; import tech.ydb.auth.AuthProvider; import tech.ydb.auth.iam.CloudAuthHelper; -import tech.ydb.core.Result; import tech.ydb.core.grpc.GrpcTransport; import tech.ydb.table.SessionRetryContext; import tech.ydb.table.TableClient; +import tech.ydb.table.query.DataQueryResult; import tech.ydb.table.result.ResultSetReader; import tech.ydb.table.transaction.TxControl; @@ -23,24 +22,20 @@ public static void main(String[] args) { AuthProvider authProvider = CloudAuthHelper.getServiceAccountFileAuthProvider(saKeyFile); - try ( GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) - .withAuthProvider(authProvider) // Or this method could not be called at all + try (GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) + .withAuthProvider(authProvider) .build()) { - try ( TableClient tableClient = TableClient - .newClient(transport) - .build()) { - + try (TableClient tableClient = TableClient.newClient(transport).build()) { SessionRetryContext retryCtx = SessionRetryContext.create(tableClient).build(); - retryCtx.supplyResult(session -> { - ResultSetReader rsReader = session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) - .join().getValue().getResultSet(0); + DataQueryResult dataQueryResult = retryCtx.supplyResult( + session -> session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) + ).join().getValue(); - rsReader.next(); + ResultSetReader rsReader = dataQueryResult.getResultSet(0); + while (rsReader.next()) { System.out.println(rsReader.getColumn(0).getInt32()); - - return CompletableFuture.completedFuture(Result.success(Boolean.TRUE)); - }).join(); + } } } } diff --git a/auth/static_credentials/src/main/java/tech/ydb/example/Main.java b/auth/static_credentials/src/main/java/tech/ydb/example/Main.java index 876292d..b5272fd 100644 --- a/auth/static_credentials/src/main/java/tech/ydb/example/Main.java +++ b/auth/static_credentials/src/main/java/tech/ydb/example/Main.java @@ -1,13 +1,11 @@ package tech.ydb.example; -import java.util.concurrent.CompletableFuture; - -import tech.ydb.core.Result; import tech.ydb.core.auth.StaticCredentials; import tech.ydb.core.grpc.GrpcTransport; import tech.ydb.table.SessionRetryContext; import tech.ydb.table.TableClient; +import tech.ydb.table.query.DataQueryResult; import tech.ydb.table.result.ResultSetReader; import tech.ydb.table.transaction.TxControl; @@ -29,23 +27,20 @@ public static void main(String[] args) { // Use credentials auth provider with username and password StaticCredentials authProvider = new StaticCredentials(username, password); - try ( GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) - .withAuthProvider(authProvider) // Or this method could not be called at all + try (GrpcTransport transport = GrpcTransport.forConnectionString(connectionString) + .withAuthProvider(authProvider) .build()) { - try ( TableClient tableClient = TableClient - .newClient(transport) - .build()) { + try (TableClient tableClient = TableClient.newClient(transport).build()) { SessionRetryContext retryCtx = SessionRetryContext.create(tableClient).build(); - retryCtx.supplyResult(session -> { - ResultSetReader rsReader = session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) - .join().getValue().getResultSet(0); + DataQueryResult dataQueryResult = retryCtx.supplyResult( + session -> session.executeDataQuery("SELECT 1;", TxControl.serializableRw()) + ).join().getValue(); - rsReader.next(); + ResultSetReader rsReader = dataQueryResult.getResultSet(0); + while (rsReader.next()) { System.out.println(rsReader.getColumn(0).getInt32()); - - return CompletableFuture.completedFuture(Result.success(Boolean.TRUE)); - }).join(); + } } } } diff --git a/basic_example/pom.xml b/basic_example/pom.xml index c47233a..d69fe3b 100644 --- a/basic_example/pom.xml +++ b/basic_example/pom.xml @@ -12,15 +12,15 @@ YDB Basic Example Simple example of usage Java SDK for YDB + + 5.10.1 + + tech.ydb ydb-sdk-table - - tech.ydb - ydb-sdk-topic - tech.ydb.auth yc-auth-provider @@ -30,6 +30,19 @@ org.apache.logging.log4j log4j-slf4j-impl + + + tech.ydb.test + ydb-junit5-support + test + + + + org.junit.jupiter + junit-jupiter-api + ${junit5.version} + test + @@ -52,7 +65,18 @@ tech.ydb.example.App - + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + true + 1 + + diff --git a/basic_example/src/main/java/tech/ydb/example/App.java b/basic_example/src/main/java/tech/ydb/example/App.java index 72cefcc..05d1c8e 100644 --- a/basic_example/src/main/java/tech/ydb/example/App.java +++ b/basic_example/src/main/java/tech/ydb/example/App.java @@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory; import tech.ydb.auth.iam.CloudAuthHelper; +import tech.ydb.common.transaction.TxMode; import tech.ydb.core.Status; import tech.ydb.core.grpc.GrpcReadStream; import tech.ydb.core.grpc.GrpcTransport; @@ -24,7 +25,7 @@ import tech.ydb.table.result.ResultSetReader; import tech.ydb.table.settings.BulkUpsertSettings; import tech.ydb.table.settings.ExecuteScanQuerySettings; -import tech.ydb.table.transaction.Transaction; +import tech.ydb.table.transaction.TableTransaction; import tech.ydb.table.transaction.TxControl; import tech.ydb.table.values.ListType; import tech.ydb.table.values.ListValue; @@ -41,7 +42,7 @@ public final class App implements Runnable, AutoCloseable { private final String database; private final SessionRetryContext retryCtx; - private App(String connectionString) { + App(String connectionString) { this.transport = GrpcTransport.forConnectionString(connectionString) .withAuthProvider(CloudAuthHelper.getAuthProviderFromEnviron()) .build(); @@ -303,6 +304,7 @@ private void scanQueryWithParams(long seriesID, long seasonID) { private void multiStepTransaction(long seriesID, long seasonID) { retryCtx.supplyStatus(session -> { + TableTransaction transaction = session.createNewTransaction(TxMode.SERIALIZABLE_RW); String query1 = "DECLARE $seriesId AS Uint64; " + "DECLARE $seasonId AS Uint64; " @@ -312,8 +314,7 @@ private void multiStepTransaction(long seriesID, long seasonID) { // Execute first query to get the required values to the client. // Transaction control settings don't set CommitTx flag to keep transaction active // after query execution. - TxControl tx1 = TxControl.serializableRw().setCommitTx(false); - DataQueryResult res1 = session.executeDataQuery(query1, tx1, Params.of( + DataQueryResult res1 = transaction.executeDataQuery(query1, Params.of( "$seriesId", PrimitiveValue.newUint64(seriesID), "$seasonId", PrimitiveValue.newUint64(seasonID) )).join().getValue(); @@ -327,7 +328,7 @@ private void multiStepTransaction(long seriesID, long seasonID) { LocalDate toDate = fromDate.plusDays(15); // Get active transaction id - String txId = res1.getTxId(); + logger.info("got transaction id {}", transaction.getId()); // Construct next query based on the results of client logic String query2 @@ -340,8 +341,7 @@ private void multiStepTransaction(long seriesID, long seasonID) { // Execute second query. // Transaction control settings continues active transaction (tx) and // commits it at the end of second query execution. - TxControl tx2 = TxControl.id(txId).setCommitTx(true); - DataQueryResult res2 = session.executeDataQuery(query2, tx2, Params.of( + DataQueryResult res2 = transaction.executeDataQueryAndCommit(query2, Params.of( "$seriesId", PrimitiveValue.newUint64(seriesID), "$fromDate", PrimitiveValue.newDate(fromDate), "$toDate", PrimitiveValue.newDate(toDate) @@ -362,7 +362,7 @@ private void multiStepTransaction(long seriesID, long seasonID) { private void tclTransaction() { retryCtx.supplyStatus(session -> { - Transaction transaction = session.beginTransaction(Transaction.Mode.SERIALIZABLE_READ_WRITE) + TableTransaction transaction = session.beginTransaction(TxMode.SERIALIZABLE_RW) .join().getValue(); String query @@ -373,8 +373,7 @@ private void tclTransaction() { // Execute data query. // Transaction control settings continues active transaction (tx) - TxControl txControl = TxControl.id(transaction).setCommitTx(false); - DataQueryResult result = session.executeDataQuery(query, txControl, params) + DataQueryResult result = transaction.executeDataQuery(query, params) .join().getValue(); logger.info("get transaction {}", result.getTxId()); diff --git a/basic_example/src/main/resources/log4j2.xml b/basic_example/src/main/resources/log4j2.xml index 7ca65b6..cdcbde9 100644 --- a/basic_example/src/main/resources/log4j2.xml +++ b/basic_example/src/main/resources/log4j2.xml @@ -2,30 +2,21 @@ - + - - - - - - - - - - - - - - - - + + + + + + - + + diff --git a/basic_example/src/test/java/tech/ydb/example/BasicExampleTest.java b/basic_example/src/test/java/tech/ydb/example/BasicExampleTest.java new file mode 100644 index 0000000..8d162a1 --- /dev/null +++ b/basic_example/src/test/java/tech/ydb/example/BasicExampleTest.java @@ -0,0 +1,30 @@ +package tech.ydb.example; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import tech.ydb.test.junit5.YdbHelperExtension; + +/** + * + * @author Aleksandr Gorshenin + */ +public class BasicExampleTest { + @RegisterExtension + private static final YdbHelperExtension ydb = new YdbHelperExtension(); + + private static String connectionString() { + StringBuilder sb = new StringBuilder(); + sb.append(ydb.useTls() ? "grpcs://" : "grpc://" ); + sb.append(ydb.endpoint()); + sb.append(ydb.database()); + return sb.toString(); + } + + @Test + public void testBasicApp() { + App app = new App(connectionString()); + app.run(); + app.close(); + } +} diff --git a/jdbc/spring-data-jpa-v5/pom.xml b/jdbc/spring-data-jpa-v5/pom.xml index bba7163..3299cc8 100644 --- a/jdbc/spring-data-jpa-v5/pom.xml +++ b/jdbc/spring-data-jpa-v5/pom.xml @@ -57,7 +57,7 @@ org.postgresql postgresql - 42.7.1 + 42.7.3 org.testcontainers @@ -65,23 +65,17 @@ 1.19.1 test - - tech.ydb.test - ydb-junit5-support - test - - - org.junit.jupiter - junit-jupiter-api - - - org.springframework.boot spring-boot-starter-test ${spring.boot.version} test + + tech.ydb.test + ydb-junit5-support + test + ${project.basedir}/src/main/kotlin diff --git a/jdbc/spring-data-jpa/pom.xml b/jdbc/spring-data-jpa/pom.xml index d883b09..1be2214 100644 --- a/jdbc/spring-data-jpa/pom.xml +++ b/jdbc/spring-data-jpa/pom.xml @@ -58,7 +58,7 @@ org.postgresql postgresql - 42.7.1 + 42.7.3 org.testcontainers diff --git a/pom.xml b/pom.xml index 1f1188a..1655ee9 100644 --- a/pom.xml +++ b/pom.xml @@ -18,13 +18,14 @@ 2.22.1 1.82 - 2.1.11 + 2.2.0 auth secondary_index basic_example + query-example ydb-cookbook url-shortener-demo jdbc diff --git a/query-example/pom.xml b/query-example/pom.xml new file mode 100644 index 0000000..42a68f9 --- /dev/null +++ b/query-example/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + + tech.ydb.examples + ydb-sdk-examples + 1.1.0-SNAPSHOT + + + ydb-query-example + YDB QueryClient basic example + Simple example of usage QueryClient of Java SDK for YDB + + + 5.10.1 + + + + + tech.ydb + ydb-sdk-query + + + tech.ydb.auth + yc-auth-provider + + + + org.apache.logging.log4j + log4j-slf4j-impl + + + + tech.ydb.test + ydb-junit5-support + test + + + + org.junit.jupiter + junit-jupiter-api + ${junit5.version} + test + + + + + ydb-basic-example + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + libs/ + tech.ydb.example.App + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + cr.yandex/yc/yandex-docker-local-ydb:trunk + true + 1 + + + + + + diff --git a/query-example/src/main/java/tech/ydb/example/App.java b/query-example/src/main/java/tech/ydb/example/App.java new file mode 100644 index 0000000..58ff312 --- /dev/null +++ b/query-example/src/main/java/tech/ydb/example/App.java @@ -0,0 +1,374 @@ +package tech.ydb.example; + +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDate; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import tech.ydb.auth.iam.CloudAuthHelper; +import tech.ydb.common.transaction.TxMode; +import tech.ydb.core.Status; +import tech.ydb.core.grpc.GrpcTransport; +import tech.ydb.query.QueryClient; +import tech.ydb.query.QueryStream; +import tech.ydb.query.QueryTransaction; +import tech.ydb.query.tools.QueryReader; +import tech.ydb.query.tools.SessionRetryContext; +import tech.ydb.table.query.Params; +import tech.ydb.table.result.ResultSetReader; +import tech.ydb.table.values.ListType; +import tech.ydb.table.values.ListValue; +import tech.ydb.table.values.PrimitiveType; +import tech.ydb.table.values.PrimitiveValue; +import tech.ydb.table.values.StructType; + + +public final class App implements Runnable, AutoCloseable { + private static final Logger logger = LoggerFactory.getLogger(App.class); + + private final GrpcTransport transport; + private final QueryClient queryClient; + private final SessionRetryContext retryCtx; + + App(String connectionString) { + this.transport = GrpcTransport.forConnectionString(connectionString) + .withAuthProvider(CloudAuthHelper.getAuthProviderFromEnviron()) + .build(); + this.queryClient = QueryClient.newClient(transport).build(); + this.retryCtx = SessionRetryContext.create(queryClient).build(); + } + + @Override + public void run() { + createTables(); + upsertTablesData(); + + upsertSimple(); + + selectSimple(); + selectWithParams(1, 2); + asyncSelectRead(2, 1); + + multiStepTransaction(2, 5); + tclTransaction(); + + dropTables(); + } + + @Override + public void close() { + queryClient.close(); + transport.close(); + } + + private void createTables() { + retryCtx.supplyResult(session -> session.createQuery("" + + "CREATE TABLE series (" + + " series_id UInt64," + + " title Text," + + " series_info Text," + + " release_date Date," + + " PRIMARY KEY(series_id)" + + ")", TxMode.NONE).execute() + ).join().getStatus().expectSuccess("Can't create table series"); + + retryCtx.supplyResult(session -> session.createQuery("" + + "CREATE TABLE seasons (" + + " series_id UInt64," + + " season_id UInt64," + + " title Text," + + " first_aired Date," + + " last_aired Date," + + " PRIMARY KEY(series_id, season_id)" + + ")", TxMode.NONE).execute() + ).join().getStatus().expectSuccess("Can't create table seasons"); + + retryCtx.supplyResult(session -> session.createQuery("" + + "CREATE TABLE episodes (" + + " series_id UInt64," + + " season_id UInt64," + + " episode_id UInt64," + + " title Text," + + " air_date Date," + + " PRIMARY KEY(series_id, season_id, episode_id)" + + ")", TxMode.NONE).execute() + ).join().getStatus().expectSuccess("Can't create table episodes"); + } + + private void upsertTablesData() { + // Create type for struct of series + StructType seriesType = StructType.of( + "series_id", PrimitiveType.Uint64, + "title", PrimitiveType.Text, + "release_date", PrimitiveType.Date, + "series_info", PrimitiveType.Text + ); + // Create and fill list of series + ListValue seriesData = ListType.of(seriesType).newValue( + SeriesData.SERIES.stream().map(series -> seriesType.newValue( + "series_id", PrimitiveValue.newUint64(series.seriesID()), + "title", PrimitiveValue.newText(series.title()), + "release_date", PrimitiveValue.newDate(series.releaseDate()), + "series_info", PrimitiveValue.newText(series.seriesInfo()) + )).collect(Collectors.toList()) + ); + + // Upsert list of series to table + retryCtx.supplyResult(session -> session.createQuery( + "UPSERT INTO series SELECT * FROM AS_TABLE($values)", + TxMode.SERIALIZABLE_RW, + Params.of("$values", seriesData) + ).execute()).join().getStatus().expectSuccess("upsert problem"); + + + // Create type for struct of season + StructType seasonType = StructType.of( + "series_id", PrimitiveType.Uint64, + "season_id", PrimitiveType.Uint64, + "title", PrimitiveType.Text, + "first_aired", PrimitiveType.Date, + "last_aired", PrimitiveType.Date + ); + // Create and fill list of seasons + ListValue seasonsData = ListType.of(seasonType).newValue( + SeriesData.SEASONS.stream().map(season -> seasonType.newValue( + "series_id", PrimitiveValue.newUint64(season.seriesID()), + "season_id", PrimitiveValue.newUint64(season.seasonID()), + "title", PrimitiveValue.newText(season.title()), + "first_aired", PrimitiveValue.newDate(season.firstAired()), + "last_aired", PrimitiveValue.newDate(season.lastAired()) + )).collect(Collectors.toList()) + ); + + // Upsert list of seasons to table + retryCtx.supplyResult(session -> session.createQuery( + "UPSERT INTO seasons SELECT * FROM AS_TABLE($values)", + TxMode.SERIALIZABLE_RW, + Params.of("$values", seasonsData) + ).execute()).join().getStatus().expectSuccess("upsert problem"); + + + // Create type for struct of episode + StructType episodeType = StructType.of( + "series_id", PrimitiveType.Uint64, + "season_id", PrimitiveType.Uint64, + "episode_id", PrimitiveType.Uint64, + "title", PrimitiveType.Text, + "air_date", PrimitiveType.Date + ); + // Create and fill list of episodes + ListValue episodesData = ListType.of(episodeType).newValue( + SeriesData.EPISODES.stream().map(episode -> episodeType.newValue( + "series_id", PrimitiveValue.newUint64(episode.seriesID()), + "season_id", PrimitiveValue.newUint64(episode.seasonID()), + "episode_id", PrimitiveValue.newUint64(episode.episodeID()), + "title", PrimitiveValue.newText(episode.title()), + "air_date", PrimitiveValue.newDate(episode.airDate()) + )).collect(Collectors.toList()) + ); + + // Upsert list of series to episodes + retryCtx.supplyResult(session -> session.createQuery( + "UPSERT INTO episodes SELECT * FROM AS_TABLE($values)", + TxMode.SERIALIZABLE_RW, + Params.of("$values", episodesData) + ).execute()).join().getStatus().expectSuccess("upsert problem"); + } + + private void upsertSimple() { + String query + = "UPSERT INTO episodes (series_id, season_id, episode_id, title) " + + "VALUES (2, 6, 1, \"TBD\");"; + + // Executes data query with specified transaction control settings. + retryCtx.supplyResult(session -> session.createQuery(query, TxMode.SERIALIZABLE_RW).execute()) + .join().getValue(); + } + + private void selectSimple() { + String query + = "SELECT series_id, title, release_date " + + "FROM series WHERE series_id = 1;"; + + // Executes data query with specified transaction control settings. + QueryReader result = retryCtx.supplyResult( + session -> QueryReader.readFrom(session.createQuery(query, TxMode.SERIALIZABLE_RW)) + ).join().getValue(); + + logger.info("--[ SelectSimple ]--"); + + ResultSetReader rs = result.getResultSet(0); + while (rs.next()) { + logger.info("read series with id {}, title {} and release_date {}", + rs.getColumn("series_id").getUint64(), + rs.getColumn("title").getText(), + rs.getColumn("release_date").getDate() + ); + } + } + + private void selectWithParams(long seriesID, long seasonID) { + String query + = "DECLARE $seriesId AS Uint64; " + + "DECLARE $seasonId AS Uint64; " + + "SELECT sa.title AS season_title, sr.title AS series_title " + + "FROM seasons AS sa INNER JOIN series AS sr ON sa.series_id = sr.series_id " + + "WHERE sa.series_id = $seriesId AND sa.season_id = $seasonId"; + + // Type of parameter values should be exactly the same as in DECLARE statements. + Params params = Params.of( + "$seriesId", PrimitiveValue.newUint64(seriesID), + "$seasonId", PrimitiveValue.newUint64(seasonID) + ); + + QueryReader result = retryCtx.supplyResult( + session -> QueryReader.readFrom(session.createQuery(query, TxMode.SNAPSHOT_RO, params)) + ).join().getValue(); + + logger.info("--[ SelectWithParams ] -- "); + + ResultSetReader rs = result.getResultSet(0); + while (rs.next()) { + logger.info("read season with title {} for series {}", + rs.getColumn("season_title").getText(), + rs.getColumn("series_title").getText() + ); + } + } + + private void asyncSelectRead(long seriesID, long seasonID) { + String query + = "DECLARE $seriesId AS Uint64; " + + "DECLARE $seasonId AS Uint64; " + + "SELECT ep.title AS episode_title, sa.title AS season_title, sr.title AS series_title " + + "FROM episodes AS ep " + + "JOIN seasons AS sa ON sa.season_id = ep.season_id " + + "JOIN series AS sr ON sr.series_id = sa.series_id " + + "WHERE sa.series_id = $seriesId AND sa.season_id = $seasonId;"; + + // Type of parameter values should be exactly the same as in DECLARE statements. + Params params = Params.of( + "$seriesId", PrimitiveValue.newUint64(seriesID), + "$seasonId", PrimitiveValue.newUint64(seasonID) + ); + + logger.info("--[ ExecuteAsyncQueryWithParams ]--"); + retryCtx.supplyResult(session -> { + QueryStream asyncQuery = session.createQuery(query, TxMode.SNAPSHOT_RO, params); + return asyncQuery.execute(part -> { + ResultSetReader rs = part.getResultSetReader(); + logger.info("read {} rows of result set {}", rs.getRowCount(), part.getResultSetIndex()); + while (rs.next()) { + logger.info("read episode {} of {} for {}", + rs.getColumn("episode_title").getText(), + rs.getColumn("season_title").getText(), + rs.getColumn("series_title").getText() + ); + } + }); + }).join().getStatus().expectSuccess("execute query problem"); + } + + private void multiStepTransaction(long seriesID, long seasonID) { + retryCtx.supplyStatus(session -> { + QueryTransaction transaction = session.createNewTransaction(TxMode.SNAPSHOT_RO); + String query1 + = "DECLARE $seriesId AS Uint64; " + + "DECLARE $seasonId AS Uint64; " + + "SELECT MIN(first_aired) AS from_date FROM seasons " + + "WHERE series_id = $seriesId AND season_id = $seasonId;"; + + // Execute first query to start a new transaction + QueryReader res1 = QueryReader.readFrom(transaction.createQuery(query1, Params.of( + "$seriesId", PrimitiveValue.newUint64(seriesID), + "$seasonId", PrimitiveValue.newUint64(seasonID) + ))).join().getValue(); + + // Perform some client logic on returned values + ResultSetReader resultSet = res1.getResultSet(0); + if (!resultSet.next()) { + throw new RuntimeException("not found first_aired"); + } + LocalDate fromDate = resultSet.getColumn("from_date").getDate(); + LocalDate toDate = fromDate.plusDays(15); + + // Get active transaction id + logger.info("started new transaction {}", transaction.getId()); + + // Construct next query based on the results of client logic + String query2 + = "DECLARE $seriesId AS Uint64;" + + "DECLARE $fromDate AS Date;" + + "DECLARE $toDate AS Date;" + + "SELECT season_id, episode_id, title, air_date FROM episodes " + + "WHERE series_id = $seriesId AND air_date >= $fromDate AND air_date <= $toDate;"; + + // Execute second query with commit at end. + QueryReader res2 = QueryReader.readFrom(transaction.createQueryWithCommit(query2, Params.of( + "$seriesId", PrimitiveValue.newUint64(seriesID), + "$fromDate", PrimitiveValue.newDate(fromDate), + "$toDate", PrimitiveValue.newDate(toDate) + ))).join().getValue(); + + logger.info("--[ MultiStep ]--"); + ResultSetReader rs = res2.getResultSet(0); + while (rs.next()) { + logger.info("read episode {} with air date {}", + rs.getColumn("title").getText(), + rs.getColumn("air_date").getDate() + ); + } + + return CompletableFuture.completedFuture(Status.SUCCESS); + }).join().expectSuccess("multistep transaction problem"); + } + + private void tclTransaction() { + retryCtx.supplyResult(session -> { + QueryTransaction transaction = session.beginTransaction(TxMode.SERIALIZABLE_RW) + .join().getValue(); + + String query + = "DECLARE $airDate AS Date; " + + "UPDATE episodes SET air_date = $airDate WHERE title = \"TBD\";"; + + Params params = Params.of("$airDate", PrimitiveValue.newDate(Instant.now())); + + // Execute data query. + // Transaction control settings continues active transaction (tx) + QueryReader reader = QueryReader.readFrom(transaction.createQuery(query, params)) + .join().getValue(); + + logger.info("get transaction {}", transaction.getId()); + + // Commit active transaction (tx) + return transaction.commit(); + }).join().getStatus().expectSuccess("tcl transaction problem"); + } + + private void dropTables() { + retryCtx.supplyResult(session -> session.createQuery("DROP TABLE episodes;", TxMode.NONE).execute()) + .join().getStatus().expectSuccess("drop table episodes problem"); + retryCtx.supplyResult(session -> session.createQuery("DROP TABLE seasons;", TxMode.NONE).execute()) + .join().getStatus().expectSuccess("drop table seasons problem"); + retryCtx.supplyResult(session -> session.createQuery("DROP TABLE series;", TxMode.NONE).execute()) + .join().getStatus().expectSuccess("drop table series problem"); + } + + public static void main(String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Usage: java -jar ydb-basic-example.jar "); + return; + } + + try (App app = new App(args[0])) { + app.run(); + } catch (Exception e) { + logger.error("app problem", e); + } + } +} diff --git a/query-example/src/main/java/tech/ydb/example/SeriesData.java b/query-example/src/main/java/tech/ydb/example/SeriesData.java new file mode 100644 index 0000000..f047a2d --- /dev/null +++ b/query-example/src/main/java/tech/ydb/example/SeriesData.java @@ -0,0 +1,114 @@ +package tech.ydb.example; + +import java.time.Instant; +import java.util.Arrays; +import java.util.List; + +import tech.ydb.example.model.Episode; +import tech.ydb.example.model.Season; +import tech.ydb.example.model.Series; + + +final class SeriesData { + public static final List SERIES = Arrays.asList( + new Series( + 1, "IT Crowd", date("2006-02-03"), + "The IT Crowd is a British sitcom produced by Channel 4, written by Graham Linehan, produced by " + + "Ash Atalla and starring Chris O'Dowd, Richard Ayoade, Katherine Parkinson, and Matt Berry."), + new Series( + 2, "Silicon Valley", date("2014-04-06"), + "Silicon Valley is an American comedy television series created by Mike Judge, John Altschuler and " + + "Dave Krinsky. The series focuses on five young men who founded a startup company in Silicon Valley.") + ); + + public static final List SEASONS = Arrays.asList( + new Season(1, 1, "Season 1", date("2006-02-03"), date("2006-03-03")), + new Season(1, 2, "Season 2", date("2007-08-24"), date("2007-09-28")), + new Season(1, 3, "Season 3", date("2008-11-21"), date("2008-12-26")), + new Season(1, 4, "Season 4", date("2010-06-25"), date("2010-07-30")), + new Season(2, 1, "Season 1", date("2014-04-06"), date("2014-06-01")), + new Season(2, 2, "Season 2", date("2015-04-12"), date("2015-06-14")), + new Season(2, 3, "Season 3", date("2016-04-24"), date("2016-06-26")), + new Season(2, 4, "Season 4", date("2017-04-23"), date("2017-06-25")), + new Season(2, 5, "Season 5", date("2018-03-25"), date("2018-05-13")) + ); + + public static final List EPISODES = Arrays.asList( + new Episode(1, 1, 1, "Yesterday's Jam", date("2006-02-03")), + new Episode(1, 1, 2, "Calamity Jen", date("2006-02-03")), + new Episode(1, 1, 3, "Fifty-Fifty", date("2006-02-10")), + new Episode(1, 1, 4, "The Red Door", date("2006-02-17")), + new Episode(1, 1, 5, "The Haunting of Bill Crouse", date("2006-02-24")), + new Episode(1, 1, 6, "Aunt Irma Visits", date("2006-03-03")), + new Episode(1, 2, 1, "The Work Outing", date("2006-08-24")), + new Episode(1, 2, 2, "Return of the Golden Child", date("2007-08-31")), + new Episode(1, 2, 3, "Moss and the German", date("2007-09-07")), + new Episode(1, 2, 4, "The Dinner Party", date("2007-09-14")), + new Episode(1, 2, 5, "Smoke and Mirrors", date("2007-09-21")), + new Episode(1, 2, 6, "Men Without Women", date("2007-09-28")), + new Episode(1, 3, 1, "From Hell", date("2008-11-21")), + new Episode(1, 3, 2, "Are We Not Men?", date("2008-11-28")), + new Episode(1, 3, 3, "Tramps Like Us", date("2008-12-05")), + new Episode(1, 3, 4, "The Speech", date("2008-12-12")), + new Episode(1, 3, 5, "Friendface", date("2008-12-19")), + new Episode(1, 3, 6, "Calendar Geeks", date("2008-12-26")), + new Episode(1, 4, 1, "Jen The Fredo", date("2010-06-25")), + new Episode(1, 4, 2, "The Final Countdown", date("2010-07-02")), + new Episode(1, 4, 3, "Something Happened", date("2010-07-09")), + new Episode(1, 4, 4, "Italian For Beginners", date("2010-07-16")), + new Episode(1, 4, 5, "Bad Boys", date("2010-07-23")), + new Episode(1, 4, 6, "Reynholm vs Reynholm", date("2010-07-30")), + new Episode(2, 1, 1, "Minimum Viable Product", date("2014-04-06")), + new Episode(2, 1, 2, "The Cap Table", date("2014-04-13")), + new Episode(2, 1, 3, "Articles of Incorporation", date("2014-04-20")), + new Episode(2, 1, 4, "Fiduciary Duties", date("2014-04-27")), + new Episode(2, 1, 5, "Signaling Risk", date("2014-05-04")), + new Episode(2, 1, 6, "Third Party Insourcing", date("2014-05-11")), + new Episode(2, 1, 7, "Proof of Concept", date("2014-05-18")), + new Episode(2, 1, 8, "Optimal Tip-to-Tip Efficiency", date("2014-06-01")), + new Episode(2, 2, 1, "Sand Hill Shuffle", date("2015-04-12")), + new Episode(2, 2, 2, "Runaway Devaluation", date("2015-04-19")), + new Episode(2, 2, 3, "Bad Money", date("2015-04-26")), + new Episode(2, 2, 4, "The Lady", date("2015-05-03")), + new Episode(2, 2, 5, "Server Space", date("2015-05-10")), + new Episode(2, 2, 6, "Homicide", date("2015-05-17")), + new Episode(2, 2, 7, "Adult Content", date("2015-05-24")), + new Episode(2, 2, 8, "White Hat/Black Hat", date("2015-05-31")), + new Episode(2, 2, 9, "Binding Arbitration", date("2015-06-07")), + new Episode(2, 2, 10, "Two Days of the Condor", date("2015-06-14")), + new Episode(2, 3, 1, "Founder Friendly", date("2016-04-24")), + new Episode(2, 3, 2, "Two in the Box", date("2016-05-01")), + new Episode(2, 3, 3, "Meinertzhagen's Haversack", date("2016-05-08")), + new Episode(2, 3, 4, "Maleant Data Systems Solutions", date("2016-05-15")), + new Episode(2, 3, 5, "The Empty Chair", date("2016-05-22")), + new Episode(2, 3, 6, "Bachmanity Insanity", date("2016-05-29")), + new Episode(2, 3, 7, "To Build a Better Beta", date("2016-06-05")), + new Episode(2, 3, 8, "Bachman's Earnings Over-Ride", date("2016-06-12")), + new Episode(2, 3, 9, "Daily Active Users", date("2016-06-19")), + new Episode(2, 3, 10, "The Uptick", date("2016-06-26")), + new Episode(2, 4, 1, "Success Failure", date("2017-04-23")), + new Episode(2, 4, 2, "Terms of Service", date("2017-04-30")), + new Episode(2, 4, 3, "Intellectual Property", date("2017-05-07")), + new Episode(2, 4, 4, "Teambuilding Exercise", date("2017-05-14")), + new Episode(2, 4, 5, "The Blood Boy", date("2017-05-21")), + new Episode(2, 4, 6, "Customer Service", date("2017-05-28")), + new Episode(2, 4, 7, "The Patent Troll", date("2017-06-04")), + new Episode(2, 4, 8, "The Keenan Vortex", date("2017-06-11")), + new Episode(2, 4, 9, "Hooli-Con", date("2017-06-18")), + new Episode(2, 4, 10, "Server Error", date("2017-06-25")), + new Episode(2, 5, 1, "Grow Fast or Die Slow", date("2018-03-25")), + new Episode(2, 5, 2, "Reorientation", date("2018-04-01")), + new Episode(2, 5, 3, "Chief Operating Officer", date("2018-04-08")), + new Episode(2, 5, 4, "Tech Evangelist", date("2018-04-15")), + new Episode(2, 5, 5, "Facial Recognition", date("2018-04-22")), + new Episode(2, 5, 6, "Artificial Emotional Intelligence", date("2018-04-29")), + new Episode(2, 5, 7, "Initial Coin Offering", date("2018-05-06")), + new Episode(2, 5, 8, "Fifty-One Percent", date("2018-05-13")) + ); + + private SeriesData() { } + + private static Instant date(String str) { + return Instant.parse(str + "T00:00:00Z"); + } +} diff --git a/query-example/src/main/java/tech/ydb/example/model/Episode.java b/query-example/src/main/java/tech/ydb/example/model/Episode.java new file mode 100644 index 0000000..0c68ef7 --- /dev/null +++ b/query-example/src/main/java/tech/ydb/example/model/Episode.java @@ -0,0 +1,40 @@ +package tech.ydb.example.model; + +import java.time.Instant; + + +public class Episode { + private final long seriesID; + private final long seasonID; + private final long episodeID; + private final String title; + private final Instant airDate; + + public Episode(long seriesID, long seasonID, long episodeID, String title, Instant airDate) { + this.seriesID = seriesID; + this.seasonID = seasonID; + this.episodeID = episodeID; + this.title = title; + this.airDate = airDate; + } + + public long seriesID() { + return seriesID; + } + + public long seasonID() { + return seasonID; + } + + public long episodeID() { + return episodeID; + } + + public String title() { + return title; + } + + public Instant airDate() { + return airDate; + } +} diff --git a/query-example/src/main/java/tech/ydb/example/model/Season.java b/query-example/src/main/java/tech/ydb/example/model/Season.java new file mode 100644 index 0000000..eeb512d --- /dev/null +++ b/query-example/src/main/java/tech/ydb/example/model/Season.java @@ -0,0 +1,40 @@ +package tech.ydb.example.model; + +import java.time.Instant; + + +public class Season { + private final long seriesID; + private final long seasonID; + private final String title; + private final Instant firstAired; + private final Instant lastAired; + + public Season(long seriesID, long seasonID, String title, Instant firstAired, Instant lastAired) { + this.seriesID = seriesID; + this.seasonID = seasonID; + this.title = title; + this.firstAired = firstAired; + this.lastAired = lastAired; + } + + public long seriesID() { + return this.seriesID; + } + + public long seasonID() { + return this.seasonID; + } + + public String title() { + return this.title; + } + + public Instant firstAired() { + return this.firstAired; + } + + public Instant lastAired() { + return this.lastAired; + } +} diff --git a/query-example/src/main/java/tech/ydb/example/model/Series.java b/query-example/src/main/java/tech/ydb/example/model/Series.java new file mode 100644 index 0000000..d074c28 --- /dev/null +++ b/query-example/src/main/java/tech/ydb/example/model/Series.java @@ -0,0 +1,34 @@ +package tech.ydb.example.model; + +import java.time.Instant; + + +public class Series { + private final long seriesID; + private final String title; + private final Instant releaseDate; + private final String seriesInfo; + + public Series(long seriesID, String title, Instant releaseDate, String seriesInfo) { + this.seriesID = seriesID; + this.title = title; + this.releaseDate = releaseDate; + this.seriesInfo = seriesInfo; + } + + public long seriesID() { + return seriesID; + } + + public String title() { + return title; + } + + public Instant releaseDate() { + return releaseDate; + } + + public String seriesInfo() { + return seriesInfo; + } +} diff --git a/query-example/src/main/resources/log4j2.xml b/query-example/src/main/resources/log4j2.xml new file mode 100644 index 0000000..cdcbde9 --- /dev/null +++ b/query-example/src/main/resources/log4j2.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/query-example/src/test/java/tech/ydb/example/BasicExampleTest.java b/query-example/src/test/java/tech/ydb/example/BasicExampleTest.java new file mode 100644 index 0000000..8d162a1 --- /dev/null +++ b/query-example/src/test/java/tech/ydb/example/BasicExampleTest.java @@ -0,0 +1,30 @@ +package tech.ydb.example; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import tech.ydb.test.junit5.YdbHelperExtension; + +/** + * + * @author Aleksandr Gorshenin + */ +public class BasicExampleTest { + @RegisterExtension + private static final YdbHelperExtension ydb = new YdbHelperExtension(); + + private static String connectionString() { + StringBuilder sb = new StringBuilder(); + sb.append(ydb.useTls() ? "grpcs://" : "grpc://" ); + sb.append(ydb.endpoint()); + sb.append(ydb.database()); + return sb.toString(); + } + + @Test + public void testBasicApp() { + App app = new App(connectionString()); + app.run(); + app.close(); + } +} diff --git a/url-shortener-demo/pom.xml b/url-shortener-demo/pom.xml index 4b51b88..9209912 100644 --- a/url-shortener-demo/pom.xml +++ b/url-shortener-demo/pom.xml @@ -16,6 +16,7 @@ 10.0.14 2.9.0 + 5.10.1 @@ -53,6 +54,13 @@ ydb-junit5-support test + + + org.junit.jupiter + junit-jupiter-api + ${junit5.version} + test + diff --git a/ydb-cookbook/pom.xml b/ydb-cookbook/pom.xml index 799d38e..a0aa1c1 100644 --- a/ydb-cookbook/pom.xml +++ b/ydb-cookbook/pom.xml @@ -14,7 +14,7 @@ Receipts of usage Java SDK for YDB - UTF-8 + 5.10.1 @@ -50,5 +50,27 @@ ydb-junit5-support test + + + org.junit.jupiter + junit-jupiter-api + ${junit5.version} + test + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + true + 1 + + + + + diff --git a/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java b/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java index b269a70..47cd292 100644 --- a/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java +++ b/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ComplexTransaction.java @@ -1,14 +1,15 @@ package tech.ydb.examples.simple; import java.time.Duration; -import tech.ydb.core.grpc.GrpcTransport; +import tech.ydb.common.transaction.TxMode; +import tech.ydb.core.grpc.GrpcTransport; import tech.ydb.examples.SimpleExample; import tech.ydb.table.Session; import tech.ydb.table.TableClient; import tech.ydb.table.description.TableDescription; import tech.ydb.table.query.DataQueryResult; -import tech.ydb.table.transaction.Transaction; +import tech.ydb.table.transaction.TableTransaction; import tech.ydb.table.transaction.TxControl; import tech.ydb.table.values.PrimitiveType; @@ -24,7 +25,7 @@ protected void run(GrpcTransport transport, String pathPrefix) { try ( TableClient tableClient = TableClient.newClient(transport).build(); - Session session = tableClient.createSession(Duration.ofSeconds(5)).join().getValue(); + Session session = tableClient.createSession(Duration.ofSeconds(5)).join().getValue() ) { session.dropTable(tablePath) @@ -40,27 +41,22 @@ protected void run(GrpcTransport transport, String pathPrefix) { .join() .expectSuccess("cannot create table"); - Transaction transaction = session.beginTransaction(Transaction.Mode.SERIALIZABLE_READ_WRITE) - .join() - .getValue(); + TableTransaction transaction = session.beginTransaction(TxMode.SERIALIZABLE_RW) + .join().getValue(); - String query1 = "UPSERT INTO [" + tablePath + "] (key, value) VALUES (1, 'one');"; - DataQueryResult result1 = session.executeDataQuery(query1, TxControl.id(transaction)) - .join() - .getValue(); + String query1 = "UPSERT INTO `" + tablePath + "` (key, value) VALUES (1, 'one');"; + DataQueryResult result1 = transaction.executeDataQuery(query1).join().getValue(); System.out.println("--[insert1]-------------------"); DataQueryResults.print(result1); System.out.println("------------------------------"); - String query2 = "UPSERT INTO [" + tablePath + "] (key, value) VALUES (2, 'two');"; - DataQueryResult result2 = session.executeDataQuery(query2, TxControl.id(transaction)) - .join() - .getValue(); + String query2 = "UPSERT INTO `" + tablePath + "` (key, value) VALUES (2, 'two');"; + DataQueryResult result2 = transaction.executeDataQuery(query2).join().getValue(); System.out.println("--[insert2]-------------------"); DataQueryResults.print(result2); System.out.println("------------------------------"); - String query3 = "SELECT * FROM [" + tablePath + "];"; + String query3 = "SELECT * FROM `" + tablePath + "`;"; DataQueryResult result3 = session.executeDataQuery(query3, TxControl.onlineRo().setCommitTx(true)) .join() .getValue(); @@ -72,7 +68,7 @@ protected void run(GrpcTransport transport, String pathPrefix) { .join() .expectSuccess("cannot commit transaction"); - String query = "SELECT * FROM [" + tablePath + "];"; + String query = "SELECT * FROM `" + tablePath + "`;"; DataQueryResult result = session.executeDataQuery(query, TxControl.onlineRo().setCommitTx(true)) .join() .getValue(); @@ -85,4 +81,9 @@ protected void run(GrpcTransport transport, String pathPrefix) { public static void main(String[] args) { new ComplexTransaction().doMain(args); } + + public static int test(String[] args) { + new ComplexTransaction().doMain(args); + return 0; + } } diff --git a/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ReadTableExample.java b/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ReadTableExample.java index f53a456..e6ab31b 100644 --- a/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ReadTableExample.java +++ b/ydb-cookbook/src/main/java/tech/ydb/examples/simple/ReadTableExample.java @@ -1,11 +1,13 @@ package tech.ydb.examples.simple; -import java.time.Duration; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import tech.ydb.core.grpc.GrpcTransport; import tech.ydb.examples.SimpleExample; -import tech.ydb.table.Session; +import tech.ydb.table.SessionRetryContext; import tech.ydb.table.TableClient; import tech.ydb.table.result.ResultSetReader; import tech.ydb.table.settings.ReadTableSettings; @@ -17,28 +19,31 @@ * @author Sergey Polovko */ public class ReadTableExample extends SimpleExample { + private static final String TABLE_NAME = "read_table_example"; + private static final Logger logger = LoggerFactory.getLogger(ReadTableExample.class); + @Override protected void run(GrpcTransport transport, String pathPrefix) { - try ( - TableClient tableClient = TableClient.newClient(transport).build(); - Session session = tableClient.createSession(Duration.ofSeconds(5)).join().getValue() - ) { - - String tablePath = pathPrefix + getClass().getSimpleName(); - createAndFillTable(session, tablePath); - readTable(session, tablePath); + try (TableClient tableClient = TableClient.newClient(transport).build()) { + SessionRetryContext retryCtx = SessionRetryContext.create(tableClient).build(); + + createAndFillTable(retryCtx); + readTable(retryCtx, transport.getDatabase()); + dropTable(retryCtx); } } - private void readTable(Session session, String tablePath) { + private void readTable(SessionRetryContext retryCtx, String database) { + ReadTableSettings settings = ReadTableSettings.newBuilder() .orderedRead(true) .fromKeyInclusive(PrimitiveValue.newUint32(10)) .toKeyExclusive(PrimitiveValue.newUint32(25)) .build(); - session.executeReadTable(tablePath, settings).start(part -> { + String tablePath = database + "/" + TABLE_NAME; + retryCtx.supplyStatus(session -> session.executeReadTable(tablePath, settings).start(part -> { ResultSetReader resultSet = part.getResultSetReader(); // we are going to read a lot of data, so map column names to indexes @@ -49,31 +54,37 @@ private void readTable(Session session, String tablePath) { while (resultSet.next()) { long key = resultSet.getColumn(keyIdx).getUint32(); String value = resultSet.getColumn(valueIdx).getText(); - System.out.printf("key=%d, value=%s\n", key, value); + logger.info("key={}, value={}", key, value); } - }).join().expectSuccess("readTable failed"); + })).join().expectSuccess("readTable failed"); } - private void createAndFillTable(Session session, String tablePath) { + private void createAndFillTable(SessionRetryContext retryCtx) { String createTable = - "CREATE TABLE [" + tablePath + "] (" + + "CREATE TABLE " + TABLE_NAME + " (" + " key Uint32," + " value Utf8," + " PRIMARY KEY(key)" + ");"; - session.executeSchemeQuery(createTable) + retryCtx.supplyStatus(session -> session.executeSchemeQuery(createTable)) .join() .expectSuccess("cannot create table"); for (int i = 0; i < 100; i++) { - String query = "REPLACE INTO [" + tablePath + "](key, value) VALUES (" + i + ", \"<" + i + ">\");"; - session.executeDataQuery(query, TxControl.serializableRw().setCommitTx(true)) - .join() - .getStatus().expectSuccess("cannot execute insert"); + String query = "UPSERT INTO " + TABLE_NAME + "(key, value) VALUES (" + i + ", \"<" + i + ">\");"; + retryCtx.supplyResult(session -> session.executeDataQuery(query, TxControl.serializableRw())) + .join().getStatus().expectSuccess("cannot execute insert"); } } + private void dropTable(SessionRetryContext retryCtx) { + String dropSQL = "DROP TABLE " + TABLE_NAME + ";"; + retryCtx.supplyStatus(session -> session.executeSchemeQuery(dropSQL)) + .join() + .expectSuccess("cannot create table"); + } + public static void main(String[] args) { new ReadTableExample().doMain(args); } diff --git a/ydb-cookbook/src/test/java/tech/ydb/examples/ExamplesTest.java b/ydb-cookbook/src/test/java/tech/ydb/examples/ExamplesTest.java index 0d4884d..98c5d6b 100644 --- a/ydb-cookbook/src/test/java/tech/ydb/examples/ExamplesTest.java +++ b/ydb-cookbook/src/test/java/tech/ydb/examples/ExamplesTest.java @@ -7,6 +7,8 @@ import tech.ydb.examples.batch_upload.BatchUpload; import tech.ydb.examples.bulk_upsert.BulkUpsert; import tech.ydb.examples.pagination.PaginationApp; +import tech.ydb.examples.simple.ComplexTransaction; +import tech.ydb.examples.simple.ReadTableExample; import tech.ydb.test.junit5.YdbHelperExtension; /** @@ -24,6 +26,14 @@ private String[] args() { }; } + private String[] connectionString() { + StringBuilder sb = new StringBuilder(); + sb.append(ydb.useTls() ? "grpcs://" : "grpc://" ); + sb.append(ydb.endpoint()); + sb.append(ydb.database()); + return new String [] { sb.toString() }; + } + @Test public void testBatchUpload() { Assertions.assertEquals(0, BatchUpload.test(args()), "Batch upload test"); @@ -34,8 +44,18 @@ public void testBulkUpsert() { Assertions.assertEquals(0, BulkUpsert.test(args()), "Bulk upsert test"); } + @Test + public void testReadTable() { + ReadTableExample.main(connectionString()); + } + @Test public void testPagination() { Assertions.assertEquals(0, PaginationApp.test(args(), "Pagination test")); } + + @Test + public void testComplexTransaction() { + Assertions.assertEquals(0, ComplexTransaction.test(connectionString())); + } }