|  | // Copyright 2013 The Flutter Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "impeller/archivist/archive_class_registration.h" | 
|  |  | 
|  | #include <sstream> | 
|  |  | 
|  | #include "impeller/archivist/archive_database.h" | 
|  | #include "impeller/archivist/archive_statement.h" | 
|  | #include "impeller/base/validation.h" | 
|  |  | 
|  | namespace impeller { | 
|  |  | 
|  | static constexpr const char* kArchivePrimaryKeyColumnName = "primary_key"; | 
|  |  | 
|  | ArchiveClassRegistration::ArchiveClassRegistration(ArchiveDatabase& database, | 
|  | ArchiveDef definition) | 
|  | : database_(database), definition_(std::move(definition)) { | 
|  | for (size_t i = 0; i < definition_.members.size(); i++) { | 
|  | // The first index entry is the primary key. So add one to the index. | 
|  | column_map_[definition_.members[i]] = i + 1; | 
|  | } | 
|  | is_valid_ = CreateTable(); | 
|  | } | 
|  |  | 
|  | const std::string& ArchiveClassRegistration::GetClassName() const { | 
|  | return definition_.table_name; | 
|  | } | 
|  |  | 
|  | size_t ArchiveClassRegistration::GetMemberCount() const { | 
|  | return column_map_.size(); | 
|  | } | 
|  |  | 
|  | bool ArchiveClassRegistration::IsValid() const { | 
|  | return is_valid_; | 
|  | } | 
|  |  | 
|  | std::optional<size_t> ArchiveClassRegistration::FindColumnIndex( | 
|  | const std::string& member) const { | 
|  | auto found = column_map_.find(member); | 
|  | if (found == column_map_.end()) { | 
|  | VALIDATION_LOG << "No member named '" << member << "' in class '" | 
|  | << definition_.table_name | 
|  | << "'. Did you forget to register it?"; | 
|  | return std::nullopt; | 
|  | } | 
|  | return found->second; | 
|  | } | 
|  |  | 
|  | bool ArchiveClassRegistration::CreateTable() { | 
|  | if (definition_.table_name.empty() || definition_.members.empty()) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | std::stringstream stream; | 
|  |  | 
|  | /* | 
|  | *  Table names cannot participate in parameter substitution, so we prepare | 
|  | *  a statement and check its validity before running. | 
|  | */ | 
|  | stream << "CREATE TABLE IF NOT EXISTS " << definition_.table_name << " (" | 
|  | << kArchivePrimaryKeyColumnName << " INTEGER PRIMARY KEY, "; | 
|  |  | 
|  | for (size_t i = 0, columns = definition_.members.size(); i < columns; i++) { | 
|  | stream << definition_.members[i]; | 
|  | if (i != columns - 1) { | 
|  | stream << ", "; | 
|  | } | 
|  | } | 
|  | stream << ");"; | 
|  |  | 
|  | auto statement = database_.CreateStatement(stream.str()); | 
|  |  | 
|  | if (!statement.IsValid()) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (!statement.Reset()) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return statement.Execute() == ArchiveStatement::Result::kDone; | 
|  | } | 
|  |  | 
|  | ArchiveStatement ArchiveClassRegistration::CreateQueryStatement( | 
|  | bool single) const { | 
|  | std::stringstream stream; | 
|  | stream << "SELECT " << kArchivePrimaryKeyColumnName << ", "; | 
|  | for (size_t i = 0, columns = definition_.members.size(); i < columns; i++) { | 
|  | stream << definition_.members[i]; | 
|  | if (i != columns - 1) { | 
|  | stream << ","; | 
|  | } | 
|  | } | 
|  | stream << " FROM " << definition_.table_name; | 
|  |  | 
|  | if (single) { | 
|  | stream << " WHERE " << kArchivePrimaryKeyColumnName << " = ?"; | 
|  | } else { | 
|  | stream << " ORDER BY  " << kArchivePrimaryKeyColumnName << " ASC"; | 
|  | } | 
|  |  | 
|  | stream << ";"; | 
|  |  | 
|  | return database_.CreateStatement(stream.str()); | 
|  | } | 
|  |  | 
|  | ArchiveStatement ArchiveClassRegistration::CreateInsertStatement() const { | 
|  | std::stringstream stream; | 
|  | stream << "INSERT OR REPLACE INTO " << definition_.table_name | 
|  | << " VALUES ( ?, "; | 
|  | for (size_t i = 0, columns = definition_.members.size(); i < columns; i++) { | 
|  | stream << "?"; | 
|  | if (i != columns - 1) { | 
|  | stream << ", "; | 
|  | } | 
|  | } | 
|  | stream << ");"; | 
|  |  | 
|  | return database_.CreateStatement(stream.str()); | 
|  | } | 
|  |  | 
|  | }  // namespace impeller |