backend/query/queryable_property_graph.h (372 lines of code) (raw):

// // Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_QUERY_QUERYABLE_PROPERTY_GRAPH_H_ #define THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_QUERY_QUERYABLE_PROPERTY_GRAPH_H_ #include <memory> #include <string> #include <vector> #include "zetasql/public/analyzer_output.h" #include "zetasql/public/catalog.h" #include "zetasql/public/property_graph.h" #include "zetasql/public/types/type.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "backend/common/case.h" #include "backend/schema/catalog/property_graph.h" namespace google { namespace spanner { namespace emulator { namespace backend { // Forward declarations class QueryablePropertyGraph; class QueryableGraphElementTable; class QueryableGraphNodeTable; class QueryableGraphEdgeTable; class QueryableGraphElementLabel; class QueryableGraphNodeTableReference; class QueryableGraphPropertyDeclaration; class QueryableGraphPropertyDefinition; class QueryableGraphPropertyDeclaration : public zetasql::GraphPropertyDeclaration { public: explicit QueryableGraphPropertyDeclaration( const QueryablePropertyGraph* property_graph, zetasql::Catalog* catalog, zetasql::TypeFactory* type_factory, const google::spanner::emulator::backend::PropertyGraph:: PropertyDeclaration* wrapped_property_declaration); std::string FullName() const override; std::string Name() const override { return wrapped_property_declaration_->name; } const zetasql::Type* Type() const override { return type_; } private: const QueryablePropertyGraph* const property_graph_; const google::spanner::emulator::backend::PropertyGraph:: PropertyDeclaration* const wrapped_property_declaration_; const zetasql::Type* type_; }; class QueryableGraphPropertyDefinition : public zetasql::GraphPropertyDefinition { public: QueryableGraphPropertyDefinition( zetasql::Catalog* catalog, zetasql::TypeFactory* type_factory, const zetasql::Table* data_source_table, const zetasql::GraphPropertyDeclaration* property_declaration, const google::spanner::emulator::backend::PropertyGraph:: GraphElementTable::PropertyDefinition* wrapped_property_definition); const zetasql::GraphPropertyDeclaration& GetDeclaration() const override { return *property_declaration_; } absl::string_view expression_sql() const override { return wrapped_property_definition_->value_expression_string; } absl::StatusOr<const zetasql::ResolvedExpr*> GetValueExpression() const override { return analyzer_output_->resolved_expr(); } private: const zetasql::GraphPropertyDeclaration* property_declaration_; const google::spanner::emulator::backend::PropertyGraph::GraphElementTable:: PropertyDefinition* const wrapped_property_definition_; std::unique_ptr<const zetasql::AnalyzerOutput> analyzer_output_; }; class QueryableGraphElementLabel : public zetasql::GraphElementLabel { public: QueryableGraphElementLabel( const QueryablePropertyGraph* property_graph, const google::spanner::emulator::backend::PropertyGraph::Label* label) : property_graph_(property_graph), label_(label) {} std::string FullName() const override; std::string Name() const override { return label_->name; } absl::Status GetPropertyDeclarations( absl::flat_hash_set<const zetasql::GraphPropertyDeclaration*>& output) const override; private: const QueryablePropertyGraph* const property_graph_; const google::spanner::emulator::backend::PropertyGraph::Label* const label_; }; class QueryableGraphElementTableInternal { public: QueryableGraphElementTableInternal( zetasql::Catalog* catalog, zetasql::TypeFactory* type_factory, const QueryablePropertyGraph* property_graph, const google::spanner::emulator::backend::PropertyGraph:: GraphElementTable* element_table); std::string Name() const { return wrapped_element_table_->name(); } absl::Span<const std::string> PropertyGraphNamePath() const; std::string FullName() const; const zetasql::Table* GetTable() const; const std::vector<int>& GetKeyColumns() const { return ordinal_key_columns_idxs_; } absl::Status FindPropertyDefinitionByName( absl::string_view property_name, const zetasql::GraphPropertyDefinition*& property_definition) const; absl::Status GetPropertyDefinitions( absl::flat_hash_set<const zetasql::GraphPropertyDefinition*>& output) const; absl::Status FindLabelByName( absl::string_view name, const zetasql::GraphElementLabel*& label) const; absl::Status GetLabels( absl::flat_hash_set<const zetasql::GraphElementLabel*>& output) const; protected: const QueryablePropertyGraph* const property_graph_; const google::spanner::emulator::backend::PropertyGraph:: GraphElementTable* const wrapped_element_table_; const zetasql::Table* data_source_table_; // Pointers to the labels applicable to this element table. // Labels are owned by the 'QueryablePropertyGraph'. CaseInsensitiveStringMap<const zetasql::GraphElementLabel*> label_ptrs_; std::vector<int> ordinal_key_columns_idxs_; CaseInsensitiveStringMap< std::unique_ptr<const QueryableGraphPropertyDefinition>> property_definitions_; }; class QueryableGraphNodeTable : public zetasql::GraphNodeTable { public: QueryableGraphNodeTable(zetasql::Catalog* catalog, zetasql::TypeFactory* type_factory, const QueryablePropertyGraph* property_graph, const google::spanner::emulator::backend:: PropertyGraph::GraphElementTable* node_table); Kind kind() const override { return Kind::kNode; } std::string Name() const override { return element_table_internals_->Name(); } absl::Span<const std::string> PropertyGraphNamePath() const override { return element_table_internals_->PropertyGraphNamePath(); }; std::string FullName() const override { return element_table_internals_->FullName(); }; const zetasql::Table* GetTable() const override { return element_table_internals_->GetTable(); } const std::vector<int>& GetKeyColumns() const override { return element_table_internals_->GetKeyColumns(); } absl::Status FindPropertyDefinitionByName( absl::string_view property_name, const zetasql::GraphPropertyDefinition*& property_definition) const override { return element_table_internals_->FindPropertyDefinitionByName( property_name, property_definition); } absl::Status GetPropertyDefinitions( absl::flat_hash_set<const zetasql::GraphPropertyDefinition*>& output) const override { return element_table_internals_->GetPropertyDefinitions(output); } absl::Status FindLabelByName( absl::string_view name, const zetasql::GraphElementLabel*& label) const override { return element_table_internals_->FindLabelByName(name, label); } absl::Status GetLabels( absl::flat_hash_set<const zetasql::GraphElementLabel*>& output) const override { return element_table_internals_->GetLabels(output); } private: std::unique_ptr<QueryableGraphElementTableInternal> element_table_internals_; }; class QueryableGraphNodeTableReference : public zetasql::GraphNodeTableReference { public: QueryableGraphNodeTableReference( zetasql::Catalog* catalog, const QueryablePropertyGraph* property_graph, const google::spanner::emulator::backend::PropertyGraph:: GraphElementTable::GraphNodeReference* wrapped_node_reference, const google::spanner::emulator::backend::PropertyGraph:: GraphElementTable* wrapped_edge_table); const zetasql::GraphNodeTable* GetReferencedNodeTable() const override; const std::vector<int>& GetEdgeTableColumns() const override { return edge_table_column_idxs_; } const std::vector<int>& GetNodeTableColumns() const override { return node_table_column_idxs_; } private: const QueryablePropertyGraph* const property_graph_; const google::spanner::emulator::backend::PropertyGraph::GraphElementTable:: GraphNodeReference* const wrapped_node_reference_; std::vector<int> node_table_column_idxs_; std::vector<int> edge_table_column_idxs_; }; class QueryableGraphEdgeTable : public zetasql::GraphEdgeTable { public: QueryableGraphEdgeTable(zetasql::Catalog* catalog, zetasql::TypeFactory* type_factory, const QueryablePropertyGraph* property_graph, const google::spanner::emulator::backend:: PropertyGraph::GraphElementTable* edge_table); Kind kind() const override { return Kind::kEdge; } std::string Name() const override { return element_table_internals_->Name(); } absl::Span<const std::string> PropertyGraphNamePath() const override { return element_table_internals_->PropertyGraphNamePath(); }; std::string FullName() const override { return element_table_internals_->FullName(); }; const zetasql::Table* GetTable() const override { return element_table_internals_->GetTable(); } const std::vector<int>& GetKeyColumns() const override { return element_table_internals_->GetKeyColumns(); } absl::Status FindPropertyDefinitionByName( absl::string_view property_name, const zetasql::GraphPropertyDefinition*& property_definition) const override { return element_table_internals_->FindPropertyDefinitionByName( property_name, property_definition); } absl::Status GetPropertyDefinitions( absl::flat_hash_set<const zetasql::GraphPropertyDefinition*>& output) const override { return element_table_internals_->GetPropertyDefinitions(output); } absl::Status FindLabelByName( absl::string_view name, const zetasql::GraphElementLabel*& label) const override { return element_table_internals_->FindLabelByName(name, label); } absl::Status GetLabels( absl::flat_hash_set<const zetasql::GraphElementLabel*>& output) const override { return element_table_internals_->GetLabels(output); } const zetasql::GraphNodeTableReference* GetSourceNodeTable() const override { return source_node_table_reference_.get(); } const zetasql::GraphNodeTableReference* GetDestNodeTable() const override { return target_node_table_reference_.get(); } private: std::unique_ptr<QueryableGraphElementTableInternal> element_table_internals_; std::unique_ptr<QueryableGraphNodeTableReference> source_node_table_reference_; std::unique_ptr<QueryableGraphNodeTableReference> target_node_table_reference_; }; class QueryablePropertyGraph : public zetasql::PropertyGraph { public: QueryablePropertyGraph( zetasql::Catalog* catalog, zetasql::TypeFactory* type_factory, const google::spanner::emulator::backend::PropertyGraph* wrapped_property_graph) : wrapped_property_graph_(wrapped_property_graph) { for (const auto& label : wrapped_property_graph->Labels()) { labels_[label.name] = std::make_unique<QueryableGraphElementLabel>(this, &label); } for (const auto& property_decl : wrapped_property_graph->PropertyDeclarations()) { property_declarations_[property_decl.name] = std::make_unique<QueryableGraphPropertyDeclaration>( this, catalog, type_factory, &property_decl); } for (const auto& node_table : wrapped_property_graph->NodeTables()) { node_tables_[node_table.name()] = std::make_unique<QueryableGraphNodeTable>(catalog, type_factory, this, &node_table); } for (const auto& edge_table : wrapped_property_graph_->EdgeTables()) { edge_tables_[edge_table.name()] = std::make_unique<QueryableGraphEdgeTable>(catalog, type_factory, this, &edge_table); } } zetasql::Catalog* catalog() const { return catalog_; } std::string Name() const override { return wrapped_property_graph_->Name(); } absl::Span<const std::string> NamePath() const override { // TODO: Support full graph name path after spanner supports it return {&wrapped_property_graph_->Name(), 1}; } std::string FullName() const override { return Name(); } absl::Status FindLabelByName( absl::string_view name, const zetasql::GraphElementLabel*& label) const override { auto it = labels_.find(std::string(name)); if (it == labels_.end()) { return absl::NotFoundError(absl::StrCat("Label not found: ", name)); } label = it->second.get(); return absl::OkStatus(); } absl::Status FindPropertyDeclarationByName( absl::string_view name, const zetasql::GraphPropertyDeclaration*& property_declaration) const override { auto it = property_declarations_.find(std::string(name)); if (it == property_declarations_.end()) { return absl::NotFoundError( absl::StrCat("Property declaration not found: ", name)); } property_declaration = it->second.get(); return absl::OkStatus(); } absl::Status FindElementTableByName( absl::string_view name, const zetasql::GraphElementTable*& element_table) const override { auto node_it = node_tables_.find(std::string(name)); if (node_it != node_tables_.end()) { element_table = node_it->second.get(); return absl::OkStatus(); } auto edge_it = edge_tables_.find(std::string(name)); if (edge_it != edge_tables_.end()) { element_table = edge_it->second.get(); return absl::OkStatus(); } return absl::NotFoundError(absl::StrCat("Element table not found: ", name)); } absl::Status GetNodeTables( absl::flat_hash_set<const zetasql::GraphNodeTable*>& output) const override { for (const auto& [_, node_table] : node_tables_) { output.insert(node_table.get()); } return absl::OkStatus(); } absl::Status GetEdgeTables( absl::flat_hash_set<const zetasql::GraphEdgeTable*>& output) const override { for (const auto& [_, edge_table] : edge_tables_) { output.insert(edge_table.get()); } return absl::OkStatus(); } absl::Status GetLabels( absl::flat_hash_set<const zetasql::GraphElementLabel*>& output) const override { for (const auto& [_, label] : labels_) { output.insert(label.get()); } return absl::OkStatus(); } absl::Status GetPropertyDeclarations( absl::flat_hash_set<const zetasql::GraphPropertyDeclaration*>& output) const override { for (const auto& [_, property_declaration] : property_declarations_) { output.insert(property_declaration.get()); } return absl::OkStatus(); } private: // The catalog to which this property graph belongs. Not owned. zetasql::Catalog* catalog_; const google::spanner::emulator::backend::PropertyGraph* const wrapped_property_graph_; CaseInsensitiveStringMap<std::unique_ptr<const QueryableGraphElementLabel>> labels_; CaseInsensitiveStringMap< std::unique_ptr<const QueryableGraphPropertyDeclaration>> property_declarations_; CaseInsensitiveStringMap<std::unique_ptr<const QueryableGraphNodeTable>> node_tables_; CaseInsensitiveStringMap<std::unique_ptr<const QueryableGraphEdgeTable>> edge_tables_; }; } // namespace backend } // namespace emulator } // namespace spanner } // namespace google #endif // THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_QUERY_QUERYABLE_PROPERTY_GRAPH_H_