appService = new AppService; $this->ydb = $this->appService->initYdb(); parent::__construct(); } protected function configure() { $this->setDescription('Run the Basic Example.'); } /** * @param InputInterface $input * @param OutputInterface $output * @return int * @throws \Exception */ protected function execute(InputInterface $input, OutputInterface $output) { $this->output = $output; $this->runExample(); return Command::SUCCESS; } /** * @param mixed $value */ protected function print($value) { if (is_array($value)) { $this->table($value); } else { $this->output->writeln($value); } } /** * @param array $value */ protected function table($array) { if ($array) { $table = new Table($this->output); $table ->setHeaders(array_keys($array[0])) ->setRows($array); $table->render(); } } protected function runExample() { $this->runQuery('Create tables', function () { $this->createTables(); }); $this->runQuery('Describe table', function () { $this->describeTable('seasons'); }); $this->runQuery('Fill tables with data', function () { $this->fillTablesWithData(); }); $this->runQuery('Select simple transaction', function () { $this->selectSimple(); }); $this->runQuery('Upsert simple transaction', function () { $this->upsertSimple(); }); $this->runQuery('Bulk upsert', function () { $this->bulkUpsert(); }); $this->runQuery('Select prepared', function () { $this->selectPrepared(2, 3, 7); $this->selectPrepared(2, 3, 8); }); $this->runQuery('Explicit TCL', function () { $this->explicitTcl(2, 6, 1); }); $this->runQuery('Select prepared', function () { $this->selectPrepared(2, 6, 1); }); } /** * @param string $header * @param callable $closure */ protected function runQuery($header, $closure) { $this->print('> ' . $header . ':'); $this->print(''); $closure(); $this->print(''); } protected function createTables() { $this->ydb->table()->retrySession(function (Session $session) { $session->createTable( 'series', YdbTable::make() ->addColumn('series_id', 'UINT64') ->addColumn('title', 'UTF8') ->addColumn('series_info', 'UTF8') ->addColumn('release_date', 'UINT64') ->primaryKey('series_id') ); }, true); $this->print('Table `series` has been created.'); $this->ydb->table()->retrySession(function (Session $session) { $session->createTable( 'seasons', YdbTable::make() ->addColumn('series_id', 'UINT64') ->addColumn('season_id', 'UINT64') ->addColumn('title', 'UTF8') ->addColumn('first_aired', 'UINT64') ->addColumn('last_aired', 'UINT64') ->primaryKey(['series_id', 'season_id']) ); }, true); $this->print('Table `seasons` has been created.'); $this->ydb->table()->retrySession(function (Session $session) { $session->createTable( 'episodes', YdbTable::make() ->addColumn('series_id', 'UINT64') ->addColumn('season_id', 'UINT64') ->addColumn('episode_id', 'UINT64') ->addColumn('title', 'UTF8') ->addColumn('air_date', 'UINT64') ->primaryKey(['series_id', 'season_id', 'episode_id']) ); }, true); $this->print('Table `episodes` has been created.'); } /** * @param string $table */ protected function describeTable($table) { $data = $this->ydb->table()->retrySession(function (Session $session) use ($table) { return $session->describeTable($table); }, true); $columns = []; foreach ($data['columns'] as $column) { if (isset($column['type']['optionalType']['item']['typeId'])) { $columns[] = [ 'Name' => $column['name'], 'Type' => $column['type']['optionalType']['item']['typeId'], ]; } } $this->print('Table `' . $table . '`'); $this->print($columns); $this->print(''); $this->print('Primary key: ' . implode(', ', (array)$data['primaryKey'])); } protected function fillTablesWithData() { $params = new RetryParams(4000,null,new Backoff(10,1000)); $this->ydb->table()->retryTransaction(function (Session $session) { $prepared_query = $session->prepare($this->getFillDataQuery()); $prepared_query->execute([ 'seriesData' => $this->getSeriesData(), 'seasonsData' => $this->getSeasonsData(), 'episodesData' => $this->getEpisodesData(), ]); }, false, $params); $this->print('Finished.'); } protected function selectSimple() { $params = new RetryParams(4000,new Backoff(3,20)); $result = $this->ydb->table()->retryTransaction(function (Session $session) { return $session->query(' $format = DateTime::Format("%Y-%m-%d"); SELECT series_id, title, $format(DateTime::FromSeconds(CAST(release_date AS Uint32))) AS release_date FROM series WHERE series_id = 1;'); }, true, $params); $this->print($result->rows()); } protected function upsertSimple() { $this->ydb->table()->retryTransaction(function (Session $session) { return $session->query(' UPSERT INTO episodes (series_id, season_id, episode_id, title) VALUES (2, 6, 1, "TBD");'); }, true); $this->print('Finished.'); } protected function bulkUpsert() { $this->ydb->retry(function (Ydb $ydb) { $table = $ydb->table(); $table->bulkUpsert( 'episodes', $this->getEpisodesDataForBulkUpsert(), [ 'series_id' => 'Uint64', 'season_id' => 'Uint64', 'episode_id' => 'Uint64', 'title' => 'Utf8', 'air_date' => 'Uint64', ] ); }, true); $this->print('Finished.'); } /** * @param int $series_id * @param int $season_id * @param int $episode_id */ protected function selectPrepared($series_id, $season_id, $episode_id) { $result = $this->ydb->table()->retryTransaction(function (Session $session) use ($series_id, $season_id, $episode_id) { $prepared_query = $session->prepare(' DECLARE $series_id AS Uint64; DECLARE $season_id AS Uint64; DECLARE $episode_id AS Uint64; $format = DateTime::Format("%Y-%m-%d"); SELECT title AS `Episode title`, $format(DateTime::FromSeconds(CAST(air_date AS Uint32))) AS `Air date` FROM episodes WHERE series_id = $series_id AND season_id = $season_id AND episode_id = $episode_id;'); return $prepared_query->execute(compact( 'series_id', 'season_id', 'episode_id' )); },true); $this->print($result->rows()); } /** * @param int $series_id * @param int $season_id * @param int $episode_id */ protected function explicitTcl($series_id, $season_id, $episode_id) { $this->ydb->table()->retryTransaction(function (Session $session) use ($series_id, $season_id, $episode_id) { $prepared_query = $session->prepare(' DECLARE $today AS Uint64; DECLARE $series_id AS Uint64; DECLARE $season_id AS Uint64; DECLARE $episode_id AS Uint64; UPDATE episodes SET air_date = $today WHERE series_id = $series_id AND season_id = $season_id AND episode_id = $episode_id;'); $today = strtotime('today'); $prepared_query->execute(compact( 'series_id', 'season_id', 'episode_id', 'today' )); }); $this->print('Finished.'); } /** * @param int $series_id * @param string $title * @param int $release_date * @param string $series_info */ protected function newSeries($series_id, $title, $release_date, $series_info) { $release_date = strtotime($release_date); return compact('series_id', 'title', 'release_date', 'series_info'); } /** * @return array */ protected function getSeriesData() { return [ $this->newSeries( 1, 'IT Crowd', '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.', ), $this->newSeries( 2, 'Silicon Valley', '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.', ), ]; } /** * @param int $series_id * @param int $season_id * @param string $title * @param int $first_aired * @param int $last_aired */ protected function newSeason($series_id, $season_id, $title, $first_aired, $last_aired) { $first_aired = strtotime($first_aired); $last_aired = strtotime($last_aired); return compact('series_id', 'season_id', 'title', 'first_aired', 'last_aired'); } /** * @return array */ protected function getSeasonsData() { return [ $this->newSeason(1, 1, 'Season 1', '2006-02-03', '2006-03-03'), $this->newSeason(1, 2, 'Season 2', '2007-08-24', '2007-09-28'), $this->newSeason(1, 3, 'Season 3', '2008-11-21', '2008-12-26'), $this->newSeason(1, 4, 'Season 4', '2010-06-25', '2010-07-30'), $this->newSeason(2, 1, 'Season 1', '2014-04-06', '2014-06-01'), $this->newSeason(2, 2, 'Season 2', '2015-04-12', '2015-06-14'), $this->newSeason(2, 3, 'Season 3', '2016-04-24', '2016-06-26'), $this->newSeason(2, 4, 'Season 4', '2017-04-23', '2017-06-25'), $this->newSeason(2, 5, 'Season 5', '2018-03-25', '2018-05-13'), ]; } /** * @param int $series_id * @param int $season_id * @param int $episode_id * @param string $title * @param int $air_date */ protected function newEpisode($series_id, $season_id, $episode_id, $title, $air_date) { $air_date = strtotime($air_date); return compact('series_id', 'season_id', 'episode_id', 'title', 'air_date'); } /** * @return array */ protected function getEpisodesData() { return [ $this->newEpisode(1, 1, 1, 'Yesterday\'s Jam', '2006-02-03'), $this->newEpisode(1, 1, 2, 'Calamity Jen', '2006-02-03'), $this->newEpisode(1, 1, 3, 'Fifty-Fifty', '2006-02-10'), $this->newEpisode(1, 1, 4, 'The Red Door', '2006-02-17'), $this->newEpisode(1, 1, 5, 'The Haunting of Bill Crouse', '2006-02-24'), $this->newEpisode(1, 1, 6, 'Aunt Irma Visits', '2006-03-03'), $this->newEpisode(1, 2, 1, 'The Work Outing', '2006-08-24'), $this->newEpisode(1, 2, 2, 'Return of the Golden Child', '2007-08-31'), $this->newEpisode(1, 2, 3, 'Moss and the German', '2007-09-07'), $this->newEpisode(1, 2, 4, 'The Dinner Party', '2007-09-14'), $this->newEpisode(1, 2, 5, 'Smoke and Mirrors', '2007-09-21'), $this->newEpisode(1, 2, 6, 'Men Without Women', '2007-09-28'), $this->newEpisode(1, 3, 1, 'From Hell', '2008-11-21'), $this->newEpisode(1, 3, 2, 'Are We Not Men?', '2008-11-28'), $this->newEpisode(1, 3, 3, 'Tramps Like Us', '2008-12-05'), $this->newEpisode(1, 3, 4, 'The Speech', '2008-12-12'), $this->newEpisode(1, 3, 5, 'Friendface', '2008-12-19'), $this->newEpisode(1, 3, 6, 'Calendar Geeks', '2008-12-26'), $this->newEpisode(1, 4, 1, 'Jen The Fredo', '2010-06-25'), $this->newEpisode(1, 4, 2, 'The Final Countdown', '2010-07-02'), $this->newEpisode(1, 4, 3, 'Something Happened', '2010-07-09'), $this->newEpisode(1, 4, 4, 'Italian For Beginners', '2010-07-16'), $this->newEpisode(1, 4, 5, 'Bad Boys', '2010-07-23'), $this->newEpisode(1, 4, 6, 'Reynholm vs Reynholm', '2010-07-30'), ]; } /** * @return array */ protected function getEpisodesDataForBulkUpsert() { return [ $this->newEpisode(2, 1, 1, 'Minimum Viable Product', '2014-04-06'), $this->newEpisode(2, 1, 2, 'The Cap Table', '2014-04-13'), $this->newEpisode(2, 1, 3, 'Articles of Incorporation', '2014-04-20'), $this->newEpisode(2, 1, 4, 'Fiduciary Duties', '2014-04-27'), $this->newEpisode(2, 1, 5, 'Signaling Risk', '2014-05-04'), $this->newEpisode(2, 1, 6, 'Third Party Insourcing', '2014-05-11'), $this->newEpisode(2, 1, 7, 'Proof of Concept', '2014-05-18'), $this->newEpisode(2, 1, 8, 'Optimal Tip-to-Tip Efficiency', '2014-06-01'), $this->newEpisode(2, 2, 1, 'Sand Hill Shuffle', '2015-04-12'), $this->newEpisode(2, 2, 2, 'Runaway Devaluation', '2015-04-19'), $this->newEpisode(2, 2, 3, 'Bad Money', '2015-04-26'), $this->newEpisode(2, 2, 4, 'The Lady', '2015-05-03'), $this->newEpisode(2, 2, 5, 'Server Space', '2015-05-10'), $this->newEpisode(2, 2, 6, 'Homicide', '2015-05-17'), $this->newEpisode(2, 2, 7, 'Adult Content', '2015-05-24'), $this->newEpisode(2, 2, 8, 'White Hat/Black Hat', '2015-05-31'), $this->newEpisode(2, 2, 9, 'Binding Arbitration', '2015-06-07'), $this->newEpisode(2, 2, 10, 'Two Days of the Condor', '2015-06-14'), $this->newEpisode(2, 3, 1, 'Founder Friendly', '2016-04-24'), $this->newEpisode(2, 3, 2, 'Two in the Box', '2016-05-01'), $this->newEpisode(2, 3, 3, 'Meinertzhagen\'s Haversack', '2016-05-08'), $this->newEpisode(2, 3, 4, 'Maleant Data Systems Solutions', '2016-05-15'), $this->newEpisode(2, 3, 5, 'The Empty Chair', '2016-05-22'), $this->newEpisode(2, 3, 6, 'Bachmanity Insanity', '2016-05-29'), $this->newEpisode(2, 3, 7, 'To Build a Better Beta', '2016-06-05'), $this->newEpisode(2, 3, 8, 'Bachman\'s Earnings Over-Ride', '2016-06-12'), $this->newEpisode(2, 3, 9, 'Daily Active Users', '2016-06-19'), $this->newEpisode(2, 3, 10, 'The Uptick', '2016-06-26'), $this->newEpisode(2, 4, 1, 'Success Failure', '2017-04-23'), $this->newEpisode(2, 4, 2, 'Terms of Service', '2017-04-30'), $this->newEpisode(2, 4, 3, 'Intellectual Property', '2017-05-07'), $this->newEpisode(2, 4, 4, 'Teambuilding Exercise', '2017-05-14'), $this->newEpisode(2, 4, 5, 'The Blood Boy', '2017-05-21'), $this->newEpisode(2, 4, 6, 'Customer Service', '2017-05-28'), $this->newEpisode(2, 4, 7, 'The Patent Troll', '2017-06-04'), $this->newEpisode(2, 4, 8, 'The Keenan Vortex', '2017-06-11'), $this->newEpisode(2, 4, 9, 'Hooli-Con', '2017-06-18'), $this->newEpisode(2, 4, 10, 'Server Error', '2017-06-25'), $this->newEpisode(2, 5, 1, 'Grow Fast or Die Slow', '2018-03-25'), $this->newEpisode(2, 5, 2, 'Reorientation', '2018-04-01'), $this->newEpisode(2, 5, 3, 'Chief Operating Officer', '2018-04-08'), $this->newEpisode(2, 5, 4, 'Tech Evangelist', '2018-04-15'), $this->newEpisode(2, 5, 5, 'Facial Recognition', '2018-04-22'), $this->newEpisode(2, 5, 6, 'Artificial Emotional Intelligence', '2018-04-29'), $this->newEpisode(2, 5, 7, 'Initial Coin Offering', '2018-05-06'), $this->newEpisode(2, 5, 8, 'Fifty-One Percent', '2018-05-13'), ]; } /** * @return string */ protected function getFillDataQuery() { return <<<'EOT' DECLARE $seriesData AS List>; DECLARE $seasonsData AS List>; DECLARE $episodesData AS List>; REPLACE INTO series SELECT series_id, title, series_info, release_date FROM AS_TABLE($seriesData); REPLACE INTO seasons SELECT series_id, season_id, title, first_aired, last_aired FROM AS_TABLE($seasonsData); REPLACE INTO episodes SELECT series_id, season_id, episode_id, title, air_date FROM AS_TABLE($episodesData); EOT; } }