diff --git a/pom.xml b/pom.xml
index 1f1188a..8a72253 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,13 +18,14 @@
2.22.1
1.82
- 2.1.11
+ 2.2.0-SNAPSHOT
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..b95c969
--- /dev/null
+++ b/query-example/pom.xml
@@ -0,0 +1,88 @@
+
+
+ 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
+ ydb-sdk-topic
+
+
+ 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..bab6d2b
--- /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.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.QueryTx;
+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)"
+ + ")", QueryTx.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)"
+ + ")", QueryTx.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)"
+ + ")", QueryTx.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)",
+ QueryTx.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)",
+ QueryTx.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)",
+ QueryTx.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, QueryTx.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, QueryTx.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, QueryTx.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, QueryTx.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(QueryTx.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(QueryTx.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;", QueryTx.NONE).execute())
+ .join().getStatus().expectSuccess("drop table episodes problem");
+ retryCtx.supplyResult(session -> session.createQuery("DROP TABLE seasons;", QueryTx.NONE).execute())
+ .join().getStatus().expectSuccess("drop table seasons problem");
+ retryCtx.supplyResult(session -> session.createQuery("DROP TABLE series;", QueryTx.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();
+ }
+}