db = $storage->getPdo(); parent::__construct(); } protected function configure(): void { $this->setName(self::ROUTE) ->setDescription('Ensure database has correct indexes.') ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Do not commit changes.') ->addOption('force-reindex', 'f', InputOption::VALUE_NONE, 'Drop existing indexes, and re-create them.') ->setHelp( <<getOption('dry-run'); $queries = []; $drop = 'DROP INDEX IF EXISTS "${name}"'; $insert = 'CREATE INDEX IF NOT EXISTS "${name}" ON "state" (${expr});'; $startedTransaction = false; if (!$inDryRunMode && !$this->db->inTransaction()) { $startedTransaction = true; $this->db->beginTransaction(); } if ($input->getOption('force-reindex')) { $this->logger->debug('Force reindex is called.'); $sql = "select name FROM sqlite_master WHERE tbl_name = 'state' AND type = 'index';"; foreach ($this->db->query($sql) as $row) { $name = ag($row, 'name'); $query = replacer($drop, ['name' => $name], '${', '}'); $this->logger->debug('Dropping Index [%(index)].', [ 'index' => $name, 'query' => $query, ]); $queries[] = $query; } } foreach (iState::ENTITY_KEYS as $column) { if (true === in_array($column, self::INDEX_IGNORE_ON)) { continue; } $query = replacer($insert, [ 'name' => sprintf('state_%s', $column), 'expr' => sprintf('"%s"', $column), ], '${', '}'); $this->logger->debug('Generating index on [%(column)].', [ 'column' => $column, 'query' => $query, ]); $queries[] = $query; } // -- Ensure main parent/guids sub keys are indexed. foreach (array_keys(Guid::getSupported()) as $subKey) { foreach ([iState::COLUMN_PARENT, iState::COLUMN_GUIDS] as $column) { $query = replacer($insert, [ 'name' => sprintf('state_%s_%s', $column, $subKey), 'expr' => sprintf("JSON_EXTRACT(%s,'$.%s')", $column, $subKey), ], '${', '}'); $this->logger->debug('Generating index on %(column) column [%(key)] key.', [ 'column' => $column, 'key' => $subKey, 'query' => $query, ]); $queries[] = $query; } } // -- Ensure backends metadata.id,metadata.show are indexed foreach (array_keys(Config::get('servers', [])) as $backend) { foreach (self::BACKEND_INDEXES as $subKey) { $query = replacer($insert, [ 'name' => sprintf('state_%s_%s_%s', iState::COLUMN_META_DATA, $backend, $subKey), 'expr' => sprintf("JSON_EXTRACT(%s,'$.%s.%s')", iState::COLUMN_META_DATA, $backend, $subKey), ], '${', '}'); $this->logger->debug('Generating index on [%(backend)] metadata column [%(key)] key.', [ 'backend' => $backend, 'key' => $subKey, 'query' => $query, ]); $queries[] = $query; } } if (false === $inDryRunMode) { foreach ($queries as $query) { $this->logger->debug('Running query.', [ 'query' => $query, 'start' => makeDate(), ]); $this->db->query($query); } if ($startedTransaction && $this->db->inTransaction()) { $this->db->commit(); } if ($input->getOption('force-reindex')) { $this->db->query('VACUUM;'); } } return self::SUCCESS; } }