From b4df1725676a2edc5fc788e36edfeeab692e687d Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 29 Mar 2026 01:00:45 -0500 Subject: [PATCH 01/10] feat: add v2 entity system with Postgres-native search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New entity system built as an independent package alongside the existing asset system. Zero changes to existing asset code. All search is Postgres-native — no Elasticsearch dependency for v2. Core domain (core/entity/): - Entity: open type system, temporal (valid_from/valid_to), properties JSONB - Edge: typed, directed, temporal relationships - Chunk: pgvector embeddings for semantic search - Service: context assembly, impact analysis, search orchestration - HybridSearch: keyword + semantic fusion via Reciprocal Rank Fusion - SearchRepository: Postgres tsvector + pg_trgm (replaces ES) Storage (store/postgres/): - EntityRepository: CRUD with temporal support - EdgeRepository: recursive CTE graph traversal - ChunkRepository: pgvector cosine similarity search - EntitySearchRepository: tsvector full-text + pg_trgm fuzzy matching - Migration 000019: entities, edges, chunks tables with search_vector generated column, GIN indexes, trigram indexes Search architecture (all Postgres): - Keyword: tsvector with weighted fields (URN/name=A, desc=B, source=C) - Fuzzy: pg_trgm similarity with automatic fallback - Semantic: pgvector cosine distance on chunk embeddings - Hybrid: RRF fusion of keyword + semantic results - Suggest: pg_trgm similarity-based autocomplete MCP tools (internal/mcp/): - search_entities: hybrid search across the entity graph - get_context: assembled context subgraph - impact: downstream blast radius analysis --- core/entity/chunk.go | 30 +++ core/entity/edge.go | 39 +++ core/entity/entity.go | 69 +++++ core/entity/search.go | 165 ++++++++++++ core/entity/service.go | 157 ++++++++++++ internal/mcp/entity_handlers.go | 163 ++++++++++++ internal/mcp/entity_tools.go | 53 ++++ internal/mcp/server.go | 38 ++- internal/server/bootstrap.go | 23 +- store/postgres/chunk_repository.go | 128 ++++++++++ store/postgres/edge_repository.go | 177 +++++++++++++ store/postgres/entity_repository.go | 236 ++++++++++++++++++ store/postgres/entity_search_repository.go | 167 +++++++++++++ .../000019_create_entity_tables.down.sql | 3 + .../000019_create_entity_tables.up.sql | 98 ++++++++ 15 files changed, 1538 insertions(+), 8 deletions(-) create mode 100644 core/entity/chunk.go create mode 100644 core/entity/edge.go create mode 100644 core/entity/entity.go create mode 100644 core/entity/search.go create mode 100644 core/entity/service.go create mode 100644 internal/mcp/entity_handlers.go create mode 100644 internal/mcp/entity_tools.go create mode 100644 store/postgres/chunk_repository.go create mode 100644 store/postgres/edge_repository.go create mode 100644 store/postgres/entity_repository.go create mode 100644 store/postgres/entity_search_repository.go create mode 100644 store/postgres/migrations/000019_create_entity_tables.down.sql create mode 100644 store/postgres/migrations/000019_create_entity_tables.up.sql diff --git a/core/entity/chunk.go b/core/entity/chunk.go new file mode 100644 index 00000000..bb1f0929 --- /dev/null +++ b/core/entity/chunk.go @@ -0,0 +1,30 @@ +package entity + +import ( + "context" + "time" + + "github.com/raystack/compass/core/namespace" +) + +// Chunk is a text fragment with a vector embedding for semantic search. +// Derived from entities — an indexing mechanism, not knowledge. +type Chunk struct { + ID string `json:"id"` + NamespaceID string `json:"namespace_id"` + EntityURN string `json:"entity_urn"` + Content string `json:"content"` + Context string `json:"context"` + Embedding []float32 `json:"embedding,omitempty"` + Position int `json:"position"` + Heading string `json:"heading,omitempty"` + TokenCount int `json:"token_count"` + CreatedAt time.Time `json:"created_at"` +} + +// ChunkRepository defines storage operations for the chunk index. +type ChunkRepository interface { + UpsertBatch(ctx context.Context, ns *namespace.Namespace, chunks []Chunk) error + DeleteByEntityURN(ctx context.Context, ns *namespace.Namespace, entityURN string) error + Search(ctx context.Context, ns *namespace.Namespace, embedding []float32, limit int) ([]Chunk, error) +} diff --git a/core/entity/edge.go b/core/entity/edge.go new file mode 100644 index 00000000..eff7aec0 --- /dev/null +++ b/core/entity/edge.go @@ -0,0 +1,39 @@ +package entity + +import ( + "context" + "time" + + "github.com/raystack/compass/core/namespace" +) + +// Edge is a typed, directed, temporal relationship between two entities. +type Edge struct { + ID string `json:"id"` + NamespaceID string `json:"namespace_id"` + SourceURN string `json:"source_urn"` + TargetURN string `json:"target_urn"` + Type string `json:"type"` + Properties map[string]interface{} `json:"properties,omitempty"` + ValidFrom time.Time `json:"valid_from"` + ValidTo *time.Time `json:"valid_to,omitempty"` + Source string `json:"source,omitempty"` + CreatedAt time.Time `json:"created_at"` +} + +// EdgeFilter for querying edges. +type EdgeFilter struct { + Types []string + Current bool // only current edges (valid_to IS NULL) +} + +// EdgeRepository defines storage operations for edges. +type EdgeRepository interface { + Upsert(ctx context.Context, ns *namespace.Namespace, e *Edge) error + GetBySource(ctx context.Context, ns *namespace.Namespace, urn string, filter EdgeFilter) ([]Edge, error) + GetByTarget(ctx context.Context, ns *namespace.Namespace, urn string, filter EdgeFilter) ([]Edge, error) + GetDownstream(ctx context.Context, ns *namespace.Namespace, urn string, depth int) ([]Edge, error) + GetUpstream(ctx context.Context, ns *namespace.Namespace, urn string, depth int) ([]Edge, error) + Delete(ctx context.Context, ns *namespace.Namespace, sourceURN, targetURN, edgeType string) error + DeleteByURN(ctx context.Context, ns *namespace.Namespace, urn string) error +} diff --git a/core/entity/entity.go b/core/entity/entity.go new file mode 100644 index 00000000..47091249 --- /dev/null +++ b/core/entity/entity.go @@ -0,0 +1,69 @@ +package entity + +import ( + "context" + "time" + + "github.com/raystack/compass/core/namespace" +) + +// Type is an open type system — any non-empty string is valid. +type Type string + +func (t Type) String() string { return string(t) } + +func (t Type) IsValid() bool { return t != "" } + +// Well-known types for convenience. Not an exhaustive list. +const ( + TypeTable Type = "table" + TypeJob Type = "job" + TypeDashboard Type = "dashboard" + TypeTopic Type = "topic" + TypeFeatureTable Type = "feature_table" + TypeApplication Type = "application" + TypeModel Type = "model" + TypeQuery Type = "query" + TypeMetric Type = "metric" + TypeExperiment Type = "experiment" +) + +// Entity is the core domain object — anything worth naming in the +// organization's knowledge graph. +type Entity struct { + ID string `json:"id"` + NamespaceID string `json:"namespace_id"` + URN string `json:"urn"` + Type Type `json:"type"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + Properties map[string]interface{} `json:"properties,omitempty"` + Source string `json:"source,omitempty"` + ValidFrom time.Time `json:"valid_from"` + ValidTo *time.Time `json:"valid_to,omitempty"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// IsCurrent returns true if this entity represents current state. +func (e Entity) IsCurrent() bool { return e.ValidTo == nil } + +// Repository defines storage operations for entities. +type Repository interface { + Upsert(ctx context.Context, ns *namespace.Namespace, ent *Entity) (string, error) + GetByURN(ctx context.Context, ns *namespace.Namespace, urn string) (Entity, error) + GetByID(ctx context.Context, id string) (Entity, error) + GetAll(ctx context.Context, ns *namespace.Namespace, filter Filter) ([]Entity, error) + GetCount(ctx context.Context, ns *namespace.Namespace, filter Filter) (int, error) + GetTypes(ctx context.Context, ns *namespace.Namespace) (map[Type]int, error) + Delete(ctx context.Context, ns *namespace.Namespace, urn string) error +} + +// Filter for querying entities. +type Filter struct { + Types []Type + Source string + Size int + Offset int + Query string +} diff --git a/core/entity/search.go b/core/entity/search.go new file mode 100644 index 00000000..9be28dd0 --- /dev/null +++ b/core/entity/search.go @@ -0,0 +1,165 @@ +package entity + +import ( + "context" + "sort" + + "github.com/raystack/compass/core/namespace" +) + +// SearchMode specifies which search backend(s) to use. +type SearchMode string + +const ( + SearchModeKeyword SearchMode = "keyword" // Postgres tsvector + pg_trgm + SearchModeSemantic SearchMode = "semantic" // pgvector cosine similarity + SearchModeHybrid SearchMode = "hybrid" // both, fused with RRF +) + +// SearchConfig for entity search. +type SearchConfig struct { + Text string + Filters map[string][]string + MaxResults int + Offset int + Mode SearchMode + Namespace *namespace.Namespace +} + +// SearchResult represents a single search hit. +type SearchResult struct { + ID string `json:"id"` + URN string `json:"urn"` + Type string `json:"type"` + Name string `json:"name"` + Source string `json:"source"` + Description string `json:"description"` + Rank float64 `json:"rank,omitempty"` +} + +// SearchRepository defines search operations for entities. +// All implementations are Postgres-native (no ES dependency). +type SearchRepository interface { + // Search performs keyword search using tsvector ranking + pg_trgm fuzzy matching. + Search(ctx context.Context, cfg SearchConfig) ([]SearchResult, error) + // Suggest returns name completions using pg_trgm similarity. + Suggest(ctx context.Context, ns *namespace.Namespace, text string, limit int) ([]string, error) +} + +// EmbeddingFunc generates vector embeddings from text. +type EmbeddingFunc func(ctx context.Context, text string) ([]float32, error) + +// HybridSearch fuses keyword (Postgres) + semantic (pgvector) results using RRF. +type HybridSearch struct { + search SearchRepository + chunks ChunkRepository + embedFn EmbeddingFunc +} + +func NewHybridSearch(search SearchRepository, chunks ChunkRepository, embedFn EmbeddingFunc) *HybridSearch { + return &HybridSearch{search: search, chunks: chunks, embedFn: embedFn} +} + +func (h *HybridSearch) Search(ctx context.Context, cfg SearchConfig) ([]SearchResult, error) { + switch cfg.Mode { + case SearchModeSemantic: + return h.semanticSearch(ctx, cfg) + case SearchModeHybrid: + return h.hybridSearch(ctx, cfg) + default: + return h.search.Search(ctx, cfg) + } +} + +func (h *HybridSearch) semanticSearch(ctx context.Context, cfg SearchConfig) ([]SearchResult, error) { + if h.embedFn == nil || h.chunks == nil { + return h.search.Search(ctx, cfg) + } + + embedding, err := h.embedFn(ctx, cfg.Text) + if err != nil { + return nil, err + } + + limit := cfg.MaxResults + if limit <= 0 { + limit = 10 + } + + chunks, err := h.chunks.Search(ctx, cfg.Namespace, embedding, limit) + if err != nil { + return nil, err + } + + seen := make(map[string]bool) + var results []SearchResult + for _, c := range chunks { + if seen[c.EntityURN] { + continue + } + seen[c.EntityURN] = true + results = append(results, SearchResult{URN: c.EntityURN, Description: c.Content}) + } + return results, nil +} + +func (h *HybridSearch) hybridSearch(ctx context.Context, cfg SearchConfig) ([]SearchResult, error) { + keywordResults, err := h.search.Search(ctx, cfg) + if err != nil { + return nil, err + } + + semanticResults, err := h.semanticSearch(ctx, cfg) + if err != nil { + return keywordResults, nil // degrade gracefully + } + + fused := reciprocalRankFusion(keywordResults, semanticResults) + + limit := cfg.MaxResults + if limit <= 0 { + limit = 10 + } + if len(fused) > limit { + fused = fused[:limit] + } + return fused, nil +} + +// reciprocalRankFusion merges ranked lists. RRF score = Σ(1 / (k + rank)). +func reciprocalRankFusion(lists ...[]SearchResult) []SearchResult { + const k = 60.0 + + type scored struct { + result SearchResult + score float64 + } + + scores := make(map[string]*scored) + for _, list := range lists { + for rank, r := range list { + key := r.URN + if key == "" { + key = r.ID + } + s, ok := scores[key] + if !ok { + s = &scored{result: r} + scores[key] = s + } + s.score += 1.0 / (k + float64(rank+1)) + } + } + + all := make([]scored, 0, len(scores)) + for _, s := range scores { + all = append(all, *s) + } + sort.Slice(all, func(i, j int) bool { return all[i].score > all[j].score }) + + results := make([]SearchResult, len(all)) + for i, s := range all { + results[i] = s.result + } + return results +} diff --git a/core/entity/service.go b/core/entity/service.go new file mode 100644 index 00000000..cd33f78e --- /dev/null +++ b/core/entity/service.go @@ -0,0 +1,157 @@ +package entity + +import ( + "context" + "fmt" + + "github.com/raystack/compass/core/namespace" +) + +// Service orchestrates entity operations across repositories. +type Service struct { + repo Repository + edges EdgeRepository + search SearchRepository + hybrid *HybridSearch +} + +func NewService(repo Repository, edges EdgeRepository, search SearchRepository) *Service { + return &Service{repo: repo, edges: edges, search: search} +} + +// WithHybridSearch enables semantic/hybrid search modes. +func (s *Service) WithHybridSearch(hs *HybridSearch) { + s.hybrid = hs +} + +func (s *Service) Upsert(ctx context.Context, ns *namespace.Namespace, ent *Entity) (string, error) { + id, err := s.repo.Upsert(ctx, ns, ent) + if err != nil { + return "", fmt.Errorf("upsert entity: %w", err) + } + ent.ID = id + return id, nil +} + +func (s *Service) UpsertWithEdges(ctx context.Context, ns *namespace.Namespace, ent *Entity, upstreams, downstreams []string) (string, error) { + id, err := s.Upsert(ctx, ns, ent) + if err != nil { + return "", err + } + + if s.edges != nil { + for _, us := range upstreams { + _ = s.edges.Upsert(ctx, ns, &Edge{SourceURN: us, TargetURN: ent.URN, Type: "lineage", Properties: map[string]interface{}{"root": ent.URN}}) + } + for _, ds := range downstreams { + _ = s.edges.Upsert(ctx, ns, &Edge{SourceURN: ent.URN, TargetURN: ds, Type: "lineage", Properties: map[string]interface{}{"root": ent.URN}}) + } + } + + return id, nil +} + +func (s *Service) GetByURN(ctx context.Context, ns *namespace.Namespace, urn string) (Entity, error) { + return s.repo.GetByURN(ctx, ns, urn) +} + +func (s *Service) GetByID(ctx context.Context, id string) (Entity, error) { + return s.repo.GetByID(ctx, id) +} + +func (s *Service) GetAll(ctx context.Context, ns *namespace.Namespace, flt Filter) ([]Entity, int, error) { + entities, err := s.repo.GetAll(ctx, ns, flt) + if err != nil { + return nil, 0, err + } + count, err := s.repo.GetCount(ctx, ns, flt) + if err != nil { + return entities, 0, nil + } + return entities, count, nil +} + +func (s *Service) GetTypes(ctx context.Context, ns *namespace.Namespace) (map[Type]int, error) { + return s.repo.GetTypes(ctx, ns) +} + +func (s *Service) Delete(ctx context.Context, ns *namespace.Namespace, urn string) error { + if err := s.repo.Delete(ctx, ns, urn); err != nil { + return fmt.Errorf("delete entity: %w", err) + } + if s.edges != nil { + _ = s.edges.DeleteByURN(ctx, ns, urn) + } + return nil +} + +func (s *Service) Search(ctx context.Context, cfg SearchConfig) ([]SearchResult, error) { + if s.hybrid != nil && (cfg.Mode == SearchModeSemantic || cfg.Mode == SearchModeHybrid) { + return s.hybrid.Search(ctx, cfg) + } + if s.search != nil { + return s.search.Search(ctx, cfg) + } + return nil, nil +} + +func (s *Service) Suggest(ctx context.Context, ns *namespace.Namespace, text string, limit int) ([]string, error) { + if s.search != nil { + return s.search.Suggest(ctx, ns, text, limit) + } + return nil, nil +} + +// GetContext assembles a context subgraph around an entity. +func (s *Service) GetContext(ctx context.Context, ns *namespace.Namespace, urn string, depth int) (*ContextGraph, error) { + ent, err := s.repo.GetByURN(ctx, ns, urn) + if err != nil { + return nil, fmt.Errorf("get entity: %w", err) + } + + cg := &ContextGraph{Entity: ent} + + if s.edges != nil { + if depth <= 0 { + depth = 2 + } + outgoing, _ := s.edges.GetBySource(ctx, ns, urn, EdgeFilter{Current: true}) + incoming, _ := s.edges.GetByTarget(ctx, ns, urn, EdgeFilter{Current: true}) + cg.Edges = append(outgoing, incoming...) + + seen := map[string]bool{urn: true} + for _, e := range cg.Edges { + relURN := e.TargetURN + if relURN == urn { + relURN = e.SourceURN + } + if seen[relURN] { + continue + } + seen[relURN] = true + if rel, err := s.repo.GetByURN(ctx, ns, relURN); err == nil { + cg.Related = append(cg.Related, rel) + } + } + } + + return cg, nil +} + +// GetImpact returns downstream entities affected by changes to the given entity. +func (s *Service) GetImpact(ctx context.Context, ns *namespace.Namespace, urn string, depth int) ([]Edge, error) { + if s.edges == nil { + return nil, nil + } + if depth <= 0 { + depth = 3 + } + return s.edges.GetDownstream(ctx, ns, urn, depth) +} + +// ContextGraph is the assembled context subgraph for an entity. +type ContextGraph struct { + Entity Entity `json:"entity"` + Edges []Edge `json:"edges,omitempty"` + Related []Entity `json:"related,omitempty"` +} diff --git a/internal/mcp/entity_handlers.go b/internal/mcp/entity_handlers.go new file mode 100644 index 00000000..a44f3c19 --- /dev/null +++ b/internal/mcp/entity_handlers.go @@ -0,0 +1,163 @@ +package mcp + +import ( + "context" + "fmt" + "strings" + + gomcp "github.com/mark3labs/mcp-go/mcp" + "github.com/raystack/compass/core/entity" +) + +func (s *Server) handleSearchEntities(ctx context.Context, req gomcp.CallToolRequest) (*gomcp.CallToolResult, error) { + if s.entityService == nil { + return gomcp.NewToolResultError("entity service not configured"), nil + } + + text := gomcp.ParseString(req, "text", "") + if text == "" { + return gomcp.NewToolResultError("'text' parameter is required"), nil + } + + size := gomcp.ParseInt(req, "size", 10) + mode := entity.SearchMode(gomcp.ParseString(req, "mode", "keyword")) + + cfg := entity.SearchConfig{ + Text: strings.TrimSpace(text), + MaxResults: size, + Mode: mode, + Namespace: s.namespace, + } + + if types := gomcp.ParseString(req, "types", ""); types != "" { + cfg.Filters = map[string][]string{"type": strings.Split(types, ",")} + } + if source := gomcp.ParseString(req, "source", ""); source != "" { + if cfg.Filters == nil { + cfg.Filters = make(map[string][]string) + } + cfg.Filters["source"] = []string{source} + } + + results, err := s.entityService.Search(ctx, cfg) + if err != nil { + return gomcp.NewToolResultError("search failed: " + err.Error()), nil + } + + return gomcp.NewToolResultText(formatEntitySearchResults(results)), nil +} + +func (s *Server) handleGetContext(ctx context.Context, req gomcp.CallToolRequest) (*gomcp.CallToolResult, error) { + if s.entityService == nil { + return gomcp.NewToolResultError("entity service not configured"), nil + } + + urn := gomcp.ParseString(req, "urn", "") + if urn == "" { + return gomcp.NewToolResultError("'urn' parameter is required"), nil + } + + depth := gomcp.ParseInt(req, "depth", 2) + + cg, err := s.entityService.GetContext(ctx, s.namespace, urn, depth) + if err != nil { + return gomcp.NewToolResultError("get context failed: " + err.Error()), nil + } + + return gomcp.NewToolResultText(formatContextGraph(cg)), nil +} + +func (s *Server) handleImpact(ctx context.Context, req gomcp.CallToolRequest) (*gomcp.CallToolResult, error) { + if s.entityService == nil { + return gomcp.NewToolResultError("entity service not configured"), nil + } + + urn := gomcp.ParseString(req, "urn", "") + if urn == "" { + return gomcp.NewToolResultError("'urn' parameter is required"), nil + } + + depth := gomcp.ParseInt(req, "depth", 3) + + edges, err := s.entityService.GetImpact(ctx, s.namespace, urn, depth) + if err != nil { + return gomcp.NewToolResultError("impact analysis failed: " + err.Error()), nil + } + + return gomcp.NewToolResultText(formatImpactAnalysis(urn, edges)), nil +} + +// Formatters + +func formatEntitySearchResults(results []entity.SearchResult) string { + if len(results) == 0 { + return "No entities found." + } + var b strings.Builder + fmt.Fprintf(&b, "Found %d entities:\n\n", len(results)) + for _, r := range results { + fmt.Fprintf(&b, "- **%s** (%s) — source: %s, urn: %s\n", r.Name, r.Type, r.Source, r.URN) + if r.Description != "" { + desc := r.Description + if len(desc) > 120 { + desc = desc[:120] + "..." + } + fmt.Fprintf(&b, " %s\n", desc) + } + } + return b.String() +} + +func formatContextGraph(cg *entity.ContextGraph) string { + var b strings.Builder + e := cg.Entity + fmt.Fprintf(&b, "## %s (%s)\n", e.Name, e.Type) + fmt.Fprintf(&b, "URN: %s | Source: %s\n", e.URN, e.Source) + if e.Description != "" { + fmt.Fprintf(&b, "Description: %s\n", e.Description) + } + + if len(cg.Edges) > 0 { + b.WriteString("\n### Relationships\n") + for _, edge := range cg.Edges { + if edge.SourceURN == e.URN { + fmt.Fprintf(&b, " —[%s]→ %s\n", edge.Type, edge.TargetURN) + } else { + fmt.Fprintf(&b, " ←[%s]— %s\n", edge.Type, edge.SourceURN) + } + } + } + + if len(cg.Related) > 0 { + b.WriteString("\n### Related Entities\n") + for _, r := range cg.Related { + fmt.Fprintf(&b, "- **%s** (%s) — %s\n", r.Name, r.Type, r.URN) + } + } + + return b.String() +} + +func formatImpactAnalysis(urn string, edges []entity.Edge) string { + if len(edges) == 0 { + return fmt.Sprintf("No downstream dependencies found for %s.", urn) + } + + affected := make(map[string]bool) + for _, e := range edges { + if e.Source != "" && e.SourceURN != urn { + affected[e.SourceURN] = true + } + if e.TargetURN != urn { + affected[e.TargetURN] = true + } + } + + var b strings.Builder + fmt.Fprintf(&b, "## Impact Analysis for %s\n\n", urn) + fmt.Fprintf(&b, "**%d entities affected** across %d edges:\n\n", len(affected), len(edges)) + for _, e := range edges { + fmt.Fprintf(&b, " %s → %s\n", e.SourceURN, e.TargetURN) + } + return b.String() +} diff --git a/internal/mcp/entity_tools.go b/internal/mcp/entity_tools.go new file mode 100644 index 00000000..18265cd7 --- /dev/null +++ b/internal/mcp/entity_tools.go @@ -0,0 +1,53 @@ +package mcp + +import ( + "github.com/mark3labs/mcp-go/mcp" +) + +func searchEntitiesTool() mcp.Tool { + return mcp.NewTool("search_entities", + mcp.WithDescription("Search the entity knowledge graph. Supports keyword, semantic, and hybrid search modes. Finds tables, services, pipelines, people, and any other entity type."), + mcp.WithString("text", + mcp.Required(), + mcp.Description("Search query text"), + ), + mcp.WithString("types", + mcp.Description("Comma-separated entity types to filter by (e.g. table,topic,dashboard,pipeline)"), + ), + mcp.WithString("source", + mcp.Description("Filter by source system (e.g. bigquery,kafka)"), + ), + mcp.WithString("mode", + mcp.Description("Search mode: keyword, semantic, or hybrid (default: keyword)"), + ), + mcp.WithNumber("size", + mcp.Description("Maximum number of results (default: 10)"), + ), + ) +} + +func getContextTool() mcp.Tool { + return mcp.NewTool("get_context", + mcp.WithDescription("Get full context about an entity: the entity itself, its relationships (edges), and related entities. The primary tool for understanding an entity in context."), + mcp.WithString("urn", + mcp.Required(), + mcp.Description("URN of the entity"), + ), + mcp.WithNumber("depth", + mcp.Description("Relationship traversal depth (default: 2)"), + ), + ) +} + +func impactAnalysisTool() mcp.Tool { + return mcp.NewTool("impact", + mcp.WithDescription("Analyze downstream blast radius: what entities are affected if this entity changes?"), + mcp.WithString("urn", + mcp.Required(), + mcp.Description("URN of the entity to analyze"), + ), + mcp.WithNumber("depth", + mcp.Description("Downstream traversal depth (default: 3)"), + ), + ) +} diff --git a/internal/mcp/server.go b/internal/mcp/server.go index 0cd55b76..c11d73a1 100644 --- a/internal/mcp/server.go +++ b/internal/mcp/server.go @@ -6,6 +6,7 @@ import ( mcpserver "github.com/mark3labs/mcp-go/server" "github.com/raystack/compass/core/asset" + "github.com/raystack/compass/core/entity" "github.com/raystack/compass/core/namespace" ) @@ -18,33 +19,58 @@ type AssetService interface { GetAllAssets(ctx context.Context, flt asset.Filter, withTotal bool) ([]asset.Asset, uint32, error) } +// EntityServiceV2 defines the v2 entity operations for MCP tools. +type EntityServiceV2 interface { + Search(ctx context.Context, cfg entity.SearchConfig) ([]entity.SearchResult, error) + GetContext(ctx context.Context, ns *namespace.Namespace, urn string, depth int) (*entity.ContextGraph, error) + GetImpact(ctx context.Context, ns *namespace.Namespace, urn string, depth int) ([]entity.Edge, error) +} + // Server is the MCP server that exposes Compass catalog as AI-agent tools. type Server struct { - assetService AssetService - namespace *namespace.Namespace - mcpServer *mcpserver.MCPServer - httpServer *mcpserver.StreamableHTTPServer + assetService AssetService + entityService EntityServiceV2 + namespace *namespace.Namespace + mcpServer *mcpserver.MCPServer + httpServer *mcpserver.StreamableHTTPServer +} + +// Option configures the MCP server. +type Option func(*Server) + +// WithEntityService adds the v2 entity service for new MCP tools. +func WithEntityService(svc EntityServiceV2) Option { + return func(s *Server) { s.entityService = svc } } // New creates a new MCP server with the given dependencies. -func New(assetSvc AssetService, ns *namespace.Namespace) *Server { +func New(assetSvc AssetService, ns *namespace.Namespace, opts ...Option) *Server { s := &Server{ assetService: assetSvc, namespace: ns, } + for _, opt := range opts { + opt(s) + } mcpSrv := mcpserver.NewMCPServer( "compass", - "0.1.0", + "0.2.0", mcpserver.WithToolCapabilities(false), ) + // v1 asset tools (retained) mcpSrv.AddTool(searchAssetsTool(), s.handleSearchAssets) mcpSrv.AddTool(getAssetTool(), s.handleGetAsset) mcpSrv.AddTool(getLineageTool(), s.handleGetLineage) mcpSrv.AddTool(listTypesTool(), s.handleListTypes) mcpSrv.AddTool(getAllAssetsTool(), s.handleGetAllAssets) + // v2 entity tools + mcpSrv.AddTool(searchEntitiesTool(), s.handleSearchEntities) + mcpSrv.AddTool(getContextTool(), s.handleGetContext) + mcpSrv.AddTool(impactAnalysisTool(), s.handleImpact) + s.mcpServer = mcpSrv s.httpServer = mcpserver.NewStreamableHTTPServer(mcpSrv) diff --git a/internal/server/bootstrap.go b/internal/server/bootstrap.go index f9bbfa3b..74cd5966 100644 --- a/internal/server/bootstrap.go +++ b/internal/server/bootstrap.go @@ -10,6 +10,7 @@ import ( "github.com/raystack/compass/core/asset" "github.com/raystack/compass/core/discussion" + "github.com/raystack/compass/core/entity" "github.com/raystack/compass/core/namespace" "github.com/raystack/compass/core/star" "github.com/raystack/compass/core/tag" @@ -116,8 +117,26 @@ func Start(ctx context.Context, cfg *config.Config, version string) error { // init namespace namespaceService := namespace.NewService(postgres.NewNamespaceRepository(pgClient), discoveryRepository) - // init MCP server - mcpServer := compassmcp.New(assetService, namespace.DefaultNamespace) + // init entity v2 system (runs alongside existing asset system) + // All search is Postgres-native: tsvector + pg_trgm + pgvector. No ES dependency. + entityRepo, err := postgres.NewEntityRepository(pgClient) + if err != nil { + return fmt.Errorf("failed to create entity repository: %w", err) + } + edgeRepo, err := postgres.NewEdgeRepository(pgClient) + if err != nil { + return fmt.Errorf("failed to create edge repository: %w", err) + } + entitySearchRepo, err := postgres.NewEntitySearchRepository(pgClient) + if err != nil { + return fmt.Errorf("failed to create entity search repository: %w", err) + } + entityService := entity.NewService(entityRepo, edgeRepo, entitySearchRepo) + + // init MCP server (v1 asset tools + v2 entity tools) + mcpServer := compassmcp.New(assetService, namespace.DefaultNamespace, + compassmcp.WithEntityService(entityService), + ) return Serve( ctx, diff --git a/store/postgres/chunk_repository.go b/store/postgres/chunk_repository.go new file mode 100644 index 00000000..a6819cc9 --- /dev/null +++ b/store/postgres/chunk_repository.go @@ -0,0 +1,128 @@ +package postgres + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + sq "github.com/Masterminds/squirrel" + "github.com/raystack/compass/core/entity" + "github.com/raystack/compass/core/namespace" +) + +type ChunkRepository struct { + client *Client +} + +func NewChunkRepository(client *Client) (*ChunkRepository, error) { + if client == nil { + return nil, errors.New("postgres client is nil") + } + return &ChunkRepository{client: client}, nil +} + +func (r *ChunkRepository) UpsertBatch(ctx context.Context, ns *namespace.Namespace, chunks []entity.Chunk) error { + if len(chunks) == 0 { + return nil + } + + // Delete old chunks for affected entities, then insert fresh + urns := uniqueURNs(chunks) + for _, urn := range urns { + if err := r.DeleteByEntityURN(ctx, ns, urn); err != nil { + return fmt.Errorf("clear old chunks for %s: %w", urn, err) + } + } + + builder := sq.Insert("chunks"). + Columns("namespace_id", "entity_urn", "content", "context", "embedding", "position", "heading", "token_count"). + PlaceholderFormat(sq.Dollar) + + for _, c := range chunks { + builder = builder.Values(ns.ID, c.EntityURN, c.Content, c.Context, + vectorString(c.Embedding), c.Position, c.Heading, c.TokenCount) + } + + query, args, err := builder.ToSql() + if err != nil { + return fmt.Errorf("build insert chunks: %w", err) + } + _, err = r.client.ExecContext(ctx, query, args...) + if err != nil { + return fmt.Errorf("insert chunks: %w", err) + } + return nil +} + +func (r *ChunkRepository) DeleteByEntityURN(ctx context.Context, ns *namespace.Namespace, entityURN string) error { + _, err := r.client.ExecContext(ctx, + `DELETE FROM chunks WHERE namespace_id = $1 AND entity_urn = $2`, ns.ID, entityURN) + return err +} + +func (r *ChunkRepository) Search(ctx context.Context, ns *namespace.Namespace, embedding []float32, limit int) ([]entity.Chunk, error) { + if limit <= 0 { + limit = 10 + } + + query := `SELECT id, namespace_id, entity_urn, content, context, position, heading, token_count, created_at + FROM chunks WHERE namespace_id = $1 + ORDER BY embedding <=> $2::vector + LIMIT $3` + + var models []chunkModel + if err := r.client.SelectContext(ctx, &models, query, ns.ID, vectorString(embedding), limit); err != nil { + return nil, fmt.Errorf("semantic search: %w", err) + } + + result := make([]entity.Chunk, len(models)) + for i, m := range models { + result[i] = entity.Chunk{ + ID: m.ID, + EntityURN: m.EntityURN, + Content: m.Content, + Context: m.Context, + Position: m.Position, + Heading: m.Heading, + TokenCount: m.TokenCount, + CreatedAt: m.CreatedAt, + } + } + return result, nil +} + +type chunkModel struct { + ID string `db:"id"` + EntityURN string `db:"entity_urn"` + Content string `db:"content"` + Context string `db:"context"` + Position int `db:"position"` + Heading string `db:"heading"` + TokenCount int `db:"token_count"` + CreatedAt time.Time `db:"created_at"` +} + +func vectorString(v []float32) string { + if len(v) == 0 { + return "[]" + } + parts := make([]string, len(v)) + for i, f := range v { + parts[i] = fmt.Sprintf("%g", f) + } + return "[" + strings.Join(parts, ",") + "]" +} + +func uniqueURNs(chunks []entity.Chunk) []string { + seen := make(map[string]bool) + var urns []string + for _, c := range chunks { + if !seen[c.EntityURN] { + seen[c.EntityURN] = true + urns = append(urns, c.EntityURN) + } + } + return urns +} diff --git a/store/postgres/edge_repository.go b/store/postgres/edge_repository.go new file mode 100644 index 00000000..57589e7b --- /dev/null +++ b/store/postgres/edge_repository.go @@ -0,0 +1,177 @@ +package postgres + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + sq "github.com/Masterminds/squirrel" + "github.com/raystack/compass/core/entity" + "github.com/raystack/compass/core/namespace" +) + +type EdgeRepository struct { + client *Client +} + +func NewEdgeRepository(client *Client) (*EdgeRepository, error) { + if client == nil { + return nil, errors.New("postgres client is nil") + } + return &EdgeRepository{client: client}, nil +} + +var edgeColumns = `id, namespace_id, source_urn, target_urn, type, properties, valid_from, valid_to, source, created_at` + +func (r *EdgeRepository) Upsert(ctx context.Context, ns *namespace.Namespace, e *entity.Edge) error { + query, args, err := sq.Insert("edges"). + Columns("namespace_id", "source_urn", "target_urn", "type", "properties", "source"). + Values(ns.ID, e.SourceURN, e.TargetURN, e.Type, JSONMap(e.Properties), e.Source). + Suffix(`ON CONFLICT (namespace_id, source_urn, target_urn, type, valid_from) + DO UPDATE SET properties = EXCLUDED.properties, source = EXCLUDED.source`). + PlaceholderFormat(sq.Dollar). + ToSql() + if err != nil { + return fmt.Errorf("build upsert edge: %w", err) + } + _, err = r.client.ExecContext(ctx, query, args...) + if err != nil { + return fmt.Errorf("upsert edge: %w", err) + } + return nil +} + +func (r *EdgeRepository) GetBySource(ctx context.Context, ns *namespace.Namespace, urn string, filter entity.EdgeFilter) ([]entity.Edge, error) { + builder := sq.Select(edgeColumns).From("edges"). + Where(sq.Eq{"namespace_id": ns.ID, "source_urn": urn}). + PlaceholderFormat(sq.Dollar) + builder = applyEdgeFilter(builder, filter) + + query, args, err := builder.ToSql() + if err != nil { + return nil, fmt.Errorf("build query: %w", err) + } + return r.queryEdges(ctx, query, args...) +} + +func (r *EdgeRepository) GetByTarget(ctx context.Context, ns *namespace.Namespace, urn string, filter entity.EdgeFilter) ([]entity.Edge, error) { + builder := sq.Select(edgeColumns).From("edges"). + Where(sq.Eq{"namespace_id": ns.ID, "target_urn": urn}). + PlaceholderFormat(sq.Dollar) + builder = applyEdgeFilter(builder, filter) + + query, args, err := builder.ToSql() + if err != nil { + return nil, fmt.Errorf("build query: %w", err) + } + return r.queryEdges(ctx, query, args...) +} + +func (r *EdgeRepository) GetDownstream(ctx context.Context, ns *namespace.Namespace, urn string, depth int) ([]entity.Edge, error) { + return r.traverse(ctx, ns, urn, depth, "downstream") +} + +func (r *EdgeRepository) GetUpstream(ctx context.Context, ns *namespace.Namespace, urn string, depth int) ([]entity.Edge, error) { + return r.traverse(ctx, ns, urn, depth, "upstream") +} + +func (r *EdgeRepository) Delete(ctx context.Context, ns *namespace.Namespace, sourceURN, targetURN, edgeType string) error { + _, err := r.client.ExecContext(ctx, + `UPDATE edges SET valid_to = now() WHERE namespace_id = $1 AND source_urn = $2 AND target_urn = $3 AND type = $4 AND valid_to IS NULL`, + ns.ID, sourceURN, targetURN, edgeType) + return err +} + +func (r *EdgeRepository) DeleteByURN(ctx context.Context, ns *namespace.Namespace, urn string) error { + _, err := r.client.ExecContext(ctx, + `UPDATE edges SET valid_to = now() WHERE namespace_id = $1 AND (source_urn = $2 OR target_urn = $2) AND valid_to IS NULL`, + ns.ID, urn) + return err +} + +func (r *EdgeRepository) traverse(ctx context.Context, ns *namespace.Namespace, urn string, depth int, direction string) ([]entity.Edge, error) { + if depth <= 0 { + depth = 3 + } + + var seedCol, joinCol string + if direction == "downstream" { + seedCol, joinCol = "source_urn", "target_urn" + } else { + seedCol, joinCol = "target_urn", "source_urn" + } + + query := fmt.Sprintf(` + WITH RECURSIVE graph(source_urn, target_urn, type, properties, depth, path) AS ( + SELECT source_urn, target_urn, type, properties, 1, ARRAY[%s] + FROM edges + WHERE namespace_id = $1 AND %s = $2 AND valid_to IS NULL + UNION ALL + SELECT e.source_urn, e.target_urn, e.type, e.properties, g.depth + 1, g.path || e.%s + FROM edges e + JOIN graph g ON e.%s = g.%s + WHERE e.%s <> ALL(g.path) AND e.valid_to IS NULL AND g.depth < $3 + ) + SELECT source_urn, target_urn, type, properties FROM graph`, + seedCol, seedCol, seedCol, joinCol, joinCol, seedCol) + + var models []edgeModel + if err := r.client.SelectContext(ctx, &models, query, ns.ID, urn, depth); err != nil { + return nil, fmt.Errorf("traverse %s: %w", direction, err) + } + return toEdgeList(models), nil +} + +func (r *EdgeRepository) queryEdges(ctx context.Context, query string, args ...interface{}) ([]entity.Edge, error) { + var models []edgeModel + if err := r.client.SelectContext(ctx, &models, query, args...); err != nil { + return nil, fmt.Errorf("query edges: %w", err) + } + return toEdgeList(models), nil +} + +func applyEdgeFilter(builder sq.SelectBuilder, filter entity.EdgeFilter) sq.SelectBuilder { + if filter.Current { + builder = builder.Where("valid_to IS NULL") + } + if len(filter.Types) > 0 { + builder = builder.Where(sq.Eq{"type": filter.Types}) + } + return builder +} + +type edgeModel struct { + ID string `db:"id"` + NamespaceID string `db:"namespace_id"` + SourceURN string `db:"source_urn"` + TargetURN string `db:"target_urn"` + Type string `db:"type"` + Properties JSONMap `db:"properties"` + ValidFrom time.Time `db:"valid_from"` + ValidTo *time.Time `db:"valid_to"` + Source string `db:"source"` + CreatedAt time.Time `db:"created_at"` +} + +func toEdgeList(models []edgeModel) []entity.Edge { + edges := make([]entity.Edge, len(models)) + for i, m := range models { + edges[i] = entity.Edge{ + ID: m.ID, + NamespaceID: m.NamespaceID, + SourceURN: m.SourceURN, + TargetURN: m.TargetURN, + Type: m.Type, + Properties: m.Properties, + ValidFrom: m.ValidFrom, + ValidTo: m.ValidTo, + Source: m.Source, + CreatedAt: m.CreatedAt, + } + } + return edges +} + +var _ = strings.Join // keep import diff --git a/store/postgres/entity_repository.go b/store/postgres/entity_repository.go new file mode 100644 index 00000000..07ccf6da --- /dev/null +++ b/store/postgres/entity_repository.go @@ -0,0 +1,236 @@ +package postgres + +import ( + "context" + "database/sql" + "errors" + "fmt" + "time" + + sq "github.com/Masterminds/squirrel" + "github.com/jmoiron/sqlx" + "github.com/raystack/compass/core/entity" + "github.com/raystack/compass/core/namespace" +) + +type EntityRepository struct { + client *Client +} + +func NewEntityRepository(client *Client) (*EntityRepository, error) { + if client == nil { + return nil, errors.New("postgres client is nil") + } + return &EntityRepository{client: client}, nil +} + +var entityColumns = `id, namespace_id, urn, type, name, description, properties, source, + valid_from, valid_to, created_at, updated_at` + +func (r *EntityRepository) Upsert(ctx context.Context, ns *namespace.Namespace, ent *entity.Entity) (string, error) { + now := time.Now().UTC() + ent.UpdatedAt = now + + // Check if entity already exists + existing, err := r.GetByURN(ctx, ns, ent.URN) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return "", fmt.Errorf("check existing entity: %w", err) + } + + if existing.ID != "" { + // Update: set valid_to on old row, insert new row + _, err := r.client.ExecContext(ctx, + `UPDATE entities SET updated_at = $1, properties = $2, name = $3, description = $4, source = $5, type = $6 + WHERE id = $7`, + now, JSONMap(ent.Properties), ent.Name, ent.Description, ent.Source, string(ent.Type), existing.ID) + if err != nil { + return "", fmt.Errorf("update entity: %w", err) + } + return existing.ID, nil + } + + // Insert new entity + var id string + err = r.client.QueryFn(ctx, func(conn *sqlx.Conn) error { + return conn.QueryRowxContext(ctx, + `INSERT INTO entities (namespace_id, urn, type, name, description, properties, source, valid_from, created_at, updated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + RETURNING id`, + ns.ID, ent.URN, string(ent.Type), ent.Name, ent.Description, + JSONMap(ent.Properties), ent.Source, now, now, now, + ).Scan(&id) + }) + if err != nil { + return "", fmt.Errorf("insert entity: %w", err) + } + ent.CreatedAt = now + ent.ValidFrom = now + return id, nil +} + +func (r *EntityRepository) GetByURN(ctx context.Context, ns *namespace.Namespace, urn string) (entity.Entity, error) { + q := fmt.Sprintf(`SELECT %s FROM entities WHERE namespace_id = $1 AND urn = $2 AND valid_to IS NULL LIMIT 1`, entityColumns) + var m entityModel + if err := r.client.GetContext(ctx, &m, q, ns.ID, urn); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return entity.Entity{}, sql.ErrNoRows + } + return entity.Entity{}, fmt.Errorf("get entity by URN: %w", err) + } + return m.toEntity(), nil +} + +func (r *EntityRepository) GetByID(ctx context.Context, id string) (entity.Entity, error) { + q := fmt.Sprintf(`SELECT %s FROM entities WHERE id = $1 AND valid_to IS NULL LIMIT 1`, entityColumns) + var m entityModel + if err := r.client.GetContext(ctx, &m, q, id); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return entity.Entity{}, sql.ErrNoRows + } + return entity.Entity{}, fmt.Errorf("get entity by ID: %w", err) + } + return m.toEntity(), nil +} + +func (r *EntityRepository) GetAll(ctx context.Context, ns *namespace.Namespace, flt entity.Filter) ([]entity.Entity, error) { + builder := sq.Select(entityColumns). + From("entities"). + Where(sq.Eq{"namespace_id": ns.ID}). + Where("valid_to IS NULL"). + PlaceholderFormat(sq.Dollar) + + builder = applyEntityFilter(builder, flt) + + limit := flt.Size + if limit <= 0 { + limit = 50 + } + builder = builder.Limit(uint64(limit)).Offset(uint64(flt.Offset)) + builder = builder.OrderBy("updated_at DESC") + + query, args, err := builder.ToSql() + if err != nil { + return nil, fmt.Errorf("build query: %w", err) + } + + var models []entityModel + if err := r.client.SelectContext(ctx, &models, query, args...); err != nil { + return nil, fmt.Errorf("get entities: %w", err) + } + + result := make([]entity.Entity, len(models)) + for i, m := range models { + result[i] = m.toEntity() + } + return result, nil +} + +func (r *EntityRepository) GetCount(ctx context.Context, ns *namespace.Namespace, flt entity.Filter) (int, error) { + builder := sq.Select("count(1)"). + From("entities"). + Where(sq.Eq{"namespace_id": ns.ID}). + Where("valid_to IS NULL"). + PlaceholderFormat(sq.Dollar) + + builder = applyEntityFilter(builder, flt) + + query, args, err := builder.ToSql() + if err != nil { + return 0, fmt.Errorf("build count query: %w", err) + } + + var total int + if err := r.client.GetContext(ctx, &total, query, args...); err != nil { + return 0, fmt.Errorf("count entities: %w", err) + } + return total, nil +} + +func (r *EntityRepository) GetTypes(ctx context.Context, ns *namespace.Namespace) (map[entity.Type]int, error) { + query := `SELECT type, count(1) as count FROM entities WHERE namespace_id = $1 AND valid_to IS NULL GROUP BY type` + + type typeCount struct { + Type string `db:"type"` + Count int `db:"count"` + } + var rows []typeCount + if err := r.client.SelectContext(ctx, &rows, query, ns.ID); err != nil { + return nil, fmt.Errorf("get entity types: %w", err) + } + + result := make(map[entity.Type]int, len(rows)) + for _, r := range rows { + result[entity.Type(r.Type)] = r.Count + } + return result, nil +} + +func (r *EntityRepository) Delete(ctx context.Context, ns *namespace.Namespace, urn string) error { + // Soft delete: set valid_to + res, err := r.client.ExecContext(ctx, + `UPDATE entities SET valid_to = now(), updated_at = now() WHERE namespace_id = $1 AND urn = $2 AND valid_to IS NULL`, + ns.ID, urn) + if err != nil { + return fmt.Errorf("delete entity: %w", err) + } + n, _ := res.RowsAffected() + if n == 0 { + return sql.ErrNoRows + } + return nil +} + +func applyEntityFilter(builder sq.SelectBuilder, flt entity.Filter) sq.SelectBuilder { + if len(flt.Types) > 0 { + types := make([]string, len(flt.Types)) + for i, t := range flt.Types { + types[i] = string(t) + } + builder = builder.Where(sq.Eq{"type": types}) + } + if flt.Source != "" { + builder = builder.Where(sq.Eq{"source": flt.Source}) + } + if flt.Query != "" { + builder = builder.Where(sq.Or{ + sq.ILike{"name": "%" + flt.Query + "%"}, + sq.ILike{"urn": "%" + flt.Query + "%"}, + }) + } + return builder +} + +// entityModel maps to the entities table. +type entityModel struct { + ID string `db:"id"` + NamespaceID string `db:"namespace_id"` + URN string `db:"urn"` + Type string `db:"type"` + Name string `db:"name"` + Description string `db:"description"` + Properties JSONMap `db:"properties"` + Source string `db:"source"` + ValidFrom time.Time `db:"valid_from"` + ValidTo *time.Time `db:"valid_to"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` +} + +func (m entityModel) toEntity() entity.Entity { + return entity.Entity{ + ID: m.ID, + NamespaceID: m.NamespaceID, + URN: m.URN, + Type: entity.Type(m.Type), + Name: m.Name, + Description: m.Description, + Properties: m.Properties, + Source: m.Source, + ValidFrom: m.ValidFrom, + ValidTo: m.ValidTo, + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } +} + + diff --git a/store/postgres/entity_search_repository.go b/store/postgres/entity_search_repository.go new file mode 100644 index 00000000..3609bd76 --- /dev/null +++ b/store/postgres/entity_search_repository.go @@ -0,0 +1,167 @@ +package postgres + +import ( + "context" + "errors" + "fmt" + + "github.com/raystack/compass/core/entity" + "github.com/raystack/compass/core/namespace" +) + +// EntitySearchRepository implements entity.SearchRepository using Postgres +// tsvector (full-text search) + pg_trgm (fuzzy matching). No ES dependency. +type EntitySearchRepository struct { + client *Client +} + +func NewEntitySearchRepository(client *Client) (*EntitySearchRepository, error) { + if client == nil { + return nil, errors.New("postgres client is nil") + } + return &EntitySearchRepository{client: client}, nil +} + +// Search performs keyword search using tsvector ranking with pg_trgm fuzzy fallback. +// Ranking: ts_rank weights URN/name (A) higher than description (B) and source (C). +// If tsvector returns no results, falls back to pg_trgm similarity on name and URN. +func (r *EntitySearchRepository) Search(ctx context.Context, cfg entity.SearchConfig) ([]entity.SearchResult, error) { + limit := cfg.MaxResults + if limit <= 0 { + limit = 10 + } + + nsID := "" + if cfg.Namespace != nil { + nsID = cfg.Namespace.ID.String() + } + + // Primary: tsvector full-text search with ranking + results, err := r.tsvectorSearch(ctx, nsID, cfg.Text, cfg.Filters, limit, cfg.Offset) + if err != nil { + return nil, err + } + + // Fallback: if tsvector returned nothing, try pg_trgm fuzzy match + if len(results) == 0 && cfg.Text != "" { + results, err = r.trigramSearch(ctx, nsID, cfg.Text, cfg.Filters, limit, cfg.Offset) + if err != nil { + return nil, err + } + } + + return results, nil +} + +// Suggest returns name completions using pg_trgm similarity. +func (r *EntitySearchRepository) Suggest(ctx context.Context, ns *namespace.Namespace, text string, limit int) ([]string, error) { + if limit <= 0 { + limit = 5 + } + + query := `SELECT DISTINCT name FROM entities + WHERE namespace_id = $1 AND valid_to IS NULL AND name % $2 + ORDER BY similarity(name, $2) DESC + LIMIT $3` + + var names []string + if err := r.client.SelectContext(ctx, &names, query, ns.ID, text, limit); err != nil { + return nil, fmt.Errorf("suggest: %w", err) + } + return names, nil +} + +func (r *EntitySearchRepository) tsvectorSearch(ctx context.Context, nsID, text string, filters map[string][]string, limit, offset int) ([]entity.SearchResult, error) { + // Build the query with plainto_tsquery for robustness (handles unquoted input) + query := `SELECT id, urn, type, name, COALESCE(source, '') as source, + COALESCE(description, '') as description, + ts_rank(search_vector, plainto_tsquery('english', $2)) as rank + FROM entities + WHERE namespace_id = $1 AND valid_to IS NULL + AND search_vector @@ plainto_tsquery('english', $2)` + + args := []interface{}{nsID, text} + argIdx := 3 + + // Apply type filter + if types, ok := filters["type"]; ok && len(types) > 0 { + query += fmt.Sprintf(" AND type = ANY($%d)", argIdx) + args = append(args, types) + argIdx++ + } + + // Apply source filter + if sources, ok := filters["source"]; ok && len(sources) > 0 { + query += fmt.Sprintf(" AND source = ANY($%d)", argIdx) + args = append(args, sources) + argIdx++ + } + + query += " ORDER BY rank DESC" + query += fmt.Sprintf(" LIMIT $%d OFFSET $%d", argIdx, argIdx+1) + args = append(args, limit, offset) + + return r.querySearchResults(ctx, query, args...) +} + +func (r *EntitySearchRepository) trigramSearch(ctx context.Context, nsID, text string, filters map[string][]string, limit, offset int) ([]entity.SearchResult, error) { + // pg_trgm similarity search: matches even with typos + query := `SELECT id, urn, type, name, COALESCE(source, '') as source, + COALESCE(description, '') as description, + GREATEST(similarity(name, $2), similarity(urn, $2)) as rank + FROM entities + WHERE namespace_id = $1 AND valid_to IS NULL + AND (name % $2 OR urn % $2)` + + args := []interface{}{nsID, text} + argIdx := 3 + + if types, ok := filters["type"]; ok && len(types) > 0 { + query += fmt.Sprintf(" AND type = ANY($%d)", argIdx) + args = append(args, types) + argIdx++ + } + + if sources, ok := filters["source"]; ok && len(sources) > 0 { + query += fmt.Sprintf(" AND source = ANY($%d)", argIdx) + args = append(args, sources) + argIdx++ + } + + query += " ORDER BY rank DESC" + query += fmt.Sprintf(" LIMIT $%d OFFSET $%d", argIdx, argIdx+1) + args = append(args, limit, offset) + + return r.querySearchResults(ctx, query, args...) +} + +func (r *EntitySearchRepository) querySearchResults(ctx context.Context, query string, args ...interface{}) ([]entity.SearchResult, error) { + type row struct { + ID string `db:"id"` + URN string `db:"urn"` + Type string `db:"type"` + Name string `db:"name"` + Source string `db:"source"` + Description string `db:"description"` + Rank float64 `db:"rank"` + } + + var rows []row + if err := r.client.SelectContext(ctx, &rows, query, args...); err != nil { + return nil, fmt.Errorf("search entities: %w", err) + } + + results := make([]entity.SearchResult, len(rows)) + for i, r := range rows { + results[i] = entity.SearchResult{ + ID: r.ID, + URN: r.URN, + Type: r.Type, + Name: r.Name, + Source: r.Source, + Description: r.Description, + Rank: r.Rank, + } + } + return results, nil +} diff --git a/store/postgres/migrations/000019_create_entity_tables.down.sql b/store/postgres/migrations/000019_create_entity_tables.down.sql new file mode 100644 index 00000000..bfe8b849 --- /dev/null +++ b/store/postgres/migrations/000019_create_entity_tables.down.sql @@ -0,0 +1,3 @@ +DROP TABLE IF EXISTS chunks CASCADE; +DROP TABLE IF EXISTS edges CASCADE; +DROP TABLE IF EXISTS entities CASCADE; diff --git a/store/postgres/migrations/000019_create_entity_tables.up.sql b/store/postgres/migrations/000019_create_entity_tables.up.sql new file mode 100644 index 00000000..ae8243bf --- /dev/null +++ b/store/postgres/migrations/000019_create_entity_tables.up.sql @@ -0,0 +1,98 @@ +-- Entity Model v2: entities, edges, chunks (alongside existing assets tables) +-- All search is Postgres-native: tsvector for keyword, pg_trgm for fuzzy, pgvector for semantic. +-- No Elasticsearch dependency for the v2 entity system. + +CREATE EXTENSION IF NOT EXISTS vector; +CREATE EXTENSION IF NOT EXISTS pg_trgm; + +-- Entities: the core knowledge layer +CREATE TABLE entities ( + id uuid DEFAULT gen_random_uuid() PRIMARY KEY, + namespace_id uuid NOT NULL REFERENCES namespaces(id), + urn text NOT NULL, + type text NOT NULL, + name text NOT NULL, + description text, + properties jsonb DEFAULT '{}', + source text, + valid_from timestamptz DEFAULT now(), + valid_to timestamptz, + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now(), + + -- Full-text search vector (auto-populated by trigger) + search_vector tsvector GENERATED ALWAYS AS ( + setweight(to_tsvector('english', coalesce(urn, '')), 'A') || + setweight(to_tsvector('english', coalesce(name, '')), 'A') || + setweight(to_tsvector('english', coalesce(description, '')), 'B') || + setweight(to_tsvector('english', coalesce(source, '')), 'C') + ) STORED, + + UNIQUE (namespace_id, urn, valid_from) +); + +CREATE INDEX idx_entities_ns_urn ON entities(namespace_id, urn); +CREATE INDEX idx_entities_type ON entities(type); +CREATE INDEX idx_entities_current ON entities(valid_to) WHERE valid_to IS NULL; +CREATE INDEX idx_entities_properties ON entities USING GIN(properties); +CREATE INDEX idx_entities_source ON entities(source); + +-- Full-text search index (GIN on tsvector) +CREATE INDEX idx_entities_search ON entities USING GIN(search_vector); + +-- Trigram indexes for fuzzy matching on name and URN +CREATE INDEX idx_entities_name_trgm ON entities USING GIN(name gin_trgm_ops); +CREATE INDEX idx_entities_urn_trgm ON entities USING GIN(urn gin_trgm_ops); + +ALTER TABLE entities ENABLE ROW LEVEL SECURITY; +CREATE POLICY entities_ns_policy ON entities + USING (namespace_id = current_setting('app.current_tenant')::UUID); + +-- Edges: typed, temporal relationships between entities +CREATE TABLE edges ( + id uuid DEFAULT gen_random_uuid() PRIMARY KEY, + namespace_id uuid NOT NULL REFERENCES namespaces(id), + source_urn text NOT NULL, + target_urn text NOT NULL, + type text NOT NULL, + properties jsonb DEFAULT '{}', + valid_from timestamptz DEFAULT now(), + valid_to timestamptz, + source text, + created_at timestamptz DEFAULT now(), + + UNIQUE (namespace_id, source_urn, target_urn, type, valid_from) +); + +CREATE INDEX idx_edges_source_urn ON edges(namespace_id, source_urn); +CREATE INDEX idx_edges_target_urn ON edges(namespace_id, target_urn); +CREATE INDEX idx_edges_type ON edges(type); +CREATE INDEX idx_edges_current ON edges(valid_to) WHERE valid_to IS NULL; + +ALTER TABLE edges ENABLE ROW LEVEL SECURITY; +CREATE POLICY edges_ns_policy ON edges + USING (namespace_id = current_setting('app.current_tenant')::UUID); + +-- Chunks: vector embeddings for semantic search +CREATE TABLE chunks ( + id uuid DEFAULT gen_random_uuid() PRIMARY KEY, + namespace_id uuid NOT NULL REFERENCES namespaces(id), + entity_urn text NOT NULL, + content text NOT NULL, + context text, + embedding vector(1536) NOT NULL, + position int, + heading text, + token_count int, + created_at timestamptz DEFAULT now() +); + +CREATE INDEX chunks_embedding_idx ON chunks + USING hnsw (embedding vector_cosine_ops) + WITH (m = 16, ef_construction = 64); +CREATE INDEX idx_chunks_entity_urn ON chunks(entity_urn); +CREATE INDEX idx_chunks_namespace ON chunks(namespace_id); + +ALTER TABLE chunks ENABLE ROW LEVEL SECURITY; +CREATE POLICY chunks_ns_policy ON chunks + USING (namespace_id = current_setting('app.current_tenant')::UUID); From 3dfa835b761a3a9882bb542103c11909d6b50fee Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 29 Mar 2026 01:14:57 -0500 Subject: [PATCH 02/10] feat: add entity v2 handler with gRPC/REST endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generated Go code from proton proto definitions for entity v2 RPCs. Created handler/entity.go implementing all 12 new RPC methods: Entity CRUD: GetAllEntities, GetEntityByID, UpsertEntity, DeleteEntity Search: SearchEntities, SuggestEntities, GetEntityTypes Context: GetEntityContext, GetEntityImpact Edges: UpsertEdge, GetEdges, DeleteEdge Handler accepts entity and edge services via WithEntityService/ WithEdgeService options — no changes to existing handler constructor signature. Serve function passes options through to handler. --- .../compassv1beta1connect/service.connect.go | 353 +++ gen/raystack/compass/v1beta1/service.pb.go | 2057 +++++++++++++++-- handler/entity.go | 318 +++ handler/handler.go | 22 +- internal/server/bootstrap.go | 3 + internal/server/server.go | 2 + 6 files changed, 2583 insertions(+), 172 deletions(-) create mode 100644 handler/entity.go diff --git a/gen/raystack/compass/v1beta1/compassv1beta1connect/service.connect.go b/gen/raystack/compass/v1beta1/compassv1beta1connect/service.connect.go index 2ac86626..d3cfecaf 100644 --- a/gen/raystack/compass/v1beta1/compassv1beta1connect/service.connect.go +++ b/gen/raystack/compass/v1beta1/compassv1beta1connect/service.connect.go @@ -161,6 +161,41 @@ const ( // CompassServiceListNamespacesProcedure is the fully-qualified name of the CompassService's // ListNamespaces RPC. CompassServiceListNamespacesProcedure = "/raystack.compass.v1beta1.CompassService/ListNamespaces" + // CompassServiceGetAllEntitiesProcedure is the fully-qualified name of the CompassService's + // GetAllEntities RPC. + CompassServiceGetAllEntitiesProcedure = "/raystack.compass.v1beta1.CompassService/GetAllEntities" + // CompassServiceGetEntityByIDProcedure is the fully-qualified name of the CompassService's + // GetEntityByID RPC. + CompassServiceGetEntityByIDProcedure = "/raystack.compass.v1beta1.CompassService/GetEntityByID" + // CompassServiceUpsertEntityProcedure is the fully-qualified name of the CompassService's + // UpsertEntity RPC. + CompassServiceUpsertEntityProcedure = "/raystack.compass.v1beta1.CompassService/UpsertEntity" + // CompassServiceDeleteEntityProcedure is the fully-qualified name of the CompassService's + // DeleteEntity RPC. + CompassServiceDeleteEntityProcedure = "/raystack.compass.v1beta1.CompassService/DeleteEntity" + // CompassServiceSearchEntitiesProcedure is the fully-qualified name of the CompassService's + // SearchEntities RPC. + CompassServiceSearchEntitiesProcedure = "/raystack.compass.v1beta1.CompassService/SearchEntities" + // CompassServiceSuggestEntitiesProcedure is the fully-qualified name of the CompassService's + // SuggestEntities RPC. + CompassServiceSuggestEntitiesProcedure = "/raystack.compass.v1beta1.CompassService/SuggestEntities" + // CompassServiceGetEntityTypesProcedure is the fully-qualified name of the CompassService's + // GetEntityTypes RPC. + CompassServiceGetEntityTypesProcedure = "/raystack.compass.v1beta1.CompassService/GetEntityTypes" + // CompassServiceGetEntityContextProcedure is the fully-qualified name of the CompassService's + // GetEntityContext RPC. + CompassServiceGetEntityContextProcedure = "/raystack.compass.v1beta1.CompassService/GetEntityContext" + // CompassServiceGetEntityImpactProcedure is the fully-qualified name of the CompassService's + // GetEntityImpact RPC. + CompassServiceGetEntityImpactProcedure = "/raystack.compass.v1beta1.CompassService/GetEntityImpact" + // CompassServiceUpsertEdgeProcedure is the fully-qualified name of the CompassService's UpsertEdge + // RPC. + CompassServiceUpsertEdgeProcedure = "/raystack.compass.v1beta1.CompassService/UpsertEdge" + // CompassServiceGetEdgesProcedure is the fully-qualified name of the CompassService's GetEdges RPC. + CompassServiceGetEdgesProcedure = "/raystack.compass.v1beta1.CompassService/GetEdges" + // CompassServiceDeleteEdgeProcedure is the fully-qualified name of the CompassService's DeleteEdge + // RPC. + CompassServiceDeleteEdgeProcedure = "/raystack.compass.v1beta1.CompassService/DeleteEdge" ) // CompassServiceClient is a client for the raystack.compass.v1beta1.CompassService service. @@ -213,6 +248,21 @@ type CompassServiceClient interface { GetNamespace(context.Context, *connect.Request[v1beta1.GetNamespaceRequest]) (*connect.Response[v1beta1.GetNamespaceResponse], error) UpdateNamespace(context.Context, *connect.Request[v1beta1.UpdateNamespaceRequest]) (*connect.Response[v1beta1.UpdateNamespaceResponse], error) ListNamespaces(context.Context, *connect.Request[v1beta1.ListNamespacesRequest]) (*connect.Response[v1beta1.ListNamespacesResponse], error) + // Domain: Entity (v2) + GetAllEntities(context.Context, *connect.Request[v1beta1.GetAllEntitiesRequest]) (*connect.Response[v1beta1.GetAllEntitiesResponse], error) + GetEntityByID(context.Context, *connect.Request[v1beta1.GetEntityByIDRequest]) (*connect.Response[v1beta1.GetEntityByIDResponse], error) + UpsertEntity(context.Context, *connect.Request[v1beta1.UpsertEntityRequest]) (*connect.Response[v1beta1.UpsertEntityResponse], error) + DeleteEntity(context.Context, *connect.Request[v1beta1.DeleteEntityRequest]) (*connect.Response[v1beta1.DeleteEntityResponse], error) + SearchEntities(context.Context, *connect.Request[v1beta1.SearchEntitiesRequest]) (*connect.Response[v1beta1.SearchEntitiesResponse], error) + SuggestEntities(context.Context, *connect.Request[v1beta1.SuggestEntitiesRequest]) (*connect.Response[v1beta1.SuggestEntitiesResponse], error) + GetEntityTypes(context.Context, *connect.Request[v1beta1.GetEntityTypesRequest]) (*connect.Response[v1beta1.GetEntityTypesResponse], error) + // Domain: Entity Context & Impact (v2) + GetEntityContext(context.Context, *connect.Request[v1beta1.GetEntityContextRequest]) (*connect.Response[v1beta1.GetEntityContextResponse], error) + GetEntityImpact(context.Context, *connect.Request[v1beta1.GetEntityImpactRequest]) (*connect.Response[v1beta1.GetEntityImpactResponse], error) + // Domain: Edges (v2) + UpsertEdge(context.Context, *connect.Request[v1beta1.UpsertEdgeRequest]) (*connect.Response[v1beta1.UpsertEdgeResponse], error) + GetEdges(context.Context, *connect.Request[v1beta1.GetEdgesRequest]) (*connect.Response[v1beta1.GetEdgesResponse], error) + DeleteEdge(context.Context, *connect.Request[v1beta1.DeleteEdgeRequest]) (*connect.Response[v1beta1.DeleteEdgeResponse], error) } // NewCompassServiceClient constructs a client for the raystack.compass.v1beta1.CompassService @@ -484,6 +534,78 @@ func NewCompassServiceClient(httpClient connect.HTTPClient, baseURL string, opts connect.WithSchema(compassServiceMethods.ByName("ListNamespaces")), connect.WithClientOptions(opts...), ), + getAllEntities: connect.NewClient[v1beta1.GetAllEntitiesRequest, v1beta1.GetAllEntitiesResponse]( + httpClient, + baseURL+CompassServiceGetAllEntitiesProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetAllEntities")), + connect.WithClientOptions(opts...), + ), + getEntityByID: connect.NewClient[v1beta1.GetEntityByIDRequest, v1beta1.GetEntityByIDResponse]( + httpClient, + baseURL+CompassServiceGetEntityByIDProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetEntityByID")), + connect.WithClientOptions(opts...), + ), + upsertEntity: connect.NewClient[v1beta1.UpsertEntityRequest, v1beta1.UpsertEntityResponse]( + httpClient, + baseURL+CompassServiceUpsertEntityProcedure, + connect.WithSchema(compassServiceMethods.ByName("UpsertEntity")), + connect.WithClientOptions(opts...), + ), + deleteEntity: connect.NewClient[v1beta1.DeleteEntityRequest, v1beta1.DeleteEntityResponse]( + httpClient, + baseURL+CompassServiceDeleteEntityProcedure, + connect.WithSchema(compassServiceMethods.ByName("DeleteEntity")), + connect.WithClientOptions(opts...), + ), + searchEntities: connect.NewClient[v1beta1.SearchEntitiesRequest, v1beta1.SearchEntitiesResponse]( + httpClient, + baseURL+CompassServiceSearchEntitiesProcedure, + connect.WithSchema(compassServiceMethods.ByName("SearchEntities")), + connect.WithClientOptions(opts...), + ), + suggestEntities: connect.NewClient[v1beta1.SuggestEntitiesRequest, v1beta1.SuggestEntitiesResponse]( + httpClient, + baseURL+CompassServiceSuggestEntitiesProcedure, + connect.WithSchema(compassServiceMethods.ByName("SuggestEntities")), + connect.WithClientOptions(opts...), + ), + getEntityTypes: connect.NewClient[v1beta1.GetEntityTypesRequest, v1beta1.GetEntityTypesResponse]( + httpClient, + baseURL+CompassServiceGetEntityTypesProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetEntityTypes")), + connect.WithClientOptions(opts...), + ), + getEntityContext: connect.NewClient[v1beta1.GetEntityContextRequest, v1beta1.GetEntityContextResponse]( + httpClient, + baseURL+CompassServiceGetEntityContextProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetEntityContext")), + connect.WithClientOptions(opts...), + ), + getEntityImpact: connect.NewClient[v1beta1.GetEntityImpactRequest, v1beta1.GetEntityImpactResponse]( + httpClient, + baseURL+CompassServiceGetEntityImpactProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetEntityImpact")), + connect.WithClientOptions(opts...), + ), + upsertEdge: connect.NewClient[v1beta1.UpsertEdgeRequest, v1beta1.UpsertEdgeResponse]( + httpClient, + baseURL+CompassServiceUpsertEdgeProcedure, + connect.WithSchema(compassServiceMethods.ByName("UpsertEdge")), + connect.WithClientOptions(opts...), + ), + getEdges: connect.NewClient[v1beta1.GetEdgesRequest, v1beta1.GetEdgesResponse]( + httpClient, + baseURL+CompassServiceGetEdgesProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetEdges")), + connect.WithClientOptions(opts...), + ), + deleteEdge: connect.NewClient[v1beta1.DeleteEdgeRequest, v1beta1.DeleteEdgeResponse]( + httpClient, + baseURL+CompassServiceDeleteEdgeProcedure, + connect.WithSchema(compassServiceMethods.ByName("DeleteEdge")), + connect.WithClientOptions(opts...), + ), } } @@ -532,6 +654,18 @@ type compassServiceClient struct { getNamespace *connect.Client[v1beta1.GetNamespaceRequest, v1beta1.GetNamespaceResponse] updateNamespace *connect.Client[v1beta1.UpdateNamespaceRequest, v1beta1.UpdateNamespaceResponse] listNamespaces *connect.Client[v1beta1.ListNamespacesRequest, v1beta1.ListNamespacesResponse] + getAllEntities *connect.Client[v1beta1.GetAllEntitiesRequest, v1beta1.GetAllEntitiesResponse] + getEntityByID *connect.Client[v1beta1.GetEntityByIDRequest, v1beta1.GetEntityByIDResponse] + upsertEntity *connect.Client[v1beta1.UpsertEntityRequest, v1beta1.UpsertEntityResponse] + deleteEntity *connect.Client[v1beta1.DeleteEntityRequest, v1beta1.DeleteEntityResponse] + searchEntities *connect.Client[v1beta1.SearchEntitiesRequest, v1beta1.SearchEntitiesResponse] + suggestEntities *connect.Client[v1beta1.SuggestEntitiesRequest, v1beta1.SuggestEntitiesResponse] + getEntityTypes *connect.Client[v1beta1.GetEntityTypesRequest, v1beta1.GetEntityTypesResponse] + getEntityContext *connect.Client[v1beta1.GetEntityContextRequest, v1beta1.GetEntityContextResponse] + getEntityImpact *connect.Client[v1beta1.GetEntityImpactRequest, v1beta1.GetEntityImpactResponse] + upsertEdge *connect.Client[v1beta1.UpsertEdgeRequest, v1beta1.UpsertEdgeResponse] + getEdges *connect.Client[v1beta1.GetEdgesRequest, v1beta1.GetEdgesResponse] + deleteEdge *connect.Client[v1beta1.DeleteEdgeRequest, v1beta1.DeleteEdgeResponse] } // GetAllDiscussions calls raystack.compass.v1beta1.CompassService.GetAllDiscussions. @@ -749,6 +883,66 @@ func (c *compassServiceClient) ListNamespaces(ctx context.Context, req *connect. return c.listNamespaces.CallUnary(ctx, req) } +// GetAllEntities calls raystack.compass.v1beta1.CompassService.GetAllEntities. +func (c *compassServiceClient) GetAllEntities(ctx context.Context, req *connect.Request[v1beta1.GetAllEntitiesRequest]) (*connect.Response[v1beta1.GetAllEntitiesResponse], error) { + return c.getAllEntities.CallUnary(ctx, req) +} + +// GetEntityByID calls raystack.compass.v1beta1.CompassService.GetEntityByID. +func (c *compassServiceClient) GetEntityByID(ctx context.Context, req *connect.Request[v1beta1.GetEntityByIDRequest]) (*connect.Response[v1beta1.GetEntityByIDResponse], error) { + return c.getEntityByID.CallUnary(ctx, req) +} + +// UpsertEntity calls raystack.compass.v1beta1.CompassService.UpsertEntity. +func (c *compassServiceClient) UpsertEntity(ctx context.Context, req *connect.Request[v1beta1.UpsertEntityRequest]) (*connect.Response[v1beta1.UpsertEntityResponse], error) { + return c.upsertEntity.CallUnary(ctx, req) +} + +// DeleteEntity calls raystack.compass.v1beta1.CompassService.DeleteEntity. +func (c *compassServiceClient) DeleteEntity(ctx context.Context, req *connect.Request[v1beta1.DeleteEntityRequest]) (*connect.Response[v1beta1.DeleteEntityResponse], error) { + return c.deleteEntity.CallUnary(ctx, req) +} + +// SearchEntities calls raystack.compass.v1beta1.CompassService.SearchEntities. +func (c *compassServiceClient) SearchEntities(ctx context.Context, req *connect.Request[v1beta1.SearchEntitiesRequest]) (*connect.Response[v1beta1.SearchEntitiesResponse], error) { + return c.searchEntities.CallUnary(ctx, req) +} + +// SuggestEntities calls raystack.compass.v1beta1.CompassService.SuggestEntities. +func (c *compassServiceClient) SuggestEntities(ctx context.Context, req *connect.Request[v1beta1.SuggestEntitiesRequest]) (*connect.Response[v1beta1.SuggestEntitiesResponse], error) { + return c.suggestEntities.CallUnary(ctx, req) +} + +// GetEntityTypes calls raystack.compass.v1beta1.CompassService.GetEntityTypes. +func (c *compassServiceClient) GetEntityTypes(ctx context.Context, req *connect.Request[v1beta1.GetEntityTypesRequest]) (*connect.Response[v1beta1.GetEntityTypesResponse], error) { + return c.getEntityTypes.CallUnary(ctx, req) +} + +// GetEntityContext calls raystack.compass.v1beta1.CompassService.GetEntityContext. +func (c *compassServiceClient) GetEntityContext(ctx context.Context, req *connect.Request[v1beta1.GetEntityContextRequest]) (*connect.Response[v1beta1.GetEntityContextResponse], error) { + return c.getEntityContext.CallUnary(ctx, req) +} + +// GetEntityImpact calls raystack.compass.v1beta1.CompassService.GetEntityImpact. +func (c *compassServiceClient) GetEntityImpact(ctx context.Context, req *connect.Request[v1beta1.GetEntityImpactRequest]) (*connect.Response[v1beta1.GetEntityImpactResponse], error) { + return c.getEntityImpact.CallUnary(ctx, req) +} + +// UpsertEdge calls raystack.compass.v1beta1.CompassService.UpsertEdge. +func (c *compassServiceClient) UpsertEdge(ctx context.Context, req *connect.Request[v1beta1.UpsertEdgeRequest]) (*connect.Response[v1beta1.UpsertEdgeResponse], error) { + return c.upsertEdge.CallUnary(ctx, req) +} + +// GetEdges calls raystack.compass.v1beta1.CompassService.GetEdges. +func (c *compassServiceClient) GetEdges(ctx context.Context, req *connect.Request[v1beta1.GetEdgesRequest]) (*connect.Response[v1beta1.GetEdgesResponse], error) { + return c.getEdges.CallUnary(ctx, req) +} + +// DeleteEdge calls raystack.compass.v1beta1.CompassService.DeleteEdge. +func (c *compassServiceClient) DeleteEdge(ctx context.Context, req *connect.Request[v1beta1.DeleteEdgeRequest]) (*connect.Response[v1beta1.DeleteEdgeResponse], error) { + return c.deleteEdge.CallUnary(ctx, req) +} + // CompassServiceHandler is an implementation of the raystack.compass.v1beta1.CompassService // service. type CompassServiceHandler interface { @@ -800,6 +994,21 @@ type CompassServiceHandler interface { GetNamespace(context.Context, *connect.Request[v1beta1.GetNamespaceRequest]) (*connect.Response[v1beta1.GetNamespaceResponse], error) UpdateNamespace(context.Context, *connect.Request[v1beta1.UpdateNamespaceRequest]) (*connect.Response[v1beta1.UpdateNamespaceResponse], error) ListNamespaces(context.Context, *connect.Request[v1beta1.ListNamespacesRequest]) (*connect.Response[v1beta1.ListNamespacesResponse], error) + // Domain: Entity (v2) + GetAllEntities(context.Context, *connect.Request[v1beta1.GetAllEntitiesRequest]) (*connect.Response[v1beta1.GetAllEntitiesResponse], error) + GetEntityByID(context.Context, *connect.Request[v1beta1.GetEntityByIDRequest]) (*connect.Response[v1beta1.GetEntityByIDResponse], error) + UpsertEntity(context.Context, *connect.Request[v1beta1.UpsertEntityRequest]) (*connect.Response[v1beta1.UpsertEntityResponse], error) + DeleteEntity(context.Context, *connect.Request[v1beta1.DeleteEntityRequest]) (*connect.Response[v1beta1.DeleteEntityResponse], error) + SearchEntities(context.Context, *connect.Request[v1beta1.SearchEntitiesRequest]) (*connect.Response[v1beta1.SearchEntitiesResponse], error) + SuggestEntities(context.Context, *connect.Request[v1beta1.SuggestEntitiesRequest]) (*connect.Response[v1beta1.SuggestEntitiesResponse], error) + GetEntityTypes(context.Context, *connect.Request[v1beta1.GetEntityTypesRequest]) (*connect.Response[v1beta1.GetEntityTypesResponse], error) + // Domain: Entity Context & Impact (v2) + GetEntityContext(context.Context, *connect.Request[v1beta1.GetEntityContextRequest]) (*connect.Response[v1beta1.GetEntityContextResponse], error) + GetEntityImpact(context.Context, *connect.Request[v1beta1.GetEntityImpactRequest]) (*connect.Response[v1beta1.GetEntityImpactResponse], error) + // Domain: Edges (v2) + UpsertEdge(context.Context, *connect.Request[v1beta1.UpsertEdgeRequest]) (*connect.Response[v1beta1.UpsertEdgeResponse], error) + GetEdges(context.Context, *connect.Request[v1beta1.GetEdgesRequest]) (*connect.Response[v1beta1.GetEdgesResponse], error) + DeleteEdge(context.Context, *connect.Request[v1beta1.DeleteEdgeRequest]) (*connect.Response[v1beta1.DeleteEdgeResponse], error) } // NewCompassServiceHandler builds an HTTP handler from the service implementation. It returns the @@ -1067,6 +1276,78 @@ func NewCompassServiceHandler(svc CompassServiceHandler, opts ...connect.Handler connect.WithSchema(compassServiceMethods.ByName("ListNamespaces")), connect.WithHandlerOptions(opts...), ) + compassServiceGetAllEntitiesHandler := connect.NewUnaryHandler( + CompassServiceGetAllEntitiesProcedure, + svc.GetAllEntities, + connect.WithSchema(compassServiceMethods.ByName("GetAllEntities")), + connect.WithHandlerOptions(opts...), + ) + compassServiceGetEntityByIDHandler := connect.NewUnaryHandler( + CompassServiceGetEntityByIDProcedure, + svc.GetEntityByID, + connect.WithSchema(compassServiceMethods.ByName("GetEntityByID")), + connect.WithHandlerOptions(opts...), + ) + compassServiceUpsertEntityHandler := connect.NewUnaryHandler( + CompassServiceUpsertEntityProcedure, + svc.UpsertEntity, + connect.WithSchema(compassServiceMethods.ByName("UpsertEntity")), + connect.WithHandlerOptions(opts...), + ) + compassServiceDeleteEntityHandler := connect.NewUnaryHandler( + CompassServiceDeleteEntityProcedure, + svc.DeleteEntity, + connect.WithSchema(compassServiceMethods.ByName("DeleteEntity")), + connect.WithHandlerOptions(opts...), + ) + compassServiceSearchEntitiesHandler := connect.NewUnaryHandler( + CompassServiceSearchEntitiesProcedure, + svc.SearchEntities, + connect.WithSchema(compassServiceMethods.ByName("SearchEntities")), + connect.WithHandlerOptions(opts...), + ) + compassServiceSuggestEntitiesHandler := connect.NewUnaryHandler( + CompassServiceSuggestEntitiesProcedure, + svc.SuggestEntities, + connect.WithSchema(compassServiceMethods.ByName("SuggestEntities")), + connect.WithHandlerOptions(opts...), + ) + compassServiceGetEntityTypesHandler := connect.NewUnaryHandler( + CompassServiceGetEntityTypesProcedure, + svc.GetEntityTypes, + connect.WithSchema(compassServiceMethods.ByName("GetEntityTypes")), + connect.WithHandlerOptions(opts...), + ) + compassServiceGetEntityContextHandler := connect.NewUnaryHandler( + CompassServiceGetEntityContextProcedure, + svc.GetEntityContext, + connect.WithSchema(compassServiceMethods.ByName("GetEntityContext")), + connect.WithHandlerOptions(opts...), + ) + compassServiceGetEntityImpactHandler := connect.NewUnaryHandler( + CompassServiceGetEntityImpactProcedure, + svc.GetEntityImpact, + connect.WithSchema(compassServiceMethods.ByName("GetEntityImpact")), + connect.WithHandlerOptions(opts...), + ) + compassServiceUpsertEdgeHandler := connect.NewUnaryHandler( + CompassServiceUpsertEdgeProcedure, + svc.UpsertEdge, + connect.WithSchema(compassServiceMethods.ByName("UpsertEdge")), + connect.WithHandlerOptions(opts...), + ) + compassServiceGetEdgesHandler := connect.NewUnaryHandler( + CompassServiceGetEdgesProcedure, + svc.GetEdges, + connect.WithSchema(compassServiceMethods.ByName("GetEdges")), + connect.WithHandlerOptions(opts...), + ) + compassServiceDeleteEdgeHandler := connect.NewUnaryHandler( + CompassServiceDeleteEdgeProcedure, + svc.DeleteEdge, + connect.WithSchema(compassServiceMethods.ByName("DeleteEdge")), + connect.WithHandlerOptions(opts...), + ) return "/raystack.compass.v1beta1.CompassService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case CompassServiceGetAllDiscussionsProcedure: @@ -1155,6 +1436,30 @@ func NewCompassServiceHandler(svc CompassServiceHandler, opts ...connect.Handler compassServiceUpdateNamespaceHandler.ServeHTTP(w, r) case CompassServiceListNamespacesProcedure: compassServiceListNamespacesHandler.ServeHTTP(w, r) + case CompassServiceGetAllEntitiesProcedure: + compassServiceGetAllEntitiesHandler.ServeHTTP(w, r) + case CompassServiceGetEntityByIDProcedure: + compassServiceGetEntityByIDHandler.ServeHTTP(w, r) + case CompassServiceUpsertEntityProcedure: + compassServiceUpsertEntityHandler.ServeHTTP(w, r) + case CompassServiceDeleteEntityProcedure: + compassServiceDeleteEntityHandler.ServeHTTP(w, r) + case CompassServiceSearchEntitiesProcedure: + compassServiceSearchEntitiesHandler.ServeHTTP(w, r) + case CompassServiceSuggestEntitiesProcedure: + compassServiceSuggestEntitiesHandler.ServeHTTP(w, r) + case CompassServiceGetEntityTypesProcedure: + compassServiceGetEntityTypesHandler.ServeHTTP(w, r) + case CompassServiceGetEntityContextProcedure: + compassServiceGetEntityContextHandler.ServeHTTP(w, r) + case CompassServiceGetEntityImpactProcedure: + compassServiceGetEntityImpactHandler.ServeHTTP(w, r) + case CompassServiceUpsertEdgeProcedure: + compassServiceUpsertEdgeHandler.ServeHTTP(w, r) + case CompassServiceGetEdgesProcedure: + compassServiceGetEdgesHandler.ServeHTTP(w, r) + case CompassServiceDeleteEdgeProcedure: + compassServiceDeleteEdgeHandler.ServeHTTP(w, r) default: http.NotFound(w, r) } @@ -1335,3 +1640,51 @@ func (UnimplementedCompassServiceHandler) UpdateNamespace(context.Context, *conn func (UnimplementedCompassServiceHandler) ListNamespaces(context.Context, *connect.Request[v1beta1.ListNamespacesRequest]) (*connect.Response[v1beta1.ListNamespacesResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.ListNamespaces is not implemented")) } + +func (UnimplementedCompassServiceHandler) GetAllEntities(context.Context, *connect.Request[v1beta1.GetAllEntitiesRequest]) (*connect.Response[v1beta1.GetAllEntitiesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAllEntities is not implemented")) +} + +func (UnimplementedCompassServiceHandler) GetEntityByID(context.Context, *connect.Request[v1beta1.GetEntityByIDRequest]) (*connect.Response[v1beta1.GetEntityByIDResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityByID is not implemented")) +} + +func (UnimplementedCompassServiceHandler) UpsertEntity(context.Context, *connect.Request[v1beta1.UpsertEntityRequest]) (*connect.Response[v1beta1.UpsertEntityResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UpsertEntity is not implemented")) +} + +func (UnimplementedCompassServiceHandler) DeleteEntity(context.Context, *connect.Request[v1beta1.DeleteEntityRequest]) (*connect.Response[v1beta1.DeleteEntityResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.DeleteEntity is not implemented")) +} + +func (UnimplementedCompassServiceHandler) SearchEntities(context.Context, *connect.Request[v1beta1.SearchEntitiesRequest]) (*connect.Response[v1beta1.SearchEntitiesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.SearchEntities is not implemented")) +} + +func (UnimplementedCompassServiceHandler) SuggestEntities(context.Context, *connect.Request[v1beta1.SuggestEntitiesRequest]) (*connect.Response[v1beta1.SuggestEntitiesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.SuggestEntities is not implemented")) +} + +func (UnimplementedCompassServiceHandler) GetEntityTypes(context.Context, *connect.Request[v1beta1.GetEntityTypesRequest]) (*connect.Response[v1beta1.GetEntityTypesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityTypes is not implemented")) +} + +func (UnimplementedCompassServiceHandler) GetEntityContext(context.Context, *connect.Request[v1beta1.GetEntityContextRequest]) (*connect.Response[v1beta1.GetEntityContextResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityContext is not implemented")) +} + +func (UnimplementedCompassServiceHandler) GetEntityImpact(context.Context, *connect.Request[v1beta1.GetEntityImpactRequest]) (*connect.Response[v1beta1.GetEntityImpactResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityImpact is not implemented")) +} + +func (UnimplementedCompassServiceHandler) UpsertEdge(context.Context, *connect.Request[v1beta1.UpsertEdgeRequest]) (*connect.Response[v1beta1.UpsertEdgeResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UpsertEdge is not implemented")) +} + +func (UnimplementedCompassServiceHandler) GetEdges(context.Context, *connect.Request[v1beta1.GetEdgesRequest]) (*connect.Response[v1beta1.GetEdgesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEdges is not implemented")) +} + +func (UnimplementedCompassServiceHandler) DeleteEdge(context.Context, *connect.Request[v1beta1.DeleteEdgeRequest]) (*connect.Response[v1beta1.DeleteEdgeResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.DeleteEdge is not implemented")) +} diff --git a/gen/raystack/compass/v1beta1/service.pb.go b/gen/raystack/compass/v1beta1/service.pb.go index c7b20a30..9e8a757a 100644 --- a/gen/raystack/compass/v1beta1/service.pb.go +++ b/gen/raystack/compass/v1beta1/service.pb.go @@ -6018,6 +6018,1518 @@ func (x *Namespace) GetMetadata() *structpb.Struct { return nil } +type Entity struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Urn string `protobuf:"bytes,2,opt,name=urn,proto3" json:"urn,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` + Properties *structpb.Struct `protobuf:"bytes,6,opt,name=properties,proto3" json:"properties,omitempty"` + Source string `protobuf:"bytes,7,opt,name=source,proto3" json:"source,omitempty"` + ValidFrom *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=valid_from,json=validFrom,proto3" json:"valid_from,omitempty"` + ValidTo *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=valid_to,json=validTo,proto3" json:"valid_to,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Entity) Reset() { + *x = Entity{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[103] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Entity) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Entity) ProtoMessage() {} + +func (x *Entity) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[103] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Entity.ProtoReflect.Descriptor instead. +func (*Entity) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{103} +} + +func (x *Entity) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Entity) GetUrn() string { + if x != nil { + return x.Urn + } + return "" +} + +func (x *Entity) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *Entity) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Entity) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Entity) GetProperties() *structpb.Struct { + if x != nil { + return x.Properties + } + return nil +} + +func (x *Entity) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *Entity) GetValidFrom() *timestamppb.Timestamp { + if x != nil { + return x.ValidFrom + } + return nil +} + +func (x *Entity) GetValidTo() *timestamppb.Timestamp { + if x != nil { + return x.ValidTo + } + return nil +} + +func (x *Entity) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *Entity) GetUpdatedAt() *timestamppb.Timestamp { + if x != nil { + return x.UpdatedAt + } + return nil +} + +type Edge struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + SourceUrn string `protobuf:"bytes,2,opt,name=source_urn,json=sourceUrn,proto3" json:"source_urn,omitempty"` + TargetUrn string `protobuf:"bytes,3,opt,name=target_urn,json=targetUrn,proto3" json:"target_urn,omitempty"` + Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` + Properties *structpb.Struct `protobuf:"bytes,5,opt,name=properties,proto3" json:"properties,omitempty"` + Source string `protobuf:"bytes,6,opt,name=source,proto3" json:"source,omitempty"` + ValidFrom *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=valid_from,json=validFrom,proto3" json:"valid_from,omitempty"` + ValidTo *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=valid_to,json=validTo,proto3" json:"valid_to,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Edge) Reset() { + *x = Edge{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[104] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Edge) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Edge) ProtoMessage() {} + +func (x *Edge) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[104] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Edge.ProtoReflect.Descriptor instead. +func (*Edge) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{104} +} + +func (x *Edge) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Edge) GetSourceUrn() string { + if x != nil { + return x.SourceUrn + } + return "" +} + +func (x *Edge) GetTargetUrn() string { + if x != nil { + return x.TargetUrn + } + return "" +} + +func (x *Edge) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *Edge) GetProperties() *structpb.Struct { + if x != nil { + return x.Properties + } + return nil +} + +func (x *Edge) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *Edge) GetValidFrom() *timestamppb.Timestamp { + if x != nil { + return x.ValidFrom + } + return nil +} + +func (x *Edge) GetValidTo() *timestamppb.Timestamp { + if x != nil { + return x.ValidTo + } + return nil +} + +func (x *Edge) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +type GetAllEntitiesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Types string `protobuf:"bytes,1,opt,name=types,proto3" json:"types,omitempty"` + Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"` + Q string `protobuf:"bytes,3,opt,name=q,proto3" json:"q,omitempty"` + Size uint32 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"` + Offset uint32 `protobuf:"varint,5,opt,name=offset,proto3" json:"offset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetAllEntitiesRequest) Reset() { + *x = GetAllEntitiesRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[105] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetAllEntitiesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllEntitiesRequest) ProtoMessage() {} + +func (x *GetAllEntitiesRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[105] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAllEntitiesRequest.ProtoReflect.Descriptor instead. +func (*GetAllEntitiesRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{105} +} + +func (x *GetAllEntitiesRequest) GetTypes() string { + if x != nil { + return x.Types + } + return "" +} + +func (x *GetAllEntitiesRequest) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *GetAllEntitiesRequest) GetQ() string { + if x != nil { + return x.Q + } + return "" +} + +func (x *GetAllEntitiesRequest) GetSize() uint32 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *GetAllEntitiesRequest) GetOffset() uint32 { + if x != nil { + return x.Offset + } + return 0 +} + +type GetAllEntitiesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Data []*Entity `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + Total uint32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetAllEntitiesResponse) Reset() { + *x = GetAllEntitiesResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[106] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetAllEntitiesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllEntitiesResponse) ProtoMessage() {} + +func (x *GetAllEntitiesResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[106] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAllEntitiesResponse.ProtoReflect.Descriptor instead. +func (*GetAllEntitiesResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{106} +} + +func (x *GetAllEntitiesResponse) GetData() []*Entity { + if x != nil { + return x.Data + } + return nil +} + +func (x *GetAllEntitiesResponse) GetTotal() uint32 { + if x != nil { + return x.Total + } + return 0 +} + +type GetEntityByIDRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEntityByIDRequest) Reset() { + *x = GetEntityByIDRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[107] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEntityByIDRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEntityByIDRequest) ProtoMessage() {} + +func (x *GetEntityByIDRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[107] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEntityByIDRequest.ProtoReflect.Descriptor instead. +func (*GetEntityByIDRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{107} +} + +func (x *GetEntityByIDRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetEntityByIDResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Data *Entity `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEntityByIDResponse) Reset() { + *x = GetEntityByIDResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[108] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEntityByIDResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEntityByIDResponse) ProtoMessage() {} + +func (x *GetEntityByIDResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[108] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEntityByIDResponse.ProtoReflect.Descriptor instead. +func (*GetEntityByIDResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{108} +} + +func (x *GetEntityByIDResponse) GetData() *Entity { + if x != nil { + return x.Data + } + return nil +} + +type UpsertEntityRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` + Properties *structpb.Struct `protobuf:"bytes,5,opt,name=properties,proto3" json:"properties,omitempty"` + Source string `protobuf:"bytes,6,opt,name=source,proto3" json:"source,omitempty"` + Upstreams []string `protobuf:"bytes,7,rep,name=upstreams,proto3" json:"upstreams,omitempty"` + Downstreams []string `protobuf:"bytes,8,rep,name=downstreams,proto3" json:"downstreams,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpsertEntityRequest) Reset() { + *x = UpsertEntityRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[109] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpsertEntityRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpsertEntityRequest) ProtoMessage() {} + +func (x *UpsertEntityRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[109] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpsertEntityRequest.ProtoReflect.Descriptor instead. +func (*UpsertEntityRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{109} +} + +func (x *UpsertEntityRequest) GetUrn() string { + if x != nil { + return x.Urn + } + return "" +} + +func (x *UpsertEntityRequest) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *UpsertEntityRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpsertEntityRequest) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *UpsertEntityRequest) GetProperties() *structpb.Struct { + if x != nil { + return x.Properties + } + return nil +} + +func (x *UpsertEntityRequest) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *UpsertEntityRequest) GetUpstreams() []string { + if x != nil { + return x.Upstreams + } + return nil +} + +func (x *UpsertEntityRequest) GetDownstreams() []string { + if x != nil { + return x.Downstreams + } + return nil +} + +type UpsertEntityResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpsertEntityResponse) Reset() { + *x = UpsertEntityResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[110] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpsertEntityResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpsertEntityResponse) ProtoMessage() {} + +func (x *UpsertEntityResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[110] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpsertEntityResponse.ProtoReflect.Descriptor instead. +func (*UpsertEntityResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{110} +} + +func (x *UpsertEntityResponse) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type DeleteEntityRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteEntityRequest) Reset() { + *x = DeleteEntityRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[111] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteEntityRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteEntityRequest) ProtoMessage() {} + +func (x *DeleteEntityRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[111] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteEntityRequest.ProtoReflect.Descriptor instead. +func (*DeleteEntityRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{111} +} + +func (x *DeleteEntityRequest) GetUrn() string { + if x != nil { + return x.Urn + } + return "" +} + +type DeleteEntityResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteEntityResponse) Reset() { + *x = DeleteEntityResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[112] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteEntityResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteEntityResponse) ProtoMessage() {} + +func (x *DeleteEntityResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[112] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteEntityResponse.ProtoReflect.Descriptor instead. +func (*DeleteEntityResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{112} +} + +type SearchEntitiesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Types string `protobuf:"bytes,2,opt,name=types,proto3" json:"types,omitempty"` + Source string `protobuf:"bytes,3,opt,name=source,proto3" json:"source,omitempty"` + Mode string `protobuf:"bytes,4,opt,name=mode,proto3" json:"mode,omitempty"` // keyword, semantic, hybrid + Size uint32 `protobuf:"varint,5,opt,name=size,proto3" json:"size,omitempty"` + Offset uint32 `protobuf:"varint,6,opt,name=offset,proto3" json:"offset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SearchEntitiesRequest) Reset() { + *x = SearchEntitiesRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[113] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SearchEntitiesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchEntitiesRequest) ProtoMessage() {} + +func (x *SearchEntitiesRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[113] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchEntitiesRequest.ProtoReflect.Descriptor instead. +func (*SearchEntitiesRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{113} +} + +func (x *SearchEntitiesRequest) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *SearchEntitiesRequest) GetTypes() string { + if x != nil { + return x.Types + } + return "" +} + +func (x *SearchEntitiesRequest) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *SearchEntitiesRequest) GetMode() string { + if x != nil { + return x.Mode + } + return "" +} + +func (x *SearchEntitiesRequest) GetSize() uint32 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *SearchEntitiesRequest) GetOffset() uint32 { + if x != nil { + return x.Offset + } + return 0 +} + +type SearchEntitiesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Data []*Entity `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SearchEntitiesResponse) Reset() { + *x = SearchEntitiesResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[114] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SearchEntitiesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchEntitiesResponse) ProtoMessage() {} + +func (x *SearchEntitiesResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[114] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchEntitiesResponse.ProtoReflect.Descriptor instead. +func (*SearchEntitiesResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{114} +} + +func (x *SearchEntitiesResponse) GetData() []*Entity { + if x != nil { + return x.Data + } + return nil +} + +type SuggestEntitiesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SuggestEntitiesRequest) Reset() { + *x = SuggestEntitiesRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[115] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SuggestEntitiesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SuggestEntitiesRequest) ProtoMessage() {} + +func (x *SuggestEntitiesRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[115] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SuggestEntitiesRequest.ProtoReflect.Descriptor instead. +func (*SuggestEntitiesRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{115} +} + +func (x *SuggestEntitiesRequest) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +type SuggestEntitiesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Data []string `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SuggestEntitiesResponse) Reset() { + *x = SuggestEntitiesResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[116] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SuggestEntitiesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SuggestEntitiesResponse) ProtoMessage() {} + +func (x *SuggestEntitiesResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[116] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SuggestEntitiesResponse.ProtoReflect.Descriptor instead. +func (*SuggestEntitiesResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{116} +} + +func (x *SuggestEntitiesResponse) GetData() []string { + if x != nil { + return x.Data + } + return nil +} + +type GetEntityTypesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEntityTypesRequest) Reset() { + *x = GetEntityTypesRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[117] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEntityTypesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEntityTypesRequest) ProtoMessage() {} + +func (x *GetEntityTypesRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[117] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEntityTypesRequest.ProtoReflect.Descriptor instead. +func (*GetEntityTypesRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{117} +} + +type GetEntityTypesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Data []*Type `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEntityTypesResponse) Reset() { + *x = GetEntityTypesResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[118] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEntityTypesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEntityTypesResponse) ProtoMessage() {} + +func (x *GetEntityTypesResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[118] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEntityTypesResponse.ProtoReflect.Descriptor instead. +func (*GetEntityTypesResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{118} +} + +func (x *GetEntityTypesResponse) GetData() []*Type { + if x != nil { + return x.Data + } + return nil +} + +type GetEntityContextRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` + Depth uint32 `protobuf:"varint,2,opt,name=depth,proto3" json:"depth,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEntityContextRequest) Reset() { + *x = GetEntityContextRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[119] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEntityContextRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEntityContextRequest) ProtoMessage() {} + +func (x *GetEntityContextRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[119] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEntityContextRequest.ProtoReflect.Descriptor instead. +func (*GetEntityContextRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{119} +} + +func (x *GetEntityContextRequest) GetUrn() string { + if x != nil { + return x.Urn + } + return "" +} + +func (x *GetEntityContextRequest) GetDepth() uint32 { + if x != nil { + return x.Depth + } + return 0 +} + +type GetEntityContextResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Entity *Entity `protobuf:"bytes,1,opt,name=entity,proto3" json:"entity,omitempty"` + Edges []*Edge `protobuf:"bytes,2,rep,name=edges,proto3" json:"edges,omitempty"` + Related []*Entity `protobuf:"bytes,3,rep,name=related,proto3" json:"related,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEntityContextResponse) Reset() { + *x = GetEntityContextResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[120] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEntityContextResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEntityContextResponse) ProtoMessage() {} + +func (x *GetEntityContextResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[120] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEntityContextResponse.ProtoReflect.Descriptor instead. +func (*GetEntityContextResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{120} +} + +func (x *GetEntityContextResponse) GetEntity() *Entity { + if x != nil { + return x.Entity + } + return nil +} + +func (x *GetEntityContextResponse) GetEdges() []*Edge { + if x != nil { + return x.Edges + } + return nil +} + +func (x *GetEntityContextResponse) GetRelated() []*Entity { + if x != nil { + return x.Related + } + return nil +} + +type GetEntityImpactRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` + Depth uint32 `protobuf:"varint,2,opt,name=depth,proto3" json:"depth,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEntityImpactRequest) Reset() { + *x = GetEntityImpactRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[121] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEntityImpactRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEntityImpactRequest) ProtoMessage() {} + +func (x *GetEntityImpactRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[121] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEntityImpactRequest.ProtoReflect.Descriptor instead. +func (*GetEntityImpactRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{121} +} + +func (x *GetEntityImpactRequest) GetUrn() string { + if x != nil { + return x.Urn + } + return "" +} + +func (x *GetEntityImpactRequest) GetDepth() uint32 { + if x != nil { + return x.Depth + } + return 0 +} + +type GetEntityImpactResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Edges []*Edge `protobuf:"bytes,1,rep,name=edges,proto3" json:"edges,omitempty"` + Affected []*Entity `protobuf:"bytes,2,rep,name=affected,proto3" json:"affected,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEntityImpactResponse) Reset() { + *x = GetEntityImpactResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[122] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEntityImpactResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEntityImpactResponse) ProtoMessage() {} + +func (x *GetEntityImpactResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[122] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEntityImpactResponse.ProtoReflect.Descriptor instead. +func (*GetEntityImpactResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{122} +} + +func (x *GetEntityImpactResponse) GetEdges() []*Edge { + if x != nil { + return x.Edges + } + return nil +} + +func (x *GetEntityImpactResponse) GetAffected() []*Entity { + if x != nil { + return x.Affected + } + return nil +} + +type UpsertEdgeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SourceUrn string `protobuf:"bytes,1,opt,name=source_urn,json=sourceUrn,proto3" json:"source_urn,omitempty"` + TargetUrn string `protobuf:"bytes,2,opt,name=target_urn,json=targetUrn,proto3" json:"target_urn,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + Properties *structpb.Struct `protobuf:"bytes,4,opt,name=properties,proto3" json:"properties,omitempty"` + Source string `protobuf:"bytes,5,opt,name=source,proto3" json:"source,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpsertEdgeRequest) Reset() { + *x = UpsertEdgeRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[123] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpsertEdgeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpsertEdgeRequest) ProtoMessage() {} + +func (x *UpsertEdgeRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[123] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpsertEdgeRequest.ProtoReflect.Descriptor instead. +func (*UpsertEdgeRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{123} +} + +func (x *UpsertEdgeRequest) GetSourceUrn() string { + if x != nil { + return x.SourceUrn + } + return "" +} + +func (x *UpsertEdgeRequest) GetTargetUrn() string { + if x != nil { + return x.TargetUrn + } + return "" +} + +func (x *UpsertEdgeRequest) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *UpsertEdgeRequest) GetProperties() *structpb.Struct { + if x != nil { + return x.Properties + } + return nil +} + +func (x *UpsertEdgeRequest) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +type UpsertEdgeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpsertEdgeResponse) Reset() { + *x = UpsertEdgeResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[124] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpsertEdgeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpsertEdgeResponse) ProtoMessage() {} + +func (x *UpsertEdgeResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[124] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpsertEdgeResponse.ProtoReflect.Descriptor instead. +func (*UpsertEdgeResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{124} +} + +func (x *UpsertEdgeResponse) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetEdgesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` + Direction string `protobuf:"bytes,2,opt,name=direction,proto3" json:"direction,omitempty"` // outgoing, incoming, both (default: both) + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` // filter by edge type + CurrentOnly bool `protobuf:"varint,4,opt,name=current_only,json=currentOnly,proto3" json:"current_only,omitempty"` // only current edges (valid_to IS NULL) + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEdgesRequest) Reset() { + *x = GetEdgesRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[125] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEdgesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEdgesRequest) ProtoMessage() {} + +func (x *GetEdgesRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[125] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEdgesRequest.ProtoReflect.Descriptor instead. +func (*GetEdgesRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{125} +} + +func (x *GetEdgesRequest) GetUrn() string { + if x != nil { + return x.Urn + } + return "" +} + +func (x *GetEdgesRequest) GetDirection() string { + if x != nil { + return x.Direction + } + return "" +} + +func (x *GetEdgesRequest) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *GetEdgesRequest) GetCurrentOnly() bool { + if x != nil { + return x.CurrentOnly + } + return false +} + +type GetEdgesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Data []*Edge `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEdgesResponse) Reset() { + *x = GetEdgesResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[126] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEdgesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEdgesResponse) ProtoMessage() {} + +func (x *GetEdgesResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[126] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEdgesResponse.ProtoReflect.Descriptor instead. +func (*GetEdgesResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{126} +} + +func (x *GetEdgesResponse) GetData() []*Edge { + if x != nil { + return x.Data + } + return nil +} + +type DeleteEdgeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SourceUrn string `protobuf:"bytes,1,opt,name=source_urn,json=sourceUrn,proto3" json:"source_urn,omitempty"` + TargetUrn string `protobuf:"bytes,2,opt,name=target_urn,json=targetUrn,proto3" json:"target_urn,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteEdgeRequest) Reset() { + *x = DeleteEdgeRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[127] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteEdgeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteEdgeRequest) ProtoMessage() {} + +func (x *DeleteEdgeRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[127] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteEdgeRequest.ProtoReflect.Descriptor instead. +func (*DeleteEdgeRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{127} +} + +func (x *DeleteEdgeRequest) GetSourceUrn() string { + if x != nil { + return x.SourceUrn + } + return "" +} + +func (x *DeleteEdgeRequest) GetTargetUrn() string { + if x != nil { + return x.TargetUrn + } + return "" +} + +func (x *DeleteEdgeRequest) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +type DeleteEdgeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteEdgeResponse) Reset() { + *x = DeleteEdgeResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[128] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteEdgeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteEdgeResponse) ProtoMessage() {} + +func (x *DeleteEdgeResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[128] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteEdgeResponse.ProtoReflect.Descriptor instead. +func (*DeleteEdgeResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{128} +} + type GetGraphResponse_ProbesInfo struct { state protoimpl.MessageState `protogen:"open.v1"` Latest *Probe `protobuf:"bytes,1,opt,name=latest,proto3" json:"latest,omitempty"` @@ -6027,7 +7539,7 @@ type GetGraphResponse_ProbesInfo struct { func (x *GetGraphResponse_ProbesInfo) Reset() { *x = GetGraphResponse_ProbesInfo{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[106] + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6039,7 +7551,7 @@ func (x *GetGraphResponse_ProbesInfo) String() string { func (*GetGraphResponse_ProbesInfo) ProtoMessage() {} func (x *GetGraphResponse_ProbesInfo) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[106] + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[132] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6071,7 +7583,7 @@ type GetGraphResponse_NodeAttributes struct { func (x *GetGraphResponse_NodeAttributes) Reset() { *x = GetGraphResponse_NodeAttributes{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[107] + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6083,7 +7595,7 @@ func (x *GetGraphResponse_NodeAttributes) String() string { func (*GetGraphResponse_NodeAttributes) ProtoMessage() {} func (x *GetGraphResponse_NodeAttributes) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[107] + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[133] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6123,7 +7635,7 @@ type UpsertAssetRequest_Asset struct { func (x *UpsertAssetRequest_Asset) Reset() { *x = UpsertAssetRequest_Asset{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[111] + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6135,7 +7647,7 @@ func (x *UpsertAssetRequest_Asset) String() string { func (*UpsertAssetRequest_Asset) ProtoMessage() {} func (x *UpsertAssetRequest_Asset) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[111] + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[137] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6231,7 +7743,7 @@ type UpsertPatchAssetRequest_Asset struct { func (x *UpsertPatchAssetRequest_Asset) Reset() { *x = UpsertPatchAssetRequest_Asset{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[113] + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6243,7 +7755,7 @@ func (x *UpsertPatchAssetRequest_Asset) String() string { func (*UpsertPatchAssetRequest_Asset) ProtoMessage() {} func (x *UpsertPatchAssetRequest_Asset) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[113] + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[139] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6335,7 +7847,7 @@ type CreateAssetProbeRequest_Probe struct { func (x *CreateAssetProbeRequest_Probe) Reset() { *x = CreateAssetProbeRequest_Probe{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[115] + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[141] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6347,7 +7859,7 @@ func (x *CreateAssetProbeRequest_Probe) String() string { func (*CreateAssetProbeRequest_Probe) ProtoMessage() {} func (x *CreateAssetProbeRequest_Probe) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[115] + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[141] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6888,7 +8400,125 @@ const file_raystack_compass_v1beta1_service_proto_rawDesc = "" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1b\n" + "\x04name\x18\x02 \x01(\tB\a\xbaH\x04r\x02\x10\x03R\x04name\x12\x14\n" + "\x05state\x18\x03 \x01(\tR\x05state\x123\n" + - "\bmetadata\x18\x04 \x01(\v2\x17.google.protobuf.StructR\bmetadata2\xde(\n" + + "\bmetadata\x18\x04 \x01(\v2\x17.google.protobuf.StructR\bmetadata\"\xad\x03\n" + + "\x06Entity\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x10\n" + + "\x03urn\x18\x02 \x01(\tR\x03urn\x12\x12\n" + + "\x04type\x18\x03 \x01(\tR\x04type\x12\x12\n" + + "\x04name\x18\x04 \x01(\tR\x04name\x12 \n" + + "\vdescription\x18\x05 \x01(\tR\vdescription\x127\n" + + "\n" + + "properties\x18\x06 \x01(\v2\x17.google.protobuf.StructR\n" + + "properties\x12\x16\n" + + "\x06source\x18\a \x01(\tR\x06source\x129\n" + + "\n" + + "valid_from\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\tvalidFrom\x125\n" + + "\bvalid_to\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\avalidTo\x129\n" + + "\n" + + "created_at\x18\n" + + " \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" + + "\n" + + "updated_at\x18\v \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\"\xe6\x02\n" + + "\x04Edge\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1d\n" + + "\n" + + "source_urn\x18\x02 \x01(\tR\tsourceUrn\x12\x1d\n" + + "\n" + + "target_urn\x18\x03 \x01(\tR\ttargetUrn\x12\x12\n" + + "\x04type\x18\x04 \x01(\tR\x04type\x127\n" + + "\n" + + "properties\x18\x05 \x01(\v2\x17.google.protobuf.StructR\n" + + "properties\x12\x16\n" + + "\x06source\x18\x06 \x01(\tR\x06source\x129\n" + + "\n" + + "valid_from\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\tvalidFrom\x125\n" + + "\bvalid_to\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\avalidTo\x129\n" + + "\n" + + "created_at\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\"\x91\x01\n" + + "\x15GetAllEntitiesRequest\x12\x14\n" + + "\x05types\x18\x01 \x01(\tR\x05types\x12\x16\n" + + "\x06source\x18\x02 \x01(\tR\x06source\x12\f\n" + + "\x01q\x18\x03 \x01(\tR\x01q\x12\x1b\n" + + "\x04size\x18\x04 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + + "\x06offset\x18\x05 \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"d\n" + + "\x16GetAllEntitiesResponse\x124\n" + + "\x04data\x18\x01 \x03(\v2 .raystack.compass.v1beta1.EntityR\x04data\x12\x14\n" + + "\x05total\x18\x02 \x01(\rR\x05total\"&\n" + + "\x14GetEntityByIDRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"M\n" + + "\x15GetEntityByIDResponse\x124\n" + + "\x04data\x18\x01 \x01(\v2 .raystack.compass.v1beta1.EntityR\x04data\"\x9d\x02\n" + + "\x13UpsertEntityRequest\x12\x19\n" + + "\x03urn\x18\x01 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x03urn\x12\x1b\n" + + "\x04type\x18\x02 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x04type\x12\x1b\n" + + "\x04name\x18\x03 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x04name\x12 \n" + + "\vdescription\x18\x04 \x01(\tR\vdescription\x127\n" + + "\n" + + "properties\x18\x05 \x01(\v2\x17.google.protobuf.StructR\n" + + "properties\x12\x16\n" + + "\x06source\x18\x06 \x01(\tR\x06source\x12\x1c\n" + + "\tupstreams\x18\a \x03(\tR\tupstreams\x12 \n" + + "\vdownstreams\x18\b \x03(\tR\vdownstreams\"&\n" + + "\x14UpsertEntityResponse\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"0\n" + + "\x13DeleteEntityRequest\x12\x19\n" + + "\x03urn\x18\x01 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x03urn\"\x16\n" + + "\x14DeleteEntityResponse\"\xab\x01\n" + + "\x15SearchEntitiesRequest\x12\x12\n" + + "\x04text\x18\x01 \x01(\tR\x04text\x12\x14\n" + + "\x05types\x18\x02 \x01(\tR\x05types\x12\x16\n" + + "\x06source\x18\x03 \x01(\tR\x06source\x12\x12\n" + + "\x04mode\x18\x04 \x01(\tR\x04mode\x12\x1b\n" + + "\x04size\x18\x05 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + + "\x06offset\x18\x06 \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"N\n" + + "\x16SearchEntitiesResponse\x124\n" + + "\x04data\x18\x01 \x03(\v2 .raystack.compass.v1beta1.EntityR\x04data\",\n" + + "\x16SuggestEntitiesRequest\x12\x12\n" + + "\x04text\x18\x01 \x01(\tR\x04text\"-\n" + + "\x17SuggestEntitiesResponse\x12\x12\n" + + "\x04data\x18\x01 \x03(\tR\x04data\"\x17\n" + + "\x15GetEntityTypesRequest\"L\n" + + "\x16GetEntityTypesResponse\x122\n" + + "\x04data\x18\x01 \x03(\v2\x1e.raystack.compass.v1beta1.TypeR\x04data\"J\n" + + "\x17GetEntityContextRequest\x12\x19\n" + + "\x03urn\x18\x01 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x03urn\x12\x14\n" + + "\x05depth\x18\x02 \x01(\rR\x05depth\"\xc6\x01\n" + + "\x18GetEntityContextResponse\x128\n" + + "\x06entity\x18\x01 \x01(\v2 .raystack.compass.v1beta1.EntityR\x06entity\x124\n" + + "\x05edges\x18\x02 \x03(\v2\x1e.raystack.compass.v1beta1.EdgeR\x05edges\x12:\n" + + "\arelated\x18\x03 \x03(\v2 .raystack.compass.v1beta1.EntityR\arelated\"I\n" + + "\x16GetEntityImpactRequest\x12\x19\n" + + "\x03urn\x18\x01 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x03urn\x12\x14\n" + + "\x05depth\x18\x02 \x01(\rR\x05depth\"\x8d\x01\n" + + "\x17GetEntityImpactResponse\x124\n" + + "\x05edges\x18\x01 \x03(\v2\x1e.raystack.compass.v1beta1.EdgeR\x05edges\x12<\n" + + "\baffected\x18\x02 \x03(\v2 .raystack.compass.v1beta1.EntityR\baffected\"\xd1\x01\n" + + "\x11UpsertEdgeRequest\x12&\n" + + "\n" + + "source_urn\x18\x01 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\tsourceUrn\x12&\n" + + "\n" + + "target_urn\x18\x02 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\ttargetUrn\x12\x1b\n" + + "\x04type\x18\x03 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x04type\x127\n" + + "\n" + + "properties\x18\x04 \x01(\v2\x17.google.protobuf.StructR\n" + + "properties\x12\x16\n" + + "\x06source\x18\x05 \x01(\tR\x06source\"$\n" + + "\x12UpsertEdgeResponse\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"\x81\x01\n" + + "\x0fGetEdgesRequest\x12\x19\n" + + "\x03urn\x18\x01 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x03urn\x12\x1c\n" + + "\tdirection\x18\x02 \x01(\tR\tdirection\x12\x12\n" + + "\x04type\x18\x03 \x01(\tR\x04type\x12!\n" + + "\fcurrent_only\x18\x04 \x01(\bR\vcurrentOnly\"F\n" + + "\x10GetEdgesResponse\x122\n" + + "\x04data\x18\x01 \x03(\v2\x1e.raystack.compass.v1beta1.EdgeR\x04data\"\x80\x01\n" + + "\x11DeleteEdgeRequest\x12&\n" + + "\n" + + "source_urn\x18\x01 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\tsourceUrn\x12&\n" + + "\n" + + "target_urn\x18\x02 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\ttargetUrn\x12\x1b\n" + + "\x04type\x18\x03 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x04type\"\x14\n" + + "\x12DeleteEdgeResponse2\xc53\n" + "\x0eCompassService\x12~\n" + "\x11GetAllDiscussions\x122.raystack.compass.v1beta1.GetAllDiscussionsRequest\x1a3.raystack.compass.v1beta1.GetAllDiscussionsResponse\"\x00\x12{\n" + "\x10CreateDiscussion\x121.raystack.compass.v1beta1.CreateDiscussionRequest\x1a2.raystack.compass.v1beta1.CreateDiscussionResponse\"\x00\x12r\n" + @@ -6933,7 +8563,21 @@ const file_raystack_compass_v1beta1_service_proto_rawDesc = "" + "\x0fCreateNamespace\x120.raystack.compass.v1beta1.CreateNamespaceRequest\x1a1.raystack.compass.v1beta1.CreateNamespaceResponse\"\x00\x12o\n" + "\fGetNamespace\x12-.raystack.compass.v1beta1.GetNamespaceRequest\x1a..raystack.compass.v1beta1.GetNamespaceResponse\"\x00\x12x\n" + "\x0fUpdateNamespace\x120.raystack.compass.v1beta1.UpdateNamespaceRequest\x1a1.raystack.compass.v1beta1.UpdateNamespaceResponse\"\x00\x12u\n" + - "\x0eListNamespaces\x12/.raystack.compass.v1beta1.ListNamespacesRequest\x1a0.raystack.compass.v1beta1.ListNamespacesResponse\"\x00B\xf7\x01\n" + + "\x0eListNamespaces\x12/.raystack.compass.v1beta1.ListNamespacesRequest\x1a0.raystack.compass.v1beta1.ListNamespacesResponse\"\x00\x12u\n" + + "\x0eGetAllEntities\x12/.raystack.compass.v1beta1.GetAllEntitiesRequest\x1a0.raystack.compass.v1beta1.GetAllEntitiesResponse\"\x00\x12r\n" + + "\rGetEntityByID\x12..raystack.compass.v1beta1.GetEntityByIDRequest\x1a/.raystack.compass.v1beta1.GetEntityByIDResponse\"\x00\x12o\n" + + "\fUpsertEntity\x12-.raystack.compass.v1beta1.UpsertEntityRequest\x1a..raystack.compass.v1beta1.UpsertEntityResponse\"\x00\x12o\n" + + "\fDeleteEntity\x12-.raystack.compass.v1beta1.DeleteEntityRequest\x1a..raystack.compass.v1beta1.DeleteEntityResponse\"\x00\x12u\n" + + "\x0eSearchEntities\x12/.raystack.compass.v1beta1.SearchEntitiesRequest\x1a0.raystack.compass.v1beta1.SearchEntitiesResponse\"\x00\x12x\n" + + "\x0fSuggestEntities\x120.raystack.compass.v1beta1.SuggestEntitiesRequest\x1a1.raystack.compass.v1beta1.SuggestEntitiesResponse\"\x00\x12u\n" + + "\x0eGetEntityTypes\x12/.raystack.compass.v1beta1.GetEntityTypesRequest\x1a0.raystack.compass.v1beta1.GetEntityTypesResponse\"\x00\x12{\n" + + "\x10GetEntityContext\x121.raystack.compass.v1beta1.GetEntityContextRequest\x1a2.raystack.compass.v1beta1.GetEntityContextResponse\"\x00\x12x\n" + + "\x0fGetEntityImpact\x120.raystack.compass.v1beta1.GetEntityImpactRequest\x1a1.raystack.compass.v1beta1.GetEntityImpactResponse\"\x00\x12i\n" + + "\n" + + "UpsertEdge\x12+.raystack.compass.v1beta1.UpsertEdgeRequest\x1a,.raystack.compass.v1beta1.UpsertEdgeResponse\"\x00\x12c\n" + + "\bGetEdges\x12).raystack.compass.v1beta1.GetEdgesRequest\x1a*.raystack.compass.v1beta1.GetEdgesResponse\"\x00\x12i\n" + + "\n" + + "DeleteEdge\x12+.raystack.compass.v1beta1.DeleteEdgeRequest\x1a,.raystack.compass.v1beta1.DeleteEdgeResponse\"\x00B\xf7\x01\n" + "\x1ccom.raystack.compass.v1beta1B\fServiceProtoP\x01ZGgithub.com/raystack/compass/gen/raystack/compass/v1beta1;compassv1beta1\xa2\x02\x03RCX\xaa\x02\x18Raystack.Compass.V1beta1\xca\x02\x18Raystack\\Compass\\V1beta1\xe2\x02$Raystack\\Compass\\V1beta1\\GPBMetadata\xea\x02\x1aRaystack::Compass::V1beta1b\x06proto3" var ( @@ -6948,7 +8592,7 @@ func file_raystack_compass_v1beta1_service_proto_rawDescGZIP() []byte { return file_raystack_compass_v1beta1_service_proto_rawDescData } -var file_raystack_compass_v1beta1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 117) +var file_raystack_compass_v1beta1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 143) var file_raystack_compass_v1beta1_service_proto_goTypes = []any{ (*GetAllDiscussionsRequest)(nil), // 0: raystack.compass.v1beta1.GetAllDiscussionsRequest (*GetAllDiscussionsResponse)(nil), // 1: raystack.compass.v1beta1.GetAllDiscussionsResponse @@ -7053,55 +8697,81 @@ var file_raystack_compass_v1beta1_service_proto_goTypes = []any{ (*TagTemplateField)(nil), // 100: raystack.compass.v1beta1.TagTemplateField (*Type)(nil), // 101: raystack.compass.v1beta1.Type (*Namespace)(nil), // 102: raystack.compass.v1beta1.Namespace - nil, // 103: raystack.compass.v1beta1.SearchAssetsRequest.FilterEntry - nil, // 104: raystack.compass.v1beta1.SearchAssetsRequest.QueryEntry - nil, // 105: raystack.compass.v1beta1.GroupAssetsRequest.FilterEntry - (*GetGraphResponse_ProbesInfo)(nil), // 106: raystack.compass.v1beta1.GetGraphResponse.ProbesInfo - (*GetGraphResponse_NodeAttributes)(nil), // 107: raystack.compass.v1beta1.GetGraphResponse.NodeAttributes - nil, // 108: raystack.compass.v1beta1.GetGraphResponse.NodeAttrsEntry - nil, // 109: raystack.compass.v1beta1.GetAllTypesRequest.DataEntry - nil, // 110: raystack.compass.v1beta1.GetAllAssetsRequest.DataEntry - (*UpsertAssetRequest_Asset)(nil), // 111: raystack.compass.v1beta1.UpsertAssetRequest.Asset - nil, // 112: raystack.compass.v1beta1.UpsertAssetRequest.Asset.LabelsEntry - (*UpsertPatchAssetRequest_Asset)(nil), // 113: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset - nil, // 114: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.LabelsEntry - (*CreateAssetProbeRequest_Probe)(nil), // 115: raystack.compass.v1beta1.CreateAssetProbeRequest.Probe - nil, // 116: raystack.compass.v1beta1.Asset.LabelsEntry - (*structpb.Struct)(nil), // 117: google.protobuf.Struct - (*timestamppb.Timestamp)(nil), // 118: google.protobuf.Timestamp - (*structpb.Value)(nil), // 119: google.protobuf.Value - (*wrapperspb.StringValue)(nil), // 120: google.protobuf.StringValue + (*Entity)(nil), // 103: raystack.compass.v1beta1.Entity + (*Edge)(nil), // 104: raystack.compass.v1beta1.Edge + (*GetAllEntitiesRequest)(nil), // 105: raystack.compass.v1beta1.GetAllEntitiesRequest + (*GetAllEntitiesResponse)(nil), // 106: raystack.compass.v1beta1.GetAllEntitiesResponse + (*GetEntityByIDRequest)(nil), // 107: raystack.compass.v1beta1.GetEntityByIDRequest + (*GetEntityByIDResponse)(nil), // 108: raystack.compass.v1beta1.GetEntityByIDResponse + (*UpsertEntityRequest)(nil), // 109: raystack.compass.v1beta1.UpsertEntityRequest + (*UpsertEntityResponse)(nil), // 110: raystack.compass.v1beta1.UpsertEntityResponse + (*DeleteEntityRequest)(nil), // 111: raystack.compass.v1beta1.DeleteEntityRequest + (*DeleteEntityResponse)(nil), // 112: raystack.compass.v1beta1.DeleteEntityResponse + (*SearchEntitiesRequest)(nil), // 113: raystack.compass.v1beta1.SearchEntitiesRequest + (*SearchEntitiesResponse)(nil), // 114: raystack.compass.v1beta1.SearchEntitiesResponse + (*SuggestEntitiesRequest)(nil), // 115: raystack.compass.v1beta1.SuggestEntitiesRequest + (*SuggestEntitiesResponse)(nil), // 116: raystack.compass.v1beta1.SuggestEntitiesResponse + (*GetEntityTypesRequest)(nil), // 117: raystack.compass.v1beta1.GetEntityTypesRequest + (*GetEntityTypesResponse)(nil), // 118: raystack.compass.v1beta1.GetEntityTypesResponse + (*GetEntityContextRequest)(nil), // 119: raystack.compass.v1beta1.GetEntityContextRequest + (*GetEntityContextResponse)(nil), // 120: raystack.compass.v1beta1.GetEntityContextResponse + (*GetEntityImpactRequest)(nil), // 121: raystack.compass.v1beta1.GetEntityImpactRequest + (*GetEntityImpactResponse)(nil), // 122: raystack.compass.v1beta1.GetEntityImpactResponse + (*UpsertEdgeRequest)(nil), // 123: raystack.compass.v1beta1.UpsertEdgeRequest + (*UpsertEdgeResponse)(nil), // 124: raystack.compass.v1beta1.UpsertEdgeResponse + (*GetEdgesRequest)(nil), // 125: raystack.compass.v1beta1.GetEdgesRequest + (*GetEdgesResponse)(nil), // 126: raystack.compass.v1beta1.GetEdgesResponse + (*DeleteEdgeRequest)(nil), // 127: raystack.compass.v1beta1.DeleteEdgeRequest + (*DeleteEdgeResponse)(nil), // 128: raystack.compass.v1beta1.DeleteEdgeResponse + nil, // 129: raystack.compass.v1beta1.SearchAssetsRequest.FilterEntry + nil, // 130: raystack.compass.v1beta1.SearchAssetsRequest.QueryEntry + nil, // 131: raystack.compass.v1beta1.GroupAssetsRequest.FilterEntry + (*GetGraphResponse_ProbesInfo)(nil), // 132: raystack.compass.v1beta1.GetGraphResponse.ProbesInfo + (*GetGraphResponse_NodeAttributes)(nil), // 133: raystack.compass.v1beta1.GetGraphResponse.NodeAttributes + nil, // 134: raystack.compass.v1beta1.GetGraphResponse.NodeAttrsEntry + nil, // 135: raystack.compass.v1beta1.GetAllTypesRequest.DataEntry + nil, // 136: raystack.compass.v1beta1.GetAllAssetsRequest.DataEntry + (*UpsertAssetRequest_Asset)(nil), // 137: raystack.compass.v1beta1.UpsertAssetRequest.Asset + nil, // 138: raystack.compass.v1beta1.UpsertAssetRequest.Asset.LabelsEntry + (*UpsertPatchAssetRequest_Asset)(nil), // 139: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset + nil, // 140: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.LabelsEntry + (*CreateAssetProbeRequest_Probe)(nil), // 141: raystack.compass.v1beta1.CreateAssetProbeRequest.Probe + nil, // 142: raystack.compass.v1beta1.Asset.LabelsEntry + (*structpb.Struct)(nil), // 143: google.protobuf.Struct + (*timestamppb.Timestamp)(nil), // 144: google.protobuf.Timestamp + (*structpb.Value)(nil), // 145: google.protobuf.Value + (*wrapperspb.StringValue)(nil), // 146: google.protobuf.StringValue } var file_raystack_compass_v1beta1_service_proto_depIdxs = []int32{ 93, // 0: raystack.compass.v1beta1.GetAllDiscussionsResponse.data:type_name -> raystack.compass.v1beta1.Discussion 93, // 1: raystack.compass.v1beta1.GetDiscussionResponse.data:type_name -> raystack.compass.v1beta1.Discussion 94, // 2: raystack.compass.v1beta1.GetAllCommentsResponse.data:type_name -> raystack.compass.v1beta1.Comment 94, // 3: raystack.compass.v1beta1.GetCommentResponse.data:type_name -> raystack.compass.v1beta1.Comment - 103, // 4: raystack.compass.v1beta1.SearchAssetsRequest.filter:type_name -> raystack.compass.v1beta1.SearchAssetsRequest.FilterEntry - 104, // 5: raystack.compass.v1beta1.SearchAssetsRequest.query:type_name -> raystack.compass.v1beta1.SearchAssetsRequest.QueryEntry + 129, // 4: raystack.compass.v1beta1.SearchAssetsRequest.filter:type_name -> raystack.compass.v1beta1.SearchAssetsRequest.FilterEntry + 130, // 5: raystack.compass.v1beta1.SearchAssetsRequest.query:type_name -> raystack.compass.v1beta1.SearchAssetsRequest.QueryEntry 19, // 6: raystack.compass.v1beta1.SearchAssetsRequest.flags:type_name -> raystack.compass.v1beta1.SearchFlags 91, // 7: raystack.compass.v1beta1.SearchAssetsResponse.data:type_name -> raystack.compass.v1beta1.Asset - 105, // 8: raystack.compass.v1beta1.GroupAssetsRequest.filter:type_name -> raystack.compass.v1beta1.GroupAssetsRequest.FilterEntry + 131, // 8: raystack.compass.v1beta1.GroupAssetsRequest.filter:type_name -> raystack.compass.v1beta1.GroupAssetsRequest.FilterEntry 25, // 9: raystack.compass.v1beta1.GroupAssetsResponse.asset_groups:type_name -> raystack.compass.v1beta1.AssetGroup 26, // 10: raystack.compass.v1beta1.AssetGroup.group_fields:type_name -> raystack.compass.v1beta1.GroupField 91, // 11: raystack.compass.v1beta1.AssetGroup.assets:type_name -> raystack.compass.v1beta1.Asset 95, // 12: raystack.compass.v1beta1.GetGraphResponse.data:type_name -> raystack.compass.v1beta1.LineageEdge - 108, // 13: raystack.compass.v1beta1.GetGraphResponse.node_attrs:type_name -> raystack.compass.v1beta1.GetGraphResponse.NodeAttrsEntry - 109, // 14: raystack.compass.v1beta1.GetAllTypesRequest.data:type_name -> raystack.compass.v1beta1.GetAllTypesRequest.DataEntry + 134, // 13: raystack.compass.v1beta1.GetGraphResponse.node_attrs:type_name -> raystack.compass.v1beta1.GetGraphResponse.NodeAttrsEntry + 135, // 14: raystack.compass.v1beta1.GetAllTypesRequest.data:type_name -> raystack.compass.v1beta1.GetAllTypesRequest.DataEntry 101, // 15: raystack.compass.v1beta1.GetAllTypesResponse.data:type_name -> raystack.compass.v1beta1.Type - 110, // 16: raystack.compass.v1beta1.GetAllAssetsRequest.data:type_name -> raystack.compass.v1beta1.GetAllAssetsRequest.DataEntry + 136, // 16: raystack.compass.v1beta1.GetAllAssetsRequest.data:type_name -> raystack.compass.v1beta1.GetAllAssetsRequest.DataEntry 91, // 17: raystack.compass.v1beta1.GetAllAssetsResponse.data:type_name -> raystack.compass.v1beta1.Asset 91, // 18: raystack.compass.v1beta1.GetAssetByIDResponse.data:type_name -> raystack.compass.v1beta1.Asset - 111, // 19: raystack.compass.v1beta1.UpsertAssetRequest.asset:type_name -> raystack.compass.v1beta1.UpsertAssetRequest.Asset + 137, // 19: raystack.compass.v1beta1.UpsertAssetRequest.asset:type_name -> raystack.compass.v1beta1.UpsertAssetRequest.Asset 96, // 20: raystack.compass.v1beta1.UpsertAssetRequest.upstreams:type_name -> raystack.compass.v1beta1.LineageNode 96, // 21: raystack.compass.v1beta1.UpsertAssetRequest.downstreams:type_name -> raystack.compass.v1beta1.LineageNode - 113, // 22: raystack.compass.v1beta1.UpsertPatchAssetRequest.asset:type_name -> raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset + 139, // 22: raystack.compass.v1beta1.UpsertPatchAssetRequest.asset:type_name -> raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset 96, // 23: raystack.compass.v1beta1.UpsertPatchAssetRequest.upstreams:type_name -> raystack.compass.v1beta1.LineageNode 96, // 24: raystack.compass.v1beta1.UpsertPatchAssetRequest.downstreams:type_name -> raystack.compass.v1beta1.LineageNode 89, // 25: raystack.compass.v1beta1.GetAssetStargazersResponse.data:type_name -> raystack.compass.v1beta1.User 91, // 26: raystack.compass.v1beta1.GetAssetVersionHistoryResponse.data:type_name -> raystack.compass.v1beta1.Asset 91, // 27: raystack.compass.v1beta1.GetAssetByVersionResponse.data:type_name -> raystack.compass.v1beta1.Asset - 115, // 28: raystack.compass.v1beta1.CreateAssetProbeRequest.probe:type_name -> raystack.compass.v1beta1.CreateAssetProbeRequest.Probe + 141, // 28: raystack.compass.v1beta1.CreateAssetProbeRequest.probe:type_name -> raystack.compass.v1beta1.CreateAssetProbeRequest.Probe 91, // 29: raystack.compass.v1beta1.GetUserStarredAssetsResponse.data:type_name -> raystack.compass.v1beta1.Asset 91, // 30: raystack.compass.v1beta1.GetMyStarredAssetsResponse.data:type_name -> raystack.compass.v1beta1.Asset 91, // 31: raystack.compass.v1beta1.GetMyStarredAssetResponse.data:type_name -> raystack.compass.v1beta1.Asset @@ -7118,147 +8788,192 @@ var file_raystack_compass_v1beta1_service_proto_depIdxs = []int32{ 99, // 42: raystack.compass.v1beta1.GetTagTemplateResponse.data:type_name -> raystack.compass.v1beta1.TagTemplate 100, // 43: raystack.compass.v1beta1.UpdateTagTemplateRequest.fields:type_name -> raystack.compass.v1beta1.TagTemplateField 99, // 44: raystack.compass.v1beta1.UpdateTagTemplateResponse.data:type_name -> raystack.compass.v1beta1.TagTemplate - 117, // 45: raystack.compass.v1beta1.CreateNamespaceRequest.metadata:type_name -> google.protobuf.Struct + 143, // 45: raystack.compass.v1beta1.CreateNamespaceRequest.metadata:type_name -> google.protobuf.Struct 102, // 46: raystack.compass.v1beta1.GetNamespaceResponse.namespace:type_name -> raystack.compass.v1beta1.Namespace - 117, // 47: raystack.compass.v1beta1.UpdateNamespaceRequest.metadata:type_name -> google.protobuf.Struct + 143, // 47: raystack.compass.v1beta1.UpdateNamespaceRequest.metadata:type_name -> google.protobuf.Struct 102, // 48: raystack.compass.v1beta1.ListNamespacesResponse.namespaces:type_name -> raystack.compass.v1beta1.Namespace - 118, // 49: raystack.compass.v1beta1.User.created_at:type_name -> google.protobuf.Timestamp - 118, // 50: raystack.compass.v1beta1.User.updated_at:type_name -> google.protobuf.Timestamp - 119, // 51: raystack.compass.v1beta1.Change.from:type_name -> google.protobuf.Value - 119, // 52: raystack.compass.v1beta1.Change.to:type_name -> google.protobuf.Value - 117, // 53: raystack.compass.v1beta1.Asset.data:type_name -> google.protobuf.Struct - 116, // 54: raystack.compass.v1beta1.Asset.labels:type_name -> raystack.compass.v1beta1.Asset.LabelsEntry + 144, // 49: raystack.compass.v1beta1.User.created_at:type_name -> google.protobuf.Timestamp + 144, // 50: raystack.compass.v1beta1.User.updated_at:type_name -> google.protobuf.Timestamp + 145, // 51: raystack.compass.v1beta1.Change.from:type_name -> google.protobuf.Value + 145, // 52: raystack.compass.v1beta1.Change.to:type_name -> google.protobuf.Value + 143, // 53: raystack.compass.v1beta1.Asset.data:type_name -> google.protobuf.Struct + 142, // 54: raystack.compass.v1beta1.Asset.labels:type_name -> raystack.compass.v1beta1.Asset.LabelsEntry 89, // 55: raystack.compass.v1beta1.Asset.owners:type_name -> raystack.compass.v1beta1.User 89, // 56: raystack.compass.v1beta1.Asset.updated_by:type_name -> raystack.compass.v1beta1.User 90, // 57: raystack.compass.v1beta1.Asset.changelog:type_name -> raystack.compass.v1beta1.Change - 118, // 58: raystack.compass.v1beta1.Asset.created_at:type_name -> google.protobuf.Timestamp - 118, // 59: raystack.compass.v1beta1.Asset.updated_at:type_name -> google.protobuf.Timestamp + 144, // 58: raystack.compass.v1beta1.Asset.created_at:type_name -> google.protobuf.Timestamp + 144, // 59: raystack.compass.v1beta1.Asset.updated_at:type_name -> google.protobuf.Timestamp 92, // 60: raystack.compass.v1beta1.Asset.probes:type_name -> raystack.compass.v1beta1.Probe - 117, // 61: raystack.compass.v1beta1.Probe.metadata:type_name -> google.protobuf.Struct - 118, // 62: raystack.compass.v1beta1.Probe.timestamp:type_name -> google.protobuf.Timestamp - 118, // 63: raystack.compass.v1beta1.Probe.created_at:type_name -> google.protobuf.Timestamp + 143, // 61: raystack.compass.v1beta1.Probe.metadata:type_name -> google.protobuf.Struct + 144, // 62: raystack.compass.v1beta1.Probe.timestamp:type_name -> google.protobuf.Timestamp + 144, // 63: raystack.compass.v1beta1.Probe.created_at:type_name -> google.protobuf.Timestamp 89, // 64: raystack.compass.v1beta1.Discussion.owner:type_name -> raystack.compass.v1beta1.User - 118, // 65: raystack.compass.v1beta1.Discussion.created_at:type_name -> google.protobuf.Timestamp - 118, // 66: raystack.compass.v1beta1.Discussion.updated_at:type_name -> google.protobuf.Timestamp + 144, // 65: raystack.compass.v1beta1.Discussion.created_at:type_name -> google.protobuf.Timestamp + 144, // 66: raystack.compass.v1beta1.Discussion.updated_at:type_name -> google.protobuf.Timestamp 89, // 67: raystack.compass.v1beta1.Comment.owner:type_name -> raystack.compass.v1beta1.User 89, // 68: raystack.compass.v1beta1.Comment.updated_by:type_name -> raystack.compass.v1beta1.User - 118, // 69: raystack.compass.v1beta1.Comment.created_at:type_name -> google.protobuf.Timestamp - 118, // 70: raystack.compass.v1beta1.Comment.updated_at:type_name -> google.protobuf.Timestamp - 117, // 71: raystack.compass.v1beta1.LineageEdge.prop:type_name -> google.protobuf.Struct + 144, // 69: raystack.compass.v1beta1.Comment.created_at:type_name -> google.protobuf.Timestamp + 144, // 70: raystack.compass.v1beta1.Comment.updated_at:type_name -> google.protobuf.Timestamp + 143, // 71: raystack.compass.v1beta1.LineageEdge.prop:type_name -> google.protobuf.Struct 98, // 72: raystack.compass.v1beta1.Tag.tag_values:type_name -> raystack.compass.v1beta1.TagValue - 119, // 73: raystack.compass.v1beta1.TagValue.field_value:type_name -> google.protobuf.Value - 118, // 74: raystack.compass.v1beta1.TagValue.created_at:type_name -> google.protobuf.Timestamp - 118, // 75: raystack.compass.v1beta1.TagValue.updated_at:type_name -> google.protobuf.Timestamp + 145, // 73: raystack.compass.v1beta1.TagValue.field_value:type_name -> google.protobuf.Value + 144, // 74: raystack.compass.v1beta1.TagValue.created_at:type_name -> google.protobuf.Timestamp + 144, // 75: raystack.compass.v1beta1.TagValue.updated_at:type_name -> google.protobuf.Timestamp 100, // 76: raystack.compass.v1beta1.TagTemplate.fields:type_name -> raystack.compass.v1beta1.TagTemplateField - 118, // 77: raystack.compass.v1beta1.TagTemplate.created_at:type_name -> google.protobuf.Timestamp - 118, // 78: raystack.compass.v1beta1.TagTemplate.updated_at:type_name -> google.protobuf.Timestamp - 118, // 79: raystack.compass.v1beta1.TagTemplateField.created_at:type_name -> google.protobuf.Timestamp - 118, // 80: raystack.compass.v1beta1.TagTemplateField.updated_at:type_name -> google.protobuf.Timestamp - 117, // 81: raystack.compass.v1beta1.Namespace.metadata:type_name -> google.protobuf.Struct - 92, // 82: raystack.compass.v1beta1.GetGraphResponse.ProbesInfo.latest:type_name -> raystack.compass.v1beta1.Probe - 106, // 83: raystack.compass.v1beta1.GetGraphResponse.NodeAttributes.probes:type_name -> raystack.compass.v1beta1.GetGraphResponse.ProbesInfo - 107, // 84: raystack.compass.v1beta1.GetGraphResponse.NodeAttrsEntry.value:type_name -> raystack.compass.v1beta1.GetGraphResponse.NodeAttributes - 117, // 85: raystack.compass.v1beta1.UpsertAssetRequest.Asset.data:type_name -> google.protobuf.Struct - 112, // 86: raystack.compass.v1beta1.UpsertAssetRequest.Asset.labels:type_name -> raystack.compass.v1beta1.UpsertAssetRequest.Asset.LabelsEntry - 89, // 87: raystack.compass.v1beta1.UpsertAssetRequest.Asset.owners:type_name -> raystack.compass.v1beta1.User - 120, // 88: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.name:type_name -> google.protobuf.StringValue - 120, // 89: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.description:type_name -> google.protobuf.StringValue - 117, // 90: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.data:type_name -> google.protobuf.Struct - 114, // 91: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.labels:type_name -> raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.LabelsEntry - 89, // 92: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.owners:type_name -> raystack.compass.v1beta1.User - 117, // 93: raystack.compass.v1beta1.CreateAssetProbeRequest.Probe.metadata:type_name -> google.protobuf.Struct - 118, // 94: raystack.compass.v1beta1.CreateAssetProbeRequest.Probe.timestamp:type_name -> google.protobuf.Timestamp - 0, // 95: raystack.compass.v1beta1.CompassService.GetAllDiscussions:input_type -> raystack.compass.v1beta1.GetAllDiscussionsRequest - 2, // 96: raystack.compass.v1beta1.CompassService.CreateDiscussion:input_type -> raystack.compass.v1beta1.CreateDiscussionRequest - 4, // 97: raystack.compass.v1beta1.CompassService.GetDiscussion:input_type -> raystack.compass.v1beta1.GetDiscussionRequest - 6, // 98: raystack.compass.v1beta1.CompassService.PatchDiscussion:input_type -> raystack.compass.v1beta1.PatchDiscussionRequest - 7, // 99: raystack.compass.v1beta1.CompassService.CreateComment:input_type -> raystack.compass.v1beta1.CreateCommentRequest - 10, // 100: raystack.compass.v1beta1.CompassService.GetAllComments:input_type -> raystack.compass.v1beta1.GetAllCommentsRequest - 12, // 101: raystack.compass.v1beta1.CompassService.GetComment:input_type -> raystack.compass.v1beta1.GetCommentRequest - 14, // 102: raystack.compass.v1beta1.CompassService.UpdateComment:input_type -> raystack.compass.v1beta1.UpdateCommentRequest - 16, // 103: raystack.compass.v1beta1.CompassService.DeleteComment:input_type -> raystack.compass.v1beta1.DeleteCommentRequest - 18, // 104: raystack.compass.v1beta1.CompassService.SearchAssets:input_type -> raystack.compass.v1beta1.SearchAssetsRequest - 21, // 105: raystack.compass.v1beta1.CompassService.SuggestAssets:input_type -> raystack.compass.v1beta1.SuggestAssetsRequest - 23, // 106: raystack.compass.v1beta1.CompassService.GroupAssets:input_type -> raystack.compass.v1beta1.GroupAssetsRequest - 27, // 107: raystack.compass.v1beta1.CompassService.GetGraph:input_type -> raystack.compass.v1beta1.GetGraphRequest - 29, // 108: raystack.compass.v1beta1.CompassService.GetAllTypes:input_type -> raystack.compass.v1beta1.GetAllTypesRequest - 31, // 109: raystack.compass.v1beta1.CompassService.GetAllAssets:input_type -> raystack.compass.v1beta1.GetAllAssetsRequest - 33, // 110: raystack.compass.v1beta1.CompassService.GetAssetByID:input_type -> raystack.compass.v1beta1.GetAssetByIDRequest - 35, // 111: raystack.compass.v1beta1.CompassService.UpsertAsset:input_type -> raystack.compass.v1beta1.UpsertAssetRequest - 37, // 112: raystack.compass.v1beta1.CompassService.UpsertPatchAsset:input_type -> raystack.compass.v1beta1.UpsertPatchAssetRequest - 39, // 113: raystack.compass.v1beta1.CompassService.DeleteAsset:input_type -> raystack.compass.v1beta1.DeleteAssetRequest - 41, // 114: raystack.compass.v1beta1.CompassService.GetAssetStargazers:input_type -> raystack.compass.v1beta1.GetAssetStargazersRequest - 43, // 115: raystack.compass.v1beta1.CompassService.GetAssetVersionHistory:input_type -> raystack.compass.v1beta1.GetAssetVersionHistoryRequest - 45, // 116: raystack.compass.v1beta1.CompassService.GetAssetByVersion:input_type -> raystack.compass.v1beta1.GetAssetByVersionRequest - 47, // 117: raystack.compass.v1beta1.CompassService.CreateAssetProbe:input_type -> raystack.compass.v1beta1.CreateAssetProbeRequest - 49, // 118: raystack.compass.v1beta1.CompassService.GetUserStarredAssets:input_type -> raystack.compass.v1beta1.GetUserStarredAssetsRequest - 51, // 119: raystack.compass.v1beta1.CompassService.GetMyStarredAssets:input_type -> raystack.compass.v1beta1.GetMyStarredAssetsRequest - 53, // 120: raystack.compass.v1beta1.CompassService.GetMyStarredAsset:input_type -> raystack.compass.v1beta1.GetMyStarredAssetRequest - 55, // 121: raystack.compass.v1beta1.CompassService.StarAsset:input_type -> raystack.compass.v1beta1.StarAssetRequest - 57, // 122: raystack.compass.v1beta1.CompassService.UnstarAsset:input_type -> raystack.compass.v1beta1.UnstarAssetRequest - 59, // 123: raystack.compass.v1beta1.CompassService.GetMyDiscussions:input_type -> raystack.compass.v1beta1.GetMyDiscussionsRequest - 61, // 124: raystack.compass.v1beta1.CompassService.CreateTagAsset:input_type -> raystack.compass.v1beta1.CreateTagAssetRequest - 63, // 125: raystack.compass.v1beta1.CompassService.GetTagByAssetAndTemplate:input_type -> raystack.compass.v1beta1.GetTagByAssetAndTemplateRequest - 65, // 126: raystack.compass.v1beta1.CompassService.UpdateTagAsset:input_type -> raystack.compass.v1beta1.UpdateTagAssetRequest - 67, // 127: raystack.compass.v1beta1.CompassService.DeleteTagAsset:input_type -> raystack.compass.v1beta1.DeleteTagAssetRequest - 69, // 128: raystack.compass.v1beta1.CompassService.GetAllTagsByAsset:input_type -> raystack.compass.v1beta1.GetAllTagsByAssetRequest - 71, // 129: raystack.compass.v1beta1.CompassService.GetAllTagTemplates:input_type -> raystack.compass.v1beta1.GetAllTagTemplatesRequest - 73, // 130: raystack.compass.v1beta1.CompassService.CreateTagTemplate:input_type -> raystack.compass.v1beta1.CreateTagTemplateRequest - 75, // 131: raystack.compass.v1beta1.CompassService.GetTagTemplate:input_type -> raystack.compass.v1beta1.GetTagTemplateRequest - 77, // 132: raystack.compass.v1beta1.CompassService.UpdateTagTemplate:input_type -> raystack.compass.v1beta1.UpdateTagTemplateRequest - 79, // 133: raystack.compass.v1beta1.CompassService.DeleteTagTemplate:input_type -> raystack.compass.v1beta1.DeleteTagTemplateRequest - 81, // 134: raystack.compass.v1beta1.CompassService.CreateNamespace:input_type -> raystack.compass.v1beta1.CreateNamespaceRequest - 83, // 135: raystack.compass.v1beta1.CompassService.GetNamespace:input_type -> raystack.compass.v1beta1.GetNamespaceRequest - 85, // 136: raystack.compass.v1beta1.CompassService.UpdateNamespace:input_type -> raystack.compass.v1beta1.UpdateNamespaceRequest - 87, // 137: raystack.compass.v1beta1.CompassService.ListNamespaces:input_type -> raystack.compass.v1beta1.ListNamespacesRequest - 1, // 138: raystack.compass.v1beta1.CompassService.GetAllDiscussions:output_type -> raystack.compass.v1beta1.GetAllDiscussionsResponse - 3, // 139: raystack.compass.v1beta1.CompassService.CreateDiscussion:output_type -> raystack.compass.v1beta1.CreateDiscussionResponse - 5, // 140: raystack.compass.v1beta1.CompassService.GetDiscussion:output_type -> raystack.compass.v1beta1.GetDiscussionResponse - 8, // 141: raystack.compass.v1beta1.CompassService.PatchDiscussion:output_type -> raystack.compass.v1beta1.PatchDiscussionResponse - 9, // 142: raystack.compass.v1beta1.CompassService.CreateComment:output_type -> raystack.compass.v1beta1.CreateCommentResponse - 11, // 143: raystack.compass.v1beta1.CompassService.GetAllComments:output_type -> raystack.compass.v1beta1.GetAllCommentsResponse - 13, // 144: raystack.compass.v1beta1.CompassService.GetComment:output_type -> raystack.compass.v1beta1.GetCommentResponse - 15, // 145: raystack.compass.v1beta1.CompassService.UpdateComment:output_type -> raystack.compass.v1beta1.UpdateCommentResponse - 17, // 146: raystack.compass.v1beta1.CompassService.DeleteComment:output_type -> raystack.compass.v1beta1.DeleteCommentResponse - 20, // 147: raystack.compass.v1beta1.CompassService.SearchAssets:output_type -> raystack.compass.v1beta1.SearchAssetsResponse - 22, // 148: raystack.compass.v1beta1.CompassService.SuggestAssets:output_type -> raystack.compass.v1beta1.SuggestAssetsResponse - 24, // 149: raystack.compass.v1beta1.CompassService.GroupAssets:output_type -> raystack.compass.v1beta1.GroupAssetsResponse - 28, // 150: raystack.compass.v1beta1.CompassService.GetGraph:output_type -> raystack.compass.v1beta1.GetGraphResponse - 30, // 151: raystack.compass.v1beta1.CompassService.GetAllTypes:output_type -> raystack.compass.v1beta1.GetAllTypesResponse - 32, // 152: raystack.compass.v1beta1.CompassService.GetAllAssets:output_type -> raystack.compass.v1beta1.GetAllAssetsResponse - 34, // 153: raystack.compass.v1beta1.CompassService.GetAssetByID:output_type -> raystack.compass.v1beta1.GetAssetByIDResponse - 36, // 154: raystack.compass.v1beta1.CompassService.UpsertAsset:output_type -> raystack.compass.v1beta1.UpsertAssetResponse - 38, // 155: raystack.compass.v1beta1.CompassService.UpsertPatchAsset:output_type -> raystack.compass.v1beta1.UpsertPatchAssetResponse - 40, // 156: raystack.compass.v1beta1.CompassService.DeleteAsset:output_type -> raystack.compass.v1beta1.DeleteAssetResponse - 42, // 157: raystack.compass.v1beta1.CompassService.GetAssetStargazers:output_type -> raystack.compass.v1beta1.GetAssetStargazersResponse - 44, // 158: raystack.compass.v1beta1.CompassService.GetAssetVersionHistory:output_type -> raystack.compass.v1beta1.GetAssetVersionHistoryResponse - 46, // 159: raystack.compass.v1beta1.CompassService.GetAssetByVersion:output_type -> raystack.compass.v1beta1.GetAssetByVersionResponse - 48, // 160: raystack.compass.v1beta1.CompassService.CreateAssetProbe:output_type -> raystack.compass.v1beta1.CreateAssetProbeResponse - 50, // 161: raystack.compass.v1beta1.CompassService.GetUserStarredAssets:output_type -> raystack.compass.v1beta1.GetUserStarredAssetsResponse - 52, // 162: raystack.compass.v1beta1.CompassService.GetMyStarredAssets:output_type -> raystack.compass.v1beta1.GetMyStarredAssetsResponse - 54, // 163: raystack.compass.v1beta1.CompassService.GetMyStarredAsset:output_type -> raystack.compass.v1beta1.GetMyStarredAssetResponse - 56, // 164: raystack.compass.v1beta1.CompassService.StarAsset:output_type -> raystack.compass.v1beta1.StarAssetResponse - 58, // 165: raystack.compass.v1beta1.CompassService.UnstarAsset:output_type -> raystack.compass.v1beta1.UnstarAssetResponse - 60, // 166: raystack.compass.v1beta1.CompassService.GetMyDiscussions:output_type -> raystack.compass.v1beta1.GetMyDiscussionsResponse - 62, // 167: raystack.compass.v1beta1.CompassService.CreateTagAsset:output_type -> raystack.compass.v1beta1.CreateTagAssetResponse - 64, // 168: raystack.compass.v1beta1.CompassService.GetTagByAssetAndTemplate:output_type -> raystack.compass.v1beta1.GetTagByAssetAndTemplateResponse - 66, // 169: raystack.compass.v1beta1.CompassService.UpdateTagAsset:output_type -> raystack.compass.v1beta1.UpdateTagAssetResponse - 68, // 170: raystack.compass.v1beta1.CompassService.DeleteTagAsset:output_type -> raystack.compass.v1beta1.DeleteTagAssetResponse - 70, // 171: raystack.compass.v1beta1.CompassService.GetAllTagsByAsset:output_type -> raystack.compass.v1beta1.GetAllTagsByAssetResponse - 72, // 172: raystack.compass.v1beta1.CompassService.GetAllTagTemplates:output_type -> raystack.compass.v1beta1.GetAllTagTemplatesResponse - 74, // 173: raystack.compass.v1beta1.CompassService.CreateTagTemplate:output_type -> raystack.compass.v1beta1.CreateTagTemplateResponse - 76, // 174: raystack.compass.v1beta1.CompassService.GetTagTemplate:output_type -> raystack.compass.v1beta1.GetTagTemplateResponse - 78, // 175: raystack.compass.v1beta1.CompassService.UpdateTagTemplate:output_type -> raystack.compass.v1beta1.UpdateTagTemplateResponse - 80, // 176: raystack.compass.v1beta1.CompassService.DeleteTagTemplate:output_type -> raystack.compass.v1beta1.DeleteTagTemplateResponse - 82, // 177: raystack.compass.v1beta1.CompassService.CreateNamespace:output_type -> raystack.compass.v1beta1.CreateNamespaceResponse - 84, // 178: raystack.compass.v1beta1.CompassService.GetNamespace:output_type -> raystack.compass.v1beta1.GetNamespaceResponse - 86, // 179: raystack.compass.v1beta1.CompassService.UpdateNamespace:output_type -> raystack.compass.v1beta1.UpdateNamespaceResponse - 88, // 180: raystack.compass.v1beta1.CompassService.ListNamespaces:output_type -> raystack.compass.v1beta1.ListNamespacesResponse - 138, // [138:181] is the sub-list for method output_type - 95, // [95:138] is the sub-list for method input_type - 95, // [95:95] is the sub-list for extension type_name - 95, // [95:95] is the sub-list for extension extendee - 0, // [0:95] is the sub-list for field type_name + 144, // 77: raystack.compass.v1beta1.TagTemplate.created_at:type_name -> google.protobuf.Timestamp + 144, // 78: raystack.compass.v1beta1.TagTemplate.updated_at:type_name -> google.protobuf.Timestamp + 144, // 79: raystack.compass.v1beta1.TagTemplateField.created_at:type_name -> google.protobuf.Timestamp + 144, // 80: raystack.compass.v1beta1.TagTemplateField.updated_at:type_name -> google.protobuf.Timestamp + 143, // 81: raystack.compass.v1beta1.Namespace.metadata:type_name -> google.protobuf.Struct + 143, // 82: raystack.compass.v1beta1.Entity.properties:type_name -> google.protobuf.Struct + 144, // 83: raystack.compass.v1beta1.Entity.valid_from:type_name -> google.protobuf.Timestamp + 144, // 84: raystack.compass.v1beta1.Entity.valid_to:type_name -> google.protobuf.Timestamp + 144, // 85: raystack.compass.v1beta1.Entity.created_at:type_name -> google.protobuf.Timestamp + 144, // 86: raystack.compass.v1beta1.Entity.updated_at:type_name -> google.protobuf.Timestamp + 143, // 87: raystack.compass.v1beta1.Edge.properties:type_name -> google.protobuf.Struct + 144, // 88: raystack.compass.v1beta1.Edge.valid_from:type_name -> google.protobuf.Timestamp + 144, // 89: raystack.compass.v1beta1.Edge.valid_to:type_name -> google.protobuf.Timestamp + 144, // 90: raystack.compass.v1beta1.Edge.created_at:type_name -> google.protobuf.Timestamp + 103, // 91: raystack.compass.v1beta1.GetAllEntitiesResponse.data:type_name -> raystack.compass.v1beta1.Entity + 103, // 92: raystack.compass.v1beta1.GetEntityByIDResponse.data:type_name -> raystack.compass.v1beta1.Entity + 143, // 93: raystack.compass.v1beta1.UpsertEntityRequest.properties:type_name -> google.protobuf.Struct + 103, // 94: raystack.compass.v1beta1.SearchEntitiesResponse.data:type_name -> raystack.compass.v1beta1.Entity + 101, // 95: raystack.compass.v1beta1.GetEntityTypesResponse.data:type_name -> raystack.compass.v1beta1.Type + 103, // 96: raystack.compass.v1beta1.GetEntityContextResponse.entity:type_name -> raystack.compass.v1beta1.Entity + 104, // 97: raystack.compass.v1beta1.GetEntityContextResponse.edges:type_name -> raystack.compass.v1beta1.Edge + 103, // 98: raystack.compass.v1beta1.GetEntityContextResponse.related:type_name -> raystack.compass.v1beta1.Entity + 104, // 99: raystack.compass.v1beta1.GetEntityImpactResponse.edges:type_name -> raystack.compass.v1beta1.Edge + 103, // 100: raystack.compass.v1beta1.GetEntityImpactResponse.affected:type_name -> raystack.compass.v1beta1.Entity + 143, // 101: raystack.compass.v1beta1.UpsertEdgeRequest.properties:type_name -> google.protobuf.Struct + 104, // 102: raystack.compass.v1beta1.GetEdgesResponse.data:type_name -> raystack.compass.v1beta1.Edge + 92, // 103: raystack.compass.v1beta1.GetGraphResponse.ProbesInfo.latest:type_name -> raystack.compass.v1beta1.Probe + 132, // 104: raystack.compass.v1beta1.GetGraphResponse.NodeAttributes.probes:type_name -> raystack.compass.v1beta1.GetGraphResponse.ProbesInfo + 133, // 105: raystack.compass.v1beta1.GetGraphResponse.NodeAttrsEntry.value:type_name -> raystack.compass.v1beta1.GetGraphResponse.NodeAttributes + 143, // 106: raystack.compass.v1beta1.UpsertAssetRequest.Asset.data:type_name -> google.protobuf.Struct + 138, // 107: raystack.compass.v1beta1.UpsertAssetRequest.Asset.labels:type_name -> raystack.compass.v1beta1.UpsertAssetRequest.Asset.LabelsEntry + 89, // 108: raystack.compass.v1beta1.UpsertAssetRequest.Asset.owners:type_name -> raystack.compass.v1beta1.User + 146, // 109: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.name:type_name -> google.protobuf.StringValue + 146, // 110: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.description:type_name -> google.protobuf.StringValue + 143, // 111: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.data:type_name -> google.protobuf.Struct + 140, // 112: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.labels:type_name -> raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.LabelsEntry + 89, // 113: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.owners:type_name -> raystack.compass.v1beta1.User + 143, // 114: raystack.compass.v1beta1.CreateAssetProbeRequest.Probe.metadata:type_name -> google.protobuf.Struct + 144, // 115: raystack.compass.v1beta1.CreateAssetProbeRequest.Probe.timestamp:type_name -> google.protobuf.Timestamp + 0, // 116: raystack.compass.v1beta1.CompassService.GetAllDiscussions:input_type -> raystack.compass.v1beta1.GetAllDiscussionsRequest + 2, // 117: raystack.compass.v1beta1.CompassService.CreateDiscussion:input_type -> raystack.compass.v1beta1.CreateDiscussionRequest + 4, // 118: raystack.compass.v1beta1.CompassService.GetDiscussion:input_type -> raystack.compass.v1beta1.GetDiscussionRequest + 6, // 119: raystack.compass.v1beta1.CompassService.PatchDiscussion:input_type -> raystack.compass.v1beta1.PatchDiscussionRequest + 7, // 120: raystack.compass.v1beta1.CompassService.CreateComment:input_type -> raystack.compass.v1beta1.CreateCommentRequest + 10, // 121: raystack.compass.v1beta1.CompassService.GetAllComments:input_type -> raystack.compass.v1beta1.GetAllCommentsRequest + 12, // 122: raystack.compass.v1beta1.CompassService.GetComment:input_type -> raystack.compass.v1beta1.GetCommentRequest + 14, // 123: raystack.compass.v1beta1.CompassService.UpdateComment:input_type -> raystack.compass.v1beta1.UpdateCommentRequest + 16, // 124: raystack.compass.v1beta1.CompassService.DeleteComment:input_type -> raystack.compass.v1beta1.DeleteCommentRequest + 18, // 125: raystack.compass.v1beta1.CompassService.SearchAssets:input_type -> raystack.compass.v1beta1.SearchAssetsRequest + 21, // 126: raystack.compass.v1beta1.CompassService.SuggestAssets:input_type -> raystack.compass.v1beta1.SuggestAssetsRequest + 23, // 127: raystack.compass.v1beta1.CompassService.GroupAssets:input_type -> raystack.compass.v1beta1.GroupAssetsRequest + 27, // 128: raystack.compass.v1beta1.CompassService.GetGraph:input_type -> raystack.compass.v1beta1.GetGraphRequest + 29, // 129: raystack.compass.v1beta1.CompassService.GetAllTypes:input_type -> raystack.compass.v1beta1.GetAllTypesRequest + 31, // 130: raystack.compass.v1beta1.CompassService.GetAllAssets:input_type -> raystack.compass.v1beta1.GetAllAssetsRequest + 33, // 131: raystack.compass.v1beta1.CompassService.GetAssetByID:input_type -> raystack.compass.v1beta1.GetAssetByIDRequest + 35, // 132: raystack.compass.v1beta1.CompassService.UpsertAsset:input_type -> raystack.compass.v1beta1.UpsertAssetRequest + 37, // 133: raystack.compass.v1beta1.CompassService.UpsertPatchAsset:input_type -> raystack.compass.v1beta1.UpsertPatchAssetRequest + 39, // 134: raystack.compass.v1beta1.CompassService.DeleteAsset:input_type -> raystack.compass.v1beta1.DeleteAssetRequest + 41, // 135: raystack.compass.v1beta1.CompassService.GetAssetStargazers:input_type -> raystack.compass.v1beta1.GetAssetStargazersRequest + 43, // 136: raystack.compass.v1beta1.CompassService.GetAssetVersionHistory:input_type -> raystack.compass.v1beta1.GetAssetVersionHistoryRequest + 45, // 137: raystack.compass.v1beta1.CompassService.GetAssetByVersion:input_type -> raystack.compass.v1beta1.GetAssetByVersionRequest + 47, // 138: raystack.compass.v1beta1.CompassService.CreateAssetProbe:input_type -> raystack.compass.v1beta1.CreateAssetProbeRequest + 49, // 139: raystack.compass.v1beta1.CompassService.GetUserStarredAssets:input_type -> raystack.compass.v1beta1.GetUserStarredAssetsRequest + 51, // 140: raystack.compass.v1beta1.CompassService.GetMyStarredAssets:input_type -> raystack.compass.v1beta1.GetMyStarredAssetsRequest + 53, // 141: raystack.compass.v1beta1.CompassService.GetMyStarredAsset:input_type -> raystack.compass.v1beta1.GetMyStarredAssetRequest + 55, // 142: raystack.compass.v1beta1.CompassService.StarAsset:input_type -> raystack.compass.v1beta1.StarAssetRequest + 57, // 143: raystack.compass.v1beta1.CompassService.UnstarAsset:input_type -> raystack.compass.v1beta1.UnstarAssetRequest + 59, // 144: raystack.compass.v1beta1.CompassService.GetMyDiscussions:input_type -> raystack.compass.v1beta1.GetMyDiscussionsRequest + 61, // 145: raystack.compass.v1beta1.CompassService.CreateTagAsset:input_type -> raystack.compass.v1beta1.CreateTagAssetRequest + 63, // 146: raystack.compass.v1beta1.CompassService.GetTagByAssetAndTemplate:input_type -> raystack.compass.v1beta1.GetTagByAssetAndTemplateRequest + 65, // 147: raystack.compass.v1beta1.CompassService.UpdateTagAsset:input_type -> raystack.compass.v1beta1.UpdateTagAssetRequest + 67, // 148: raystack.compass.v1beta1.CompassService.DeleteTagAsset:input_type -> raystack.compass.v1beta1.DeleteTagAssetRequest + 69, // 149: raystack.compass.v1beta1.CompassService.GetAllTagsByAsset:input_type -> raystack.compass.v1beta1.GetAllTagsByAssetRequest + 71, // 150: raystack.compass.v1beta1.CompassService.GetAllTagTemplates:input_type -> raystack.compass.v1beta1.GetAllTagTemplatesRequest + 73, // 151: raystack.compass.v1beta1.CompassService.CreateTagTemplate:input_type -> raystack.compass.v1beta1.CreateTagTemplateRequest + 75, // 152: raystack.compass.v1beta1.CompassService.GetTagTemplate:input_type -> raystack.compass.v1beta1.GetTagTemplateRequest + 77, // 153: raystack.compass.v1beta1.CompassService.UpdateTagTemplate:input_type -> raystack.compass.v1beta1.UpdateTagTemplateRequest + 79, // 154: raystack.compass.v1beta1.CompassService.DeleteTagTemplate:input_type -> raystack.compass.v1beta1.DeleteTagTemplateRequest + 81, // 155: raystack.compass.v1beta1.CompassService.CreateNamespace:input_type -> raystack.compass.v1beta1.CreateNamespaceRequest + 83, // 156: raystack.compass.v1beta1.CompassService.GetNamespace:input_type -> raystack.compass.v1beta1.GetNamespaceRequest + 85, // 157: raystack.compass.v1beta1.CompassService.UpdateNamespace:input_type -> raystack.compass.v1beta1.UpdateNamespaceRequest + 87, // 158: raystack.compass.v1beta1.CompassService.ListNamespaces:input_type -> raystack.compass.v1beta1.ListNamespacesRequest + 105, // 159: raystack.compass.v1beta1.CompassService.GetAllEntities:input_type -> raystack.compass.v1beta1.GetAllEntitiesRequest + 107, // 160: raystack.compass.v1beta1.CompassService.GetEntityByID:input_type -> raystack.compass.v1beta1.GetEntityByIDRequest + 109, // 161: raystack.compass.v1beta1.CompassService.UpsertEntity:input_type -> raystack.compass.v1beta1.UpsertEntityRequest + 111, // 162: raystack.compass.v1beta1.CompassService.DeleteEntity:input_type -> raystack.compass.v1beta1.DeleteEntityRequest + 113, // 163: raystack.compass.v1beta1.CompassService.SearchEntities:input_type -> raystack.compass.v1beta1.SearchEntitiesRequest + 115, // 164: raystack.compass.v1beta1.CompassService.SuggestEntities:input_type -> raystack.compass.v1beta1.SuggestEntitiesRequest + 117, // 165: raystack.compass.v1beta1.CompassService.GetEntityTypes:input_type -> raystack.compass.v1beta1.GetEntityTypesRequest + 119, // 166: raystack.compass.v1beta1.CompassService.GetEntityContext:input_type -> raystack.compass.v1beta1.GetEntityContextRequest + 121, // 167: raystack.compass.v1beta1.CompassService.GetEntityImpact:input_type -> raystack.compass.v1beta1.GetEntityImpactRequest + 123, // 168: raystack.compass.v1beta1.CompassService.UpsertEdge:input_type -> raystack.compass.v1beta1.UpsertEdgeRequest + 125, // 169: raystack.compass.v1beta1.CompassService.GetEdges:input_type -> raystack.compass.v1beta1.GetEdgesRequest + 127, // 170: raystack.compass.v1beta1.CompassService.DeleteEdge:input_type -> raystack.compass.v1beta1.DeleteEdgeRequest + 1, // 171: raystack.compass.v1beta1.CompassService.GetAllDiscussions:output_type -> raystack.compass.v1beta1.GetAllDiscussionsResponse + 3, // 172: raystack.compass.v1beta1.CompassService.CreateDiscussion:output_type -> raystack.compass.v1beta1.CreateDiscussionResponse + 5, // 173: raystack.compass.v1beta1.CompassService.GetDiscussion:output_type -> raystack.compass.v1beta1.GetDiscussionResponse + 8, // 174: raystack.compass.v1beta1.CompassService.PatchDiscussion:output_type -> raystack.compass.v1beta1.PatchDiscussionResponse + 9, // 175: raystack.compass.v1beta1.CompassService.CreateComment:output_type -> raystack.compass.v1beta1.CreateCommentResponse + 11, // 176: raystack.compass.v1beta1.CompassService.GetAllComments:output_type -> raystack.compass.v1beta1.GetAllCommentsResponse + 13, // 177: raystack.compass.v1beta1.CompassService.GetComment:output_type -> raystack.compass.v1beta1.GetCommentResponse + 15, // 178: raystack.compass.v1beta1.CompassService.UpdateComment:output_type -> raystack.compass.v1beta1.UpdateCommentResponse + 17, // 179: raystack.compass.v1beta1.CompassService.DeleteComment:output_type -> raystack.compass.v1beta1.DeleteCommentResponse + 20, // 180: raystack.compass.v1beta1.CompassService.SearchAssets:output_type -> raystack.compass.v1beta1.SearchAssetsResponse + 22, // 181: raystack.compass.v1beta1.CompassService.SuggestAssets:output_type -> raystack.compass.v1beta1.SuggestAssetsResponse + 24, // 182: raystack.compass.v1beta1.CompassService.GroupAssets:output_type -> raystack.compass.v1beta1.GroupAssetsResponse + 28, // 183: raystack.compass.v1beta1.CompassService.GetGraph:output_type -> raystack.compass.v1beta1.GetGraphResponse + 30, // 184: raystack.compass.v1beta1.CompassService.GetAllTypes:output_type -> raystack.compass.v1beta1.GetAllTypesResponse + 32, // 185: raystack.compass.v1beta1.CompassService.GetAllAssets:output_type -> raystack.compass.v1beta1.GetAllAssetsResponse + 34, // 186: raystack.compass.v1beta1.CompassService.GetAssetByID:output_type -> raystack.compass.v1beta1.GetAssetByIDResponse + 36, // 187: raystack.compass.v1beta1.CompassService.UpsertAsset:output_type -> raystack.compass.v1beta1.UpsertAssetResponse + 38, // 188: raystack.compass.v1beta1.CompassService.UpsertPatchAsset:output_type -> raystack.compass.v1beta1.UpsertPatchAssetResponse + 40, // 189: raystack.compass.v1beta1.CompassService.DeleteAsset:output_type -> raystack.compass.v1beta1.DeleteAssetResponse + 42, // 190: raystack.compass.v1beta1.CompassService.GetAssetStargazers:output_type -> raystack.compass.v1beta1.GetAssetStargazersResponse + 44, // 191: raystack.compass.v1beta1.CompassService.GetAssetVersionHistory:output_type -> raystack.compass.v1beta1.GetAssetVersionHistoryResponse + 46, // 192: raystack.compass.v1beta1.CompassService.GetAssetByVersion:output_type -> raystack.compass.v1beta1.GetAssetByVersionResponse + 48, // 193: raystack.compass.v1beta1.CompassService.CreateAssetProbe:output_type -> raystack.compass.v1beta1.CreateAssetProbeResponse + 50, // 194: raystack.compass.v1beta1.CompassService.GetUserStarredAssets:output_type -> raystack.compass.v1beta1.GetUserStarredAssetsResponse + 52, // 195: raystack.compass.v1beta1.CompassService.GetMyStarredAssets:output_type -> raystack.compass.v1beta1.GetMyStarredAssetsResponse + 54, // 196: raystack.compass.v1beta1.CompassService.GetMyStarredAsset:output_type -> raystack.compass.v1beta1.GetMyStarredAssetResponse + 56, // 197: raystack.compass.v1beta1.CompassService.StarAsset:output_type -> raystack.compass.v1beta1.StarAssetResponse + 58, // 198: raystack.compass.v1beta1.CompassService.UnstarAsset:output_type -> raystack.compass.v1beta1.UnstarAssetResponse + 60, // 199: raystack.compass.v1beta1.CompassService.GetMyDiscussions:output_type -> raystack.compass.v1beta1.GetMyDiscussionsResponse + 62, // 200: raystack.compass.v1beta1.CompassService.CreateTagAsset:output_type -> raystack.compass.v1beta1.CreateTagAssetResponse + 64, // 201: raystack.compass.v1beta1.CompassService.GetTagByAssetAndTemplate:output_type -> raystack.compass.v1beta1.GetTagByAssetAndTemplateResponse + 66, // 202: raystack.compass.v1beta1.CompassService.UpdateTagAsset:output_type -> raystack.compass.v1beta1.UpdateTagAssetResponse + 68, // 203: raystack.compass.v1beta1.CompassService.DeleteTagAsset:output_type -> raystack.compass.v1beta1.DeleteTagAssetResponse + 70, // 204: raystack.compass.v1beta1.CompassService.GetAllTagsByAsset:output_type -> raystack.compass.v1beta1.GetAllTagsByAssetResponse + 72, // 205: raystack.compass.v1beta1.CompassService.GetAllTagTemplates:output_type -> raystack.compass.v1beta1.GetAllTagTemplatesResponse + 74, // 206: raystack.compass.v1beta1.CompassService.CreateTagTemplate:output_type -> raystack.compass.v1beta1.CreateTagTemplateResponse + 76, // 207: raystack.compass.v1beta1.CompassService.GetTagTemplate:output_type -> raystack.compass.v1beta1.GetTagTemplateResponse + 78, // 208: raystack.compass.v1beta1.CompassService.UpdateTagTemplate:output_type -> raystack.compass.v1beta1.UpdateTagTemplateResponse + 80, // 209: raystack.compass.v1beta1.CompassService.DeleteTagTemplate:output_type -> raystack.compass.v1beta1.DeleteTagTemplateResponse + 82, // 210: raystack.compass.v1beta1.CompassService.CreateNamespace:output_type -> raystack.compass.v1beta1.CreateNamespaceResponse + 84, // 211: raystack.compass.v1beta1.CompassService.GetNamespace:output_type -> raystack.compass.v1beta1.GetNamespaceResponse + 86, // 212: raystack.compass.v1beta1.CompassService.UpdateNamespace:output_type -> raystack.compass.v1beta1.UpdateNamespaceResponse + 88, // 213: raystack.compass.v1beta1.CompassService.ListNamespaces:output_type -> raystack.compass.v1beta1.ListNamespacesResponse + 106, // 214: raystack.compass.v1beta1.CompassService.GetAllEntities:output_type -> raystack.compass.v1beta1.GetAllEntitiesResponse + 108, // 215: raystack.compass.v1beta1.CompassService.GetEntityByID:output_type -> raystack.compass.v1beta1.GetEntityByIDResponse + 110, // 216: raystack.compass.v1beta1.CompassService.UpsertEntity:output_type -> raystack.compass.v1beta1.UpsertEntityResponse + 112, // 217: raystack.compass.v1beta1.CompassService.DeleteEntity:output_type -> raystack.compass.v1beta1.DeleteEntityResponse + 114, // 218: raystack.compass.v1beta1.CompassService.SearchEntities:output_type -> raystack.compass.v1beta1.SearchEntitiesResponse + 116, // 219: raystack.compass.v1beta1.CompassService.SuggestEntities:output_type -> raystack.compass.v1beta1.SuggestEntitiesResponse + 118, // 220: raystack.compass.v1beta1.CompassService.GetEntityTypes:output_type -> raystack.compass.v1beta1.GetEntityTypesResponse + 120, // 221: raystack.compass.v1beta1.CompassService.GetEntityContext:output_type -> raystack.compass.v1beta1.GetEntityContextResponse + 122, // 222: raystack.compass.v1beta1.CompassService.GetEntityImpact:output_type -> raystack.compass.v1beta1.GetEntityImpactResponse + 124, // 223: raystack.compass.v1beta1.CompassService.UpsertEdge:output_type -> raystack.compass.v1beta1.UpsertEdgeResponse + 126, // 224: raystack.compass.v1beta1.CompassService.GetEdges:output_type -> raystack.compass.v1beta1.GetEdgesResponse + 128, // 225: raystack.compass.v1beta1.CompassService.DeleteEdge:output_type -> raystack.compass.v1beta1.DeleteEdgeResponse + 171, // [171:226] is the sub-list for method output_type + 116, // [116:171] is the sub-list for method input_type + 116, // [116:116] is the sub-list for extension type_name + 116, // [116:116] is the sub-list for extension extendee + 0, // [0:116] is the sub-list for field type_name } func init() { file_raystack_compass_v1beta1_service_proto_init() } @@ -7273,7 +8988,7 @@ func file_raystack_compass_v1beta1_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_raystack_compass_v1beta1_service_proto_rawDesc), len(file_raystack_compass_v1beta1_service_proto_rawDesc)), NumEnums: 0, - NumMessages: 117, + NumMessages: 143, NumExtensions: 0, NumServices: 1, }, diff --git a/handler/entity.go b/handler/entity.go new file mode 100644 index 00000000..fdec7780 --- /dev/null +++ b/handler/entity.go @@ -0,0 +1,318 @@ +package handler + +import ( + "context" + "strings" + + "connectrpc.com/connect" + "github.com/raystack/compass/internal/middleware" + "github.com/raystack/compass/core/entity" + "github.com/raystack/compass/core/namespace" + compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" + "google.golang.org/protobuf/types/known/structpb" + "google.golang.org/protobuf/types/known/timestamppb" +) + +// EntityServiceV2 defines entity operations for the handler. +type EntityServiceV2 interface { + Upsert(ctx context.Context, ns *namespace.Namespace, ent *entity.Entity) (string, error) + UpsertWithEdges(ctx context.Context, ns *namespace.Namespace, ent *entity.Entity, upstreams, downstreams []string) (string, error) + GetByURN(ctx context.Context, ns *namespace.Namespace, urn string) (entity.Entity, error) + GetByID(ctx context.Context, id string) (entity.Entity, error) + GetAll(ctx context.Context, ns *namespace.Namespace, flt entity.Filter) ([]entity.Entity, int, error) + GetTypes(ctx context.Context, ns *namespace.Namespace) (map[entity.Type]int, error) + Delete(ctx context.Context, ns *namespace.Namespace, urn string) error + Search(ctx context.Context, cfg entity.SearchConfig) ([]entity.SearchResult, error) + Suggest(ctx context.Context, ns *namespace.Namespace, text string, limit int) ([]string, error) + GetContext(ctx context.Context, ns *namespace.Namespace, urn string, depth int) (*entity.ContextGraph, error) + GetImpact(ctx context.Context, ns *namespace.Namespace, urn string, depth int) ([]entity.Edge, error) +} + +// EdgeServiceV2 defines edge operations for the handler. +type EdgeServiceV2 interface { + Upsert(ctx context.Context, ns *namespace.Namespace, e *entity.Edge) error + GetBySource(ctx context.Context, ns *namespace.Namespace, urn string, filter entity.EdgeFilter) ([]entity.Edge, error) + GetByTarget(ctx context.Context, ns *namespace.Namespace, urn string, filter entity.EdgeFilter) ([]entity.Edge, error) + Delete(ctx context.Context, ns *namespace.Namespace, sourceURN, targetURN, edgeType string) error +} + +func (server *Handler) GetAllEntities(ctx context.Context, req *connect.Request[compassv1beta1.GetAllEntitiesRequest]) (*connect.Response[compassv1beta1.GetAllEntitiesResponse], error) { + ns := middleware.FetchNamespaceFromContext(ctx) + + flt := entity.Filter{ + Size: int(req.Msg.GetSize()), + Offset: int(req.Msg.GetOffset()), + Query: req.Msg.GetQ(), + } + if types := req.Msg.GetTypes(); types != "" { + for _, t := range strings.Split(types, ",") { + flt.Types = append(flt.Types, entity.Type(strings.TrimSpace(t))) + } + } + if src := req.Msg.GetSource(); src != "" { + flt.Source = src + } + + entities, total, err := server.entityService.GetAll(ctx, ns, flt) + if err != nil { + return nil, internalServerError(ctx, "error getting entities", err) + } + + data := make([]*compassv1beta1.Entity, len(entities)) + for i, e := range entities { + data[i] = entityToProto(e) + } + + return connect.NewResponse(&compassv1beta1.GetAllEntitiesResponse{ + Data: data, + Total: uint32(total), + }), nil +} + +func (server *Handler) GetEntityByID(ctx context.Context, req *connect.Request[compassv1beta1.GetEntityByIDRequest]) (*connect.Response[compassv1beta1.GetEntityByIDResponse], error) { + ent, err := server.entityService.GetByID(ctx, req.Msg.GetId()) + if err != nil { + return nil, internalServerError(ctx, "error getting entity", err) + } + return connect.NewResponse(&compassv1beta1.GetEntityByIDResponse{ + Data: entityToProto(ent), + }), nil +} + +func (server *Handler) UpsertEntity(ctx context.Context, req *connect.Request[compassv1beta1.UpsertEntityRequest]) (*connect.Response[compassv1beta1.UpsertEntityResponse], error) { + ns := middleware.FetchNamespaceFromContext(ctx) + + ent := &entity.Entity{ + URN: req.Msg.GetUrn(), + Type: entity.Type(req.Msg.GetType()), + Name: req.Msg.GetName(), + Description: req.Msg.GetDescription(), + Source: req.Msg.GetSource(), + } + if req.Msg.GetProperties() != nil { + ent.Properties = req.Msg.GetProperties().AsMap() + } + + id, err := server.entityService.UpsertWithEdges(ctx, ns, ent, + req.Msg.GetUpstreams(), req.Msg.GetDownstreams()) + if err != nil { + return nil, internalServerError(ctx, "error upserting entity", err) + } + + return connect.NewResponse(&compassv1beta1.UpsertEntityResponse{Id: id}), nil +} + +func (server *Handler) DeleteEntity(ctx context.Context, req *connect.Request[compassv1beta1.DeleteEntityRequest]) (*connect.Response[compassv1beta1.DeleteEntityResponse], error) { + ns := middleware.FetchNamespaceFromContext(ctx) + + if err := server.entityService.Delete(ctx, ns, req.Msg.GetUrn()); err != nil { + return nil, internalServerError(ctx, "error deleting entity", err) + } + return connect.NewResponse(&compassv1beta1.DeleteEntityResponse{}), nil +} + +func (server *Handler) SearchEntities(ctx context.Context, req *connect.Request[compassv1beta1.SearchEntitiesRequest]) (*connect.Response[compassv1beta1.SearchEntitiesResponse], error) { + ns := middleware.FetchNamespaceFromContext(ctx) + + cfg := entity.SearchConfig{ + Text: req.Msg.GetText(), + MaxResults: int(req.Msg.GetSize()), + Offset: int(req.Msg.GetOffset()), + Mode: entity.SearchMode(req.Msg.GetMode()), + Namespace: ns, + } + if types := req.Msg.GetTypes(); types != "" { + cfg.Filters = map[string][]string{"type": strings.Split(types, ",")} + } + if src := req.Msg.GetSource(); src != "" { + if cfg.Filters == nil { + cfg.Filters = make(map[string][]string) + } + cfg.Filters["source"] = []string{src} + } + + results, err := server.entityService.Search(ctx, cfg) + if err != nil { + return nil, internalServerError(ctx, "error searching entities", err) + } + + data := make([]*compassv1beta1.Entity, len(results)) + for i, r := range results { + data[i] = &compassv1beta1.Entity{ + Id: r.ID, + Urn: r.URN, + Type: r.Type, + Name: r.Name, + Source: r.Source, + Description: r.Description, + } + } + return connect.NewResponse(&compassv1beta1.SearchEntitiesResponse{Data: data}), nil +} + +func (server *Handler) SuggestEntities(ctx context.Context, req *connect.Request[compassv1beta1.SuggestEntitiesRequest]) (*connect.Response[compassv1beta1.SuggestEntitiesResponse], error) { + ns := middleware.FetchNamespaceFromContext(ctx) + + suggestions, err := server.entityService.Suggest(ctx, ns, req.Msg.GetText(), 5) + if err != nil { + return nil, internalServerError(ctx, "error suggesting entities", err) + } + return connect.NewResponse(&compassv1beta1.SuggestEntitiesResponse{Data: suggestions}), nil +} + +func (server *Handler) GetEntityTypes(ctx context.Context, _ *connect.Request[compassv1beta1.GetEntityTypesRequest]) (*connect.Response[compassv1beta1.GetEntityTypesResponse], error) { + ns := middleware.FetchNamespaceFromContext(ctx) + + types, err := server.entityService.GetTypes(ctx, ns) + if err != nil { + return nil, internalServerError(ctx, "error getting entity types", err) + } + + data := make([]*compassv1beta1.Type, 0, len(types)) + for t, count := range types { + data = append(data, &compassv1beta1.Type{Name: t.String(), Count: uint32(count)}) + } + return connect.NewResponse(&compassv1beta1.GetEntityTypesResponse{Data: data}), nil +} + +func (server *Handler) GetEntityContext(ctx context.Context, req *connect.Request[compassv1beta1.GetEntityContextRequest]) (*connect.Response[compassv1beta1.GetEntityContextResponse], error) { + ns := middleware.FetchNamespaceFromContext(ctx) + + cg, err := server.entityService.GetContext(ctx, ns, req.Msg.GetUrn(), int(req.Msg.GetDepth())) + if err != nil { + return nil, internalServerError(ctx, "error getting entity context", err) + } + + edges := make([]*compassv1beta1.Edge, len(cg.Edges)) + for i, e := range cg.Edges { + edges[i] = edgeToProto(e) + } + related := make([]*compassv1beta1.Entity, len(cg.Related)) + for i, r := range cg.Related { + related[i] = entityToProto(r) + } + + return connect.NewResponse(&compassv1beta1.GetEntityContextResponse{ + Entity: entityToProto(cg.Entity), + Edges: edges, + Related: related, + }), nil +} + +func (server *Handler) GetEntityImpact(ctx context.Context, req *connect.Request[compassv1beta1.GetEntityImpactRequest]) (*connect.Response[compassv1beta1.GetEntityImpactResponse], error) { + ns := middleware.FetchNamespaceFromContext(ctx) + + impactEdges, err := server.entityService.GetImpact(ctx, ns, req.Msg.GetUrn(), int(req.Msg.GetDepth())) + if err != nil { + return nil, internalServerError(ctx, "error analyzing impact", err) + } + + edges := make([]*compassv1beta1.Edge, len(impactEdges)) + for i, e := range impactEdges { + edges[i] = edgeToProto(e) + } + + return connect.NewResponse(&compassv1beta1.GetEntityImpactResponse{Edges: edges}), nil +} + +func (server *Handler) UpsertEdge(ctx context.Context, req *connect.Request[compassv1beta1.UpsertEdgeRequest]) (*connect.Response[compassv1beta1.UpsertEdgeResponse], error) { + ns := middleware.FetchNamespaceFromContext(ctx) + + e := &entity.Edge{ + SourceURN: req.Msg.GetSourceUrn(), + TargetURN: req.Msg.GetTargetUrn(), + Type: req.Msg.GetType(), + Source: req.Msg.GetSource(), + } + if req.Msg.GetProperties() != nil { + e.Properties = req.Msg.GetProperties().AsMap() + } + + if err := server.edgeService.Upsert(ctx, ns, e); err != nil { + return nil, internalServerError(ctx, "error upserting edge", err) + } + return connect.NewResponse(&compassv1beta1.UpsertEdgeResponse{Id: e.ID}), nil +} + +func (server *Handler) GetEdges(ctx context.Context, req *connect.Request[compassv1beta1.GetEdgesRequest]) (*connect.Response[compassv1beta1.GetEdgesResponse], error) { + ns := middleware.FetchNamespaceFromContext(ctx) + + filter := entity.EdgeFilter{Current: req.Msg.GetCurrentOnly()} + if t := req.Msg.GetType(); t != "" { + filter.Types = []string{t} + } + + var allEdges []entity.Edge + dir := req.Msg.GetDirection() + if dir == "" || dir == "both" || dir == "outgoing" { + edges, err := server.edgeService.GetBySource(ctx, ns, req.Msg.GetUrn(), filter) + if err != nil { + return nil, internalServerError(ctx, "error getting outgoing edges", err) + } + allEdges = append(allEdges, edges...) + } + if dir == "" || dir == "both" || dir == "incoming" { + edges, err := server.edgeService.GetByTarget(ctx, ns, req.Msg.GetUrn(), filter) + if err != nil { + return nil, internalServerError(ctx, "error getting incoming edges", err) + } + allEdges = append(allEdges, edges...) + } + + data := make([]*compassv1beta1.Edge, len(allEdges)) + for i, e := range allEdges { + data[i] = edgeToProto(e) + } + return connect.NewResponse(&compassv1beta1.GetEdgesResponse{Data: data}), nil +} + +func (server *Handler) DeleteEdge(ctx context.Context, req *connect.Request[compassv1beta1.DeleteEdgeRequest]) (*connect.Response[compassv1beta1.DeleteEdgeResponse], error) { + ns := middleware.FetchNamespaceFromContext(ctx) + + if err := server.edgeService.Delete(ctx, ns, req.Msg.GetSourceUrn(), req.Msg.GetTargetUrn(), req.Msg.GetType()); err != nil { + return nil, internalServerError(ctx, "error deleting edge", err) + } + return connect.NewResponse(&compassv1beta1.DeleteEdgeResponse{}), nil +} + +// Proto conversion helpers + +func entityToProto(e entity.Entity) *compassv1beta1.Entity { + pb := &compassv1beta1.Entity{ + Id: e.ID, + Urn: e.URN, + Type: string(e.Type), + Name: e.Name, + Description: e.Description, + Source: e.Source, + ValidFrom: timestamppb.New(e.ValidFrom), + CreatedAt: timestamppb.New(e.CreatedAt), + UpdatedAt: timestamppb.New(e.UpdatedAt), + } + if e.ValidTo != nil { + pb.ValidTo = timestamppb.New(*e.ValidTo) + } + if len(e.Properties) > 0 { + pb.Properties, _ = structpb.NewStruct(e.Properties) + } + return pb +} + +func edgeToProto(e entity.Edge) *compassv1beta1.Edge { + pb := &compassv1beta1.Edge{ + Id: e.ID, + SourceUrn: e.SourceURN, + TargetUrn: e.TargetURN, + Type: e.Type, + Source: e.Source, + ValidFrom: timestamppb.New(e.ValidFrom), + CreatedAt: timestamppb.New(e.CreatedAt), + } + if e.ValidTo != nil { + pb.ValidTo = timestamppb.New(*e.ValidTo) + } + if len(e.Properties) > 0 { + pb.Properties, _ = structpb.NewStruct(e.Properties) + } + return pb +} diff --git a/handler/handler.go b/handler/handler.go index adf29d71..865490c8 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -21,12 +21,27 @@ type Handler struct { tagService TagService tagTemplateService TagTemplateService userService UserService + entityService EntityServiceV2 + edgeService EdgeServiceV2 } var ( errMissingUserInfo = errors.New("missing user information") ) +// HandlerOption configures the Handler. +type HandlerOption func(*Handler) + +// WithEntityService adds the v2 entity service. +func WithEntityService(svc EntityServiceV2) HandlerOption { + return func(h *Handler) { h.entityService = svc } +} + +// WithEdgeService adds the v2 edge service. +func WithEdgeService(svc EdgeServiceV2) HandlerOption { + return func(h *Handler) { h.edgeService = svc } +} + func New( namespaceService NamespaceService, assetService AssetService, @@ -35,8 +50,9 @@ func New( tagService TagService, tagTemplateService TagTemplateService, userService UserService, + opts ...HandlerOption, ) *Handler { - return &Handler{ + h := &Handler{ namespaceService: namespaceService, assetService: assetService, starService: starService, @@ -45,6 +61,10 @@ func New( tagTemplateService: tagTemplateService, userService: userService, } + for _, opt := range opts { + opt(h) + } + return h } func (server *Handler) validateUserInCtx(ctx context.Context, ns *namespace.Namespace) (string, error) { diff --git a/internal/server/bootstrap.go b/internal/server/bootstrap.go index 74cd5966..b7cf7ba7 100644 --- a/internal/server/bootstrap.go +++ b/internal/server/bootstrap.go @@ -15,6 +15,7 @@ import ( "github.com/raystack/compass/core/star" "github.com/raystack/compass/core/tag" "github.com/raystack/compass/core/user" + "github.com/raystack/compass/handler" "github.com/raystack/compass/internal/config" compassmcp "github.com/raystack/compass/internal/mcp" "github.com/raystack/compass/internal/telemetry" @@ -149,6 +150,8 @@ func Start(ctx context.Context, cfg *config.Config, version string) error { tagService, tagTemplateService, userService, + handler.WithEntityService(entityService), + handler.WithEdgeService(edgeRepo), ) } diff --git a/internal/server/server.go b/internal/server/server.go index 1b1d5c98..a08e6aa0 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -34,6 +34,7 @@ func Serve( tagService handler.TagService, tagTemplateService handler.TagTemplateService, userService handler.UserService, + handlerOpts ...handler.HandlerOption, ) error { logger := slog.Default().With("component", "server") @@ -45,6 +46,7 @@ func Serve( tagService, tagTemplateService, userService, + handlerOpts..., ) // Build interceptor chain From a98d068d7e6325c3a6a0b4ef607b9fb6ba9d1d2c Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 29 Mar 2026 01:46:41 -0500 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20remove=20old=20asset=20system,=20?= =?UTF-8?q?discussions,=20tags=20=E2=80=94=20entity-only?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deleted: - core/asset/ — entire old asset package - core/discussion/ — discussions and comments - core/tag/ — tags and tag templates - store/elasticsearch/ — ES client and discovery repos - store/postgres/asset_*, lineage_*, discussion_*, comment_*, tag_* repos - handler/asset.go, discussion.go, comment.go, tag.go, search.go, lineage.go - All old CLI commands (assets, discussions, lineage, search) - All old migrations (replaced with single 000001_init_schema.up.sql) Updated: - Proto regenerated from proton (entity-only service definition) - handler.go: simplified — only namespace, star, user, entity, edge services - bootstrap.go: removed ES, removed all old service wiring - config.go: removed Elasticsearch config - star package: updated to use entity.Entity instead of asset.Asset - CLI: entity commands (list, view, upsert, delete, search, types, context, impact) - Migration: single fresh schema with namespaces, users, entities, edges, chunks, stars Schema (6 tables): - namespaces, users, entities, edges, chunks, stars - tsvector + pg_trgm + pgvector for search (no ES) - RLS on all tables --- cli/assets.go | 549 -- cli/discussions.go | 176 - cli/entities.go | 319 + cli/lineage.go | 52 - cli/root.go | 6 +- cli/search.go | 77 - core/asset/asset.go | 69 - core/asset/asset_test.go | 490 - core/asset/discovery.go | 112 - core/asset/discovery_test.go | 111 - core/asset/errors.go | 55 - core/asset/filter.go | 129 - core/asset/filter_test.go | 111 - core/asset/lineage.go | 64 - core/asset/mocks/asset_repository.go | 844 -- core/asset/mocks/discovery_repository.go | 318 - core/asset/mocks/lineage_repository.go | 193 - core/asset/patch.go | 187 - core/asset/probe.go | 16 - core/asset/probes_filter.go | 10 - core/asset/service.go | 224 - core/asset/service_test.go | 915 -- core/asset/type.go | 47 - core/asset/type_test.go | 37 - core/asset/unique_strings.go | 28 - core/asset/version.go | 28 - core/asset/version_test.go | 55 - core/discussion/comment.go | 31 - core/discussion/comment_test.go | 28 - core/discussion/discussion.go | 115 - core/discussion/discussion_test.go | 152 - core/discussion/errors.go | 45 - core/discussion/filter.go | 45 - core/discussion/filter_test.go | 98 - .../discussion/mocks/discussion_repository.go | 496 - core/discussion/service.go | 44 - core/discussion/service_test.go | 457 - core/discussion/state.go | 37 - core/discussion/state_test.go | 98 - core/discussion/type_test.go | 108 - core/discussion/types.go | 40 - core/star/errors.go | 20 +- core/star/mocks/star_repository.go | 124 +- core/star/service.go | 22 +- core/star/star.go | 14 +- core/tag/errors.go | 51 - core/tag/mocks/tag_repository.go | 225 - core/tag/mocks/tag_template_repository.go | 281 - core/tag/service.go | 192 - core/tag/service_test.go | 617 -- core/tag/tag.go | 39 - core/tag/tag_template.go | 41 - core/tag/tag_template_service.go | 144 - core/tag/tag_template_service_test.go | 604 -- core/tag/utils.go | 64 - core/tag/validator.go | 107 - core/tag/validator/builder.go | 169 - core/tag/validator/error.go | 29 - core/tag/validator/validator.go | 31 - docs/docs/guides/discussion.md | 219 - docs/docs/guides/tagging.md | 204 - .../compassv1beta1connect/service.connect.go | 1598 +--- gen/raystack/compass/v1beta1/service.pb.go | 8344 +++-------------- handler/asset.go | 720 -- handler/asset_test.go | 1686 ---- handler/comment.go | 279 - handler/comment_test.go | 779 -- handler/discussion.go | 227 - handler/discussion_test.go | 621 -- handler/handler.go | 52 +- handler/lineage.go | 97 - handler/lineage_test.go | 120 - handler/mocks/asset_service.go | 708 -- handler/mocks/discussion_service.go | 497 - handler/mocks/star_service.go | 310 - handler/mocks/tag_service.go | 323 - handler/mocks/tag_template_service.go | 323 - handler/namespace_test.go | 349 - handler/option.go | 3 - handler/search.go | 147 - handler/search_test.go | 373 - handler/star.go | 16 +- handler/tag.go | 350 - handler/tag_template.go | 276 - handler/tag_template_test.go | 698 -- handler/tag_test.go | 847 -- handler/type.go | 42 - handler/type_test.go | 152 - handler/user.go | 268 +- handler/user_test.go | 851 -- internal/config/config.go | 12 +- internal/mcp/format.go | 201 - internal/mcp/handlers.go | 127 - internal/mcp/handlers_test.go | 298 - internal/mcp/server.go | 48 +- internal/mcp/server_test.go | 229 - internal/mcp/tools.go | 77 - internal/server/bootstrap.go | 85 +- internal/server/server.go | 14 +- store/elasticsearch/discovery_repository.go | 183 - .../discovery_repository_test.go | 315 - .../discovery_search_repository.go | 527 -- .../discovery_search_repository_test.go | 282 - store/elasticsearch/es.go | 284 - store/elasticsearch/es_test.go | 159 - store/elasticsearch/init_test.go | 29 - store/elasticsearch/options.go | 11 - store/elasticsearch/schema.go | 139 - .../testdata/search-test-fixture.json | 437 - .../testdata/suggest-test-fixture.json | 22 - .../elasticsearch/testutil/elastic_search.go | 223 - store/postgres/asset_model.go | 195 - store/postgres/asset_model_test.go | 24 - store/postgres/asset_repository.go | 1058 --- store/postgres/asset_repository_test.go | 1870 ---- store/postgres/comment_model.go | 29 - .../postgres/discussion_comment_repository.go | 180 - .../discussion_comment_repository_test.go | 227 - store/postgres/discussion_model.go | 56 - store/postgres/discussion_repository.go | 296 - store/postgres/discussion_repository_test.go | 436 - store/postgres/jsonmap.go | 54 + store/postgres/lineage_model.go | 33 - store/postgres/lineage_repository.go | 384 - store/postgres/lineage_repository_test.go | 196 - ...reate_tags_templates_fields_table.down.sql | 9 - ..._create_tags_templates_fields_table.up.sql | 38 - .../migrations/000001_init_schema.down.sql | 6 + .../migrations/000001_init_schema.up.sql | 154 + .../000002_create_users_table.down.sql | 1 - .../000002_create_users_table.up.sql | 11 - .../000003_create_assets_table.down.sql | 2 - .../000003_create_assets_table.up.sql | 24 - .../000004_create_stars_table.down.sql | 1 - .../000004_create_stars_table.up.sql | 10 - ...0005_create_assets_versions_table.down.sql | 1 - ...000005_create_assets_versions_table.up.sql | 20 - ...000006_create_lineage_graph_table.down.sql | 1 - .../000006_create_lineage_graph_table.up.sql | 6 - .../000007_create_discussions_table.down.sql | 1 - .../000007_create_discussions_table.up.sql | 19 - .../000008_create_comments_table.down.sql | 1 - .../000008_create_comments_table.up.sql | 12 - ...009_update_tags_templates_assetid.down.sql | 12 - ...00009_update_tags_templates_assetid.up.sql | 12 - ..._drop_assets_idx_urn_type_service.down.sql | 1 - ...10_drop_assets_idx_urn_type_service.up.sql | 4 - .../000011_create_idx_assets_urn.down.sql | 1 - .../000011_create_idx_assets_urn.up.sql | 1 - .../000012_create_asset_probes_table.down.sql | 1 - .../000012_create_asset_probes_table.up.sql | 9 - .../000013_alter_assets_table.down.sql | 1 - .../000013_alter_assets_table.up.sql | 1 - ...table_and_add_namespace_in_tables.down.sql | 65 - ...e_table_and_add_namespace_in_tables.up.sql | 66 - ...ble_row_level_security_all_tables.down.sql | 29 - ...nable_row_level_security_all_tables.up.sql | 52 - .../000016_update_assets_versions.down.sql | 0 .../000016_update_assets_versions.up.sql | 1 - .../000017_add_soft_deletion.down.sql | 3 - .../000017_add_soft_deletion.up.sql | 3 - .../000018_index_asset_probes.down.sql | 2 - .../000018_index_asset_probes.up.sql | 2 - .../000019_create_entity_tables.down.sql | 3 - .../000019_create_entity_tables.up.sql | 98 - store/postgres/postgres_test.go | 207 - store/postgres/star_repository.go | 238 +- store/postgres/star_repository_test.go | 466 - store/postgres/tag_model.go | 310 - store/postgres/tag_model_test.go | 360 - store/postgres/tag_repository.go | 315 - store/postgres/tag_repository_test.go | 471 - store/postgres/tag_template_repository.go | 321 - .../postgres/tag_template_repository_test.go | 432 - test/asset_test.go | 289 - test/helper_test.go | 156 - 176 files changed, 2316 insertions(+), 41942 deletions(-) delete mode 100644 cli/assets.go delete mode 100644 cli/discussions.go create mode 100644 cli/entities.go delete mode 100644 cli/lineage.go delete mode 100644 cli/search.go delete mode 100644 core/asset/asset.go delete mode 100644 core/asset/asset_test.go delete mode 100644 core/asset/discovery.go delete mode 100644 core/asset/discovery_test.go delete mode 100644 core/asset/errors.go delete mode 100644 core/asset/filter.go delete mode 100644 core/asset/filter_test.go delete mode 100644 core/asset/lineage.go delete mode 100644 core/asset/mocks/asset_repository.go delete mode 100644 core/asset/mocks/discovery_repository.go delete mode 100644 core/asset/mocks/lineage_repository.go delete mode 100644 core/asset/patch.go delete mode 100644 core/asset/probe.go delete mode 100644 core/asset/probes_filter.go delete mode 100644 core/asset/service.go delete mode 100644 core/asset/service_test.go delete mode 100644 core/asset/type.go delete mode 100644 core/asset/type_test.go delete mode 100644 core/asset/unique_strings.go delete mode 100644 core/asset/version.go delete mode 100644 core/asset/version_test.go delete mode 100644 core/discussion/comment.go delete mode 100644 core/discussion/comment_test.go delete mode 100644 core/discussion/discussion.go delete mode 100644 core/discussion/discussion_test.go delete mode 100644 core/discussion/errors.go delete mode 100644 core/discussion/filter.go delete mode 100644 core/discussion/filter_test.go delete mode 100644 core/discussion/mocks/discussion_repository.go delete mode 100644 core/discussion/service.go delete mode 100644 core/discussion/service_test.go delete mode 100644 core/discussion/state.go delete mode 100644 core/discussion/state_test.go delete mode 100644 core/discussion/type_test.go delete mode 100644 core/discussion/types.go delete mode 100644 core/tag/errors.go delete mode 100644 core/tag/mocks/tag_repository.go delete mode 100644 core/tag/mocks/tag_template_repository.go delete mode 100644 core/tag/service.go delete mode 100644 core/tag/service_test.go delete mode 100644 core/tag/tag.go delete mode 100644 core/tag/tag_template.go delete mode 100644 core/tag/tag_template_service.go delete mode 100644 core/tag/tag_template_service_test.go delete mode 100644 core/tag/utils.go delete mode 100644 core/tag/validator.go delete mode 100644 core/tag/validator/builder.go delete mode 100644 core/tag/validator/error.go delete mode 100644 core/tag/validator/validator.go delete mode 100644 docs/docs/guides/discussion.md delete mode 100644 docs/docs/guides/tagging.md delete mode 100644 handler/asset.go delete mode 100644 handler/asset_test.go delete mode 100644 handler/comment.go delete mode 100644 handler/comment_test.go delete mode 100644 handler/discussion.go delete mode 100644 handler/discussion_test.go delete mode 100644 handler/lineage.go delete mode 100644 handler/lineage_test.go delete mode 100644 handler/mocks/asset_service.go delete mode 100644 handler/mocks/discussion_service.go delete mode 100644 handler/mocks/star_service.go delete mode 100644 handler/mocks/tag_service.go delete mode 100644 handler/mocks/tag_template_service.go delete mode 100644 handler/namespace_test.go delete mode 100644 handler/option.go delete mode 100644 handler/search.go delete mode 100644 handler/search_test.go delete mode 100644 handler/tag.go delete mode 100644 handler/tag_template.go delete mode 100644 handler/tag_template_test.go delete mode 100644 handler/tag_test.go delete mode 100644 handler/type.go delete mode 100644 handler/type_test.go delete mode 100644 handler/user_test.go delete mode 100644 internal/mcp/format.go delete mode 100644 internal/mcp/handlers.go delete mode 100644 internal/mcp/handlers_test.go delete mode 100644 internal/mcp/server_test.go delete mode 100644 internal/mcp/tools.go delete mode 100644 store/elasticsearch/discovery_repository.go delete mode 100644 store/elasticsearch/discovery_repository_test.go delete mode 100644 store/elasticsearch/discovery_search_repository.go delete mode 100644 store/elasticsearch/discovery_search_repository_test.go delete mode 100644 store/elasticsearch/es.go delete mode 100644 store/elasticsearch/es_test.go delete mode 100644 store/elasticsearch/init_test.go delete mode 100644 store/elasticsearch/options.go delete mode 100644 store/elasticsearch/schema.go delete mode 100644 store/elasticsearch/testdata/search-test-fixture.json delete mode 100644 store/elasticsearch/testdata/suggest-test-fixture.json delete mode 100644 store/elasticsearch/testutil/elastic_search.go delete mode 100644 store/postgres/asset_model.go delete mode 100644 store/postgres/asset_model_test.go delete mode 100644 store/postgres/asset_repository.go delete mode 100644 store/postgres/asset_repository_test.go delete mode 100644 store/postgres/comment_model.go delete mode 100644 store/postgres/discussion_comment_repository.go delete mode 100644 store/postgres/discussion_comment_repository_test.go delete mode 100644 store/postgres/discussion_model.go delete mode 100644 store/postgres/discussion_repository.go delete mode 100644 store/postgres/discussion_repository_test.go create mode 100644 store/postgres/jsonmap.go delete mode 100644 store/postgres/lineage_model.go delete mode 100644 store/postgres/lineage_repository.go delete mode 100644 store/postgres/lineage_repository_test.go delete mode 100644 store/postgres/migrations/000001_create_tags_templates_fields_table.down.sql delete mode 100644 store/postgres/migrations/000001_create_tags_templates_fields_table.up.sql create mode 100644 store/postgres/migrations/000001_init_schema.down.sql create mode 100644 store/postgres/migrations/000001_init_schema.up.sql delete mode 100644 store/postgres/migrations/000002_create_users_table.down.sql delete mode 100644 store/postgres/migrations/000002_create_users_table.up.sql delete mode 100644 store/postgres/migrations/000003_create_assets_table.down.sql delete mode 100644 store/postgres/migrations/000003_create_assets_table.up.sql delete mode 100644 store/postgres/migrations/000004_create_stars_table.down.sql delete mode 100644 store/postgres/migrations/000004_create_stars_table.up.sql delete mode 100644 store/postgres/migrations/000005_create_assets_versions_table.down.sql delete mode 100644 store/postgres/migrations/000005_create_assets_versions_table.up.sql delete mode 100644 store/postgres/migrations/000006_create_lineage_graph_table.down.sql delete mode 100644 store/postgres/migrations/000006_create_lineage_graph_table.up.sql delete mode 100644 store/postgres/migrations/000007_create_discussions_table.down.sql delete mode 100644 store/postgres/migrations/000007_create_discussions_table.up.sql delete mode 100644 store/postgres/migrations/000008_create_comments_table.down.sql delete mode 100644 store/postgres/migrations/000008_create_comments_table.up.sql delete mode 100644 store/postgres/migrations/000009_update_tags_templates_assetid.down.sql delete mode 100644 store/postgres/migrations/000009_update_tags_templates_assetid.up.sql delete mode 100644 store/postgres/migrations/000010_drop_assets_idx_urn_type_service.down.sql delete mode 100644 store/postgres/migrations/000010_drop_assets_idx_urn_type_service.up.sql delete mode 100644 store/postgres/migrations/000011_create_idx_assets_urn.down.sql delete mode 100644 store/postgres/migrations/000011_create_idx_assets_urn.up.sql delete mode 100644 store/postgres/migrations/000012_create_asset_probes_table.down.sql delete mode 100644 store/postgres/migrations/000012_create_asset_probes_table.up.sql delete mode 100644 store/postgres/migrations/000013_alter_assets_table.down.sql delete mode 100644 store/postgres/migrations/000013_alter_assets_table.up.sql delete mode 100644 store/postgres/migrations/000014_create_namespace_table_and_add_namespace_in_tables.down.sql delete mode 100644 store/postgres/migrations/000014_create_namespace_table_and_add_namespace_in_tables.up.sql delete mode 100644 store/postgres/migrations/000015_enable_row_level_security_all_tables.down.sql delete mode 100644 store/postgres/migrations/000015_enable_row_level_security_all_tables.up.sql delete mode 100644 store/postgres/migrations/000016_update_assets_versions.down.sql delete mode 100644 store/postgres/migrations/000016_update_assets_versions.up.sql delete mode 100644 store/postgres/migrations/000017_add_soft_deletion.down.sql delete mode 100644 store/postgres/migrations/000017_add_soft_deletion.up.sql delete mode 100644 store/postgres/migrations/000018_index_asset_probes.down.sql delete mode 100644 store/postgres/migrations/000018_index_asset_probes.up.sql delete mode 100644 store/postgres/migrations/000019_create_entity_tables.down.sql delete mode 100644 store/postgres/migrations/000019_create_entity_tables.up.sql delete mode 100644 store/postgres/postgres_test.go delete mode 100644 store/postgres/star_repository_test.go delete mode 100644 store/postgres/tag_model.go delete mode 100644 store/postgres/tag_model_test.go delete mode 100644 store/postgres/tag_repository.go delete mode 100644 store/postgres/tag_repository_test.go delete mode 100644 store/postgres/tag_template_repository.go delete mode 100644 store/postgres/tag_template_repository_test.go delete mode 100644 test/asset_test.go delete mode 100644 test/helper_test.go diff --git a/cli/assets.go b/cli/assets.go deleted file mode 100644 index dfadbc9d..00000000 --- a/cli/assets.go +++ /dev/null @@ -1,549 +0,0 @@ -package cli - -import ( - "fmt" - "os" - - "github.com/MakeNowJust/heredoc" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/client" - "github.com/raystack/compass/internal/config" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "github.com/raystack/salt/cli/printer" - "github.com/spf13/cobra" -) - -const ( - pageSize = 10 - pageOffset = 0 -) - -func assetsCommand(cfg *config.Config) *cobra.Command { - cmd := &cobra.Command{ - Use: "asset", - Aliases: []string{"assets"}, - Short: "Manage assets", - Annotations: map[string]string{ - "group": "core", - }, - Example: heredoc.Doc(` - $ compass asset list - $ compass asset view - $ compass asset delete - $ compass asset edit - $ compass asset types - $ compass asset star - $ compass asset unstar - $ compass asset starred - $ compass asset stargazers - $ compass asset versionhistory - $ compass asset version - `), - } - - cmd.AddCommand( - listAllAssetsCommand(cfg), - viewAssetByIDCommand(cfg), - editAssetCommand(cfg), - deleteAssetByIDCommand(cfg), - listAllTypesCommand(cfg), - listAssetStargazerCommand(cfg), - starAssetCommand(cfg), - unstarAssetCommand(cfg), - starredAssetCommand(cfg), - versionHistoryAssetCommand(cfg), - viewAssetByVersionCommand(cfg), - ) - cmd.PersistentFlags().StringVarP(&namespaceID, "namespace", "n", namespace.DefaultNamespace.ID.String(), "namespace id or name") - return cmd -} - -func listAllAssetsCommand(cfg *config.Config) *cobra.Command { - var types, services, q, qFields, sort, sort_dir, output string - var data map[string]string - var size, page uint32 - cmd := &cobra.Command{ - Use: "list", - Short: "lists all assets", - Example: heredoc.Doc(` - $ compass asset list - `), - Args: cobra.NoArgs, - Annotations: map[string]string{ - "action:core": "true", - }, - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.GetAllAssetsRequest{ - Q: q, - QFields: qFields, - Types: types, - Services: services, - Sort: sort, - Direction: sort_dir, - Data: data, - Size: size, - Offset: page, - }) - res, err := clnt.GetAllAssets(cmd.Context(), req) - if err != nil { - return err - } - - spinner.Stop() - if output != "json" { - report := [][]string{} - report = append(report, []string{"ID", "TYPE", "SERVICE", "URN", "NAME", "VERSION"}) - for _, i := range res.Msg.GetData() { - report = append(report, []string{i.Id, i.Type, i.Service, i.Urn, printer.Bluef("%s", i.Name), i.Version}) - } - printer.Table(os.Stdout, report) - - fmt.Println(printer.Cyanf("To view all the data in JSON format, use flag `-o json`")) - } else { - fmt.Println(printer.Bluef("%s", prettyPrint(res.Msg.GetData()))) - } - - return nil - }, - } - - cmd.Flags().StringVarP(&types, "types", "t", "", "filter by types") - cmd.Flags().StringVarP(&services, "services", "s", "", "filter by services") - cmd.Flags().StringToStringVarP(&data, "data", "d", nil, "filter by field in asset.data") - cmd.Flags().StringVar(&q, "query", "", "querying by field") - cmd.Flags().StringVar(&qFields, "query_fields", "", "querying by fields") - cmd.Flags().StringVar(&sort, "sort", "", "sort by certain fields") - cmd.Flags().StringVar(&sort_dir, "sort_dir", "", "sorting direction (asc / desc)") - cmd.Flags().StringVarP(&output, "out", "o", "table", "flag to control output viewing, for json `-o json`") - cmd.Flags().Uint32Var(&size, "size", pageSize, "Size of each page") - cmd.Flags().Uint32Var(&page, "page", pageOffset, "Page number offset (starts from 0)") - - return cmd -} - -func viewAssetByIDCommand(cfg *config.Config) *cobra.Command { - cmd := &cobra.Command{ - Use: "view ", - Short: "view asset for the given ID or URN", - Example: heredoc.Doc(` - $ compass asset view - $ compass asset view - `), - Args: cobra.ExactArgs(1), - Annotations: map[string]string{ - "action:core": "true", - }, - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - assetID := args[0] - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.GetAssetByIDRequest{ - Id: assetID, - }) - res, err := clnt.GetAssetByID(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - - fmt.Println(printer.Bluef("%s", prettyPrint(res.Msg.GetData()))) - return nil - }, - } - return cmd -} - -func editAssetCommand(cfg *config.Config) *cobra.Command { - var filePath string - cmd := &cobra.Command{ - Use: "edit", - Short: "upsert a new asset or patch", - Example: heredoc.Doc(` - $ compass asset edit --body=filePath - `), - Args: cobra.NoArgs, - Annotations: map[string]string{ - "action:core": "true", - }, - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - var reqBody compassv1beta1.UpsertPatchAssetRequest - if err := parseFile(filePath, &reqBody); err != nil { - return err - } - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.UpsertPatchAssetRequest{ - Asset: reqBody.Asset, - Upstreams: reqBody.Upstreams, - }) - res, err := clnt.UpsertPatchAsset(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - - fmt.Println("ID: \t", printer.Greenf("%s", res.Msg.Id)) - return nil - }, - } - cmd.Flags().StringVarP(&filePath, "body", "b", "", "filepath to body that has to be upserted") - if err := cmd.MarkFlagRequired("body"); err != nil { - panic(err) - } - - return cmd -} - -func deleteAssetByIDCommand(cfg *config.Config) *cobra.Command { - cmd := &cobra.Command{ - Use: "delete ", - Short: "delete asset with the given ID", - Example: heredoc.Doc(` - $ compass asset delete - `), - Args: cobra.ExactArgs(1), - Annotations: map[string]string{ - "action:core": "true", - }, - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - assetID := args[0] - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.DeleteAssetRequest{ - Id: assetID, - }) - _, err = clnt.DeleteAsset(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - fmt.Println("Asset ", printer.Redf("%s", assetID), " Deleted Successfully") - return nil - }, - } - return cmd -} - -func listAllTypesCommand(cfg *config.Config) *cobra.Command { - var types, services, q, qFields string - var data map[string]string - - cmd := &cobra.Command{ - Use: "types", - Short: "lists all asset types", - Example: heredoc.Doc(` - $ compass asset types - $ compass asset types -t type1 --query query1 --query_fields qFields1 - `), - Args: cobra.NoArgs, - Annotations: map[string]string{ - "action:core": "true", - }, - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - req := client.NewRequest(cfg.Client, "", &compassv1beta1.GetAllTypesRequest{ - Q: q, - QFields: qFields, - Types: types, - Services: services, - Data: data, - }) - res, err := clnt.GetAllTypes(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - - report := [][]string{{"NAME", "COUNT"}} - for _, i := range res.Msg.GetData() { - report = append(report, []string{printer.Bluef("%s", i.Name), fmt.Sprintf("%v", i.Count)}) - } - printer.Table(os.Stdout, report) - - return nil - }, - } - cmd.Flags().StringVarP(&types, "types", "t", "", "filter by types") - cmd.Flags().StringVarP(&services, "services", "s", "", "filter by services") - cmd.Flags().StringToStringVarP(&data, "data", "d", nil, "filter by field in asset.data") - cmd.Flags().StringVar(&q, "query", "", "filter by specific query") - cmd.Flags().StringVar(&qFields, "query_fields", "", "filter by query field") - - return cmd -} - -func listAssetStargazerCommand(cfg *config.Config) *cobra.Command { - var size, page uint32 - cmd := &cobra.Command{ - Use: "stargazers ", - Short: "list all stargazers for a given asset id", - Example: heredoc.Doc(` - $ compass asset stargazers - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - assetID := args[0] - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.GetAssetStargazersRequest{ - Id: assetID, - Size: size, - Offset: page, - }) - res, err := clnt.GetAssetStargazers(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - fmt.Println(printer.Bluef("%s", prettyPrint(res.Msg.GetData()))) - return nil - }, - } - cmd.Flags().Uint32Var(&size, "size", pageSize, "Size of each page") - cmd.Flags().Uint32Var(&page, "page", pageOffset, "Page number offset (starts from 0)") - - return cmd -} - -func starAssetCommand(cfg *config.Config) *cobra.Command { - cmd := &cobra.Command{ - Use: "star ", - Short: "star an asset by id for current user", - Example: heredoc.Doc(` - $ compass asset star - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - assetID := args[0] - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.StarAssetRequest{ - AssetId: assetID, - }) - _, err = clnt.StarAsset(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - - fmt.Println(printer.Bluef("Asset %v starred successfully", assetID)) - - return nil - }, - } - return cmd -} - -func unstarAssetCommand(cfg *config.Config) *cobra.Command { - cmd := &cobra.Command{ - Use: "unstar ", - Short: "unstar an asset by id for current user", - Example: heredoc.Doc(` - $ compass unasset star - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - assetID := args[0] - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.UnstarAssetRequest{ - AssetId: assetID, - }) - _, err = clnt.UnstarAsset(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - - fmt.Println(printer.Bluef("Asset %v unstarred successfully", assetID)) - - return nil - }, - } - - return cmd -} - -func starredAssetCommand(cfg *config.Config) *cobra.Command { - var size, page uint32 - var output string - - cmd := &cobra.Command{ - Use: "starred", - Short: "list all the starred assets for current user", - Example: heredoc.Doc(` - $ compass asset starred - `), - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.GetMyStarredAssetsRequest{ - Size: size, - Offset: page, - }) - res, err := clnt.GetMyStarredAssets(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - - if output != "json" { - report := [][]string{} - report = append(report, []string{"ID", "TYPE", "SERVICE", "URN", "NAME", "VERSION"}) - for _, i := range res.Msg.GetData() { - report = append(report, []string{i.Id, i.Type, i.Service, i.Urn, printer.Bluef("%s", i.Name), i.Version}) - } - printer.Table(os.Stdout, report) - - fmt.Println(printer.Cyanf("To view all the data in JSON format, use flag `-o json`")) - } else { - fmt.Println(printer.Bluef("%s", prettyPrint(res.Msg.GetData()))) - } - - return nil - }, - } - cmd.Flags().StringVarP(&output, "out", "o", "table", "flag to control output viewing, for json `-o json`") - cmd.Flags().Uint32Var(&size, "size", pageSize, "Size of each page") - cmd.Flags().Uint32Var(&page, "page", pageOffset, "Page number offset (starts from 0)") - return cmd -} - -func versionHistoryAssetCommand(cfg *config.Config) *cobra.Command { - var size, page uint32 - cmd := &cobra.Command{ - Use: "versionhistory ", - Short: "get asset version history by id", - Example: heredoc.Doc(` - $ compass asset versionhistory - `), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - assetID := args[0] - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.GetAssetVersionHistoryRequest{ - Id: assetID, - Size: size, - Offset: page, - }) - res, err := clnt.GetAssetVersionHistory(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - - fmt.Println(printer.Bluef("%s", prettyPrint(res.Msg.GetData()))) - - return nil - }, - } - - cmd.Flags().Uint32Var(&size, "size", pageSize, "Size of each page") - cmd.Flags().Uint32Var(&page, "page", pageOffset, "Page number offset (start from 0)") - - return cmd -} - -func viewAssetByVersionCommand(cfg *config.Config) *cobra.Command { - cmd := &cobra.Command{ - Use: "version ", - Short: "get asset's previous version by urn or id and version number", - Example: heredoc.Doc(` - $ compass asset version - $ compass asset version - `), - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - assetID := args[0] - assetVersion := args[1] - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.GetAssetByVersionRequest{ - Id: assetID, - Version: assetVersion, - }) - res, err := clnt.GetAssetByVersion(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - - fmt.Println(printer.Bluef("%s", prettyPrint(res.Msg.GetData()))) - - return nil - }, - } - return cmd -} diff --git a/cli/discussions.go b/cli/discussions.go deleted file mode 100644 index 14001669..00000000 --- a/cli/discussions.go +++ /dev/null @@ -1,176 +0,0 @@ -package cli - -import ( - "fmt" - "os" - - "github.com/MakeNowJust/heredoc" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/client" - "github.com/raystack/compass/internal/config" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "github.com/raystack/salt/cli/printer" - "github.com/spf13/cobra" -) - -func discussionsCommand(cfg *config.Config) *cobra.Command { - cmd := &cobra.Command{ - Use: "discussion", - Aliases: []string{"discussions"}, - Short: "Manage discussions", - Annotations: map[string]string{ - "group": "core", - }, - Example: heredoc.Doc(` - $ compass discussion list - $ compass discussion view - $ compass discussion post - `), - } - - cmd.AddCommand( - listAllDiscussionsCommand(cfg), - viewDiscussionByIDCommand(cfg), - postDiscussionCommand(cfg), - ) - cmd.PersistentFlags().StringVarP(&namespaceID, "namespace", "n", namespace.DefaultNamespace.ID.String(), "namespace id or name") - return cmd -} - -func listAllDiscussionsCommand(cfg *config.Config) *cobra.Command { - var json string - cmd := &cobra.Command{ - Use: "list", - Short: "lists all discussions", - Example: heredoc.Doc(` - $ compass discussion list - `), - Annotations: map[string]string{ - "action:core": "true", - }, - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.GetAllDiscussionsRequest{}) - res, err := clnt.GetAllDiscussions(cmd.Context(), req) - if err != nil { - return err - } - - if json != "json" { - report := [][]string{} - report = append(report, []string{"ID", "TITLE", "TYPE", "STATE"}) - index := 1 - for _, i := range res.Msg.GetData() { - report = append(report, []string{i.Id, i.Title, i.Type, i.State}) - index++ - } - printer.Table(os.Stdout, report) - - fmt.Println(printer.Cyanf("To view all the data in JSON format, use flag `-o json`")) - } else { - fmt.Println(printer.Bluef("%s", prettyPrint(res.Msg.GetData()))) - } - - return nil - }, - } - - cmd.Flags().StringVarP(&json, "out", "o", "table", "flag to control output viewing, for json `-o json`") - - return cmd -} - -func viewDiscussionByIDCommand(cfg *config.Config) *cobra.Command { - cmd := &cobra.Command{ - Use: "view ", - Short: "view discussion for the given ID", - Example: heredoc.Doc(` - $ compass discussion view - `), - Annotations: map[string]string{ - "action:core": "true", - }, - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - discussionID := args[0] - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.GetDiscussionRequest{ - Id: discussionID, - }) - res, err := clnt.GetDiscussion(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - - fmt.Println(printer.Bluef("%s", prettyPrint(res.Msg.GetData()))) - return nil - }, - } - - return cmd -} - -func postDiscussionCommand(cfg *config.Config) *cobra.Command { - var filePath string - - cmd := &cobra.Command{ - Use: "post", - Short: "post discussions, add ", - Example: heredoc.Doc(` - $ compass discussion post - `), - Annotations: map[string]string{ - "action:core": "true", - }, - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - var reqBody compassv1beta1.Discussion - if err := parseFile(filePath, &reqBody); err != nil { - return err - } - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.CreateDiscussionRequest{ - Title: reqBody.Title, - Body: reqBody.Body, - Type: reqBody.Type, - State: reqBody.State, - Labels: reqBody.Labels, - Assets: reqBody.Assets, - }) - res, err := clnt.CreateDiscussion(cmd.Context(), req) - if err != nil { - return err - } - spinner.Stop() - - fmt.Println("ID: \t", printer.Greenf("%s", res.Msg.Id)) - return nil - }, - } - cmd.Flags().StringVarP(&filePath, "body", "b", "", "filepath to body that has to be upserted") - if err := cmd.MarkFlagRequired("body"); err != nil { - panic(err) - } - - return cmd -} diff --git a/cli/entities.go b/cli/entities.go new file mode 100644 index 00000000..92322e47 --- /dev/null +++ b/cli/entities.go @@ -0,0 +1,319 @@ +package cli + +import ( + "fmt" + + "connectrpc.com/connect" + "github.com/MakeNowJust/heredoc" + compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" + "github.com/raystack/compass/internal/client" + "github.com/raystack/compass/internal/config" + "github.com/spf13/cobra" + "google.golang.org/protobuf/types/known/structpb" +) + +func entitiesCommand(cfg *config.Config) *cobra.Command { + cmd := &cobra.Command{ + Use: "entity", + Aliases: []string{"entities"}, + Short: "Manage entities in the knowledge graph", + Annotations: map[string]string{ + "group": "core", + }, + Example: heredoc.Doc(` + $ compass entity list + $ compass entity view + $ compass entity upsert + $ compass entity delete + $ compass entity search + $ compass entity types + $ compass entity context + $ compass entity impact + `), + } + + cmd.AddCommand( + listEntitiesCommand(cfg), + viewEntityCommand(cfg), + upsertEntityCommand(cfg), + deleteEntityCommand(cfg), + searchEntitiesCommand(cfg), + entityTypesCommand(cfg), + entityContextCommand(cfg), + entityImpactCommand(cfg), + ) + + return cmd +} + +func listEntitiesCommand(cfg *config.Config) *cobra.Command { + var types, source, query string + var size, offset uint32 + + cmd := &cobra.Command{ + Use: "list", + Short: "List all entities", + RunE: func(cmd *cobra.Command, args []string) error { + clnt, err := createEntityClient(cmd, cfg) + if err != nil { + return err + } + + + req := connect.NewRequest(&compassv1beta1.GetAllEntitiesRequest{ + Types: types, + Source: source, + Q: query, + Size: size, + Offset: offset, + }) + res, err := clnt.GetAllEntities(cmd.Context(), req) + if err != nil { + return err + } + + fmt.Println(res.Msg.GetData()); return nil + }, + } + cmd.Flags().StringVar(&types, "types", "", "Filter by types (comma-separated)") + cmd.Flags().StringVar(&source, "source", "", "Filter by source") + cmd.Flags().StringVarP(&query, "query", "q", "", "Search query") + cmd.Flags().Uint32Var(&size, "size", 20, "Page size") + cmd.Flags().Uint32Var(&offset, "offset", 0, "Page offset") + return cmd +} + +func viewEntityCommand(cfg *config.Config) *cobra.Command { + return &cobra.Command{ + Use: "view ", + Short: "View entity details by ID or URN", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clnt, err := createEntityClient(cmd, cfg) + if err != nil { + return err + } + + + req := connect.NewRequest(&compassv1beta1.GetEntityByIDRequest{Id: args[0]}) + res, err := clnt.GetEntityByID(cmd.Context(), req) + if err != nil { + return err + } + + fmt.Println(res.Msg.GetData()); return nil + }, + } +} + +func upsertEntityCommand(cfg *config.Config) *cobra.Command { + var urn, typ, name, desc, source string + + cmd := &cobra.Command{ + Use: "upsert", + Short: "Create or update an entity", + RunE: func(cmd *cobra.Command, args []string) error { + clnt, err := createEntityClient(cmd, cfg) + if err != nil { + return err + } + + + req := connect.NewRequest(&compassv1beta1.UpsertEntityRequest{ + Urn: urn, + Type: typ, + Name: name, + Description: desc, + Source: source, + Properties: &structpb.Struct{}, + }) + res, err := clnt.UpsertEntity(cmd.Context(), req) + if err != nil { + return err + } + + fmt.Println("Entity upserted:", res.Msg.GetId()) + return nil + }, + } + cmd.Flags().StringVar(&urn, "urn", "", "Entity URN (required)") + cmd.Flags().StringVar(&typ, "type", "", "Entity type (required)") + cmd.Flags().StringVar(&name, "name", "", "Entity name (required)") + cmd.Flags().StringVar(&desc, "description", "", "Description") + cmd.Flags().StringVar(&source, "source", "", "Source system") + _ = cmd.MarkFlagRequired("urn") + _ = cmd.MarkFlagRequired("type") + _ = cmd.MarkFlagRequired("name") + return cmd +} + +func deleteEntityCommand(cfg *config.Config) *cobra.Command { + return &cobra.Command{ + Use: "delete ", + Short: "Delete an entity by URN", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clnt, err := createEntityClient(cmd, cfg) + if err != nil { + return err + } + + + req := connect.NewRequest(&compassv1beta1.DeleteEntityRequest{Urn: args[0]}) + if _, err := clnt.DeleteEntity(cmd.Context(), req); err != nil { + return err + } + + fmt.Println("Entity deleted:", args[0]) + return nil + }, + } +} + +func searchEntitiesCommand(cfg *config.Config) *cobra.Command { + var types, source, mode string + var size uint32 + + cmd := &cobra.Command{ + Use: "search ", + Short: "Search entities (keyword, semantic, or hybrid)", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clnt, err := createEntityClient(cmd, cfg) + if err != nil { + return err + } + + + req := connect.NewRequest(&compassv1beta1.SearchEntitiesRequest{ + Text: args[0], + Types: types, + Source: source, + Mode: mode, + Size: size, + }) + res, err := clnt.SearchEntities(cmd.Context(), req) + if err != nil { + return err + } + + fmt.Println(res.Msg.GetData()); return nil + }, + } + cmd.Flags().StringVar(&types, "types", "", "Filter by types") + cmd.Flags().StringVar(&source, "source", "", "Filter by source") + cmd.Flags().StringVar(&mode, "mode", "keyword", "Search mode: keyword, semantic, hybrid") + cmd.Flags().Uint32Var(&size, "size", 10, "Max results") + return cmd +} + +func entityTypesCommand(cfg *config.Config) *cobra.Command { + return &cobra.Command{ + Use: "types", + Short: "List all entity types with counts", + RunE: func(cmd *cobra.Command, args []string) error { + clnt, err := createEntityClient(cmd, cfg) + if err != nil { + return err + } + + + req := connect.NewRequest(&compassv1beta1.GetEntityTypesRequest{}) + res, err := clnt.GetEntityTypes(cmd.Context(), req) + if err != nil { + return err + } + + fmt.Println(res.Msg.GetData()); return nil + }, + } +} + +func entityContextCommand(cfg *config.Config) *cobra.Command { + var depth uint32 + + cmd := &cobra.Command{ + Use: "context ", + Short: "Get full context subgraph for an entity", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clnt, err := createEntityClient(cmd, cfg) + if err != nil { + return err + } + + + req := connect.NewRequest(&compassv1beta1.GetEntityContextRequest{ + Urn: args[0], + Depth: depth, + }) + res, err := clnt.GetEntityContext(cmd.Context(), req) + if err != nil { + return err + } + + fmt.Printf("Entity: %s (%s)\n", res.Msg.Entity.GetName(), res.Msg.Entity.GetType()) + if len(res.Msg.Edges) > 0 { + fmt.Printf("\nRelationships (%d):\n", len(res.Msg.Edges)) + for _, e := range res.Msg.Edges { + fmt.Printf(" %s —[%s]→ %s\n", e.GetSourceUrn(), e.GetType(), e.GetTargetUrn()) + } + } + if len(res.Msg.Related) > 0 { + fmt.Printf("\nRelated (%d):\n", len(res.Msg.Related)) + for _, r := range res.Msg.Related { + fmt.Printf(" %s (%s) — %s\n", r.GetName(), r.GetType(), r.GetUrn()) + } + } + return nil + }, + } + cmd.Flags().Uint32Var(&depth, "depth", 2, "Traversal depth") + return cmd +} + +func entityImpactCommand(cfg *config.Config) *cobra.Command { + var depth uint32 + + cmd := &cobra.Command{ + Use: "impact ", + Short: "Analyze downstream blast radius", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clnt, err := createEntityClient(cmd, cfg) + if err != nil { + return err + } + + + req := connect.NewRequest(&compassv1beta1.GetEntityImpactRequest{ + Urn: args[0], + Depth: depth, + }) + res, err := clnt.GetEntityImpact(cmd.Context(), req) + if err != nil { + return err + } + + if len(res.Msg.Edges) == 0 { + fmt.Println("No downstream dependencies found.") + return nil + } + fmt.Printf("Impact (%d edges):\n", len(res.Msg.Edges)) + for _, e := range res.Msg.Edges { + fmt.Printf(" %s → %s\n", e.GetSourceUrn(), e.GetTargetUrn()) + } + return nil + }, + } + cmd.Flags().Uint32Var(&depth, "depth", 3, "Traversal depth") + return cmd +} + +func createEntityClient(cmd *cobra.Command, cfg *config.Config) (*client.Client, error) { + clnt, err := client.Create(cmd.Context(), cfg.Client) + if err != nil { + return nil, err + } + return clnt, nil +} diff --git a/cli/lineage.go b/cli/lineage.go deleted file mode 100644 index ebf50e33..00000000 --- a/cli/lineage.go +++ /dev/null @@ -1,52 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/MakeNowJust/heredoc" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/client" - "github.com/raystack/compass/internal/config" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "github.com/raystack/salt/cli/printer" - "github.com/spf13/cobra" -) - -func lineageCommand(cfg *config.Config) *cobra.Command { - cmd := &cobra.Command{ - Use: "lineage ", - Aliases: []string{}, - Short: "observe the lineage of metadata", - Annotations: map[string]string{ - "group": "core", - }, - Args: cobra.ExactArgs(1), - Example: heredoc.Doc(` - $ compass lineage - `), - - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - req := client.NewRequest(cfg.Client, namespaceID, &compassv1beta1.GetGraphRequest{ - Urn: args[0], - }) - res, err := clnt.GetGraph(cmd.Context(), req) - if err != nil { - return err - } - - fmt.Println(printer.Bluef("%s", prettyPrint(res.Msg.GetData()))) - - return nil - }, - } - cmd.PersistentFlags().StringVarP(&namespaceID, "namespace", "n", namespace.DefaultNamespace.ID.String(), "namespace id or name") - return cmd -} diff --git a/cli/root.go b/cli/root.go index 98c031d6..b16227fb 100644 --- a/cli/root.go +++ b/cli/root.go @@ -17,7 +17,6 @@ var ( SilenceUsage: true, Example: heredoc.Doc(` $ compass asset - $ compass discussion $ compass search $ compass server `), @@ -58,10 +57,7 @@ func New(cliConfig *config.Config) *cobra.Command { serverCmd(cliConfig), configCommand(cliConfig), namespacesCommand(cliConfig), - assetsCommand(cliConfig), - discussionsCommand(cliConfig), - searchCommand(cliConfig), - lineageCommand(cliConfig), + entitiesCommand(cliConfig), versionCmd(), ) diff --git a/cli/search.go b/cli/search.go deleted file mode 100644 index b4c0c738..00000000 --- a/cli/search.go +++ /dev/null @@ -1,77 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/MakeNowJust/heredoc" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/client" - "github.com/raystack/compass/internal/config" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "github.com/raystack/salt/cli/printer" - "github.com/spf13/cobra" -) - -func searchCommand(cfg *config.Config) *cobra.Command { - var filter, query, rankBy string - var size uint32 - cmd := &cobra.Command{ - Use: "search ", - Aliases: []string{}, - Short: "query the metadata available", - Annotations: map[string]string{ - "group": "core", - }, - Args: cobra.ExactArgs(1), - Example: heredoc.Doc(` - $ compass search view - `), - - RunE: func(cmd *cobra.Command, args []string) error { - spinner := printer.Spin("") - defer spinner.Stop() - - clnt, err := client.Create(cmd.Context(), cfg.Client) - if err != nil { - return err - } - - searchReq := makeSearchAssetRequest(namespaceID, args[0], filter, query, rankBy, size) - req := client.NewRequest(cfg.Client, namespaceID, searchReq) - res, err := clnt.SearchAssets(cmd.Context(), req) - if err != nil { - return err - } - - fmt.Println(printer.Bluef("%s", prettyPrint(res.Msg.GetData()))) - - return nil - }, - } - - cmd.Flags().StringVarP(&namespaceID, "namespace", "n", namespace.DefaultNamespace.ID.String(), "namespace id or name") - cmd.Flags().StringVarP(&filter, "filter", "f", "", "--filter=field_key1:val1,key2:val2,key3:val3 gives exact match for values") - cmd.Flags().StringVarP(&query, "query", "q", "", "--query=--filter=field_key1:val1 supports fuzzy search") - cmd.Flags().StringVarP(&rankBy, "rankby", "r", "", "--rankby=") - cmd.Flags().Uint32VarP(&size, "size", "s", 0, "--size=10 maximum size of response query") - return cmd -} - -func makeSearchAssetRequest(namespaceID, text, filter, query, rankby string, size uint32) *compassv1beta1.SearchAssetsRequest { - newReq := &compassv1beta1.SearchAssetsRequest{ - Text: text, - } - if filter != "" { - newReq.Filter = makeMapFromString(filter) - } - if query != "" { - newReq.Query = makeMapFromString(query) - } - if rankby != "" { - newReq.Rankby = rankby - } - if size > 0 { - newReq.Size = size - } - return newReq -} diff --git a/core/asset/asset.go b/core/asset/asset.go deleted file mode 100644 index b8e5afac..00000000 --- a/core/asset/asset.go +++ /dev/null @@ -1,69 +0,0 @@ -package asset - -//go:generate mockery --name=Repository -r --case underscore --with-expecter --structname AssetRepository --filename asset_repository.go --output=./mocks -import ( - "context" - "fmt" - "time" - - "github.com/r3labs/diff/v3" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/user" -) - -type Repository interface { - GetAll(context.Context, Filter) ([]Asset, error) - GetCount(context.Context, Filter) (int, error) - GetByID(ctx context.Context, id string) (Asset, error) - GetByURN(ctx context.Context, urn string) (Asset, error) - GetVersionHistory(ctx context.Context, flt Filter, id string) ([]Asset, error) - GetByVersionWithID(ctx context.Context, id string, version string) (Asset, error) - GetByVersionWithURN(ctx context.Context, urn string, version string) (Asset, error) - GetTypes(ctx context.Context, flt Filter) (map[Type]int, error) - Upsert(ctx context.Context, ns *namespace.Namespace, ast *Asset) (string, error) - DeleteByID(ctx context.Context, id string) error - DeleteByURN(ctx context.Context, urn string) error - SoftDeleteByID(ctx context.Context, id string) (string, error) - SoftDeleteByURN(ctx context.Context, urn string) (string, error) - GetCountByIsDeleted(ctx context.Context, isDeleted bool) (int, error) - HardDeleteByURNs(ctx context.Context, urns []string) error - AddProbe(ctx context.Context, ns *namespace.Namespace, assetURN string, probe *Probe) error - GetProbes(ctx context.Context, assetURN string) ([]Probe, error) - GetProbesWithFilter(ctx context.Context, flt ProbesFilter) (map[string][]Probe, error) -} - -// Asset is a model that wraps arbitrary data with Compass' context -type Asset struct { - ID string `json:"id" diff:"-"` - URN string `json:"urn" diff:"-"` - Type Type `json:"type" diff:"-"` - Service string `json:"service" diff:"-"` - Name string `json:"name" diff:"name"` - Description string `json:"description" diff:"description"` - Data map[string]interface{} `json:"data" diff:"data"` - URL string `json:"url" diff:"url"` - Labels map[string]string `json:"labels" diff:"labels"` - Owners []user.User `json:"owners,omitempty" diff:"owners"` - IsDeleted bool `json:"is_deleted" diff:"is_deleted"` - CreatedAt time.Time `json:"created_at" diff:"-"` - UpdatedAt time.Time `json:"updated_at" diff:"-"` - RefreshedAt *time.Time `json:"refreshed_at,omitempty" diff:"-"` - Version string `json:"version" diff:"-"` - UpdatedBy user.User `json:"updated_by" diff:"-"` - Changelog diff.Changelog `json:"changelog,omitempty" diff:"-"` - Probes []Probe `json:"probes,omitempty"` -} - -var ErrAssetAlreadyDeleted = fmt.Errorf("asset already deleted") - -// Diff returns nil changelog with nil error if equal -// returns wrapped r3labs/diff Changelog struct with nil error if not equal -func (a *Asset) Diff(otherAsset *Asset) (diff.Changelog, error) { - return diff.Diff(a, otherAsset, diff.DiscardComplexOrigin(), diff.AllowTypeMismatch(true)) -} - -// Patch appends asset with data from map. It mutates the asset itself. -// It is using json annotation of the struct to patch the correct keys -func (a *Asset) Patch(patchData map[string]interface{}) { - patchAsset(a, patchData) -} diff --git a/core/asset/asset_test.go b/core/asset/asset_test.go deleted file mode 100644 index 1a604e4c..00000000 --- a/core/asset/asset_test.go +++ /dev/null @@ -1,490 +0,0 @@ -package asset_test - -import ( - "encoding/json" - "testing" - - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/user" - "github.com/r3labs/diff/v3" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestDiffTopLevel(t *testing.T) { - cases := []struct { - Name string - Source, Target string - Changelog diff.Changelog - Error error - }{ - { - "ignored field won't be compared", - `{ - "id": "1234", - "urn": "urn1234", - "type": "dashboard", - "service": "service1234" - }`, - `{ - "id": "5678", - "urn": "urn5678", - "type": "job", - "service": "service5678" - }`, - nil, - nil, - }, - { - "updated top level field should be reflected", - `{ - "name": "old-name" - }`, - `{ - "name": "updated-name", - "description": "updated-decsription" - }`, - diff.Changelog{ - diff.Change{Type: diff.UPDATE, Path: []string{"name"}, From: "old-name", To: "updated-name"}, - diff.Change{Type: diff.UPDATE, Path: []string{"description"}, From: "", To: "updated-decsription"}, - }, - nil, - }, - { - "created owners should be reflected", - `{ - "name": "old-name" - }`, - `{ - "name": "old-name", - "owners": [ - { - "email": "email@raystack.io" - } - ] - }`, - diff.Changelog{ - diff.Change{Type: diff.CREATE, Path: []string{"owners", "0", "email"}, To: "email@raystack.io"}, - }, - nil, - }, - } - - for _, tc := range cases { - t.Run(tc.Name, func(t *testing.T) { - - var sourceAsset asset.Asset - err := json.Unmarshal([]byte(tc.Source), &sourceAsset) - if err != nil { - t.Fatal(err) - } - var targetAsset asset.Asset - err = json.Unmarshal([]byte(tc.Target), &targetAsset) - if err != nil { - t.Fatal(err) - } - - cl, err := sourceAsset.Diff(&targetAsset) - - assert.Equal(t, tc.Error, err) - require.Equal(t, len(tc.Changelog), len(cl)) - - for i, c := range cl { - assert.Equal(t, tc.Changelog[i].Type, c.Type) - assert.Equal(t, tc.Changelog[i].Path, c.Path) - assert.Equal(t, tc.Changelog[i].From, c.From) - assert.Equal(t, tc.Changelog[i].To, c.To) - } - }) - } -} - -func TestDiffData(t *testing.T) { - cases := []struct { - Name string - Source, Target string - Changelog diff.Changelog - Error error - }{ - { - "updated data value string should be reflected", - `{ - "name": "jane-kafka-1a", - "description": "", - "data": { - "title": "jane-kafka-1a", - "entity": "raystack", - "country": "vn" - } - }`, - `{ - "name": "jane-kafka-1a", - "service": "kafka", - "description": "", - "data": { - "title": "jane-kafka-1a", - "description": "a new description inside", - "entity": "raystack", - "country": "id" - } - }`, - diff.Changelog{ - diff.Change{Type: diff.UPDATE, Path: []string{"data", "country"}, From: "vn", To: "id"}, - diff.Change{Type: diff.CREATE, Path: []string{"data", "description"}, To: "a new description inside"}, - }, - nil, - }, - { - "updated data value array should be reflected", - `{ - "name": "jane-kafka-1a", - "data": { - "some_array": [ - { - "id": "element1id" - } - ], - "entity": "raystack", - "country": "vn" - } - }`, - `{ - "name": "jane-kafka-1a", - "data": { - "some_array": [ - { - "id": "element2id" - } - ], - "entity": "raystack", - "country": "vn" - } - }`, - diff.Changelog{ - diff.Change{Type: diff.UPDATE, Path: []string{"data", "some_array", "0", "id"}, From: "element1id", To: "element2id"}, - }, - nil, - }, - { - "created data value array should be reflected", - `{ - "name": "jane-kafka-1a", - "data": { - "some_array": [ - { - "id": "element1id" - } - ], - "entity": "raystack", - "country": "vn" - } - }`, - `{ - "name": "jane-kafka-1a", - "data": { - "some_array": [ - { - "id": "element1id" - }, - { - "id": "element2id" - } - ], - "entity": "raystack", - "country": "vn" - } - }`, - diff.Changelog{ - diff.Change{Type: diff.CREATE, Path: []string{"data", "some_array", "1"}, To: map[string]interface{}(map[string]interface{}{"id": "element2id"})}, - }, - nil, - }, - { - "deleted data value array should be reflected", - `{ - "name": "jane-kafka-1a", - "data": { - "some_array": [ - { - "id": "element1id" - }, - { - "id": "element2id" - } - ], - "entity": "raystack", - "country": "vn" - } - }`, - `{ - "name": "jane-kafka-1a", - "data": { - "some_array": [ - { - "id": "element1id" - } - ], - "entity": "raystack", - "country": "vn" - } - }`, - diff.Changelog{ - diff.Change{Type: diff.DELETE, Path: []string{"data", "some_array", "1"}, From: map[string]interface{}(map[string]interface{}{"id": "element2id"})}, - }, - nil, - }, - } - - for _, tc := range cases { - t.Run(tc.Name, func(t *testing.T) { - - var sourceAsset asset.Asset - err := json.Unmarshal([]byte(tc.Source), &sourceAsset) - if err != nil { - t.Fatal(err) - } - var targetAsset asset.Asset - err = json.Unmarshal([]byte(tc.Target), &targetAsset) - if err != nil { - t.Fatal(err) - } - - cl, err := sourceAsset.Diff(&targetAsset) - - assert.Equal(t, tc.Error, err) - require.Equal(t, len(tc.Changelog), len(cl)) - - for i, c := range cl { - assert.Equal(t, tc.Changelog[i].Type, c.Type) - assert.Equal(t, tc.Changelog[i].Path, c.Path) - assert.Equal(t, tc.Changelog[i].From, c.From) - assert.Equal(t, tc.Changelog[i].To, c.To) - } - }) - } -} - -func TestAssetPatch(t *testing.T) { - testcases := []struct { - description string - asset asset.Asset - patchData map[string]interface{} - expected asset.Asset - }{ - { - description: "should patch all allowed fields", - asset: asset.Asset{ - URN: "some-urn", - Type: asset.TypeJob, - Service: "optimus", - Description: "sample-description", - Name: "old-name", - Labels: map[string]string{ - "foo": "bar", - }, - Owners: []user.User{ - {Email: "old@example.com"}, - }, - }, - patchData: map[string]interface{}{ - "urn": "new-urn", - "type": "table", - "service": "firehose", - "description": "new-description", - "name": "new-name", - "url": "https://sample-url.com", - "labels": map[string]string{ - "bar": "foo", - "bar2": "foo2", - }, - "owners": []user.User{ - {Email: "new@example.com"}, - {Email: "new2@example.com"}, - }, - }, - expected: asset.Asset{ - URN: "new-urn", - Type: asset.TypeTable, - Service: "firehose", - Description: "new-description", - Name: "new-name", - URL: "https://sample-url.com", - Labels: map[string]string{ - "foo": "bar", - "bar": "foo", - "bar2": "foo2", - }, - Owners: []user.User{ - {Email: "old@example.com"}, - {Email: "new@example.com"}, - {Email: "new2@example.com"}, - }, - }, - }, - { - description: "should patch all allowed fields without JSON", - asset: asset.Asset{ - URN: "some-urn", - Type: asset.TypeJob, - Service: "optimus", - Description: "sample-description", - Name: "old-name", - URL: "https://sample-url-old.com", - Labels: map[string]string{ - "foo": "bar", - }, - Owners: []user.User{ - {Email: "old@example.com"}, - }, - }, - patchData: map[string]interface{}{ - "urn": "new-urn", - "type": "table", - "service": "firehose", - "description": "new-description", - "name": "new-name", - "url": "https://sample-url.com", - "labels": map[string]string{ - "bar": "foo", - "bar2": "foo2", - }, - "owners": []map[string]interface{}{ - {"email": "new@example.com"}, - {"email": "new2@example.com"}, - }, - }, - expected: asset.Asset{ - URN: "new-urn", - Type: asset.TypeTable, - Service: "firehose", - Description: "new-description", - Name: "new-name", - URL: "https://sample-url.com", - Labels: map[string]string{ - "foo": "bar", - "bar": "foo", - "bar2": "foo2", - }, - Owners: []user.User{ - {Email: "old@example.com"}, - {Email: "new@example.com"}, - {Email: "new2@example.com"}, - }, - }, - }, { - description: "should patch all allowed fields without labels and owners", - asset: asset.Asset{ - URN: "some-urn", - Type: asset.TypeJob, - Service: "optimus", - Description: "sample-description", - Name: "old-name", - Labels: map[string]string{ - "foo": "bar", - }, - Owners: []user.User{ - {Email: "old@example.com"}, - }, - }, - patchData: map[string]interface{}{ - "urn": "new-urn", - "type": "table", - "service": "firehose", - "description": "new-description", - "name": "new-name", - "labels": "", - "owners": "", - }, - expected: asset.Asset{ - URN: "new-urn", - Type: asset.TypeTable, - Service: "firehose", - Description: "new-description", - Name: "new-name", - Labels: map[string]string{ - "foo": "bar", - }, - Owners: []user.User{ - {Email: "old@example.com"}, - }, - }, - }, - { - description: "should patch data field", - asset: asset.Asset{ - Data: map[string]interface{}{ - "user": map[string]interface{}{ - "name": "sample-name", - "email": "sample@test.com", - }, - "properties": map[string]interface{}{ - "attributes": map[string]interface{}{ - "entity": "raystack", - "environment": "staging", - }, - }, - }, - }, - patchData: map[string]interface{}{ - "data": map[string]interface{}{ - "user": map[string]interface{}{ - "email": "new-email@test.com", - "description": "user description", - }, - "schemas": []interface{}{ - "schema1", - "schema2", - }, - "properties": map[string]interface{}{ - "attributes": map[string]interface{}{ - "environment": "production", - "type": "some-type", - }, - }, - }, - }, - expected: asset.Asset{ - Data: map[string]interface{}{ - "user": map[string]interface{}{ - "name": "sample-name", - "email": "new-email@test.com", - "description": "user description", - }, - "properties": map[string]interface{}{ - "attributes": map[string]interface{}{ - "entity": "raystack", - "environment": "production", - "type": "some-type", - }, - }, - "schemas": []interface{}{ - "schema1", - "schema2", - }, - }, - }, - }, - { - description: "should not panic if current asset's data is nil", - asset: asset.Asset{ - Data: nil, - }, - patchData: map[string]interface{}{ - "data": map[string]interface{}{ - "foo": "bar", - }, - }, - expected: asset.Asset{ - Data: map[string]interface{}{ - "foo": "bar", - }, - }, - }, - } - for _, tc := range testcases { - t.Run(tc.description, func(t *testing.T) { - tc.asset.Patch(tc.patchData) - assert.Equal(t, tc.expected, tc.asset) - }) - } -} diff --git a/core/asset/discovery.go b/core/asset/discovery.go deleted file mode 100644 index 42e116e2..00000000 --- a/core/asset/discovery.go +++ /dev/null @@ -1,112 +0,0 @@ -package asset - -//go:generate mockery --name=DiscoveryRepository -r --case underscore --with-expecter --structname DiscoveryRepository --filename discovery_repository.go --output=./mocks -import ( - "context" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/validator" -) - -type DiscoveryRepository interface { - Upsert(ctx context.Context, ns *namespace.Namespace, ast *Asset) error - DeleteByID(ctx context.Context, ns *namespace.Namespace, assetID string) error - DeleteByURN(ctx context.Context, ns *namespace.Namespace, assetURN string) error - SoftDeleteByURN(ctx context.Context, ns *namespace.Namespace, assetURN string) error - Search(ctx context.Context, cfg SearchConfig) (results []SearchResult, err error) - Suggest(ctx context.Context, cfg SearchConfig) (suggestions []string, err error) - GroupAssets(ctx context.Context, cfg GroupConfig) ([]GroupResult, error) -} - -// GroupConfig represents configuration for grouping assets -type GroupConfig struct { - GroupBy []string - Filters SearchFilter - IncludeFields []string - Size int - Namespace *namespace.Namespace -} - -// GroupResult represents a single group of assets -type GroupResult struct { - Fields []GroupField - Assets []Asset -} - -// GroupField represents a key-value pair identifying a group -type GroupField struct { - Key string - Value string -} - -// SearchFilter is a filter intended to be used as a search -// criteria for operations involving asset search -type SearchFilter = map[string][]string - -// SearchFlags contains flags that modify search behavior -type SearchFlags struct { - DisableFuzzy bool - EnableHighlight bool - IsColumnSearch bool -} - -// SearchConfig represents a search query along -// with any corresponding filter(s) -type SearchConfig struct { - // Text to search for - Text string - - // Filters specifies document level values to look for. - // Multiple values can be specified for a single key - Filters SearchFilter - - // Number of relevant results to return - MaxResults int - - // Offset is the offset for search results, used for pagination - Offset int - - // RankBy is a param to rank based on a specific parameter - RankBy string - - // Queries is a param to search a resource based on asset's fields - Queries map[string]string - - // IncludeFields specifies which fields to include in search results - IncludeFields []string - - // Flags contains optional search flags - Flags SearchFlags - - // Namespace under which assets are partitioned. *Required* - Namespace *namespace.Namespace `validate:"required"` -} - -func (s SearchConfig) Validate() error { - return validator.ValidateStruct(s) -} - -// SearchResult represents an item/result in a list of search results -type SearchResult struct { - ID string `json:"id"` - URN string `json:"urn"` - Title string `json:"title"` - Type string `json:"type"` - Service string `json:"service"` - Description string `json:"description"` - Labels map[string]string `json:"labels"` - Data map[string]interface{} `json:"data"` -} - -// ToAsset returns search result as asset -func (sr SearchResult) ToAsset() Asset { - return Asset{ - ID: sr.ID, - URN: sr.URN, - Name: sr.Title, - Type: Type(sr.Type), - Service: sr.Service, - Description: sr.Description, - Labels: sr.Labels, - Data: sr.Data, - } -} diff --git a/core/asset/discovery_test.go b/core/asset/discovery_test.go deleted file mode 100644 index ef7135b7..00000000 --- a/core/asset/discovery_test.go +++ /dev/null @@ -1,111 +0,0 @@ -package asset_test - -import ( - "github.com/raystack/compass/core/namespace" - "github.com/stretchr/testify/assert" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/raystack/compass/core/asset" -) - -func TestToAsset(t *testing.T) { - type testCase struct { - Title string - SearchResult asset.SearchResult - Expect asset.Asset - } - - var testCases = []testCase{ - { - Title: "should return correct asset", - SearchResult: asset.SearchResult{ - ID: "an-id", - URN: "an-urn", - Title: "a-title", - Type: "table", - Service: "a-service", - Description: "a-description", - Labels: map[string]string{ - "label1": "value1", - }, - }, - Expect: asset.Asset{ - ID: "an-id", - URN: "an-urn", - Name: "a-title", - Type: asset.TypeTable, - Service: "a-service", - Description: "a-description", - Labels: map[string]string{ - "label1": "value1", - }, - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - got := tc.SearchResult.ToAsset() - if diff := cmp.Diff(got, tc.Expect); diff != "" { - t.Errorf("expected response to be %+v, was %+v", tc.Expect, got) - } - }) - } -} - -func TestSearchConfig_Validate(t *testing.T) { - type fields struct { - Text string - Filters asset.SearchFilter - MaxResults int - RankBy string - Queries map[string]string - Namespace *namespace.Namespace - } - tests := []struct { - name string - fields fields - wantErr bool - }{ - { - name: "fail validation if namespace is empty", - fields: fields{ - Namespace: nil, - }, - wantErr: true, - }, - { - name: "should not fail validation if text is empty but namespace is present", - fields: fields{ - Text: "", - Namespace: &namespace.Namespace{}, - }, - wantErr: false, - }, - { - name: "should not fail validation if all required fields are non empty", - fields: fields{ - Text: "query", - Namespace: &namespace.Namespace{}, - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := asset.SearchConfig{ - Text: tt.fields.Text, - Filters: tt.fields.Filters, - MaxResults: tt.fields.MaxResults, - RankBy: tt.fields.RankBy, - Queries: tt.fields.Queries, - Namespace: tt.fields.Namespace, - } - if !tt.wantErr { - assert.Nil(t, s.Validate()) - } else { - assert.NotNil(t, s.Validate()) - } - }) - } -} diff --git a/core/asset/errors.go b/core/asset/errors.go deleted file mode 100644 index e66df9e2..00000000 --- a/core/asset/errors.go +++ /dev/null @@ -1,55 +0,0 @@ -package asset - -import ( - "errors" - "fmt" -) - -var ( - ErrEmptyID = errors.New("asset does not have ID") - ErrEmptyURN = errors.New("asset does not have URN") - ErrUnknownType = errors.New("unknown type") - ErrNilAsset = errors.New("nil asset") -) - -type NotFoundError struct { - AssetID string - URN string -} - -type LineageNotFoundError struct { - URN string -} - -func (err LineageNotFoundError) Error() string { - if err.URN != "" { - return fmt.Sprintf("no lineage found for record: %q", err.URN) - } - return "could not find lineage" -} - -func (err NotFoundError) Error() string { - if err.AssetID != "" { - return fmt.Sprintf("no such record: %q", err.AssetID) - } else if err.URN != "" { - return fmt.Sprintf("could not find asset with urn = %s", err.URN) - } - - return "could not find asset" -} - -type InvalidError struct { - AssetID string -} - -func (err InvalidError) Error() string { - return fmt.Sprintf("invalid asset id: %q", err.AssetID) -} - -type DiscoveryError struct { - Err error -} - -func (err DiscoveryError) Error() string { - return fmt.Sprintf("discovery error: %s", err.Err) -} diff --git a/core/asset/filter.go b/core/asset/filter.go deleted file mode 100644 index 2d0c8d48..00000000 --- a/core/asset/filter.go +++ /dev/null @@ -1,129 +0,0 @@ -package asset - -import ( - "strings" - - "github.com/raystack/compass/core/validator" -) - -type Filter struct { - Types []Type - Services []string - Size int - Offset int - SortBy string `validate:"omitempty,oneof=name type service created_at updated_at"` - SortDirection string `validate:"omitempty,oneof=asc desc"` - QueryFields []string - Query string - Data map[string][]string - IsDeleted *bool -} - -func (f *Filter) Validate() error { - return validator.ValidateStruct(f) -} - -type filterBuilder struct { - types string - services string - q string - qFields string - data map[string]string - size int - offset int - sortBy string - sortDirection string - isDeleted *bool -} - -func NewFilterBuilder() *filterBuilder { - return &filterBuilder{} -} - -func (fb *filterBuilder) Types(types string) *filterBuilder { - fb.types = types - return fb -} - -func (fb *filterBuilder) Services(services string) *filterBuilder { - fb.services = services - return fb -} - -func (fb *filterBuilder) Q(q string) *filterBuilder { - fb.q = q - return fb -} - -func (fb *filterBuilder) QFields(qFields string) *filterBuilder { - fb.qFields = qFields - return fb -} - -func (fb *filterBuilder) Data(data map[string]string) *filterBuilder { - fb.data = data - return fb -} - -func (fb *filterBuilder) Size(size int) *filterBuilder { - fb.size = size - return fb -} - -func (fb *filterBuilder) Offset(offset int) *filterBuilder { - fb.offset = offset - return fb -} - -func (fb *filterBuilder) SortBy(sortBy string) *filterBuilder { - fb.sortBy = sortBy - return fb -} - -func (fb *filterBuilder) SortDirection(sortDirection string) *filterBuilder { - fb.sortDirection = sortDirection - return fb -} - -func (fb *filterBuilder) IsDeleted(isDeleted bool) *filterBuilder { - fb.isDeleted = &isDeleted - return fb -} - -func (fb *filterBuilder) Build() (Filter, error) { - flt := Filter{ - Size: fb.size, - Offset: fb.offset, - SortBy: fb.sortBy, - SortDirection: fb.sortDirection, - Query: fb.q, - IsDeleted: fb.isDeleted, - } - - if len(fb.data) != 0 { - flt.Data = make(map[string][]string) - for k, v := range fb.data { - flt.Data[k] = strings.Split(v, ",") - } - } - - if fb.types != "" { - typs := strings.Split(fb.types, ",") - for _, typeVal := range typs { - flt.Types = append(flt.Types, Type(typeVal)) - } - } - if fb.services != "" { - flt.Services = strings.Split(fb.services, ",") - } - - if fb.qFields != "" { - flt.QueryFields = strings.Split(fb.qFields, ",") - } - - if err := flt.Validate(); err != nil { - return Filter{}, err - } - - return flt, nil -} diff --git a/core/asset/filter_test.go b/core/asset/filter_test.go deleted file mode 100644 index f61afbda..00000000 --- a/core/asset/filter_test.go +++ /dev/null @@ -1,111 +0,0 @@ -package asset_test - -import ( - "testing" - - "github.com/raystack/compass/core/asset" - "github.com/stretchr/testify/assert" -) - -func TestValidateFilter(t *testing.T) { - type testCase struct { - Description string - Filter *asset.Filter - errString string - } - var testCases = []testCase{ - { - Description: "invalid type will return error", - Filter: &asset.Filter{Types: []asset.Type{"random"}}, - errString: "error value \"random\" for key \"type\" not recognized, only support \"openended issues qanda all\"", - }, - { - Description: "invalid sort and direction will return error", - Filter: &asset.Filter{SortBy: "random", SortDirection: "random"}, - errString: "error value \"random\" for key \"SortBy\" not recognized, only support \"name type service created_at updated_at\" and error value \"random\" for key \"SortDirection\" not recognized, only support \"asc desc\"", - }, - { - Description: "invalid size and offset will return error", - Filter: &asset.Filter{Size: -12, Offset: -1}, - errString: "size cannot be less than 0 and offset cannot be less than 0", - }, - } - - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - err := tc.Filter.Validate() - if err != nil { - assert.Equal(t, tc.errString, err.Error()) - } - }) - } -} - -func TestBuild(t *testing.T) { - type testCase struct { - Description string - ErrString string - Size int - SortBy string - SortDirection string - Offset int - Types string - Services string - QFields string - } - var testCases = []testCase{ - { - Description: "invalid size and offset will return error", - Size: -12, - Offset: -1, - ErrString: "size cannot be less than 0 and offset cannot be less than 0", - }, - { - Description: "invalid sort and direction will return error", - SortBy: "random", - SortDirection: "random", - ErrString: "error value \"random\" for key \"SortBy\" not recognized, only support \"name type service created_at updated_at\" and error value \"random\" for key \"SortDirection\" not recognized, only support \"asc desc\"", - }, - { - Description: "returns no error for valid fields", - Types: "int,string,char", - Services: "dashboard", - QFields: "de-platform", - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - fb := asset.NewFilterBuilder() - fb.Data(map[string]string{ - "name": "go-data", - }) - fb.Q("merchants") - fb.Size(128) - if tc.Offset != 0 { - fb.Offset(tc.Offset) - } - if tc.QFields != "" { - fb.QFields(tc.QFields) - } - if tc.Services != "" { - fb.Services(tc.Services) - } - if tc.Size != 0 { - fb.Size(tc.Size) - } - if tc.SortBy != "" { - fb.SortBy(tc.SortBy) - } - if tc.SortDirection != "" { - fb.SortDirection(tc.SortDirection) - } - if tc.Types != "" { - fb.Types(tc.Types) - } - _, err := fb.Build() - if err != nil { - assert.Equal(t, tc.ErrString, err.Error()) - } - }) - } -} diff --git a/core/asset/lineage.go b/core/asset/lineage.go deleted file mode 100644 index 33ae379c..00000000 --- a/core/asset/lineage.go +++ /dev/null @@ -1,64 +0,0 @@ -package asset - -import ( - "context" - - "github.com/raystack/compass/core/namespace" -) - -type LineageDirection string - -func (dir LineageDirection) IsValid() bool { - switch dir { - case LineageDirectionUpstream, LineageDirectionDownstream, "": - return true - default: - return false - } -} - -const ( - LineageDirectionUpstream LineageDirection = "upstream" - LineageDirectionDownstream LineageDirection = "downstream" -) - -type LineageQuery struct { - Level int - Direction LineageDirection - WithAttributes bool - IncludeDeleted bool -} - -//go:generate mockery --name=LineageRepository -r --case underscore --with-expecter --structname=LineageRepository --filename=lineage_repository.go --output=./mocks -type LineageRepository interface { - GetGraph(ctx context.Context, urn string, query LineageQuery) (LineageGraph, error) - Upsert(ctx context.Context, ns *namespace.Namespace, urn string, upstreams, downstreams []string) error - DeleteByURN(ctx context.Context, urn string) error - DeleteByURNs(ctx context.Context, urns []string) error -} - -type LineageGraph []LineageEdge - -type Lineage struct { - Edges []LineageEdge `json:"edges"` - NodeAttrs map[string]NodeAttributes `json:"node_attrs"` -} - -type LineageEdge struct { - // Source represents source's node ID - Source string `json:"source"` - - // Target represents target's node ID - Target string `json:"target"` - - // Prop is a map containing extra information about the edge - Prop map[string]interface{} `json:"prop"` -} - -type NodeAttributes struct { - Probes ProbesInfo `json:"probes"` -} - -type ProbesInfo struct { - Latest Probe `json:"latest"` -} diff --git a/core/asset/mocks/asset_repository.go b/core/asset/mocks/asset_repository.go deleted file mode 100644 index b028577a..00000000 --- a/core/asset/mocks/asset_repository.go +++ /dev/null @@ -1,844 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - asset "github.com/raystack/compass/core/asset" - - mock "github.com/stretchr/testify/mock" - - namespace "github.com/raystack/compass/core/namespace" -) - -// AssetRepository is an autogenerated mock type for the Repository type -type AssetRepository struct { - mock.Mock -} - -type AssetRepository_Expecter struct { - mock *mock.Mock -} - -func (_m *AssetRepository) EXPECT() *AssetRepository_Expecter { - return &AssetRepository_Expecter{mock: &_m.Mock} -} - -// AddProbe provides a mock function with given fields: ctx, ns, assetURN, probe -func (_m *AssetRepository) AddProbe(ctx context.Context, ns *namespace.Namespace, assetURN string, probe *asset.Probe) error { - ret := _m.Called(ctx, ns, assetURN, probe) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string, *asset.Probe) error); ok { - r0 = rf(ctx, ns, assetURN, probe) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AssetRepository_AddProbe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddProbe' -type AssetRepository_AddProbe_Call struct { - *mock.Call -} - -// AddProbe is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - assetURN string -// - probe *asset.Probe -func (_e *AssetRepository_Expecter) AddProbe(ctx interface{}, ns interface{}, assetURN interface{}, probe interface{}) *AssetRepository_AddProbe_Call { - return &AssetRepository_AddProbe_Call{Call: _e.mock.On("AddProbe", ctx, ns, assetURN, probe)} -} - -func (_c *AssetRepository_AddProbe_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, assetURN string, probe *asset.Probe)) *AssetRepository_AddProbe_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(string), args[3].(*asset.Probe)) - }) - return _c -} - -func (_c *AssetRepository_AddProbe_Call) Return(_a0 error) *AssetRepository_AddProbe_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *AssetRepository_AddProbe_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, string, *asset.Probe) error) *AssetRepository_AddProbe_Call { - _c.Call.Return(run) - return _c -} - -// DeleteByID provides a mock function with given fields: ctx, id -func (_m *AssetRepository) DeleteByID(ctx context.Context, id string) error { - ret := _m.Called(ctx, id) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { - r0 = rf(ctx, id) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AssetRepository_DeleteByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteByID' -type AssetRepository_DeleteByID_Call struct { - *mock.Call -} - -// DeleteByID is a helper method to define mock.On call -// - ctx context.Context -// - id string -func (_e *AssetRepository_Expecter) DeleteByID(ctx interface{}, id interface{}) *AssetRepository_DeleteByID_Call { - return &AssetRepository_DeleteByID_Call{Call: _e.mock.On("DeleteByID", ctx, id)} -} - -func (_c *AssetRepository_DeleteByID_Call) Run(run func(ctx context.Context, id string)) *AssetRepository_DeleteByID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *AssetRepository_DeleteByID_Call) Return(_a0 error) *AssetRepository_DeleteByID_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *AssetRepository_DeleteByID_Call) RunAndReturn(run func(context.Context, string) error) *AssetRepository_DeleteByID_Call { - _c.Call.Return(run) - return _c -} - -// DeleteByURN provides a mock function with given fields: ctx, urn -func (_m *AssetRepository) DeleteByURN(ctx context.Context, urn string) error { - ret := _m.Called(ctx, urn) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { - r0 = rf(ctx, urn) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AssetRepository_DeleteByURN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteByURN' -type AssetRepository_DeleteByURN_Call struct { - *mock.Call -} - -// DeleteByURN is a helper method to define mock.On call -// - ctx context.Context -// - urn string -func (_e *AssetRepository_Expecter) DeleteByURN(ctx interface{}, urn interface{}) *AssetRepository_DeleteByURN_Call { - return &AssetRepository_DeleteByURN_Call{Call: _e.mock.On("DeleteByURN", ctx, urn)} -} - -func (_c *AssetRepository_DeleteByURN_Call) Run(run func(ctx context.Context, urn string)) *AssetRepository_DeleteByURN_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *AssetRepository_DeleteByURN_Call) Return(_a0 error) *AssetRepository_DeleteByURN_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *AssetRepository_DeleteByURN_Call) RunAndReturn(run func(context.Context, string) error) *AssetRepository_DeleteByURN_Call { - _c.Call.Return(run) - return _c -} - -// GetAll provides a mock function with given fields: _a0, _a1 -func (_m *AssetRepository) GetAll(_a0 context.Context, _a1 asset.Filter) ([]asset.Asset, error) { - ret := _m.Called(_a0, _a1) - - var r0 []asset.Asset - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter) ([]asset.Asset, error)); ok { - return rf(_a0, _a1) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter) []asset.Asset); ok { - r0 = rf(_a0, _a1) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]asset.Asset) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.Filter) error); ok { - r1 = rf(_a0, _a1) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetRepository_GetAll_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAll' -type AssetRepository_GetAll_Call struct { - *mock.Call -} - -// GetAll is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 asset.Filter -func (_e *AssetRepository_Expecter) GetAll(_a0 interface{}, _a1 interface{}) *AssetRepository_GetAll_Call { - return &AssetRepository_GetAll_Call{Call: _e.mock.On("GetAll", _a0, _a1)} -} - -func (_c *AssetRepository_GetAll_Call) Run(run func(_a0 context.Context, _a1 asset.Filter)) *AssetRepository_GetAll_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.Filter)) - }) - return _c -} - -func (_c *AssetRepository_GetAll_Call) Return(_a0 []asset.Asset, _a1 error) *AssetRepository_GetAll_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetRepository_GetAll_Call) RunAndReturn(run func(context.Context, asset.Filter) ([]asset.Asset, error)) *AssetRepository_GetAll_Call { - _c.Call.Return(run) - return _c -} - -// GetByID provides a mock function with given fields: ctx, id -func (_m *AssetRepository) GetByID(ctx context.Context, id string) (asset.Asset, error) { - ret := _m.Called(ctx, id) - - var r0 asset.Asset - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (asset.Asset, error)); ok { - return rf(ctx, id) - } - if rf, ok := ret.Get(0).(func(context.Context, string) asset.Asset); ok { - r0 = rf(ctx, id) - } else { - r0 = ret.Get(0).(asset.Asset) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetRepository_GetByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByID' -type AssetRepository_GetByID_Call struct { - *mock.Call -} - -// GetByID is a helper method to define mock.On call -// - ctx context.Context -// - id string -func (_e *AssetRepository_Expecter) GetByID(ctx interface{}, id interface{}) *AssetRepository_GetByID_Call { - return &AssetRepository_GetByID_Call{Call: _e.mock.On("GetByID", ctx, id)} -} - -func (_c *AssetRepository_GetByID_Call) Run(run func(ctx context.Context, id string)) *AssetRepository_GetByID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *AssetRepository_GetByID_Call) Return(_a0 asset.Asset, _a1 error) *AssetRepository_GetByID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetRepository_GetByID_Call) RunAndReturn(run func(context.Context, string) (asset.Asset, error)) *AssetRepository_GetByID_Call { - _c.Call.Return(run) - return _c -} - -// GetByURN provides a mock function with given fields: ctx, urn -func (_m *AssetRepository) GetByURN(ctx context.Context, urn string) (asset.Asset, error) { - ret := _m.Called(ctx, urn) - - var r0 asset.Asset - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (asset.Asset, error)); ok { - return rf(ctx, urn) - } - if rf, ok := ret.Get(0).(func(context.Context, string) asset.Asset); ok { - r0 = rf(ctx, urn) - } else { - r0 = ret.Get(0).(asset.Asset) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, urn) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetRepository_GetByURN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByURN' -type AssetRepository_GetByURN_Call struct { - *mock.Call -} - -// GetByURN is a helper method to define mock.On call -// - ctx context.Context -// - urn string -func (_e *AssetRepository_Expecter) GetByURN(ctx interface{}, urn interface{}) *AssetRepository_GetByURN_Call { - return &AssetRepository_GetByURN_Call{Call: _e.mock.On("GetByURN", ctx, urn)} -} - -func (_c *AssetRepository_GetByURN_Call) Run(run func(ctx context.Context, urn string)) *AssetRepository_GetByURN_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *AssetRepository_GetByURN_Call) Return(_a0 asset.Asset, _a1 error) *AssetRepository_GetByURN_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetRepository_GetByURN_Call) RunAndReturn(run func(context.Context, string) (asset.Asset, error)) *AssetRepository_GetByURN_Call { - _c.Call.Return(run) - return _c -} - -// GetByVersionWithID provides a mock function with given fields: ctx, id, version -func (_m *AssetRepository) GetByVersionWithID(ctx context.Context, id string, version string) (asset.Asset, error) { - ret := _m.Called(ctx, id, version) - - var r0 asset.Asset - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (asset.Asset, error)); ok { - return rf(ctx, id, version) - } - if rf, ok := ret.Get(0).(func(context.Context, string, string) asset.Asset); ok { - r0 = rf(ctx, id, version) - } else { - r0 = ret.Get(0).(asset.Asset) - } - - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, id, version) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetRepository_GetByVersionWithID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByVersionWithID' -type AssetRepository_GetByVersionWithID_Call struct { - *mock.Call -} - -// GetByVersionWithID is a helper method to define mock.On call -// - ctx context.Context -// - id string -// - version string -func (_e *AssetRepository_Expecter) GetByVersionWithID(ctx interface{}, id interface{}, version interface{}) *AssetRepository_GetByVersionWithID_Call { - return &AssetRepository_GetByVersionWithID_Call{Call: _e.mock.On("GetByVersionWithID", ctx, id, version)} -} - -func (_c *AssetRepository_GetByVersionWithID_Call) Run(run func(ctx context.Context, id string, version string)) *AssetRepository_GetByVersionWithID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) - }) - return _c -} - -func (_c *AssetRepository_GetByVersionWithID_Call) Return(_a0 asset.Asset, _a1 error) *AssetRepository_GetByVersionWithID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetRepository_GetByVersionWithID_Call) RunAndReturn(run func(context.Context, string, string) (asset.Asset, error)) *AssetRepository_GetByVersionWithID_Call { - _c.Call.Return(run) - return _c -} - -// GetByVersionWithURN provides a mock function with given fields: ctx, urn, version -func (_m *AssetRepository) GetByVersionWithURN(ctx context.Context, urn string, version string) (asset.Asset, error) { - ret := _m.Called(ctx, urn, version) - - var r0 asset.Asset - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (asset.Asset, error)); ok { - return rf(ctx, urn, version) - } - if rf, ok := ret.Get(0).(func(context.Context, string, string) asset.Asset); ok { - r0 = rf(ctx, urn, version) - } else { - r0 = ret.Get(0).(asset.Asset) - } - - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, urn, version) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetRepository_GetByVersionWithURN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByVersionWithURN' -type AssetRepository_GetByVersionWithURN_Call struct { - *mock.Call -} - -// GetByVersionWithURN is a helper method to define mock.On call -// - ctx context.Context -// - urn string -// - version string -func (_e *AssetRepository_Expecter) GetByVersionWithURN(ctx interface{}, urn interface{}, version interface{}) *AssetRepository_GetByVersionWithURN_Call { - return &AssetRepository_GetByVersionWithURN_Call{Call: _e.mock.On("GetByVersionWithURN", ctx, urn, version)} -} - -func (_c *AssetRepository_GetByVersionWithURN_Call) Run(run func(ctx context.Context, urn string, version string)) *AssetRepository_GetByVersionWithURN_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) - }) - return _c -} - -func (_c *AssetRepository_GetByVersionWithURN_Call) Return(_a0 asset.Asset, _a1 error) *AssetRepository_GetByVersionWithURN_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetRepository_GetByVersionWithURN_Call) RunAndReturn(run func(context.Context, string, string) (asset.Asset, error)) *AssetRepository_GetByVersionWithURN_Call { - _c.Call.Return(run) - return _c -} - -// GetCount provides a mock function with given fields: _a0, _a1 -func (_m *AssetRepository) GetCount(_a0 context.Context, _a1 asset.Filter) (int, error) { - ret := _m.Called(_a0, _a1) - - var r0 int - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter) (int, error)); ok { - return rf(_a0, _a1) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter) int); ok { - r0 = rf(_a0, _a1) - } else { - r0 = ret.Get(0).(int) - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.Filter) error); ok { - r1 = rf(_a0, _a1) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetRepository_GetCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCount' -type AssetRepository_GetCount_Call struct { - *mock.Call -} - -// GetCount is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 asset.Filter -func (_e *AssetRepository_Expecter) GetCount(_a0 interface{}, _a1 interface{}) *AssetRepository_GetCount_Call { - return &AssetRepository_GetCount_Call{Call: _e.mock.On("GetCount", _a0, _a1)} -} - -func (_c *AssetRepository_GetCount_Call) Run(run func(_a0 context.Context, _a1 asset.Filter)) *AssetRepository_GetCount_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.Filter)) - }) - return _c -} - -func (_c *AssetRepository_GetCount_Call) Return(_a0 int, _a1 error) *AssetRepository_GetCount_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetRepository_GetCount_Call) RunAndReturn(run func(context.Context, asset.Filter) (int, error)) *AssetRepository_GetCount_Call { - _c.Call.Return(run) - return _c -} - -// GetProbes provides a mock function with given fields: ctx, assetURN -func (_m *AssetRepository) GetProbes(ctx context.Context, assetURN string) ([]asset.Probe, error) { - ret := _m.Called(ctx, assetURN) - - var r0 []asset.Probe - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) ([]asset.Probe, error)); ok { - return rf(ctx, assetURN) - } - if rf, ok := ret.Get(0).(func(context.Context, string) []asset.Probe); ok { - r0 = rf(ctx, assetURN) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]asset.Probe) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, assetURN) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetRepository_GetProbes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProbes' -type AssetRepository_GetProbes_Call struct { - *mock.Call -} - -// GetProbes is a helper method to define mock.On call -// - ctx context.Context -// - assetURN string -func (_e *AssetRepository_Expecter) GetProbes(ctx interface{}, assetURN interface{}) *AssetRepository_GetProbes_Call { - return &AssetRepository_GetProbes_Call{Call: _e.mock.On("GetProbes", ctx, assetURN)} -} - -func (_c *AssetRepository_GetProbes_Call) Run(run func(ctx context.Context, assetURN string)) *AssetRepository_GetProbes_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *AssetRepository_GetProbes_Call) Return(_a0 []asset.Probe, _a1 error) *AssetRepository_GetProbes_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetRepository_GetProbes_Call) RunAndReturn(run func(context.Context, string) ([]asset.Probe, error)) *AssetRepository_GetProbes_Call { - _c.Call.Return(run) - return _c -} - -// GetProbesWithFilter provides a mock function with given fields: ctx, flt -func (_m *AssetRepository) GetProbesWithFilter(ctx context.Context, flt asset.ProbesFilter) (map[string][]asset.Probe, error) { - ret := _m.Called(ctx, flt) - - var r0 map[string][]asset.Probe - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.ProbesFilter) (map[string][]asset.Probe, error)); ok { - return rf(ctx, flt) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.ProbesFilter) map[string][]asset.Probe); ok { - r0 = rf(ctx, flt) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string][]asset.Probe) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.ProbesFilter) error); ok { - r1 = rf(ctx, flt) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetRepository_GetProbesWithFilter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProbesWithFilter' -type AssetRepository_GetProbesWithFilter_Call struct { - *mock.Call -} - -// GetProbesWithFilter is a helper method to define mock.On call -// - ctx context.Context -// - flt asset.ProbesFilter -func (_e *AssetRepository_Expecter) GetProbesWithFilter(ctx interface{}, flt interface{}) *AssetRepository_GetProbesWithFilter_Call { - return &AssetRepository_GetProbesWithFilter_Call{Call: _e.mock.On("GetProbesWithFilter", ctx, flt)} -} - -func (_c *AssetRepository_GetProbesWithFilter_Call) Run(run func(ctx context.Context, flt asset.ProbesFilter)) *AssetRepository_GetProbesWithFilter_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.ProbesFilter)) - }) - return _c -} - -func (_c *AssetRepository_GetProbesWithFilter_Call) Return(_a0 map[string][]asset.Probe, _a1 error) *AssetRepository_GetProbesWithFilter_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetRepository_GetProbesWithFilter_Call) RunAndReturn(run func(context.Context, asset.ProbesFilter) (map[string][]asset.Probe, error)) *AssetRepository_GetProbesWithFilter_Call { - _c.Call.Return(run) - return _c -} - -// GetTypes provides a mock function with given fields: ctx, flt -func (_m *AssetRepository) GetTypes(ctx context.Context, flt asset.Filter) (map[asset.Type]int, error) { - ret := _m.Called(ctx, flt) - - var r0 map[asset.Type]int - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter) (map[asset.Type]int, error)); ok { - return rf(ctx, flt) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter) map[asset.Type]int); ok { - r0 = rf(ctx, flt) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[asset.Type]int) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.Filter) error); ok { - r1 = rf(ctx, flt) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetRepository_GetTypes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTypes' -type AssetRepository_GetTypes_Call struct { - *mock.Call -} - -// GetTypes is a helper method to define mock.On call -// - ctx context.Context -// - flt asset.Filter -func (_e *AssetRepository_Expecter) GetTypes(ctx interface{}, flt interface{}) *AssetRepository_GetTypes_Call { - return &AssetRepository_GetTypes_Call{Call: _e.mock.On("GetTypes", ctx, flt)} -} - -func (_c *AssetRepository_GetTypes_Call) Run(run func(ctx context.Context, flt asset.Filter)) *AssetRepository_GetTypes_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.Filter)) - }) - return _c -} - -func (_c *AssetRepository_GetTypes_Call) Return(_a0 map[asset.Type]int, _a1 error) *AssetRepository_GetTypes_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetRepository_GetTypes_Call) RunAndReturn(run func(context.Context, asset.Filter) (map[asset.Type]int, error)) *AssetRepository_GetTypes_Call { - _c.Call.Return(run) - return _c -} - -// GetVersionHistory provides a mock function with given fields: ctx, flt, id -func (_m *AssetRepository) GetVersionHistory(ctx context.Context, flt asset.Filter, id string) ([]asset.Asset, error) { - ret := _m.Called(ctx, flt, id) - - var r0 []asset.Asset - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter, string) ([]asset.Asset, error)); ok { - return rf(ctx, flt, id) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter, string) []asset.Asset); ok { - r0 = rf(ctx, flt, id) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]asset.Asset) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.Filter, string) error); ok { - r1 = rf(ctx, flt, id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetRepository_GetVersionHistory_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetVersionHistory' -type AssetRepository_GetVersionHistory_Call struct { - *mock.Call -} - -// GetVersionHistory is a helper method to define mock.On call -// - ctx context.Context -// - flt asset.Filter -// - id string -func (_e *AssetRepository_Expecter) GetVersionHistory(ctx interface{}, flt interface{}, id interface{}) *AssetRepository_GetVersionHistory_Call { - return &AssetRepository_GetVersionHistory_Call{Call: _e.mock.On("GetVersionHistory", ctx, flt, id)} -} - -func (_c *AssetRepository_GetVersionHistory_Call) Run(run func(ctx context.Context, flt asset.Filter, id string)) *AssetRepository_GetVersionHistory_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.Filter), args[2].(string)) - }) - return _c -} - -func (_c *AssetRepository_GetVersionHistory_Call) Return(_a0 []asset.Asset, _a1 error) *AssetRepository_GetVersionHistory_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetRepository_GetVersionHistory_Call) RunAndReturn(run func(context.Context, asset.Filter, string) ([]asset.Asset, error)) *AssetRepository_GetVersionHistory_Call { - _c.Call.Return(run) - return _c -} - -// Upsert provides a mock function with given fields: ctx, ns, ast -func (_m *AssetRepository) Upsert(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset) (string, error) { - ret := _m.Called(ctx, ns, ast) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *asset.Asset) (string, error)); ok { - return rf(ctx, ns, ast) - } - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *asset.Asset) string); ok { - r0 = rf(ctx, ns, ast) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(context.Context, *namespace.Namespace, *asset.Asset) error); ok { - r1 = rf(ctx, ns, ast) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetRepository_Upsert_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Upsert' -type AssetRepository_Upsert_Call struct { - *mock.Call -} - -// Upsert is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - ast *asset.Asset -func (_e *AssetRepository_Expecter) Upsert(ctx interface{}, ns interface{}, ast interface{}) *AssetRepository_Upsert_Call { - return &AssetRepository_Upsert_Call{Call: _e.mock.On("Upsert", ctx, ns, ast)} -} - -func (_c *AssetRepository_Upsert_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset)) *AssetRepository_Upsert_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*asset.Asset)) - }) - return _c -} - -func (_c *AssetRepository_Upsert_Call) Return(_a0 string, _a1 error) *AssetRepository_Upsert_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetRepository_Upsert_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *asset.Asset) (string, error)) *AssetRepository_Upsert_Call { - _c.Call.Return(run) - return _c -} - -// SoftDeleteByID provides a mock function with given fields: ctx, id -func (_m *AssetRepository) SoftDeleteByID(ctx context.Context, id string) (string, error) { - ret := _m.Called(ctx, id) - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (string, error)); ok { - return rf(ctx, id) - } - if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { - r0 = rf(ctx, id) - } else { - r0 = ret.Get(0).(string) - } - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, id) - } else { - r1 = ret.Error(1) - } - return r0, r1 -} - -// SoftDeleteByURN provides a mock function with given fields: ctx, urn -func (_m *AssetRepository) SoftDeleteByURN(ctx context.Context, urn string) (string, error) { - ret := _m.Called(ctx, urn) - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (string, error)); ok { - return rf(ctx, urn) - } - if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { - r0 = rf(ctx, urn) - } else { - r0 = ret.Get(0).(string) - } - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, urn) - } else { - r1 = ret.Error(1) - } - return r0, r1 -} - -// GetCountByIsDeleted provides a mock function with given fields: ctx, isDeleted -func (_m *AssetRepository) GetCountByIsDeleted(ctx context.Context, isDeleted bool) (int, error) { - ret := _m.Called(ctx, isDeleted) - var r0 int - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, bool) (int, error)); ok { - return rf(ctx, isDeleted) - } - if rf, ok := ret.Get(0).(func(context.Context, bool) int); ok { - r0 = rf(ctx, isDeleted) - } else { - r0 = ret.Get(0).(int) - } - if rf, ok := ret.Get(1).(func(context.Context, bool) error); ok { - r1 = rf(ctx, isDeleted) - } else { - r1 = ret.Error(1) - } - return r0, r1 -} - -// HardDeleteByURNs provides a mock function with given fields: ctx, urns -func (_m *AssetRepository) HardDeleteByURNs(ctx context.Context, urns []string) error { - ret := _m.Called(ctx, urns) - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, []string) error); ok { - r0 = rf(ctx, urns) - } else { - r0 = ret.Error(0) - } - return r0 -} - -type mockConstructorTestingTNewAssetRepository interface { - mock.TestingT - Cleanup(func()) -} - -// NewAssetRepository creates a new instance of AssetRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewAssetRepository(t mockConstructorTestingTNewAssetRepository) *AssetRepository { - mock := &AssetRepository{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/asset/mocks/discovery_repository.go b/core/asset/mocks/discovery_repository.go deleted file mode 100644 index 1d3c1833..00000000 --- a/core/asset/mocks/discovery_repository.go +++ /dev/null @@ -1,318 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - asset "github.com/raystack/compass/core/asset" - - mock "github.com/stretchr/testify/mock" - - namespace "github.com/raystack/compass/core/namespace" -) - -// DiscoveryRepository is an autogenerated mock type for the DiscoveryRepository type -type DiscoveryRepository struct { - mock.Mock -} - -type DiscoveryRepository_Expecter struct { - mock *mock.Mock -} - -func (_m *DiscoveryRepository) EXPECT() *DiscoveryRepository_Expecter { - return &DiscoveryRepository_Expecter{mock: &_m.Mock} -} - -// DeleteByID provides a mock function with given fields: ctx, ns, assetID -func (_m *DiscoveryRepository) DeleteByID(ctx context.Context, ns *namespace.Namespace, assetID string) error { - ret := _m.Called(ctx, ns, assetID) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string) error); ok { - r0 = rf(ctx, ns, assetID) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DiscoveryRepository_DeleteByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteByID' -type DiscoveryRepository_DeleteByID_Call struct { - *mock.Call -} - -// DeleteByID is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - assetID string -func (_e *DiscoveryRepository_Expecter) DeleteByID(ctx interface{}, ns interface{}, assetID interface{}) *DiscoveryRepository_DeleteByID_Call { - return &DiscoveryRepository_DeleteByID_Call{Call: _e.mock.On("DeleteByID", ctx, ns, assetID)} -} - -func (_c *DiscoveryRepository_DeleteByID_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, assetID string)) *DiscoveryRepository_DeleteByID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(string)) - }) - return _c -} - -func (_c *DiscoveryRepository_DeleteByID_Call) Return(_a0 error) *DiscoveryRepository_DeleteByID_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *DiscoveryRepository_DeleteByID_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, string) error) *DiscoveryRepository_DeleteByID_Call { - _c.Call.Return(run) - return _c -} - -// DeleteByURN provides a mock function with given fields: ctx, ns, assetURN -func (_m *DiscoveryRepository) DeleteByURN(ctx context.Context, ns *namespace.Namespace, assetURN string) error { - ret := _m.Called(ctx, ns, assetURN) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string) error); ok { - r0 = rf(ctx, ns, assetURN) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DiscoveryRepository_DeleteByURN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteByURN' -type DiscoveryRepository_DeleteByURN_Call struct { - *mock.Call -} - -// DeleteByURN is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - assetURN string -func (_e *DiscoveryRepository_Expecter) DeleteByURN(ctx interface{}, ns interface{}, assetURN interface{}) *DiscoveryRepository_DeleteByURN_Call { - return &DiscoveryRepository_DeleteByURN_Call{Call: _e.mock.On("DeleteByURN", ctx, ns, assetURN)} -} - -func (_c *DiscoveryRepository_DeleteByURN_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, assetURN string)) *DiscoveryRepository_DeleteByURN_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(string)) - }) - return _c -} - -func (_c *DiscoveryRepository_DeleteByURN_Call) Return(_a0 error) *DiscoveryRepository_DeleteByURN_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *DiscoveryRepository_DeleteByURN_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, string) error) *DiscoveryRepository_DeleteByURN_Call { - _c.Call.Return(run) - return _c -} - -// Search provides a mock function with given fields: ctx, cfg -func (_m *DiscoveryRepository) Search(ctx context.Context, cfg asset.SearchConfig) ([]asset.SearchResult, error) { - ret := _m.Called(ctx, cfg) - - var r0 []asset.SearchResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.SearchConfig) ([]asset.SearchResult, error)); ok { - return rf(ctx, cfg) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.SearchConfig) []asset.SearchResult); ok { - r0 = rf(ctx, cfg) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]asset.SearchResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.SearchConfig) error); ok { - r1 = rf(ctx, cfg) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscoveryRepository_Search_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Search' -type DiscoveryRepository_Search_Call struct { - *mock.Call -} - -// Search is a helper method to define mock.On call -// - ctx context.Context -// - cfg asset.SearchConfig -func (_e *DiscoveryRepository_Expecter) Search(ctx interface{}, cfg interface{}) *DiscoveryRepository_Search_Call { - return &DiscoveryRepository_Search_Call{Call: _e.mock.On("Search", ctx, cfg)} -} - -func (_c *DiscoveryRepository_Search_Call) Run(run func(ctx context.Context, cfg asset.SearchConfig)) *DiscoveryRepository_Search_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.SearchConfig)) - }) - return _c -} - -func (_c *DiscoveryRepository_Search_Call) Return(results []asset.SearchResult, err error) *DiscoveryRepository_Search_Call { - _c.Call.Return(results, err) - return _c -} - -func (_c *DiscoveryRepository_Search_Call) RunAndReturn(run func(context.Context, asset.SearchConfig) ([]asset.SearchResult, error)) *DiscoveryRepository_Search_Call { - _c.Call.Return(run) - return _c -} - -// Suggest provides a mock function with given fields: ctx, cfg -func (_m *DiscoveryRepository) Suggest(ctx context.Context, cfg asset.SearchConfig) ([]string, error) { - ret := _m.Called(ctx, cfg) - - var r0 []string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.SearchConfig) ([]string, error)); ok { - return rf(ctx, cfg) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.SearchConfig) []string); ok { - r0 = rf(ctx, cfg) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.SearchConfig) error); ok { - r1 = rf(ctx, cfg) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscoveryRepository_Suggest_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Suggest' -type DiscoveryRepository_Suggest_Call struct { - *mock.Call -} - -// Suggest is a helper method to define mock.On call -// - ctx context.Context -// - cfg asset.SearchConfig -func (_e *DiscoveryRepository_Expecter) Suggest(ctx interface{}, cfg interface{}) *DiscoveryRepository_Suggest_Call { - return &DiscoveryRepository_Suggest_Call{Call: _e.mock.On("Suggest", ctx, cfg)} -} - -func (_c *DiscoveryRepository_Suggest_Call) Run(run func(ctx context.Context, cfg asset.SearchConfig)) *DiscoveryRepository_Suggest_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.SearchConfig)) - }) - return _c -} - -func (_c *DiscoveryRepository_Suggest_Call) Return(suggestions []string, err error) *DiscoveryRepository_Suggest_Call { - _c.Call.Return(suggestions, err) - return _c -} - -func (_c *DiscoveryRepository_Suggest_Call) RunAndReturn(run func(context.Context, asset.SearchConfig) ([]string, error)) *DiscoveryRepository_Suggest_Call { - _c.Call.Return(run) - return _c -} - -// Upsert provides a mock function with given fields: ctx, ns, ast -func (_m *DiscoveryRepository) Upsert(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset) error { - ret := _m.Called(ctx, ns, ast) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *asset.Asset) error); ok { - r0 = rf(ctx, ns, ast) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DiscoveryRepository_Upsert_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Upsert' -type DiscoveryRepository_Upsert_Call struct { - *mock.Call -} - -// Upsert is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - ast *asset.Asset -func (_e *DiscoveryRepository_Expecter) Upsert(ctx interface{}, ns interface{}, ast interface{}) *DiscoveryRepository_Upsert_Call { - return &DiscoveryRepository_Upsert_Call{Call: _e.mock.On("Upsert", ctx, ns, ast)} -} - -func (_c *DiscoveryRepository_Upsert_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset)) *DiscoveryRepository_Upsert_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*asset.Asset)) - }) - return _c -} - -func (_c *DiscoveryRepository_Upsert_Call) Return(_a0 error) *DiscoveryRepository_Upsert_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *DiscoveryRepository_Upsert_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *asset.Asset) error) *DiscoveryRepository_Upsert_Call { - _c.Call.Return(run) - return _c -} - -// GroupAssets provides a mock function with given fields: ctx, cfg -func (_m *DiscoveryRepository) GroupAssets(ctx context.Context, cfg asset.GroupConfig) ([]asset.GroupResult, error) { - ret := _m.Called(ctx, cfg) - var r0 []asset.GroupResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.GroupConfig) ([]asset.GroupResult, error)); ok { - return rf(ctx, cfg) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.GroupConfig) []asset.GroupResult); ok { - r0 = rf(ctx, cfg) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]asset.GroupResult) - } - } - if rf, ok := ret.Get(1).(func(context.Context, asset.GroupConfig) error); ok { - r1 = rf(ctx, cfg) - } else { - r1 = ret.Error(1) - } - return r0, r1 -} - -// SoftDeleteByURN provides a mock function with given fields: ctx, ns, assetURN -func (_m *DiscoveryRepository) SoftDeleteByURN(ctx context.Context, ns *namespace.Namespace, assetURN string) error { - ret := _m.Called(ctx, ns, assetURN) - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string) error); ok { - r0 = rf(ctx, ns, assetURN) - } else { - r0 = ret.Error(0) - } - return r0 -} - -type mockConstructorTestingTNewDiscoveryRepository interface { - mock.TestingT - Cleanup(func()) -} - -// NewDiscoveryRepository creates a new instance of DiscoveryRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewDiscoveryRepository(t mockConstructorTestingTNewDiscoveryRepository) *DiscoveryRepository { - mock := &DiscoveryRepository{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/asset/mocks/lineage_repository.go b/core/asset/mocks/lineage_repository.go deleted file mode 100644 index 6c342b98..00000000 --- a/core/asset/mocks/lineage_repository.go +++ /dev/null @@ -1,193 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - asset "github.com/raystack/compass/core/asset" - - mock "github.com/stretchr/testify/mock" - - namespace "github.com/raystack/compass/core/namespace" -) - -// LineageRepository is an autogenerated mock type for the LineageRepository type -type LineageRepository struct { - mock.Mock -} - -type LineageRepository_Expecter struct { - mock *mock.Mock -} - -func (_m *LineageRepository) EXPECT() *LineageRepository_Expecter { - return &LineageRepository_Expecter{mock: &_m.Mock} -} - -// DeleteByURN provides a mock function with given fields: ctx, urn -func (_m *LineageRepository) DeleteByURN(ctx context.Context, urn string) error { - ret := _m.Called(ctx, urn) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { - r0 = rf(ctx, urn) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// LineageRepository_DeleteByURN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteByURN' -type LineageRepository_DeleteByURN_Call struct { - *mock.Call -} - -// DeleteByURN is a helper method to define mock.On call -// - ctx context.Context -// - urn string -func (_e *LineageRepository_Expecter) DeleteByURN(ctx interface{}, urn interface{}) *LineageRepository_DeleteByURN_Call { - return &LineageRepository_DeleteByURN_Call{Call: _e.mock.On("DeleteByURN", ctx, urn)} -} - -func (_c *LineageRepository_DeleteByURN_Call) Run(run func(ctx context.Context, urn string)) *LineageRepository_DeleteByURN_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *LineageRepository_DeleteByURN_Call) Return(_a0 error) *LineageRepository_DeleteByURN_Call { - _c.Call.Return(_a0) - return _c -} - -// GetGraph provides a mock function with given fields: ctx, urn, query -func (_m *LineageRepository) GetGraph(ctx context.Context, urn string, query asset.LineageQuery) (asset.LineageGraph, error) { - ret := _m.Called(ctx, urn, query) - - var r0 asset.LineageGraph - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, asset.LineageQuery) (asset.LineageGraph, error)); ok { - return rf(ctx, urn, query) - } - if rf, ok := ret.Get(0).(func(context.Context, string, asset.LineageQuery) asset.LineageGraph); ok { - r0 = rf(ctx, urn, query) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(asset.LineageGraph) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string, asset.LineageQuery) error); ok { - r1 = rf(ctx, urn, query) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// LineageRepository_GetGraph_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGraph' -type LineageRepository_GetGraph_Call struct { - *mock.Call -} - -// GetGraph is a helper method to define mock.On call -// - ctx context.Context -// - urn string -// - query asset.LineageQuery -func (_e *LineageRepository_Expecter) GetGraph(ctx interface{}, urn interface{}, query interface{}) *LineageRepository_GetGraph_Call { - return &LineageRepository_GetGraph_Call{Call: _e.mock.On("GetGraph", ctx, urn, query)} -} - -func (_c *LineageRepository_GetGraph_Call) Run(run func(ctx context.Context, urn string, query asset.LineageQuery)) *LineageRepository_GetGraph_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(asset.LineageQuery)) - }) - return _c -} - -func (_c *LineageRepository_GetGraph_Call) Return(_a0 asset.LineageGraph, _a1 error) *LineageRepository_GetGraph_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *LineageRepository_GetGraph_Call) RunAndReturn(run func(context.Context, string, asset.LineageQuery) (asset.LineageGraph, error)) *LineageRepository_GetGraph_Call { - _c.Call.Return(run) - return _c -} - -// Upsert provides a mock function with given fields: ctx, ns, urn, upstreams, downstreams -func (_m *LineageRepository) Upsert(ctx context.Context, ns *namespace.Namespace, urn string, upstreams []string, downstreams []string) error { - ret := _m.Called(ctx, ns, urn, upstreams, downstreams) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string, []string, []string) error); ok { - r0 = rf(ctx, ns, urn, upstreams, downstreams) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// LineageRepository_Upsert_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Upsert' -type LineageRepository_Upsert_Call struct { - *mock.Call -} - -// Upsert is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - urn string -// - upstreams []string -// - downstreams []string -func (_e *LineageRepository_Expecter) Upsert(ctx interface{}, ns interface{}, urn interface{}, upstreams interface{}, downstreams interface{}) *LineageRepository_Upsert_Call { - return &LineageRepository_Upsert_Call{Call: _e.mock.On("Upsert", ctx, ns, urn, upstreams, downstreams)} -} - -func (_c *LineageRepository_Upsert_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, urn string, upstreams []string, downstreams []string)) *LineageRepository_Upsert_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(string), args[3].([]string), args[4].([]string)) - }) - return _c -} - -func (_c *LineageRepository_Upsert_Call) Return(_a0 error) *LineageRepository_Upsert_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *LineageRepository_Upsert_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, string, []string, []string) error) *LineageRepository_Upsert_Call { - _c.Call.Return(run) - return _c -} - -// DeleteByURNs provides a mock function with given fields: ctx, urns -func (_m *LineageRepository) DeleteByURNs(ctx context.Context, urns []string) error { - ret := _m.Called(ctx, urns) - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, []string) error); ok { - r0 = rf(ctx, urns) - } else { - r0 = ret.Error(0) - } - return r0 -} - -type mockConstructorTestingTNewLineageRepository interface { - mock.TestingT - Cleanup(func()) -} - -// NewLineageRepository creates a new instance of LineageRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewLineageRepository(t mockConstructorTestingTNewLineageRepository) *LineageRepository { - mock := &LineageRepository{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/asset/patch.go b/core/asset/patch.go deleted file mode 100644 index 34b3bd84..00000000 --- a/core/asset/patch.go +++ /dev/null @@ -1,187 +0,0 @@ -package asset - -import ( - "github.com/peterbourgon/mergemap" - "github.com/raystack/compass/core/user" -) - -// patch appends asset with data from map. It mutates the asset itself. -func patchAsset(a *Asset, patchData map[string]interface{}) { - a.URN = patchString("urn", patchData, a.URN) - a.Type = Type(patchString("type", patchData, a.Type.String())) - a.Service = patchString("service", patchData, a.Service) - a.Name = patchString("name", patchData, a.Name) - a.Description = patchString("description", patchData, a.Description) - a.URL = patchString("url", patchData, a.URL) - - labels, exists := patchData["labels"] - if exists { - a.Labels = mergeLabels(a.Labels, buildLabels(labels)) - } - owners, exists := patchData["owners"] - if exists { - a.Owners = mergeOwners(a.Owners, buildOwners(owners)) - } - data, exists := patchData["data"] - if exists { - patchAssetData(a, data) - } -} - -// mergeLabels merges new labels into existing ones. New values override existing keys. -func mergeLabels(existing, patch map[string]string) map[string]string { - if existing == nil { - return patch - } - if patch == nil { - return existing - } - for k, v := range patch { - existing[k] = v - } - return existing -} - -// mergeOwners merges new owners into existing ones, deduplicating by email or uuid. -func mergeOwners(existing, patch []user.User) []user.User { - if existing == nil { - return patch - } - if patch == nil { - return existing - } - - seen := make(map[string]int) // key -> index in result - result := make([]user.User, len(existing)) - copy(result, existing) - - for i, o := range result { - if key := ownerKey(o); key != "" { - seen[key] = i - } - } - - for _, o := range patch { - key := ownerKey(o) - if key == "" { - result = append(result, o) - continue - } - if idx, exists := seen[key]; exists { - // update existing owner in-place - result[idx] = o - } else { - seen[key] = len(result) - result = append(result, o) - } - } - - return result -} - -// ownerKey returns a deduplication key for an owner (email preferred, then uuid). -func ownerKey(o user.User) string { - if o.Email != "" { - return "email:" + o.Email - } - if o.UUID != "" { - return "uuid:" + o.UUID - } - return "" -} - -// buildLabels builds labels from interface{} -func buildLabels(data interface{}) (labels map[string]string) { - switch d := data.(type) { - case map[string]interface{}: - labels = map[string]string{} - for key, value := range d { - stringVal, ok := value.(string) - if !ok { - continue - } - labels[key] = stringVal - } - case map[string]string: - labels = d - default: - labels = nil - } - - return -} - -// buildOwners builds owners from interface{} -func buildOwners(data interface{}) (owners []user.User) { - buildOwner := func(data map[string]interface{}) user.User { - return user.User{ - ID: getString("id", data), - UUID: getString("uuid", data), - Email: getString("email", data), - Provider: getString("provider", data), - } - } - - switch d := data.(type) { - case []interface{}: - owners = []user.User{} - for _, value := range d { - mapValue, ok := value.(map[string]interface{}) - if !ok { - continue - } - owners = append(owners, buildOwner(mapValue)) - } - case []map[string]interface{}: - owners = []user.User{} - for _, value := range d { - owners = append(owners, buildOwner(value)) - } - case []user.User: - owners = d - default: - owners = nil - } - - return -} - -// patchAssetData patches asset's data using map -func patchAssetData(a *Asset, data interface{}) { - if data == nil { - return - } - dataMap, ok := data.(map[string]interface{}) - if !ok { - return - } - - if a.Data == nil { - a.Data = dataMap - return - } - - a.Data = mergemap.Merge(a.Data, dataMap) -} - -func patchString(key string, data map[string]interface{}, defaultVal string) string { - _, exists := data[key] - if !exists { - return defaultVal - } - - return getString(key, data) -} - -func getString(key string, data map[string]interface{}) string { - val, exists := data[key] - if !exists { - return "" - } - stringVal, ok := val.(string) - if !ok { - return "" - } - - return stringVal -} diff --git a/core/asset/probe.go b/core/asset/probe.go deleted file mode 100644 index 0bfcc27c..00000000 --- a/core/asset/probe.go +++ /dev/null @@ -1,16 +0,0 @@ -package asset - -import ( - "time" -) - -// Probe represents a single asset's probe -type Probe struct { - ID string `json:"id"` - AssetURN string `json:"asset_urn"` - Status string `json:"status"` - StatusReason string `json:"status_reason"` - Metadata map[string]interface{} `json:"metadata"` - Timestamp time.Time `json:"timestamp"` - CreatedAt time.Time `json:"created_at"` -} diff --git a/core/asset/probes_filter.go b/core/asset/probes_filter.go deleted file mode 100644 index 8c032999..00000000 --- a/core/asset/probes_filter.go +++ /dev/null @@ -1,10 +0,0 @@ -package asset - -import "time" - -type ProbesFilter struct { - AssetURNs []string - MaxRows int - NewerThan time.Time - OlderThan time.Time -} diff --git a/core/asset/service.go b/core/asset/service.go deleted file mode 100644 index 6898c5e9..00000000 --- a/core/asset/service.go +++ /dev/null @@ -1,224 +0,0 @@ -package asset - -import ( - "context" - "fmt" - - "github.com/raystack/compass/core/namespace" - - "github.com/google/uuid" -) - -type Service struct { - assetRepository Repository - discoveryRepository DiscoveryRepository - lineageRepository LineageRepository -} - -func NewService(assetRepository Repository, discoveryRepository DiscoveryRepository, lineageRepository LineageRepository) *Service { - return &Service{ - assetRepository: assetRepository, - discoveryRepository: discoveryRepository, - lineageRepository: lineageRepository, - } -} - -func (s *Service) GetAllAssets(ctx context.Context, flt Filter, withTotal bool) ([]Asset, uint32, error) { - var totalCount uint32 = 0 - assets, err := s.assetRepository.GetAll(ctx, flt) - if err != nil { - return nil, totalCount, err - } - - if withTotal { - total, err := s.assetRepository.GetCount(ctx, flt) - if err != nil { - return nil, totalCount, err - } - totalCount = uint32(total) - } - return assets, totalCount, nil -} - -func (s *Service) UpsertAsset(ctx context.Context, ns *namespace.Namespace, ast *Asset, upstreams, downstreams []string) (string, error) { - assetID, err := s.UpsertAssetWithoutLineage(ctx, ns, ast) - if err != nil { - return "", err - } - - if err := s.lineageRepository.Upsert(ctx, ns, ast.URN, upstreams, downstreams); err != nil { - return "", err - } - - return assetID, nil -} - -func (s *Service) UpsertAssetWithoutLineage(ctx context.Context, ns *namespace.Namespace, ast *Asset) (string, error) { - assetID, err := s.assetRepository.Upsert(ctx, ns, ast) - if err != nil { - return "", err - } - - ast.ID = assetID - if err := s.discoveryRepository.Upsert(ctx, ns, ast); err != nil { - return "", err - } - - return assetID, nil -} - -func (s *Service) DeleteAsset(ctx context.Context, ns *namespace.Namespace, id string) error { - if isValidUUID(id) { - asset, err := s.assetRepository.GetByID(ctx, id) - if err != nil { - return err - } - if err := s.assetRepository.DeleteByID(ctx, id); err != nil { - return err - } - if err := s.discoveryRepository.DeleteByID(ctx, ns, id); err != nil { - return err - } - return s.lineageRepository.DeleteByURN(ctx, asset.URN) - } - - if err := s.assetRepository.DeleteByURN(ctx, id); err != nil { - return err - } - - if err := s.discoveryRepository.DeleteByURN(ctx, ns, id); err != nil { - return err - } - - return s.lineageRepository.DeleteByURN(ctx, id) -} - -// SoftDeleteAsset marks an asset as deleted without removing it -func (s *Service) SoftDeleteAsset(ctx context.Context, ns *namespace.Namespace, id string) error { - var urn string - var err error - - if isValidUUID(id) { - urn, err = s.assetRepository.SoftDeleteByID(ctx, id) - } else { - urn = id - _, err = s.assetRepository.SoftDeleteByURN(ctx, id) - } - if err != nil { - return err - } - - if err := s.discoveryRepository.SoftDeleteByURN(ctx, ns, urn); err != nil { - return fmt.Errorf("error soft deleting asset in discovery: %w", err) - } - - return nil -} - -func (s *Service) GetAssetByID(ctx context.Context, id string) (ast Asset, err error) { - if isValidUUID(id) { - if ast, err = s.assetRepository.GetByID(ctx, id); err != nil { - return Asset{}, fmt.Errorf("error when getting asset by id: %w", err) - } - } else { - if ast, err = s.assetRepository.GetByURN(ctx, id); err != nil { - return Asset{}, fmt.Errorf("error when getting asset by urn: %w", err) - } - } - - probes, err := s.assetRepository.GetProbes(ctx, ast.URN) - if err != nil { - return Asset{}, fmt.Errorf("error when getting probes: %w", err) - } - - ast.Probes = probes - - return -} - -func (s *Service) GetAssetByVersion(ctx context.Context, id string, version string) (Asset, error) { - if isValidUUID(id) { - return s.assetRepository.GetByVersionWithID(ctx, id, version) - } - - return s.assetRepository.GetByVersionWithURN(ctx, id, version) -} - -func (s *Service) GetAssetVersionHistory(ctx context.Context, flt Filter, id string) ([]Asset, error) { - return s.assetRepository.GetVersionHistory(ctx, flt, id) -} - -func (s *Service) AddProbe(ctx context.Context, ns *namespace.Namespace, assetURN string, probe *Probe) error { - return s.assetRepository.AddProbe(ctx, ns, assetURN, probe) -} - -func (s *Service) GetLineage(ctx context.Context, urn string, query LineageQuery) (Lineage, error) { - edges, err := s.lineageRepository.GetGraph(ctx, urn, query) - if err != nil { - return Lineage{}, fmt.Errorf("get lineage: get graph edges: %w", err) - } - - if !query.WithAttributes { - return Lineage{ - Edges: edges, - }, nil - } - - urns := newUniqueStrings(len(edges)) - urns.add(urn) - for _, edge := range edges { - urns.add(edge.Source, edge.Target) - } - - assetProbes, err := s.assetRepository.GetProbesWithFilter(ctx, ProbesFilter{ - AssetURNs: urns.list(), - MaxRows: 1, - }) - if err != nil { - return Lineage{}, fmt.Errorf("get lineage: get latest probes: %w", err) - } - - return Lineage{ - Edges: edges, - NodeAttrs: buildNodeAttrs(assetProbes), - }, nil -} - -func (s *Service) GetTypes(ctx context.Context, flt Filter) (map[Type]int, error) { - result, err := s.assetRepository.GetTypes(ctx, flt) - if err != nil { - return nil, err - } - return result, nil -} - -func (s *Service) SearchAssets(ctx context.Context, cfg SearchConfig) (results []SearchResult, err error) { - return s.discoveryRepository.Search(ctx, cfg) -} - -func (s *Service) GroupAssets(ctx context.Context, cfg GroupConfig) ([]GroupResult, error) { - return s.discoveryRepository.GroupAssets(ctx, cfg) -} -func (s *Service) SuggestAssets(ctx context.Context, cfg SearchConfig) (suggestions []string, err error) { - return s.discoveryRepository.Suggest(ctx, cfg) -} - -func isValidUUID(u string) bool { - _, err := uuid.Parse(u) - return err == nil -} - -func buildNodeAttrs(assetProbes map[string][]Probe) map[string]NodeAttributes { - nodeAttrs := make(map[string]NodeAttributes, len(assetProbes)) - for urn, probes := range assetProbes { - if len(probes) == 0 { - continue - } - - nodeAttrs[urn] = NodeAttributes{ - Probes: ProbesInfo{Latest: probes[0]}, - } - } - - return nodeAttrs -} diff --git a/core/asset/service_test.go b/core/asset/service_test.go deleted file mode 100644 index 26538aa8..00000000 --- a/core/asset/service_test.go +++ /dev/null @@ -1,915 +0,0 @@ -package asset_test - -import ( - "context" - "errors" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/asset/mocks" - "github.com/stretchr/testify/assert" -) - -func TestService_GetAllAssets(t *testing.T) { - type testCase struct { - Description string - Filter asset.Filter - WithTotal bool - Err error - ResultLen int - TotalCnt uint32 - Setup func(context.Context, *mocks.AssetRepository, *mocks.DiscoveryRepository, *mocks.LineageRepository) - } - - var testCases = []testCase{ - { - Description: `should return error if asset repository get all return error and with total false`, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().GetAll(ctx, asset.Filter{}).Return([]asset.Asset{}, errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - ResultLen: 0, - TotalCnt: 0, - }, - { - Description: `should return assets if asset repository get all return no error and with total false`, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().GetAll(ctx, asset.Filter{}).Return([]asset.Asset{ - { - ID: "some-id", - }, - }, nil) - }, - Err: errors.New("unknown error"), - ResultLen: 1, - TotalCnt: 0, - }, - { - Description: `should return error if asset repository get count return error and with total true`, - WithTotal: true, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().GetAll(ctx, asset.Filter{}).Return([]asset.Asset{ - { - ID: "some-id", - }, - }, nil) - ar.EXPECT().GetCount(ctx, asset.Filter{}).Return(0, errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - ResultLen: 0, - TotalCnt: 0, - }, - { - Description: `should return no error if asset repository get count return no error and with total true`, - WithTotal: true, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().GetAll(ctx, asset.Filter{}).Return([]asset.Asset{ - { - ID: "some-id", - }, - }, nil) - ar.EXPECT().GetCount(ctx, asset.Filter{}).Return(1, nil) - }, - Err: nil, - ResultLen: 1, - TotalCnt: 1, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := context.Background() - - mockAssetRepo := mocks.NewAssetRepository(t) - mockDiscoveryRepo := mocks.NewDiscoveryRepository(t) - mockLineageRepo := mocks.NewLineageRepository(t) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetRepo, mockDiscoveryRepo, mockLineageRepo) - } - - svc := asset.NewService(mockAssetRepo, mockDiscoveryRepo, mockLineageRepo) - got, cnt, err := svc.GetAllAssets(ctx, tc.Filter, tc.WithTotal) - if err != nil && errors.Is(tc.Err, err) { - t.Fatalf("got error %v, expected error was %v", err, tc.Err) - } - if tc.ResultLen != len(got) { - t.Fatalf("got result len %v, expected result len was %v", len(got), tc.ResultLen) - } - if tc.TotalCnt != cnt { - t.Fatalf("got total count %v, expected total count was %v", cnt, tc.TotalCnt) - } - }) - } -} - -func TestService_GetTypes(t *testing.T) { - type testCase struct { - Description string - Filter asset.Filter - Err error - Result map[asset.Type]int - Setup func(context.Context, *mocks.AssetRepository) - } - - var testCases = []testCase{ - { - Description: `should return error if asset repository get types return error`, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetTypes(ctx, asset.Filter{}).Return(nil, errors.New("unknown error")) - }, - Result: nil, - Err: errors.New("unknown error"), - }, - { - Description: `should return map types if asset repository get types return no error`, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetTypes(ctx, asset.Filter{}).Return(map[asset.Type]int{ - asset.TypeJob: 1, - asset.TypeTable: 1, - asset.TypeTopic: 1, - }, nil) - }, - Result: map[asset.Type]int{ - asset.TypeJob: 1, - asset.TypeTable: 1, - asset.TypeTopic: 1, - }, - Err: nil, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := context.Background() - - mockAssetRepo := mocks.NewAssetRepository(t) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetRepo) - } - - svc := asset.NewService(mockAssetRepo, nil, nil) - got, err := svc.GetTypes(ctx, tc.Filter) - if err != nil && errors.Is(tc.Err, err) { - t.Fatalf("got error %v, expected error was %v", err, tc.Err) - } - if !cmp.Equal(tc.Result, got) { - t.Fatalf("got result %+v, expected result was %+v", got, tc.Result) - } - }) - } -} - -func TestService_UpsertAsset(t *testing.T) { - sampleAsset := &asset.Asset{ID: "some-id", URN: "some-urn", Type: asset.TypeDashboard, Service: "some-service"} - sampleNodes1 := []string{"1-urn-1", "1-urn-2"} - sampleNodes2 := []string{"2-urn-1", "2-urn-2"} - type testCase struct { - Description string - Asset *asset.Asset - Upstreams []string - Downstreams []string - Err error - ReturnedID string - Setup func(context.Context, *mocks.AssetRepository, *mocks.DiscoveryRepository, *mocks.LineageRepository) - } - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - - var testCases = []testCase{ - { - Description: `should return error if asset repository upsert return error`, - Asset: sampleAsset, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().Upsert(ctx, ns, sampleAsset).Return("", errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - ReturnedID: "", - }, - { - Description: `should return error if discovery repository upsert return error`, - Asset: sampleAsset, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().Upsert(ctx, ns, sampleAsset).Return(sampleAsset.ID, nil) - dr.EXPECT().Upsert(ctx, ns, sampleAsset).Return(errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - ReturnedID: sampleAsset.ID, - }, - { - Description: `should return error if lineage repository upsert return error`, - Asset: sampleAsset, - Upstreams: sampleNodes1, - Downstreams: sampleNodes2, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().Upsert(ctx, ns, sampleAsset).Return(sampleAsset.ID, nil) - dr.EXPECT().Upsert(ctx, ns, sampleAsset).Return(nil) - lr.EXPECT().Upsert(ctx, ns, sampleAsset.URN, sampleNodes1, sampleNodes2).Return(errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - ReturnedID: sampleAsset.ID, - }, - { - Description: `should return no error if all repositories upsert return no error`, - Asset: sampleAsset, - Upstreams: sampleNodes1, - Downstreams: sampleNodes2, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().Upsert(ctx, ns, sampleAsset).Return(sampleAsset.ID, nil) - dr.EXPECT().Upsert(ctx, ns, sampleAsset).Return(nil) - lr.EXPECT().Upsert(ctx, ns, sampleAsset.URN, sampleNodes1, sampleNodes2).Return(nil) - }, - Err: nil, - ReturnedID: sampleAsset.ID, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := context.Background() - - mockAssetRepo := mocks.NewAssetRepository(t) - mockDiscoveryRepo := mocks.NewDiscoveryRepository(t) - mockLineageRepo := mocks.NewLineageRepository(t) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetRepo, mockDiscoveryRepo, mockLineageRepo) - } - - svc := asset.NewService(mockAssetRepo, mockDiscoveryRepo, mockLineageRepo) - rid, err := svc.UpsertAsset(ctx, ns, tc.Asset, tc.Upstreams, tc.Downstreams) - if tc.Err != nil { - assert.EqualError(t, err, tc.Err.Error()) - return - } - assert.NoError(t, err) - assert.Equal(t, tc.ReturnedID, rid) - }) - } -} - -func TestService_UpsertAssetWithoutLineage(t *testing.T) { - sampleAsset := &asset.Asset{ID: "some-id", URN: "some-urn", Type: asset.TypeDashboard, Service: "some-service"} - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - var testCases = []struct { - Description string - Asset *asset.Asset - Err error - ReturnedID string - Setup func(context.Context, *mocks.AssetRepository, *mocks.DiscoveryRepository) - }{ - { - Description: `should return error if asset repository upsert return error`, - Asset: sampleAsset, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository) { - ar.EXPECT().Upsert(ctx, ns, sampleAsset).Return("", errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - }, - { - Description: `should return error if discovery repository upsert return error`, - Asset: sampleAsset, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository) { - ar.EXPECT().Upsert(ctx, ns, sampleAsset).Return(sampleAsset.ID, nil) - dr.EXPECT().Upsert(ctx, ns, sampleAsset).Return(errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - }, - { - Description: `should return no error if all repositories upsert return no error`, - Asset: sampleAsset, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository) { - ar.EXPECT().Upsert(ctx, ns, sampleAsset).Return(sampleAsset.ID, nil) - dr.EXPECT().Upsert(ctx, ns, sampleAsset).Return(nil) - }, - ReturnedID: sampleAsset.ID, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := context.Background() - - mockAssetRepo := mocks.NewAssetRepository(t) - mockDiscoveryRepo := mocks.NewDiscoveryRepository(t) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetRepo, mockDiscoveryRepo) - } - - svc := asset.NewService(mockAssetRepo, mockDiscoveryRepo, mocks.NewLineageRepository(t)) - rid, err := svc.UpsertAssetWithoutLineage(ctx, ns, tc.Asset) - if tc.Err != nil { - assert.EqualError(t, err, tc.Err.Error()) - return - } - assert.NoError(t, err) - assert.Equal(t, tc.ReturnedID, rid) - }) - } -} - -func TestService_DeleteAsset(t *testing.T) { - assetID := "d9351e2e-a6b2-4c5d-af68-b95432e30203" - urn := "my-test-urn" - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - type testCase struct { - Description string - ID string - Err error - Setup func(context.Context, *mocks.AssetRepository, *mocks.DiscoveryRepository, *mocks.LineageRepository) - } - - var testCases = []testCase{ - { - Description: `with ID, should return error if asset repository getAsset return error`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().GetByID(ctx, assetID).Return(asset.Asset{}, errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - }, - { - Description: `with ID, should return error if asset repository delete return error`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().GetByID(ctx, assetID).Return(asset.Asset{URN: urn}, nil) - ar.EXPECT().DeleteByID(ctx, assetID).Return(errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - }, - { - Description: `with ID, should return error if discovery repository delete return error`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().GetByID(ctx, assetID).Return(asset.Asset{URN: urn}, nil) - ar.EXPECT().DeleteByID(ctx, assetID).Return(nil) - dr.EXPECT().DeleteByID(ctx, ns, assetID).Return(errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - }, - { - Description: `with ID, should return error if lineage repository delete return error`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().GetByID(ctx, assetID).Return(asset.Asset{URN: urn}, nil) - ar.EXPECT().DeleteByID(ctx, assetID).Return(nil) - dr.EXPECT().DeleteByID(ctx, ns, assetID).Return(nil) - lr.EXPECT().DeleteByURN(ctx, urn).Return(errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - }, - { - Description: `with URN, should return error if asset repository delete return error`, - ID: urn, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().DeleteByURN(ctx, urn).Return(errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - }, - { - Description: `with URN, should return error if discovery repository delete return error`, - ID: urn, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().DeleteByURN(ctx, urn).Return(nil) - dr.EXPECT().DeleteByURN(ctx, ns, urn).Return(errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - }, - { - Description: `with URN, should return error if lineage repository delete return error`, - ID: urn, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().DeleteByURN(ctx, urn).Return(nil) - dr.EXPECT().DeleteByURN(ctx, ns, urn).Return(nil) - lr.EXPECT().DeleteByURN(ctx, urn).Return(errors.New("unknown error")) - }, - Err: errors.New("unknown error"), - }, - { - Description: `should call DeleteByID on repositories when given a UUID`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().GetByID(ctx, assetID).Return(asset.Asset{URN: urn}, nil) - ar.EXPECT().DeleteByID(ctx, assetID).Return(nil) - dr.EXPECT().DeleteByID(ctx, ns, assetID).Return(nil) - lr.EXPECT().DeleteByURN(ctx, urn).Return(nil) - }, - Err: nil, - }, - { - Description: `should call DeleteByURN on repositories when not given a UUID`, - ID: urn, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - ar.EXPECT().DeleteByURN(ctx, urn).Return(nil) - dr.EXPECT().DeleteByURN(ctx, ns, urn).Return(nil) - lr.EXPECT().DeleteByURN(ctx, urn).Return(nil) - }, - Err: nil, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := context.Background() - - mockAssetRepo := mocks.NewAssetRepository(t) - mockDiscoveryRepo := mocks.NewDiscoveryRepository(t) - mockLineageRepo := mocks.NewLineageRepository(t) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetRepo, mockDiscoveryRepo, mockLineageRepo) - } - - svc := asset.NewService(mockAssetRepo, mockDiscoveryRepo, mockLineageRepo) - err := svc.DeleteAsset(ctx, ns, tc.ID) - if err != nil && errors.Is(tc.Err, err) { - t.Fatalf("got error %v, expected error was %v", err, tc.Err) - } - }) - } -} - -func TestService_GetAssetByID(t *testing.T) { - assetID := "f742aa61-1100-445c-8d72-355a42e2fb59" - urn := "my-test-urn" - now := time.Now().UTC() - type testCase struct { - Description string - ID string - Expected *asset.Asset - ExpectedErr error - Setup func(context.Context, *mocks.AssetRepository) - } - - ast := asset.Asset{ - ID: assetID, - } - - var testCases = []testCase{ - { - Description: `should return error if the repository return error without id`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetByID(ctx, assetID).Return(asset.Asset{}, asset.NotFoundError{}) - }, - ExpectedErr: asset.NotFoundError{}, - }, - { - Description: `should return error if the repository return error, with id`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetByID(ctx, assetID).Return(asset.Asset{}, asset.NotFoundError{AssetID: ast.ID}) - }, - ExpectedErr: asset.NotFoundError{AssetID: ast.ID}, - }, - { - Description: `should return error if the repository return error, with invalid id`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetByID(ctx, assetID).Return(asset.Asset{}, asset.InvalidError{AssetID: ast.ID}) - }, - ExpectedErr: asset.InvalidError{AssetID: ast.ID}, - }, - { - Description: `with URN, should return error from repository`, - ID: urn, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetByURN(ctx, urn).Return(asset.Asset{}, errors.New("the world exploded")) - }, - ExpectedErr: errors.New("the world exploded"), - }, - { - Description: `with ID, should return no error if asset is found`, - ID: assetID, - Expected: &asset.Asset{ - ID: assetID, - URN: urn, - CreatedAt: now, - Probes: []asset.Probe{ - {ID: "probe-1", AssetURN: urn, Status: "RUNNING", Timestamp: now}, - {ID: "probe-2", AssetURN: urn, Status: "FAILED", Timestamp: now.Add(2 * time.Hour)}, - }, - }, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetByID(ctx, assetID).Return(asset.Asset{ - ID: assetID, - URN: urn, - CreatedAt: now, - }, nil) - ar.EXPECT().GetProbes(ctx, urn).Return([]asset.Probe{ - {ID: "probe-1", AssetURN: urn, Status: "RUNNING", Timestamp: now}, - {ID: "probe-2", AssetURN: urn, Status: "FAILED", Timestamp: now.Add(2 * time.Hour)}, - }, nil) - }, - ExpectedErr: nil, - }, - { - Description: `with URN, should return no error if asset is found`, - ID: urn, - Expected: &asset.Asset{ - ID: assetID, - URN: urn, - CreatedAt: now, - Probes: []asset.Probe{ - {ID: "probe-1", AssetURN: urn, Status: "RUNNING", Timestamp: now}, - {ID: "probe-2", AssetURN: urn, Status: "FAILED", Timestamp: now.Add(2 * time.Hour)}, - }, - }, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetByURN(ctx, urn).Return(asset.Asset{ - ID: assetID, - URN: urn, - CreatedAt: now, - }, nil) - ar.EXPECT().GetProbes(ctx, urn).Return([]asset.Probe{ - {ID: "probe-1", AssetURN: urn, Status: "RUNNING", Timestamp: now}, - {ID: "probe-2", AssetURN: urn, Status: "FAILED", Timestamp: now.Add(2 * time.Hour)}, - }, nil) - }, - ExpectedErr: nil, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := context.Background() - - mockAssetRepo := mocks.NewAssetRepository(t) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetRepo) - } - - svc := asset.NewService(mockAssetRepo, mocks.NewDiscoveryRepository(t), mocks.NewLineageRepository(t)) - actual, err := svc.GetAssetByID(ctx, tc.ID) - if tc.Expected != nil { - assert.Equal(t, *tc.Expected, actual) - } - if tc.ExpectedErr != nil { - assert.ErrorContains(t, err, tc.ExpectedErr.Error()) - assert.ErrorAs(t, err, &tc.ExpectedErr) - } - }) - } -} - -func TestService_GetAssetByVersion(t *testing.T) { - assetID := "f742aa61-1100-445c-8d72-355a42e2fb59" - urn := "my-test-urn" - type testCase struct { - Description string - ID string - ExpectedErr error - Setup func(context.Context, *mocks.AssetRepository) - } - - var testCases = []testCase{ - { - Description: `should return error if the GetByVersionWithID function return error`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetByVersionWithID(ctx, assetID, "v0.0.2"). - Return(asset.Asset{}, errors.New("error fetching asset")) - }, - ExpectedErr: errors.New("error fetching asset"), - }, - { - Description: `should return error if the GetByVersionWithURN function return error`, - ID: urn, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetByVersionWithURN(ctx, urn, "v0.0.2"). - Return(asset.Asset{}, errors.New("error fetching asset")) - }, - ExpectedErr: errors.New("error fetching asset"), - }, - { - Description: `should return no error if asset is found with ID`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetByVersionWithID(ctx, assetID, "v0.0.2").Return(asset.Asset{}, nil) - }, - ExpectedErr: nil, - }, - { - Description: `should return no error if asset is found with URN`, - ID: urn, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetByVersionWithURN(ctx, urn, "v0.0.2").Return(asset.Asset{}, nil) - }, - ExpectedErr: nil, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := context.Background() - - mockAssetRepo := mocks.NewAssetRepository(t) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetRepo) - } - - svc := asset.NewService(mockAssetRepo, mocks.NewDiscoveryRepository(t), mocks.NewLineageRepository(t)) - _, err := svc.GetAssetByVersion(ctx, tc.ID, "v0.0.2") - if tc.ExpectedErr != nil { - assert.EqualError(t, err, tc.ExpectedErr.Error()) - } - }) - } -} - -func TestService_GetAssetVersionHistory(t *testing.T) { - assetID := "some-id" - type testCase struct { - Description string - ID string - Err error - Setup func(context.Context, *mocks.AssetRepository) - } - - ast := []asset.Asset{} - var testCases = []testCase{ - { - Description: `should return error if the GetVersionHistory function return error`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetVersionHistory(ctx, asset.Filter{}, assetID).Return(ast, errors.New("error fetching asset")) - }, - Err: errors.New("error fetching asset"), - }, - { - Description: `should return no error if asset is found by the version`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository) { - ar.EXPECT().GetVersionHistory(ctx, asset.Filter{}, assetID).Return(ast, nil) - }, - Err: nil, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := context.Background() - - mockAssetRepo := mocks.NewAssetRepository(t) - mockDiscoveryRepo := mocks.NewDiscoveryRepository(t) - mockLineageRepo := mocks.NewLineageRepository(t) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetRepo) - } - - svc := asset.NewService(mockAssetRepo, mockDiscoveryRepo, mockLineageRepo) - _, err := svc.GetAssetVersionHistory(ctx, asset.Filter{}, tc.ID) - if err != nil && errors.Is(tc.Err, err) { - t.Fatalf("got error %v, expected error was %v", err, tc.Err) - } - }) - } -} - -func TestService_GetLineage(t *testing.T) { - assetID := "some-id" - type testCase struct { - Description string - ID string - Setup func(context.Context, *mocks.AssetRepository, *mocks.DiscoveryRepository, *mocks.LineageRepository) - Expected asset.Lineage - Err error - } - - var testCases = []testCase{ - { - Description: `should return error if the GetGraph function return error`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - lr.EXPECT().GetGraph(ctx, "urn-source-1", asset.LineageQuery{WithAttributes: true}). - Return(asset.LineageGraph{}, errors.New("error fetching graph")) - }, - Expected: asset.Lineage{}, - Err: errors.New("error fetching graph"), - }, - { - Description: `should return no error if graph with 0 edges are returned`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - lr.EXPECT().GetGraph(ctx, "urn-source-1", asset.LineageQuery{WithAttributes: true}). - Return(asset.LineageGraph{}, nil) - ar.EXPECT().GetProbesWithFilter(ctx, asset.ProbesFilter{ - AssetURNs: []string{"urn-source-1"}, - MaxRows: 1, - }).Return(nil, nil) - }, - Expected: asset.Lineage{Edges: []asset.LineageEdge{}, NodeAttrs: map[string]asset.NodeAttributes{}}, - Err: nil, - }, - { - Description: `should return an error if GetProbesWithFilter function returns error`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - lr.EXPECT().GetGraph(ctx, "urn-source-1", asset.LineageQuery{WithAttributes: true}).Return(asset.LineageGraph{ - {Source: "urn-source-1", Target: "urn-target-1", Prop: nil}, - {Source: "urn-source-1", Target: "urn-target-2", Prop: nil}, - {Source: "urn-target-2", Target: "urn-target-3", Prop: nil}, - }, nil) - ar.EXPECT().GetProbesWithFilter(ctx, asset.ProbesFilter{ - AssetURNs: []string{"urn-source-1", "urn-target-1", "urn-target-2", "urn-target-3"}, - MaxRows: 1, - }).Return(nil, errors.New("error fetching probes")) - }, - Expected: asset.Lineage{}, - Err: errors.New("error fetching probes"), - }, - { - Description: `should return no error if GetProbesWithFilter function returns 0 probes`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - lr.EXPECT().GetGraph(ctx, "urn-source-1", asset.LineageQuery{WithAttributes: true}).Return(asset.LineageGraph{ - {Source: "urn-source-1", Target: "urn-target-1", Prop: nil}, - {Source: "urn-source-1", Target: "urn-target-2", Prop: nil}, - {Source: "urn-target-2", Target: "urn-target-3", Prop: nil}, - }, nil) - ar.EXPECT().GetProbesWithFilter(ctx, asset.ProbesFilter{ - AssetURNs: []string{"urn-source-1", "urn-target-1", "urn-target-2", "urn-target-3"}, - MaxRows: 1, - }).Return(nil, nil) - }, - Expected: asset.Lineage{ - Edges: []asset.LineageEdge{ - {Source: "urn-source-1", Target: "urn-target-1", Prop: nil}, - {Source: "urn-source-1", Target: "urn-target-2", Prop: nil}, - {Source: "urn-target-2", Target: "urn-target-3", Prop: nil}, - }, - NodeAttrs: map[string]asset.NodeAttributes{}, - }, - Err: nil, - }, - { - Description: `should return lineage with edges and node attributes`, - ID: assetID, - Setup: func(ctx context.Context, ar *mocks.AssetRepository, dr *mocks.DiscoveryRepository, lr *mocks.LineageRepository) { - lr.EXPECT().GetGraph(ctx, "urn-source-1", asset.LineageQuery{WithAttributes: true}).Return(asset.LineageGraph{ - {Source: "urn-source-1", Target: "urn-target-1", Prop: nil}, - {Source: "urn-source-1", Target: "urn-target-2", Prop: nil}, - {Source: "urn-target-2", Target: "urn-target-3", Prop: nil}, - }, nil) - ar.EXPECT().GetProbesWithFilter(ctx, asset.ProbesFilter{ - AssetURNs: []string{"urn-source-1", "urn-target-1", "urn-target-2", "urn-target-3"}, - MaxRows: 1, - }).Return( - map[string][]asset.Probe{ - "urn-source-1": { - asset.Probe{Status: "SUCCESS"}, - }, - "urn-target-2": {}, - "urn-target-3": { - asset.Probe{Status: "FAILED"}, - }, - }, - nil, - ) - }, - Expected: asset.Lineage{ - Edges: []asset.LineageEdge{ - {Source: "urn-source-1", Target: "urn-target-1", Prop: nil}, - {Source: "urn-source-1", Target: "urn-target-2", Prop: nil}, - {Source: "urn-target-2", Target: "urn-target-3", Prop: nil}, - }, - NodeAttrs: map[string]asset.NodeAttributes{ - "urn-source-1": { - Probes: asset.ProbesInfo{ - Latest: asset.Probe{Status: "SUCCESS"}, - }, - }, - "urn-target-3": { - Probes: asset.ProbesInfo{ - Latest: asset.Probe{Status: "FAILED"}, - }, - }, - }, - }, - Err: nil, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := context.Background() - - mockAssetRepo := mocks.NewAssetRepository(t) - mockDiscoveryRepo := mocks.NewDiscoveryRepository(t) - mockLineageRepo := mocks.NewLineageRepository(t) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetRepo, mockDiscoveryRepo, mockLineageRepo) - } - - svc := asset.NewService(mockAssetRepo, mockDiscoveryRepo, mockLineageRepo) - actual, err := svc.GetLineage(ctx, "urn-source-1", asset.LineageQuery{WithAttributes: true}) - if tc.Err == nil { - assert.NoError(t, err) - } else { - assert.ErrorContains(t, err, tc.Err.Error()) - } - assert.Equal(t, tc.Expected, actual) - }) - } -} - -func TestService_SearchSuggestAssets(t *testing.T) { - assetID := "some-id" - type testCase struct { - Description string - ID string - ErrSearch error - ErrSuggest error - Setup func(context.Context, *mocks.DiscoveryRepository) - } - - DisErr := asset.DiscoveryError{Err: errors.New("could not find")} - - searchResults := []asset.SearchResult{} - var testCases = []testCase{ - { - Description: `should return error if the GetGraph function return error`, - ID: assetID, - Setup: func(ctx context.Context, dr *mocks.DiscoveryRepository) { - dr.EXPECT().Search(ctx, asset.SearchConfig{}).Return(searchResults, DisErr) - dr.EXPECT().Suggest(ctx, asset.SearchConfig{}).Return([]string{}, DisErr) - }, - ErrSearch: DisErr, - ErrSuggest: DisErr, - }, - { - Description: `should return no error if search and suggest function work`, - ID: assetID, - Setup: func(ctx context.Context, dr *mocks.DiscoveryRepository) { - dr.EXPECT().Search(ctx, asset.SearchConfig{}).Return(searchResults, nil) - dr.EXPECT().Suggest(ctx, asset.SearchConfig{}).Return([]string{}, nil) - }, - ErrSearch: nil, - ErrSuggest: nil, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := context.Background() - - mockAssetRepo := mocks.NewAssetRepository(t) - mockDiscoveryRepo := mocks.NewDiscoveryRepository(t) - mockLineageRepo := mocks.NewLineageRepository(t) - if tc.Setup != nil { - tc.Setup(ctx, mockDiscoveryRepo) - } - - svc := asset.NewService(mockAssetRepo, mockDiscoveryRepo, mockLineageRepo) - _, err := svc.SearchAssets(ctx, asset.SearchConfig{}) - if err != nil && !assert.Equal(t, tc.ErrSearch, err) { - t.Fatalf("got error %v, expected error was %v", err, tc.ErrSearch) - } - _, err = svc.SuggestAssets(ctx, asset.SearchConfig{}) - if err != nil && !assert.Equal(t, tc.ErrSuggest.Error(), err.Error()) { - t.Fatalf("got error %v, expected error was %v", err, tc.ErrSuggest) - } - }) - } -} - -func TestService_CreateAssetProbe(t *testing.T) { - var ( - ctx = context.Background() - assetURN = "sample-urn" - probe = asset.Probe{ - Status: "RUNNING", - } - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - - t.Run("should return no error on success", func(t *testing.T) { - mockAssetRepo := mocks.NewAssetRepository(t) - mockAssetRepo.EXPECT().AddProbe(ctx, ns, assetURN, &probe).Return(nil) - - svc := asset.NewService(mockAssetRepo, nil, nil) - err := svc.AddProbe(ctx, ns, assetURN, &probe) - assert.NoError(t, err) - }) - - t.Run("should return error on failed", func(t *testing.T) { - expectedErr := errors.New("test error") - - mockAssetRepo := mocks.NewAssetRepository(t) - mockAssetRepo.EXPECT().AddProbe(ctx, ns, assetURN, &probe).Return(expectedErr) - - svc := asset.NewService(mockAssetRepo, nil, nil) - err := svc.AddProbe(ctx, ns, assetURN, &probe) - assert.Equal(t, expectedErr, err) - }) -} diff --git a/core/asset/type.go b/core/asset/type.go deleted file mode 100644 index 959e0757..00000000 --- a/core/asset/type.go +++ /dev/null @@ -1,47 +0,0 @@ -package asset - -const ( - TypeTable Type = "table" - TypeJob Type = "job" - TypeDashboard Type = "dashboard" - TypeTopic Type = "topic" - TypeFeatureTable Type = "feature_table" - TypeApplication Type = "application" - TypeModel Type = "model" - TypeQuery Type = "query" - TypeMetric Type = "metric" - TypeExperiment Type = "experiment" -) - -// AllSupportedTypes holds a list of all supported types struct -var AllSupportedTypes = []Type{ - TypeTable, - TypeJob, - TypeDashboard, - TypeTopic, - TypeFeatureTable, - TypeApplication, - TypeModel, - TypeQuery, - TypeMetric, - TypeExperiment, -} - -// Type specifies a supported type name -type Type string - -// String cast Type to string -func (t Type) String() string { - return string(t) -} - -// IsValid will validate whether the typename is valid or not -func (t Type) IsValid() bool { - switch t { - case TypeTable, TypeJob, TypeDashboard, TypeTopic, - TypeFeatureTable, TypeApplication, TypeModel, - TypeQuery, TypeMetric, TypeExperiment: - return true - } - return false -} diff --git a/core/asset/type_test.go b/core/asset/type_test.go deleted file mode 100644 index 751637fb..00000000 --- a/core/asset/type_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package asset - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestTypeString(t *testing.T) { - for typ, expected := range map[Type]string{ - TypeDashboard: "dashboard", - TypeJob: "job", - TypeTable: "table", - TypeTopic: "topic", - TypeFeatureTable: "feature_table", - TypeApplication: "application", - TypeModel: "model", - } { - t.Run((string)(typ), func(t *testing.T) { - assert.Equal(t, expected, typ.String()) - }) - } -} - -func TestTypeIsValid(t *testing.T) { - for _, typ := range []Type{ - "dashboard", "job", "table", "topic", "feature_table", "application", "model", - } { - t.Run((string)(typ), func(t *testing.T) { - assert.Truef(t, typ.IsValid(), "%s should be valid", typ) - }) - } - - if typ := Type("random"); typ.IsValid() { - t.Fatalf("type %s should not be valid", typ) - } -} diff --git a/core/asset/unique_strings.go b/core/asset/unique_strings.go deleted file mode 100644 index 4ba49cb3..00000000 --- a/core/asset/unique_strings.go +++ /dev/null @@ -1,28 +0,0 @@ -package asset - -type uniqueStrings struct { - m map[string]struct{} - l []string -} - -func newUniqueStrings(cap int) uniqueStrings { - return uniqueStrings{ - m: make(map[string]struct{}, cap), - l: make([]string, 0, cap), - } -} - -func (u *uniqueStrings) add(ss ...string) { - for _, s := range ss { - if _, ok := u.m[s]; ok { - continue - } - - u.m[s] = struct{}{} - u.l = append(u.l, s) - } -} - -func (u *uniqueStrings) list() []string { - return u.l -} diff --git a/core/asset/version.go b/core/asset/version.go deleted file mode 100644 index 60a8c3e1..00000000 --- a/core/asset/version.go +++ /dev/null @@ -1,28 +0,0 @@ -package asset - -import ( - "fmt" - - "github.com/Masterminds/semver/v3" -) - -const BaseVersion = "0.1" - -// ParseVersion returns error if version string is not in MAJOR.MINOR format -func ParseVersion(v string) (*semver.Version, error) { - semverVersion, err := semver.NewVersion(v) - if err != nil { - return nil, fmt.Errorf("invalid version \"%s\"", v) - } - return semverVersion, nil -} - -// IncreaseMinorVersion bumps up the minor version +0.1 -func IncreaseMinorVersion(v string) (string, error) { - oldVersion, err := ParseVersion(v) - if err != nil { - return "", err - } - newVersion := oldVersion.IncMinor() - return fmt.Sprintf("%d.%d", newVersion.Major(), newVersion.Minor()), nil -} diff --git a/core/asset/version_test.go b/core/asset/version_test.go deleted file mode 100644 index 4ba35e27..00000000 --- a/core/asset/version_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package asset - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestParseVersionSemver(t *testing.T) { - t.Run("parse invalid version will return non nil error", func(t *testing.T) { - v := "xx" - sv, err := ParseVersion(v) - assert.Error(t, err) - assert.Nil(t, sv) - }) - - t.Run("parse valid version will return nil error", func(t *testing.T) { - v := "1.0" - sv, err := ParseVersion(v) - assert.Nil(t, err) - assert.Equal(t, sv.Major(), uint64(1)) - assert.Equal(t, sv.Minor(), uint64(0)) - }) - - t.Run("parse valid version with prefix 'v' will return nil error", func(t *testing.T) { - v := "v1.0" - sv, err := ParseVersion(v) - assert.Nil(t, err) - assert.Equal(t, sv.Major(), uint64(1)) - assert.Equal(t, sv.Minor(), uint64(0)) - }) -} - -func TestIncreaseMinorVersion(t *testing.T) { - t.Run("increase minor version of invalid version will return non nil error", func(t *testing.T) { - v := "xx" - sv, err := IncreaseMinorVersion(v) - assert.Error(t, err) - assert.Empty(t, sv) - }) - - t.Run("increase minor version of valid version will return nil error", func(t *testing.T) { - v := "1.0" - sv, err := IncreaseMinorVersion(v) - assert.Nil(t, err) - assert.Equal(t, "1.1", sv) - }) - - t.Run("increase minor version of valid version with prefix 'v' will return nil error", func(t *testing.T) { - v := "v1.0" - sv, err := IncreaseMinorVersion(v) - assert.Nil(t, err) - assert.Equal(t, "1.1", sv) - }) -} diff --git a/core/discussion/comment.go b/core/discussion/comment.go deleted file mode 100644 index 26ca2129..00000000 --- a/core/discussion/comment.go +++ /dev/null @@ -1,31 +0,0 @@ -package discussion - -import ( - "fmt" - "strings" - "time" - - "github.com/raystack/compass/core/user" -) - -type Comment struct { - ID string `json:"id" db:"id"` - DiscussionID string `json:"discussion_id" db:"discussion_id"` - Body string `json:"body" db:"body"` - Owner user.User `json:"owner" db:"owner"` - UpdatedBy user.User `json:"updated_by" db:"updated_by"` - CreatedAt time.Time `json:"created_at" db:"created_at"` - UpdatedAt time.Time `json:"updated_at" db:"updated_at"` -} - -// Validate checks emptyness required fields and constraint in comment and return error if the required is empty -func (c Comment) Validate() error { - if len(strings.TrimSpace(c.Body)) == 0 { - return fmt.Errorf("body cannot be empty") - } - - if len(strings.TrimSpace(c.DiscussionID)) == 0 { - return fmt.Errorf("discussion_id cannot be empty") - } - return nil -} diff --git a/core/discussion/comment_test.go b/core/discussion/comment_test.go deleted file mode 100644 index ec11058e..00000000 --- a/core/discussion/comment_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package discussion_test - -import ( - "fmt" - "testing" - - "github.com/raystack/compass/core/discussion" - "github.com/stretchr/testify/assert" -) - -func TestValidate(t *testing.T) { - comment := discussion.Comment{} - t.Run("throws error for empty comment body", func(t *testing.T) { - err := comment.Validate() - assert.Equal(t, err, fmt.Errorf("body cannot be empty")) - }) - t.Run("throws error for empty discussion id", func(t *testing.T) { - comment.Body = "compass: sample body for comments" - err := comment.Validate() - assert.Equal(t, err, fmt.Errorf("discussion_id cannot be empty")) - }) - t.Run("throws no error for correct comment", func(t *testing.T) { - comment.Body = "compass: sample body for comments" - comment.DiscussionID = "hit_1" - err := comment.Validate() - assert.NoError(t, err) - }) -} diff --git a/core/discussion/discussion.go b/core/discussion/discussion.go deleted file mode 100644 index 1c2638c0..00000000 --- a/core/discussion/discussion.go +++ /dev/null @@ -1,115 +0,0 @@ -package discussion - -//go:generate mockery --name=Repository -r --case underscore --with-expecter --structname DiscussionRepository --filename discussion_repository.go --output=./mocks - -import ( - "context" - "fmt" - "github.com/raystack/compass/core/namespace" - "strings" - "time" - - "github.com/raystack/compass/core/user" -) - -const MAX_ARRAY_FIELD_NUM = 10 - -type Repository interface { - Create(ctx context.Context, ns *namespace.Namespace, discussion *Discussion) (string, error) - GetAll(ctx context.Context, filter Filter) ([]Discussion, error) - Get(ctx context.Context, did string) (Discussion, error) - Patch(ctx context.Context, discussion *Discussion) error - GetAllComments(ctx context.Context, discussionID string, filter Filter) ([]Comment, error) - CreateComment(ctx context.Context, ns *namespace.Namespace, cmt *Comment) (string, error) - GetComment(ctx context.Context, commentID string, discussionID string) (Comment, error) - UpdateComment(ctx context.Context, cmt *Comment) error - DeleteComment(ctx context.Context, commentID string, discussionID string) error -} - -type Discussion struct { - ID string `json:"id"` - Title string `json:"title"` - Body string `json:"body"` - Type Type `json:"type"` - State State `json:"state"` - Labels []string `json:"labels"` - Assets []string `json:"assets"` - Assignees []string `json:"assignees"` - Owner user.User `json:"owner"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` -} - -// IsEmpty returns true if all fields inside discussion are considered empty -func (d Discussion) IsEmpty() bool { - if len(strings.TrimSpace(d.Title)) > 0 { - return false - } - - if len(strings.TrimSpace(d.Body)) > 0 { - return false - } - - if len(strings.TrimSpace(d.Type.String())) > 0 { - return false - } - - if len(strings.TrimSpace(d.State.String())) > 0 { - return false - } - - if d.Labels != nil { - return false - } - - if d.Assets != nil { - return false - } - - if d.Assignees != nil { - return false - } - - return true -} - -// Validate checks emptiness required fields and constraint in discussion and return error if the required is empty -func (d Discussion) Validate() error { - if len(strings.TrimSpace(d.Title)) == 0 { - return fmt.Errorf("title cannot be empty") - } - - if len(strings.TrimSpace(d.Body)) == 0 { - return fmt.Errorf("body cannot be empty") - } - - if len(strings.TrimSpace(d.Type.String())) == 0 { - return fmt.Errorf("type must be specified") - } - - return d.ValidateConstraint() -} - -// ValidateConstraint checks whether non-empty/nil fields fulfill the contract -func (d Discussion) ValidateConstraint() error { - if len(strings.TrimSpace(d.Type.String())) > 0 && !IsTypeStringValid(d.Type.String()) { - return ErrInvalidType - } - - if len(strings.TrimSpace(d.State.String())) > 0 && !IsStateStringValid(d.State.String()) { - return ErrInvalidState - } - - if len(d.Assignees) > MAX_ARRAY_FIELD_NUM { - return fmt.Errorf("assignees cannot be more than %d", MAX_ARRAY_FIELD_NUM) - } - - if len(d.Assets) > MAX_ARRAY_FIELD_NUM { - return fmt.Errorf("assets cannot be more than %d", MAX_ARRAY_FIELD_NUM) - } - - if len(d.Labels) > MAX_ARRAY_FIELD_NUM { - return fmt.Errorf("labels cannot be more than %d", MAX_ARRAY_FIELD_NUM) - } - return nil -} diff --git a/core/discussion/discussion_test.go b/core/discussion/discussion_test.go deleted file mode 100644 index 035db01a..00000000 --- a/core/discussion/discussion_test.go +++ /dev/null @@ -1,152 +0,0 @@ -package discussion_test - -import ( - "errors" - "testing" - "time" - - "github.com/raystack/compass/core/discussion" - "github.com/stretchr/testify/assert" -) - -func TestIsEmpty(t *testing.T) { - type TestCase struct { - Description string - Discussion discussion.Discussion - IsEmpty bool - } - - var testCases = []TestCase{ - { - Description: "all necessary fields are empty and nil will be considered empty", - Discussion: discussion.Discussion{ID: "123", CreatedAt: time.Now(), UpdatedAt: time.Now()}, - IsEmpty: true, - }, - { - Description: "nil slice will be considered empty", - Discussion: discussion.Discussion{Labels: nil}, - IsEmpty: true, - }, - { - Description: "empty slice won't be considered empty", - Discussion: discussion.Discussion{Labels: []string{}}, - IsEmpty: false, - }, - { - Description: "title exist won't be considered empty", - Discussion: discussion.Discussion{Title: "title"}, - IsEmpty: false, - }, - { - Description: "body exist won't be considered empty", - Discussion: discussion.Discussion{Body: "body"}, - IsEmpty: false, - }, - { - Description: "type exist won't be considered empty", - Discussion: discussion.Discussion{Type: "type"}, - IsEmpty: false, - }, - { - Description: "state exist won't be considered empty", - Discussion: discussion.Discussion{State: "state"}, - IsEmpty: false, - }, - { - Description: "assets exist won't be considered empty", - Discussion: discussion.Discussion{Assets: []string{"asset-1", "asset-2"}}, - IsEmpty: false, - }, - { - Description: "assignees exist won't be considered empty", - Discussion: discussion.Discussion{Assignees: []string{"user-1", "user-2"}}, - IsEmpty: false, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - assert.Equal(t, tc.IsEmpty, tc.Discussion.IsEmpty()) - }) - } -} - -func TestValidateConstraint(t *testing.T) { - type TestCase struct { - Description string - Discussion discussion.Discussion - Err error - } - - var testCases = []TestCase{ - { - Description: "type is not one of supported types will return error", - Discussion: discussion.Discussion{Type: "random"}, - Err: discussion.ErrInvalidType, - }, - { - Description: "state is not one of supported states will return error", - Discussion: discussion.Discussion{State: "random"}, - Err: discussion.ErrInvalidState, - }, - { - Description: "labels is more than MAX will return error", - Discussion: discussion.Discussion{Labels: []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}}, - Err: errors.New("labels cannot be more than 10"), - }, - { - Description: "assets is more than MAX will return error", - Discussion: discussion.Discussion{Assets: []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}}, - Err: errors.New("assets cannot be more than 10"), - }, - { - Description: "assignees is more than MAX will return error", - Discussion: discussion.Discussion{Assignees: []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}}, - Err: errors.New("assignees cannot be more than 10"), - }, - { - Description: "empty fields return nil", - Discussion: discussion.Discussion{}, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - assert.Equal(t, tc.Err, tc.Discussion.ValidateConstraint()) - }) - } -} - -func TestValidateDiscussion(t *testing.T) { - type TestCase struct { - Description string - Discussion discussion.Discussion - Err error - } - - var testCases = []TestCase{ - { - Description: "empty title will return error", - Discussion: discussion.Discussion{}, - Err: errors.New("title cannot be empty"), - }, - { - Description: "empty body will return error", - Discussion: discussion.Discussion{Title: "title"}, - Err: errors.New("body cannot be empty"), - }, - { - Description: "empty type will return error", - Discussion: discussion.Discussion{Title: "title", Body: "body"}, - Err: errors.New("type must be specified"), - }, - { - Description: "invalid value of type will return error", - Discussion: discussion.Discussion{Title: "title", Body: "body", Type: "type"}, - Err: errors.New("discussion type is invalid, supported types are: openended,issues,qanda"), - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - assert.Equal(t, tc.Err, tc.Discussion.Validate()) - }) - } -} diff --git a/core/discussion/errors.go b/core/discussion/errors.go deleted file mode 100644 index 7d434561..00000000 --- a/core/discussion/errors.go +++ /dev/null @@ -1,45 +0,0 @@ -package discussion - -import ( - "errors" - "fmt" - "strings" -) - -var ( - ErrInvalidID = errors.New("invalid discussion ID") - ErrInvalidType = fmt.Errorf("discussion type is invalid, supported types are: %s", strings.Join(SupportedTypes, ",")) - ErrInvalidState = fmt.Errorf("discussion state is invalid, supported states are: %s", strings.Join(SupportedStates, ",")) -) - -type NotFoundError struct { - CommentID string - DiscussionID string -} - -func (e NotFoundError) Error() string { - reasons := []string{} - if e.DiscussionID != "" { - reasons = append(reasons, fmt.Sprintf("with discussion id \"%s\"", e.DiscussionID)) - } - if e.CommentID != "" { - reasons = append(reasons, fmt.Sprintf("with comment id \"%s\"", e.CommentID)) - } - return "resource not found " + strings.Join(reasons, " and ") -} - -type InvalidError struct { - CommentID string - DiscussionID string -} - -func (e InvalidError) Error() string { - reasons := []string{} - if e.DiscussionID != "" { - reasons = append(reasons, fmt.Sprintf("with discussion id \"%s\"", e.DiscussionID)) - } - if e.CommentID != "" { - reasons = append(reasons, fmt.Sprintf("with comment id \"%s\"", e.CommentID)) - } - return "invalid input " + strings.Join(reasons, " and ") -} diff --git a/core/discussion/filter.go b/core/discussion/filter.go deleted file mode 100644 index e43412ce..00000000 --- a/core/discussion/filter.go +++ /dev/null @@ -1,45 +0,0 @@ -package discussion - -import ( - "strings" - - validator "github.com/raystack/compass/core/validator" -) - -type Filter struct { - Type string `json:"type" validate:"omitempty,oneof=openended issues qanda all"` - State string `json:"state" validate:"omitempty,oneof=open closed all"` - Assets []string - Owner string - Assignees []string - Labels []string - SortBy string `json:"sort" validate:"omitempty,oneof=created_at updated_at"` - SortDirection string `json:"direction" validate:"omitempty,oneof=asc desc"` - Size int `json:"size" validate:"omitempty,gte=0"` - Offset int `json:"offset" validate:"omitempty,gte=0"` - DisjointAssigneeOwner bool -} - -// Validate will check whether fields in the filter fulfills the constraint -func (f *Filter) Validate() error { - return validator.ValidateStruct(f) -} - -// AssignDefault will populate default value to filter -func (f *Filter) AssignDefault() { - if len(strings.TrimSpace(f.Type)) == 0 { - f.Type = "all" - } - - if len(strings.TrimSpace(f.State)) == 0 { - f.State = StateOpen.String() - } - - if len(strings.TrimSpace(f.SortBy)) == 0 { - f.SortBy = "created_at" - } - - if len(strings.TrimSpace(f.SortDirection)) == 0 { - f.SortDirection = "desc" - } -} diff --git a/core/discussion/filter_test.go b/core/discussion/filter_test.go deleted file mode 100644 index 3efa6aed..00000000 --- a/core/discussion/filter_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package discussion_test - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/raystack/compass/core/discussion" - "github.com/stretchr/testify/assert" -) - -func TestValidateFilter(t *testing.T) { - type testCase struct { - Description string - Filter *discussion.Filter - errString string - } - - var testCases = []testCase{ - { - Description: "empty filter will be valid", - Filter: &discussion.Filter{}, - }, - { - Description: "invalid type will return error", - Filter: &discussion.Filter{Type: "random"}, - errString: "error value \"random\" for key \"type\" not recognized, only support \"openended issues qanda all\"", - }, - { - Description: "invalid state will return error", - Filter: &discussion.Filter{State: "random"}, - errString: "error value \"random\" for key \"state\" not recognized, only support \"open closed all\"", - }, - { - Description: "invalid sort and direction will return error", - Filter: &discussion.Filter{SortBy: "random", SortDirection: "random"}, - errString: "error value \"random\" for key \"sort\" not recognized, only support \"created_at updated_at\" and error value \"random\" for key \"direction\" not recognized, only support \"asc desc\"", - }, - { - Description: "invalid size and offset will return error", - Filter: &discussion.Filter{Size: -12, Offset: -1}, - errString: "size cannot be less than 0 and offset cannot be less than 0", - }, - } - - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - err := tc.Filter.Validate() - if err != nil { - assert.Equal(t, tc.errString, err.Error()) - } - }) - } -} - -func TestAssignDefault(t *testing.T) { - type testCase struct { - Description string - Filter *discussion.Filter - ExpectedFilter *discussion.Filter - } - - var testCases = []testCase{ - { - Description: "non empty fields in filter won't be changed", - Filter: &discussion.Filter{ - Type: "a-type", - State: discussion.StateClosed.String(), - SortBy: "sort-by", - SortDirection: "sort-direction", - }, - ExpectedFilter: &discussion.Filter{ - Type: "a-type", - State: discussion.StateClosed.String(), - SortBy: "sort-by", - SortDirection: "sort-direction", - }, - }, - { - Description: "empty default fields will set to defaults", - Filter: &discussion.Filter{}, - ExpectedFilter: &discussion.Filter{ - Type: "all", - State: discussion.StateOpen.String(), - SortBy: "created_at", - SortDirection: "desc", - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - tc.Filter.AssignDefault() - if diff := cmp.Diff(tc.Filter, tc.ExpectedFilter); diff != "" { - t.Errorf("expected response to be %+v, was %+v", tc.ExpectedFilter, tc.Filter) - } - }) - } -} diff --git a/core/discussion/mocks/discussion_repository.go b/core/discussion/mocks/discussion_repository.go deleted file mode 100644 index f8f697bc..00000000 --- a/core/discussion/mocks/discussion_repository.go +++ /dev/null @@ -1,496 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - discussion "github.com/raystack/compass/core/discussion" - mock "github.com/stretchr/testify/mock" - - namespace "github.com/raystack/compass/core/namespace" -) - -// DiscussionRepository is an autogenerated mock type for the Repository type -type DiscussionRepository struct { - mock.Mock -} - -type DiscussionRepository_Expecter struct { - mock *mock.Mock -} - -func (_m *DiscussionRepository) EXPECT() *DiscussionRepository_Expecter { - return &DiscussionRepository_Expecter{mock: &_m.Mock} -} - -// Create provides a mock function with given fields: ctx, ns, _a2 -func (_m *DiscussionRepository) Create(ctx context.Context, ns *namespace.Namespace, _a2 *discussion.Discussion) (string, error) { - ret := _m.Called(ctx, ns, _a2) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *discussion.Discussion) (string, error)); ok { - return rf(ctx, ns, _a2) - } - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *discussion.Discussion) string); ok { - r0 = rf(ctx, ns, _a2) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(context.Context, *namespace.Namespace, *discussion.Discussion) error); ok { - r1 = rf(ctx, ns, _a2) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionRepository_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' -type DiscussionRepository_Create_Call struct { - *mock.Call -} - -// Create is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - _a2 *discussion.Discussion -func (_e *DiscussionRepository_Expecter) Create(ctx interface{}, ns interface{}, _a2 interface{}) *DiscussionRepository_Create_Call { - return &DiscussionRepository_Create_Call{Call: _e.mock.On("Create", ctx, ns, _a2)} -} - -func (_c *DiscussionRepository_Create_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, _a2 *discussion.Discussion)) *DiscussionRepository_Create_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*discussion.Discussion)) - }) - return _c -} - -func (_c *DiscussionRepository_Create_Call) Return(_a0 string, _a1 error) *DiscussionRepository_Create_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionRepository_Create_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *discussion.Discussion) (string, error)) *DiscussionRepository_Create_Call { - _c.Call.Return(run) - return _c -} - -// CreateComment provides a mock function with given fields: ctx, ns, cmt -func (_m *DiscussionRepository) CreateComment(ctx context.Context, ns *namespace.Namespace, cmt *discussion.Comment) (string, error) { - ret := _m.Called(ctx, ns, cmt) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *discussion.Comment) (string, error)); ok { - return rf(ctx, ns, cmt) - } - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *discussion.Comment) string); ok { - r0 = rf(ctx, ns, cmt) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(context.Context, *namespace.Namespace, *discussion.Comment) error); ok { - r1 = rf(ctx, ns, cmt) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionRepository_CreateComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateComment' -type DiscussionRepository_CreateComment_Call struct { - *mock.Call -} - -// CreateComment is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - cmt *discussion.Comment -func (_e *DiscussionRepository_Expecter) CreateComment(ctx interface{}, ns interface{}, cmt interface{}) *DiscussionRepository_CreateComment_Call { - return &DiscussionRepository_CreateComment_Call{Call: _e.mock.On("CreateComment", ctx, ns, cmt)} -} - -func (_c *DiscussionRepository_CreateComment_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, cmt *discussion.Comment)) *DiscussionRepository_CreateComment_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*discussion.Comment)) - }) - return _c -} - -func (_c *DiscussionRepository_CreateComment_Call) Return(_a0 string, _a1 error) *DiscussionRepository_CreateComment_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionRepository_CreateComment_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *discussion.Comment) (string, error)) *DiscussionRepository_CreateComment_Call { - _c.Call.Return(run) - return _c -} - -// DeleteComment provides a mock function with given fields: ctx, commentID, discussionID -func (_m *DiscussionRepository) DeleteComment(ctx context.Context, commentID string, discussionID string) error { - ret := _m.Called(ctx, commentID, discussionID) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { - r0 = rf(ctx, commentID, discussionID) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DiscussionRepository_DeleteComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteComment' -type DiscussionRepository_DeleteComment_Call struct { - *mock.Call -} - -// DeleteComment is a helper method to define mock.On call -// - ctx context.Context -// - commentID string -// - discussionID string -func (_e *DiscussionRepository_Expecter) DeleteComment(ctx interface{}, commentID interface{}, discussionID interface{}) *DiscussionRepository_DeleteComment_Call { - return &DiscussionRepository_DeleteComment_Call{Call: _e.mock.On("DeleteComment", ctx, commentID, discussionID)} -} - -func (_c *DiscussionRepository_DeleteComment_Call) Run(run func(ctx context.Context, commentID string, discussionID string)) *DiscussionRepository_DeleteComment_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) - }) - return _c -} - -func (_c *DiscussionRepository_DeleteComment_Call) Return(_a0 error) *DiscussionRepository_DeleteComment_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *DiscussionRepository_DeleteComment_Call) RunAndReturn(run func(context.Context, string, string) error) *DiscussionRepository_DeleteComment_Call { - _c.Call.Return(run) - return _c -} - -// Get provides a mock function with given fields: ctx, did -func (_m *DiscussionRepository) Get(ctx context.Context, did string) (discussion.Discussion, error) { - ret := _m.Called(ctx, did) - - var r0 discussion.Discussion - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (discussion.Discussion, error)); ok { - return rf(ctx, did) - } - if rf, ok := ret.Get(0).(func(context.Context, string) discussion.Discussion); ok { - r0 = rf(ctx, did) - } else { - r0 = ret.Get(0).(discussion.Discussion) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, did) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionRepository_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' -type DiscussionRepository_Get_Call struct { - *mock.Call -} - -// Get is a helper method to define mock.On call -// - ctx context.Context -// - did string -func (_e *DiscussionRepository_Expecter) Get(ctx interface{}, did interface{}) *DiscussionRepository_Get_Call { - return &DiscussionRepository_Get_Call{Call: _e.mock.On("Get", ctx, did)} -} - -func (_c *DiscussionRepository_Get_Call) Run(run func(ctx context.Context, did string)) *DiscussionRepository_Get_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *DiscussionRepository_Get_Call) Return(_a0 discussion.Discussion, _a1 error) *DiscussionRepository_Get_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionRepository_Get_Call) RunAndReturn(run func(context.Context, string) (discussion.Discussion, error)) *DiscussionRepository_Get_Call { - _c.Call.Return(run) - return _c -} - -// GetAll provides a mock function with given fields: ctx, filter -func (_m *DiscussionRepository) GetAll(ctx context.Context, filter discussion.Filter) ([]discussion.Discussion, error) { - ret := _m.Called(ctx, filter) - - var r0 []discussion.Discussion - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, discussion.Filter) ([]discussion.Discussion, error)); ok { - return rf(ctx, filter) - } - if rf, ok := ret.Get(0).(func(context.Context, discussion.Filter) []discussion.Discussion); ok { - r0 = rf(ctx, filter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]discussion.Discussion) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, discussion.Filter) error); ok { - r1 = rf(ctx, filter) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionRepository_GetAll_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAll' -type DiscussionRepository_GetAll_Call struct { - *mock.Call -} - -// GetAll is a helper method to define mock.On call -// - ctx context.Context -// - filter discussion.Filter -func (_e *DiscussionRepository_Expecter) GetAll(ctx interface{}, filter interface{}) *DiscussionRepository_GetAll_Call { - return &DiscussionRepository_GetAll_Call{Call: _e.mock.On("GetAll", ctx, filter)} -} - -func (_c *DiscussionRepository_GetAll_Call) Run(run func(ctx context.Context, filter discussion.Filter)) *DiscussionRepository_GetAll_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(discussion.Filter)) - }) - return _c -} - -func (_c *DiscussionRepository_GetAll_Call) Return(_a0 []discussion.Discussion, _a1 error) *DiscussionRepository_GetAll_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionRepository_GetAll_Call) RunAndReturn(run func(context.Context, discussion.Filter) ([]discussion.Discussion, error)) *DiscussionRepository_GetAll_Call { - _c.Call.Return(run) - return _c -} - -// GetAllComments provides a mock function with given fields: ctx, discussionID, filter -func (_m *DiscussionRepository) GetAllComments(ctx context.Context, discussionID string, filter discussion.Filter) ([]discussion.Comment, error) { - ret := _m.Called(ctx, discussionID, filter) - - var r0 []discussion.Comment - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, discussion.Filter) ([]discussion.Comment, error)); ok { - return rf(ctx, discussionID, filter) - } - if rf, ok := ret.Get(0).(func(context.Context, string, discussion.Filter) []discussion.Comment); ok { - r0 = rf(ctx, discussionID, filter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]discussion.Comment) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string, discussion.Filter) error); ok { - r1 = rf(ctx, discussionID, filter) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionRepository_GetAllComments_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllComments' -type DiscussionRepository_GetAllComments_Call struct { - *mock.Call -} - -// GetAllComments is a helper method to define mock.On call -// - ctx context.Context -// - discussionID string -// - filter discussion.Filter -func (_e *DiscussionRepository_Expecter) GetAllComments(ctx interface{}, discussionID interface{}, filter interface{}) *DiscussionRepository_GetAllComments_Call { - return &DiscussionRepository_GetAllComments_Call{Call: _e.mock.On("GetAllComments", ctx, discussionID, filter)} -} - -func (_c *DiscussionRepository_GetAllComments_Call) Run(run func(ctx context.Context, discussionID string, filter discussion.Filter)) *DiscussionRepository_GetAllComments_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(discussion.Filter)) - }) - return _c -} - -func (_c *DiscussionRepository_GetAllComments_Call) Return(_a0 []discussion.Comment, _a1 error) *DiscussionRepository_GetAllComments_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionRepository_GetAllComments_Call) RunAndReturn(run func(context.Context, string, discussion.Filter) ([]discussion.Comment, error)) *DiscussionRepository_GetAllComments_Call { - _c.Call.Return(run) - return _c -} - -// GetComment provides a mock function with given fields: ctx, commentID, discussionID -func (_m *DiscussionRepository) GetComment(ctx context.Context, commentID string, discussionID string) (discussion.Comment, error) { - ret := _m.Called(ctx, commentID, discussionID) - - var r0 discussion.Comment - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (discussion.Comment, error)); ok { - return rf(ctx, commentID, discussionID) - } - if rf, ok := ret.Get(0).(func(context.Context, string, string) discussion.Comment); ok { - r0 = rf(ctx, commentID, discussionID) - } else { - r0 = ret.Get(0).(discussion.Comment) - } - - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, commentID, discussionID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionRepository_GetComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetComment' -type DiscussionRepository_GetComment_Call struct { - *mock.Call -} - -// GetComment is a helper method to define mock.On call -// - ctx context.Context -// - commentID string -// - discussionID string -func (_e *DiscussionRepository_Expecter) GetComment(ctx interface{}, commentID interface{}, discussionID interface{}) *DiscussionRepository_GetComment_Call { - return &DiscussionRepository_GetComment_Call{Call: _e.mock.On("GetComment", ctx, commentID, discussionID)} -} - -func (_c *DiscussionRepository_GetComment_Call) Run(run func(ctx context.Context, commentID string, discussionID string)) *DiscussionRepository_GetComment_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) - }) - return _c -} - -func (_c *DiscussionRepository_GetComment_Call) Return(_a0 discussion.Comment, _a1 error) *DiscussionRepository_GetComment_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionRepository_GetComment_Call) RunAndReturn(run func(context.Context, string, string) (discussion.Comment, error)) *DiscussionRepository_GetComment_Call { - _c.Call.Return(run) - return _c -} - -// Patch provides a mock function with given fields: ctx, _a1 -func (_m *DiscussionRepository) Patch(ctx context.Context, _a1 *discussion.Discussion) error { - ret := _m.Called(ctx, _a1) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *discussion.Discussion) error); ok { - r0 = rf(ctx, _a1) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DiscussionRepository_Patch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Patch' -type DiscussionRepository_Patch_Call struct { - *mock.Call -} - -// Patch is a helper method to define mock.On call -// - ctx context.Context -// - _a1 *discussion.Discussion -func (_e *DiscussionRepository_Expecter) Patch(ctx interface{}, _a1 interface{}) *DiscussionRepository_Patch_Call { - return &DiscussionRepository_Patch_Call{Call: _e.mock.On("Patch", ctx, _a1)} -} - -func (_c *DiscussionRepository_Patch_Call) Run(run func(ctx context.Context, _a1 *discussion.Discussion)) *DiscussionRepository_Patch_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*discussion.Discussion)) - }) - return _c -} - -func (_c *DiscussionRepository_Patch_Call) Return(_a0 error) *DiscussionRepository_Patch_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *DiscussionRepository_Patch_Call) RunAndReturn(run func(context.Context, *discussion.Discussion) error) *DiscussionRepository_Patch_Call { - _c.Call.Return(run) - return _c -} - -// UpdateComment provides a mock function with given fields: ctx, cmt -func (_m *DiscussionRepository) UpdateComment(ctx context.Context, cmt *discussion.Comment) error { - ret := _m.Called(ctx, cmt) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *discussion.Comment) error); ok { - r0 = rf(ctx, cmt) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DiscussionRepository_UpdateComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateComment' -type DiscussionRepository_UpdateComment_Call struct { - *mock.Call -} - -// UpdateComment is a helper method to define mock.On call -// - ctx context.Context -// - cmt *discussion.Comment -func (_e *DiscussionRepository_Expecter) UpdateComment(ctx interface{}, cmt interface{}) *DiscussionRepository_UpdateComment_Call { - return &DiscussionRepository_UpdateComment_Call{Call: _e.mock.On("UpdateComment", ctx, cmt)} -} - -func (_c *DiscussionRepository_UpdateComment_Call) Run(run func(ctx context.Context, cmt *discussion.Comment)) *DiscussionRepository_UpdateComment_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*discussion.Comment)) - }) - return _c -} - -func (_c *DiscussionRepository_UpdateComment_Call) Return(_a0 error) *DiscussionRepository_UpdateComment_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *DiscussionRepository_UpdateComment_Call) RunAndReturn(run func(context.Context, *discussion.Comment) error) *DiscussionRepository_UpdateComment_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTNewDiscussionRepository interface { - mock.TestingT - Cleanup(func()) -} - -// NewDiscussionRepository creates a new instance of DiscussionRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewDiscussionRepository(t mockConstructorTestingTNewDiscussionRepository) *DiscussionRepository { - mock := &DiscussionRepository{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/discussion/service.go b/core/discussion/service.go deleted file mode 100644 index dd6e804d..00000000 --- a/core/discussion/service.go +++ /dev/null @@ -1,44 +0,0 @@ -package discussion - -import ( - "context" - "github.com/raystack/compass/core/namespace" -) - -func NewService(discussionRepository Repository) *Service { - return &Service{ - discussionRepository: discussionRepository, - } -} - -type Service struct { - discussionRepository Repository -} - -func (s *Service) GetDiscussions(ctx context.Context, filter Filter) ([]Discussion, error) { - return s.discussionRepository.GetAll(ctx, filter) -} -func (s *Service) CreateDiscussion(ctx context.Context, ns *namespace.Namespace, dsc *Discussion) (string, error) { - return s.discussionRepository.Create(ctx, ns, dsc) -} -func (s *Service) GetDiscussion(ctx context.Context, did string) (Discussion, error) { - return s.discussionRepository.Get(ctx, did) -} -func (s *Service) PatchDiscussion(ctx context.Context, dsc *Discussion) error { - return s.discussionRepository.Patch(ctx, dsc) -} -func (s *Service) GetComments(ctx context.Context, discussionID string, filter Filter) ([]Comment, error) { - return s.discussionRepository.GetAllComments(ctx, discussionID, filter) -} -func (s *Service) CreateComment(ctx context.Context, ns *namespace.Namespace, cmt *Comment) (string, error) { - return s.discussionRepository.CreateComment(ctx, ns, cmt) -} -func (s *Service) GetComment(ctx context.Context, commentID string, discussionID string) (Comment, error) { - return s.discussionRepository.GetComment(ctx, commentID, discussionID) -} -func (s *Service) UpdateComment(ctx context.Context, cmt *Comment) error { - return s.discussionRepository.UpdateComment(ctx, cmt) -} -func (s *Service) DeleteComment(ctx context.Context, commentID string, discussionID string) error { - return s.discussionRepository.DeleteComment(ctx, commentID, discussionID) -} diff --git a/core/discussion/service_test.go b/core/discussion/service_test.go deleted file mode 100644 index 31f6bcb0..00000000 --- a/core/discussion/service_test.go +++ /dev/null @@ -1,457 +0,0 @@ -package discussion_test - -import ( - "context" - "errors" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "testing" - - "github.com/raystack/compass/core/discussion" - "github.com/raystack/compass/core/discussion/mocks" - "github.com/stretchr/testify/assert" -) - -func TestGetDiscussions(t *testing.T) { - ctx := context.Background() - testcase := []struct { - Description string - Setup func(context.Context, *mocks.DiscussionRepository) - Err string - Filter discussion.Filter - Discussion []discussion.Discussion - }{ - { - Description: "should catch not found error", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().GetAll(ctx, discussion.Filter{}).Return([]discussion.Discussion{}, discussion.NotFoundError{}) - }, - Err: discussion.NotFoundError{}.Error(), - Discussion: []discussion.Discussion{}, - Filter: discussion.Filter{}, - }, - { - Description: "should catch invalid error for invalid state", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().GetAll(ctx, discussion.Filter{Type: "random"}).Return([]discussion.Discussion{}, discussion.InvalidError{}) - }, - Err: discussion.InvalidError{}.Error(), - Discussion: []discussion.Discussion{}, - Filter: discussion.Filter{Type: "random"}, - }, - { - Description: "should return all discussions for correct request", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().GetAll(ctx, discussion.Filter{}).Return([]discussion.Discussion{{ID: "1", Title: "title", Body: "body"}}, nil) - }, - Filter: discussion.Filter{}, - Discussion: []discussion.Discussion{ - {ID: "1", Title: "title", Body: "body"}, - }, - }, - } - - for _, tc := range testcase { - t.Run(tc.Description, func(t *testing.T) { - mockDiscussionRepo := new(mocks.DiscussionRepository) - if tc.Setup != nil { - tc.Setup(ctx, mockDiscussionRepo) - } - defer mockDiscussionRepo.AssertExpectations(t) - - svc := discussion.NewService(mockDiscussionRepo) - discussions, err := svc.GetDiscussions(ctx, tc.Filter) - if err != nil { - assert.Equal(t, tc.Err, err.Error()) - } - assert.Equal(t, tc.Discussion, discussions) - }) - } -} - -func TestGetDiscussion(t *testing.T) { - ctx := context.Background() - testcase := []struct { - Description string - Setup func(context.Context, *mocks.DiscussionRepository) - Err string - did string - Discussion discussion.Discussion - }{ - { - Description: "should catch not found error", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().Get(ctx, "id-1").Return(discussion.Discussion{}, discussion.NotFoundError{DiscussionID: "id-1"}) - }, - Err: discussion.NotFoundError{DiscussionID: "id-1"}.Error(), - Discussion: discussion.Discussion{}, - did: "id-1", - }, - { - Description: "should catch invalid error for invalid state", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().Get(ctx, "invalid-id").Return(discussion.Discussion{}, discussion.InvalidError{DiscussionID: "invalid-id"}) - }, - Err: discussion.InvalidError{DiscussionID: "invalid-id"}.Error(), - Discussion: discussion.Discussion{}, - did: "invalid-id", - }, - { - Description: "should return all discussions for correct request", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().Get(ctx, "id").Return(discussion.Discussion{ID: "1", Title: "title", Body: "body"}, nil) - }, - Discussion: discussion.Discussion{ - ID: "1", Title: "title", Body: "body", - }, - did: "id", - }, - } - - for _, tc := range testcase { - t.Run(tc.Description, func(t *testing.T) { - mockDiscussionRepo := new(mocks.DiscussionRepository) - if tc.Setup != nil { - tc.Setup(ctx, mockDiscussionRepo) - } - defer mockDiscussionRepo.AssertExpectations(t) - - svc := discussion.NewService(mockDiscussionRepo) - discussions, err := svc.GetDiscussion(ctx, tc.did) - if err != nil { - assert.Equal(t, tc.Err, err.Error()) - } - assert.Equal(t, tc.Discussion, discussions) - }) - } -} - -func TestGetComments(t *testing.T) { - ctx := context.Background() - testcase := []struct { - Description string - Setup func(context.Context, *mocks.DiscussionRepository) - Err string - Filter discussion.Filter - Comment []discussion.Comment - }{ - { - Description: "should catch not found error", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().GetAllComments(ctx, "id-1", discussion.Filter{}).Return([]discussion.Comment{}, discussion.NotFoundError{}) - }, - Err: discussion.NotFoundError{}.Error(), - Comment: []discussion.Comment{}, - Filter: discussion.Filter{}, - }, - { - Description: "should catch invalid error for invalid state", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().GetAllComments(ctx, "id-1", discussion.Filter{Type: "random"}).Return([]discussion.Comment{}, discussion.InvalidError{}) - }, - Err: discussion.InvalidError{}.Error(), - Comment: []discussion.Comment{}, - Filter: discussion.Filter{Type: "random"}, - }, - { - Description: "should return all discussions for correct request", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().GetAllComments(ctx, "id-1", discussion.Filter{}).Return([]discussion.Comment{{ID: "1", DiscussionID: "id-1", Body: "body"}}, nil) - }, - Comment: []discussion.Comment{ - {ID: "1", DiscussionID: "id-1", Body: "body"}, - }, - Filter: discussion.Filter{}, - }, - } - - for _, tc := range testcase { - t.Run(tc.Description, func(t *testing.T) { - mockDiscussionRepo := new(mocks.DiscussionRepository) - if tc.Setup != nil { - tc.Setup(ctx, mockDiscussionRepo) - } - defer mockDiscussionRepo.AssertExpectations(t) - - svc := discussion.NewService(mockDiscussionRepo) - comments, err := svc.GetComments(ctx, "id-1", tc.Filter) - if err != nil { - assert.Equal(t, tc.Err, err.Error()) - } - assert.Equal(t, tc.Comment, comments) - }) - } -} - -func TestGetDeleteComment(t *testing.T) { - ctx := context.Background() - testcase := []struct { - Description string - Setup func(context.Context, *mocks.DiscussionRepository) - Err string - cid string - did string - Comment discussion.Comment - }{ - { - Description: "should catch not found error", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().GetComment(ctx, "id-1", "id-1").Return(discussion.Comment{}, discussion.NotFoundError{DiscussionID: "id-1", CommentID: "id-1"}) - }, - Err: discussion.NotFoundError{DiscussionID: "id-1", CommentID: "id-1"}.Error(), - Comment: discussion.Comment{}, - cid: "id-1", - did: "id-1", - }, - { - Description: "should catch invalid error for invalid state", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().GetComment(ctx, "invalid-id", "invalid-id").Return(discussion.Comment{}, discussion.InvalidError{DiscussionID: "invalid-id", CommentID: "invalid-id"}) - }, - Err: discussion.InvalidError{DiscussionID: "invalid-id", CommentID: "invalid-id"}.Error(), - Comment: discussion.Comment{}, - cid: "invalid-id", - did: "invalid-id", - }, - { - Description: "should return all discussions for correct request", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().GetComment(ctx, "id", "id").Return(discussion.Comment{ID: "1", DiscussionID: "id", Body: "body"}, nil) - dr.EXPECT().DeleteComment(ctx, "id", "id").Return(nil) - }, - Comment: discussion.Comment{ - ID: "1", DiscussionID: "id", Body: "body", - }, - cid: "id", - did: "id", - }, - } - - for _, tc := range testcase { - t.Run(tc.Description, func(t *testing.T) { - mockDiscussionRepo := new(mocks.DiscussionRepository) - if tc.Setup != nil { - tc.Setup(ctx, mockDiscussionRepo) - } - defer mockDiscussionRepo.AssertExpectations(t) - - svc := discussion.NewService(mockDiscussionRepo) - comment, err := svc.GetComment(ctx, tc.did, tc.cid) - if err != nil { - assert.Equal(t, tc.Err, err.Error()) - } else { - err = svc.DeleteComment(ctx, tc.did, tc.cid) - assert.NoError(t, err) - } - assert.Equal(t, tc.Comment, comment) - }) - } -} - -func TestCreateDiscussions(t *testing.T) { - ctx := context.Background() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - validDiscussion := discussion.Discussion{ - ID: "1", Title: "title", Body: "body", Type: "openended", - } - invalidDiscussion := discussion.Discussion{ - ID: "1", Title: "title", Body: "body", Type: "invalid", - } - testcase := []struct { - Description string - Setup func(context.Context, *mocks.DiscussionRepository) - Err error - Filter discussion.Filter - Discussion discussion.Discussion - }{ - { - Description: "throws error for empty discussion", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().Create(ctx, ns, &discussion.Discussion{}).Return("", errors.New("empty fields")) - }, - Err: errors.New("empty fields"), - Discussion: discussion.Discussion{}, - }, - { - Description: "throws error for invalid type", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().Create(ctx, ns, &invalidDiscussion).Return("", discussion.InvalidError{}) - }, - Err: discussion.InvalidError{}, - Discussion: invalidDiscussion, - }, - { - Description: "create discussion without error for correct input", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().Create(ctx, ns, &validDiscussion).Return("", nil) - }, - Discussion: validDiscussion, - }, - } - - for _, tc := range testcase { - t.Run(tc.Description, func(t *testing.T) { - mockDiscussionRepo := new(mocks.DiscussionRepository) - if tc.Setup != nil { - tc.Setup(ctx, mockDiscussionRepo) - } - defer mockDiscussionRepo.AssertExpectations(t) - - svc := discussion.NewService(mockDiscussionRepo) - _, err := svc.CreateDiscussion(ctx, ns, &tc.Discussion) - assert.Equal(t, tc.Err, err) - }) - } -} - -func TestPatchDiscussions(t *testing.T) { - ctx := context.Background() - validDiscussion := discussion.Discussion{ - ID: "1", Title: "title", Body: "body", Type: "openended", - } - invalidDiscussion := discussion.Discussion{ - ID: "1", Title: "title", Body: "body", Type: "invalid", - } - testcase := []struct { - Description string - Setup func(context.Context, *mocks.DiscussionRepository) - Err error - Filter discussion.Filter - Discussion discussion.Discussion - }{ - { - Description: "throws error for empty discussion", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().Patch(ctx, &discussion.Discussion{}).Return(errors.New("empty fields")) - }, - Err: errors.New("empty fields"), - Discussion: discussion.Discussion{}, - }, - { - Description: "throws error for invalid type", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().Patch(ctx, &invalidDiscussion).Return(discussion.InvalidError{}) - }, - Err: discussion.InvalidError{}, - Discussion: invalidDiscussion, - }, - { - Description: "patch discussion properly for valid data", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().Patch(ctx, &validDiscussion).Return(nil) - }, - Discussion: validDiscussion, - }, - } - - for _, tc := range testcase { - t.Run(tc.Description, func(t *testing.T) { - mockDiscussionRepo := new(mocks.DiscussionRepository) - if tc.Setup != nil { - tc.Setup(ctx, mockDiscussionRepo) - } - defer mockDiscussionRepo.AssertExpectations(t) - - svc := discussion.NewService(mockDiscussionRepo) - err := svc.PatchDiscussion(ctx, &tc.Discussion) - assert.Equal(t, tc.Err, err) - }) - } -} - -func TestCreateComment(t *testing.T) { - ctx := context.Background() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - validComment := discussion.Comment{ - ID: "1", DiscussionID: "id-1", Body: "body", - } - testcase := []struct { - Description string - Setup func(context.Context, *mocks.DiscussionRepository) - Err error - Comment discussion.Comment - }{ - { - Description: "throw error for empty fields", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().CreateComment(ctx, ns, &discussion.Comment{}).Return("", errors.New("empty fields")) - }, - Err: errors.New("empty fields"), - Comment: discussion.Comment{}, - }, - { - Description: "create comment for proper data", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().CreateComment(ctx, ns, &validComment).Return("", nil) - }, - Comment: validComment, - }, - } - - for _, tc := range testcase { - t.Run(tc.Description, func(t *testing.T) { - mockDiscussionRepo := new(mocks.DiscussionRepository) - if tc.Setup != nil { - tc.Setup(ctx, mockDiscussionRepo) - } - defer mockDiscussionRepo.AssertExpectations(t) - - svc := discussion.NewService(mockDiscussionRepo) - _, err := svc.CreateComment(ctx, ns, &tc.Comment) - assert.Equal(t, tc.Err, err) - }) - } -} - -func TestUpdateComment(t *testing.T) { - ctx := context.Background() - validComment := discussion.Comment{ - ID: "1", DiscussionID: "id-1", Body: "body", - } - testcase := []struct { - Description string - Setup func(context.Context, *mocks.DiscussionRepository) - Err error - Comment discussion.Comment - }{ - { - Description: "throw error for empty fields", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().UpdateComment(ctx, &discussion.Comment{}).Return(errors.New("empty fields")) - }, - Err: errors.New("empty fields"), - Comment: discussion.Comment{}, - }, - { - Description: "update comment for proper data", - Setup: func(ctx context.Context, dr *mocks.DiscussionRepository) { - dr.EXPECT().UpdateComment(ctx, &validComment).Return(nil) - }, - Comment: validComment, - }, - } - - for _, tc := range testcase { - t.Run(tc.Description, func(t *testing.T) { - mockDiscussionRepo := new(mocks.DiscussionRepository) - if tc.Setup != nil { - tc.Setup(ctx, mockDiscussionRepo) - } - defer mockDiscussionRepo.AssertExpectations(t) - - svc := discussion.NewService(mockDiscussionRepo) - err := svc.UpdateComment(ctx, &tc.Comment) - assert.Equal(t, tc.Err, err) - }) - } -} diff --git a/core/discussion/state.go b/core/discussion/state.go deleted file mode 100644 index 97411c68..00000000 --- a/core/discussion/state.go +++ /dev/null @@ -1,37 +0,0 @@ -package discussion - -type State string - -const ( - StateOpen State = "open" - StateClosed State = "closed" -) - -var SupportedStates = []string{StateOpen.String(), StateClosed.String()} - -// String returns state enum as string -func (ds State) String() string { - return string(ds) -} - -// GetStateEnum converts string to state enum -func GetStateEnum(ds string) State { - switch { - case ds == StateOpen.String(): - return StateOpen - case ds == StateClosed.String(): - return StateClosed - } - // fallback - return StateOpen -} - -// IsStateStringValid returns true if state string is valid/supported -func IsStateStringValid(ss string) bool { - for _, supported := range SupportedStates { - if supported == ss { - return true - } - } - return false -} diff --git a/core/discussion/state_test.go b/core/discussion/state_test.go deleted file mode 100644 index aaaf31ef..00000000 --- a/core/discussion/state_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package discussion_test - -import ( - "testing" - - "github.com/raystack/compass/core/discussion" - "github.com/stretchr/testify/assert" -) - -func TestState(t *testing.T) { - t.Run("enum to string conversion", func(t *testing.T) { - type TestCase struct { - Description string - State discussion.State - Result string - } - - var testCases = []TestCase{ - { - Description: "state open converts to \"open\"", - State: discussion.StateOpen, - Result: "open", - }, - { - Description: "state closed converts to \"closed\"", - State: discussion.StateClosed, - Result: "closed", - }, - { - Description: "unknown state converts to \"open\"", - State: discussion.StateOpen, - Result: "open", - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - assert.Equal(t, tc.Result, tc.State.String()) - }) - } - }) - - t.Run("string to enum conversion", func(t *testing.T) { - type TestCase struct { - Description string - StateString string - Result discussion.State - } - - var testCases = []TestCase{ - { - Description: "\"open\" converts to state open", - StateString: "open", - Result: discussion.StateOpen, - }, - { - Description: "\"closed\" converts to state closed", - StateString: "closed", - Result: discussion.StateClosed, - }, - { - Description: "other words converts to state open", - StateString: "random", - Result: discussion.StateOpen, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - assert.Equal(t, tc.Result, discussion.GetStateEnum(tc.StateString)) - }) - } - }) - - t.Run("validating string", func(t *testing.T) { - type TestCase struct { - Description string - StateString string - IsValid bool - } - - var testCases = []TestCase{ - { - Description: "supported state will return valid true", - StateString: "open", - IsValid: true, - }, - { - Description: "unsupported state will return valid true", - StateString: "random", - IsValid: false, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - assert.Equal(t, tc.IsValid, discussion.IsStateStringValid(tc.StateString)) - }) - } - }) -} diff --git a/core/discussion/type_test.go b/core/discussion/type_test.go deleted file mode 100644 index c70a50cd..00000000 --- a/core/discussion/type_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package discussion_test - -import ( - "testing" - - "github.com/raystack/compass/core/discussion" - "github.com/stretchr/testify/assert" -) - -func TestType(t *testing.T) { - t.Run("enum to string conversion", func(t *testing.T) { - type TestCase struct { - Description string - Type discussion.Type - Result string - } - - var testCases = []TestCase{ - { - Description: "type openended converts to \"openended\"", - Type: discussion.TypeOpenEnded, - Result: "openended", - }, - { - Description: "type issues converts to \"issues\"", - Type: discussion.TypeIssues, - Result: "issues", - }, - { - Description: "type qanda converts to \"qanda\"", - Type: discussion.TypeQAndA, - Result: "qanda", - }, - { - Description: "unknown state converts to \"openended\"", - Type: discussion.TypeOpenEnded, - Result: "openended", - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - assert.Equal(t, tc.Result, tc.Type.String()) - }) - } - }) - - t.Run("string to enum conversion", func(t *testing.T) { - type TestCase struct { - Description string - TypeString string - Result discussion.Type - } - - var testCases = []TestCase{ - { - Description: "\"openended\" converts to type openended", - TypeString: "openended", - Result: discussion.TypeOpenEnded, - }, - { - Description: "\"issues\" converts to type issues", - TypeString: "issues", - Result: discussion.TypeIssues, - }, - { - Description: "\"qanda\" converts to type qanda", - TypeString: "qanda", - Result: discussion.TypeQAndA, - }, - { - Description: "other words fallback to type openended", - TypeString: "random", - Result: discussion.TypeOpenEnded, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - assert.Equal(t, tc.Result, discussion.GetTypeEnum(tc.TypeString)) - }) - } - }) - - t.Run("validating string", func(t *testing.T) { - type TestCase struct { - Description string - TypeString string - IsValid bool - } - - var testCases = []TestCase{ - { - Description: "supported type will return valid true", - TypeString: "openended", - IsValid: true, - }, - { - Description: "unsupported type will return valid true", - TypeString: "random", - IsValid: false, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - assert.Equal(t, tc.IsValid, discussion.IsTypeStringValid(tc.TypeString)) - }) - } - }) -} diff --git a/core/discussion/types.go b/core/discussion/types.go deleted file mode 100644 index ec0342d8..00000000 --- a/core/discussion/types.go +++ /dev/null @@ -1,40 +0,0 @@ -package discussion - -type Type string - -const ( - TypeOpenEnded Type = "openended" - TypeIssues Type = "issues" - TypeQAndA Type = "qanda" -) - -var SupportedTypes = []string{TypeOpenEnded.String(), TypeIssues.String(), TypeQAndA.String()} - -// String returns type enum as string -func (dt Type) String() string { - return string(dt) -} - -// GetTypeEnum converts string to type enum -func GetTypeEnum(dt string) Type { - switch { - case dt == TypeOpenEnded.String(): - return TypeOpenEnded - case dt == TypeIssues.String(): - return TypeIssues - case dt == TypeQAndA.String(): - return TypeQAndA - } - // fallback - return TypeOpenEnded -} - -// IsTypeStringValid returns true if type string is valid/supported -func IsTypeStringValid(ts string) bool { - for _, supported := range SupportedTypes { - if supported == ts { - return true - } - } - return false -} diff --git a/core/star/errors.go b/core/star/errors.go index 702bcaa4..851c9a3e 100644 --- a/core/star/errors.go +++ b/core/star/errors.go @@ -8,18 +8,18 @@ import ( var ( ErrEmptyUserID = errors.New("star is not related to any user") - ErrEmptyAssetID = errors.New("star is not related to any asset") + ErrEmptyEntityID = errors.New("star is not related to any entity") ) type NotFoundError struct { - AssetID string + EntityID string UserID string } func (e NotFoundError) Error() string { - fields := []string{"could not find starred asset"} - if e.AssetID != "" { - fields = append(fields, fmt.Sprintf("with asset id \"%s\"", e.AssetID)) + fields := []string{"could not find starred entity"} + if e.EntityID != "" { + fields = append(fields, fmt.Sprintf("with entity id \"%s\"", e.EntityID)) } if e.UserID != "" { fields = append(fields, fmt.Sprintf("by user id \"%s\"", e.UserID)) @@ -37,22 +37,22 @@ func (e UserNotFoundError) Error() string { type DuplicateRecordError struct { UserID string - AssetID string + EntityID string } func (e DuplicateRecordError) Error() string { - return fmt.Sprintf("duplicate starred asset id \"%s\" with user id \"%s\"", e.AssetID, e.UserID) + return fmt.Sprintf("duplicate starred entity id \"%s\" with user id \"%s\"", e.EntityID, e.UserID) } type InvalidError struct { UserID string - AssetID string + EntityID string } func (e InvalidError) Error() string { fields := []string{"invalid"} - if e.AssetID != "" { - fields = append(fields, fmt.Sprintf("asset id \"%s\"", e.AssetID)) + if e.EntityID != "" { + fields = append(fields, fmt.Sprintf("asset id \"%s\"", e.EntityID)) } if e.UserID != "" { fields = append(fields, fmt.Sprintf("user id \"%s\"", e.UserID)) diff --git a/core/star/mocks/star_repository.go b/core/star/mocks/star_repository.go index 84f4a499..53ebdb41 100644 --- a/core/star/mocks/star_repository.go +++ b/core/star/mocks/star_repository.go @@ -5,7 +5,7 @@ package mocks import ( context "context" - asset "github.com/raystack/compass/core/asset" + entity "github.com/raystack/compass/core/entity" mock "github.com/stretchr/testify/mock" @@ -29,23 +29,23 @@ func (_m *StarRepository) EXPECT() *StarRepository_Expecter { return &StarRepository_Expecter{mock: &_m.Mock} } -// Create provides a mock function with given fields: ctx, ns, userID, assetID -func (_m *StarRepository) Create(ctx context.Context, ns *namespace.Namespace, userID string, assetID string) (string, error) { - ret := _m.Called(ctx, ns, userID, assetID) +// Create provides a mock function with given fields: ctx, ns, userID, entityID +func (_m *StarRepository) Create(ctx context.Context, ns *namespace.Namespace, userID string, entityID string) (string, error) { + ret := _m.Called(ctx, ns, userID, entityID) var r0 string var r1 error if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string, string) (string, error)); ok { - return rf(ctx, ns, userID, assetID) + return rf(ctx, ns, userID, entityID) } if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string, string) string); ok { - r0 = rf(ctx, ns, userID, assetID) + r0 = rf(ctx, ns, userID, entityID) } else { r0 = ret.Get(0).(string) } if rf, ok := ret.Get(1).(func(context.Context, *namespace.Namespace, string, string) error); ok { - r1 = rf(ctx, ns, userID, assetID) + r1 = rf(ctx, ns, userID, entityID) } else { r1 = ret.Error(1) } @@ -62,12 +62,12 @@ type StarRepository_Create_Call struct { // - ctx context.Context // - ns *namespace.Namespace // - userID string -// - assetID string -func (_e *StarRepository_Expecter) Create(ctx interface{}, ns interface{}, userID interface{}, assetID interface{}) *StarRepository_Create_Call { - return &StarRepository_Create_Call{Call: _e.mock.On("Create", ctx, ns, userID, assetID)} +// - entityID string +func (_e *StarRepository_Expecter) Create(ctx interface{}, ns interface{}, userID interface{}, entityID interface{}) *StarRepository_Create_Call { + return &StarRepository_Create_Call{Call: _e.mock.On("Create", ctx, ns, userID, entityID)} } -func (_c *StarRepository_Create_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, userID string, assetID string)) *StarRepository_Create_Call { +func (_c *StarRepository_Create_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, userID string, entityID string)) *StarRepository_Create_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(string), args[3].(string)) }) @@ -84,13 +84,13 @@ func (_c *StarRepository_Create_Call) RunAndReturn(run func(context.Context, *na return _c } -// Delete provides a mock function with given fields: ctx, userID, assetID -func (_m *StarRepository) Delete(ctx context.Context, userID string, assetID string) error { - ret := _m.Called(ctx, userID, assetID) +// Delete provides a mock function with given fields: ctx, userID, entityID +func (_m *StarRepository) Delete(ctx context.Context, userID string, entityID string) error { + ret := _m.Called(ctx, userID, entityID) var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { - r0 = rf(ctx, userID, assetID) + r0 = rf(ctx, userID, entityID) } else { r0 = ret.Error(0) } @@ -106,12 +106,12 @@ type StarRepository_Delete_Call struct { // Delete is a helper method to define mock.On call // - ctx context.Context // - userID string -// - assetID string -func (_e *StarRepository_Expecter) Delete(ctx interface{}, userID interface{}, assetID interface{}) *StarRepository_Delete_Call { - return &StarRepository_Delete_Call{Call: _e.mock.On("Delete", ctx, userID, assetID)} +// - entityID string +func (_e *StarRepository_Expecter) Delete(ctx interface{}, userID interface{}, entityID interface{}) *StarRepository_Delete_Call { + return &StarRepository_Delete_Call{Call: _e.mock.On("Delete", ctx, userID, entityID)} } -func (_c *StarRepository_Delete_Call) Run(run func(ctx context.Context, userID string, assetID string)) *StarRepository_Delete_Call { +func (_c *StarRepository_Delete_Call) Run(run func(ctx context.Context, userID string, entityID string)) *StarRepository_Delete_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(string), args[2].(string)) }) @@ -128,20 +128,20 @@ func (_c *StarRepository_Delete_Call) RunAndReturn(run func(context.Context, str return _c } -// GetAllAssetsByUserID provides a mock function with given fields: ctx, flt, userID -func (_m *StarRepository) GetAllAssetsByUserID(ctx context.Context, flt star.Filter, userID string) ([]asset.Asset, error) { +// GetAllEntitiesByUserID provides a mock function with given fields: ctx, flt, userID +func (_m *StarRepository) GetAllEntitiesByUserID(ctx context.Context, flt star.Filter, userID string) ([]entity.Entity, error) { ret := _m.Called(ctx, flt, userID) - var r0 []asset.Asset + var r0 []entity.Entity var r1 error - if rf, ok := ret.Get(0).(func(context.Context, star.Filter, string) ([]asset.Asset, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, star.Filter, string) ([]entity.Entity, error)); ok { return rf(ctx, flt, userID) } - if rf, ok := ret.Get(0).(func(context.Context, star.Filter, string) []asset.Asset); ok { + if rf, ok := ret.Get(0).(func(context.Context, star.Filter, string) []entity.Entity); ok { r0 = rf(ctx, flt, userID) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]asset.Asset) + r0 = ret.Get(0).([]entity.Entity) } } @@ -154,53 +154,53 @@ func (_m *StarRepository) GetAllAssetsByUserID(ctx context.Context, flt star.Fil return r0, r1 } -// StarRepository_GetAllAssetsByUserID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllAssetsByUserID' -type StarRepository_GetAllAssetsByUserID_Call struct { +// StarRepository_GetAllEntitiesByUserID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllEntitiesByUserID' +type StarRepository_GetAllEntitiesByUserID_Call struct { *mock.Call } -// GetAllAssetsByUserID is a helper method to define mock.On call +// GetAllEntitiesByUserID is a helper method to define mock.On call // - ctx context.Context // - flt star.Filter // - userID string -func (_e *StarRepository_Expecter) GetAllAssetsByUserID(ctx interface{}, flt interface{}, userID interface{}) *StarRepository_GetAllAssetsByUserID_Call { - return &StarRepository_GetAllAssetsByUserID_Call{Call: _e.mock.On("GetAllAssetsByUserID", ctx, flt, userID)} +func (_e *StarRepository_Expecter) GetAllEntitiesByUserID(ctx interface{}, flt interface{}, userID interface{}) *StarRepository_GetAllEntitiesByUserID_Call { + return &StarRepository_GetAllEntitiesByUserID_Call{Call: _e.mock.On("GetAllEntitiesByUserID", ctx, flt, userID)} } -func (_c *StarRepository_GetAllAssetsByUserID_Call) Run(run func(ctx context.Context, flt star.Filter, userID string)) *StarRepository_GetAllAssetsByUserID_Call { +func (_c *StarRepository_GetAllEntitiesByUserID_Call) Run(run func(ctx context.Context, flt star.Filter, userID string)) *StarRepository_GetAllEntitiesByUserID_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(star.Filter), args[2].(string)) }) return _c } -func (_c *StarRepository_GetAllAssetsByUserID_Call) Return(_a0 []asset.Asset, _a1 error) *StarRepository_GetAllAssetsByUserID_Call { +func (_c *StarRepository_GetAllEntitiesByUserID_Call) Return(_a0 []entity.Entity, _a1 error) *StarRepository_GetAllEntitiesByUserID_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *StarRepository_GetAllAssetsByUserID_Call) RunAndReturn(run func(context.Context, star.Filter, string) ([]asset.Asset, error)) *StarRepository_GetAllAssetsByUserID_Call { +func (_c *StarRepository_GetAllEntitiesByUserID_Call) RunAndReturn(run func(context.Context, star.Filter, string) ([]entity.Entity, error)) *StarRepository_GetAllEntitiesByUserID_Call { _c.Call.Return(run) return _c } -// GetAssetByUserID provides a mock function with given fields: ctx, userID, assetID -func (_m *StarRepository) GetAssetByUserID(ctx context.Context, userID string, assetID string) (asset.Asset, error) { - ret := _m.Called(ctx, userID, assetID) +// GetEntityByUserID provides a mock function with given fields: ctx, userID, entityID +func (_m *StarRepository) GetEntityByUserID(ctx context.Context, userID string, entityID string) (entity.Entity, error) { + ret := _m.Called(ctx, userID, entityID) - var r0 asset.Asset + var r0 entity.Entity var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (asset.Asset, error)); ok { - return rf(ctx, userID, assetID) + if rf, ok := ret.Get(0).(func(context.Context, string, string) (entity.Entity, error)); ok { + return rf(ctx, userID, entityID) } - if rf, ok := ret.Get(0).(func(context.Context, string, string) asset.Asset); ok { - r0 = rf(ctx, userID, assetID) + if rf, ok := ret.Get(0).(func(context.Context, string, string) entity.Entity); ok { + r0 = rf(ctx, userID, entityID) } else { - r0 = ret.Get(0).(asset.Asset) + r0 = ret.Get(0).(entity.Entity) } if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, userID, assetID) + r1 = rf(ctx, userID, entityID) } else { r1 = ret.Error(1) } @@ -208,47 +208,47 @@ func (_m *StarRepository) GetAssetByUserID(ctx context.Context, userID string, a return r0, r1 } -// StarRepository_GetAssetByUserID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAssetByUserID' -type StarRepository_GetAssetByUserID_Call struct { +// StarRepository_GetEntityByUserID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetEntityByUserID' +type StarRepository_GetEntityByUserID_Call struct { *mock.Call } -// GetAssetByUserID is a helper method to define mock.On call +// GetEntityByUserID is a helper method to define mock.On call // - ctx context.Context // - userID string -// - assetID string -func (_e *StarRepository_Expecter) GetAssetByUserID(ctx interface{}, userID interface{}, assetID interface{}) *StarRepository_GetAssetByUserID_Call { - return &StarRepository_GetAssetByUserID_Call{Call: _e.mock.On("GetAssetByUserID", ctx, userID, assetID)} +// - entityID string +func (_e *StarRepository_Expecter) GetEntityByUserID(ctx interface{}, userID interface{}, entityID interface{}) *StarRepository_GetEntityByUserID_Call { + return &StarRepository_GetEntityByUserID_Call{Call: _e.mock.On("GetEntityByUserID", ctx, userID, entityID)} } -func (_c *StarRepository_GetAssetByUserID_Call) Run(run func(ctx context.Context, userID string, assetID string)) *StarRepository_GetAssetByUserID_Call { +func (_c *StarRepository_GetEntityByUserID_Call) Run(run func(ctx context.Context, userID string, entityID string)) *StarRepository_GetEntityByUserID_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(string), args[2].(string)) }) return _c } -func (_c *StarRepository_GetAssetByUserID_Call) Return(_a0 asset.Asset, _a1 error) *StarRepository_GetAssetByUserID_Call { +func (_c *StarRepository_GetEntityByUserID_Call) Return(_a0 entity.Entity, _a1 error) *StarRepository_GetEntityByUserID_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *StarRepository_GetAssetByUserID_Call) RunAndReturn(run func(context.Context, string, string) (asset.Asset, error)) *StarRepository_GetAssetByUserID_Call { +func (_c *StarRepository_GetEntityByUserID_Call) RunAndReturn(run func(context.Context, string, string) (entity.Entity, error)) *StarRepository_GetEntityByUserID_Call { _c.Call.Return(run) return _c } -// GetStargazers provides a mock function with given fields: ctx, flt, assetID -func (_m *StarRepository) GetStargazers(ctx context.Context, flt star.Filter, assetID string) ([]user.User, error) { - ret := _m.Called(ctx, flt, assetID) +// GetStargazers provides a mock function with given fields: ctx, flt, entityID +func (_m *StarRepository) GetStargazers(ctx context.Context, flt star.Filter, entityID string) ([]user.User, error) { + ret := _m.Called(ctx, flt, entityID) var r0 []user.User var r1 error if rf, ok := ret.Get(0).(func(context.Context, star.Filter, string) ([]user.User, error)); ok { - return rf(ctx, flt, assetID) + return rf(ctx, flt, entityID) } if rf, ok := ret.Get(0).(func(context.Context, star.Filter, string) []user.User); ok { - r0 = rf(ctx, flt, assetID) + r0 = rf(ctx, flt, entityID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]user.User) @@ -256,7 +256,7 @@ func (_m *StarRepository) GetStargazers(ctx context.Context, flt star.Filter, as } if rf, ok := ret.Get(1).(func(context.Context, star.Filter, string) error); ok { - r1 = rf(ctx, flt, assetID) + r1 = rf(ctx, flt, entityID) } else { r1 = ret.Error(1) } @@ -272,12 +272,12 @@ type StarRepository_GetStargazers_Call struct { // GetStargazers is a helper method to define mock.On call // - ctx context.Context // - flt star.Filter -// - assetID string -func (_e *StarRepository_Expecter) GetStargazers(ctx interface{}, flt interface{}, assetID interface{}) *StarRepository_GetStargazers_Call { - return &StarRepository_GetStargazers_Call{Call: _e.mock.On("GetStargazers", ctx, flt, assetID)} +// - entityID string +func (_e *StarRepository_Expecter) GetStargazers(ctx interface{}, flt interface{}, entityID interface{}) *StarRepository_GetStargazers_Call { + return &StarRepository_GetStargazers_Call{Call: _e.mock.On("GetStargazers", ctx, flt, entityID)} } -func (_c *StarRepository_GetStargazers_Call) Run(run func(ctx context.Context, flt star.Filter, assetID string)) *StarRepository_GetStargazers_Call { +func (_c *StarRepository_GetStargazers_Call) Run(run func(ctx context.Context, flt star.Filter, entityID string)) *StarRepository_GetStargazers_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(star.Filter), args[2].(string)) }) diff --git a/core/star/service.go b/core/star/service.go index c5da6046..fb3e303d 100644 --- a/core/star/service.go +++ b/core/star/service.go @@ -4,7 +4,7 @@ import ( "context" "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/asset" + "github.com/raystack/compass/core/entity" "github.com/raystack/compass/core/user" ) @@ -18,18 +18,18 @@ type Service struct { starRepository Repository } -func (s *Service) GetStarredAssetsByUserID(ctx context.Context, flt Filter, userID string) ([]asset.Asset, error) { - return s.starRepository.GetAllAssetsByUserID(ctx, flt, userID) +func (s *Service) GetStarredEntitiesByUserID(ctx context.Context, flt Filter, userID string) ([]entity.Entity, error) { + return s.starRepository.GetAllEntitiesByUserID(ctx, flt, userID) } -func (s *Service) GetStarredAssetByUserID(ctx context.Context, userID, assetID string) (asset.Asset, error) { - return s.starRepository.GetAssetByUserID(ctx, userID, assetID) +func (s *Service) GetStarredEntityByUserID(ctx context.Context, userID, entityID string) (entity.Entity, error) { + return s.starRepository.GetEntityByUserID(ctx, userID, entityID) } -func (s *Service) GetStargazers(ctx context.Context, flt Filter, assetID string) ([]user.User, error) { - return s.starRepository.GetStargazers(ctx, flt, assetID) +func (s *Service) GetStargazers(ctx context.Context, flt Filter, entityID string) ([]user.User, error) { + return s.starRepository.GetStargazers(ctx, flt, entityID) } -func (s *Service) Stars(ctx context.Context, ns *namespace.Namespace, userID, assetID string) (string, error) { - return s.starRepository.Create(ctx, ns, userID, assetID) +func (s *Service) Stars(ctx context.Context, ns *namespace.Namespace, userID, entityID string) (string, error) { + return s.starRepository.Create(ctx, ns, userID, entityID) } -func (s *Service) Unstars(ctx context.Context, userID, assetID string) error { - return s.starRepository.Delete(ctx, userID, assetID) +func (s *Service) Unstars(ctx context.Context, userID, entityID string) error { + return s.starRepository.Delete(ctx, userID, entityID) } diff --git a/core/star/star.go b/core/star/star.go index f934e046..2c368603 100644 --- a/core/star/star.go +++ b/core/star/star.go @@ -4,16 +4,16 @@ package star import ( "context" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/asset" + "github.com/raystack/compass/core/entity" + "github.com/raystack/compass/core/namespace" "github.com/raystack/compass/core/user" ) type Repository interface { - Create(ctx context.Context, ns *namespace.Namespace, userID string, assetID string) (string, error) - GetStargazers(ctx context.Context, flt Filter, assetID string) ([]user.User, error) - GetAllAssetsByUserID(ctx context.Context, flt Filter, userID string) ([]asset.Asset, error) - GetAssetByUserID(ctx context.Context, userID string, assetID string) (asset.Asset, error) - Delete(ctx context.Context, userID string, assetID string) error + Create(ctx context.Context, ns *namespace.Namespace, userID string, entityID string) (string, error) + GetStargazers(ctx context.Context, flt Filter, entityID string) ([]user.User, error) + GetAllEntitiesByUserID(ctx context.Context, flt Filter, userID string) ([]entity.Entity, error) + GetEntityByUserID(ctx context.Context, userID string, entityID string) (entity.Entity, error) + Delete(ctx context.Context, userID string, entityID string) error } diff --git a/core/tag/errors.go b/core/tag/errors.go deleted file mode 100644 index 73b8c0be..00000000 --- a/core/tag/errors.go +++ /dev/null @@ -1,51 +0,0 @@ -package tag - -import ( - "fmt" -) - -type NotFoundError struct { - AssetID string - Template string -} - -func (e NotFoundError) Error() string { - return fmt.Sprintf( - "could not find tag with asset id: \"%s\", template: \"%s\"", - e.AssetID, - e.Template, - ) -} - -type TemplateNotFoundError struct { - URN string -} - -func (e TemplateNotFoundError) Error() string { - return fmt.Sprintf("could not find template \"%s\"", e.URN) -} - -type DuplicateError struct { - AssetID string - TemplateURN string -} - -func (e DuplicateError) Error() string { - return fmt.Sprintf("tag of asset ID \"%s\" and template URN \"%s\" already exists", e.AssetID, e.TemplateURN) -} - -type DuplicateTemplateError struct { - URN string -} - -func (e DuplicateTemplateError) Error() string { - return fmt.Sprintf("template \"%s\" already exists", e.URN) -} - -type ValidationError struct { - Err error -} - -func (e ValidationError) Error() string { - return e.Err.Error() -} diff --git a/core/tag/mocks/tag_repository.go b/core/tag/mocks/tag_repository.go deleted file mode 100644 index aa2260b5..00000000 --- a/core/tag/mocks/tag_repository.go +++ /dev/null @@ -1,225 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - namespace "github.com/raystack/compass/core/namespace" - mock "github.com/stretchr/testify/mock" - - tag "github.com/raystack/compass/core/tag" -) - -// TagRepository is an autogenerated mock type for the TagRepository type -type TagRepository struct { - mock.Mock -} - -type TagRepository_Expecter struct { - mock *mock.Mock -} - -func (_m *TagRepository) EXPECT() *TagRepository_Expecter { - return &TagRepository_Expecter{mock: &_m.Mock} -} - -// Create provides a mock function with given fields: ctx, ns, _a2 -func (_m *TagRepository) Create(ctx context.Context, ns *namespace.Namespace, _a2 *tag.Tag) error { - ret := _m.Called(ctx, ns, _a2) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *tag.Tag) error); ok { - r0 = rf(ctx, ns, _a2) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagRepository_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' -type TagRepository_Create_Call struct { - *mock.Call -} - -// Create is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - _a2 *tag.Tag -func (_e *TagRepository_Expecter) Create(ctx interface{}, ns interface{}, _a2 interface{}) *TagRepository_Create_Call { - return &TagRepository_Create_Call{Call: _e.mock.On("Create", ctx, ns, _a2)} -} - -func (_c *TagRepository_Create_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, _a2 *tag.Tag)) *TagRepository_Create_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*tag.Tag)) - }) - return _c -} - -func (_c *TagRepository_Create_Call) Return(_a0 error) *TagRepository_Create_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagRepository_Create_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *tag.Tag) error) *TagRepository_Create_Call { - _c.Call.Return(run) - return _c -} - -// Delete provides a mock function with given fields: ctx, filter -func (_m *TagRepository) Delete(ctx context.Context, filter tag.Tag) error { - ret := _m.Called(ctx, filter) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, tag.Tag) error); ok { - r0 = rf(ctx, filter) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagRepository_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' -type TagRepository_Delete_Call struct { - *mock.Call -} - -// Delete is a helper method to define mock.On call -// - ctx context.Context -// - filter tag.Tag -func (_e *TagRepository_Expecter) Delete(ctx interface{}, filter interface{}) *TagRepository_Delete_Call { - return &TagRepository_Delete_Call{Call: _e.mock.On("Delete", ctx, filter)} -} - -func (_c *TagRepository_Delete_Call) Run(run func(ctx context.Context, filter tag.Tag)) *TagRepository_Delete_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(tag.Tag)) - }) - return _c -} - -func (_c *TagRepository_Delete_Call) Return(_a0 error) *TagRepository_Delete_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagRepository_Delete_Call) RunAndReturn(run func(context.Context, tag.Tag) error) *TagRepository_Delete_Call { - _c.Call.Return(run) - return _c -} - -// Read provides a mock function with given fields: ctx, filter -func (_m *TagRepository) Read(ctx context.Context, filter tag.Tag) ([]tag.Tag, error) { - ret := _m.Called(ctx, filter) - - var r0 []tag.Tag - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, tag.Tag) ([]tag.Tag, error)); ok { - return rf(ctx, filter) - } - if rf, ok := ret.Get(0).(func(context.Context, tag.Tag) []tag.Tag); ok { - r0 = rf(ctx, filter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]tag.Tag) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, tag.Tag) error); ok { - r1 = rf(ctx, filter) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TagRepository_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read' -type TagRepository_Read_Call struct { - *mock.Call -} - -// Read is a helper method to define mock.On call -// - ctx context.Context -// - filter tag.Tag -func (_e *TagRepository_Expecter) Read(ctx interface{}, filter interface{}) *TagRepository_Read_Call { - return &TagRepository_Read_Call{Call: _e.mock.On("Read", ctx, filter)} -} - -func (_c *TagRepository_Read_Call) Run(run func(ctx context.Context, filter tag.Tag)) *TagRepository_Read_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(tag.Tag)) - }) - return _c -} - -func (_c *TagRepository_Read_Call) Return(_a0 []tag.Tag, _a1 error) *TagRepository_Read_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *TagRepository_Read_Call) RunAndReturn(run func(context.Context, tag.Tag) ([]tag.Tag, error)) *TagRepository_Read_Call { - _c.Call.Return(run) - return _c -} - -// Update provides a mock function with given fields: ctx, _a1 -func (_m *TagRepository) Update(ctx context.Context, _a1 *tag.Tag) error { - ret := _m.Called(ctx, _a1) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *tag.Tag) error); ok { - r0 = rf(ctx, _a1) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagRepository_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' -type TagRepository_Update_Call struct { - *mock.Call -} - -// Update is a helper method to define mock.On call -// - ctx context.Context -// - _a1 *tag.Tag -func (_e *TagRepository_Expecter) Update(ctx interface{}, _a1 interface{}) *TagRepository_Update_Call { - return &TagRepository_Update_Call{Call: _e.mock.On("Update", ctx, _a1)} -} - -func (_c *TagRepository_Update_Call) Run(run func(ctx context.Context, _a1 *tag.Tag)) *TagRepository_Update_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*tag.Tag)) - }) - return _c -} - -func (_c *TagRepository_Update_Call) Return(_a0 error) *TagRepository_Update_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagRepository_Update_Call) RunAndReturn(run func(context.Context, *tag.Tag) error) *TagRepository_Update_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTNewTagRepository interface { - mock.TestingT - Cleanup(func()) -} - -// NewTagRepository creates a new instance of TagRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTagRepository(t mockConstructorTestingTNewTagRepository) *TagRepository { - mock := &TagRepository{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/tag/mocks/tag_template_repository.go b/core/tag/mocks/tag_template_repository.go deleted file mode 100644 index 06f9490c..00000000 --- a/core/tag/mocks/tag_template_repository.go +++ /dev/null @@ -1,281 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - namespace "github.com/raystack/compass/core/namespace" - mock "github.com/stretchr/testify/mock" - - tag "github.com/raystack/compass/core/tag" -) - -// TagTemplateRepository is an autogenerated mock type for the TagTemplateRepository type -type TagTemplateRepository struct { - mock.Mock -} - -type TagTemplateRepository_Expecter struct { - mock *mock.Mock -} - -func (_m *TagTemplateRepository) EXPECT() *TagTemplateRepository_Expecter { - return &TagTemplateRepository_Expecter{mock: &_m.Mock} -} - -// Create provides a mock function with given fields: ctx, ns, template -func (_m *TagTemplateRepository) Create(ctx context.Context, ns *namespace.Namespace, template *tag.Template) error { - ret := _m.Called(ctx, ns, template) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *tag.Template) error); ok { - r0 = rf(ctx, ns, template) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagTemplateRepository_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' -type TagTemplateRepository_Create_Call struct { - *mock.Call -} - -// Create is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - template *tag.Template -func (_e *TagTemplateRepository_Expecter) Create(ctx interface{}, ns interface{}, template interface{}) *TagTemplateRepository_Create_Call { - return &TagTemplateRepository_Create_Call{Call: _e.mock.On("Create", ctx, ns, template)} -} - -func (_c *TagTemplateRepository_Create_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, template *tag.Template)) *TagTemplateRepository_Create_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*tag.Template)) - }) - return _c -} - -func (_c *TagTemplateRepository_Create_Call) Return(_a0 error) *TagTemplateRepository_Create_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagTemplateRepository_Create_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *tag.Template) error) *TagTemplateRepository_Create_Call { - _c.Call.Return(run) - return _c -} - -// Delete provides a mock function with given fields: ctx, templateURN -func (_m *TagTemplateRepository) Delete(ctx context.Context, templateURN string) error { - ret := _m.Called(ctx, templateURN) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { - r0 = rf(ctx, templateURN) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagTemplateRepository_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' -type TagTemplateRepository_Delete_Call struct { - *mock.Call -} - -// Delete is a helper method to define mock.On call -// - ctx context.Context -// - templateURN string -func (_e *TagTemplateRepository_Expecter) Delete(ctx interface{}, templateURN interface{}) *TagTemplateRepository_Delete_Call { - return &TagTemplateRepository_Delete_Call{Call: _e.mock.On("Delete", ctx, templateURN)} -} - -func (_c *TagTemplateRepository_Delete_Call) Run(run func(ctx context.Context, templateURN string)) *TagTemplateRepository_Delete_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *TagTemplateRepository_Delete_Call) Return(_a0 error) *TagTemplateRepository_Delete_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagTemplateRepository_Delete_Call) RunAndReturn(run func(context.Context, string) error) *TagTemplateRepository_Delete_Call { - _c.Call.Return(run) - return _c -} - -// Read provides a mock function with given fields: ctx, templateURN -func (_m *TagTemplateRepository) Read(ctx context.Context, templateURN string) ([]tag.Template, error) { - ret := _m.Called(ctx, templateURN) - - var r0 []tag.Template - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) ([]tag.Template, error)); ok { - return rf(ctx, templateURN) - } - if rf, ok := ret.Get(0).(func(context.Context, string) []tag.Template); ok { - r0 = rf(ctx, templateURN) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]tag.Template) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, templateURN) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TagTemplateRepository_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read' -type TagTemplateRepository_Read_Call struct { - *mock.Call -} - -// Read is a helper method to define mock.On call -// - ctx context.Context -// - templateURN string -func (_e *TagTemplateRepository_Expecter) Read(ctx interface{}, templateURN interface{}) *TagTemplateRepository_Read_Call { - return &TagTemplateRepository_Read_Call{Call: _e.mock.On("Read", ctx, templateURN)} -} - -func (_c *TagTemplateRepository_Read_Call) Run(run func(ctx context.Context, templateURN string)) *TagTemplateRepository_Read_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *TagTemplateRepository_Read_Call) Return(_a0 []tag.Template, _a1 error) *TagTemplateRepository_Read_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *TagTemplateRepository_Read_Call) RunAndReturn(run func(context.Context, string) ([]tag.Template, error)) *TagTemplateRepository_Read_Call { - _c.Call.Return(run) - return _c -} - -// ReadAll provides a mock function with given fields: ctx -func (_m *TagTemplateRepository) ReadAll(ctx context.Context) ([]tag.Template, error) { - ret := _m.Called(ctx) - - var r0 []tag.Template - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) ([]tag.Template, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) []tag.Template); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]tag.Template) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TagTemplateRepository_ReadAll_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadAll' -type TagTemplateRepository_ReadAll_Call struct { - *mock.Call -} - -// ReadAll is a helper method to define mock.On call -// - ctx context.Context -func (_e *TagTemplateRepository_Expecter) ReadAll(ctx interface{}) *TagTemplateRepository_ReadAll_Call { - return &TagTemplateRepository_ReadAll_Call{Call: _e.mock.On("ReadAll", ctx)} -} - -func (_c *TagTemplateRepository_ReadAll_Call) Run(run func(ctx context.Context)) *TagTemplateRepository_ReadAll_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *TagTemplateRepository_ReadAll_Call) Return(_a0 []tag.Template, _a1 error) *TagTemplateRepository_ReadAll_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *TagTemplateRepository_ReadAll_Call) RunAndReturn(run func(context.Context) ([]tag.Template, error)) *TagTemplateRepository_ReadAll_Call { - _c.Call.Return(run) - return _c -} - -// Update provides a mock function with given fields: ctx, ns, templateURN, template -func (_m *TagTemplateRepository) Update(ctx context.Context, ns *namespace.Namespace, templateURN string, template *tag.Template) error { - ret := _m.Called(ctx, ns, templateURN, template) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string, *tag.Template) error); ok { - r0 = rf(ctx, ns, templateURN, template) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagTemplateRepository_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' -type TagTemplateRepository_Update_Call struct { - *mock.Call -} - -// Update is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - templateURN string -// - template *tag.Template -func (_e *TagTemplateRepository_Expecter) Update(ctx interface{}, ns interface{}, templateURN interface{}, template interface{}) *TagTemplateRepository_Update_Call { - return &TagTemplateRepository_Update_Call{Call: _e.mock.On("Update", ctx, ns, templateURN, template)} -} - -func (_c *TagTemplateRepository_Update_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, templateURN string, template *tag.Template)) *TagTemplateRepository_Update_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(string), args[3].(*tag.Template)) - }) - return _c -} - -func (_c *TagTemplateRepository_Update_Call) Return(_a0 error) *TagTemplateRepository_Update_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagTemplateRepository_Update_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, string, *tag.Template) error) *TagTemplateRepository_Update_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTNewTagTemplateRepository interface { - mock.TestingT - Cleanup(func()) -} - -// NewTagTemplateRepository creates a new instance of TagTemplateRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTagTemplateRepository(t mockConstructorTestingTNewTagTemplateRepository) *TagTemplateRepository { - mock := &TagTemplateRepository{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/tag/service.go b/core/tag/service.go deleted file mode 100644 index c0862f49..00000000 --- a/core/tag/service.go +++ /dev/null @@ -1,192 +0,0 @@ -package tag - -import ( - "context" - "errors" - "fmt" - "github.com/raystack/compass/core/namespace" - - "github.com/raystack/compass/core/tag/validator" -) - -// Service is a type that manages business process -type Service struct { - validator validator.Validator - repository TagRepository - templateService *TemplateService -} - -// Validate validates domain tag based on business requirement -func (s *Service) Validate(tag *Tag) error { - if tag == nil { - return errors.New("tag is nil") - } - - err := s.validator.Validate(*tag) - if err != nil { - err = ValidationError{err} - } - - return err -} - -// Create handles business process for create -func (s *Service) CreateTag(ctx context.Context, ns *namespace.Namespace, tag *Tag) error { - if err := s.Validate(tag); err != nil { - return err - } - template, err := s.templateService.GetTemplate(ctx, tag.TemplateURN) - if err != nil { - return fmt.Errorf("error finding template: %w", err) - } - if err := s.validateFieldIsMemberOfTemplate(*tag, template); err != nil { - return err - } - if err := s.validateRequiredFieldIsPassed(*tag, template); err != nil { - return err - } - if err := s.validateFieldValueIsValid(*tag, template); err != nil { - return err - } - if err := s.repository.Create(ctx, ns, tag); err != nil { - return err - } - - return nil -} - -// GetTagsByAssetID handles business process to get tags by its asset id -func (s *Service) GetTagsByAssetID(ctx context.Context, assetID string) ([]Tag, error) { - tag := Tag{AssetID: assetID} - return s.repository.Read(ctx, tag) -} - -// FindByAssetAndTemplate handles business process to get tags by its asset id and template id -func (s *Service) FindTagByAssetIDAndTemplateURN(ctx context.Context, assetID, templateURN string) (Tag, error) { - _, err := s.templateService.GetTemplate(ctx, templateURN) - if err != nil { - return Tag{}, err - } - listOfTag, err := s.repository.Read(ctx, Tag{AssetID: assetID, TemplateURN: templateURN}) - if err != nil { - return Tag{}, err - } - var output Tag - if len(listOfTag) == 0 { - return Tag{}, NotFoundError{AssetID: assetID, Template: templateURN} - } - - output = listOfTag[0] - return output, err -} - -// DeleteTag handles business process to delete a tag -func (s *Service) DeleteTag(ctx context.Context, assetID, templateURN string) error { - _, err := s.templateService.GetTemplate(ctx, templateURN) - if err != nil { - return fmt.Errorf("error finding template: %w", err) - } - if err := s.repository.Delete(ctx, Tag{ - AssetID: assetID, - TemplateURN: templateURN, - }); err != nil { - return err - } - return nil -} - -// Update handles business process for update -func (s *Service) UpdateTag(ctx context.Context, tag *Tag) error { - if err := s.Validate(tag); err != nil { - return err - } - template, err := s.templateService.GetTemplate(ctx, tag.TemplateURN) - if err != nil { - return TemplateNotFoundError{URN: tag.TemplateURN} - } - existingTags, err := s.repository.Read(ctx, Tag{ - AssetID: tag.AssetID, - TemplateURN: tag.TemplateURN, - }) - if err != nil { - return NotFoundError{AssetID: tag.AssetID, Template: tag.TemplateURN} - } - if len(existingTags) == 0 { - return NotFoundError{AssetID: tag.AssetID, Template: tag.TemplateURN} - } - - if err = s.validateFieldIsMemberOfTemplate(*tag, template); err != nil { - return err - } - if err := s.validateFieldValueIsValid(*tag, template); err != nil { - return err - } - if err := s.repository.Update(ctx, tag); err != nil { - return fmt.Errorf("error updating tag: %w", err) - } - return nil -} - -func (s *Service) validateFieldIsMemberOfTemplate(tag Tag, template Template) error { - fieldIsMemberOfTemplate := make(map[uint]bool) - for _, field := range template.Fields { - fieldIsMemberOfTemplate[field.ID] = true - } - for i, value := range tag.TagValues { - if !fieldIsMemberOfTemplate[value.FieldID] { - return buildFieldError( - fmt.Sprintf("fields[%d].id", i), - fmt.Sprintf("not part of template [%s]", - template.URN), - ) - } - } - return nil -} - -func (s *Service) validateRequiredFieldIsPassed(tag Tag, template Template) error { - passedFieldMap := make(map[uint]bool) - for _, value := range tag.TagValues { - if value.FieldValue != nil && value.FieldValue != "" { - passedFieldMap[value.FieldID] = true - } - } - for i, field := range template.Fields { - if field.Required && !passedFieldMap[field.ID] { - return buildFieldError( - fmt.Sprintf("fields[%d].id", i), fmt.Sprintf("required by template [%s]", template.URN), - ) - } - } - return nil -} - -func (s *Service) validateFieldValueIsValid(tag Tag, template Template) error { - domainFieldByID := make(map[uint]Field) - for _, field := range template.Fields { - domainFieldByID[field.ID] = field - } - for i, value := range tag.TagValues { - if value.FieldValue != nil && value.FieldValue != "" { - fieldValue := fmt.Sprintf("%v", value.FieldValue) - fieldID := value.FieldID - domainField := domainFieldByID[fieldID] - _, err := ParseTagValue(template.URN, domainField.ID, - domainField.DataType, fieldValue, domainField.Options, - ) - if err != nil { - return buildFieldError(fmt.Sprintf("fields[%d].value", i), err.Error()) - } - } - } - return nil -} - -// NewService initializes service tag -func NewService(repository TagRepository, templateService *TemplateService) *Service { - return &Service{ - validator: newValidator(), - repository: repository, - templateService: templateService, - } -} diff --git a/core/tag/service_test.go b/core/tag/service_test.go deleted file mode 100644 index 342a2ec4..00000000 --- a/core/tag/service_test.go +++ /dev/null @@ -1,617 +0,0 @@ -package tag_test - -import ( - "context" - "errors" - "fmt" - "github.com/raystack/compass/core/namespace" - "testing" - - "github.com/google/uuid" - "github.com/raystack/compass/core/tag" - "github.com/raystack/compass/core/tag/mocks" - "github.com/raystack/compass/core/tag/validator" - - "github.com/golang-module/carbon/v2" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/suite" -) - -type ServiceTestSuite struct { - suite.Suite - tagService *tag.Service - templateRepo *mocks.TagTemplateRepository - repository *mocks.TagRepository -} - -func (s *ServiceTestSuite) TestNewService() { - s.Run("should return service and nil if repository is not nil", func() { - repository := &mocks.TagRepository{} - templateService := tag.NewTemplateService(s.templateRepo) - actualService := tag.NewService(repository, templateService) - - s.NotNil(actualService) - }) -} - -func (s *ServiceTestSuite) Setup() { - s.repository = &mocks.TagRepository{} - s.templateRepo = &mocks.TagTemplateRepository{} - - templateService := tag.NewTemplateService(s.templateRepo) - s.tagService = tag.NewService(s.repository, templateService) -} - -func (s *ServiceTestSuite) TestValidate() { - repository := &mocks.TagRepository{} - templateService := tag.NewTemplateService(&mocks.TagTemplateRepository{}) - tagService := tag.NewService(repository, templateService) - - s.Run("should return error if asset id is empty", func() { - t := s.buildTag() - t.AssetID = "" - - expectedErrorMsg := "error with [asset_id : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "asset_id": "cannot be empty", - }, - } - - actualError := tagService.Validate(&t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if template URN is empty", func() { - t := s.buildTag() - t.TemplateURN = "" - - expectedErrorMsg := "error with [template_urn : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "template_urn": "cannot be empty", - }, - } - - actualError := tagService.Validate(&t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if tag values are nil", func() { - t := s.buildTag() - t.TemplateURN = "" - - expectedErrorMsg := "error with [template_urn : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "template_urn": "cannot be empty", - }, - } - - actualError := tagService.Validate(&t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if tag values contains zero element", func() { - t := s.buildTag() - t.TagValues = []tag.TagValue{} - - expectedErrorMsg := "error with [tag_values : must be at least 1]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "tag_values": "must be at least 1", - }, - } - - actualError := tagService.Validate(&t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if tag value field ID is zero", func() { - t := s.buildTag() - t.TagValues[1].FieldID = 0 - - expectedErrorMsg := "error with [tag_values[1].field_id : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "tag_values[1].field_id": "cannot be empty", - }, - } - - actualError := tagService.Validate(&t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if tag value field value is nil", func() { - t := s.buildTag() - t.TagValues[1].FieldValue = nil - - expectedErrorMsg := "error with [tag_values[1].field_value : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "tag_values[1].field_value": "cannot be empty", - }, - } - - actualError := tagService.Validate(&t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) -} - -func (s *ServiceTestSuite) TestCreate() { - ctx := context.TODO() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - s.Run("should return error if value validations return error", func() { - s.Setup() - t := s.buildTag() - t.AssetID = "" - - expectedErrorMsg := "error with [asset_id : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "asset_id": "cannot be empty", - }, - } - - actualError := s.tagService.CreateTag(ctx, ns, &t) - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if error retrieving template", func() { - s.Setup() - t := s.buildTag() - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return(nil, errors.New("random error")) - - err := s.tagService.CreateTag(ctx, ns, &t) - s.Error(err) - }) - - s.Run("should return error if specified field is not part of the template", func() { - s.Setup() - t := s.buildTag() - t.TagValues[0].FieldID = 50 - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - - expectedErrorMsg := "error with [fields[0].id : not part of template [governance_policy]]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[0].id": fmt.Sprintf("not part of template [%s]", t.TemplateURN), - }, - } - - actualError := s.tagService.CreateTag(ctx, ns, &t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if required field is not passed", func() { - s.Setup() - t := s.buildTag() - t.TagValues = t.TagValues[:1] - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - - expectedErrorMsg := "error with [fields[1].id : required by template [governance_policy]]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[1].id": fmt.Sprintf("required by template [%s]", t.TemplateURN), - }, - } - - actualError := s.tagService.CreateTag(ctx, ns, &t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - - }) - - s.Run("should return error if passed value is not parsable", func() { - t := s.buildTag() - t.TagValues[1].FieldValue = "hello" - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - - expectedErrorMsg := "error with [fields[1].value : template [governance_policy] on field [2] should be boolean]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[1].value": fmt.Sprintf("template [%s] on field [%d] should be boolean", t.TemplateURN, 2), - }, - } - - actualError := s.tagService.CreateTag(ctx, ns, &t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return repository error if repository met error", func() { - s.Setup() - t := s.buildTag() - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Create(mock.Anything, ns, &t).Return(errors.New("random error")) - - err := s.tagService.CreateTag(ctx, ns, &t) - s.Error(err) - }) - - s.Run("should return repository nil if repository not error", func() { - s.Setup() - t := s.buildTag() - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Create(mock.Anything, ns, &t).Return(nil) - - actualError := s.tagService.CreateTag(ctx, ns, &t) - - s.NoError(actualError) - }) -} - -func (s *ServiceTestSuite) TestGetByAsset() { - ctx := context.TODO() - - s.Run("should return tags and error based on the repository", func() { - s.Setup() - t := s.buildTag() - template := s.buildTemplate() - expectedTag := []tag.Tag{t} - - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Read(mock.Anything, tag.Tag{ - AssetID: t.AssetID, - }).Return(expectedTag, nil) - - actualTag, actualError := s.tagService.GetTagsByAssetID(ctx, t.AssetID) - - s.EqualValues(expectedTag, actualTag) - s.NoError(actualError) - }) -} - -func (s *ServiceTestSuite) TestFindByAssetAndTemplate() { - ctx := context.TODO() - - s.Run("should return error if error retrieving template", func() { - s.Setup() - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return(nil, errors.New("random error")) - - _, err := s.tagService.FindTagByAssetIDAndTemplateURN(ctx, uuid.NewString(), template.URN) - s.Error(err) - }) - - s.Run("should return nil and error if tag is not found", func() { - s.Setup() - var assetID = uuid.NewString() - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Read(mock.Anything, tag.Tag{ - AssetID: assetID, - TemplateURN: template.URN, - }).Return([]tag.Tag{}, nil) - - _, err := s.tagService.FindTagByAssetIDAndTemplateURN(ctx, assetID, template.URN) - s.Equal(err.Error(), tag.NotFoundError{ - AssetID: assetID, - Template: template.URN, - }.Error()) - }) - - s.Run("should return tag and nil if tag is found", func() { - s.Setup() - t := s.buildTag() - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Read(mock.Anything, tag.Tag{ - AssetID: t.AssetID, - TemplateURN: t.TemplateURN, - }).Return([]tag.Tag{t}, nil) - - expectedTag := t - - actualTag, actualError := s.tagService.FindTagByAssetIDAndTemplateURN(ctx, t.AssetID, template.URN) - - s.EqualValues(expectedTag, actualTag) - s.NoError(actualError) - }) -} - -func (s *ServiceTestSuite) TestUpdate() { - ctx := context.TODO() - - s.Run("should return error if value validations return error", func() { - s.Setup() - t := s.buildTag() - t.AssetID = "" - - expectedErrorMsg := "error with [asset_id : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "asset_id": "cannot be empty", - }, - } - actualError := s.tagService.UpdateTag(ctx, &t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if error retrieving template", func() { - s.Setup() - t := s.buildTag() - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return(nil, errors.New("random error")) - - err := s.tagService.UpdateTag(ctx, &t) - s.Error(err) - }) - - s.Run("should return not found error if tag could not be found", func() { - s.Setup() - t := s.buildTag() - template := s.buildTemplate() - - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Read(mock.Anything, tag.Tag{ - AssetID: t.AssetID, - TemplateURN: t.TemplateURN, - }).Return([]tag.Tag{}, nil) - - err := s.tagService.UpdateTag(ctx, &t) - - s.Error(err) - s.ErrorIs(err, tag.NotFoundError{AssetID: t.AssetID, Template: t.TemplateURN}) - }) - - s.Run("should return error if specified field is not part of the template", func() { - s.Setup() - t := s.buildTag() - t.TagValues[0].FieldID = 50 - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Read(mock.Anything, tag.Tag{ - AssetID: t.AssetID, - TemplateURN: t.TemplateURN, - }).Return([]tag.Tag{t}, nil) - - expectedErrorMsg := "error with [fields[0].id : not part of template [governance_policy]]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[0].id": fmt.Sprintf("not part of template [%s]", t.TemplateURN), - }, - } - - actualError := s.tagService.UpdateTag(ctx, &t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if passed value is not parsable", func() { - t := s.buildTag() - t.TagValues[1].FieldValue = "hello" - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Read(mock.Anything, tag.Tag{ - AssetID: t.AssetID, - TemplateURN: t.TemplateURN, - }).Return([]tag.Tag{t}, nil) - - expectedErrorMsg := "error with [fields[1].value : template [governance_policy] on field [2] should be boolean]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[1].value": fmt.Sprintf("template [%s] on field [%d] should be boolean", t.TemplateURN, 2), - }, - } - - actualError := s.tagService.UpdateTag(ctx, &t) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return repository error if repository met error", func() { - s.Setup() - t := s.buildTag() - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Read(mock.Anything, tag.Tag{ - AssetID: t.AssetID, - TemplateURN: t.TemplateURN, - }).Return([]tag.Tag{t}, nil) - s.repository.EXPECT().Update(mock.Anything, &t).Return(errors.New("random error")) - - err := s.tagService.UpdateTag(ctx, &t) - s.Error(err) - }) - - s.Run("should return repository nil if repository not error", func() { - s.Setup() - t := s.buildTag() - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Read(mock.Anything, tag.Tag{ - AssetID: t.AssetID, - TemplateURN: t.TemplateURN, - }).Return([]tag.Tag{t}, nil) - s.repository.EXPECT().Update(mock.Anything, &t).Return(nil) - - actualError := s.tagService.UpdateTag(ctx, &t) - - s.NoError(actualError) - }) -} - -func (s *ServiceTestSuite) TestDelete() { - ctx := context.TODO() - - s.Run("should return error if error retrieving template", func() { - s.Setup() - - templateURN := "template-urn" - s.templateRepo.EXPECT().Read(mock.Anything, templateURN).Return(nil, errors.New("random error")) - - err := s.tagService.DeleteTag(ctx, uuid.NewString(), templateURN) - s.Error(err) - }) - - s.Run("should return error if repository error", func() { - s.Setup() - assetID := uuid.NewString() - - template := s.buildTemplate() - s.templateRepo.EXPECT().Read(mock.Anything, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Delete(mock.Anything, tag.Tag{ - AssetID: assetID, - TemplateURN: template.URN, - }).Return(errors.New("random error")) - - err := s.tagService.DeleteTag(ctx, assetID, template.URN) - s.Error(err) - }) -} - -func (s *ServiceTestSuite) buildTemplate() tag.Template { - return tag.Template{ - URN: "governance_policy", - DisplayName: "Governance Policy", - Description: "Template that is mandatory to be used.", - Fields: []tag.Field{ - { - ID: 1, - URN: "classification", - DisplayName: "classification", - Description: "The classification of this asset", - DataType: "enumerated", - Required: true, - Options: []string{"Public", "Restricted"}, - }, - { - ID: 2, - URN: "is_encrypted", - DisplayName: "Is Encrypted?", - Description: "Specify whether this asset is encrypted or not.", - DataType: "boolean", - Required: true, - }, - { - ID: 3, - URN: "owner", - DisplayName: "name of owner", - Description: "name of owner of this asset", - DataType: "string", - Required: false, - }, - { - ID: 4, - URN: "date_created", - DisplayName: "date of creation?", - Description: "date when asset was created", - DataType: "datetime", - Required: false, - }, - { - ID: 5, - URN: "no_of_records", - DisplayName: "no of records", - Description: "record count for the asset", - DataType: "double", - Required: false, - }, - }, - } -} - -func (s *ServiceTestSuite) buildTag() tag.Tag { - return tag.Tag{ - AssetID: uuid.NewString(), - TemplateURN: "governance_policy", - TemplateDisplayName: "Governance Policy", - TemplateDescription: "Template that is mandatory to be used.", - TagValues: []tag.TagValue{ - { - FieldID: 1, - FieldValue: "Public", - FieldURN: "classification", - FieldDisplayName: "classification", - FieldDescription: "The classification of this asset", - FieldDataType: "enumerated", - FieldRequired: true, - FieldOptions: []string{"Public", "Restricted"}, - }, - { - FieldID: 2, - FieldValue: true, - FieldURN: "is_encrypted", - FieldDisplayName: "Is Encrypted?", - FieldDescription: "Specify whether this asset is encrypted or not.", - FieldDataType: "boolean", - FieldRequired: true, - }, - { - FieldID: 3, - FieldValue: "john doe", - FieldURN: "owner", - FieldDisplayName: "name of owner", - FieldDescription: "name of owner of this asset", - FieldDataType: "string", - FieldRequired: false, - }, - { - FieldID: 4, - FieldValue: carbon.Parse("2020-12-31").ToRfc3339String(), - FieldURN: "date_created", - FieldDisplayName: "date of creation?", - FieldDescription: "date when asset was created", - FieldDataType: "datetime", - FieldRequired: false, - }, - { - FieldID: 5, - FieldValue: "91.0", - FieldURN: "no_of_records", - FieldDisplayName: "no of records", - FieldDescription: "record count for the asset", - FieldDataType: "double", - FieldRequired: false, - }, - }, - } -} - -func TestService(t *testing.T) { - suite.Run(t, &ServiceTestSuite{}) -} diff --git a/core/tag/tag.go b/core/tag/tag.go deleted file mode 100644 index 9eb117ed..00000000 --- a/core/tag/tag.go +++ /dev/null @@ -1,39 +0,0 @@ -package tag - -//go:generate mockery --name=TagRepository -r --case underscore --with-expecter --structname TagRepository --filename tag_repository.go --output=./mocks -import ( - "context" - "github.com/raystack/compass/core/namespace" - "time" -) - -// TagRepository is a contract to communicate with the primary store -type TagRepository interface { - Create(ctx context.Context, ns *namespace.Namespace, tag *Tag) error - Read(ctx context.Context, filter Tag) ([]Tag, error) - Update(ctx context.Context, tag *Tag) error - Delete(ctx context.Context, filter Tag) error -} - -// Tag is the tag to be managed -type Tag struct { - AssetID string `json:"asset_id" validate:"required"` - TemplateURN string `json:"template_urn" validate:"required"` - TagValues []TagValue `json:"tag_values" validate:"required,min=1,dive"` - TemplateDisplayName string `json:"template_display_name"` - TemplateDescription string `json:"template_description"` -} - -// TagValue is one of the value for a tag -type TagValue struct { - FieldID uint `json:"field_id" validate:"required"` - FieldValue interface{} `json:"field_value" validate:"required"` - FieldURN string `json:"field_urn"` - FieldDisplayName string `json:"field_display_name"` - FieldDescription string `json:"field_description"` - FieldDataType string `json:"field_data_type"` - FieldOptions []string `json:"field_options"` - FieldRequired bool `json:"field_required"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` -} diff --git a/core/tag/tag_template.go b/core/tag/tag_template.go deleted file mode 100644 index 06f9efa9..00000000 --- a/core/tag/tag_template.go +++ /dev/null @@ -1,41 +0,0 @@ -package tag - -//go:generate mockery --name=TagTemplateRepository -r --case underscore --with-expecter --structname TagTemplateRepository --filename tag_template_repository.go --output=./mocks - -import ( - "context" - "github.com/raystack/compass/core/namespace" - "time" -) - -// TagTemplateRepository is a contract to communicate with the primary store -type TagTemplateRepository interface { - Create(ctx context.Context, ns *namespace.Namespace, template *Template) error - Read(ctx context.Context, templateURN string) ([]Template, error) - ReadAll(ctx context.Context) ([]Template, error) - Update(ctx context.Context, ns *namespace.Namespace, templateURN string, template *Template) error - Delete(ctx context.Context, templateURN string) error -} - -// Template is a template of a tag for a resource -type Template struct { - URN string `json:"urn" validate:"required"` - DisplayName string `json:"display_name" validate:"required"` - Description string `json:"description" validate:"required"` - Fields []Field `json:"fields" validate:"required,min=1,dive"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` -} - -// Field is a field for a single template -type Field struct { - ID uint `json:"id"` - URN string `json:"urn" validate:"required"` - DisplayName string `json:"display_name" validate:"required"` - Description string `json:"description" validate:"required"` - DataType string `json:"data_type" validate:"oneof=string double boolean enumerated datetime"` - Options []string `json:"options"` - Required bool `json:"required"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` -} diff --git a/core/tag/tag_template_service.go b/core/tag/tag_template_service.go deleted file mode 100644 index cfa8f3e5..00000000 --- a/core/tag/tag_template_service.go +++ /dev/null @@ -1,144 +0,0 @@ -package tag - -import ( - "context" - "errors" - "fmt" - "github.com/raystack/compass/core/namespace" - - "github.com/raystack/compass/core/tag/validator" -) - -// TemplateService is a type of service that manages business process -type TemplateService struct { - validator validator.Validator - repository TagTemplateRepository -} - -// Validate validates domain template based on the business rule -func (s *TemplateService) Validate(template Template) error { - err := s.validator.Validate(template) - if err != nil { - err = ValidationError{err} - } - - return err -} - -// CreateTemplate handles create business operation for template -func (s *TemplateService) CreateTemplate(ctx context.Context, ns *namespace.Namespace, template *Template) error { - if template == nil { - return errors.New("template is nil") - } - err := s.Validate(*template) - if err != nil { - return err - } - - templateAssets, err := s.repository.Read(ctx, template.URN) - if err != nil { - return fmt.Errorf("error checking template existence: %w", err) - } - if len(templateAssets) > 0 { - return DuplicateTemplateError{URN: template.URN} - } - - err = s.repository.Create(ctx, ns, template) - if err != nil { - return fmt.Errorf("error creating template: %w", err) - } - - return nil -} - -// GetTemplates handles read business operation for template -func (s *TemplateService) GetTemplates(ctx context.Context, templateURN string) ([]Template, error) { - if templateURN == "" { - output, err := s.repository.ReadAll(ctx) - if err != nil { - return nil, fmt.Errorf("error fetching templates: %w", err) - } - return output, nil - } - output, err := s.repository.Read(ctx, templateURN) - if err != nil { - return nil, fmt.Errorf("error fetching templates: %w", err) - } - return output, nil -} - -// UpdateTemplate handles update business operation for template -func (s *TemplateService) UpdateTemplate(ctx context.Context, ns *namespace.Namespace, templateURN string, template *Template) error { - if template == nil { - return errors.New("template is nil") - } - err := s.Validate(*template) - if err != nil { - return err - } - templateAssets, err := s.repository.Read(ctx, templateURN) - if err != nil { - return fmt.Errorf("error checking template existence: %w", err) - } - if len(templateAssets) == 0 { - return TemplateNotFoundError{URN: templateURN} - } - - // check for duplication - templateFromDB := templateAssets[0] - isFieldIDPartOfTemplateMap := make(map[uint]bool) - fieldURNToIDMap := make(map[string]uint) - for _, f := range templateFromDB.Fields { - isFieldIDPartOfTemplateMap[f.ID] = true - fieldURNToIDMap[f.URN] = f.ID - } - for i, f := range template.Fields { - if !isFieldIDPartOfTemplateMap[f.ID] { - return buildFieldError( - fmt.Sprintf("fields.[%d].id", i), - fmt.Sprintf("[%d] is not part of the template", f.ID), - ) - } - if fieldURNToIDMap[f.URN] != f.ID { - return buildFieldError( - fmt.Sprintf("fields.[%d].urn", i), - fmt.Sprintf("[%s] already exists within the template", f.URN), - ) - } - } - - err = s.repository.Update(ctx, ns, templateURN, template) - if err != nil { - return fmt.Errorf("error updating template: %w", err) - } - return nil -} - -// GetTemplate handles request to get template by urn -func (s *TemplateService) GetTemplate(ctx context.Context, urn string) (Template, error) { - listOfDomainTemplate, err := s.repository.Read(ctx, urn) - if err != nil { - return Template{}, fmt.Errorf("error reading repository: %w", err) - } - if len(listOfDomainTemplate) == 0 { - return Template{}, TemplateNotFoundError{URN: urn} - } - return listOfDomainTemplate[0], nil -} - -// DeleteTemplate handles request to delete template by urn -func (s *TemplateService) DeleteTemplate(ctx context.Context, urn string) error { - err := s.repository.Delete(ctx, urn) - if err != nil { - return fmt.Errorf("error deleting template: %w", err) - } - return nil -} - -// NewTemplateService initializes service template service -func NewTemplateService(r TagTemplateRepository) *TemplateService { - return &TemplateService{ - validator: newTemplateValidator(), - repository: r, - } -} diff --git a/core/tag/tag_template_service_test.go b/core/tag/tag_template_service_test.go deleted file mode 100644 index 17f2ca85..00000000 --- a/core/tag/tag_template_service_test.go +++ /dev/null @@ -1,604 +0,0 @@ -package tag_test - -import ( - "context" - "errors" - "fmt" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "testing" - "time" - - "github.com/raystack/compass/core/tag" - "github.com/raystack/compass/core/tag/mocks" - "github.com/raystack/compass/core/tag/validator" - - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/suite" -) - -type TemplateServiceTestSuite struct { - suite.Suite - service *tag.TemplateService - repository *mocks.TagTemplateRepository -} - -func (s *TemplateServiceTestSuite) TestNewTemplateService() { - s.Run("should return service and nil no error found", func() { - r := &mocks.TagTemplateRepository{} - - actualService := tag.NewTemplateService(r) - s.NotNil(actualService) - }) -} - -func (s *TemplateServiceTestSuite) Setup() { - s.repository = &mocks.TagTemplateRepository{} - var err error - s.service = tag.NewTemplateService(s.repository) - s.Require().NoError(err) -} - -func (s *TemplateServiceTestSuite) TestValidate() { - r := &mocks.TagTemplateRepository{} - service := tag.NewTemplateService(r) - - s.Run("should return error if urn is empty", func() { - template := s.buildTemplate() - template.URN = "" - - expectedErrorMsg := "error with [urn : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "urn": "cannot be empty", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if display name is empty", func() { - template := s.buildTemplate() - template.DisplayName = "" - - expectedErrorMsg := "error with [display_name : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "display_name": "cannot be empty", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if description is empty", func() { - template := s.buildTemplate() - template.Description = "" - - expectedErrorMsg := "error with [description : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "description": "cannot be empty", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if fields is nil", func() { - template := s.buildTemplate() - template.Fields = nil - - expectedErrorMsg := "error with [fields : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields": "cannot be empty", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if fields is empty", func() { - template := s.buildTemplate() - template.Fields = []tag.Field{} - - expectedErrorMsg := "error with [fields : must be at least 1]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields": "must be at least 1", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if fields urn is empty", func() { - template := s.buildTemplate() - template.Fields[0].URN = "" - - expectedErrorMsg := "error with [fields[0].urn : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[0].urn": "cannot be empty", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if fields display name is empty", func() { - template := s.buildTemplate() - template.Fields[0].DisplayName = "" - - expectedErrorMsg := "error with [fields[0].display_name : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[0].display_name": "cannot be empty", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if fields description is empty", func() { - template := s.buildTemplate() - template.Fields[0].Description = "" - - expectedErrorMsg := "error with [fields[0].description : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[0].description": "cannot be empty", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if fields data type is invalid", func() { - template := s.buildTemplate() - template.Fields[0].DataType = "Random_Type" - - expectedErrorMsg := "error with [fields[0].data_type : data_type must be one of [string double boolean enumerated datetime]]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[0].data_type": "data_type must be one of [string double boolean enumerated datetime]", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if fields data type enumerated but options nil", func() { - template := s.buildTemplate() - template.Fields[0].Options = nil - - expectedErrorMsg := "error with [fields[0].options : cannot be empty with data_type [enumerated]]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[0].options": "cannot be empty with data_type [enumerated]", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if fields data type enumerated but options empty", func() { - template := s.buildTemplate() - template.Fields[0].Options = []string{} - - expectedErrorMsg := "error with [fields[0].options : cannot be empty with data_type [enumerated]]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[0].options": "cannot be empty with data_type [enumerated]", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if fields data type enumerated but options contains empty", func() { - template := s.buildTemplate() - template.Fields[0].Options = []string{ - "Team Owner", "", "Governor Email", - } - - expectedErrorMsg := "error with [fields[0].options : cannot contain empty element]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields[0].options": "cannot contain empty element", - }, - } - - actualError := service.Validate(template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return nil if fields data type not enumerated and options empty", func() { - template := s.buildTemplate() - template.Fields[0].Options = nil - template.Fields[0].DataType = "string" - - actualError := service.Validate(template) - - s.NoError(actualError) - }) -} - -func (s *TemplateServiceTestSuite) TestCreate() { - ctx := context.TODO() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - s.Run("should return error if domain template is nil", func() { - s.Setup() - - err := s.service.CreateTemplate(ctx, ns, nil) - s.Error(err) - }) - - s.Run("should return error if error encountered during validation", func() { - s.Setup() - template := s.buildTemplate() - template.Description = "" - - expectedErrorMsg := "error with [description : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "description": "cannot be empty", - }, - } - - actualError := s.service.CreateTemplate(ctx, ns, &template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if error encountered when checking for duplication", func() { - s.Setup() - template := s.buildTemplate() - s.repository.EXPECT().Read(ctx, template.URN).Return(nil, errors.New("unexpected error")) - - err := s.service.CreateTemplate(ctx, ns, &template) - s.Error(err) - }) - - s.Run("should return error if template specified by the urn already exists", func() { - s.Setup() - template := s.buildTemplate() - s.repository.EXPECT().Read(ctx, template.URN).Return([]tag.Template{{}}, nil) - - err := s.service.CreateTemplate(ctx, ns, &template) - s.Equal(tag.DuplicateTemplateError{URN: template.URN}, err) - }) - - s.Run("should return error if found error during create", func() { - s.Setup() - now := time.Now() - originalDomainTemplate := s.buildTemplate() - referenceDomainTemplate := s.buildTemplate() - referenceDomainTemplate.CreatedAt = now - - s.repository.EXPECT().Read(ctx, originalDomainTemplate.URN).Return([]tag.Template{}, nil) - s.repository.EXPECT().Create(ctx, ns, &originalDomainTemplate).Return(errors.New("unexpected error")) - - err := s.service.CreateTemplate(ctx, ns, &originalDomainTemplate) - s.Error(err) - }) - - s.Run("should return nil if success in create", func() { - s.Setup() - now := time.Now() - originalDomainTemplate := s.buildTemplate() - referenceDomainTemplate := s.buildTemplate() - referenceDomainTemplate.CreatedAt = now - - s.repository.EXPECT().Read(ctx, originalDomainTemplate.URN).Return([]tag.Template{}, nil) - s.repository.EXPECT().Create(ctx, ns, &originalDomainTemplate).Run(func(ctx context.Context, ns *namespace.Namespace, template *tag.Template) { - template.CreatedAt = now - }).Return(nil) - - actualError := s.service.CreateTemplate(ctx, ns, &originalDomainTemplate) - - s.NoError(actualError) - s.EqualValues(referenceDomainTemplate, originalDomainTemplate) - }) -} - -func (s *TemplateServiceTestSuite) TestIndex() { - ctx := context.TODO() - s.Run("should return nil and error if encountered unexpected error during read", func() { - s.Setup() - template := s.buildTemplate() - s.repository.EXPECT().Read(ctx, template.URN).Return(nil, errors.New("unexpected error")) - - _, err := s.service.GetTemplates(ctx, template.URN) - s.Error(err) - }) - - s.Run("should return nil and error for error in readall with empty urn", func() { - s.Setup() - s.repository.EXPECT().ReadAll(ctx).Return(nil, errors.New("unexpected error")) - - _, err := s.service.GetTemplates(ctx, "") - s.Error(err) - }) - - s.Run("should return domain templates and nil if no error found", func() { - s.Setup() - template := s.buildTemplate() - s.repository.EXPECT().Read(ctx, template.URN).Return([]tag.Template{template}, nil) - - expectedTemplate := []tag.Template{template} - - actualTemplate, actualError := s.service.GetTemplates(ctx, template.URN) - - s.EqualValues(expectedTemplate, actualTemplate) - s.NoError(actualError) - }) - - s.Run("should return domain templates and nil if no error found with empty urn", func() { - s.Setup() - template := s.buildTemplate() - s.repository.EXPECT().ReadAll(ctx).Return([]tag.Template{template}, nil) - - expectedTemplate := []tag.Template{template} - - actualTemplate, actualError := s.service.GetTemplates(ctx, "") - - s.EqualValues(expectedTemplate, actualTemplate) - s.NoError(actualError) - }) -} - -func (s *TemplateServiceTestSuite) TestUpdate() { - ctx := context.TODO() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - s.Run("should return error if domain template is nil", func() { - s.Setup() - var template *tag.Template = nil - - err := s.service.UpdateTemplate(ctx, ns, "", template) - s.EqualError(err, "template is nil") - }) - - s.Run("should return error if error encountered during validation", func() { - s.Setup() - template := s.buildTemplate() - template.Description = "" - - expectedErrorMsg := "error with [description : cannot be empty]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "description": "cannot be empty", - }, - } - - actualError := s.service.UpdateTemplate(ctx, ns, template.URN, &template) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if encountered unexpected error during read for existence", func() { - s.Setup() - template := s.buildTemplate() - - s.repository.EXPECT().Read(ctx, template.URN).Return(nil, errors.New("unexpected error")) - - err := s.service.UpdateTemplate(ctx, ns, template.URN, &template) - s.Error(err) - }) - - s.Run("should return error if field is not part of template", func() { - s.Setup() - template := s.buildTemplate() - newTemplate := s.buildTemplate() - newTemplate.Fields[0].ID = 99 - - s.repository.EXPECT().Read(ctx, newTemplate.URN).Return([]tag.Template{template}, nil) - - expectedErrorMsg := "error with [fields.[0].id : [99] is not part of the template]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields.[0].id": fmt.Sprintf("[%d] is not part of the template", - newTemplate.Fields[0].ID, - ), - }, - } - - actualError := s.service.UpdateTemplate(ctx, ns, newTemplate.URN, &newTemplate) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if trying to update field urn that already exist", func() { - s.Setup() - template := s.buildTemplate() - newTemplate := s.buildTemplate() - newTemplate.Fields[0].URN = template.Fields[1].URN - - s.repository.EXPECT().Read(ctx, newTemplate.URN).Return([]tag.Template{template}, nil) - - expectedErrorMsg := "error with [fields.[0].urn : [team_custodianr] already exists within the template]" - expectedFieldError := tag.ValidationError{ - validator.FieldError{ - "fields.[0].urn": fmt.Sprintf("[%s] already exists within the template", - newTemplate.Fields[0].URN, - ), - }, - } - - actualError := s.service.UpdateTemplate(ctx, ns, template.URN, &newTemplate) - - s.EqualError(actualError, expectedErrorMsg) - s.EqualValues(expectedFieldError, actualError.(tag.ValidationError)) - }) - - s.Run("should return error if found error during update", func() { - s.Setup() - template := s.buildTemplate() - newTemplate := s.buildTemplate() - - s.repository.EXPECT().Read(ctx, newTemplate.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Update(ctx, ns, newTemplate.URN, &newTemplate).Return(errors.New("unexpected error")) - - err := s.service.UpdateTemplate(ctx, ns, template.URN, &newTemplate) - s.Error(err) - }) - - s.Run("should return nil if repository update is success", func() { - s.Setup() - template := s.buildTemplate() - newTemplate := s.buildTemplate() - - s.repository.EXPECT().Read(ctx, template.URN).Return([]tag.Template{template}, nil) - s.repository.EXPECT().Update(ctx, ns, newTemplate.URN, &newTemplate).Run(func(ctx context.Context, ns *namespace.Namespace, templateURN string, template *tag.Template) { - template.UpdatedAt = time.Now() - }).Return(nil) - - actualError := s.service.UpdateTemplate(ctx, ns, template.URN, &newTemplate) - s.NoError(actualError) - }) -} - -func (s *TemplateServiceTestSuite) TestFind() { - ctx := context.TODO() - - s.Run("should return empty and error if found unexpected error", func() { - s.Setup() - var urn = "sample-urn" - s.repository.EXPECT().Read(ctx, urn).Return(nil, errors.New("unexpected error")) - - _, err := s.service.GetTemplate(ctx, urn) - s.Error(err) - }) - - s.Run("should return not found error if template is not found", func() { - s.Setup() - var urn = "sample-urn" - s.repository.EXPECT().Read(ctx, urn).Return([]tag.Template{}, nil) - - _, err := s.service.GetTemplate(ctx, urn) - s.Error(err) - s.Equal(err.Error(), tag.TemplateNotFoundError{URN: urn}.Error()) - }) - - s.Run("should return domain template and nil if record is found", func() { - s.Setup() - var urn = "sample-urn" - template := s.buildTemplate() - s.repository.EXPECT().Read(ctx, urn).Return([]tag.Template{template}, nil) - - expectedTemplate := template - - actualTemplate, actualError := s.service.GetTemplate(ctx, urn) - - s.EqualValues(expectedTemplate, actualTemplate) - s.NoError(actualError) - }) -} - -func (s *TemplateServiceTestSuite) TestDelete() { - ctx := context.TODO() - - s.Run("should return error if encountered unexpected error during delete", func() { - s.Setup() - var urn = "sample-urn" - s.repository.EXPECT().Delete(ctx, mock.Anything).Return(errors.New("unexpected error")) - - actualError := s.service.DeleteTemplate(ctx, urn) - - s.Error(actualError) - s.EqualValues("error deleting template: unexpected error", actualError.Error()) - }) - - s.Run("should return delete result from repository", func() { - s.Setup() - var urn = "sample-urn" - s.repository.EXPECT().Delete(ctx, mock.Anything).Return(nil).Once() - s.repository.EXPECT().Delete(ctx, mock.Anything).Return(errors.New("unexpected error")).Once() - - actualError1 := s.service.DeleteTemplate(ctx, urn) - actualError2 := s.service.DeleteTemplate(ctx, urn) - - s.NoError(actualError1) - s.Error(actualError2) - }) -} - -func (s *TemplateServiceTestSuite) buildTemplate() tag.Template { - return tag.Template{ - URN: "governance_policy", - DisplayName: "Governance Policy", - Description: "Template that is mandatory to be used.", - Fields: []tag.Field{ - { - ID: 1, - URN: "team_owner", - DisplayName: "Team Owner", - Description: "Owner of the resource.", - DataType: "enumerated", - Required: true, - Options: []string{"PIC", "Escalated"}, - }, - { - ID: 2, - URN: "team_custodianr", - DisplayName: "Team Custodian", - Description: "Custodian of the resource.", - DataType: "string", - Required: false, - }, - }, - } -} - -func TestTemplateService(t *testing.T) { - suite.Run(t, &TemplateServiceTestSuite{}) -} diff --git a/core/tag/utils.go b/core/tag/utils.go deleted file mode 100644 index f9d7dffd..00000000 --- a/core/tag/utils.go +++ /dev/null @@ -1,64 +0,0 @@ -package tag - -import ( - "fmt" - "strconv" - "strings" - "time" - - "github.com/raystack/compass/core/tag/validator" -) - -func buildFieldError(key string, message string) error { - return ValidationError{ - validator.FieldError{ - key: message, - }, - } -} - -func ParseTagValue(templateURN string, fieldID uint, - dataType string, tagValue string, options []string) (interface{}, error, -) { - if tagValue == "" { - return nil, nil - } - var output interface{} - var err error - switch dataType { - case "double": - output, err = strconv.ParseFloat(tagValue, 64) - if err != nil { - err = fmt.Errorf("template [%s] on field [%d] should be double", templateURN, fieldID) - } - case "boolean": - output, err = strconv.ParseBool(tagValue) - if err != nil { - err = fmt.Errorf("template [%s] on field [%d] should be boolean", templateURN, fieldID) - } - case "enumerated": - isValueValid := false - for _, opt := range options { - if tagValue == opt { - isValueValid = true - output = opt - break - } - } - if !isValueValid { - err = fmt.Errorf("template [%s] on field [%d] should be one of (%s)", - templateURN, fieldID, strings.Join(options, ", "), - ) - } - case "datetime": - output, err = time.Parse(time.RFC3339, tagValue) - if err != nil { - err = fmt.Errorf("template [%s] on field [%d] should follow RFC3339", - templateURN, fieldID, - ) - } - case "string": - output = tagValue - } - return output, err -} diff --git a/core/tag/validator.go b/core/tag/validator.go deleted file mode 100644 index ae1a6054..00000000 --- a/core/tag/validator.go +++ /dev/null @@ -1,107 +0,0 @@ -package tag - -import ( - "fmt" - - ut "github.com/go-playground/universal-translator" - v "github.com/go-playground/validator/v10" - "github.com/raystack/compass/core/tag/validator" -) - -// newValidator initializes validator for tag -func newValidator() validator.Validator { - v, err := validator.NewBuilder(). - WithTranslations([]validator.Translation{ - { - Tag: "required", - Message: "cannot be empty", - Override: true, - }, - { - Tag: "min", - Message: "must be at least {0}", - Override: true, - TranslationFunc: func(t ut.Translator, fe v.FieldError) string { - output, _ := t.T(fe.Tag(), fe.Param()) - return output - }, - }, - }). - Build() - if err != nil { - panic(err) - } - - return v -} - -// newTemplateValidator initializes validator for tag template -func newTemplateValidator() validator.Validator { - v, err := validator.NewBuilder(). - WithStructValidations([]validator.StructValidation{ - { - Type: Template{}, - Func: func(sl v.StructLevel) { - template, ok := sl.Current().Interface().(Template) - if !ok { - sl.ReportError(nil, "struct", "", "is_not_a_template", "") - } - - for i, field := range template.Fields { - if field.DataType == "enumerated" { - if len(field.Options) == 0 { - sl.ReportError( - nil, fmt.Sprintf("fields[%d].options", i), "", "enumerated_restricted", "", - ) - } - for _, opt := range field.Options { - if opt == "" { - sl.ReportError( - nil, fmt.Sprintf("fields[%d].options", i), "", "element_not_empty", "", - ) - } - } - } - } - }, - }, - }). - WithTranslations([]validator.Translation{ - { - Tag: "required", - Message: "cannot be empty", - Override: true, - }, - { - Tag: "min", - Message: "must be at least {0}", - Override: true, - TranslationFunc: func(t ut.Translator, fe v.FieldError) string { - output, _ := t.T(fe.Tag(), fe.Param()) - return output - }, - }, - { - Tag: "enumerated_restricted", - Message: "cannot be empty with data_type [enumerated]", - TranslationFunc: func(t ut.Translator, fe v.FieldError) string { - output, _ := t.T(fe.Tag()) - return output - }, - }, - { - Tag: "element_not_empty", - Message: "cannot contain empty element", - TranslationFunc: func(t ut.Translator, fe v.FieldError) string { - output, _ := t.T(fe.Tag()) - return output - }, - }, - }). - Build() - if err != nil { - panic(err) - } - - return v -} diff --git a/core/tag/validator/builder.go b/core/tag/validator/builder.go deleted file mode 100644 index 61bca469..00000000 --- a/core/tag/validator/builder.go +++ /dev/null @@ -1,169 +0,0 @@ -package validator - -import ( - "reflect" - "strings" - - "github.com/go-playground/locales/en" - ut "github.com/go-playground/universal-translator" - "github.com/go-playground/validator/v10" - en_translation "github.com/go-playground/validator/v10/translations/en" -) - -const defaultLocale = "en" - -// Builder is type to build validator -type Builder struct { - fieldValidations []FieldValidation - structValidations []StructValidation - translations []Translation - - validate *validator.Validate - translator ut.Translator -} - -// WithTranslations tells builder to include custom translation -func (b *Builder) WithTranslations(translations []Translation) *Builder { - output := *b - output.translations = translations - return &output -} - -// WithStructValidations tells builder to include custom struct validation -func (b *Builder) WithStructValidations(structValidations []StructValidation) *Builder { - output := *b - output.structValidations = structValidations - return &output -} - -// WithFieldValidations tells builder to include custom field validation -func (b *Builder) WithFieldValidations(fieldValidations []FieldValidation) *Builder { - output := *b - output.fieldValidations = fieldValidations - return &output -} - -// Build builds the validator -func (b *Builder) Build() (Validator, error) { - b.translator = b.initializeTranslator() - validate, err := b.initializeValidate(b.translator) - if err != nil { - return nil, err - } - b.validate = validate - - if b.fieldValidations != nil { - err = b.registerFieldValidations(b.validate, b.fieldValidations) - if err != nil { - return nil, err - } - } - if b.structValidations != nil { - b.registerStructValidations(b.validate, b.structValidations) - } - if b.translations != nil { - err = b.registerTranslations(b.validate, b.translator, b.translations) - if err != nil { - return nil, err - } - } - return b, nil -} - -// Validate validates the type for any violation -func (b *Builder) Validate(s interface{}) error { - err := b.validate.Struct(s) - if err == nil { - return nil - } - validationErrors, ok := err.(validator.ValidationErrors) - if !ok { - return err - } - fieldErrors := make(FieldError) - for _, f := range validationErrors { - var field string - splitNamespace := strings.Split(f.Namespace(), ".") - if len(splitNamespace) > 0 { - if len(splitNamespace) > 1 { - field = strings.Join(splitNamespace[1:], ".") - } else { - field = splitNamespace[0] - } - } - - errMsg := f.Translate(b.translator) - fieldErrors[field] = errMsg - } - return fieldErrors -} - -func (b *Builder) initializeTranslator() ut.Translator { - universalTranslator := ut.New(en.New(), en.New()) - translator, _ := universalTranslator.GetTranslator(defaultLocale) - return translator -} - -func (b *Builder) initializeValidate(translator ut.Translator) (*validator.Validate, error) { - validate := validator.New() - validate.RegisterTagNameFunc(b.tagNameFunc) - if err := en_translation.RegisterDefaultTranslations(validate, translator); err != nil { - return nil, err - } - return validate, nil -} - -func (b *Builder) registerFieldValidations(validate *validator.Validate, fieldValidations []FieldValidation) error { - for _, f := range fieldValidations { - err := validate.RegisterValidation(f.Tag, f.Func) - if err != nil { - return err - } - } - return nil -} - -func (b *Builder) registerStructValidations(validate *validator.Validate, structValidations []StructValidation) { - for _, s := range structValidations { - validate.RegisterStructValidation(s.Func, s.Type) - } -} - -func (b *Builder) registerTranslations(validate *validator.Validate, translator ut.Translator, translations []Translation) error { - for _, t := range translations { - registerFn := b.getRegisterFn(t.Tag, t.Message, t.Override) - transFunc := t.TranslationFunc - if transFunc == nil { - transFunc = b.transFunc - } - err := validate.RegisterTranslation(t.Tag, translator, registerFn, transFunc) - if err != nil { - return err - } - } - return nil -} - -func (b *Builder) tagNameFunc(fld reflect.StructField) string { - name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] - if name == "-" { - return "" - } - return name -} - -func (b *Builder) getRegisterFn(tag string, translation string, override bool) validator.RegisterTranslationsFunc { - return func(ut ut.Translator) error { - return ut.Add(tag, translation, override) - } -} - -func (b *Builder) transFunc(ut ut.Translator, fe validator.FieldError) string { - t, _ := ut.T(fe.Tag()) - return t -} - -// NewBuilder initializes builder -func NewBuilder() *Builder { - return &Builder{} -} diff --git a/core/tag/validator/error.go b/core/tag/validator/error.go deleted file mode 100644 index af84eebf..00000000 --- a/core/tag/validator/error.go +++ /dev/null @@ -1,29 +0,0 @@ -package validator - -import ( - "encoding/json" - "fmt" - "strings" -) - -// FieldError is error with key is field name and value is all errors for that field -type FieldError map[string]string - -// Error returns error that represent the field error -func (d FieldError) Error() string { - var errFields []string - for field, value := range d { - errFields = append(errFields, fmt.Sprintf("%s : %s", field, value)) - } - output := fmt.Sprintf("error with [%s]", strings.Join(errFields, ", ")) - return output -} - -// JSON converts field error into its JSON representation -func (d FieldError) JSON() []byte { - output, err := json.Marshal(d) - if err != nil { - return []byte(err.Error()) - } - return output -} diff --git a/core/tag/validator/validator.go b/core/tag/validator/validator.go deleted file mode 100644 index 43340d01..00000000 --- a/core/tag/validator/validator.go +++ /dev/null @@ -1,31 +0,0 @@ -package validator - -import ( - ut "github.com/go-playground/universal-translator" - "github.com/go-playground/validator/v10" -) - -// Validator is contract to do validation -type Validator interface { - Validate(interface{}) error -} - -// Translation is a type to describe how to translate -type Translation struct { - Tag string - Message string - Override bool - TranslationFunc func(ut.Translator, validator.FieldError) string -} - -// StructValidation is a type to describe how to validate a struct -type StructValidation struct { - Type interface{} - Func validator.StructLevelFunc -} - -// FieldValidation is a type to describe how to validate a field -type FieldValidation struct { - Tag string - Func validator.Func -} diff --git a/docs/docs/guides/discussion.md b/docs/docs/guides/discussion.md deleted file mode 100644 index 992a09e8..00000000 --- a/docs/docs/guides/discussion.md +++ /dev/null @@ -1,219 +0,0 @@ -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; - -# Discussion - -Discussion is a new feature in Compass. One could create a discussion and all users can put comment in it. Currently, there are three types of discussions `issues`, `open ended`, and `question and answer`. Depending on the type, the discussion could have multiple possible states. In the current version, all types only have two states: `open` and `closed`. A newly created discussion will always be assign an `open` state. - -## Create a Discussion - -A discussion thread can be created with the Discussion API. The API contract is available [here](https://github.com/raystack/compass/blob/main/third_party/OpenAPI/compass.swagger.json). - - - - -```bash -$ compass discussion post --body= -``` - -```json -{ - "title": "The first discussion", - "body": "This is the first discussion thread in Compass", - "type": "openended" -} -``` - - - - -```bash -$ curl --request POST 'http://localhost:8080/v1beta1/discussions' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "title": "The first discussion", - "body": "This is the first discussion thread in Compass", - "type": "openended" -}' -``` - - - - -## Fetching All Discussions - -The Get Discussions will fetch all discussions in Compass. - - - - -```bash -$ compass discussion list -``` - - - - -```bash -$ curl 'http://localhost:8080/v1beta1/discussions' \ ---header 'Compass-User-UUID:raystack@email.com' -``` - - - - -The response will be something like - -```javascript -{ - "data": [ - { - "id": "1", - "title": "The first discussion", - "body": "This is the first discussion thread in Compass", - "type": "openended" - "state": "open", - "labels": [], - "assets": [], - "assignees": [], - "owner": { - "id": "dd9e2e07-a13f-1c2b-07e3-e32cf0f7688c", - "email": "raystack@email.com", - "provider": "shield" - }, - "created_at": "elit cillum Duis", - "updated_at": "velit dolor ex" - } - ] -} -``` - -Notice the state is `open` by default once we create a new discussion. There are also some additional features in discussion where we can label the discussion and assign users and assets to the discussion. These labelling and assinging assets and users could also be done when we are creating a discussion. - -## Patching Discussion - -If we are not labelling and assigning users & assets to the discussion in the creation step, there are also a dedicated API to do those. - -```bash -$ curl --request PATCH 'http://localhost:8080/v1beta1/discussions/1' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "title": "The first discussion (duplicated)", - "state": "closed" -}' -``` - -We just need to send the fields that we want to patch for a discussion. Some fields have array type, in this case the PATCH will overwrite the fields with the new value. - -For example we have this labelled discussion. - -```bash -$ curl 'http://localhost:8080/v1beta1/discussions' \ ---header 'Compass-User-UUID:raystack@email.com' - -{ - "data": [ - { - "id": "1", - "title": "The first discussion", - "body": "This is the first discussion thread in Compass", - "type": "openended" - "state": "open", - "labels": [ - "work", - "urgent", - "help wanted" - ], - "owner": { - "id": "dd9e2e07-a13f-1c2b-07e3-e32cf0f7688c", - "email": "raystack@email.com", - "provider": "shield" - }, - "created_at": "elit cillum Duis", - "updated_at": "velit dolor ex" - } - ] -} -``` - -If we patch the label with the new values. - -```bash -$ curl --request PATCH 'http://localhost:8080/v1beta1/discussions/1' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "labels": ["new value"] -}' -``` - -The discussion with id 1 will be updated like this. - -```bash -$ curl 'http://localhost:8080/v1beta1/discussions' \ ---header 'Compass-User-UUID:raystack@email.com' - -{ - "data": [ - { - "id": "1", - "title": "The first discussion", - "body": "This is the first discussion thread in Compass", - "type": "openended" - "state": "open", - "labels": [ - "new value" - ], - "owner": { - "id": "dd9e2e07-a13f-1c2b-07e3-e32cf0f7688c", - "email": "raystack@email.com", - "provider": "shield" - }, - "created_at": "elit cillum Duis", - "updated_at": "velit dolor ex" - } - ] -} -``` - -## Commenting a Discussion - -One could also comment a specific discussion with discussion comment API. - -```bash -$ curl --request POST 'http://localhost:8080/v1beta1/discussions/1/comments' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "body": "This is the first comment of discussion 1" -}' -``` - -## Getting All My Discussions - -Compass integrates discussions with User API so we could fetch all discussions belong to us with this API. - -```bash -$ curl 'http://localhost:8080/v1beta1/me/discussions' \ ---header 'Compass-User-UUID:raystack@email.com' - -{ - "data": [ - { - "id": "1", - "title": "The first discussion", - "body": "This is the first discussion thread in Compass", - "type": "openended" - "state": "open", - "labels": [ - "new value" - ], - "owner": { - "id": "dd9e2e07-a13f-1c2b-07e3-e32cf0f7688c", - "email": "raystack@email.com", - "provider": "shield" - }, - "created_at": "elit cillum Duis", - "updated_at": "velit dolor ex" - } - ] -} -``` diff --git a/docs/docs/guides/tagging.md b/docs/docs/guides/tagging.md deleted file mode 100644 index 8aa4ff3c..00000000 --- a/docs/docs/guides/tagging.md +++ /dev/null @@ -1,204 +0,0 @@ -# Tagging - -This doc explains how to tag an asset in Compass with a specific tag. - -## Tag Template - -To support reusability of a tag, Compass has a tag template that we need to define first before we apply it to an asset. Tagging an asset means Compass will wire tag template to assets. - -Creating a tag's template could be done with Tag Template API. - -```bash -$ curl --request POST 'localhost:8080/v1beta1/tags/templates' \ ---header 'Compass-User-UUID: user@raystack.io' \ ---data-raw '{ - "urn": "my-first-template", - "display_name": "My First Template", - "description": "This is my first template", - "fields": [ - { - "urn": "fieldA", - "display_name": "Field A", - "description": "This is Field A", - "data_type": "string", - "required": false - }, - { - "urn": "fieldB", - "display_name": "Field B", - "description": "This is Field B", - "data_type": "double", - "required": true - } - ] -}' -``` - -We can verify the tag's template is created by calling GET tag's templates API - -```bash -$ curl --request GET 'localhost:8080/v1beta1/tags/templates' \ ---header 'Compass-User-UUID: user@raystack.io' -``` - -The response will be like this - -```javascript -{ - "data": [ - { - "urn": "my-first-template", - "display_name": "My First Template", - "description": "This is my first template", - "fields": [ - { - "id": 1, - "urn": "fieldA", - "display_name": "Field A", - "description": "This is Field A", - "data_type": "string", - "created_at": "2022-05-10T09:34:18.766125Z", - "updated_at": "2022-05-10T09:34:18.766125Z" - }, - { - "id": 2, - "urn": "fieldB", - "display_name": "Field B", - "description": "This is Field B", - "data_type": "double", - "required": true, - "created_at": "2022-05-10T09:34:18.766125Z", - "updated_at": "2022-05-10T09:34:18.766125Z" - } - ], - "created_at": "2022-05-10T09:34:18.766125Z", - "updated_at": "2022-05-10T09:34:18.766125Z" - } - ] -} -``` - -Now, we already have a template with template urn `my-first-template` that has 2 kind of fields with id `1` and `2`. - -## Tagging an Asset - -Once templates exist, we can tag an asset with a template by calling PUT `/v1beta1/tags/assets/{asset_id}` API. - -Assuming we have an asset - -```javascript -{ - "id": "a2c74793-b584-4d20-ba2a-28bdf6b92c08", - "urn": "sample-urn", - "type": "topic", - "service": "bigquery", - "name": "sample-name", - "description": "sample description", - "version": "0.1", - "updated_by": { - "uuid": "user@raystack.io" - }, - "created_at": "2022-05-11T07:03:45.954387Z", - "updated_at": "2022-05-11T07:03:45.954387Z" -} -``` - -We can tag the asset with template `my-first-template`. - -```bash -$ curl --request POST 'localhost:8080/v1beta1/tags/assets' \ ---header 'Compass-User-UUID: user@raystack.io' ---data-raw '{ - "asset_id": "a2c74793-b584-4d20-ba2a-28bdf6b92c08", - "template_urn": "my-first-template", - "tag_values": [ - { - "field_id": 1, - "field_value": "test" - }, - { - "field_id": 2, - "field_value": 10.0 - } - ] -}' -``` - -We will get response showing that the asset is already tagged. - -```javascript -{ - "data": { - "asset_id": "a2c74793-b584-4d20-ba2a-28bdf6b92c08", - "template_urn": "my-first-template", - "tag_values": [ - { - "field_id": 1, - "field_value": "test", - "field_urn": "fieldA", - "field_display_name": "Field A", - "field_description": "This is Field A", - "field_data_type": "string", - "created_at": "2022-05-11T00:06:26.475943Z", - "updated_at": "2022-05-11T00:06:26.475943Z" - }, - { - "field_id": 2, - "field_value": 10, - "field_urn": "fieldB", - "field_display_name": "Field B", - "field_description": "This is Field B", - "field_data_type": "double", - "field_required": true, - "created_at": "2022-05-11T00:06:26.475943Z", - "updated_at": "2022-05-11T00:06:26.475943Z" - } - ], - "template_display_name": "My First Template", - "template_description": "This is my first template" - } -} -``` - -## Getting Asset's Tag(s) - -We can get all tags belong to an asset by calling GET `/v1beta1/tags/assets/{asset_id}` API. - -```bash -$ curl --request GET 'localhost:8080/v1beta1/tags/assets/a2c74793-b584-4d20-ba2a-28bdf6b92c08' \ ---header 'Compass-User-UUID: user@raystack.io' - -{ - "data": [ - { - "asset_id": "a2c74793-b584-4d20-ba2a-28bdf6b92c08", - "template_urn": "my-first-template", - "tag_values": [ - { - "field_id": 1, - "field_value": "test", - "field_urn": "fieldA", - "field_display_name": "Field A", - "field_description": "This is Field A", - "field_data_type": "string", - "created_at": "2022-05-11T00:06:26.475943Z", - "updated_at": "2022-05-11T00:06:26.475943Z" - }, - { - "field_id": 2, - "field_value": 10, - "field_urn": "fieldB", - "field_display_name": "Field B", - "field_description": "This is Field B", - "field_data_type": "double", - "field_required": true, - "created_at": "2022-05-11T00:06:26.475943Z", - "updated_at": "2022-05-11T00:06:26.475943Z" - } - ], - "template_display_name": "My First Template", - "template_description": "This is my first template" - } - ] -} -``` diff --git a/gen/raystack/compass/v1beta1/compassv1beta1connect/service.connect.go b/gen/raystack/compass/v1beta1/compassv1beta1connect/service.connect.go index d3cfecaf..74309e3c 100644 --- a/gen/raystack/compass/v1beta1/compassv1beta1connect/service.connect.go +++ b/gen/raystack/compass/v1beta1/compassv1beta1connect/service.connect.go @@ -33,134 +33,6 @@ const ( // reflection-formatted method names, remove the leading slash and convert the remaining slash to a // period. const ( - // CompassServiceGetAllDiscussionsProcedure is the fully-qualified name of the CompassService's - // GetAllDiscussions RPC. - CompassServiceGetAllDiscussionsProcedure = "/raystack.compass.v1beta1.CompassService/GetAllDiscussions" - // CompassServiceCreateDiscussionProcedure is the fully-qualified name of the CompassService's - // CreateDiscussion RPC. - CompassServiceCreateDiscussionProcedure = "/raystack.compass.v1beta1.CompassService/CreateDiscussion" - // CompassServiceGetDiscussionProcedure is the fully-qualified name of the CompassService's - // GetDiscussion RPC. - CompassServiceGetDiscussionProcedure = "/raystack.compass.v1beta1.CompassService/GetDiscussion" - // CompassServicePatchDiscussionProcedure is the fully-qualified name of the CompassService's - // PatchDiscussion RPC. - CompassServicePatchDiscussionProcedure = "/raystack.compass.v1beta1.CompassService/PatchDiscussion" - // CompassServiceCreateCommentProcedure is the fully-qualified name of the CompassService's - // CreateComment RPC. - CompassServiceCreateCommentProcedure = "/raystack.compass.v1beta1.CompassService/CreateComment" - // CompassServiceGetAllCommentsProcedure is the fully-qualified name of the CompassService's - // GetAllComments RPC. - CompassServiceGetAllCommentsProcedure = "/raystack.compass.v1beta1.CompassService/GetAllComments" - // CompassServiceGetCommentProcedure is the fully-qualified name of the CompassService's GetComment - // RPC. - CompassServiceGetCommentProcedure = "/raystack.compass.v1beta1.CompassService/GetComment" - // CompassServiceUpdateCommentProcedure is the fully-qualified name of the CompassService's - // UpdateComment RPC. - CompassServiceUpdateCommentProcedure = "/raystack.compass.v1beta1.CompassService/UpdateComment" - // CompassServiceDeleteCommentProcedure is the fully-qualified name of the CompassService's - // DeleteComment RPC. - CompassServiceDeleteCommentProcedure = "/raystack.compass.v1beta1.CompassService/DeleteComment" - // CompassServiceSearchAssetsProcedure is the fully-qualified name of the CompassService's - // SearchAssets RPC. - CompassServiceSearchAssetsProcedure = "/raystack.compass.v1beta1.CompassService/SearchAssets" - // CompassServiceSuggestAssetsProcedure is the fully-qualified name of the CompassService's - // SuggestAssets RPC. - CompassServiceSuggestAssetsProcedure = "/raystack.compass.v1beta1.CompassService/SuggestAssets" - // CompassServiceGroupAssetsProcedure is the fully-qualified name of the CompassService's - // GroupAssets RPC. - CompassServiceGroupAssetsProcedure = "/raystack.compass.v1beta1.CompassService/GroupAssets" - // CompassServiceGetGraphProcedure is the fully-qualified name of the CompassService's GetGraph RPC. - CompassServiceGetGraphProcedure = "/raystack.compass.v1beta1.CompassService/GetGraph" - // CompassServiceGetAllTypesProcedure is the fully-qualified name of the CompassService's - // GetAllTypes RPC. - CompassServiceGetAllTypesProcedure = "/raystack.compass.v1beta1.CompassService/GetAllTypes" - // CompassServiceGetAllAssetsProcedure is the fully-qualified name of the CompassService's - // GetAllAssets RPC. - CompassServiceGetAllAssetsProcedure = "/raystack.compass.v1beta1.CompassService/GetAllAssets" - // CompassServiceGetAssetByIDProcedure is the fully-qualified name of the CompassService's - // GetAssetByID RPC. - CompassServiceGetAssetByIDProcedure = "/raystack.compass.v1beta1.CompassService/GetAssetByID" - // CompassServiceUpsertAssetProcedure is the fully-qualified name of the CompassService's - // UpsertAsset RPC. - CompassServiceUpsertAssetProcedure = "/raystack.compass.v1beta1.CompassService/UpsertAsset" - // CompassServiceUpsertPatchAssetProcedure is the fully-qualified name of the CompassService's - // UpsertPatchAsset RPC. - CompassServiceUpsertPatchAssetProcedure = "/raystack.compass.v1beta1.CompassService/UpsertPatchAsset" - // CompassServiceDeleteAssetProcedure is the fully-qualified name of the CompassService's - // DeleteAsset RPC. - CompassServiceDeleteAssetProcedure = "/raystack.compass.v1beta1.CompassService/DeleteAsset" - // CompassServiceGetAssetStargazersProcedure is the fully-qualified name of the CompassService's - // GetAssetStargazers RPC. - CompassServiceGetAssetStargazersProcedure = "/raystack.compass.v1beta1.CompassService/GetAssetStargazers" - // CompassServiceGetAssetVersionHistoryProcedure is the fully-qualified name of the CompassService's - // GetAssetVersionHistory RPC. - CompassServiceGetAssetVersionHistoryProcedure = "/raystack.compass.v1beta1.CompassService/GetAssetVersionHistory" - // CompassServiceGetAssetByVersionProcedure is the fully-qualified name of the CompassService's - // GetAssetByVersion RPC. - CompassServiceGetAssetByVersionProcedure = "/raystack.compass.v1beta1.CompassService/GetAssetByVersion" - // CompassServiceCreateAssetProbeProcedure is the fully-qualified name of the CompassService's - // CreateAssetProbe RPC. - CompassServiceCreateAssetProbeProcedure = "/raystack.compass.v1beta1.CompassService/CreateAssetProbe" - // CompassServiceGetUserStarredAssetsProcedure is the fully-qualified name of the CompassService's - // GetUserStarredAssets RPC. - CompassServiceGetUserStarredAssetsProcedure = "/raystack.compass.v1beta1.CompassService/GetUserStarredAssets" - // CompassServiceGetMyStarredAssetsProcedure is the fully-qualified name of the CompassService's - // GetMyStarredAssets RPC. - CompassServiceGetMyStarredAssetsProcedure = "/raystack.compass.v1beta1.CompassService/GetMyStarredAssets" - // CompassServiceGetMyStarredAssetProcedure is the fully-qualified name of the CompassService's - // GetMyStarredAsset RPC. - CompassServiceGetMyStarredAssetProcedure = "/raystack.compass.v1beta1.CompassService/GetMyStarredAsset" - // CompassServiceStarAssetProcedure is the fully-qualified name of the CompassService's StarAsset - // RPC. - CompassServiceStarAssetProcedure = "/raystack.compass.v1beta1.CompassService/StarAsset" - // CompassServiceUnstarAssetProcedure is the fully-qualified name of the CompassService's - // UnstarAsset RPC. - CompassServiceUnstarAssetProcedure = "/raystack.compass.v1beta1.CompassService/UnstarAsset" - // CompassServiceGetMyDiscussionsProcedure is the fully-qualified name of the CompassService's - // GetMyDiscussions RPC. - CompassServiceGetMyDiscussionsProcedure = "/raystack.compass.v1beta1.CompassService/GetMyDiscussions" - // CompassServiceCreateTagAssetProcedure is the fully-qualified name of the CompassService's - // CreateTagAsset RPC. - CompassServiceCreateTagAssetProcedure = "/raystack.compass.v1beta1.CompassService/CreateTagAsset" - // CompassServiceGetTagByAssetAndTemplateProcedure is the fully-qualified name of the - // CompassService's GetTagByAssetAndTemplate RPC. - CompassServiceGetTagByAssetAndTemplateProcedure = "/raystack.compass.v1beta1.CompassService/GetTagByAssetAndTemplate" - // CompassServiceUpdateTagAssetProcedure is the fully-qualified name of the CompassService's - // UpdateTagAsset RPC. - CompassServiceUpdateTagAssetProcedure = "/raystack.compass.v1beta1.CompassService/UpdateTagAsset" - // CompassServiceDeleteTagAssetProcedure is the fully-qualified name of the CompassService's - // DeleteTagAsset RPC. - CompassServiceDeleteTagAssetProcedure = "/raystack.compass.v1beta1.CompassService/DeleteTagAsset" - // CompassServiceGetAllTagsByAssetProcedure is the fully-qualified name of the CompassService's - // GetAllTagsByAsset RPC. - CompassServiceGetAllTagsByAssetProcedure = "/raystack.compass.v1beta1.CompassService/GetAllTagsByAsset" - // CompassServiceGetAllTagTemplatesProcedure is the fully-qualified name of the CompassService's - // GetAllTagTemplates RPC. - CompassServiceGetAllTagTemplatesProcedure = "/raystack.compass.v1beta1.CompassService/GetAllTagTemplates" - // CompassServiceCreateTagTemplateProcedure is the fully-qualified name of the CompassService's - // CreateTagTemplate RPC. - CompassServiceCreateTagTemplateProcedure = "/raystack.compass.v1beta1.CompassService/CreateTagTemplate" - // CompassServiceGetTagTemplateProcedure is the fully-qualified name of the CompassService's - // GetTagTemplate RPC. - CompassServiceGetTagTemplateProcedure = "/raystack.compass.v1beta1.CompassService/GetTagTemplate" - // CompassServiceUpdateTagTemplateProcedure is the fully-qualified name of the CompassService's - // UpdateTagTemplate RPC. - CompassServiceUpdateTagTemplateProcedure = "/raystack.compass.v1beta1.CompassService/UpdateTagTemplate" - // CompassServiceDeleteTagTemplateProcedure is the fully-qualified name of the CompassService's - // DeleteTagTemplate RPC. - CompassServiceDeleteTagTemplateProcedure = "/raystack.compass.v1beta1.CompassService/DeleteTagTemplate" - // CompassServiceCreateNamespaceProcedure is the fully-qualified name of the CompassService's - // CreateNamespace RPC. - CompassServiceCreateNamespaceProcedure = "/raystack.compass.v1beta1.CompassService/CreateNamespace" - // CompassServiceGetNamespaceProcedure is the fully-qualified name of the CompassService's - // GetNamespace RPC. - CompassServiceGetNamespaceProcedure = "/raystack.compass.v1beta1.CompassService/GetNamespace" - // CompassServiceUpdateNamespaceProcedure is the fully-qualified name of the CompassService's - // UpdateNamespace RPC. - CompassServiceUpdateNamespaceProcedure = "/raystack.compass.v1beta1.CompassService/UpdateNamespace" - // CompassServiceListNamespacesProcedure is the fully-qualified name of the CompassService's - // ListNamespaces RPC. - CompassServiceListNamespacesProcedure = "/raystack.compass.v1beta1.CompassService/ListNamespaces" // CompassServiceGetAllEntitiesProcedure is the fully-qualified name of the CompassService's // GetAllEntities RPC. CompassServiceGetAllEntitiesProcedure = "/raystack.compass.v1beta1.CompassService/GetAllEntities" @@ -196,59 +68,41 @@ const ( // CompassServiceDeleteEdgeProcedure is the fully-qualified name of the CompassService's DeleteEdge // RPC. CompassServiceDeleteEdgeProcedure = "/raystack.compass.v1beta1.CompassService/DeleteEdge" + // CompassServiceStarEntityProcedure is the fully-qualified name of the CompassService's StarEntity + // RPC. + CompassServiceStarEntityProcedure = "/raystack.compass.v1beta1.CompassService/StarEntity" + // CompassServiceUnstarEntityProcedure is the fully-qualified name of the CompassService's + // UnstarEntity RPC. + CompassServiceUnstarEntityProcedure = "/raystack.compass.v1beta1.CompassService/UnstarEntity" + // CompassServiceGetUserStarredEntitiesProcedure is the fully-qualified name of the CompassService's + // GetUserStarredEntities RPC. + CompassServiceGetUserStarredEntitiesProcedure = "/raystack.compass.v1beta1.CompassService/GetUserStarredEntities" + // CompassServiceGetMyStarredEntitiesProcedure is the fully-qualified name of the CompassService's + // GetMyStarredEntities RPC. + CompassServiceGetMyStarredEntitiesProcedure = "/raystack.compass.v1beta1.CompassService/GetMyStarredEntities" + // CompassServiceGetMyStarredEntityProcedure is the fully-qualified name of the CompassService's + // GetMyStarredEntity RPC. + CompassServiceGetMyStarredEntityProcedure = "/raystack.compass.v1beta1.CompassService/GetMyStarredEntity" + // CompassServiceGetEntityStargazersProcedure is the fully-qualified name of the CompassService's + // GetEntityStargazers RPC. + CompassServiceGetEntityStargazersProcedure = "/raystack.compass.v1beta1.CompassService/GetEntityStargazers" + // CompassServiceCreateNamespaceProcedure is the fully-qualified name of the CompassService's + // CreateNamespace RPC. + CompassServiceCreateNamespaceProcedure = "/raystack.compass.v1beta1.CompassService/CreateNamespace" + // CompassServiceGetNamespaceProcedure is the fully-qualified name of the CompassService's + // GetNamespace RPC. + CompassServiceGetNamespaceProcedure = "/raystack.compass.v1beta1.CompassService/GetNamespace" + // CompassServiceUpdateNamespaceProcedure is the fully-qualified name of the CompassService's + // UpdateNamespace RPC. + CompassServiceUpdateNamespaceProcedure = "/raystack.compass.v1beta1.CompassService/UpdateNamespace" + // CompassServiceListNamespacesProcedure is the fully-qualified name of the CompassService's + // ListNamespaces RPC. + CompassServiceListNamespacesProcedure = "/raystack.compass.v1beta1.CompassService/ListNamespaces" ) // CompassServiceClient is a client for the raystack.compass.v1beta1.CompassService service. type CompassServiceClient interface { - // Domain: Discussion - GetAllDiscussions(context.Context, *connect.Request[v1beta1.GetAllDiscussionsRequest]) (*connect.Response[v1beta1.GetAllDiscussionsResponse], error) - CreateDiscussion(context.Context, *connect.Request[v1beta1.CreateDiscussionRequest]) (*connect.Response[v1beta1.CreateDiscussionResponse], error) - GetDiscussion(context.Context, *connect.Request[v1beta1.GetDiscussionRequest]) (*connect.Response[v1beta1.GetDiscussionResponse], error) - PatchDiscussion(context.Context, *connect.Request[v1beta1.PatchDiscussionRequest]) (*connect.Response[v1beta1.PatchDiscussionResponse], error) - CreateComment(context.Context, *connect.Request[v1beta1.CreateCommentRequest]) (*connect.Response[v1beta1.CreateCommentResponse], error) - GetAllComments(context.Context, *connect.Request[v1beta1.GetAllCommentsRequest]) (*connect.Response[v1beta1.GetAllCommentsResponse], error) - GetComment(context.Context, *connect.Request[v1beta1.GetCommentRequest]) (*connect.Response[v1beta1.GetCommentResponse], error) - UpdateComment(context.Context, *connect.Request[v1beta1.UpdateCommentRequest]) (*connect.Response[v1beta1.UpdateCommentResponse], error) - DeleteComment(context.Context, *connect.Request[v1beta1.DeleteCommentRequest]) (*connect.Response[v1beta1.DeleteCommentResponse], error) - // Domain: Asset - SearchAssets(context.Context, *connect.Request[v1beta1.SearchAssetsRequest]) (*connect.Response[v1beta1.SearchAssetsResponse], error) - SuggestAssets(context.Context, *connect.Request[v1beta1.SuggestAssetsRequest]) (*connect.Response[v1beta1.SuggestAssetsResponse], error) - GroupAssets(context.Context, *connect.Request[v1beta1.GroupAssetsRequest]) (*connect.Response[v1beta1.GroupAssetsResponse], error) - GetGraph(context.Context, *connect.Request[v1beta1.GetGraphRequest]) (*connect.Response[v1beta1.GetGraphResponse], error) - GetAllTypes(context.Context, *connect.Request[v1beta1.GetAllTypesRequest]) (*connect.Response[v1beta1.GetAllTypesResponse], error) - GetAllAssets(context.Context, *connect.Request[v1beta1.GetAllAssetsRequest]) (*connect.Response[v1beta1.GetAllAssetsResponse], error) - GetAssetByID(context.Context, *connect.Request[v1beta1.GetAssetByIDRequest]) (*connect.Response[v1beta1.GetAssetByIDResponse], error) - UpsertAsset(context.Context, *connect.Request[v1beta1.UpsertAssetRequest]) (*connect.Response[v1beta1.UpsertAssetResponse], error) - UpsertPatchAsset(context.Context, *connect.Request[v1beta1.UpsertPatchAssetRequest]) (*connect.Response[v1beta1.UpsertPatchAssetResponse], error) - DeleteAsset(context.Context, *connect.Request[v1beta1.DeleteAssetRequest]) (*connect.Response[v1beta1.DeleteAssetResponse], error) - GetAssetStargazers(context.Context, *connect.Request[v1beta1.GetAssetStargazersRequest]) (*connect.Response[v1beta1.GetAssetStargazersResponse], error) - GetAssetVersionHistory(context.Context, *connect.Request[v1beta1.GetAssetVersionHistoryRequest]) (*connect.Response[v1beta1.GetAssetVersionHistoryResponse], error) - GetAssetByVersion(context.Context, *connect.Request[v1beta1.GetAssetByVersionRequest]) (*connect.Response[v1beta1.GetAssetByVersionResponse], error) - CreateAssetProbe(context.Context, *connect.Request[v1beta1.CreateAssetProbeRequest]) (*connect.Response[v1beta1.CreateAssetProbeResponse], error) - // Domain: User * Star - GetUserStarredAssets(context.Context, *connect.Request[v1beta1.GetUserStarredAssetsRequest]) (*connect.Response[v1beta1.GetUserStarredAssetsResponse], error) - GetMyStarredAssets(context.Context, *connect.Request[v1beta1.GetMyStarredAssetsRequest]) (*connect.Response[v1beta1.GetMyStarredAssetsResponse], error) - GetMyStarredAsset(context.Context, *connect.Request[v1beta1.GetMyStarredAssetRequest]) (*connect.Response[v1beta1.GetMyStarredAssetResponse], error) - StarAsset(context.Context, *connect.Request[v1beta1.StarAssetRequest]) (*connect.Response[v1beta1.StarAssetResponse], error) - UnstarAsset(context.Context, *connect.Request[v1beta1.UnstarAssetRequest]) (*connect.Response[v1beta1.UnstarAssetResponse], error) - GetMyDiscussions(context.Context, *connect.Request[v1beta1.GetMyDiscussionsRequest]) (*connect.Response[v1beta1.GetMyDiscussionsResponse], error) - // Domain: Tag Templates - CreateTagAsset(context.Context, *connect.Request[v1beta1.CreateTagAssetRequest]) (*connect.Response[v1beta1.CreateTagAssetResponse], error) - GetTagByAssetAndTemplate(context.Context, *connect.Request[v1beta1.GetTagByAssetAndTemplateRequest]) (*connect.Response[v1beta1.GetTagByAssetAndTemplateResponse], error) - UpdateTagAsset(context.Context, *connect.Request[v1beta1.UpdateTagAssetRequest]) (*connect.Response[v1beta1.UpdateTagAssetResponse], error) - DeleteTagAsset(context.Context, *connect.Request[v1beta1.DeleteTagAssetRequest]) (*connect.Response[v1beta1.DeleteTagAssetResponse], error) - GetAllTagsByAsset(context.Context, *connect.Request[v1beta1.GetAllTagsByAssetRequest]) (*connect.Response[v1beta1.GetAllTagsByAssetResponse], error) - GetAllTagTemplates(context.Context, *connect.Request[v1beta1.GetAllTagTemplatesRequest]) (*connect.Response[v1beta1.GetAllTagTemplatesResponse], error) - CreateTagTemplate(context.Context, *connect.Request[v1beta1.CreateTagTemplateRequest]) (*connect.Response[v1beta1.CreateTagTemplateResponse], error) - GetTagTemplate(context.Context, *connect.Request[v1beta1.GetTagTemplateRequest]) (*connect.Response[v1beta1.GetTagTemplateResponse], error) - UpdateTagTemplate(context.Context, *connect.Request[v1beta1.UpdateTagTemplateRequest]) (*connect.Response[v1beta1.UpdateTagTemplateResponse], error) - DeleteTagTemplate(context.Context, *connect.Request[v1beta1.DeleteTagTemplateRequest]) (*connect.Response[v1beta1.DeleteTagTemplateResponse], error) - // Domain: Namespace - CreateNamespace(context.Context, *connect.Request[v1beta1.CreateNamespaceRequest]) (*connect.Response[v1beta1.CreateNamespaceResponse], error) - GetNamespace(context.Context, *connect.Request[v1beta1.GetNamespaceRequest]) (*connect.Response[v1beta1.GetNamespaceResponse], error) - UpdateNamespace(context.Context, *connect.Request[v1beta1.UpdateNamespaceRequest]) (*connect.Response[v1beta1.UpdateNamespaceResponse], error) - ListNamespaces(context.Context, *connect.Request[v1beta1.ListNamespacesRequest]) (*connect.Response[v1beta1.ListNamespacesResponse], error) - // Domain: Entity (v2) + // Domain: Entity GetAllEntities(context.Context, *connect.Request[v1beta1.GetAllEntitiesRequest]) (*connect.Response[v1beta1.GetAllEntitiesResponse], error) GetEntityByID(context.Context, *connect.Request[v1beta1.GetEntityByIDRequest]) (*connect.Response[v1beta1.GetEntityByIDResponse], error) UpsertEntity(context.Context, *connect.Request[v1beta1.UpsertEntityRequest]) (*connect.Response[v1beta1.UpsertEntityResponse], error) @@ -256,13 +110,25 @@ type CompassServiceClient interface { SearchEntities(context.Context, *connect.Request[v1beta1.SearchEntitiesRequest]) (*connect.Response[v1beta1.SearchEntitiesResponse], error) SuggestEntities(context.Context, *connect.Request[v1beta1.SuggestEntitiesRequest]) (*connect.Response[v1beta1.SuggestEntitiesResponse], error) GetEntityTypes(context.Context, *connect.Request[v1beta1.GetEntityTypesRequest]) (*connect.Response[v1beta1.GetEntityTypesResponse], error) - // Domain: Entity Context & Impact (v2) + // Domain: Entity Context & Impact GetEntityContext(context.Context, *connect.Request[v1beta1.GetEntityContextRequest]) (*connect.Response[v1beta1.GetEntityContextResponse], error) GetEntityImpact(context.Context, *connect.Request[v1beta1.GetEntityImpactRequest]) (*connect.Response[v1beta1.GetEntityImpactResponse], error) - // Domain: Edges (v2) + // Domain: Edge UpsertEdge(context.Context, *connect.Request[v1beta1.UpsertEdgeRequest]) (*connect.Response[v1beta1.UpsertEdgeResponse], error) GetEdges(context.Context, *connect.Request[v1beta1.GetEdgesRequest]) (*connect.Response[v1beta1.GetEdgesResponse], error) DeleteEdge(context.Context, *connect.Request[v1beta1.DeleteEdgeRequest]) (*connect.Response[v1beta1.DeleteEdgeResponse], error) + // Domain: Star + StarEntity(context.Context, *connect.Request[v1beta1.StarEntityRequest]) (*connect.Response[v1beta1.StarEntityResponse], error) + UnstarEntity(context.Context, *connect.Request[v1beta1.UnstarEntityRequest]) (*connect.Response[v1beta1.UnstarEntityResponse], error) + GetUserStarredEntities(context.Context, *connect.Request[v1beta1.GetUserStarredEntitiesRequest]) (*connect.Response[v1beta1.GetUserStarredEntitiesResponse], error) + GetMyStarredEntities(context.Context, *connect.Request[v1beta1.GetMyStarredEntitiesRequest]) (*connect.Response[v1beta1.GetMyStarredEntitiesResponse], error) + GetMyStarredEntity(context.Context, *connect.Request[v1beta1.GetMyStarredEntityRequest]) (*connect.Response[v1beta1.GetMyStarredEntityResponse], error) + GetEntityStargazers(context.Context, *connect.Request[v1beta1.GetEntityStargazersRequest]) (*connect.Response[v1beta1.GetEntityStargazersResponse], error) + // Domain: Namespace + CreateNamespace(context.Context, *connect.Request[v1beta1.CreateNamespaceRequest]) (*connect.Response[v1beta1.CreateNamespaceResponse], error) + GetNamespace(context.Context, *connect.Request[v1beta1.GetNamespaceRequest]) (*connect.Response[v1beta1.GetNamespaceResponse], error) + UpdateNamespace(context.Context, *connect.Request[v1beta1.UpdateNamespaceRequest]) (*connect.Response[v1beta1.UpdateNamespaceResponse], error) + ListNamespaces(context.Context, *connect.Request[v1beta1.ListNamespacesRequest]) (*connect.Response[v1beta1.ListNamespacesResponse], error) } // NewCompassServiceClient constructs a client for the raystack.compass.v1beta1.CompassService @@ -276,238 +142,112 @@ func NewCompassServiceClient(httpClient connect.HTTPClient, baseURL string, opts baseURL = strings.TrimRight(baseURL, "/") compassServiceMethods := v1beta1.File_raystack_compass_v1beta1_service_proto.Services().ByName("CompassService").Methods() return &compassServiceClient{ - getAllDiscussions: connect.NewClient[v1beta1.GetAllDiscussionsRequest, v1beta1.GetAllDiscussionsResponse]( - httpClient, - baseURL+CompassServiceGetAllDiscussionsProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetAllDiscussions")), - connect.WithClientOptions(opts...), - ), - createDiscussion: connect.NewClient[v1beta1.CreateDiscussionRequest, v1beta1.CreateDiscussionResponse]( - httpClient, - baseURL+CompassServiceCreateDiscussionProcedure, - connect.WithSchema(compassServiceMethods.ByName("CreateDiscussion")), - connect.WithClientOptions(opts...), - ), - getDiscussion: connect.NewClient[v1beta1.GetDiscussionRequest, v1beta1.GetDiscussionResponse]( - httpClient, - baseURL+CompassServiceGetDiscussionProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetDiscussion")), - connect.WithClientOptions(opts...), - ), - patchDiscussion: connect.NewClient[v1beta1.PatchDiscussionRequest, v1beta1.PatchDiscussionResponse]( - httpClient, - baseURL+CompassServicePatchDiscussionProcedure, - connect.WithSchema(compassServiceMethods.ByName("PatchDiscussion")), - connect.WithClientOptions(opts...), - ), - createComment: connect.NewClient[v1beta1.CreateCommentRequest, v1beta1.CreateCommentResponse]( - httpClient, - baseURL+CompassServiceCreateCommentProcedure, - connect.WithSchema(compassServiceMethods.ByName("CreateComment")), - connect.WithClientOptions(opts...), - ), - getAllComments: connect.NewClient[v1beta1.GetAllCommentsRequest, v1beta1.GetAllCommentsResponse]( - httpClient, - baseURL+CompassServiceGetAllCommentsProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetAllComments")), - connect.WithClientOptions(opts...), - ), - getComment: connect.NewClient[v1beta1.GetCommentRequest, v1beta1.GetCommentResponse]( - httpClient, - baseURL+CompassServiceGetCommentProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetComment")), - connect.WithClientOptions(opts...), - ), - updateComment: connect.NewClient[v1beta1.UpdateCommentRequest, v1beta1.UpdateCommentResponse]( - httpClient, - baseURL+CompassServiceUpdateCommentProcedure, - connect.WithSchema(compassServiceMethods.ByName("UpdateComment")), - connect.WithClientOptions(opts...), - ), - deleteComment: connect.NewClient[v1beta1.DeleteCommentRequest, v1beta1.DeleteCommentResponse]( - httpClient, - baseURL+CompassServiceDeleteCommentProcedure, - connect.WithSchema(compassServiceMethods.ByName("DeleteComment")), - connect.WithClientOptions(opts...), - ), - searchAssets: connect.NewClient[v1beta1.SearchAssetsRequest, v1beta1.SearchAssetsResponse]( - httpClient, - baseURL+CompassServiceSearchAssetsProcedure, - connect.WithSchema(compassServiceMethods.ByName("SearchAssets")), - connect.WithClientOptions(opts...), - ), - suggestAssets: connect.NewClient[v1beta1.SuggestAssetsRequest, v1beta1.SuggestAssetsResponse]( - httpClient, - baseURL+CompassServiceSuggestAssetsProcedure, - connect.WithSchema(compassServiceMethods.ByName("SuggestAssets")), - connect.WithClientOptions(opts...), - ), - groupAssets: connect.NewClient[v1beta1.GroupAssetsRequest, v1beta1.GroupAssetsResponse]( - httpClient, - baseURL+CompassServiceGroupAssetsProcedure, - connect.WithSchema(compassServiceMethods.ByName("GroupAssets")), - connect.WithClientOptions(opts...), - ), - getGraph: connect.NewClient[v1beta1.GetGraphRequest, v1beta1.GetGraphResponse]( - httpClient, - baseURL+CompassServiceGetGraphProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetGraph")), - connect.WithClientOptions(opts...), - ), - getAllTypes: connect.NewClient[v1beta1.GetAllTypesRequest, v1beta1.GetAllTypesResponse]( - httpClient, - baseURL+CompassServiceGetAllTypesProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetAllTypes")), - connect.WithClientOptions(opts...), - ), - getAllAssets: connect.NewClient[v1beta1.GetAllAssetsRequest, v1beta1.GetAllAssetsResponse]( - httpClient, - baseURL+CompassServiceGetAllAssetsProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetAllAssets")), - connect.WithClientOptions(opts...), - ), - getAssetByID: connect.NewClient[v1beta1.GetAssetByIDRequest, v1beta1.GetAssetByIDResponse]( - httpClient, - baseURL+CompassServiceGetAssetByIDProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetAssetByID")), - connect.WithClientOptions(opts...), - ), - upsertAsset: connect.NewClient[v1beta1.UpsertAssetRequest, v1beta1.UpsertAssetResponse]( - httpClient, - baseURL+CompassServiceUpsertAssetProcedure, - connect.WithSchema(compassServiceMethods.ByName("UpsertAsset")), - connect.WithClientOptions(opts...), - ), - upsertPatchAsset: connect.NewClient[v1beta1.UpsertPatchAssetRequest, v1beta1.UpsertPatchAssetResponse]( - httpClient, - baseURL+CompassServiceUpsertPatchAssetProcedure, - connect.WithSchema(compassServiceMethods.ByName("UpsertPatchAsset")), - connect.WithClientOptions(opts...), - ), - deleteAsset: connect.NewClient[v1beta1.DeleteAssetRequest, v1beta1.DeleteAssetResponse]( - httpClient, - baseURL+CompassServiceDeleteAssetProcedure, - connect.WithSchema(compassServiceMethods.ByName("DeleteAsset")), - connect.WithClientOptions(opts...), - ), - getAssetStargazers: connect.NewClient[v1beta1.GetAssetStargazersRequest, v1beta1.GetAssetStargazersResponse]( - httpClient, - baseURL+CompassServiceGetAssetStargazersProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetAssetStargazers")), - connect.WithClientOptions(opts...), - ), - getAssetVersionHistory: connect.NewClient[v1beta1.GetAssetVersionHistoryRequest, v1beta1.GetAssetVersionHistoryResponse]( - httpClient, - baseURL+CompassServiceGetAssetVersionHistoryProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetAssetVersionHistory")), - connect.WithClientOptions(opts...), - ), - getAssetByVersion: connect.NewClient[v1beta1.GetAssetByVersionRequest, v1beta1.GetAssetByVersionResponse]( + getAllEntities: connect.NewClient[v1beta1.GetAllEntitiesRequest, v1beta1.GetAllEntitiesResponse]( httpClient, - baseURL+CompassServiceGetAssetByVersionProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetAssetByVersion")), + baseURL+CompassServiceGetAllEntitiesProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetAllEntities")), connect.WithClientOptions(opts...), ), - createAssetProbe: connect.NewClient[v1beta1.CreateAssetProbeRequest, v1beta1.CreateAssetProbeResponse]( + getEntityByID: connect.NewClient[v1beta1.GetEntityByIDRequest, v1beta1.GetEntityByIDResponse]( httpClient, - baseURL+CompassServiceCreateAssetProbeProcedure, - connect.WithSchema(compassServiceMethods.ByName("CreateAssetProbe")), + baseURL+CompassServiceGetEntityByIDProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetEntityByID")), connect.WithClientOptions(opts...), ), - getUserStarredAssets: connect.NewClient[v1beta1.GetUserStarredAssetsRequest, v1beta1.GetUserStarredAssetsResponse]( + upsertEntity: connect.NewClient[v1beta1.UpsertEntityRequest, v1beta1.UpsertEntityResponse]( httpClient, - baseURL+CompassServiceGetUserStarredAssetsProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetUserStarredAssets")), + baseURL+CompassServiceUpsertEntityProcedure, + connect.WithSchema(compassServiceMethods.ByName("UpsertEntity")), connect.WithClientOptions(opts...), ), - getMyStarredAssets: connect.NewClient[v1beta1.GetMyStarredAssetsRequest, v1beta1.GetMyStarredAssetsResponse]( + deleteEntity: connect.NewClient[v1beta1.DeleteEntityRequest, v1beta1.DeleteEntityResponse]( httpClient, - baseURL+CompassServiceGetMyStarredAssetsProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetMyStarredAssets")), + baseURL+CompassServiceDeleteEntityProcedure, + connect.WithSchema(compassServiceMethods.ByName("DeleteEntity")), connect.WithClientOptions(opts...), ), - getMyStarredAsset: connect.NewClient[v1beta1.GetMyStarredAssetRequest, v1beta1.GetMyStarredAssetResponse]( + searchEntities: connect.NewClient[v1beta1.SearchEntitiesRequest, v1beta1.SearchEntitiesResponse]( httpClient, - baseURL+CompassServiceGetMyStarredAssetProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetMyStarredAsset")), + baseURL+CompassServiceSearchEntitiesProcedure, + connect.WithSchema(compassServiceMethods.ByName("SearchEntities")), connect.WithClientOptions(opts...), ), - starAsset: connect.NewClient[v1beta1.StarAssetRequest, v1beta1.StarAssetResponse]( + suggestEntities: connect.NewClient[v1beta1.SuggestEntitiesRequest, v1beta1.SuggestEntitiesResponse]( httpClient, - baseURL+CompassServiceStarAssetProcedure, - connect.WithSchema(compassServiceMethods.ByName("StarAsset")), + baseURL+CompassServiceSuggestEntitiesProcedure, + connect.WithSchema(compassServiceMethods.ByName("SuggestEntities")), connect.WithClientOptions(opts...), ), - unstarAsset: connect.NewClient[v1beta1.UnstarAssetRequest, v1beta1.UnstarAssetResponse]( + getEntityTypes: connect.NewClient[v1beta1.GetEntityTypesRequest, v1beta1.GetEntityTypesResponse]( httpClient, - baseURL+CompassServiceUnstarAssetProcedure, - connect.WithSchema(compassServiceMethods.ByName("UnstarAsset")), + baseURL+CompassServiceGetEntityTypesProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetEntityTypes")), connect.WithClientOptions(opts...), ), - getMyDiscussions: connect.NewClient[v1beta1.GetMyDiscussionsRequest, v1beta1.GetMyDiscussionsResponse]( + getEntityContext: connect.NewClient[v1beta1.GetEntityContextRequest, v1beta1.GetEntityContextResponse]( httpClient, - baseURL+CompassServiceGetMyDiscussionsProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetMyDiscussions")), + baseURL+CompassServiceGetEntityContextProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetEntityContext")), connect.WithClientOptions(opts...), ), - createTagAsset: connect.NewClient[v1beta1.CreateTagAssetRequest, v1beta1.CreateTagAssetResponse]( + getEntityImpact: connect.NewClient[v1beta1.GetEntityImpactRequest, v1beta1.GetEntityImpactResponse]( httpClient, - baseURL+CompassServiceCreateTagAssetProcedure, - connect.WithSchema(compassServiceMethods.ByName("CreateTagAsset")), + baseURL+CompassServiceGetEntityImpactProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetEntityImpact")), connect.WithClientOptions(opts...), ), - getTagByAssetAndTemplate: connect.NewClient[v1beta1.GetTagByAssetAndTemplateRequest, v1beta1.GetTagByAssetAndTemplateResponse]( + upsertEdge: connect.NewClient[v1beta1.UpsertEdgeRequest, v1beta1.UpsertEdgeResponse]( httpClient, - baseURL+CompassServiceGetTagByAssetAndTemplateProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetTagByAssetAndTemplate")), + baseURL+CompassServiceUpsertEdgeProcedure, + connect.WithSchema(compassServiceMethods.ByName("UpsertEdge")), connect.WithClientOptions(opts...), ), - updateTagAsset: connect.NewClient[v1beta1.UpdateTagAssetRequest, v1beta1.UpdateTagAssetResponse]( + getEdges: connect.NewClient[v1beta1.GetEdgesRequest, v1beta1.GetEdgesResponse]( httpClient, - baseURL+CompassServiceUpdateTagAssetProcedure, - connect.WithSchema(compassServiceMethods.ByName("UpdateTagAsset")), + baseURL+CompassServiceGetEdgesProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetEdges")), connect.WithClientOptions(opts...), ), - deleteTagAsset: connect.NewClient[v1beta1.DeleteTagAssetRequest, v1beta1.DeleteTagAssetResponse]( + deleteEdge: connect.NewClient[v1beta1.DeleteEdgeRequest, v1beta1.DeleteEdgeResponse]( httpClient, - baseURL+CompassServiceDeleteTagAssetProcedure, - connect.WithSchema(compassServiceMethods.ByName("DeleteTagAsset")), + baseURL+CompassServiceDeleteEdgeProcedure, + connect.WithSchema(compassServiceMethods.ByName("DeleteEdge")), connect.WithClientOptions(opts...), ), - getAllTagsByAsset: connect.NewClient[v1beta1.GetAllTagsByAssetRequest, v1beta1.GetAllTagsByAssetResponse]( + starEntity: connect.NewClient[v1beta1.StarEntityRequest, v1beta1.StarEntityResponse]( httpClient, - baseURL+CompassServiceGetAllTagsByAssetProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetAllTagsByAsset")), + baseURL+CompassServiceStarEntityProcedure, + connect.WithSchema(compassServiceMethods.ByName("StarEntity")), connect.WithClientOptions(opts...), ), - getAllTagTemplates: connect.NewClient[v1beta1.GetAllTagTemplatesRequest, v1beta1.GetAllTagTemplatesResponse]( + unstarEntity: connect.NewClient[v1beta1.UnstarEntityRequest, v1beta1.UnstarEntityResponse]( httpClient, - baseURL+CompassServiceGetAllTagTemplatesProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetAllTagTemplates")), + baseURL+CompassServiceUnstarEntityProcedure, + connect.WithSchema(compassServiceMethods.ByName("UnstarEntity")), connect.WithClientOptions(opts...), ), - createTagTemplate: connect.NewClient[v1beta1.CreateTagTemplateRequest, v1beta1.CreateTagTemplateResponse]( + getUserStarredEntities: connect.NewClient[v1beta1.GetUserStarredEntitiesRequest, v1beta1.GetUserStarredEntitiesResponse]( httpClient, - baseURL+CompassServiceCreateTagTemplateProcedure, - connect.WithSchema(compassServiceMethods.ByName("CreateTagTemplate")), + baseURL+CompassServiceGetUserStarredEntitiesProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetUserStarredEntities")), connect.WithClientOptions(opts...), ), - getTagTemplate: connect.NewClient[v1beta1.GetTagTemplateRequest, v1beta1.GetTagTemplateResponse]( + getMyStarredEntities: connect.NewClient[v1beta1.GetMyStarredEntitiesRequest, v1beta1.GetMyStarredEntitiesResponse]( httpClient, - baseURL+CompassServiceGetTagTemplateProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetTagTemplate")), + baseURL+CompassServiceGetMyStarredEntitiesProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetMyStarredEntities")), connect.WithClientOptions(opts...), ), - updateTagTemplate: connect.NewClient[v1beta1.UpdateTagTemplateRequest, v1beta1.UpdateTagTemplateResponse]( + getMyStarredEntity: connect.NewClient[v1beta1.GetMyStarredEntityRequest, v1beta1.GetMyStarredEntityResponse]( httpClient, - baseURL+CompassServiceUpdateTagTemplateProcedure, - connect.WithSchema(compassServiceMethods.ByName("UpdateTagTemplate")), + baseURL+CompassServiceGetMyStarredEntityProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetMyStarredEntity")), connect.WithClientOptions(opts...), ), - deleteTagTemplate: connect.NewClient[v1beta1.DeleteTagTemplateRequest, v1beta1.DeleteTagTemplateResponse]( + getEntityStargazers: connect.NewClient[v1beta1.GetEntityStargazersRequest, v1beta1.GetEntityStargazersResponse]( httpClient, - baseURL+CompassServiceDeleteTagTemplateProcedure, - connect.WithSchema(compassServiceMethods.ByName("DeleteTagTemplate")), + baseURL+CompassServiceGetEntityStargazersProcedure, + connect.WithSchema(compassServiceMethods.ByName("GetEntityStargazers")), connect.WithClientOptions(opts...), ), createNamespace: connect.NewClient[v1beta1.CreateNamespaceRequest, v1beta1.CreateNamespaceResponse]( @@ -534,467 +274,149 @@ func NewCompassServiceClient(httpClient connect.HTTPClient, baseURL string, opts connect.WithSchema(compassServiceMethods.ByName("ListNamespaces")), connect.WithClientOptions(opts...), ), - getAllEntities: connect.NewClient[v1beta1.GetAllEntitiesRequest, v1beta1.GetAllEntitiesResponse]( - httpClient, - baseURL+CompassServiceGetAllEntitiesProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetAllEntities")), - connect.WithClientOptions(opts...), - ), - getEntityByID: connect.NewClient[v1beta1.GetEntityByIDRequest, v1beta1.GetEntityByIDResponse]( - httpClient, - baseURL+CompassServiceGetEntityByIDProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetEntityByID")), - connect.WithClientOptions(opts...), - ), - upsertEntity: connect.NewClient[v1beta1.UpsertEntityRequest, v1beta1.UpsertEntityResponse]( - httpClient, - baseURL+CompassServiceUpsertEntityProcedure, - connect.WithSchema(compassServiceMethods.ByName("UpsertEntity")), - connect.WithClientOptions(opts...), - ), - deleteEntity: connect.NewClient[v1beta1.DeleteEntityRequest, v1beta1.DeleteEntityResponse]( - httpClient, - baseURL+CompassServiceDeleteEntityProcedure, - connect.WithSchema(compassServiceMethods.ByName("DeleteEntity")), - connect.WithClientOptions(opts...), - ), - searchEntities: connect.NewClient[v1beta1.SearchEntitiesRequest, v1beta1.SearchEntitiesResponse]( - httpClient, - baseURL+CompassServiceSearchEntitiesProcedure, - connect.WithSchema(compassServiceMethods.ByName("SearchEntities")), - connect.WithClientOptions(opts...), - ), - suggestEntities: connect.NewClient[v1beta1.SuggestEntitiesRequest, v1beta1.SuggestEntitiesResponse]( - httpClient, - baseURL+CompassServiceSuggestEntitiesProcedure, - connect.WithSchema(compassServiceMethods.ByName("SuggestEntities")), - connect.WithClientOptions(opts...), - ), - getEntityTypes: connect.NewClient[v1beta1.GetEntityTypesRequest, v1beta1.GetEntityTypesResponse]( - httpClient, - baseURL+CompassServiceGetEntityTypesProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetEntityTypes")), - connect.WithClientOptions(opts...), - ), - getEntityContext: connect.NewClient[v1beta1.GetEntityContextRequest, v1beta1.GetEntityContextResponse]( - httpClient, - baseURL+CompassServiceGetEntityContextProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetEntityContext")), - connect.WithClientOptions(opts...), - ), - getEntityImpact: connect.NewClient[v1beta1.GetEntityImpactRequest, v1beta1.GetEntityImpactResponse]( - httpClient, - baseURL+CompassServiceGetEntityImpactProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetEntityImpact")), - connect.WithClientOptions(opts...), - ), - upsertEdge: connect.NewClient[v1beta1.UpsertEdgeRequest, v1beta1.UpsertEdgeResponse]( - httpClient, - baseURL+CompassServiceUpsertEdgeProcedure, - connect.WithSchema(compassServiceMethods.ByName("UpsertEdge")), - connect.WithClientOptions(opts...), - ), - getEdges: connect.NewClient[v1beta1.GetEdgesRequest, v1beta1.GetEdgesResponse]( - httpClient, - baseURL+CompassServiceGetEdgesProcedure, - connect.WithSchema(compassServiceMethods.ByName("GetEdges")), - connect.WithClientOptions(opts...), - ), - deleteEdge: connect.NewClient[v1beta1.DeleteEdgeRequest, v1beta1.DeleteEdgeResponse]( - httpClient, - baseURL+CompassServiceDeleteEdgeProcedure, - connect.WithSchema(compassServiceMethods.ByName("DeleteEdge")), - connect.WithClientOptions(opts...), - ), } } // compassServiceClient implements CompassServiceClient. type compassServiceClient struct { - getAllDiscussions *connect.Client[v1beta1.GetAllDiscussionsRequest, v1beta1.GetAllDiscussionsResponse] - createDiscussion *connect.Client[v1beta1.CreateDiscussionRequest, v1beta1.CreateDiscussionResponse] - getDiscussion *connect.Client[v1beta1.GetDiscussionRequest, v1beta1.GetDiscussionResponse] - patchDiscussion *connect.Client[v1beta1.PatchDiscussionRequest, v1beta1.PatchDiscussionResponse] - createComment *connect.Client[v1beta1.CreateCommentRequest, v1beta1.CreateCommentResponse] - getAllComments *connect.Client[v1beta1.GetAllCommentsRequest, v1beta1.GetAllCommentsResponse] - getComment *connect.Client[v1beta1.GetCommentRequest, v1beta1.GetCommentResponse] - updateComment *connect.Client[v1beta1.UpdateCommentRequest, v1beta1.UpdateCommentResponse] - deleteComment *connect.Client[v1beta1.DeleteCommentRequest, v1beta1.DeleteCommentResponse] - searchAssets *connect.Client[v1beta1.SearchAssetsRequest, v1beta1.SearchAssetsResponse] - suggestAssets *connect.Client[v1beta1.SuggestAssetsRequest, v1beta1.SuggestAssetsResponse] - groupAssets *connect.Client[v1beta1.GroupAssetsRequest, v1beta1.GroupAssetsResponse] - getGraph *connect.Client[v1beta1.GetGraphRequest, v1beta1.GetGraphResponse] - getAllTypes *connect.Client[v1beta1.GetAllTypesRequest, v1beta1.GetAllTypesResponse] - getAllAssets *connect.Client[v1beta1.GetAllAssetsRequest, v1beta1.GetAllAssetsResponse] - getAssetByID *connect.Client[v1beta1.GetAssetByIDRequest, v1beta1.GetAssetByIDResponse] - upsertAsset *connect.Client[v1beta1.UpsertAssetRequest, v1beta1.UpsertAssetResponse] - upsertPatchAsset *connect.Client[v1beta1.UpsertPatchAssetRequest, v1beta1.UpsertPatchAssetResponse] - deleteAsset *connect.Client[v1beta1.DeleteAssetRequest, v1beta1.DeleteAssetResponse] - getAssetStargazers *connect.Client[v1beta1.GetAssetStargazersRequest, v1beta1.GetAssetStargazersResponse] - getAssetVersionHistory *connect.Client[v1beta1.GetAssetVersionHistoryRequest, v1beta1.GetAssetVersionHistoryResponse] - getAssetByVersion *connect.Client[v1beta1.GetAssetByVersionRequest, v1beta1.GetAssetByVersionResponse] - createAssetProbe *connect.Client[v1beta1.CreateAssetProbeRequest, v1beta1.CreateAssetProbeResponse] - getUserStarredAssets *connect.Client[v1beta1.GetUserStarredAssetsRequest, v1beta1.GetUserStarredAssetsResponse] - getMyStarredAssets *connect.Client[v1beta1.GetMyStarredAssetsRequest, v1beta1.GetMyStarredAssetsResponse] - getMyStarredAsset *connect.Client[v1beta1.GetMyStarredAssetRequest, v1beta1.GetMyStarredAssetResponse] - starAsset *connect.Client[v1beta1.StarAssetRequest, v1beta1.StarAssetResponse] - unstarAsset *connect.Client[v1beta1.UnstarAssetRequest, v1beta1.UnstarAssetResponse] - getMyDiscussions *connect.Client[v1beta1.GetMyDiscussionsRequest, v1beta1.GetMyDiscussionsResponse] - createTagAsset *connect.Client[v1beta1.CreateTagAssetRequest, v1beta1.CreateTagAssetResponse] - getTagByAssetAndTemplate *connect.Client[v1beta1.GetTagByAssetAndTemplateRequest, v1beta1.GetTagByAssetAndTemplateResponse] - updateTagAsset *connect.Client[v1beta1.UpdateTagAssetRequest, v1beta1.UpdateTagAssetResponse] - deleteTagAsset *connect.Client[v1beta1.DeleteTagAssetRequest, v1beta1.DeleteTagAssetResponse] - getAllTagsByAsset *connect.Client[v1beta1.GetAllTagsByAssetRequest, v1beta1.GetAllTagsByAssetResponse] - getAllTagTemplates *connect.Client[v1beta1.GetAllTagTemplatesRequest, v1beta1.GetAllTagTemplatesResponse] - createTagTemplate *connect.Client[v1beta1.CreateTagTemplateRequest, v1beta1.CreateTagTemplateResponse] - getTagTemplate *connect.Client[v1beta1.GetTagTemplateRequest, v1beta1.GetTagTemplateResponse] - updateTagTemplate *connect.Client[v1beta1.UpdateTagTemplateRequest, v1beta1.UpdateTagTemplateResponse] - deleteTagTemplate *connect.Client[v1beta1.DeleteTagTemplateRequest, v1beta1.DeleteTagTemplateResponse] - createNamespace *connect.Client[v1beta1.CreateNamespaceRequest, v1beta1.CreateNamespaceResponse] - getNamespace *connect.Client[v1beta1.GetNamespaceRequest, v1beta1.GetNamespaceResponse] - updateNamespace *connect.Client[v1beta1.UpdateNamespaceRequest, v1beta1.UpdateNamespaceResponse] - listNamespaces *connect.Client[v1beta1.ListNamespacesRequest, v1beta1.ListNamespacesResponse] - getAllEntities *connect.Client[v1beta1.GetAllEntitiesRequest, v1beta1.GetAllEntitiesResponse] - getEntityByID *connect.Client[v1beta1.GetEntityByIDRequest, v1beta1.GetEntityByIDResponse] - upsertEntity *connect.Client[v1beta1.UpsertEntityRequest, v1beta1.UpsertEntityResponse] - deleteEntity *connect.Client[v1beta1.DeleteEntityRequest, v1beta1.DeleteEntityResponse] - searchEntities *connect.Client[v1beta1.SearchEntitiesRequest, v1beta1.SearchEntitiesResponse] - suggestEntities *connect.Client[v1beta1.SuggestEntitiesRequest, v1beta1.SuggestEntitiesResponse] - getEntityTypes *connect.Client[v1beta1.GetEntityTypesRequest, v1beta1.GetEntityTypesResponse] - getEntityContext *connect.Client[v1beta1.GetEntityContextRequest, v1beta1.GetEntityContextResponse] - getEntityImpact *connect.Client[v1beta1.GetEntityImpactRequest, v1beta1.GetEntityImpactResponse] - upsertEdge *connect.Client[v1beta1.UpsertEdgeRequest, v1beta1.UpsertEdgeResponse] - getEdges *connect.Client[v1beta1.GetEdgesRequest, v1beta1.GetEdgesResponse] - deleteEdge *connect.Client[v1beta1.DeleteEdgeRequest, v1beta1.DeleteEdgeResponse] + getAllEntities *connect.Client[v1beta1.GetAllEntitiesRequest, v1beta1.GetAllEntitiesResponse] + getEntityByID *connect.Client[v1beta1.GetEntityByIDRequest, v1beta1.GetEntityByIDResponse] + upsertEntity *connect.Client[v1beta1.UpsertEntityRequest, v1beta1.UpsertEntityResponse] + deleteEntity *connect.Client[v1beta1.DeleteEntityRequest, v1beta1.DeleteEntityResponse] + searchEntities *connect.Client[v1beta1.SearchEntitiesRequest, v1beta1.SearchEntitiesResponse] + suggestEntities *connect.Client[v1beta1.SuggestEntitiesRequest, v1beta1.SuggestEntitiesResponse] + getEntityTypes *connect.Client[v1beta1.GetEntityTypesRequest, v1beta1.GetEntityTypesResponse] + getEntityContext *connect.Client[v1beta1.GetEntityContextRequest, v1beta1.GetEntityContextResponse] + getEntityImpact *connect.Client[v1beta1.GetEntityImpactRequest, v1beta1.GetEntityImpactResponse] + upsertEdge *connect.Client[v1beta1.UpsertEdgeRequest, v1beta1.UpsertEdgeResponse] + getEdges *connect.Client[v1beta1.GetEdgesRequest, v1beta1.GetEdgesResponse] + deleteEdge *connect.Client[v1beta1.DeleteEdgeRequest, v1beta1.DeleteEdgeResponse] + starEntity *connect.Client[v1beta1.StarEntityRequest, v1beta1.StarEntityResponse] + unstarEntity *connect.Client[v1beta1.UnstarEntityRequest, v1beta1.UnstarEntityResponse] + getUserStarredEntities *connect.Client[v1beta1.GetUserStarredEntitiesRequest, v1beta1.GetUserStarredEntitiesResponse] + getMyStarredEntities *connect.Client[v1beta1.GetMyStarredEntitiesRequest, v1beta1.GetMyStarredEntitiesResponse] + getMyStarredEntity *connect.Client[v1beta1.GetMyStarredEntityRequest, v1beta1.GetMyStarredEntityResponse] + getEntityStargazers *connect.Client[v1beta1.GetEntityStargazersRequest, v1beta1.GetEntityStargazersResponse] + createNamespace *connect.Client[v1beta1.CreateNamespaceRequest, v1beta1.CreateNamespaceResponse] + getNamespace *connect.Client[v1beta1.GetNamespaceRequest, v1beta1.GetNamespaceResponse] + updateNamespace *connect.Client[v1beta1.UpdateNamespaceRequest, v1beta1.UpdateNamespaceResponse] + listNamespaces *connect.Client[v1beta1.ListNamespacesRequest, v1beta1.ListNamespacesResponse] } -// GetAllDiscussions calls raystack.compass.v1beta1.CompassService.GetAllDiscussions. -func (c *compassServiceClient) GetAllDiscussions(ctx context.Context, req *connect.Request[v1beta1.GetAllDiscussionsRequest]) (*connect.Response[v1beta1.GetAllDiscussionsResponse], error) { - return c.getAllDiscussions.CallUnary(ctx, req) +// GetAllEntities calls raystack.compass.v1beta1.CompassService.GetAllEntities. +func (c *compassServiceClient) GetAllEntities(ctx context.Context, req *connect.Request[v1beta1.GetAllEntitiesRequest]) (*connect.Response[v1beta1.GetAllEntitiesResponse], error) { + return c.getAllEntities.CallUnary(ctx, req) } -// CreateDiscussion calls raystack.compass.v1beta1.CompassService.CreateDiscussion. -func (c *compassServiceClient) CreateDiscussion(ctx context.Context, req *connect.Request[v1beta1.CreateDiscussionRequest]) (*connect.Response[v1beta1.CreateDiscussionResponse], error) { - return c.createDiscussion.CallUnary(ctx, req) +// GetEntityByID calls raystack.compass.v1beta1.CompassService.GetEntityByID. +func (c *compassServiceClient) GetEntityByID(ctx context.Context, req *connect.Request[v1beta1.GetEntityByIDRequest]) (*connect.Response[v1beta1.GetEntityByIDResponse], error) { + return c.getEntityByID.CallUnary(ctx, req) } -// GetDiscussion calls raystack.compass.v1beta1.CompassService.GetDiscussion. -func (c *compassServiceClient) GetDiscussion(ctx context.Context, req *connect.Request[v1beta1.GetDiscussionRequest]) (*connect.Response[v1beta1.GetDiscussionResponse], error) { - return c.getDiscussion.CallUnary(ctx, req) +// UpsertEntity calls raystack.compass.v1beta1.CompassService.UpsertEntity. +func (c *compassServiceClient) UpsertEntity(ctx context.Context, req *connect.Request[v1beta1.UpsertEntityRequest]) (*connect.Response[v1beta1.UpsertEntityResponse], error) { + return c.upsertEntity.CallUnary(ctx, req) } -// PatchDiscussion calls raystack.compass.v1beta1.CompassService.PatchDiscussion. -func (c *compassServiceClient) PatchDiscussion(ctx context.Context, req *connect.Request[v1beta1.PatchDiscussionRequest]) (*connect.Response[v1beta1.PatchDiscussionResponse], error) { - return c.patchDiscussion.CallUnary(ctx, req) +// DeleteEntity calls raystack.compass.v1beta1.CompassService.DeleteEntity. +func (c *compassServiceClient) DeleteEntity(ctx context.Context, req *connect.Request[v1beta1.DeleteEntityRequest]) (*connect.Response[v1beta1.DeleteEntityResponse], error) { + return c.deleteEntity.CallUnary(ctx, req) } -// CreateComment calls raystack.compass.v1beta1.CompassService.CreateComment. -func (c *compassServiceClient) CreateComment(ctx context.Context, req *connect.Request[v1beta1.CreateCommentRequest]) (*connect.Response[v1beta1.CreateCommentResponse], error) { - return c.createComment.CallUnary(ctx, req) +// SearchEntities calls raystack.compass.v1beta1.CompassService.SearchEntities. +func (c *compassServiceClient) SearchEntities(ctx context.Context, req *connect.Request[v1beta1.SearchEntitiesRequest]) (*connect.Response[v1beta1.SearchEntitiesResponse], error) { + return c.searchEntities.CallUnary(ctx, req) } -// GetAllComments calls raystack.compass.v1beta1.CompassService.GetAllComments. -func (c *compassServiceClient) GetAllComments(ctx context.Context, req *connect.Request[v1beta1.GetAllCommentsRequest]) (*connect.Response[v1beta1.GetAllCommentsResponse], error) { - return c.getAllComments.CallUnary(ctx, req) +// SuggestEntities calls raystack.compass.v1beta1.CompassService.SuggestEntities. +func (c *compassServiceClient) SuggestEntities(ctx context.Context, req *connect.Request[v1beta1.SuggestEntitiesRequest]) (*connect.Response[v1beta1.SuggestEntitiesResponse], error) { + return c.suggestEntities.CallUnary(ctx, req) } -// GetComment calls raystack.compass.v1beta1.CompassService.GetComment. -func (c *compassServiceClient) GetComment(ctx context.Context, req *connect.Request[v1beta1.GetCommentRequest]) (*connect.Response[v1beta1.GetCommentResponse], error) { - return c.getComment.CallUnary(ctx, req) +// GetEntityTypes calls raystack.compass.v1beta1.CompassService.GetEntityTypes. +func (c *compassServiceClient) GetEntityTypes(ctx context.Context, req *connect.Request[v1beta1.GetEntityTypesRequest]) (*connect.Response[v1beta1.GetEntityTypesResponse], error) { + return c.getEntityTypes.CallUnary(ctx, req) } -// UpdateComment calls raystack.compass.v1beta1.CompassService.UpdateComment. -func (c *compassServiceClient) UpdateComment(ctx context.Context, req *connect.Request[v1beta1.UpdateCommentRequest]) (*connect.Response[v1beta1.UpdateCommentResponse], error) { - return c.updateComment.CallUnary(ctx, req) +// GetEntityContext calls raystack.compass.v1beta1.CompassService.GetEntityContext. +func (c *compassServiceClient) GetEntityContext(ctx context.Context, req *connect.Request[v1beta1.GetEntityContextRequest]) (*connect.Response[v1beta1.GetEntityContextResponse], error) { + return c.getEntityContext.CallUnary(ctx, req) } -// DeleteComment calls raystack.compass.v1beta1.CompassService.DeleteComment. -func (c *compassServiceClient) DeleteComment(ctx context.Context, req *connect.Request[v1beta1.DeleteCommentRequest]) (*connect.Response[v1beta1.DeleteCommentResponse], error) { - return c.deleteComment.CallUnary(ctx, req) +// GetEntityImpact calls raystack.compass.v1beta1.CompassService.GetEntityImpact. +func (c *compassServiceClient) GetEntityImpact(ctx context.Context, req *connect.Request[v1beta1.GetEntityImpactRequest]) (*connect.Response[v1beta1.GetEntityImpactResponse], error) { + return c.getEntityImpact.CallUnary(ctx, req) } -// SearchAssets calls raystack.compass.v1beta1.CompassService.SearchAssets. -func (c *compassServiceClient) SearchAssets(ctx context.Context, req *connect.Request[v1beta1.SearchAssetsRequest]) (*connect.Response[v1beta1.SearchAssetsResponse], error) { - return c.searchAssets.CallUnary(ctx, req) +// UpsertEdge calls raystack.compass.v1beta1.CompassService.UpsertEdge. +func (c *compassServiceClient) UpsertEdge(ctx context.Context, req *connect.Request[v1beta1.UpsertEdgeRequest]) (*connect.Response[v1beta1.UpsertEdgeResponse], error) { + return c.upsertEdge.CallUnary(ctx, req) } -// SuggestAssets calls raystack.compass.v1beta1.CompassService.SuggestAssets. -func (c *compassServiceClient) SuggestAssets(ctx context.Context, req *connect.Request[v1beta1.SuggestAssetsRequest]) (*connect.Response[v1beta1.SuggestAssetsResponse], error) { - return c.suggestAssets.CallUnary(ctx, req) +// GetEdges calls raystack.compass.v1beta1.CompassService.GetEdges. +func (c *compassServiceClient) GetEdges(ctx context.Context, req *connect.Request[v1beta1.GetEdgesRequest]) (*connect.Response[v1beta1.GetEdgesResponse], error) { + return c.getEdges.CallUnary(ctx, req) } -// GroupAssets calls raystack.compass.v1beta1.CompassService.GroupAssets. -func (c *compassServiceClient) GroupAssets(ctx context.Context, req *connect.Request[v1beta1.GroupAssetsRequest]) (*connect.Response[v1beta1.GroupAssetsResponse], error) { - return c.groupAssets.CallUnary(ctx, req) +// DeleteEdge calls raystack.compass.v1beta1.CompassService.DeleteEdge. +func (c *compassServiceClient) DeleteEdge(ctx context.Context, req *connect.Request[v1beta1.DeleteEdgeRequest]) (*connect.Response[v1beta1.DeleteEdgeResponse], error) { + return c.deleteEdge.CallUnary(ctx, req) } -// GetGraph calls raystack.compass.v1beta1.CompassService.GetGraph. -func (c *compassServiceClient) GetGraph(ctx context.Context, req *connect.Request[v1beta1.GetGraphRequest]) (*connect.Response[v1beta1.GetGraphResponse], error) { - return c.getGraph.CallUnary(ctx, req) +// StarEntity calls raystack.compass.v1beta1.CompassService.StarEntity. +func (c *compassServiceClient) StarEntity(ctx context.Context, req *connect.Request[v1beta1.StarEntityRequest]) (*connect.Response[v1beta1.StarEntityResponse], error) { + return c.starEntity.CallUnary(ctx, req) } -// GetAllTypes calls raystack.compass.v1beta1.CompassService.GetAllTypes. -func (c *compassServiceClient) GetAllTypes(ctx context.Context, req *connect.Request[v1beta1.GetAllTypesRequest]) (*connect.Response[v1beta1.GetAllTypesResponse], error) { - return c.getAllTypes.CallUnary(ctx, req) +// UnstarEntity calls raystack.compass.v1beta1.CompassService.UnstarEntity. +func (c *compassServiceClient) UnstarEntity(ctx context.Context, req *connect.Request[v1beta1.UnstarEntityRequest]) (*connect.Response[v1beta1.UnstarEntityResponse], error) { + return c.unstarEntity.CallUnary(ctx, req) } -// GetAllAssets calls raystack.compass.v1beta1.CompassService.GetAllAssets. -func (c *compassServiceClient) GetAllAssets(ctx context.Context, req *connect.Request[v1beta1.GetAllAssetsRequest]) (*connect.Response[v1beta1.GetAllAssetsResponse], error) { - return c.getAllAssets.CallUnary(ctx, req) +// GetUserStarredEntities calls raystack.compass.v1beta1.CompassService.GetUserStarredEntities. +func (c *compassServiceClient) GetUserStarredEntities(ctx context.Context, req *connect.Request[v1beta1.GetUserStarredEntitiesRequest]) (*connect.Response[v1beta1.GetUserStarredEntitiesResponse], error) { + return c.getUserStarredEntities.CallUnary(ctx, req) } -// GetAssetByID calls raystack.compass.v1beta1.CompassService.GetAssetByID. -func (c *compassServiceClient) GetAssetByID(ctx context.Context, req *connect.Request[v1beta1.GetAssetByIDRequest]) (*connect.Response[v1beta1.GetAssetByIDResponse], error) { - return c.getAssetByID.CallUnary(ctx, req) +// GetMyStarredEntities calls raystack.compass.v1beta1.CompassService.GetMyStarredEntities. +func (c *compassServiceClient) GetMyStarredEntities(ctx context.Context, req *connect.Request[v1beta1.GetMyStarredEntitiesRequest]) (*connect.Response[v1beta1.GetMyStarredEntitiesResponse], error) { + return c.getMyStarredEntities.CallUnary(ctx, req) } -// UpsertAsset calls raystack.compass.v1beta1.CompassService.UpsertAsset. -func (c *compassServiceClient) UpsertAsset(ctx context.Context, req *connect.Request[v1beta1.UpsertAssetRequest]) (*connect.Response[v1beta1.UpsertAssetResponse], error) { - return c.upsertAsset.CallUnary(ctx, req) +// GetMyStarredEntity calls raystack.compass.v1beta1.CompassService.GetMyStarredEntity. +func (c *compassServiceClient) GetMyStarredEntity(ctx context.Context, req *connect.Request[v1beta1.GetMyStarredEntityRequest]) (*connect.Response[v1beta1.GetMyStarredEntityResponse], error) { + return c.getMyStarredEntity.CallUnary(ctx, req) } -// UpsertPatchAsset calls raystack.compass.v1beta1.CompassService.UpsertPatchAsset. -func (c *compassServiceClient) UpsertPatchAsset(ctx context.Context, req *connect.Request[v1beta1.UpsertPatchAssetRequest]) (*connect.Response[v1beta1.UpsertPatchAssetResponse], error) { - return c.upsertPatchAsset.CallUnary(ctx, req) +// GetEntityStargazers calls raystack.compass.v1beta1.CompassService.GetEntityStargazers. +func (c *compassServiceClient) GetEntityStargazers(ctx context.Context, req *connect.Request[v1beta1.GetEntityStargazersRequest]) (*connect.Response[v1beta1.GetEntityStargazersResponse], error) { + return c.getEntityStargazers.CallUnary(ctx, req) } -// DeleteAsset calls raystack.compass.v1beta1.CompassService.DeleteAsset. -func (c *compassServiceClient) DeleteAsset(ctx context.Context, req *connect.Request[v1beta1.DeleteAssetRequest]) (*connect.Response[v1beta1.DeleteAssetResponse], error) { - return c.deleteAsset.CallUnary(ctx, req) +// CreateNamespace calls raystack.compass.v1beta1.CompassService.CreateNamespace. +func (c *compassServiceClient) CreateNamespace(ctx context.Context, req *connect.Request[v1beta1.CreateNamespaceRequest]) (*connect.Response[v1beta1.CreateNamespaceResponse], error) { + return c.createNamespace.CallUnary(ctx, req) } -// GetAssetStargazers calls raystack.compass.v1beta1.CompassService.GetAssetStargazers. -func (c *compassServiceClient) GetAssetStargazers(ctx context.Context, req *connect.Request[v1beta1.GetAssetStargazersRequest]) (*connect.Response[v1beta1.GetAssetStargazersResponse], error) { - return c.getAssetStargazers.CallUnary(ctx, req) +// GetNamespace calls raystack.compass.v1beta1.CompassService.GetNamespace. +func (c *compassServiceClient) GetNamespace(ctx context.Context, req *connect.Request[v1beta1.GetNamespaceRequest]) (*connect.Response[v1beta1.GetNamespaceResponse], error) { + return c.getNamespace.CallUnary(ctx, req) } -// GetAssetVersionHistory calls raystack.compass.v1beta1.CompassService.GetAssetVersionHistory. -func (c *compassServiceClient) GetAssetVersionHistory(ctx context.Context, req *connect.Request[v1beta1.GetAssetVersionHistoryRequest]) (*connect.Response[v1beta1.GetAssetVersionHistoryResponse], error) { - return c.getAssetVersionHistory.CallUnary(ctx, req) +// UpdateNamespace calls raystack.compass.v1beta1.CompassService.UpdateNamespace. +func (c *compassServiceClient) UpdateNamespace(ctx context.Context, req *connect.Request[v1beta1.UpdateNamespaceRequest]) (*connect.Response[v1beta1.UpdateNamespaceResponse], error) { + return c.updateNamespace.CallUnary(ctx, req) } -// GetAssetByVersion calls raystack.compass.v1beta1.CompassService.GetAssetByVersion. -func (c *compassServiceClient) GetAssetByVersion(ctx context.Context, req *connect.Request[v1beta1.GetAssetByVersionRequest]) (*connect.Response[v1beta1.GetAssetByVersionResponse], error) { - return c.getAssetByVersion.CallUnary(ctx, req) -} - -// CreateAssetProbe calls raystack.compass.v1beta1.CompassService.CreateAssetProbe. -func (c *compassServiceClient) CreateAssetProbe(ctx context.Context, req *connect.Request[v1beta1.CreateAssetProbeRequest]) (*connect.Response[v1beta1.CreateAssetProbeResponse], error) { - return c.createAssetProbe.CallUnary(ctx, req) -} - -// GetUserStarredAssets calls raystack.compass.v1beta1.CompassService.GetUserStarredAssets. -func (c *compassServiceClient) GetUserStarredAssets(ctx context.Context, req *connect.Request[v1beta1.GetUserStarredAssetsRequest]) (*connect.Response[v1beta1.GetUserStarredAssetsResponse], error) { - return c.getUserStarredAssets.CallUnary(ctx, req) -} - -// GetMyStarredAssets calls raystack.compass.v1beta1.CompassService.GetMyStarredAssets. -func (c *compassServiceClient) GetMyStarredAssets(ctx context.Context, req *connect.Request[v1beta1.GetMyStarredAssetsRequest]) (*connect.Response[v1beta1.GetMyStarredAssetsResponse], error) { - return c.getMyStarredAssets.CallUnary(ctx, req) -} - -// GetMyStarredAsset calls raystack.compass.v1beta1.CompassService.GetMyStarredAsset. -func (c *compassServiceClient) GetMyStarredAsset(ctx context.Context, req *connect.Request[v1beta1.GetMyStarredAssetRequest]) (*connect.Response[v1beta1.GetMyStarredAssetResponse], error) { - return c.getMyStarredAsset.CallUnary(ctx, req) -} - -// StarAsset calls raystack.compass.v1beta1.CompassService.StarAsset. -func (c *compassServiceClient) StarAsset(ctx context.Context, req *connect.Request[v1beta1.StarAssetRequest]) (*connect.Response[v1beta1.StarAssetResponse], error) { - return c.starAsset.CallUnary(ctx, req) -} - -// UnstarAsset calls raystack.compass.v1beta1.CompassService.UnstarAsset. -func (c *compassServiceClient) UnstarAsset(ctx context.Context, req *connect.Request[v1beta1.UnstarAssetRequest]) (*connect.Response[v1beta1.UnstarAssetResponse], error) { - return c.unstarAsset.CallUnary(ctx, req) -} - -// GetMyDiscussions calls raystack.compass.v1beta1.CompassService.GetMyDiscussions. -func (c *compassServiceClient) GetMyDiscussions(ctx context.Context, req *connect.Request[v1beta1.GetMyDiscussionsRequest]) (*connect.Response[v1beta1.GetMyDiscussionsResponse], error) { - return c.getMyDiscussions.CallUnary(ctx, req) -} - -// CreateTagAsset calls raystack.compass.v1beta1.CompassService.CreateTagAsset. -func (c *compassServiceClient) CreateTagAsset(ctx context.Context, req *connect.Request[v1beta1.CreateTagAssetRequest]) (*connect.Response[v1beta1.CreateTagAssetResponse], error) { - return c.createTagAsset.CallUnary(ctx, req) -} - -// GetTagByAssetAndTemplate calls raystack.compass.v1beta1.CompassService.GetTagByAssetAndTemplate. -func (c *compassServiceClient) GetTagByAssetAndTemplate(ctx context.Context, req *connect.Request[v1beta1.GetTagByAssetAndTemplateRequest]) (*connect.Response[v1beta1.GetTagByAssetAndTemplateResponse], error) { - return c.getTagByAssetAndTemplate.CallUnary(ctx, req) -} - -// UpdateTagAsset calls raystack.compass.v1beta1.CompassService.UpdateTagAsset. -func (c *compassServiceClient) UpdateTagAsset(ctx context.Context, req *connect.Request[v1beta1.UpdateTagAssetRequest]) (*connect.Response[v1beta1.UpdateTagAssetResponse], error) { - return c.updateTagAsset.CallUnary(ctx, req) -} - -// DeleteTagAsset calls raystack.compass.v1beta1.CompassService.DeleteTagAsset. -func (c *compassServiceClient) DeleteTagAsset(ctx context.Context, req *connect.Request[v1beta1.DeleteTagAssetRequest]) (*connect.Response[v1beta1.DeleteTagAssetResponse], error) { - return c.deleteTagAsset.CallUnary(ctx, req) -} - -// GetAllTagsByAsset calls raystack.compass.v1beta1.CompassService.GetAllTagsByAsset. -func (c *compassServiceClient) GetAllTagsByAsset(ctx context.Context, req *connect.Request[v1beta1.GetAllTagsByAssetRequest]) (*connect.Response[v1beta1.GetAllTagsByAssetResponse], error) { - return c.getAllTagsByAsset.CallUnary(ctx, req) -} - -// GetAllTagTemplates calls raystack.compass.v1beta1.CompassService.GetAllTagTemplates. -func (c *compassServiceClient) GetAllTagTemplates(ctx context.Context, req *connect.Request[v1beta1.GetAllTagTemplatesRequest]) (*connect.Response[v1beta1.GetAllTagTemplatesResponse], error) { - return c.getAllTagTemplates.CallUnary(ctx, req) -} - -// CreateTagTemplate calls raystack.compass.v1beta1.CompassService.CreateTagTemplate. -func (c *compassServiceClient) CreateTagTemplate(ctx context.Context, req *connect.Request[v1beta1.CreateTagTemplateRequest]) (*connect.Response[v1beta1.CreateTagTemplateResponse], error) { - return c.createTagTemplate.CallUnary(ctx, req) -} - -// GetTagTemplate calls raystack.compass.v1beta1.CompassService.GetTagTemplate. -func (c *compassServiceClient) GetTagTemplate(ctx context.Context, req *connect.Request[v1beta1.GetTagTemplateRequest]) (*connect.Response[v1beta1.GetTagTemplateResponse], error) { - return c.getTagTemplate.CallUnary(ctx, req) -} - -// UpdateTagTemplate calls raystack.compass.v1beta1.CompassService.UpdateTagTemplate. -func (c *compassServiceClient) UpdateTagTemplate(ctx context.Context, req *connect.Request[v1beta1.UpdateTagTemplateRequest]) (*connect.Response[v1beta1.UpdateTagTemplateResponse], error) { - return c.updateTagTemplate.CallUnary(ctx, req) -} - -// DeleteTagTemplate calls raystack.compass.v1beta1.CompassService.DeleteTagTemplate. -func (c *compassServiceClient) DeleteTagTemplate(ctx context.Context, req *connect.Request[v1beta1.DeleteTagTemplateRequest]) (*connect.Response[v1beta1.DeleteTagTemplateResponse], error) { - return c.deleteTagTemplate.CallUnary(ctx, req) -} - -// CreateNamespace calls raystack.compass.v1beta1.CompassService.CreateNamespace. -func (c *compassServiceClient) CreateNamespace(ctx context.Context, req *connect.Request[v1beta1.CreateNamespaceRequest]) (*connect.Response[v1beta1.CreateNamespaceResponse], error) { - return c.createNamespace.CallUnary(ctx, req) -} - -// GetNamespace calls raystack.compass.v1beta1.CompassService.GetNamespace. -func (c *compassServiceClient) GetNamespace(ctx context.Context, req *connect.Request[v1beta1.GetNamespaceRequest]) (*connect.Response[v1beta1.GetNamespaceResponse], error) { - return c.getNamespace.CallUnary(ctx, req) -} - -// UpdateNamespace calls raystack.compass.v1beta1.CompassService.UpdateNamespace. -func (c *compassServiceClient) UpdateNamespace(ctx context.Context, req *connect.Request[v1beta1.UpdateNamespaceRequest]) (*connect.Response[v1beta1.UpdateNamespaceResponse], error) { - return c.updateNamespace.CallUnary(ctx, req) -} - -// ListNamespaces calls raystack.compass.v1beta1.CompassService.ListNamespaces. -func (c *compassServiceClient) ListNamespaces(ctx context.Context, req *connect.Request[v1beta1.ListNamespacesRequest]) (*connect.Response[v1beta1.ListNamespacesResponse], error) { - return c.listNamespaces.CallUnary(ctx, req) -} - -// GetAllEntities calls raystack.compass.v1beta1.CompassService.GetAllEntities. -func (c *compassServiceClient) GetAllEntities(ctx context.Context, req *connect.Request[v1beta1.GetAllEntitiesRequest]) (*connect.Response[v1beta1.GetAllEntitiesResponse], error) { - return c.getAllEntities.CallUnary(ctx, req) -} - -// GetEntityByID calls raystack.compass.v1beta1.CompassService.GetEntityByID. -func (c *compassServiceClient) GetEntityByID(ctx context.Context, req *connect.Request[v1beta1.GetEntityByIDRequest]) (*connect.Response[v1beta1.GetEntityByIDResponse], error) { - return c.getEntityByID.CallUnary(ctx, req) -} - -// UpsertEntity calls raystack.compass.v1beta1.CompassService.UpsertEntity. -func (c *compassServiceClient) UpsertEntity(ctx context.Context, req *connect.Request[v1beta1.UpsertEntityRequest]) (*connect.Response[v1beta1.UpsertEntityResponse], error) { - return c.upsertEntity.CallUnary(ctx, req) -} - -// DeleteEntity calls raystack.compass.v1beta1.CompassService.DeleteEntity. -func (c *compassServiceClient) DeleteEntity(ctx context.Context, req *connect.Request[v1beta1.DeleteEntityRequest]) (*connect.Response[v1beta1.DeleteEntityResponse], error) { - return c.deleteEntity.CallUnary(ctx, req) -} - -// SearchEntities calls raystack.compass.v1beta1.CompassService.SearchEntities. -func (c *compassServiceClient) SearchEntities(ctx context.Context, req *connect.Request[v1beta1.SearchEntitiesRequest]) (*connect.Response[v1beta1.SearchEntitiesResponse], error) { - return c.searchEntities.CallUnary(ctx, req) -} - -// SuggestEntities calls raystack.compass.v1beta1.CompassService.SuggestEntities. -func (c *compassServiceClient) SuggestEntities(ctx context.Context, req *connect.Request[v1beta1.SuggestEntitiesRequest]) (*connect.Response[v1beta1.SuggestEntitiesResponse], error) { - return c.suggestEntities.CallUnary(ctx, req) -} - -// GetEntityTypes calls raystack.compass.v1beta1.CompassService.GetEntityTypes. -func (c *compassServiceClient) GetEntityTypes(ctx context.Context, req *connect.Request[v1beta1.GetEntityTypesRequest]) (*connect.Response[v1beta1.GetEntityTypesResponse], error) { - return c.getEntityTypes.CallUnary(ctx, req) -} - -// GetEntityContext calls raystack.compass.v1beta1.CompassService.GetEntityContext. -func (c *compassServiceClient) GetEntityContext(ctx context.Context, req *connect.Request[v1beta1.GetEntityContextRequest]) (*connect.Response[v1beta1.GetEntityContextResponse], error) { - return c.getEntityContext.CallUnary(ctx, req) -} - -// GetEntityImpact calls raystack.compass.v1beta1.CompassService.GetEntityImpact. -func (c *compassServiceClient) GetEntityImpact(ctx context.Context, req *connect.Request[v1beta1.GetEntityImpactRequest]) (*connect.Response[v1beta1.GetEntityImpactResponse], error) { - return c.getEntityImpact.CallUnary(ctx, req) -} - -// UpsertEdge calls raystack.compass.v1beta1.CompassService.UpsertEdge. -func (c *compassServiceClient) UpsertEdge(ctx context.Context, req *connect.Request[v1beta1.UpsertEdgeRequest]) (*connect.Response[v1beta1.UpsertEdgeResponse], error) { - return c.upsertEdge.CallUnary(ctx, req) -} - -// GetEdges calls raystack.compass.v1beta1.CompassService.GetEdges. -func (c *compassServiceClient) GetEdges(ctx context.Context, req *connect.Request[v1beta1.GetEdgesRequest]) (*connect.Response[v1beta1.GetEdgesResponse], error) { - return c.getEdges.CallUnary(ctx, req) -} - -// DeleteEdge calls raystack.compass.v1beta1.CompassService.DeleteEdge. -func (c *compassServiceClient) DeleteEdge(ctx context.Context, req *connect.Request[v1beta1.DeleteEdgeRequest]) (*connect.Response[v1beta1.DeleteEdgeResponse], error) { - return c.deleteEdge.CallUnary(ctx, req) +// ListNamespaces calls raystack.compass.v1beta1.CompassService.ListNamespaces. +func (c *compassServiceClient) ListNamespaces(ctx context.Context, req *connect.Request[v1beta1.ListNamespacesRequest]) (*connect.Response[v1beta1.ListNamespacesResponse], error) { + return c.listNamespaces.CallUnary(ctx, req) } // CompassServiceHandler is an implementation of the raystack.compass.v1beta1.CompassService // service. type CompassServiceHandler interface { - // Domain: Discussion - GetAllDiscussions(context.Context, *connect.Request[v1beta1.GetAllDiscussionsRequest]) (*connect.Response[v1beta1.GetAllDiscussionsResponse], error) - CreateDiscussion(context.Context, *connect.Request[v1beta1.CreateDiscussionRequest]) (*connect.Response[v1beta1.CreateDiscussionResponse], error) - GetDiscussion(context.Context, *connect.Request[v1beta1.GetDiscussionRequest]) (*connect.Response[v1beta1.GetDiscussionResponse], error) - PatchDiscussion(context.Context, *connect.Request[v1beta1.PatchDiscussionRequest]) (*connect.Response[v1beta1.PatchDiscussionResponse], error) - CreateComment(context.Context, *connect.Request[v1beta1.CreateCommentRequest]) (*connect.Response[v1beta1.CreateCommentResponse], error) - GetAllComments(context.Context, *connect.Request[v1beta1.GetAllCommentsRequest]) (*connect.Response[v1beta1.GetAllCommentsResponse], error) - GetComment(context.Context, *connect.Request[v1beta1.GetCommentRequest]) (*connect.Response[v1beta1.GetCommentResponse], error) - UpdateComment(context.Context, *connect.Request[v1beta1.UpdateCommentRequest]) (*connect.Response[v1beta1.UpdateCommentResponse], error) - DeleteComment(context.Context, *connect.Request[v1beta1.DeleteCommentRequest]) (*connect.Response[v1beta1.DeleteCommentResponse], error) - // Domain: Asset - SearchAssets(context.Context, *connect.Request[v1beta1.SearchAssetsRequest]) (*connect.Response[v1beta1.SearchAssetsResponse], error) - SuggestAssets(context.Context, *connect.Request[v1beta1.SuggestAssetsRequest]) (*connect.Response[v1beta1.SuggestAssetsResponse], error) - GroupAssets(context.Context, *connect.Request[v1beta1.GroupAssetsRequest]) (*connect.Response[v1beta1.GroupAssetsResponse], error) - GetGraph(context.Context, *connect.Request[v1beta1.GetGraphRequest]) (*connect.Response[v1beta1.GetGraphResponse], error) - GetAllTypes(context.Context, *connect.Request[v1beta1.GetAllTypesRequest]) (*connect.Response[v1beta1.GetAllTypesResponse], error) - GetAllAssets(context.Context, *connect.Request[v1beta1.GetAllAssetsRequest]) (*connect.Response[v1beta1.GetAllAssetsResponse], error) - GetAssetByID(context.Context, *connect.Request[v1beta1.GetAssetByIDRequest]) (*connect.Response[v1beta1.GetAssetByIDResponse], error) - UpsertAsset(context.Context, *connect.Request[v1beta1.UpsertAssetRequest]) (*connect.Response[v1beta1.UpsertAssetResponse], error) - UpsertPatchAsset(context.Context, *connect.Request[v1beta1.UpsertPatchAssetRequest]) (*connect.Response[v1beta1.UpsertPatchAssetResponse], error) - DeleteAsset(context.Context, *connect.Request[v1beta1.DeleteAssetRequest]) (*connect.Response[v1beta1.DeleteAssetResponse], error) - GetAssetStargazers(context.Context, *connect.Request[v1beta1.GetAssetStargazersRequest]) (*connect.Response[v1beta1.GetAssetStargazersResponse], error) - GetAssetVersionHistory(context.Context, *connect.Request[v1beta1.GetAssetVersionHistoryRequest]) (*connect.Response[v1beta1.GetAssetVersionHistoryResponse], error) - GetAssetByVersion(context.Context, *connect.Request[v1beta1.GetAssetByVersionRequest]) (*connect.Response[v1beta1.GetAssetByVersionResponse], error) - CreateAssetProbe(context.Context, *connect.Request[v1beta1.CreateAssetProbeRequest]) (*connect.Response[v1beta1.CreateAssetProbeResponse], error) - // Domain: User * Star - GetUserStarredAssets(context.Context, *connect.Request[v1beta1.GetUserStarredAssetsRequest]) (*connect.Response[v1beta1.GetUserStarredAssetsResponse], error) - GetMyStarredAssets(context.Context, *connect.Request[v1beta1.GetMyStarredAssetsRequest]) (*connect.Response[v1beta1.GetMyStarredAssetsResponse], error) - GetMyStarredAsset(context.Context, *connect.Request[v1beta1.GetMyStarredAssetRequest]) (*connect.Response[v1beta1.GetMyStarredAssetResponse], error) - StarAsset(context.Context, *connect.Request[v1beta1.StarAssetRequest]) (*connect.Response[v1beta1.StarAssetResponse], error) - UnstarAsset(context.Context, *connect.Request[v1beta1.UnstarAssetRequest]) (*connect.Response[v1beta1.UnstarAssetResponse], error) - GetMyDiscussions(context.Context, *connect.Request[v1beta1.GetMyDiscussionsRequest]) (*connect.Response[v1beta1.GetMyDiscussionsResponse], error) - // Domain: Tag Templates - CreateTagAsset(context.Context, *connect.Request[v1beta1.CreateTagAssetRequest]) (*connect.Response[v1beta1.CreateTagAssetResponse], error) - GetTagByAssetAndTemplate(context.Context, *connect.Request[v1beta1.GetTagByAssetAndTemplateRequest]) (*connect.Response[v1beta1.GetTagByAssetAndTemplateResponse], error) - UpdateTagAsset(context.Context, *connect.Request[v1beta1.UpdateTagAssetRequest]) (*connect.Response[v1beta1.UpdateTagAssetResponse], error) - DeleteTagAsset(context.Context, *connect.Request[v1beta1.DeleteTagAssetRequest]) (*connect.Response[v1beta1.DeleteTagAssetResponse], error) - GetAllTagsByAsset(context.Context, *connect.Request[v1beta1.GetAllTagsByAssetRequest]) (*connect.Response[v1beta1.GetAllTagsByAssetResponse], error) - GetAllTagTemplates(context.Context, *connect.Request[v1beta1.GetAllTagTemplatesRequest]) (*connect.Response[v1beta1.GetAllTagTemplatesResponse], error) - CreateTagTemplate(context.Context, *connect.Request[v1beta1.CreateTagTemplateRequest]) (*connect.Response[v1beta1.CreateTagTemplateResponse], error) - GetTagTemplate(context.Context, *connect.Request[v1beta1.GetTagTemplateRequest]) (*connect.Response[v1beta1.GetTagTemplateResponse], error) - UpdateTagTemplate(context.Context, *connect.Request[v1beta1.UpdateTagTemplateRequest]) (*connect.Response[v1beta1.UpdateTagTemplateResponse], error) - DeleteTagTemplate(context.Context, *connect.Request[v1beta1.DeleteTagTemplateRequest]) (*connect.Response[v1beta1.DeleteTagTemplateResponse], error) - // Domain: Namespace - CreateNamespace(context.Context, *connect.Request[v1beta1.CreateNamespaceRequest]) (*connect.Response[v1beta1.CreateNamespaceResponse], error) - GetNamespace(context.Context, *connect.Request[v1beta1.GetNamespaceRequest]) (*connect.Response[v1beta1.GetNamespaceResponse], error) - UpdateNamespace(context.Context, *connect.Request[v1beta1.UpdateNamespaceRequest]) (*connect.Response[v1beta1.UpdateNamespaceResponse], error) - ListNamespaces(context.Context, *connect.Request[v1beta1.ListNamespacesRequest]) (*connect.Response[v1beta1.ListNamespacesResponse], error) - // Domain: Entity (v2) + // Domain: Entity GetAllEntities(context.Context, *connect.Request[v1beta1.GetAllEntitiesRequest]) (*connect.Response[v1beta1.GetAllEntitiesResponse], error) GetEntityByID(context.Context, *connect.Request[v1beta1.GetEntityByIDRequest]) (*connect.Response[v1beta1.GetEntityByIDResponse], error) UpsertEntity(context.Context, *connect.Request[v1beta1.UpsertEntityRequest]) (*connect.Response[v1beta1.UpsertEntityResponse], error) @@ -1002,13 +424,25 @@ type CompassServiceHandler interface { SearchEntities(context.Context, *connect.Request[v1beta1.SearchEntitiesRequest]) (*connect.Response[v1beta1.SearchEntitiesResponse], error) SuggestEntities(context.Context, *connect.Request[v1beta1.SuggestEntitiesRequest]) (*connect.Response[v1beta1.SuggestEntitiesResponse], error) GetEntityTypes(context.Context, *connect.Request[v1beta1.GetEntityTypesRequest]) (*connect.Response[v1beta1.GetEntityTypesResponse], error) - // Domain: Entity Context & Impact (v2) + // Domain: Entity Context & Impact GetEntityContext(context.Context, *connect.Request[v1beta1.GetEntityContextRequest]) (*connect.Response[v1beta1.GetEntityContextResponse], error) GetEntityImpact(context.Context, *connect.Request[v1beta1.GetEntityImpactRequest]) (*connect.Response[v1beta1.GetEntityImpactResponse], error) - // Domain: Edges (v2) + // Domain: Edge UpsertEdge(context.Context, *connect.Request[v1beta1.UpsertEdgeRequest]) (*connect.Response[v1beta1.UpsertEdgeResponse], error) GetEdges(context.Context, *connect.Request[v1beta1.GetEdgesRequest]) (*connect.Response[v1beta1.GetEdgesResponse], error) DeleteEdge(context.Context, *connect.Request[v1beta1.DeleteEdgeRequest]) (*connect.Response[v1beta1.DeleteEdgeResponse], error) + // Domain: Star + StarEntity(context.Context, *connect.Request[v1beta1.StarEntityRequest]) (*connect.Response[v1beta1.StarEntityResponse], error) + UnstarEntity(context.Context, *connect.Request[v1beta1.UnstarEntityRequest]) (*connect.Response[v1beta1.UnstarEntityResponse], error) + GetUserStarredEntities(context.Context, *connect.Request[v1beta1.GetUserStarredEntitiesRequest]) (*connect.Response[v1beta1.GetUserStarredEntitiesResponse], error) + GetMyStarredEntities(context.Context, *connect.Request[v1beta1.GetMyStarredEntitiesRequest]) (*connect.Response[v1beta1.GetMyStarredEntitiesResponse], error) + GetMyStarredEntity(context.Context, *connect.Request[v1beta1.GetMyStarredEntityRequest]) (*connect.Response[v1beta1.GetMyStarredEntityResponse], error) + GetEntityStargazers(context.Context, *connect.Request[v1beta1.GetEntityStargazersRequest]) (*connect.Response[v1beta1.GetEntityStargazersResponse], error) + // Domain: Namespace + CreateNamespace(context.Context, *connect.Request[v1beta1.CreateNamespaceRequest]) (*connect.Response[v1beta1.CreateNamespaceResponse], error) + GetNamespace(context.Context, *connect.Request[v1beta1.GetNamespaceRequest]) (*connect.Response[v1beta1.GetNamespaceResponse], error) + UpdateNamespace(context.Context, *connect.Request[v1beta1.UpdateNamespaceRequest]) (*connect.Response[v1beta1.UpdateNamespaceResponse], error) + ListNamespaces(context.Context, *connect.Request[v1beta1.ListNamespacesRequest]) (*connect.Response[v1beta1.ListNamespacesResponse], error) } // NewCompassServiceHandler builds an HTTP handler from the service implementation. It returns the @@ -1018,264 +452,6 @@ type CompassServiceHandler interface { // and JSON codecs. They also support gzip compression. func NewCompassServiceHandler(svc CompassServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { compassServiceMethods := v1beta1.File_raystack_compass_v1beta1_service_proto.Services().ByName("CompassService").Methods() - compassServiceGetAllDiscussionsHandler := connect.NewUnaryHandler( - CompassServiceGetAllDiscussionsProcedure, - svc.GetAllDiscussions, - connect.WithSchema(compassServiceMethods.ByName("GetAllDiscussions")), - connect.WithHandlerOptions(opts...), - ) - compassServiceCreateDiscussionHandler := connect.NewUnaryHandler( - CompassServiceCreateDiscussionProcedure, - svc.CreateDiscussion, - connect.WithSchema(compassServiceMethods.ByName("CreateDiscussion")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetDiscussionHandler := connect.NewUnaryHandler( - CompassServiceGetDiscussionProcedure, - svc.GetDiscussion, - connect.WithSchema(compassServiceMethods.ByName("GetDiscussion")), - connect.WithHandlerOptions(opts...), - ) - compassServicePatchDiscussionHandler := connect.NewUnaryHandler( - CompassServicePatchDiscussionProcedure, - svc.PatchDiscussion, - connect.WithSchema(compassServiceMethods.ByName("PatchDiscussion")), - connect.WithHandlerOptions(opts...), - ) - compassServiceCreateCommentHandler := connect.NewUnaryHandler( - CompassServiceCreateCommentProcedure, - svc.CreateComment, - connect.WithSchema(compassServiceMethods.ByName("CreateComment")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetAllCommentsHandler := connect.NewUnaryHandler( - CompassServiceGetAllCommentsProcedure, - svc.GetAllComments, - connect.WithSchema(compassServiceMethods.ByName("GetAllComments")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetCommentHandler := connect.NewUnaryHandler( - CompassServiceGetCommentProcedure, - svc.GetComment, - connect.WithSchema(compassServiceMethods.ByName("GetComment")), - connect.WithHandlerOptions(opts...), - ) - compassServiceUpdateCommentHandler := connect.NewUnaryHandler( - CompassServiceUpdateCommentProcedure, - svc.UpdateComment, - connect.WithSchema(compassServiceMethods.ByName("UpdateComment")), - connect.WithHandlerOptions(opts...), - ) - compassServiceDeleteCommentHandler := connect.NewUnaryHandler( - CompassServiceDeleteCommentProcedure, - svc.DeleteComment, - connect.WithSchema(compassServiceMethods.ByName("DeleteComment")), - connect.WithHandlerOptions(opts...), - ) - compassServiceSearchAssetsHandler := connect.NewUnaryHandler( - CompassServiceSearchAssetsProcedure, - svc.SearchAssets, - connect.WithSchema(compassServiceMethods.ByName("SearchAssets")), - connect.WithHandlerOptions(opts...), - ) - compassServiceSuggestAssetsHandler := connect.NewUnaryHandler( - CompassServiceSuggestAssetsProcedure, - svc.SuggestAssets, - connect.WithSchema(compassServiceMethods.ByName("SuggestAssets")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGroupAssetsHandler := connect.NewUnaryHandler( - CompassServiceGroupAssetsProcedure, - svc.GroupAssets, - connect.WithSchema(compassServiceMethods.ByName("GroupAssets")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetGraphHandler := connect.NewUnaryHandler( - CompassServiceGetGraphProcedure, - svc.GetGraph, - connect.WithSchema(compassServiceMethods.ByName("GetGraph")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetAllTypesHandler := connect.NewUnaryHandler( - CompassServiceGetAllTypesProcedure, - svc.GetAllTypes, - connect.WithSchema(compassServiceMethods.ByName("GetAllTypes")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetAllAssetsHandler := connect.NewUnaryHandler( - CompassServiceGetAllAssetsProcedure, - svc.GetAllAssets, - connect.WithSchema(compassServiceMethods.ByName("GetAllAssets")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetAssetByIDHandler := connect.NewUnaryHandler( - CompassServiceGetAssetByIDProcedure, - svc.GetAssetByID, - connect.WithSchema(compassServiceMethods.ByName("GetAssetByID")), - connect.WithHandlerOptions(opts...), - ) - compassServiceUpsertAssetHandler := connect.NewUnaryHandler( - CompassServiceUpsertAssetProcedure, - svc.UpsertAsset, - connect.WithSchema(compassServiceMethods.ByName("UpsertAsset")), - connect.WithHandlerOptions(opts...), - ) - compassServiceUpsertPatchAssetHandler := connect.NewUnaryHandler( - CompassServiceUpsertPatchAssetProcedure, - svc.UpsertPatchAsset, - connect.WithSchema(compassServiceMethods.ByName("UpsertPatchAsset")), - connect.WithHandlerOptions(opts...), - ) - compassServiceDeleteAssetHandler := connect.NewUnaryHandler( - CompassServiceDeleteAssetProcedure, - svc.DeleteAsset, - connect.WithSchema(compassServiceMethods.ByName("DeleteAsset")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetAssetStargazersHandler := connect.NewUnaryHandler( - CompassServiceGetAssetStargazersProcedure, - svc.GetAssetStargazers, - connect.WithSchema(compassServiceMethods.ByName("GetAssetStargazers")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetAssetVersionHistoryHandler := connect.NewUnaryHandler( - CompassServiceGetAssetVersionHistoryProcedure, - svc.GetAssetVersionHistory, - connect.WithSchema(compassServiceMethods.ByName("GetAssetVersionHistory")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetAssetByVersionHandler := connect.NewUnaryHandler( - CompassServiceGetAssetByVersionProcedure, - svc.GetAssetByVersion, - connect.WithSchema(compassServiceMethods.ByName("GetAssetByVersion")), - connect.WithHandlerOptions(opts...), - ) - compassServiceCreateAssetProbeHandler := connect.NewUnaryHandler( - CompassServiceCreateAssetProbeProcedure, - svc.CreateAssetProbe, - connect.WithSchema(compassServiceMethods.ByName("CreateAssetProbe")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetUserStarredAssetsHandler := connect.NewUnaryHandler( - CompassServiceGetUserStarredAssetsProcedure, - svc.GetUserStarredAssets, - connect.WithSchema(compassServiceMethods.ByName("GetUserStarredAssets")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetMyStarredAssetsHandler := connect.NewUnaryHandler( - CompassServiceGetMyStarredAssetsProcedure, - svc.GetMyStarredAssets, - connect.WithSchema(compassServiceMethods.ByName("GetMyStarredAssets")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetMyStarredAssetHandler := connect.NewUnaryHandler( - CompassServiceGetMyStarredAssetProcedure, - svc.GetMyStarredAsset, - connect.WithSchema(compassServiceMethods.ByName("GetMyStarredAsset")), - connect.WithHandlerOptions(opts...), - ) - compassServiceStarAssetHandler := connect.NewUnaryHandler( - CompassServiceStarAssetProcedure, - svc.StarAsset, - connect.WithSchema(compassServiceMethods.ByName("StarAsset")), - connect.WithHandlerOptions(opts...), - ) - compassServiceUnstarAssetHandler := connect.NewUnaryHandler( - CompassServiceUnstarAssetProcedure, - svc.UnstarAsset, - connect.WithSchema(compassServiceMethods.ByName("UnstarAsset")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetMyDiscussionsHandler := connect.NewUnaryHandler( - CompassServiceGetMyDiscussionsProcedure, - svc.GetMyDiscussions, - connect.WithSchema(compassServiceMethods.ByName("GetMyDiscussions")), - connect.WithHandlerOptions(opts...), - ) - compassServiceCreateTagAssetHandler := connect.NewUnaryHandler( - CompassServiceCreateTagAssetProcedure, - svc.CreateTagAsset, - connect.WithSchema(compassServiceMethods.ByName("CreateTagAsset")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetTagByAssetAndTemplateHandler := connect.NewUnaryHandler( - CompassServiceGetTagByAssetAndTemplateProcedure, - svc.GetTagByAssetAndTemplate, - connect.WithSchema(compassServiceMethods.ByName("GetTagByAssetAndTemplate")), - connect.WithHandlerOptions(opts...), - ) - compassServiceUpdateTagAssetHandler := connect.NewUnaryHandler( - CompassServiceUpdateTagAssetProcedure, - svc.UpdateTagAsset, - connect.WithSchema(compassServiceMethods.ByName("UpdateTagAsset")), - connect.WithHandlerOptions(opts...), - ) - compassServiceDeleteTagAssetHandler := connect.NewUnaryHandler( - CompassServiceDeleteTagAssetProcedure, - svc.DeleteTagAsset, - connect.WithSchema(compassServiceMethods.ByName("DeleteTagAsset")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetAllTagsByAssetHandler := connect.NewUnaryHandler( - CompassServiceGetAllTagsByAssetProcedure, - svc.GetAllTagsByAsset, - connect.WithSchema(compassServiceMethods.ByName("GetAllTagsByAsset")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetAllTagTemplatesHandler := connect.NewUnaryHandler( - CompassServiceGetAllTagTemplatesProcedure, - svc.GetAllTagTemplates, - connect.WithSchema(compassServiceMethods.ByName("GetAllTagTemplates")), - connect.WithHandlerOptions(opts...), - ) - compassServiceCreateTagTemplateHandler := connect.NewUnaryHandler( - CompassServiceCreateTagTemplateProcedure, - svc.CreateTagTemplate, - connect.WithSchema(compassServiceMethods.ByName("CreateTagTemplate")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetTagTemplateHandler := connect.NewUnaryHandler( - CompassServiceGetTagTemplateProcedure, - svc.GetTagTemplate, - connect.WithSchema(compassServiceMethods.ByName("GetTagTemplate")), - connect.WithHandlerOptions(opts...), - ) - compassServiceUpdateTagTemplateHandler := connect.NewUnaryHandler( - CompassServiceUpdateTagTemplateProcedure, - svc.UpdateTagTemplate, - connect.WithSchema(compassServiceMethods.ByName("UpdateTagTemplate")), - connect.WithHandlerOptions(opts...), - ) - compassServiceDeleteTagTemplateHandler := connect.NewUnaryHandler( - CompassServiceDeleteTagTemplateProcedure, - svc.DeleteTagTemplate, - connect.WithSchema(compassServiceMethods.ByName("DeleteTagTemplate")), - connect.WithHandlerOptions(opts...), - ) - compassServiceCreateNamespaceHandler := connect.NewUnaryHandler( - CompassServiceCreateNamespaceProcedure, - svc.CreateNamespace, - connect.WithSchema(compassServiceMethods.ByName("CreateNamespace")), - connect.WithHandlerOptions(opts...), - ) - compassServiceGetNamespaceHandler := connect.NewUnaryHandler( - CompassServiceGetNamespaceProcedure, - svc.GetNamespace, - connect.WithSchema(compassServiceMethods.ByName("GetNamespace")), - connect.WithHandlerOptions(opts...), - ) - compassServiceUpdateNamespaceHandler := connect.NewUnaryHandler( - CompassServiceUpdateNamespaceProcedure, - svc.UpdateNamespace, - connect.WithSchema(compassServiceMethods.ByName("UpdateNamespace")), - connect.WithHandlerOptions(opts...), - ) - compassServiceListNamespacesHandler := connect.NewUnaryHandler( - CompassServiceListNamespacesProcedure, - svc.ListNamespaces, - connect.WithSchema(compassServiceMethods.ByName("ListNamespaces")), - connect.WithHandlerOptions(opts...), - ) compassServiceGetAllEntitiesHandler := connect.NewUnaryHandler( CompassServiceGetAllEntitiesProcedure, svc.GetAllEntities, @@ -1348,94 +524,68 @@ func NewCompassServiceHandler(svc CompassServiceHandler, opts ...connect.Handler connect.WithSchema(compassServiceMethods.ByName("DeleteEdge")), connect.WithHandlerOptions(opts...), ) + compassServiceStarEntityHandler := connect.NewUnaryHandler( + CompassServiceStarEntityProcedure, + svc.StarEntity, + connect.WithSchema(compassServiceMethods.ByName("StarEntity")), + connect.WithHandlerOptions(opts...), + ) + compassServiceUnstarEntityHandler := connect.NewUnaryHandler( + CompassServiceUnstarEntityProcedure, + svc.UnstarEntity, + connect.WithSchema(compassServiceMethods.ByName("UnstarEntity")), + connect.WithHandlerOptions(opts...), + ) + compassServiceGetUserStarredEntitiesHandler := connect.NewUnaryHandler( + CompassServiceGetUserStarredEntitiesProcedure, + svc.GetUserStarredEntities, + connect.WithSchema(compassServiceMethods.ByName("GetUserStarredEntities")), + connect.WithHandlerOptions(opts...), + ) + compassServiceGetMyStarredEntitiesHandler := connect.NewUnaryHandler( + CompassServiceGetMyStarredEntitiesProcedure, + svc.GetMyStarredEntities, + connect.WithSchema(compassServiceMethods.ByName("GetMyStarredEntities")), + connect.WithHandlerOptions(opts...), + ) + compassServiceGetMyStarredEntityHandler := connect.NewUnaryHandler( + CompassServiceGetMyStarredEntityProcedure, + svc.GetMyStarredEntity, + connect.WithSchema(compassServiceMethods.ByName("GetMyStarredEntity")), + connect.WithHandlerOptions(opts...), + ) + compassServiceGetEntityStargazersHandler := connect.NewUnaryHandler( + CompassServiceGetEntityStargazersProcedure, + svc.GetEntityStargazers, + connect.WithSchema(compassServiceMethods.ByName("GetEntityStargazers")), + connect.WithHandlerOptions(opts...), + ) + compassServiceCreateNamespaceHandler := connect.NewUnaryHandler( + CompassServiceCreateNamespaceProcedure, + svc.CreateNamespace, + connect.WithSchema(compassServiceMethods.ByName("CreateNamespace")), + connect.WithHandlerOptions(opts...), + ) + compassServiceGetNamespaceHandler := connect.NewUnaryHandler( + CompassServiceGetNamespaceProcedure, + svc.GetNamespace, + connect.WithSchema(compassServiceMethods.ByName("GetNamespace")), + connect.WithHandlerOptions(opts...), + ) + compassServiceUpdateNamespaceHandler := connect.NewUnaryHandler( + CompassServiceUpdateNamespaceProcedure, + svc.UpdateNamespace, + connect.WithSchema(compassServiceMethods.ByName("UpdateNamespace")), + connect.WithHandlerOptions(opts...), + ) + compassServiceListNamespacesHandler := connect.NewUnaryHandler( + CompassServiceListNamespacesProcedure, + svc.ListNamespaces, + connect.WithSchema(compassServiceMethods.ByName("ListNamespaces")), + connect.WithHandlerOptions(opts...), + ) return "/raystack.compass.v1beta1.CompassService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { - case CompassServiceGetAllDiscussionsProcedure: - compassServiceGetAllDiscussionsHandler.ServeHTTP(w, r) - case CompassServiceCreateDiscussionProcedure: - compassServiceCreateDiscussionHandler.ServeHTTP(w, r) - case CompassServiceGetDiscussionProcedure: - compassServiceGetDiscussionHandler.ServeHTTP(w, r) - case CompassServicePatchDiscussionProcedure: - compassServicePatchDiscussionHandler.ServeHTTP(w, r) - case CompassServiceCreateCommentProcedure: - compassServiceCreateCommentHandler.ServeHTTP(w, r) - case CompassServiceGetAllCommentsProcedure: - compassServiceGetAllCommentsHandler.ServeHTTP(w, r) - case CompassServiceGetCommentProcedure: - compassServiceGetCommentHandler.ServeHTTP(w, r) - case CompassServiceUpdateCommentProcedure: - compassServiceUpdateCommentHandler.ServeHTTP(w, r) - case CompassServiceDeleteCommentProcedure: - compassServiceDeleteCommentHandler.ServeHTTP(w, r) - case CompassServiceSearchAssetsProcedure: - compassServiceSearchAssetsHandler.ServeHTTP(w, r) - case CompassServiceSuggestAssetsProcedure: - compassServiceSuggestAssetsHandler.ServeHTTP(w, r) - case CompassServiceGroupAssetsProcedure: - compassServiceGroupAssetsHandler.ServeHTTP(w, r) - case CompassServiceGetGraphProcedure: - compassServiceGetGraphHandler.ServeHTTP(w, r) - case CompassServiceGetAllTypesProcedure: - compassServiceGetAllTypesHandler.ServeHTTP(w, r) - case CompassServiceGetAllAssetsProcedure: - compassServiceGetAllAssetsHandler.ServeHTTP(w, r) - case CompassServiceGetAssetByIDProcedure: - compassServiceGetAssetByIDHandler.ServeHTTP(w, r) - case CompassServiceUpsertAssetProcedure: - compassServiceUpsertAssetHandler.ServeHTTP(w, r) - case CompassServiceUpsertPatchAssetProcedure: - compassServiceUpsertPatchAssetHandler.ServeHTTP(w, r) - case CompassServiceDeleteAssetProcedure: - compassServiceDeleteAssetHandler.ServeHTTP(w, r) - case CompassServiceGetAssetStargazersProcedure: - compassServiceGetAssetStargazersHandler.ServeHTTP(w, r) - case CompassServiceGetAssetVersionHistoryProcedure: - compassServiceGetAssetVersionHistoryHandler.ServeHTTP(w, r) - case CompassServiceGetAssetByVersionProcedure: - compassServiceGetAssetByVersionHandler.ServeHTTP(w, r) - case CompassServiceCreateAssetProbeProcedure: - compassServiceCreateAssetProbeHandler.ServeHTTP(w, r) - case CompassServiceGetUserStarredAssetsProcedure: - compassServiceGetUserStarredAssetsHandler.ServeHTTP(w, r) - case CompassServiceGetMyStarredAssetsProcedure: - compassServiceGetMyStarredAssetsHandler.ServeHTTP(w, r) - case CompassServiceGetMyStarredAssetProcedure: - compassServiceGetMyStarredAssetHandler.ServeHTTP(w, r) - case CompassServiceStarAssetProcedure: - compassServiceStarAssetHandler.ServeHTTP(w, r) - case CompassServiceUnstarAssetProcedure: - compassServiceUnstarAssetHandler.ServeHTTP(w, r) - case CompassServiceGetMyDiscussionsProcedure: - compassServiceGetMyDiscussionsHandler.ServeHTTP(w, r) - case CompassServiceCreateTagAssetProcedure: - compassServiceCreateTagAssetHandler.ServeHTTP(w, r) - case CompassServiceGetTagByAssetAndTemplateProcedure: - compassServiceGetTagByAssetAndTemplateHandler.ServeHTTP(w, r) - case CompassServiceUpdateTagAssetProcedure: - compassServiceUpdateTagAssetHandler.ServeHTTP(w, r) - case CompassServiceDeleteTagAssetProcedure: - compassServiceDeleteTagAssetHandler.ServeHTTP(w, r) - case CompassServiceGetAllTagsByAssetProcedure: - compassServiceGetAllTagsByAssetHandler.ServeHTTP(w, r) - case CompassServiceGetAllTagTemplatesProcedure: - compassServiceGetAllTagTemplatesHandler.ServeHTTP(w, r) - case CompassServiceCreateTagTemplateProcedure: - compassServiceCreateTagTemplateHandler.ServeHTTP(w, r) - case CompassServiceGetTagTemplateProcedure: - compassServiceGetTagTemplateHandler.ServeHTTP(w, r) - case CompassServiceUpdateTagTemplateProcedure: - compassServiceUpdateTagTemplateHandler.ServeHTTP(w, r) - case CompassServiceDeleteTagTemplateProcedure: - compassServiceDeleteTagTemplateHandler.ServeHTTP(w, r) - case CompassServiceCreateNamespaceProcedure: - compassServiceCreateNamespaceHandler.ServeHTTP(w, r) - case CompassServiceGetNamespaceProcedure: - compassServiceGetNamespaceHandler.ServeHTTP(w, r) - case CompassServiceUpdateNamespaceProcedure: - compassServiceUpdateNamespaceHandler.ServeHTTP(w, r) - case CompassServiceListNamespacesProcedure: - compassServiceListNamespacesHandler.ServeHTTP(w, r) case CompassServiceGetAllEntitiesProcedure: compassServiceGetAllEntitiesHandler.ServeHTTP(w, r) case CompassServiceGetEntityByIDProcedure: @@ -1460,6 +610,26 @@ func NewCompassServiceHandler(svc CompassServiceHandler, opts ...connect.Handler compassServiceGetEdgesHandler.ServeHTTP(w, r) case CompassServiceDeleteEdgeProcedure: compassServiceDeleteEdgeHandler.ServeHTTP(w, r) + case CompassServiceStarEntityProcedure: + compassServiceStarEntityHandler.ServeHTTP(w, r) + case CompassServiceUnstarEntityProcedure: + compassServiceUnstarEntityHandler.ServeHTTP(w, r) + case CompassServiceGetUserStarredEntitiesProcedure: + compassServiceGetUserStarredEntitiesHandler.ServeHTTP(w, r) + case CompassServiceGetMyStarredEntitiesProcedure: + compassServiceGetMyStarredEntitiesHandler.ServeHTTP(w, r) + case CompassServiceGetMyStarredEntityProcedure: + compassServiceGetMyStarredEntityHandler.ServeHTTP(w, r) + case CompassServiceGetEntityStargazersProcedure: + compassServiceGetEntityStargazersHandler.ServeHTTP(w, r) + case CompassServiceCreateNamespaceProcedure: + compassServiceCreateNamespaceHandler.ServeHTTP(w, r) + case CompassServiceGetNamespaceProcedure: + compassServiceGetNamespaceHandler.ServeHTTP(w, r) + case CompassServiceUpdateNamespaceProcedure: + compassServiceUpdateNamespaceHandler.ServeHTTP(w, r) + case CompassServiceListNamespacesProcedure: + compassServiceListNamespacesHandler.ServeHTTP(w, r) default: http.NotFound(w, r) } @@ -1469,160 +639,76 @@ func NewCompassServiceHandler(svc CompassServiceHandler, opts ...connect.Handler // UnimplementedCompassServiceHandler returns CodeUnimplemented from all methods. type UnimplementedCompassServiceHandler struct{} -func (UnimplementedCompassServiceHandler) GetAllDiscussions(context.Context, *connect.Request[v1beta1.GetAllDiscussionsRequest]) (*connect.Response[v1beta1.GetAllDiscussionsResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAllDiscussions is not implemented")) -} - -func (UnimplementedCompassServiceHandler) CreateDiscussion(context.Context, *connect.Request[v1beta1.CreateDiscussionRequest]) (*connect.Response[v1beta1.CreateDiscussionResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.CreateDiscussion is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetDiscussion(context.Context, *connect.Request[v1beta1.GetDiscussionRequest]) (*connect.Response[v1beta1.GetDiscussionResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetDiscussion is not implemented")) -} - -func (UnimplementedCompassServiceHandler) PatchDiscussion(context.Context, *connect.Request[v1beta1.PatchDiscussionRequest]) (*connect.Response[v1beta1.PatchDiscussionResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.PatchDiscussion is not implemented")) -} - -func (UnimplementedCompassServiceHandler) CreateComment(context.Context, *connect.Request[v1beta1.CreateCommentRequest]) (*connect.Response[v1beta1.CreateCommentResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.CreateComment is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetAllComments(context.Context, *connect.Request[v1beta1.GetAllCommentsRequest]) (*connect.Response[v1beta1.GetAllCommentsResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAllComments is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetComment(context.Context, *connect.Request[v1beta1.GetCommentRequest]) (*connect.Response[v1beta1.GetCommentResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetComment is not implemented")) -} - -func (UnimplementedCompassServiceHandler) UpdateComment(context.Context, *connect.Request[v1beta1.UpdateCommentRequest]) (*connect.Response[v1beta1.UpdateCommentResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UpdateComment is not implemented")) -} - -func (UnimplementedCompassServiceHandler) DeleteComment(context.Context, *connect.Request[v1beta1.DeleteCommentRequest]) (*connect.Response[v1beta1.DeleteCommentResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.DeleteComment is not implemented")) -} - -func (UnimplementedCompassServiceHandler) SearchAssets(context.Context, *connect.Request[v1beta1.SearchAssetsRequest]) (*connect.Response[v1beta1.SearchAssetsResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.SearchAssets is not implemented")) -} - -func (UnimplementedCompassServiceHandler) SuggestAssets(context.Context, *connect.Request[v1beta1.SuggestAssetsRequest]) (*connect.Response[v1beta1.SuggestAssetsResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.SuggestAssets is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GroupAssets(context.Context, *connect.Request[v1beta1.GroupAssetsRequest]) (*connect.Response[v1beta1.GroupAssetsResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GroupAssets is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetGraph(context.Context, *connect.Request[v1beta1.GetGraphRequest]) (*connect.Response[v1beta1.GetGraphResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetGraph is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetAllTypes(context.Context, *connect.Request[v1beta1.GetAllTypesRequest]) (*connect.Response[v1beta1.GetAllTypesResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAllTypes is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetAllAssets(context.Context, *connect.Request[v1beta1.GetAllAssetsRequest]) (*connect.Response[v1beta1.GetAllAssetsResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAllAssets is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetAssetByID(context.Context, *connect.Request[v1beta1.GetAssetByIDRequest]) (*connect.Response[v1beta1.GetAssetByIDResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAssetByID is not implemented")) -} - -func (UnimplementedCompassServiceHandler) UpsertAsset(context.Context, *connect.Request[v1beta1.UpsertAssetRequest]) (*connect.Response[v1beta1.UpsertAssetResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UpsertAsset is not implemented")) -} - -func (UnimplementedCompassServiceHandler) UpsertPatchAsset(context.Context, *connect.Request[v1beta1.UpsertPatchAssetRequest]) (*connect.Response[v1beta1.UpsertPatchAssetResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UpsertPatchAsset is not implemented")) -} - -func (UnimplementedCompassServiceHandler) DeleteAsset(context.Context, *connect.Request[v1beta1.DeleteAssetRequest]) (*connect.Response[v1beta1.DeleteAssetResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.DeleteAsset is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetAssetStargazers(context.Context, *connect.Request[v1beta1.GetAssetStargazersRequest]) (*connect.Response[v1beta1.GetAssetStargazersResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAssetStargazers is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetAssetVersionHistory(context.Context, *connect.Request[v1beta1.GetAssetVersionHistoryRequest]) (*connect.Response[v1beta1.GetAssetVersionHistoryResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAssetVersionHistory is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetAssetByVersion(context.Context, *connect.Request[v1beta1.GetAssetByVersionRequest]) (*connect.Response[v1beta1.GetAssetByVersionResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAssetByVersion is not implemented")) +func (UnimplementedCompassServiceHandler) GetAllEntities(context.Context, *connect.Request[v1beta1.GetAllEntitiesRequest]) (*connect.Response[v1beta1.GetAllEntitiesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAllEntities is not implemented")) } -func (UnimplementedCompassServiceHandler) CreateAssetProbe(context.Context, *connect.Request[v1beta1.CreateAssetProbeRequest]) (*connect.Response[v1beta1.CreateAssetProbeResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.CreateAssetProbe is not implemented")) +func (UnimplementedCompassServiceHandler) GetEntityByID(context.Context, *connect.Request[v1beta1.GetEntityByIDRequest]) (*connect.Response[v1beta1.GetEntityByIDResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityByID is not implemented")) } -func (UnimplementedCompassServiceHandler) GetUserStarredAssets(context.Context, *connect.Request[v1beta1.GetUserStarredAssetsRequest]) (*connect.Response[v1beta1.GetUserStarredAssetsResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetUserStarredAssets is not implemented")) +func (UnimplementedCompassServiceHandler) UpsertEntity(context.Context, *connect.Request[v1beta1.UpsertEntityRequest]) (*connect.Response[v1beta1.UpsertEntityResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UpsertEntity is not implemented")) } -func (UnimplementedCompassServiceHandler) GetMyStarredAssets(context.Context, *connect.Request[v1beta1.GetMyStarredAssetsRequest]) (*connect.Response[v1beta1.GetMyStarredAssetsResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetMyStarredAssets is not implemented")) +func (UnimplementedCompassServiceHandler) DeleteEntity(context.Context, *connect.Request[v1beta1.DeleteEntityRequest]) (*connect.Response[v1beta1.DeleteEntityResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.DeleteEntity is not implemented")) } -func (UnimplementedCompassServiceHandler) GetMyStarredAsset(context.Context, *connect.Request[v1beta1.GetMyStarredAssetRequest]) (*connect.Response[v1beta1.GetMyStarredAssetResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetMyStarredAsset is not implemented")) +func (UnimplementedCompassServiceHandler) SearchEntities(context.Context, *connect.Request[v1beta1.SearchEntitiesRequest]) (*connect.Response[v1beta1.SearchEntitiesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.SearchEntities is not implemented")) } -func (UnimplementedCompassServiceHandler) StarAsset(context.Context, *connect.Request[v1beta1.StarAssetRequest]) (*connect.Response[v1beta1.StarAssetResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.StarAsset is not implemented")) +func (UnimplementedCompassServiceHandler) SuggestEntities(context.Context, *connect.Request[v1beta1.SuggestEntitiesRequest]) (*connect.Response[v1beta1.SuggestEntitiesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.SuggestEntities is not implemented")) } -func (UnimplementedCompassServiceHandler) UnstarAsset(context.Context, *connect.Request[v1beta1.UnstarAssetRequest]) (*connect.Response[v1beta1.UnstarAssetResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UnstarAsset is not implemented")) +func (UnimplementedCompassServiceHandler) GetEntityTypes(context.Context, *connect.Request[v1beta1.GetEntityTypesRequest]) (*connect.Response[v1beta1.GetEntityTypesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityTypes is not implemented")) } -func (UnimplementedCompassServiceHandler) GetMyDiscussions(context.Context, *connect.Request[v1beta1.GetMyDiscussionsRequest]) (*connect.Response[v1beta1.GetMyDiscussionsResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetMyDiscussions is not implemented")) +func (UnimplementedCompassServiceHandler) GetEntityContext(context.Context, *connect.Request[v1beta1.GetEntityContextRequest]) (*connect.Response[v1beta1.GetEntityContextResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityContext is not implemented")) } -func (UnimplementedCompassServiceHandler) CreateTagAsset(context.Context, *connect.Request[v1beta1.CreateTagAssetRequest]) (*connect.Response[v1beta1.CreateTagAssetResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.CreateTagAsset is not implemented")) +func (UnimplementedCompassServiceHandler) GetEntityImpact(context.Context, *connect.Request[v1beta1.GetEntityImpactRequest]) (*connect.Response[v1beta1.GetEntityImpactResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityImpact is not implemented")) } -func (UnimplementedCompassServiceHandler) GetTagByAssetAndTemplate(context.Context, *connect.Request[v1beta1.GetTagByAssetAndTemplateRequest]) (*connect.Response[v1beta1.GetTagByAssetAndTemplateResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetTagByAssetAndTemplate is not implemented")) +func (UnimplementedCompassServiceHandler) UpsertEdge(context.Context, *connect.Request[v1beta1.UpsertEdgeRequest]) (*connect.Response[v1beta1.UpsertEdgeResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UpsertEdge is not implemented")) } -func (UnimplementedCompassServiceHandler) UpdateTagAsset(context.Context, *connect.Request[v1beta1.UpdateTagAssetRequest]) (*connect.Response[v1beta1.UpdateTagAssetResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UpdateTagAsset is not implemented")) +func (UnimplementedCompassServiceHandler) GetEdges(context.Context, *connect.Request[v1beta1.GetEdgesRequest]) (*connect.Response[v1beta1.GetEdgesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEdges is not implemented")) } -func (UnimplementedCompassServiceHandler) DeleteTagAsset(context.Context, *connect.Request[v1beta1.DeleteTagAssetRequest]) (*connect.Response[v1beta1.DeleteTagAssetResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.DeleteTagAsset is not implemented")) +func (UnimplementedCompassServiceHandler) DeleteEdge(context.Context, *connect.Request[v1beta1.DeleteEdgeRequest]) (*connect.Response[v1beta1.DeleteEdgeResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.DeleteEdge is not implemented")) } -func (UnimplementedCompassServiceHandler) GetAllTagsByAsset(context.Context, *connect.Request[v1beta1.GetAllTagsByAssetRequest]) (*connect.Response[v1beta1.GetAllTagsByAssetResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAllTagsByAsset is not implemented")) +func (UnimplementedCompassServiceHandler) StarEntity(context.Context, *connect.Request[v1beta1.StarEntityRequest]) (*connect.Response[v1beta1.StarEntityResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.StarEntity is not implemented")) } -func (UnimplementedCompassServiceHandler) GetAllTagTemplates(context.Context, *connect.Request[v1beta1.GetAllTagTemplatesRequest]) (*connect.Response[v1beta1.GetAllTagTemplatesResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAllTagTemplates is not implemented")) +func (UnimplementedCompassServiceHandler) UnstarEntity(context.Context, *connect.Request[v1beta1.UnstarEntityRequest]) (*connect.Response[v1beta1.UnstarEntityResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UnstarEntity is not implemented")) } -func (UnimplementedCompassServiceHandler) CreateTagTemplate(context.Context, *connect.Request[v1beta1.CreateTagTemplateRequest]) (*connect.Response[v1beta1.CreateTagTemplateResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.CreateTagTemplate is not implemented")) +func (UnimplementedCompassServiceHandler) GetUserStarredEntities(context.Context, *connect.Request[v1beta1.GetUserStarredEntitiesRequest]) (*connect.Response[v1beta1.GetUserStarredEntitiesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetUserStarredEntities is not implemented")) } -func (UnimplementedCompassServiceHandler) GetTagTemplate(context.Context, *connect.Request[v1beta1.GetTagTemplateRequest]) (*connect.Response[v1beta1.GetTagTemplateResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetTagTemplate is not implemented")) +func (UnimplementedCompassServiceHandler) GetMyStarredEntities(context.Context, *connect.Request[v1beta1.GetMyStarredEntitiesRequest]) (*connect.Response[v1beta1.GetMyStarredEntitiesResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetMyStarredEntities is not implemented")) } -func (UnimplementedCompassServiceHandler) UpdateTagTemplate(context.Context, *connect.Request[v1beta1.UpdateTagTemplateRequest]) (*connect.Response[v1beta1.UpdateTagTemplateResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UpdateTagTemplate is not implemented")) +func (UnimplementedCompassServiceHandler) GetMyStarredEntity(context.Context, *connect.Request[v1beta1.GetMyStarredEntityRequest]) (*connect.Response[v1beta1.GetMyStarredEntityResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetMyStarredEntity is not implemented")) } -func (UnimplementedCompassServiceHandler) DeleteTagTemplate(context.Context, *connect.Request[v1beta1.DeleteTagTemplateRequest]) (*connect.Response[v1beta1.DeleteTagTemplateResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.DeleteTagTemplate is not implemented")) +func (UnimplementedCompassServiceHandler) GetEntityStargazers(context.Context, *connect.Request[v1beta1.GetEntityStargazersRequest]) (*connect.Response[v1beta1.GetEntityStargazersResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityStargazers is not implemented")) } func (UnimplementedCompassServiceHandler) CreateNamespace(context.Context, *connect.Request[v1beta1.CreateNamespaceRequest]) (*connect.Response[v1beta1.CreateNamespaceResponse], error) { @@ -1640,51 +726,3 @@ func (UnimplementedCompassServiceHandler) UpdateNamespace(context.Context, *conn func (UnimplementedCompassServiceHandler) ListNamespaces(context.Context, *connect.Request[v1beta1.ListNamespacesRequest]) (*connect.Response[v1beta1.ListNamespacesResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.ListNamespaces is not implemented")) } - -func (UnimplementedCompassServiceHandler) GetAllEntities(context.Context, *connect.Request[v1beta1.GetAllEntitiesRequest]) (*connect.Response[v1beta1.GetAllEntitiesResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetAllEntities is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetEntityByID(context.Context, *connect.Request[v1beta1.GetEntityByIDRequest]) (*connect.Response[v1beta1.GetEntityByIDResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityByID is not implemented")) -} - -func (UnimplementedCompassServiceHandler) UpsertEntity(context.Context, *connect.Request[v1beta1.UpsertEntityRequest]) (*connect.Response[v1beta1.UpsertEntityResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UpsertEntity is not implemented")) -} - -func (UnimplementedCompassServiceHandler) DeleteEntity(context.Context, *connect.Request[v1beta1.DeleteEntityRequest]) (*connect.Response[v1beta1.DeleteEntityResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.DeleteEntity is not implemented")) -} - -func (UnimplementedCompassServiceHandler) SearchEntities(context.Context, *connect.Request[v1beta1.SearchEntitiesRequest]) (*connect.Response[v1beta1.SearchEntitiesResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.SearchEntities is not implemented")) -} - -func (UnimplementedCompassServiceHandler) SuggestEntities(context.Context, *connect.Request[v1beta1.SuggestEntitiesRequest]) (*connect.Response[v1beta1.SuggestEntitiesResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.SuggestEntities is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetEntityTypes(context.Context, *connect.Request[v1beta1.GetEntityTypesRequest]) (*connect.Response[v1beta1.GetEntityTypesResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityTypes is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetEntityContext(context.Context, *connect.Request[v1beta1.GetEntityContextRequest]) (*connect.Response[v1beta1.GetEntityContextResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityContext is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetEntityImpact(context.Context, *connect.Request[v1beta1.GetEntityImpactRequest]) (*connect.Response[v1beta1.GetEntityImpactResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEntityImpact is not implemented")) -} - -func (UnimplementedCompassServiceHandler) UpsertEdge(context.Context, *connect.Request[v1beta1.UpsertEdgeRequest]) (*connect.Response[v1beta1.UpsertEdgeResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.UpsertEdge is not implemented")) -} - -func (UnimplementedCompassServiceHandler) GetEdges(context.Context, *connect.Request[v1beta1.GetEdgesRequest]) (*connect.Response[v1beta1.GetEdgesResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.GetEdges is not implemented")) -} - -func (UnimplementedCompassServiceHandler) DeleteEdge(context.Context, *connect.Request[v1beta1.DeleteEdgeRequest]) (*connect.Response[v1beta1.DeleteEdgeResponse], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("raystack.compass.v1beta1.CompassService.DeleteEdge is not implemented")) -} diff --git a/gen/raystack/compass/v1beta1/service.pb.go b/gen/raystack/compass/v1beta1/service.pb.go index 9e8a757a..65128c7e 100644 --- a/gen/raystack/compass/v1beta1/service.pb.go +++ b/gen/raystack/compass/v1beta1/service.pb.go @@ -12,7 +12,6 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" structpb "google.golang.org/protobuf/types/known/structpb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" - wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" reflect "reflect" sync "sync" unsafe "unsafe" @@ -25,36 +24,32 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type GetAllDiscussionsRequest struct { +type User struct { state protoimpl.MessageState `protogen:"open.v1"` - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` - State string `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` - Owner string `protobuf:"bytes,3,opt,name=owner,proto3" json:"owner,omitempty"` - Assignee string `protobuf:"bytes,4,opt,name=assignee,proto3" json:"assignee,omitempty"` - Asset string `protobuf:"bytes,5,opt,name=asset,proto3" json:"asset,omitempty"` - Labels string `protobuf:"bytes,6,opt,name=labels,proto3" json:"labels,omitempty"` - Sort string `protobuf:"bytes,7,opt,name=sort,proto3" json:"sort,omitempty"` - Direction string `protobuf:"bytes,8,opt,name=direction,proto3" json:"direction,omitempty"` - Size uint32 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` - Offset uint32 `protobuf:"varint,10,opt,name=offset,proto3" json:"offset,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Uuid string `protobuf:"bytes,2,opt,name=uuid,proto3" json:"uuid,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + Provider string `protobuf:"bytes,4,opt,name=provider,proto3" json:"provider,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAllDiscussionsRequest) Reset() { - *x = GetAllDiscussionsRequest{} +func (x *User) Reset() { + *x = User{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAllDiscussionsRequest) String() string { +func (x *User) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAllDiscussionsRequest) ProtoMessage() {} +func (*User) ProtoMessage() {} -func (x *GetAllDiscussionsRequest) ProtoReflect() protoreflect.Message { +func (x *User) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -66,152 +61,206 @@ func (x *GetAllDiscussionsRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAllDiscussionsRequest.ProtoReflect.Descriptor instead. -func (*GetAllDiscussionsRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{0} } -func (x *GetAllDiscussionsRequest) GetType() string { +func (x *User) GetId() string { if x != nil { - return x.Type + return x.Id } return "" } -func (x *GetAllDiscussionsRequest) GetState() string { +func (x *User) GetUuid() string { if x != nil { - return x.State + return x.Uuid } return "" } -func (x *GetAllDiscussionsRequest) GetOwner() string { +func (x *User) GetEmail() string { if x != nil { - return x.Owner + return x.Email } return "" } -func (x *GetAllDiscussionsRequest) GetAssignee() string { +func (x *User) GetProvider() string { if x != nil { - return x.Assignee + return x.Provider } return "" } -func (x *GetAllDiscussionsRequest) GetAsset() string { +func (x *User) GetCreatedAt() *timestamppb.Timestamp { if x != nil { - return x.Asset + return x.CreatedAt } - return "" + return nil } -func (x *GetAllDiscussionsRequest) GetLabels() string { +func (x *User) GetUpdatedAt() *timestamppb.Timestamp { if x != nil { - return x.Labels + return x.UpdatedAt } - return "" + return nil +} + +type Entity struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Urn string `protobuf:"bytes,2,opt,name=urn,proto3" json:"urn,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` + Properties *structpb.Struct `protobuf:"bytes,6,opt,name=properties,proto3" json:"properties,omitempty"` + Source string `protobuf:"bytes,7,opt,name=source,proto3" json:"source,omitempty"` + ValidFrom *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=valid_from,json=validFrom,proto3" json:"valid_from,omitempty"` + ValidTo *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=valid_to,json=validTo,proto3" json:"valid_to,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Entity) Reset() { + *x = Entity{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Entity) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Entity) ProtoMessage() {} + +func (x *Entity) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Entity.ProtoReflect.Descriptor instead. +func (*Entity) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{1} } -func (x *GetAllDiscussionsRequest) GetSort() string { +func (x *Entity) GetId() string { if x != nil { - return x.Sort + return x.Id } return "" } -func (x *GetAllDiscussionsRequest) GetDirection() string { +func (x *Entity) GetUrn() string { if x != nil { - return x.Direction + return x.Urn } return "" } -func (x *GetAllDiscussionsRequest) GetSize() uint32 { +func (x *Entity) GetType() string { if x != nil { - return x.Size + return x.Type } - return 0 + return "" } -func (x *GetAllDiscussionsRequest) GetOffset() uint32 { +func (x *Entity) GetName() string { if x != nil { - return x.Offset + return x.Name } - return 0 + return "" } -type GetAllDiscussionsResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data []*Discussion `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +func (x *Entity) GetDescription() string { + if x != nil { + return x.Description + } + return "" } -func (x *GetAllDiscussionsResponse) Reset() { - *x = GetAllDiscussionsResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) +func (x *Entity) GetProperties() *structpb.Struct { + if x != nil { + return x.Properties + } + return nil } -func (x *GetAllDiscussionsResponse) String() string { - return protoimpl.X.MessageStringOf(x) +func (x *Entity) GetSource() string { + if x != nil { + return x.Source + } + return "" } -func (*GetAllDiscussionsResponse) ProtoMessage() {} +func (x *Entity) GetValidFrom() *timestamppb.Timestamp { + if x != nil { + return x.ValidFrom + } + return nil +} -func (x *GetAllDiscussionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[1] +func (x *Entity) GetValidTo() *timestamppb.Timestamp { if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms + return x.ValidTo } - return mi.MessageOf(x) + return nil } -// Deprecated: Use GetAllDiscussionsResponse.ProtoReflect.Descriptor instead. -func (*GetAllDiscussionsResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{1} +func (x *Entity) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil } -func (x *GetAllDiscussionsResponse) GetData() []*Discussion { +func (x *Entity) GetUpdatedAt() *timestamppb.Timestamp { if x != nil { - return x.Data + return x.UpdatedAt } return nil } -type CreateDiscussionRequest struct { +type Edge struct { state protoimpl.MessageState `protogen:"open.v1"` - Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` - Body string `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + SourceUrn string `protobuf:"bytes,2,opt,name=source_urn,json=sourceUrn,proto3" json:"source_urn,omitempty"` + TargetUrn string `protobuf:"bytes,3,opt,name=target_urn,json=targetUrn,proto3" json:"target_urn,omitempty"` Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` - State string `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"` - Labels []string `protobuf:"bytes,6,rep,name=labels,proto3" json:"labels,omitempty"` - Assets []string `protobuf:"bytes,7,rep,name=assets,proto3" json:"assets,omitempty"` - Assignees []string `protobuf:"bytes,8,rep,name=assignees,proto3" json:"assignees,omitempty"` + Properties *structpb.Struct `protobuf:"bytes,5,opt,name=properties,proto3" json:"properties,omitempty"` + Source string `protobuf:"bytes,6,opt,name=source,proto3" json:"source,omitempty"` + ValidFrom *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=valid_from,json=validFrom,proto3" json:"valid_from,omitempty"` + ValidTo *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=valid_to,json=validTo,proto3" json:"valid_to,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *CreateDiscussionRequest) Reset() { - *x = CreateDiscussionRequest{} +func (x *Edge) Reset() { + *x = Edge{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *CreateDiscussionRequest) String() string { +func (x *Edge) String() string { return protoimpl.X.MessageStringOf(x) } -func (*CreateDiscussionRequest) ProtoMessage() {} +func (*Edge) ProtoMessage() {} -func (x *CreateDiscussionRequest) ProtoReflect() protoreflect.Message { +func (x *Edge) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -223,81 +272,96 @@ func (x *CreateDiscussionRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CreateDiscussionRequest.ProtoReflect.Descriptor instead. -func (*CreateDiscussionRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use Edge.ProtoReflect.Descriptor instead. +func (*Edge) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{2} } -func (x *CreateDiscussionRequest) GetTitle() string { +func (x *Edge) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Edge) GetSourceUrn() string { if x != nil { - return x.Title + return x.SourceUrn } return "" } -func (x *CreateDiscussionRequest) GetBody() string { +func (x *Edge) GetTargetUrn() string { if x != nil { - return x.Body + return x.TargetUrn } return "" } -func (x *CreateDiscussionRequest) GetType() string { +func (x *Edge) GetType() string { if x != nil { return x.Type } return "" } -func (x *CreateDiscussionRequest) GetState() string { +func (x *Edge) GetProperties() *structpb.Struct { if x != nil { - return x.State + return x.Properties + } + return nil +} + +func (x *Edge) GetSource() string { + if x != nil { + return x.Source } return "" } -func (x *CreateDiscussionRequest) GetLabels() []string { +func (x *Edge) GetValidFrom() *timestamppb.Timestamp { if x != nil { - return x.Labels + return x.ValidFrom } return nil } -func (x *CreateDiscussionRequest) GetAssets() []string { +func (x *Edge) GetValidTo() *timestamppb.Timestamp { if x != nil { - return x.Assets + return x.ValidTo } return nil } -func (x *CreateDiscussionRequest) GetAssignees() []string { +func (x *Edge) GetCreatedAt() *timestamppb.Timestamp { if x != nil { - return x.Assignees + return x.CreatedAt } return nil } -type CreateDiscussionResponse struct { +type Type struct { state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Count uint32 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *CreateDiscussionResponse) Reset() { - *x = CreateDiscussionResponse{} +func (x *Type) Reset() { + *x = Type{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *CreateDiscussionResponse) String() string { +func (x *Type) String() string { return protoimpl.X.MessageStringOf(x) } -func (*CreateDiscussionResponse) ProtoMessage() {} +func (*Type) ProtoMessage() {} -func (x *CreateDiscussionResponse) ProtoReflect() protoreflect.Message { +func (x *Type) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -309,39 +373,49 @@ func (x *CreateDiscussionResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CreateDiscussionResponse.ProtoReflect.Descriptor instead. -func (*CreateDiscussionResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use Type.ProtoReflect.Descriptor instead. +func (*Type) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{3} } -func (x *CreateDiscussionResponse) GetId() string { +func (x *Type) GetName() string { if x != nil { - return x.Id + return x.Name } return "" } -type GetDiscussionRequest struct { +func (x *Type) GetCount() uint32 { + if x != nil { + return x.Count + } + return 0 +} + +type Namespace struct { state protoimpl.MessageState `protogen:"open.v1"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` + Metadata *structpb.Struct `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetDiscussionRequest) Reset() { - *x = GetDiscussionRequest{} +func (x *Namespace) Reset() { + *x = Namespace{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetDiscussionRequest) String() string { +func (x *Namespace) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetDiscussionRequest) ProtoMessage() {} +func (*Namespace) ProtoMessage() {} -func (x *GetDiscussionRequest) ProtoReflect() protoreflect.Message { +func (x *Namespace) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -353,39 +427,64 @@ func (x *GetDiscussionRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetDiscussionRequest.ProtoReflect.Descriptor instead. -func (*GetDiscussionRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use Namespace.ProtoReflect.Descriptor instead. +func (*Namespace) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{4} } -func (x *GetDiscussionRequest) GetId() string { +func (x *Namespace) GetId() string { if x != nil { return x.Id } return "" } -type GetDiscussionResponse struct { +func (x *Namespace) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Namespace) GetState() string { + if x != nil { + return x.State + } + return "" +} + +func (x *Namespace) GetMetadata() *structpb.Struct { + if x != nil { + return x.Metadata + } + return nil +} + +type GetAllEntitiesRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Data *Discussion `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + Types string `protobuf:"bytes,1,opt,name=types,proto3" json:"types,omitempty"` + Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"` + Q string `protobuf:"bytes,3,opt,name=q,proto3" json:"q,omitempty"` + Size uint32 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"` + Offset uint32 `protobuf:"varint,5,opt,name=offset,proto3" json:"offset,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetDiscussionResponse) Reset() { - *x = GetDiscussionResponse{} +func (x *GetAllEntitiesRequest) Reset() { + *x = GetAllEntitiesRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetDiscussionResponse) String() string { +func (x *GetAllEntitiesRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetDiscussionResponse) ProtoMessage() {} +func (*GetAllEntitiesRequest) ProtoMessage() {} -func (x *GetDiscussionResponse) ProtoReflect() protoreflect.Message { +func (x *GetAllEntitiesRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -397,46 +496,68 @@ func (x *GetDiscussionResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetDiscussionResponse.ProtoReflect.Descriptor instead. -func (*GetDiscussionResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use GetAllEntitiesRequest.ProtoReflect.Descriptor instead. +func (*GetAllEntitiesRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{5} } -func (x *GetDiscussionResponse) GetData() *Discussion { +func (x *GetAllEntitiesRequest) GetTypes() string { if x != nil { - return x.Data + return x.Types } - return nil + return "" +} + +func (x *GetAllEntitiesRequest) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *GetAllEntitiesRequest) GetQ() string { + if x != nil { + return x.Q + } + return "" } -type PatchDiscussionRequest struct { +func (x *GetAllEntitiesRequest) GetSize() uint32 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *GetAllEntitiesRequest) GetOffset() uint32 { + if x != nil { + return x.Offset + } + return 0 +} + +type GetAllEntitiesResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` - Body string `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` - Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` - State string `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"` - Labels []string `protobuf:"bytes,6,rep,name=labels,proto3" json:"labels,omitempty"` - Assets []string `protobuf:"bytes,7,rep,name=assets,proto3" json:"assets,omitempty"` - Assignees []string `protobuf:"bytes,8,rep,name=assignees,proto3" json:"assignees,omitempty"` + Data []*Entity `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + Total uint32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *PatchDiscussionRequest) Reset() { - *x = PatchDiscussionRequest{} +func (x *GetAllEntitiesResponse) Reset() { + *x = GetAllEntitiesResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *PatchDiscussionRequest) String() string { +func (x *GetAllEntitiesResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PatchDiscussionRequest) ProtoMessage() {} +func (*GetAllEntitiesResponse) ProtoMessage() {} -func (x *PatchDiscussionRequest) ProtoReflect() protoreflect.Message { +func (x *GetAllEntitiesResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -448,89 +569,46 @@ func (x *PatchDiscussionRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PatchDiscussionRequest.ProtoReflect.Descriptor instead. -func (*PatchDiscussionRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use GetAllEntitiesResponse.ProtoReflect.Descriptor instead. +func (*GetAllEntitiesResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{6} } -func (x *PatchDiscussionRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *PatchDiscussionRequest) GetTitle() string { - if x != nil { - return x.Title - } - return "" -} - -func (x *PatchDiscussionRequest) GetBody() string { - if x != nil { - return x.Body - } - return "" -} - -func (x *PatchDiscussionRequest) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *PatchDiscussionRequest) GetState() string { - if x != nil { - return x.State - } - return "" -} - -func (x *PatchDiscussionRequest) GetLabels() []string { - if x != nil { - return x.Labels - } - return nil -} - -func (x *PatchDiscussionRequest) GetAssets() []string { +func (x *GetAllEntitiesResponse) GetData() []*Entity { if x != nil { - return x.Assets + return x.Data } return nil } -func (x *PatchDiscussionRequest) GetAssignees() []string { +func (x *GetAllEntitiesResponse) GetTotal() uint32 { if x != nil { - return x.Assignees + return x.Total } - return nil + return 0 } -type CreateCommentRequest struct { +type GetEntityByIDRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - DiscussionId string `protobuf:"bytes,1,opt,name=discussion_id,json=discussionId,proto3" json:"discussion_id,omitempty"` - Body string `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *CreateCommentRequest) Reset() { - *x = CreateCommentRequest{} +func (x *GetEntityByIDRequest) Reset() { + *x = GetEntityByIDRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *CreateCommentRequest) String() string { +func (x *GetEntityByIDRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*CreateCommentRequest) ProtoMessage() {} +func (*GetEntityByIDRequest) ProtoMessage() {} -func (x *CreateCommentRequest) ProtoReflect() protoreflect.Message { +func (x *GetEntityByIDRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -542,45 +620,39 @@ func (x *CreateCommentRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CreateCommentRequest.ProtoReflect.Descriptor instead. -func (*CreateCommentRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use GetEntityByIDRequest.ProtoReflect.Descriptor instead. +func (*GetEntityByIDRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{7} } -func (x *CreateCommentRequest) GetDiscussionId() string { - if x != nil { - return x.DiscussionId - } - return "" -} - -func (x *CreateCommentRequest) GetBody() string { +func (x *GetEntityByIDRequest) GetId() string { if x != nil { - return x.Body + return x.Id } return "" } -type PatchDiscussionResponse struct { +type GetEntityByIDResponse struct { state protoimpl.MessageState `protogen:"open.v1"` + Data *Entity `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *PatchDiscussionResponse) Reset() { - *x = PatchDiscussionResponse{} +func (x *GetEntityByIDResponse) Reset() { + *x = GetEntityByIDResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *PatchDiscussionResponse) String() string { +func (x *GetEntityByIDResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PatchDiscussionResponse) ProtoMessage() {} +func (*GetEntityByIDResponse) ProtoMessage() {} -func (x *PatchDiscussionResponse) ProtoReflect() protoreflect.Message { +func (x *GetEntityByIDResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -592,32 +664,46 @@ func (x *PatchDiscussionResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PatchDiscussionResponse.ProtoReflect.Descriptor instead. -func (*PatchDiscussionResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use GetEntityByIDResponse.ProtoReflect.Descriptor instead. +func (*GetEntityByIDResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{8} } -type CreateCommentResponse struct { +func (x *GetEntityByIDResponse) GetData() *Entity { + if x != nil { + return x.Data + } + return nil +} + +type UpsertEntityRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` + Properties *structpb.Struct `protobuf:"bytes,5,opt,name=properties,proto3" json:"properties,omitempty"` + Source string `protobuf:"bytes,6,opt,name=source,proto3" json:"source,omitempty"` + Upstreams []string `protobuf:"bytes,7,rep,name=upstreams,proto3" json:"upstreams,omitempty"` + Downstreams []string `protobuf:"bytes,8,rep,name=downstreams,proto3" json:"downstreams,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *CreateCommentResponse) Reset() { - *x = CreateCommentResponse{} +func (x *UpsertEntityRequest) Reset() { + *x = UpsertEntityRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *CreateCommentResponse) String() string { +func (x *UpsertEntityRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*CreateCommentResponse) ProtoMessage() {} +func (*UpsertEntityRequest) ProtoMessage() {} -func (x *CreateCommentResponse) ProtoReflect() protoreflect.Message { +func (x *UpsertEntityRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -629,116 +715,89 @@ func (x *CreateCommentResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CreateCommentResponse.ProtoReflect.Descriptor instead. -func (*CreateCommentResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use UpsertEntityRequest.ProtoReflect.Descriptor instead. +func (*UpsertEntityRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{9} } -func (x *CreateCommentResponse) GetId() string { +func (x *UpsertEntityRequest) GetUrn() string { if x != nil { - return x.Id + return x.Urn } return "" } -type GetAllCommentsRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - DiscussionId string `protobuf:"bytes,1,opt,name=discussion_id,json=discussionId,proto3" json:"discussion_id,omitempty"` - Sort string `protobuf:"bytes,2,opt,name=sort,proto3" json:"sort,omitempty"` - Direction string `protobuf:"bytes,3,opt,name=direction,proto3" json:"direction,omitempty"` - Size uint32 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"` - Offset uint32 `protobuf:"varint,5,opt,name=offset,proto3" json:"offset,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetAllCommentsRequest) Reset() { - *x = GetAllCommentsRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetAllCommentsRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetAllCommentsRequest) ProtoMessage() {} - -func (x *GetAllCommentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[10] +func (x *UpsertEntityRequest) GetType() string { if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms + return x.Type } - return mi.MessageOf(x) + return "" } -// Deprecated: Use GetAllCommentsRequest.ProtoReflect.Descriptor instead. -func (*GetAllCommentsRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{10} +func (x *UpsertEntityRequest) GetName() string { + if x != nil { + return x.Name + } + return "" } -func (x *GetAllCommentsRequest) GetDiscussionId() string { +func (x *UpsertEntityRequest) GetDescription() string { if x != nil { - return x.DiscussionId + return x.Description } return "" } -func (x *GetAllCommentsRequest) GetSort() string { +func (x *UpsertEntityRequest) GetProperties() *structpb.Struct { if x != nil { - return x.Sort + return x.Properties } - return "" + return nil } -func (x *GetAllCommentsRequest) GetDirection() string { +func (x *UpsertEntityRequest) GetSource() string { if x != nil { - return x.Direction + return x.Source } return "" } -func (x *GetAllCommentsRequest) GetSize() uint32 { +func (x *UpsertEntityRequest) GetUpstreams() []string { if x != nil { - return x.Size + return x.Upstreams } - return 0 + return nil } -func (x *GetAllCommentsRequest) GetOffset() uint32 { +func (x *UpsertEntityRequest) GetDownstreams() []string { if x != nil { - return x.Offset + return x.Downstreams } - return 0 + return nil } -type GetAllCommentsResponse struct { +type UpsertEntityResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Data []*Comment `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAllCommentsResponse) Reset() { - *x = GetAllCommentsResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[11] +func (x *UpsertEntityResponse) Reset() { + *x = UpsertEntityResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAllCommentsResponse) String() string { +func (x *UpsertEntityResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAllCommentsResponse) ProtoMessage() {} +func (*UpsertEntityResponse) ProtoMessage() {} -func (x *GetAllCommentsResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[11] +func (x *UpsertEntityResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -749,41 +808,40 @@ func (x *GetAllCommentsResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAllCommentsResponse.ProtoReflect.Descriptor instead. -func (*GetAllCommentsResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{11} +// Deprecated: Use UpsertEntityResponse.ProtoReflect.Descriptor instead. +func (*UpsertEntityResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{10} } -func (x *GetAllCommentsResponse) GetData() []*Comment { +func (x *UpsertEntityResponse) GetId() string { if x != nil { - return x.Data + return x.Id } - return nil + return "" } -type GetCommentRequest struct { +type DeleteEntityRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - DiscussionId string `protobuf:"bytes,1,opt,name=discussion_id,json=discussionId,proto3" json:"discussion_id,omitempty"` - Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetCommentRequest) Reset() { - *x = GetCommentRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[12] +func (x *DeleteEntityRequest) Reset() { + *x = DeleteEntityRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetCommentRequest) String() string { +func (x *DeleteEntityRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetCommentRequest) ProtoMessage() {} +func (*DeleteEntityRequest) ProtoMessage() {} -func (x *GetCommentRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[12] +func (x *DeleteEntityRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -794,47 +852,39 @@ func (x *GetCommentRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetCommentRequest.ProtoReflect.Descriptor instead. -func (*GetCommentRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{12} -} - -func (x *GetCommentRequest) GetDiscussionId() string { - if x != nil { - return x.DiscussionId - } - return "" +// Deprecated: Use DeleteEntityRequest.ProtoReflect.Descriptor instead. +func (*DeleteEntityRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{11} } -func (x *GetCommentRequest) GetId() string { +func (x *DeleteEntityRequest) GetUrn() string { if x != nil { - return x.Id + return x.Urn } return "" } -type GetCommentResponse struct { +type DeleteEntityResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Data *Comment `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetCommentResponse) Reset() { - *x = GetCommentResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[13] +func (x *DeleteEntityResponse) Reset() { + *x = DeleteEntityResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetCommentResponse) String() string { +func (x *DeleteEntityResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetCommentResponse) ProtoMessage() {} +func (*DeleteEntityResponse) ProtoMessage() {} -func (x *GetCommentResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[13] +func (x *DeleteEntityResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -845,42 +895,38 @@ func (x *GetCommentResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetCommentResponse.ProtoReflect.Descriptor instead. -func (*GetCommentResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{13} -} - -func (x *GetCommentResponse) GetData() *Comment { - if x != nil { - return x.Data - } - return nil +// Deprecated: Use DeleteEntityResponse.ProtoReflect.Descriptor instead. +func (*DeleteEntityResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{12} } -type UpdateCommentRequest struct { +type SearchEntitiesRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - DiscussionId string `protobuf:"bytes,1,opt,name=discussion_id,json=discussionId,proto3" json:"discussion_id,omitempty"` - Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` - Body string `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Types string `protobuf:"bytes,2,opt,name=types,proto3" json:"types,omitempty"` + Source string `protobuf:"bytes,3,opt,name=source,proto3" json:"source,omitempty"` + Mode string `protobuf:"bytes,4,opt,name=mode,proto3" json:"mode,omitempty"` // keyword, semantic, hybrid + Size uint32 `protobuf:"varint,5,opt,name=size,proto3" json:"size,omitempty"` + Offset uint32 `protobuf:"varint,6,opt,name=offset,proto3" json:"offset,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *UpdateCommentRequest) Reset() { - *x = UpdateCommentRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) +func (x *SearchEntitiesRequest) Reset() { + *x = SearchEntitiesRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *UpdateCommentRequest) String() string { +func (x *SearchEntitiesRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpdateCommentRequest) ProtoMessage() {} +func (*SearchEntitiesRequest) ProtoMessage() {} -func (x *UpdateCommentRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[14] +func (x *SearchEntitiesRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -891,53 +937,75 @@ func (x *UpdateCommentRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpdateCommentRequest.ProtoReflect.Descriptor instead. -func (*UpdateCommentRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{14} +// Deprecated: Use SearchEntitiesRequest.ProtoReflect.Descriptor instead. +func (*SearchEntitiesRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{13} +} + +func (x *SearchEntitiesRequest) GetText() string { + if x != nil { + return x.Text + } + return "" } -func (x *UpdateCommentRequest) GetDiscussionId() string { +func (x *SearchEntitiesRequest) GetTypes() string { if x != nil { - return x.DiscussionId + return x.Types } return "" } -func (x *UpdateCommentRequest) GetId() string { +func (x *SearchEntitiesRequest) GetSource() string { if x != nil { - return x.Id + return x.Source } return "" } -func (x *UpdateCommentRequest) GetBody() string { +func (x *SearchEntitiesRequest) GetMode() string { if x != nil { - return x.Body + return x.Mode } return "" } -type UpdateCommentResponse struct { +func (x *SearchEntitiesRequest) GetSize() uint32 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *SearchEntitiesRequest) GetOffset() uint32 { + if x != nil { + return x.Offset + } + return 0 +} + +type SearchEntitiesResponse struct { state protoimpl.MessageState `protogen:"open.v1"` + Data []*Entity `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *UpdateCommentResponse) Reset() { - *x = UpdateCommentResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[15] +func (x *SearchEntitiesResponse) Reset() { + *x = SearchEntitiesResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *UpdateCommentResponse) String() string { +func (x *SearchEntitiesResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpdateCommentResponse) ProtoMessage() {} +func (*SearchEntitiesResponse) ProtoMessage() {} -func (x *UpdateCommentResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[15] +func (x *SearchEntitiesResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -948,34 +1016,40 @@ func (x *UpdateCommentResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpdateCommentResponse.ProtoReflect.Descriptor instead. -func (*UpdateCommentResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{15} +// Deprecated: Use SearchEntitiesResponse.ProtoReflect.Descriptor instead. +func (*SearchEntitiesResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{14} } -type DeleteCommentRequest struct { +func (x *SearchEntitiesResponse) GetData() []*Entity { + if x != nil { + return x.Data + } + return nil +} + +type SuggestEntitiesRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - DiscussionId string `protobuf:"bytes,1,opt,name=discussion_id,json=discussionId,proto3" json:"discussion_id,omitempty"` - Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *DeleteCommentRequest) Reset() { - *x = DeleteCommentRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[16] +func (x *SuggestEntitiesRequest) Reset() { + *x = SuggestEntitiesRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *DeleteCommentRequest) String() string { +func (x *SuggestEntitiesRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeleteCommentRequest) ProtoMessage() {} +func (*SuggestEntitiesRequest) ProtoMessage() {} -func (x *DeleteCommentRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[16] +func (x *SuggestEntitiesRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -986,46 +1060,40 @@ func (x *DeleteCommentRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DeleteCommentRequest.ProtoReflect.Descriptor instead. -func (*DeleteCommentRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{16} -} - -func (x *DeleteCommentRequest) GetDiscussionId() string { - if x != nil { - return x.DiscussionId - } - return "" +// Deprecated: Use SuggestEntitiesRequest.ProtoReflect.Descriptor instead. +func (*SuggestEntitiesRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{15} } -func (x *DeleteCommentRequest) GetId() string { +func (x *SuggestEntitiesRequest) GetText() string { if x != nil { - return x.Id + return x.Text } return "" } -type DeleteCommentResponse struct { +type SuggestEntitiesResponse struct { state protoimpl.MessageState `protogen:"open.v1"` + Data []string `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *DeleteCommentResponse) Reset() { - *x = DeleteCommentResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[17] +func (x *SuggestEntitiesResponse) Reset() { + *x = SuggestEntitiesResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *DeleteCommentResponse) String() string { +func (x *SuggestEntitiesResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeleteCommentResponse) ProtoMessage() {} +func (*SuggestEntitiesResponse) ProtoMessage() {} -func (x *DeleteCommentResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[17] +func (x *SuggestEntitiesResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1036,40 +1104,39 @@ func (x *DeleteCommentResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DeleteCommentResponse.ProtoReflect.Descriptor instead. -func (*DeleteCommentResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{17} +// Deprecated: Use SuggestEntitiesResponse.ProtoReflect.Descriptor instead. +func (*SuggestEntitiesResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{16} +} + +func (x *SuggestEntitiesResponse) GetData() []string { + if x != nil { + return x.Data + } + return nil } -type SearchAssetsRequest struct { +type GetEntityTypesRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` - Rankby string `protobuf:"bytes,2,opt,name=rankby,proto3" json:"rankby,omitempty"` - Size uint32 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` - Filter map[string]string `protobuf:"bytes,4,rep,name=filter,proto3" json:"filter,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Query map[string]string `protobuf:"bytes,5,rep,name=query,proto3" json:"query,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - IncludeFields []string `protobuf:"bytes,6,rep,name=include_fields,json=includeFields,proto3" json:"include_fields,omitempty"` - Offset uint32 `protobuf:"varint,7,opt,name=offset,proto3" json:"offset,omitempty"` - Flags *SearchFlags `protobuf:"bytes,8,opt,name=flags,proto3" json:"flags,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *SearchAssetsRequest) Reset() { - *x = SearchAssetsRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[18] +func (x *GetEntityTypesRequest) Reset() { + *x = GetEntityTypesRequest{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SearchAssetsRequest) String() string { +func (x *GetEntityTypesRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SearchAssetsRequest) ProtoMessage() {} +func (*GetEntityTypesRequest) ProtoMessage() {} -func (x *SearchAssetsRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[18] +func (x *GetEntityTypesRequest) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1080,90 +1147,77 @@ func (x *SearchAssetsRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SearchAssetsRequest.ProtoReflect.Descriptor instead. -func (*SearchAssetsRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{18} -} - -func (x *SearchAssetsRequest) GetText() string { - if x != nil { - return x.Text - } - return "" +// Deprecated: Use GetEntityTypesRequest.ProtoReflect.Descriptor instead. +func (*GetEntityTypesRequest) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{17} } -func (x *SearchAssetsRequest) GetRankby() string { - if x != nil { - return x.Rankby - } - return "" +type GetEntityTypesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Data []*Type `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *SearchAssetsRequest) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 +func (x *GetEntityTypesResponse) Reset() { + *x = GetEntityTypesResponse{} + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } -func (x *SearchAssetsRequest) GetFilter() map[string]string { - if x != nil { - return x.Filter - } - return nil +func (x *GetEntityTypesResponse) String() string { + return protoimpl.X.MessageStringOf(x) } -func (x *SearchAssetsRequest) GetQuery() map[string]string { - if x != nil { - return x.Query - } - return nil -} +func (*GetEntityTypesResponse) ProtoMessage() {} -func (x *SearchAssetsRequest) GetIncludeFields() []string { +func (x *GetEntityTypesResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[18] if x != nil { - return x.IncludeFields + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return nil + return mi.MessageOf(x) } -func (x *SearchAssetsRequest) GetOffset() uint32 { - if x != nil { - return x.Offset - } - return 0 +// Deprecated: Use GetEntityTypesResponse.ProtoReflect.Descriptor instead. +func (*GetEntityTypesResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{18} } -func (x *SearchAssetsRequest) GetFlags() *SearchFlags { +func (x *GetEntityTypesResponse) GetData() []*Type { if x != nil { - return x.Flags + return x.Data } return nil } -type SearchFlags struct { - state protoimpl.MessageState `protogen:"open.v1"` - IsColumnSearch bool `protobuf:"varint,1,opt,name=is_column_search,json=isColumnSearch,proto3" json:"is_column_search,omitempty"` - DisableFuzzy bool `protobuf:"varint,2,opt,name=disable_fuzzy,json=disableFuzzy,proto3" json:"disable_fuzzy,omitempty"` - EnableHighlight bool `protobuf:"varint,3,opt,name=enable_highlight,json=enableHighlight,proto3" json:"enable_highlight,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +type GetEntityContextRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` + Depth uint32 `protobuf:"varint,2,opt,name=depth,proto3" json:"depth,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *SearchFlags) Reset() { - *x = SearchFlags{} +func (x *GetEntityContextRequest) Reset() { + *x = GetEntityContextRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SearchFlags) String() string { +func (x *GetEntityContextRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SearchFlags) ProtoMessage() {} +func (*GetEntityContextRequest) ProtoMessage() {} -func (x *SearchFlags) ProtoReflect() protoreflect.Message { +func (x *GetEntityContextRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1175,53 +1229,48 @@ func (x *SearchFlags) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SearchFlags.ProtoReflect.Descriptor instead. -func (*SearchFlags) Descriptor() ([]byte, []int) { +// Deprecated: Use GetEntityContextRequest.ProtoReflect.Descriptor instead. +func (*GetEntityContextRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{19} } -func (x *SearchFlags) GetIsColumnSearch() bool { - if x != nil { - return x.IsColumnSearch - } - return false -} - -func (x *SearchFlags) GetDisableFuzzy() bool { +func (x *GetEntityContextRequest) GetUrn() string { if x != nil { - return x.DisableFuzzy + return x.Urn } - return false + return "" } -func (x *SearchFlags) GetEnableHighlight() bool { +func (x *GetEntityContextRequest) GetDepth() uint32 { if x != nil { - return x.EnableHighlight + return x.Depth } - return false + return 0 } -type SearchAssetsResponse struct { +type GetEntityContextResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Data []*Asset `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + Entity *Entity `protobuf:"bytes,1,opt,name=entity,proto3" json:"entity,omitempty"` + Edges []*Edge `protobuf:"bytes,2,rep,name=edges,proto3" json:"edges,omitempty"` + Related []*Entity `protobuf:"bytes,3,rep,name=related,proto3" json:"related,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *SearchAssetsResponse) Reset() { - *x = SearchAssetsResponse{} +func (x *GetEntityContextResponse) Reset() { + *x = GetEntityContextResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SearchAssetsResponse) String() string { +func (x *GetEntityContextResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SearchAssetsResponse) ProtoMessage() {} +func (*GetEntityContextResponse) ProtoMessage() {} -func (x *SearchAssetsResponse) ProtoReflect() protoreflect.Message { +func (x *GetEntityContextResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1233,39 +1282,54 @@ func (x *SearchAssetsResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SearchAssetsResponse.ProtoReflect.Descriptor instead. -func (*SearchAssetsResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use GetEntityContextResponse.ProtoReflect.Descriptor instead. +func (*GetEntityContextResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{20} } -func (x *SearchAssetsResponse) GetData() []*Asset { +func (x *GetEntityContextResponse) GetEntity() *Entity { if x != nil { - return x.Data + return x.Entity + } + return nil +} + +func (x *GetEntityContextResponse) GetEdges() []*Edge { + if x != nil { + return x.Edges + } + return nil +} + +func (x *GetEntityContextResponse) GetRelated() []*Entity { + if x != nil { + return x.Related } return nil } -type SuggestAssetsRequest struct { +type GetEntityImpactRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` + Depth uint32 `protobuf:"varint,2,opt,name=depth,proto3" json:"depth,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *SuggestAssetsRequest) Reset() { - *x = SuggestAssetsRequest{} +func (x *GetEntityImpactRequest) Reset() { + *x = GetEntityImpactRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SuggestAssetsRequest) String() string { +func (x *GetEntityImpactRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SuggestAssetsRequest) ProtoMessage() {} +func (*GetEntityImpactRequest) ProtoMessage() {} -func (x *SuggestAssetsRequest) ProtoReflect() protoreflect.Message { +func (x *GetEntityImpactRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1277,39 +1341,47 @@ func (x *SuggestAssetsRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SuggestAssetsRequest.ProtoReflect.Descriptor instead. -func (*SuggestAssetsRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use GetEntityImpactRequest.ProtoReflect.Descriptor instead. +func (*GetEntityImpactRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{21} } -func (x *SuggestAssetsRequest) GetText() string { +func (x *GetEntityImpactRequest) GetUrn() string { if x != nil { - return x.Text + return x.Urn } return "" } -type SuggestAssetsResponse struct { +func (x *GetEntityImpactRequest) GetDepth() uint32 { + if x != nil { + return x.Depth + } + return 0 +} + +type GetEntityImpactResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Data []string `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + Edges []*Edge `protobuf:"bytes,1,rep,name=edges,proto3" json:"edges,omitempty"` + Affected []*Entity `protobuf:"bytes,2,rep,name=affected,proto3" json:"affected,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *SuggestAssetsResponse) Reset() { - *x = SuggestAssetsResponse{} +func (x *GetEntityImpactResponse) Reset() { + *x = GetEntityImpactResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SuggestAssetsResponse) String() string { +func (x *GetEntityImpactResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SuggestAssetsResponse) ProtoMessage() {} +func (*GetEntityImpactResponse) ProtoMessage() {} -func (x *SuggestAssetsResponse) ProtoReflect() protoreflect.Message { +func (x *GetEntityImpactResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1321,42 +1393,50 @@ func (x *SuggestAssetsResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SuggestAssetsResponse.ProtoReflect.Descriptor instead. -func (*SuggestAssetsResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use GetEntityImpactResponse.ProtoReflect.Descriptor instead. +func (*GetEntityImpactResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{22} } -func (x *SuggestAssetsResponse) GetData() []string { +func (x *GetEntityImpactResponse) GetEdges() []*Edge { if x != nil { - return x.Data + return x.Edges + } + return nil +} + +func (x *GetEntityImpactResponse) GetAffected() []*Entity { + if x != nil { + return x.Affected } return nil } -type GroupAssetsRequest struct { +type UpsertEdgeRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Groupby []string `protobuf:"bytes,1,rep,name=groupby,proto3" json:"groupby,omitempty"` - Filter map[string]string `protobuf:"bytes,2,rep,name=filter,proto3" json:"filter,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - IncludeFields []string `protobuf:"bytes,3,rep,name=include_fields,json=includeFields,proto3" json:"include_fields,omitempty"` - Size uint32 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"` + SourceUrn string `protobuf:"bytes,1,opt,name=source_urn,json=sourceUrn,proto3" json:"source_urn,omitempty"` + TargetUrn string `protobuf:"bytes,2,opt,name=target_urn,json=targetUrn,proto3" json:"target_urn,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + Properties *structpb.Struct `protobuf:"bytes,4,opt,name=properties,proto3" json:"properties,omitempty"` + Source string `protobuf:"bytes,5,opt,name=source,proto3" json:"source,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupAssetsRequest) Reset() { - *x = GroupAssetsRequest{} +func (x *UpsertEdgeRequest) Reset() { + *x = UpsertEdgeRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupAssetsRequest) String() string { +func (x *UpsertEdgeRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupAssetsRequest) ProtoMessage() {} +func (*UpsertEdgeRequest) ProtoMessage() {} -func (x *GroupAssetsRequest) ProtoReflect() protoreflect.Message { +func (x *UpsertEdgeRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1368,60 +1448,67 @@ func (x *GroupAssetsRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GroupAssetsRequest.ProtoReflect.Descriptor instead. -func (*GroupAssetsRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use UpsertEdgeRequest.ProtoReflect.Descriptor instead. +func (*UpsertEdgeRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{23} } -func (x *GroupAssetsRequest) GetGroupby() []string { +func (x *UpsertEdgeRequest) GetSourceUrn() string { if x != nil { - return x.Groupby + return x.SourceUrn } - return nil + return "" } -func (x *GroupAssetsRequest) GetFilter() map[string]string { +func (x *UpsertEdgeRequest) GetTargetUrn() string { if x != nil { - return x.Filter + return x.TargetUrn } - return nil + return "" +} + +func (x *UpsertEdgeRequest) GetType() string { + if x != nil { + return x.Type + } + return "" } -func (x *GroupAssetsRequest) GetIncludeFields() []string { +func (x *UpsertEdgeRequest) GetProperties() *structpb.Struct { if x != nil { - return x.IncludeFields + return x.Properties } return nil } -func (x *GroupAssetsRequest) GetSize() uint32 { +func (x *UpsertEdgeRequest) GetSource() string { if x != nil { - return x.Size + return x.Source } - return 0 + return "" } -type GroupAssetsResponse struct { +type UpsertEdgeResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - AssetGroups []*AssetGroup `protobuf:"bytes,1,rep,name=asset_groups,json=assetGroups,proto3" json:"asset_groups,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupAssetsResponse) Reset() { - *x = GroupAssetsResponse{} +func (x *UpsertEdgeResponse) Reset() { + *x = UpsertEdgeResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupAssetsResponse) String() string { +func (x *UpsertEdgeResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupAssetsResponse) ProtoMessage() {} +func (*UpsertEdgeResponse) ProtoMessage() {} -func (x *GroupAssetsResponse) ProtoReflect() protoreflect.Message { +func (x *UpsertEdgeResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1433,40 +1520,42 @@ func (x *GroupAssetsResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GroupAssetsResponse.ProtoReflect.Descriptor instead. -func (*GroupAssetsResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use UpsertEdgeResponse.ProtoReflect.Descriptor instead. +func (*UpsertEdgeResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{24} } -func (x *GroupAssetsResponse) GetAssetGroups() []*AssetGroup { +func (x *UpsertEdgeResponse) GetId() string { if x != nil { - return x.AssetGroups + return x.Id } - return nil + return "" } -type AssetGroup struct { +type GetEdgesRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - GroupFields []*GroupField `protobuf:"bytes,1,rep,name=group_fields,json=groupFields,proto3" json:"group_fields,omitempty"` - Assets []*Asset `protobuf:"bytes,2,rep,name=assets,proto3" json:"assets,omitempty"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` + Direction string `protobuf:"bytes,2,opt,name=direction,proto3" json:"direction,omitempty"` // outgoing, incoming, both + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + CurrentOnly bool `protobuf:"varint,4,opt,name=current_only,json=currentOnly,proto3" json:"current_only,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *AssetGroup) Reset() { - *x = AssetGroup{} +func (x *GetEdgesRequest) Reset() { + *x = GetEdgesRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *AssetGroup) String() string { +func (x *GetEdgesRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AssetGroup) ProtoMessage() {} +func (*GetEdgesRequest) ProtoMessage() {} -func (x *AssetGroup) ProtoReflect() protoreflect.Message { +func (x *GetEdgesRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1478,47 +1567,60 @@ func (x *AssetGroup) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use AssetGroup.ProtoReflect.Descriptor instead. -func (*AssetGroup) Descriptor() ([]byte, []int) { +// Deprecated: Use GetEdgesRequest.ProtoReflect.Descriptor instead. +func (*GetEdgesRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{25} } -func (x *AssetGroup) GetGroupFields() []*GroupField { +func (x *GetEdgesRequest) GetUrn() string { if x != nil { - return x.GroupFields + return x.Urn } - return nil + return "" } -func (x *AssetGroup) GetAssets() []*Asset { +func (x *GetEdgesRequest) GetDirection() string { if x != nil { - return x.Assets + return x.Direction } - return nil + return "" +} + +func (x *GetEdgesRequest) GetType() string { + if x != nil { + return x.Type + } + return "" } -type GroupField struct { +func (x *GetEdgesRequest) GetCurrentOnly() bool { + if x != nil { + return x.CurrentOnly + } + return false +} + +type GetEdgesResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - GroupKey string `protobuf:"bytes,1,opt,name=group_key,json=groupKey,proto3" json:"group_key,omitempty"` - GroupValue string `protobuf:"bytes,2,opt,name=group_value,json=groupValue,proto3" json:"group_value,omitempty"` + Data []*Edge `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GroupField) Reset() { - *x = GroupField{} +func (x *GetEdgesResponse) Reset() { + *x = GetEdgesResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GroupField) String() string { +func (x *GetEdgesResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GroupField) ProtoMessage() {} +func (*GetEdgesResponse) ProtoMessage() {} -func (x *GroupField) ProtoReflect() protoreflect.Message { +func (x *GetEdgesResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1530,50 +1632,41 @@ func (x *GroupField) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GroupField.ProtoReflect.Descriptor instead. -func (*GroupField) Descriptor() ([]byte, []int) { +// Deprecated: Use GetEdgesResponse.ProtoReflect.Descriptor instead. +func (*GetEdgesResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{26} } -func (x *GroupField) GetGroupKey() string { - if x != nil { - return x.GroupKey - } - return "" -} - -func (x *GroupField) GetGroupValue() string { +func (x *GetEdgesResponse) GetData() []*Edge { if x != nil { - return x.GroupValue + return x.Data } - return "" + return nil } -type GetGraphRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - Level uint32 `protobuf:"varint,2,opt,name=level,proto3" json:"level,omitempty"` - Direction string `protobuf:"bytes,3,opt,name=direction,proto3" json:"direction,omitempty"` - WithAttributes *bool `protobuf:"varint,4,opt,name=with_attributes,json=withAttributes,proto3,oneof" json:"with_attributes,omitempty"` - IncludeDeleted bool `protobuf:"varint,5,opt,name=include_deleted,json=includeDeleted,proto3" json:"include_deleted,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +type DeleteEdgeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SourceUrn string `protobuf:"bytes,1,opt,name=source_urn,json=sourceUrn,proto3" json:"source_urn,omitempty"` + TargetUrn string `protobuf:"bytes,2,opt,name=target_urn,json=targetUrn,proto3" json:"target_urn,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *GetGraphRequest) Reset() { - *x = GetGraphRequest{} +func (x *DeleteEdgeRequest) Reset() { + *x = DeleteEdgeRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetGraphRequest) String() string { +func (x *DeleteEdgeRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetGraphRequest) ProtoMessage() {} +func (*DeleteEdgeRequest) ProtoMessage() {} -func (x *GetGraphRequest) ProtoReflect() protoreflect.Message { +func (x *DeleteEdgeRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1585,71 +1678,52 @@ func (x *GetGraphRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetGraphRequest.ProtoReflect.Descriptor instead. -func (*GetGraphRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use DeleteEdgeRequest.ProtoReflect.Descriptor instead. +func (*DeleteEdgeRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{27} } -func (x *GetGraphRequest) GetUrn() string { +func (x *DeleteEdgeRequest) GetSourceUrn() string { if x != nil { - return x.Urn + return x.SourceUrn } return "" } -func (x *GetGraphRequest) GetLevel() uint32 { - if x != nil { - return x.Level - } - return 0 -} - -func (x *GetGraphRequest) GetDirection() string { +func (x *DeleteEdgeRequest) GetTargetUrn() string { if x != nil { - return x.Direction + return x.TargetUrn } return "" } -func (x *GetGraphRequest) GetWithAttributes() bool { - if x != nil && x.WithAttributes != nil { - return *x.WithAttributes - } - return false -} - -func (x *GetGraphRequest) GetIncludeDeleted() bool { +func (x *DeleteEdgeRequest) GetType() string { if x != nil { - return x.IncludeDeleted + return x.Type } - return false + return "" } -type GetGraphResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Edges in the graph. - Data []*LineageEdge `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - // Key is the asset URN. Node attributes, if present, will be returned for - // source and target nodes in the LineageEdge. - NodeAttrs map[string]*GetGraphResponse_NodeAttributes `protobuf:"bytes,2,rep,name=node_attrs,json=nodeAttrs,proto3" json:"node_attrs,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` +type DeleteEdgeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetGraphResponse) Reset() { - *x = GetGraphResponse{} +func (x *DeleteEdgeResponse) Reset() { + *x = DeleteEdgeResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetGraphResponse) String() string { +func (x *DeleteEdgeResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetGraphResponse) ProtoMessage() {} +func (*DeleteEdgeResponse) ProtoMessage() {} -func (x *GetGraphResponse) ProtoReflect() protoreflect.Message { +func (x *DeleteEdgeResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1661,50 +1735,32 @@ func (x *GetGraphResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetGraphResponse.ProtoReflect.Descriptor instead. -func (*GetGraphResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use DeleteEdgeResponse.ProtoReflect.Descriptor instead. +func (*DeleteEdgeResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{28} } -func (x *GetGraphResponse) GetData() []*LineageEdge { - if x != nil { - return x.Data - } - return nil -} - -func (x *GetGraphResponse) GetNodeAttrs() map[string]*GetGraphResponse_NodeAttributes { - if x != nil { - return x.NodeAttrs - } - return nil -} - -type GetAllTypesRequest struct { +type StarEntityRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Q string `protobuf:"bytes,1,opt,name=q,proto3" json:"q,omitempty"` - QFields string `protobuf:"bytes,2,opt,name=q_fields,json=qFields,proto3" json:"q_fields,omitempty"` - Types string `protobuf:"bytes,3,opt,name=types,proto3" json:"types,omitempty"` - Services string `protobuf:"bytes,4,opt,name=services,proto3" json:"services,omitempty"` - Data map[string]string `protobuf:"bytes,5,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAllTypesRequest) Reset() { - *x = GetAllTypesRequest{} +func (x *StarEntityRequest) Reset() { + *x = StarEntityRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAllTypesRequest) String() string { +func (x *StarEntityRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAllTypesRequest) ProtoMessage() {} +func (*StarEntityRequest) ProtoMessage() {} -func (x *GetAllTypesRequest) ProtoReflect() protoreflect.Message { +func (x *StarEntityRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1716,67 +1772,39 @@ func (x *GetAllTypesRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAllTypesRequest.ProtoReflect.Descriptor instead. -func (*GetAllTypesRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use StarEntityRequest.ProtoReflect.Descriptor instead. +func (*StarEntityRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{29} } -func (x *GetAllTypesRequest) GetQ() string { - if x != nil { - return x.Q - } - return "" -} - -func (x *GetAllTypesRequest) GetQFields() string { - if x != nil { - return x.QFields - } - return "" -} - -func (x *GetAllTypesRequest) GetTypes() string { - if x != nil { - return x.Types - } - return "" -} - -func (x *GetAllTypesRequest) GetServices() string { +func (x *StarEntityRequest) GetEntityId() string { if x != nil { - return x.Services + return x.EntityId } return "" } -func (x *GetAllTypesRequest) GetData() map[string]string { - if x != nil { - return x.Data - } - return nil -} - -type GetAllTypesResponse struct { +type StarEntityResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Data []*Type `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAllTypesResponse) Reset() { - *x = GetAllTypesResponse{} +func (x *StarEntityResponse) Reset() { + *x = StarEntityResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAllTypesResponse) String() string { +func (x *StarEntityResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAllTypesResponse) ProtoMessage() {} +func (*StarEntityResponse) ProtoMessage() {} -func (x *GetAllTypesResponse) ProtoReflect() protoreflect.Message { +func (x *StarEntityResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1788,49 +1816,39 @@ func (x *GetAllTypesResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAllTypesResponse.ProtoReflect.Descriptor instead. -func (*GetAllTypesResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use StarEntityResponse.ProtoReflect.Descriptor instead. +func (*StarEntityResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{30} } -func (x *GetAllTypesResponse) GetData() []*Type { +func (x *StarEntityResponse) GetId() string { if x != nil { - return x.Data + return x.Id } - return nil + return "" } -type GetAllAssetsRequest struct { +type UnstarEntityRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Q string `protobuf:"bytes,1,opt,name=q,proto3" json:"q,omitempty"` - QFields string `protobuf:"bytes,2,opt,name=q_fields,json=qFields,proto3" json:"q_fields,omitempty"` - Types string `protobuf:"bytes,3,opt,name=types,proto3" json:"types,omitempty"` - Services string `protobuf:"bytes,4,opt,name=services,proto3" json:"services,omitempty"` - Sort string `protobuf:"bytes,5,opt,name=sort,proto3" json:"sort,omitempty"` - Direction string `protobuf:"bytes,6,opt,name=direction,proto3" json:"direction,omitempty"` - Data map[string]string `protobuf:"bytes,7,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Size uint32 `protobuf:"varint,8,opt,name=size,proto3" json:"size,omitempty"` - Offset uint32 `protobuf:"varint,9,opt,name=offset,proto3" json:"offset,omitempty"` - WithTotal bool `protobuf:"varint,10,opt,name=with_total,json=withTotal,proto3" json:"with_total,omitempty"` - IsDeleted bool `protobuf:"varint,11,opt,name=is_deleted,json=isDeleted,proto3" json:"is_deleted,omitempty"` + EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAllAssetsRequest) Reset() { - *x = GetAllAssetsRequest{} +func (x *UnstarEntityRequest) Reset() { + *x = UnstarEntityRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAllAssetsRequest) String() string { +func (x *UnstarEntityRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAllAssetsRequest) ProtoMessage() {} +func (*UnstarEntityRequest) ProtoMessage() {} -func (x *GetAllAssetsRequest) ProtoReflect() protoreflect.Message { +func (x *UnstarEntityRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1842,110 +1860,38 @@ func (x *GetAllAssetsRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAllAssetsRequest.ProtoReflect.Descriptor instead. -func (*GetAllAssetsRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use UnstarEntityRequest.ProtoReflect.Descriptor instead. +func (*UnstarEntityRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{31} } -func (x *GetAllAssetsRequest) GetQ() string { - if x != nil { - return x.Q - } - return "" -} - -func (x *GetAllAssetsRequest) GetQFields() string { - if x != nil { - return x.QFields - } - return "" -} - -func (x *GetAllAssetsRequest) GetTypes() string { - if x != nil { - return x.Types - } - return "" -} - -func (x *GetAllAssetsRequest) GetServices() string { - if x != nil { - return x.Services - } - return "" -} - -func (x *GetAllAssetsRequest) GetSort() string { - if x != nil { - return x.Sort - } - return "" -} - -func (x *GetAllAssetsRequest) GetDirection() string { +func (x *UnstarEntityRequest) GetEntityId() string { if x != nil { - return x.Direction + return x.EntityId } return "" } -func (x *GetAllAssetsRequest) GetData() map[string]string { - if x != nil { - return x.Data - } - return nil -} - -func (x *GetAllAssetsRequest) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *GetAllAssetsRequest) GetOffset() uint32 { - if x != nil { - return x.Offset - } - return 0 -} - -func (x *GetAllAssetsRequest) GetWithTotal() bool { - if x != nil { - return x.WithTotal - } - return false -} - -func (x *GetAllAssetsRequest) GetIsDeleted() bool { - if x != nil { - return x.IsDeleted - } - return false -} - -type GetAllAssetsResponse struct { +type UnstarEntityResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Data []*Asset `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - Total uint32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAllAssetsResponse) Reset() { - *x = GetAllAssetsResponse{} +func (x *UnstarEntityResponse) Reset() { + *x = UnstarEntityResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAllAssetsResponse) String() string { +func (x *UnstarEntityResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAllAssetsResponse) ProtoMessage() {} +func (*UnstarEntityResponse) ProtoMessage() {} -func (x *GetAllAssetsResponse) ProtoReflect() protoreflect.Message { +func (x *UnstarEntityResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1957,46 +1903,34 @@ func (x *GetAllAssetsResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAllAssetsResponse.ProtoReflect.Descriptor instead. -func (*GetAllAssetsResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use UnstarEntityResponse.ProtoReflect.Descriptor instead. +func (*UnstarEntityResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{32} } -func (x *GetAllAssetsResponse) GetData() []*Asset { - if x != nil { - return x.Data - } - return nil -} - -func (x *GetAllAssetsResponse) GetTotal() uint32 { - if x != nil { - return x.Total - } - return 0 -} - -type GetAssetByIDRequest struct { +type GetUserStarredEntitiesRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Size uint32 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` + Offset uint32 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAssetByIDRequest) Reset() { - *x = GetAssetByIDRequest{} +func (x *GetUserStarredEntitiesRequest) Reset() { + *x = GetUserStarredEntitiesRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAssetByIDRequest) String() string { +func (x *GetUserStarredEntitiesRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAssetByIDRequest) ProtoMessage() {} +func (*GetUserStarredEntitiesRequest) ProtoMessage() {} -func (x *GetAssetByIDRequest) ProtoReflect() protoreflect.Message { +func (x *GetUserStarredEntitiesRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2008,39 +1942,53 @@ func (x *GetAssetByIDRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAssetByIDRequest.ProtoReflect.Descriptor instead. -func (*GetAssetByIDRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use GetUserStarredEntitiesRequest.ProtoReflect.Descriptor instead. +func (*GetUserStarredEntitiesRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{33} } -func (x *GetAssetByIDRequest) GetId() string { +func (x *GetUserStarredEntitiesRequest) GetUserId() string { if x != nil { - return x.Id + return x.UserId } return "" } -type GetAssetByIDResponse struct { +func (x *GetUserStarredEntitiesRequest) GetSize() uint32 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *GetUserStarredEntitiesRequest) GetOffset() uint32 { + if x != nil { + return x.Offset + } + return 0 +} + +type GetUserStarredEntitiesResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Data *Asset `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + Data []*Entity `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAssetByIDResponse) Reset() { - *x = GetAssetByIDResponse{} +func (x *GetUserStarredEntitiesResponse) Reset() { + *x = GetUserStarredEntitiesResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAssetByIDResponse) String() string { +func (x *GetUserStarredEntitiesResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAssetByIDResponse) ProtoMessage() {} +func (*GetUserStarredEntitiesResponse) ProtoMessage() {} -func (x *GetAssetByIDResponse) ProtoReflect() protoreflect.Message { +func (x *GetUserStarredEntitiesResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2052,42 +2000,40 @@ func (x *GetAssetByIDResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAssetByIDResponse.ProtoReflect.Descriptor instead. -func (*GetAssetByIDResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use GetUserStarredEntitiesResponse.ProtoReflect.Descriptor instead. +func (*GetUserStarredEntitiesResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{34} } -func (x *GetAssetByIDResponse) GetData() *Asset { +func (x *GetUserStarredEntitiesResponse) GetData() []*Entity { if x != nil { return x.Data } return nil } -type UpsertAssetRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Asset *UpsertAssetRequest_Asset `protobuf:"bytes,1,opt,name=asset,proto3" json:"asset,omitempty"` - Upstreams []*LineageNode `protobuf:"bytes,2,rep,name=upstreams,proto3" json:"upstreams,omitempty"` - Downstreams []*LineageNode `protobuf:"bytes,3,rep,name=downstreams,proto3" json:"downstreams,omitempty"` - UpdateOnly bool `protobuf:"varint,4,opt,name=update_only,json=updateOnly,proto3" json:"update_only,omitempty"` +type GetMyStarredEntitiesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Size uint32 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"` + Offset uint32 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *UpsertAssetRequest) Reset() { - *x = UpsertAssetRequest{} +func (x *GetMyStarredEntitiesRequest) Reset() { + *x = GetMyStarredEntitiesRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *UpsertAssetRequest) String() string { +func (x *GetMyStarredEntitiesRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpsertAssetRequest) ProtoMessage() {} +func (*GetMyStarredEntitiesRequest) ProtoMessage() {} -func (x *UpsertAssetRequest) ProtoReflect() protoreflect.Message { +func (x *GetMyStarredEntitiesRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2099,60 +2045,46 @@ func (x *UpsertAssetRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpsertAssetRequest.ProtoReflect.Descriptor instead. -func (*UpsertAssetRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use GetMyStarredEntitiesRequest.ProtoReflect.Descriptor instead. +func (*GetMyStarredEntitiesRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{35} } -func (x *UpsertAssetRequest) GetAsset() *UpsertAssetRequest_Asset { - if x != nil { - return x.Asset - } - return nil -} - -func (x *UpsertAssetRequest) GetUpstreams() []*LineageNode { - if x != nil { - return x.Upstreams - } - return nil -} - -func (x *UpsertAssetRequest) GetDownstreams() []*LineageNode { +func (x *GetMyStarredEntitiesRequest) GetSize() uint32 { if x != nil { - return x.Downstreams + return x.Size } - return nil + return 0 } -func (x *UpsertAssetRequest) GetUpdateOnly() bool { +func (x *GetMyStarredEntitiesRequest) GetOffset() uint32 { if x != nil { - return x.UpdateOnly + return x.Offset } - return false + return 0 } -type UpsertAssetResponse struct { +type GetMyStarredEntitiesResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Data []*Entity `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *UpsertAssetResponse) Reset() { - *x = UpsertAssetResponse{} +func (x *GetMyStarredEntitiesResponse) Reset() { + *x = GetMyStarredEntitiesResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *UpsertAssetResponse) String() string { +func (x *GetMyStarredEntitiesResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpsertAssetResponse) ProtoMessage() {} +func (*GetMyStarredEntitiesResponse) ProtoMessage() {} -func (x *UpsertAssetResponse) ProtoReflect() protoreflect.Message { +func (x *GetMyStarredEntitiesResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2164,47 +2096,39 @@ func (x *UpsertAssetResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpsertAssetResponse.ProtoReflect.Descriptor instead. -func (*UpsertAssetResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use GetMyStarredEntitiesResponse.ProtoReflect.Descriptor instead. +func (*GetMyStarredEntitiesResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{36} } -func (x *UpsertAssetResponse) GetId() string { +func (x *GetMyStarredEntitiesResponse) GetData() []*Entity { if x != nil { - return x.Id + return x.Data } - return "" + return nil } -type UpsertPatchAssetRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Asset *UpsertPatchAssetRequest_Asset `protobuf:"bytes,1,opt,name=asset,proto3" json:"asset,omitempty"` - Upstreams []*LineageNode `protobuf:"bytes,2,rep,name=upstreams,proto3" json:"upstreams,omitempty"` - Downstreams []*LineageNode `protobuf:"bytes,3,rep,name=downstreams,proto3" json:"downstreams,omitempty"` - // overwrite_lineage determines whether the asset's lineage should be - // overwritten with the upstreams and downstreams specified in the request. - // Currently, it is only applicable when both upstreams and downstreams are - // empty/not specified. - OverwriteLineage bool `protobuf:"varint,4,opt,name=overwrite_lineage,json=overwriteLineage,proto3" json:"overwrite_lineage,omitempty"` - UpdateOnly bool `protobuf:"varint,5,opt,name=update_only,json=updateOnly,proto3" json:"update_only,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +type GetMyStarredEntityRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } -func (x *UpsertPatchAssetRequest) Reset() { - *x = UpsertPatchAssetRequest{} +func (x *GetMyStarredEntityRequest) Reset() { + *x = GetMyStarredEntityRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *UpsertPatchAssetRequest) String() string { +func (x *GetMyStarredEntityRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpsertPatchAssetRequest) ProtoMessage() {} +func (*GetMyStarredEntityRequest) ProtoMessage() {} -func (x *UpsertPatchAssetRequest) ProtoReflect() protoreflect.Message { +func (x *GetMyStarredEntityRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2216,67 +2140,39 @@ func (x *UpsertPatchAssetRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpsertPatchAssetRequest.ProtoReflect.Descriptor instead. -func (*UpsertPatchAssetRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use GetMyStarredEntityRequest.ProtoReflect.Descriptor instead. +func (*GetMyStarredEntityRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{37} } -func (x *UpsertPatchAssetRequest) GetAsset() *UpsertPatchAssetRequest_Asset { - if x != nil { - return x.Asset - } - return nil -} - -func (x *UpsertPatchAssetRequest) GetUpstreams() []*LineageNode { - if x != nil { - return x.Upstreams - } - return nil -} - -func (x *UpsertPatchAssetRequest) GetDownstreams() []*LineageNode { - if x != nil { - return x.Downstreams - } - return nil -} - -func (x *UpsertPatchAssetRequest) GetOverwriteLineage() bool { - if x != nil { - return x.OverwriteLineage - } - return false -} - -func (x *UpsertPatchAssetRequest) GetUpdateOnly() bool { +func (x *GetMyStarredEntityRequest) GetEntityId() string { if x != nil { - return x.UpdateOnly + return x.EntityId } - return false + return "" } -type UpsertPatchAssetResponse struct { +type GetMyStarredEntityResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Data *Entity `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *UpsertPatchAssetResponse) Reset() { - *x = UpsertPatchAssetResponse{} +func (x *GetMyStarredEntityResponse) Reset() { + *x = GetMyStarredEntityResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *UpsertPatchAssetResponse) String() string { +func (x *GetMyStarredEntityResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpsertPatchAssetResponse) ProtoMessage() {} +func (*GetMyStarredEntityResponse) ProtoMessage() {} -func (x *UpsertPatchAssetResponse) ProtoReflect() protoreflect.Message { +func (x *GetMyStarredEntityResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2288,39 +2184,41 @@ func (x *UpsertPatchAssetResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpsertPatchAssetResponse.ProtoReflect.Descriptor instead. -func (*UpsertPatchAssetResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use GetMyStarredEntityResponse.ProtoReflect.Descriptor instead. +func (*GetMyStarredEntityResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{38} } -func (x *UpsertPatchAssetResponse) GetId() string { +func (x *GetMyStarredEntityResponse) GetData() *Entity { if x != nil { - return x.Id + return x.Data } - return "" + return nil } -type DeleteAssetRequest struct { +type GetEntityStargazersRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Size uint32 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` + Offset uint32 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *DeleteAssetRequest) Reset() { - *x = DeleteAssetRequest{} +func (x *GetEntityStargazersRequest) Reset() { + *x = GetEntityStargazersRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *DeleteAssetRequest) String() string { +func (x *GetEntityStargazersRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeleteAssetRequest) ProtoMessage() {} +func (*GetEntityStargazersRequest) ProtoMessage() {} -func (x *DeleteAssetRequest) ProtoReflect() protoreflect.Message { +func (x *GetEntityStargazersRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2332,38 +2230,53 @@ func (x *DeleteAssetRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DeleteAssetRequest.ProtoReflect.Descriptor instead. -func (*DeleteAssetRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use GetEntityStargazersRequest.ProtoReflect.Descriptor instead. +func (*GetEntityStargazersRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{39} } -func (x *DeleteAssetRequest) GetId() string { +func (x *GetEntityStargazersRequest) GetId() string { if x != nil { return x.Id } return "" } -type DeleteAssetResponse struct { +func (x *GetEntityStargazersRequest) GetSize() uint32 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *GetEntityStargazersRequest) GetOffset() uint32 { + if x != nil { + return x.Offset + } + return 0 +} + +type GetEntityStargazersResponse struct { state protoimpl.MessageState `protogen:"open.v1"` + Data []*User `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *DeleteAssetResponse) Reset() { - *x = DeleteAssetResponse{} +func (x *GetEntityStargazersResponse) Reset() { + *x = GetEntityStargazersResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *DeleteAssetResponse) String() string { +func (x *GetEntityStargazersResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeleteAssetResponse) ProtoMessage() {} +func (*GetEntityStargazersResponse) ProtoMessage() {} -func (x *DeleteAssetResponse) ProtoReflect() protoreflect.Message { +func (x *GetEntityStargazersResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2375,34 +2288,42 @@ func (x *DeleteAssetResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DeleteAssetResponse.ProtoReflect.Descriptor instead. -func (*DeleteAssetResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use GetEntityStargazersResponse.ProtoReflect.Descriptor instead. +func (*GetEntityStargazersResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{40} } -type GetAssetStargazersRequest struct { +func (x *GetEntityStargazersResponse) GetData() []*User { + if x != nil { + return x.Data + } + return nil +} + +type CreateNamespaceRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Size uint32 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` - Offset uint32 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` + Metadata *structpb.Struct `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAssetStargazersRequest) Reset() { - *x = GetAssetStargazersRequest{} +func (x *CreateNamespaceRequest) Reset() { + *x = CreateNamespaceRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAssetStargazersRequest) String() string { +func (x *CreateNamespaceRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAssetStargazersRequest) ProtoMessage() {} +func (*CreateNamespaceRequest) ProtoMessage() {} -func (x *GetAssetStargazersRequest) ProtoReflect() protoreflect.Message { +func (x *CreateNamespaceRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2414,53 +2335,60 @@ func (x *GetAssetStargazersRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAssetStargazersRequest.ProtoReflect.Descriptor instead. -func (*GetAssetStargazersRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use CreateNamespaceRequest.ProtoReflect.Descriptor instead. +func (*CreateNamespaceRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{41} } -func (x *GetAssetStargazersRequest) GetId() string { +func (x *CreateNamespaceRequest) GetId() string { if x != nil { return x.Id } return "" } -func (x *GetAssetStargazersRequest) GetSize() uint32 { +func (x *CreateNamespaceRequest) GetName() string { if x != nil { - return x.Size + return x.Name } - return 0 + return "" +} + +func (x *CreateNamespaceRequest) GetState() string { + if x != nil { + return x.State + } + return "" } -func (x *GetAssetStargazersRequest) GetOffset() uint32 { +func (x *CreateNamespaceRequest) GetMetadata() *structpb.Struct { if x != nil { - return x.Offset + return x.Metadata } - return 0 + return nil } -type GetAssetStargazersResponse struct { +type CreateNamespaceResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Data []*User `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAssetStargazersResponse) Reset() { - *x = GetAssetStargazersResponse{} +func (x *CreateNamespaceResponse) Reset() { + *x = CreateNamespaceResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAssetStargazersResponse) String() string { +func (x *CreateNamespaceResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAssetStargazersResponse) ProtoMessage() {} +func (*CreateNamespaceResponse) ProtoMessage() {} -func (x *GetAssetStargazersResponse) ProtoReflect() protoreflect.Message { +func (x *CreateNamespaceResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2472,41 +2400,39 @@ func (x *GetAssetStargazersResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAssetStargazersResponse.ProtoReflect.Descriptor instead. -func (*GetAssetStargazersResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use CreateNamespaceResponse.ProtoReflect.Descriptor instead. +func (*CreateNamespaceResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{42} } -func (x *GetAssetStargazersResponse) GetData() []*User { +func (x *CreateNamespaceResponse) GetId() string { if x != nil { - return x.Data + return x.Id } - return nil + return "" } -type GetAssetVersionHistoryRequest struct { +type GetNamespaceRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Size uint32 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` - Offset uint32 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAssetVersionHistoryRequest) Reset() { - *x = GetAssetVersionHistoryRequest{} +func (x *GetNamespaceRequest) Reset() { + *x = GetNamespaceRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAssetVersionHistoryRequest) String() string { +func (x *GetNamespaceRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAssetVersionHistoryRequest) ProtoMessage() {} +func (*GetNamespaceRequest) ProtoMessage() {} -func (x *GetAssetVersionHistoryRequest) ProtoReflect() protoreflect.Message { +func (x *GetNamespaceRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2518,53 +2444,39 @@ func (x *GetAssetVersionHistoryRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAssetVersionHistoryRequest.ProtoReflect.Descriptor instead. -func (*GetAssetVersionHistoryRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use GetNamespaceRequest.ProtoReflect.Descriptor instead. +func (*GetNamespaceRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{43} } -func (x *GetAssetVersionHistoryRequest) GetId() string { +func (x *GetNamespaceRequest) GetUrn() string { if x != nil { - return x.Id + return x.Urn } return "" } -func (x *GetAssetVersionHistoryRequest) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *GetAssetVersionHistoryRequest) GetOffset() uint32 { - if x != nil { - return x.Offset - } - return 0 -} - -type GetAssetVersionHistoryResponse struct { +type GetNamespaceResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Data []*Asset `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + Namespace *Namespace `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAssetVersionHistoryResponse) Reset() { - *x = GetAssetVersionHistoryResponse{} +func (x *GetNamespaceResponse) Reset() { + *x = GetNamespaceResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAssetVersionHistoryResponse) String() string { +func (x *GetNamespaceResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAssetVersionHistoryResponse) ProtoMessage() {} +func (*GetNamespaceResponse) ProtoMessage() {} -func (x *GetAssetVersionHistoryResponse) ProtoReflect() protoreflect.Message { +func (x *GetNamespaceResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2576,40 +2488,41 @@ func (x *GetAssetVersionHistoryResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAssetVersionHistoryResponse.ProtoReflect.Descriptor instead. -func (*GetAssetVersionHistoryResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use GetNamespaceResponse.ProtoReflect.Descriptor instead. +func (*GetNamespaceResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{44} } -func (x *GetAssetVersionHistoryResponse) GetData() []*Asset { +func (x *GetNamespaceResponse) GetNamespace() *Namespace { if x != nil { - return x.Data + return x.Namespace } return nil } -type GetAssetByVersionRequest struct { +type UpdateNamespaceRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` + State string `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` + Metadata *structpb.Struct `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAssetByVersionRequest) Reset() { - *x = GetAssetByVersionRequest{} +func (x *UpdateNamespaceRequest) Reset() { + *x = UpdateNamespaceRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAssetByVersionRequest) String() string { +func (x *UpdateNamespaceRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAssetByVersionRequest) ProtoMessage() {} +func (*UpdateNamespaceRequest) ProtoMessage() {} -func (x *GetAssetByVersionRequest) ProtoReflect() protoreflect.Message { +func (x *UpdateNamespaceRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2621,46 +2534,52 @@ func (x *GetAssetByVersionRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAssetByVersionRequest.ProtoReflect.Descriptor instead. -func (*GetAssetByVersionRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use UpdateNamespaceRequest.ProtoReflect.Descriptor instead. +func (*UpdateNamespaceRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{45} } -func (x *GetAssetByVersionRequest) GetId() string { +func (x *UpdateNamespaceRequest) GetUrn() string { if x != nil { - return x.Id + return x.Urn } return "" } -func (x *GetAssetByVersionRequest) GetVersion() string { +func (x *UpdateNamespaceRequest) GetState() string { if x != nil { - return x.Version + return x.State } return "" } -type GetAssetByVersionResponse struct { +func (x *UpdateNamespaceRequest) GetMetadata() *structpb.Struct { + if x != nil { + return x.Metadata + } + return nil +} + +type UpdateNamespaceResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Data *Asset `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *GetAssetByVersionResponse) Reset() { - *x = GetAssetByVersionResponse{} +func (x *UpdateNamespaceResponse) Reset() { + *x = UpdateNamespaceResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *GetAssetByVersionResponse) String() string { +func (x *UpdateNamespaceResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAssetByVersionResponse) ProtoMessage() {} +func (*UpdateNamespaceResponse) ProtoMessage() {} -func (x *GetAssetByVersionResponse) ProtoReflect() protoreflect.Message { +func (x *UpdateNamespaceResponse) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2672,40 +2591,31 @@ func (x *GetAssetByVersionResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAssetByVersionResponse.ProtoReflect.Descriptor instead. -func (*GetAssetByVersionResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use UpdateNamespaceResponse.ProtoReflect.Descriptor instead. +func (*UpdateNamespaceResponse) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{46} } -func (x *GetAssetByVersionResponse) GetData() *Asset { - if x != nil { - return x.Data - } - return nil -} - -type CreateAssetProbeRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - AssetUrn string `protobuf:"bytes,1,opt,name=asset_urn,json=assetUrn,proto3" json:"asset_urn,omitempty"` - Probe *CreateAssetProbeRequest_Probe `protobuf:"bytes,2,opt,name=probe,proto3" json:"probe,omitempty"` +type ListNamespacesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *CreateAssetProbeRequest) Reset() { - *x = CreateAssetProbeRequest{} +func (x *ListNamespacesRequest) Reset() { + *x = ListNamespacesRequest{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *CreateAssetProbeRequest) String() string { +func (x *ListNamespacesRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*CreateAssetProbeRequest) ProtoMessage() {} +func (*ListNamespacesRequest) ProtoMessage() {} -func (x *CreateAssetProbeRequest) ProtoReflect() protoreflect.Message { +func (x *ListNamespacesRequest) ProtoReflect() protoreflect.Message { mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2717,5149 +2627,33 @@ func (x *CreateAssetProbeRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CreateAssetProbeRequest.ProtoReflect.Descriptor instead. -func (*CreateAssetProbeRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use ListNamespacesRequest.ProtoReflect.Descriptor instead. +func (*ListNamespacesRequest) Descriptor() ([]byte, []int) { return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{47} } -func (x *CreateAssetProbeRequest) GetAssetUrn() string { - if x != nil { - return x.AssetUrn - } - return "" -} - -func (x *CreateAssetProbeRequest) GetProbe() *CreateAssetProbeRequest_Probe { - if x != nil { - return x.Probe - } - return nil -} - -type CreateAssetProbeResponse struct { +type ListNamespacesResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Namespaces []*Namespace `protobuf:"bytes,1,rep,name=namespaces,proto3" json:"namespaces,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *CreateAssetProbeResponse) Reset() { - *x = CreateAssetProbeResponse{} +func (x *ListNamespacesResponse) Reset() { + *x = ListNamespacesResponse{} mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *CreateAssetProbeResponse) String() string { +func (x *ListNamespacesResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*CreateAssetProbeResponse) ProtoMessage() {} - -func (x *CreateAssetProbeResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[48] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateAssetProbeResponse.ProtoReflect.Descriptor instead. -func (*CreateAssetProbeResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{48} -} - -func (x *CreateAssetProbeResponse) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -type GetUserStarredAssetsRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - Size uint32 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` - Offset uint32 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetUserStarredAssetsRequest) Reset() { - *x = GetUserStarredAssetsRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[49] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetUserStarredAssetsRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetUserStarredAssetsRequest) ProtoMessage() {} - -func (x *GetUserStarredAssetsRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[49] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetUserStarredAssetsRequest.ProtoReflect.Descriptor instead. -func (*GetUserStarredAssetsRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{49} -} - -func (x *GetUserStarredAssetsRequest) GetUserId() string { - if x != nil { - return x.UserId - } - return "" -} - -func (x *GetUserStarredAssetsRequest) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *GetUserStarredAssetsRequest) GetOffset() uint32 { - if x != nil { - return x.Offset - } - return 0 -} - -type GetUserStarredAssetsResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data []*Asset `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetUserStarredAssetsResponse) Reset() { - *x = GetUserStarredAssetsResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[50] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetUserStarredAssetsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetUserStarredAssetsResponse) ProtoMessage() {} - -func (x *GetUserStarredAssetsResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[50] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetUserStarredAssetsResponse.ProtoReflect.Descriptor instead. -func (*GetUserStarredAssetsResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{50} -} - -func (x *GetUserStarredAssetsResponse) GetData() []*Asset { - if x != nil { - return x.Data - } - return nil -} - -type GetMyStarredAssetsRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Size uint32 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"` - Offset uint32 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetMyStarredAssetsRequest) Reset() { - *x = GetMyStarredAssetsRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[51] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetMyStarredAssetsRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetMyStarredAssetsRequest) ProtoMessage() {} - -func (x *GetMyStarredAssetsRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[51] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetMyStarredAssetsRequest.ProtoReflect.Descriptor instead. -func (*GetMyStarredAssetsRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{51} -} - -func (x *GetMyStarredAssetsRequest) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *GetMyStarredAssetsRequest) GetOffset() uint32 { - if x != nil { - return x.Offset - } - return 0 -} - -type GetMyStarredAssetsResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data []*Asset `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetMyStarredAssetsResponse) Reset() { - *x = GetMyStarredAssetsResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[52] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetMyStarredAssetsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetMyStarredAssetsResponse) ProtoMessage() {} - -func (x *GetMyStarredAssetsResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[52] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetMyStarredAssetsResponse.ProtoReflect.Descriptor instead. -func (*GetMyStarredAssetsResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{52} -} - -func (x *GetMyStarredAssetsResponse) GetData() []*Asset { - if x != nil { - return x.Data - } - return nil -} - -type GetMyStarredAssetRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - AssetId string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetMyStarredAssetRequest) Reset() { - *x = GetMyStarredAssetRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[53] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetMyStarredAssetRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetMyStarredAssetRequest) ProtoMessage() {} - -func (x *GetMyStarredAssetRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[53] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetMyStarredAssetRequest.ProtoReflect.Descriptor instead. -func (*GetMyStarredAssetRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{53} -} - -func (x *GetMyStarredAssetRequest) GetAssetId() string { - if x != nil { - return x.AssetId - } - return "" -} - -type GetMyStarredAssetResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data *Asset `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetMyStarredAssetResponse) Reset() { - *x = GetMyStarredAssetResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[54] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetMyStarredAssetResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetMyStarredAssetResponse) ProtoMessage() {} - -func (x *GetMyStarredAssetResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[54] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetMyStarredAssetResponse.ProtoReflect.Descriptor instead. -func (*GetMyStarredAssetResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{54} -} - -func (x *GetMyStarredAssetResponse) GetData() *Asset { - if x != nil { - return x.Data - } - return nil -} - -type StarAssetRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - AssetId string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *StarAssetRequest) Reset() { - *x = StarAssetRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[55] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *StarAssetRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*StarAssetRequest) ProtoMessage() {} - -func (x *StarAssetRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[55] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use StarAssetRequest.ProtoReflect.Descriptor instead. -func (*StarAssetRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{55} -} - -func (x *StarAssetRequest) GetAssetId() string { - if x != nil { - return x.AssetId - } - return "" -} - -type StarAssetResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *StarAssetResponse) Reset() { - *x = StarAssetResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[56] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *StarAssetResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*StarAssetResponse) ProtoMessage() {} - -func (x *StarAssetResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[56] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use StarAssetResponse.ProtoReflect.Descriptor instead. -func (*StarAssetResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{56} -} - -func (x *StarAssetResponse) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -type UnstarAssetRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - AssetId string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UnstarAssetRequest) Reset() { - *x = UnstarAssetRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[57] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UnstarAssetRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UnstarAssetRequest) ProtoMessage() {} - -func (x *UnstarAssetRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[57] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UnstarAssetRequest.ProtoReflect.Descriptor instead. -func (*UnstarAssetRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{57} -} - -func (x *UnstarAssetRequest) GetAssetId() string { - if x != nil { - return x.AssetId - } - return "" -} - -type UnstarAssetResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UnstarAssetResponse) Reset() { - *x = UnstarAssetResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[58] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UnstarAssetResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UnstarAssetResponse) ProtoMessage() {} - -func (x *UnstarAssetResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[58] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UnstarAssetResponse.ProtoReflect.Descriptor instead. -func (*UnstarAssetResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{58} -} - -type GetMyDiscussionsRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Filter string `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` - Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` - State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` - Asset string `protobuf:"bytes,4,opt,name=asset,proto3" json:"asset,omitempty"` - Labels string `protobuf:"bytes,5,opt,name=labels,proto3" json:"labels,omitempty"` - Sort string `protobuf:"bytes,6,opt,name=sort,proto3" json:"sort,omitempty"` - Direction string `protobuf:"bytes,7,opt,name=direction,proto3" json:"direction,omitempty"` - Size uint32 `protobuf:"varint,8,opt,name=size,proto3" json:"size,omitempty"` - Offset uint32 `protobuf:"varint,9,opt,name=offset,proto3" json:"offset,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetMyDiscussionsRequest) Reset() { - *x = GetMyDiscussionsRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[59] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetMyDiscussionsRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetMyDiscussionsRequest) ProtoMessage() {} - -func (x *GetMyDiscussionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[59] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetMyDiscussionsRequest.ProtoReflect.Descriptor instead. -func (*GetMyDiscussionsRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{59} -} - -func (x *GetMyDiscussionsRequest) GetFilter() string { - if x != nil { - return x.Filter - } - return "" -} - -func (x *GetMyDiscussionsRequest) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *GetMyDiscussionsRequest) GetState() string { - if x != nil { - return x.State - } - return "" -} - -func (x *GetMyDiscussionsRequest) GetAsset() string { - if x != nil { - return x.Asset - } - return "" -} - -func (x *GetMyDiscussionsRequest) GetLabels() string { - if x != nil { - return x.Labels - } - return "" -} - -func (x *GetMyDiscussionsRequest) GetSort() string { - if x != nil { - return x.Sort - } - return "" -} - -func (x *GetMyDiscussionsRequest) GetDirection() string { - if x != nil { - return x.Direction - } - return "" -} - -func (x *GetMyDiscussionsRequest) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *GetMyDiscussionsRequest) GetOffset() uint32 { - if x != nil { - return x.Offset - } - return 0 -} - -type GetMyDiscussionsResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data []*Discussion `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetMyDiscussionsResponse) Reset() { - *x = GetMyDiscussionsResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[60] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetMyDiscussionsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetMyDiscussionsResponse) ProtoMessage() {} - -func (x *GetMyDiscussionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[60] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetMyDiscussionsResponse.ProtoReflect.Descriptor instead. -func (*GetMyDiscussionsResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{60} -} - -func (x *GetMyDiscussionsResponse) GetData() []*Discussion { - if x != nil { - return x.Data - } - return nil -} - -type CreateTagAssetRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - AssetId string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` // required - TemplateUrn string `protobuf:"bytes,2,opt,name=template_urn,json=templateUrn,proto3" json:"template_urn,omitempty"` // required - TagValues []*TagValue `protobuf:"bytes,3,rep,name=tag_values,json=tagValues,proto3" json:"tag_values,omitempty"` // required - TemplateDisplayName string `protobuf:"bytes,4,opt,name=template_display_name,json=templateDisplayName,proto3" json:"template_display_name,omitempty"` - TemplateDescription string `protobuf:"bytes,5,opt,name=template_description,json=templateDescription,proto3" json:"template_description,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *CreateTagAssetRequest) Reset() { - *x = CreateTagAssetRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[61] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *CreateTagAssetRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateTagAssetRequest) ProtoMessage() {} - -func (x *CreateTagAssetRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[61] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateTagAssetRequest.ProtoReflect.Descriptor instead. -func (*CreateTagAssetRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{61} -} - -func (x *CreateTagAssetRequest) GetAssetId() string { - if x != nil { - return x.AssetId - } - return "" -} - -func (x *CreateTagAssetRequest) GetTemplateUrn() string { - if x != nil { - return x.TemplateUrn - } - return "" -} - -func (x *CreateTagAssetRequest) GetTagValues() []*TagValue { - if x != nil { - return x.TagValues - } - return nil -} - -func (x *CreateTagAssetRequest) GetTemplateDisplayName() string { - if x != nil { - return x.TemplateDisplayName - } - return "" -} - -func (x *CreateTagAssetRequest) GetTemplateDescription() string { - if x != nil { - return x.TemplateDescription - } - return "" -} - -type CreateTagAssetResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data *Tag `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *CreateTagAssetResponse) Reset() { - *x = CreateTagAssetResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[62] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *CreateTagAssetResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateTagAssetResponse) ProtoMessage() {} - -func (x *CreateTagAssetResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[62] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateTagAssetResponse.ProtoReflect.Descriptor instead. -func (*CreateTagAssetResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{62} -} - -func (x *CreateTagAssetResponse) GetData() *Tag { - if x != nil { - return x.Data - } - return nil -} - -type GetTagByAssetAndTemplateRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - AssetId string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` - TemplateUrn string `protobuf:"bytes,3,opt,name=template_urn,json=templateUrn,proto3" json:"template_urn,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetTagByAssetAndTemplateRequest) Reset() { - *x = GetTagByAssetAndTemplateRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[63] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetTagByAssetAndTemplateRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetTagByAssetAndTemplateRequest) ProtoMessage() {} - -func (x *GetTagByAssetAndTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[63] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetTagByAssetAndTemplateRequest.ProtoReflect.Descriptor instead. -func (*GetTagByAssetAndTemplateRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{63} -} - -func (x *GetTagByAssetAndTemplateRequest) GetAssetId() string { - if x != nil { - return x.AssetId - } - return "" -} - -func (x *GetTagByAssetAndTemplateRequest) GetTemplateUrn() string { - if x != nil { - return x.TemplateUrn - } - return "" -} - -type GetTagByAssetAndTemplateResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data *Tag `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetTagByAssetAndTemplateResponse) Reset() { - *x = GetTagByAssetAndTemplateResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[64] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetTagByAssetAndTemplateResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetTagByAssetAndTemplateResponse) ProtoMessage() {} - -func (x *GetTagByAssetAndTemplateResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[64] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetTagByAssetAndTemplateResponse.ProtoReflect.Descriptor instead. -func (*GetTagByAssetAndTemplateResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{64} -} - -func (x *GetTagByAssetAndTemplateResponse) GetData() *Tag { - if x != nil { - return x.Data - } - return nil -} - -type UpdateTagAssetRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - AssetId string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` // required - TemplateUrn string `protobuf:"bytes,2,opt,name=template_urn,json=templateUrn,proto3" json:"template_urn,omitempty"` - TagValues []*TagValue `protobuf:"bytes,3,rep,name=tag_values,json=tagValues,proto3" json:"tag_values,omitempty"` // required - TemplateDisplayName string `protobuf:"bytes,4,opt,name=template_display_name,json=templateDisplayName,proto3" json:"template_display_name,omitempty"` - TemplateDescription string `protobuf:"bytes,5,opt,name=template_description,json=templateDescription,proto3" json:"template_description,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpdateTagAssetRequest) Reset() { - *x = UpdateTagAssetRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[65] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpdateTagAssetRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdateTagAssetRequest) ProtoMessage() {} - -func (x *UpdateTagAssetRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[65] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpdateTagAssetRequest.ProtoReflect.Descriptor instead. -func (*UpdateTagAssetRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{65} -} - -func (x *UpdateTagAssetRequest) GetAssetId() string { - if x != nil { - return x.AssetId - } - return "" -} - -func (x *UpdateTagAssetRequest) GetTemplateUrn() string { - if x != nil { - return x.TemplateUrn - } - return "" -} - -func (x *UpdateTagAssetRequest) GetTagValues() []*TagValue { - if x != nil { - return x.TagValues - } - return nil -} - -func (x *UpdateTagAssetRequest) GetTemplateDisplayName() string { - if x != nil { - return x.TemplateDisplayName - } - return "" -} - -func (x *UpdateTagAssetRequest) GetTemplateDescription() string { - if x != nil { - return x.TemplateDescription - } - return "" -} - -type UpdateTagAssetResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data *Tag `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpdateTagAssetResponse) Reset() { - *x = UpdateTagAssetResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[66] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpdateTagAssetResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdateTagAssetResponse) ProtoMessage() {} - -func (x *UpdateTagAssetResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[66] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpdateTagAssetResponse.ProtoReflect.Descriptor instead. -func (*UpdateTagAssetResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{66} -} - -func (x *UpdateTagAssetResponse) GetData() *Tag { - if x != nil { - return x.Data - } - return nil -} - -type DeleteTagAssetRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - AssetId string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` - TemplateUrn string `protobuf:"bytes,2,opt,name=template_urn,json=templateUrn,proto3" json:"template_urn,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DeleteTagAssetRequest) Reset() { - *x = DeleteTagAssetRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[67] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DeleteTagAssetRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteTagAssetRequest) ProtoMessage() {} - -func (x *DeleteTagAssetRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[67] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteTagAssetRequest.ProtoReflect.Descriptor instead. -func (*DeleteTagAssetRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{67} -} - -func (x *DeleteTagAssetRequest) GetAssetId() string { - if x != nil { - return x.AssetId - } - return "" -} - -func (x *DeleteTagAssetRequest) GetTemplateUrn() string { - if x != nil { - return x.TemplateUrn - } - return "" -} - -type DeleteTagAssetResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DeleteTagAssetResponse) Reset() { - *x = DeleteTagAssetResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[68] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DeleteTagAssetResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteTagAssetResponse) ProtoMessage() {} - -func (x *DeleteTagAssetResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[68] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteTagAssetResponse.ProtoReflect.Descriptor instead. -func (*DeleteTagAssetResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{68} -} - -type GetAllTagsByAssetRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - AssetId string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetAllTagsByAssetRequest) Reset() { - *x = GetAllTagsByAssetRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[69] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetAllTagsByAssetRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetAllTagsByAssetRequest) ProtoMessage() {} - -func (x *GetAllTagsByAssetRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[69] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetAllTagsByAssetRequest.ProtoReflect.Descriptor instead. -func (*GetAllTagsByAssetRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{69} -} - -func (x *GetAllTagsByAssetRequest) GetAssetId() string { - if x != nil { - return x.AssetId - } - return "" -} - -type GetAllTagsByAssetResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data []*Tag `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetAllTagsByAssetResponse) Reset() { - *x = GetAllTagsByAssetResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[70] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetAllTagsByAssetResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetAllTagsByAssetResponse) ProtoMessage() {} - -func (x *GetAllTagsByAssetResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[70] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetAllTagsByAssetResponse.ProtoReflect.Descriptor instead. -func (*GetAllTagsByAssetResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{70} -} - -func (x *GetAllTagsByAssetResponse) GetData() []*Tag { - if x != nil { - return x.Data - } - return nil -} - -type GetAllTagTemplatesRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetAllTagTemplatesRequest) Reset() { - *x = GetAllTagTemplatesRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[71] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetAllTagTemplatesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetAllTagTemplatesRequest) ProtoMessage() {} - -func (x *GetAllTagTemplatesRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[71] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetAllTagTemplatesRequest.ProtoReflect.Descriptor instead. -func (*GetAllTagTemplatesRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{71} -} - -func (x *GetAllTagTemplatesRequest) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -type GetAllTagTemplatesResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data []*TagTemplate `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetAllTagTemplatesResponse) Reset() { - *x = GetAllTagTemplatesResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[72] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetAllTagTemplatesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetAllTagTemplatesResponse) ProtoMessage() {} - -func (x *GetAllTagTemplatesResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[72] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetAllTagTemplatesResponse.ProtoReflect.Descriptor instead. -func (*GetAllTagTemplatesResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{72} -} - -func (x *GetAllTagTemplatesResponse) GetData() []*TagTemplate { - if x != nil { - return x.Data - } - return nil -} - -type CreateTagTemplateRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` // required - DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // required - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` // required - Fields []*TagTemplateField `protobuf:"bytes,4,rep,name=fields,proto3" json:"fields,omitempty"` // required - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *CreateTagTemplateRequest) Reset() { - *x = CreateTagTemplateRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[73] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *CreateTagTemplateRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateTagTemplateRequest) ProtoMessage() {} - -func (x *CreateTagTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[73] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateTagTemplateRequest.ProtoReflect.Descriptor instead. -func (*CreateTagTemplateRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{73} -} - -func (x *CreateTagTemplateRequest) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *CreateTagTemplateRequest) GetDisplayName() string { - if x != nil { - return x.DisplayName - } - return "" -} - -func (x *CreateTagTemplateRequest) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *CreateTagTemplateRequest) GetFields() []*TagTemplateField { - if x != nil { - return x.Fields - } - return nil -} - -type CreateTagTemplateResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data *TagTemplate `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *CreateTagTemplateResponse) Reset() { - *x = CreateTagTemplateResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[74] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *CreateTagTemplateResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateTagTemplateResponse) ProtoMessage() {} - -func (x *CreateTagTemplateResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[74] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateTagTemplateResponse.ProtoReflect.Descriptor instead. -func (*CreateTagTemplateResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{74} -} - -func (x *CreateTagTemplateResponse) GetData() *TagTemplate { - if x != nil { - return x.Data - } - return nil -} - -type GetTagTemplateRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - TemplateUrn string `protobuf:"bytes,1,opt,name=template_urn,json=templateUrn,proto3" json:"template_urn,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetTagTemplateRequest) Reset() { - *x = GetTagTemplateRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[75] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetTagTemplateRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetTagTemplateRequest) ProtoMessage() {} - -func (x *GetTagTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[75] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetTagTemplateRequest.ProtoReflect.Descriptor instead. -func (*GetTagTemplateRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{75} -} - -func (x *GetTagTemplateRequest) GetTemplateUrn() string { - if x != nil { - return x.TemplateUrn - } - return "" -} - -type GetTagTemplateResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data *TagTemplate `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetTagTemplateResponse) Reset() { - *x = GetTagTemplateResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[76] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetTagTemplateResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetTagTemplateResponse) ProtoMessage() {} - -func (x *GetTagTemplateResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[76] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetTagTemplateResponse.ProtoReflect.Descriptor instead. -func (*GetTagTemplateResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{76} -} - -func (x *GetTagTemplateResponse) GetData() *TagTemplate { - if x != nil { - return x.Data - } - return nil -} - -type UpdateTagTemplateRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - TemplateUrn string `protobuf:"bytes,1,opt,name=template_urn,json=templateUrn,proto3" json:"template_urn,omitempty"` - DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // required - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` // required - Fields []*TagTemplateField `protobuf:"bytes,4,rep,name=fields,proto3" json:"fields,omitempty"` // required - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpdateTagTemplateRequest) Reset() { - *x = UpdateTagTemplateRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[77] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpdateTagTemplateRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdateTagTemplateRequest) ProtoMessage() {} - -func (x *UpdateTagTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[77] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpdateTagTemplateRequest.ProtoReflect.Descriptor instead. -func (*UpdateTagTemplateRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{77} -} - -func (x *UpdateTagTemplateRequest) GetTemplateUrn() string { - if x != nil { - return x.TemplateUrn - } - return "" -} - -func (x *UpdateTagTemplateRequest) GetDisplayName() string { - if x != nil { - return x.DisplayName - } - return "" -} - -func (x *UpdateTagTemplateRequest) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *UpdateTagTemplateRequest) GetFields() []*TagTemplateField { - if x != nil { - return x.Fields - } - return nil -} - -type UpdateTagTemplateResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data *TagTemplate `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpdateTagTemplateResponse) Reset() { - *x = UpdateTagTemplateResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[78] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpdateTagTemplateResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdateTagTemplateResponse) ProtoMessage() {} - -func (x *UpdateTagTemplateResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[78] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpdateTagTemplateResponse.ProtoReflect.Descriptor instead. -func (*UpdateTagTemplateResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{78} -} - -func (x *UpdateTagTemplateResponse) GetData() *TagTemplate { - if x != nil { - return x.Data - } - return nil -} - -type DeleteTagTemplateRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - TemplateUrn string `protobuf:"bytes,1,opt,name=template_urn,json=templateUrn,proto3" json:"template_urn,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DeleteTagTemplateRequest) Reset() { - *x = DeleteTagTemplateRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[79] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DeleteTagTemplateRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteTagTemplateRequest) ProtoMessage() {} - -func (x *DeleteTagTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[79] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteTagTemplateRequest.ProtoReflect.Descriptor instead. -func (*DeleteTagTemplateRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{79} -} - -func (x *DeleteTagTemplateRequest) GetTemplateUrn() string { - if x != nil { - return x.TemplateUrn - } - return "" -} - -type DeleteTagTemplateResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DeleteTagTemplateResponse) Reset() { - *x = DeleteTagTemplateResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[80] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DeleteTagTemplateResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteTagTemplateResponse) ProtoMessage() {} - -func (x *DeleteTagTemplateResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[80] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteTagTemplateResponse.ProtoReflect.Descriptor instead. -func (*DeleteTagTemplateResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{80} -} - -type CreateNamespaceRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` - Metadata *structpb.Struct `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *CreateNamespaceRequest) Reset() { - *x = CreateNamespaceRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[81] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *CreateNamespaceRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateNamespaceRequest) ProtoMessage() {} - -func (x *CreateNamespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[81] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateNamespaceRequest.ProtoReflect.Descriptor instead. -func (*CreateNamespaceRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{81} -} - -func (x *CreateNamespaceRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *CreateNamespaceRequest) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *CreateNamespaceRequest) GetState() string { - if x != nil { - return x.State - } - return "" -} - -func (x *CreateNamespaceRequest) GetMetadata() *structpb.Struct { - if x != nil { - return x.Metadata - } - return nil -} - -type CreateNamespaceResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *CreateNamespaceResponse) Reset() { - *x = CreateNamespaceResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[82] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *CreateNamespaceResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateNamespaceResponse) ProtoMessage() {} - -func (x *CreateNamespaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[82] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateNamespaceResponse.ProtoReflect.Descriptor instead. -func (*CreateNamespaceResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{82} -} - -func (x *CreateNamespaceResponse) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -type GetNamespaceRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - // set either id or name - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetNamespaceRequest) Reset() { - *x = GetNamespaceRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[83] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetNamespaceRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetNamespaceRequest) ProtoMessage() {} - -func (x *GetNamespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[83] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetNamespaceRequest.ProtoReflect.Descriptor instead. -func (*GetNamespaceRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{83} -} - -func (x *GetNamespaceRequest) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -type GetNamespaceResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Namespace *Namespace `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetNamespaceResponse) Reset() { - *x = GetNamespaceResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[84] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetNamespaceResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetNamespaceResponse) ProtoMessage() {} - -func (x *GetNamespaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[84] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetNamespaceResponse.ProtoReflect.Descriptor instead. -func (*GetNamespaceResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{84} -} - -func (x *GetNamespaceResponse) GetNamespace() *Namespace { - if x != nil { - return x.Namespace - } - return nil -} - -type UpdateNamespaceRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - // set either id or name - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - State string `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` - Metadata *structpb.Struct `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpdateNamespaceRequest) Reset() { - *x = UpdateNamespaceRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[85] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpdateNamespaceRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdateNamespaceRequest) ProtoMessage() {} - -func (x *UpdateNamespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[85] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpdateNamespaceRequest.ProtoReflect.Descriptor instead. -func (*UpdateNamespaceRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{85} -} - -func (x *UpdateNamespaceRequest) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *UpdateNamespaceRequest) GetState() string { - if x != nil { - return x.State - } - return "" -} - -func (x *UpdateNamespaceRequest) GetMetadata() *structpb.Struct { - if x != nil { - return x.Metadata - } - return nil -} - -type UpdateNamespaceResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpdateNamespaceResponse) Reset() { - *x = UpdateNamespaceResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[86] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpdateNamespaceResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdateNamespaceResponse) ProtoMessage() {} - -func (x *UpdateNamespaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[86] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpdateNamespaceResponse.ProtoReflect.Descriptor instead. -func (*UpdateNamespaceResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{86} -} - -type ListNamespacesRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ListNamespacesRequest) Reset() { - *x = ListNamespacesRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[87] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ListNamespacesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListNamespacesRequest) ProtoMessage() {} - -func (x *ListNamespacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[87] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListNamespacesRequest.ProtoReflect.Descriptor instead. -func (*ListNamespacesRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{87} -} - -type ListNamespacesResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Namespaces []*Namespace `protobuf:"bytes,1,rep,name=namespaces,proto3" json:"namespaces,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ListNamespacesResponse) Reset() { - *x = ListNamespacesResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[88] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ListNamespacesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListNamespacesResponse) ProtoMessage() {} - -func (x *ListNamespacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[88] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListNamespacesResponse.ProtoReflect.Descriptor instead. -func (*ListNamespacesResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{88} -} - -func (x *ListNamespacesResponse) GetNamespaces() []*Namespace { - if x != nil { - return x.Namespaces - } - return nil -} - -type User struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Uuid string `protobuf:"bytes,2,opt,name=uuid,proto3" json:"uuid,omitempty"` - Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` - Provider string `protobuf:"bytes,4,opt,name=provider,proto3" json:"provider,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *User) Reset() { - *x = User{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[89] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *User) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*User) ProtoMessage() {} - -func (x *User) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[89] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use User.ProtoReflect.Descriptor instead. -func (*User) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{89} -} - -func (x *User) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *User) GetUuid() string { - if x != nil { - return x.Uuid - } - return "" -} - -func (x *User) GetEmail() string { - if x != nil { - return x.Email - } - return "" -} - -func (x *User) GetProvider() string { - if x != nil { - return x.Provider - } - return "" -} - -func (x *User) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -func (x *User) GetUpdatedAt() *timestamppb.Timestamp { - if x != nil { - return x.UpdatedAt - } - return nil -} - -type Change struct { - state protoimpl.MessageState `protogen:"open.v1"` - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` - Path []string `protobuf:"bytes,2,rep,name=path,proto3" json:"path,omitempty"` - From *structpb.Value `protobuf:"bytes,3,opt,name=from,proto3" json:"from,omitempty"` - To *structpb.Value `protobuf:"bytes,4,opt,name=to,proto3" json:"to,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *Change) Reset() { - *x = Change{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[90] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *Change) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Change) ProtoMessage() {} - -func (x *Change) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[90] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Change.ProtoReflect.Descriptor instead. -func (*Change) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{90} -} - -func (x *Change) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *Change) GetPath() []string { - if x != nil { - return x.Path - } - return nil -} - -func (x *Change) GetFrom() *structpb.Value { - if x != nil { - return x.From - } - return nil -} - -func (x *Change) GetTo() *structpb.Value { - if x != nil { - return x.To - } - return nil -} - -type Asset struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Urn string `protobuf:"bytes,2,opt,name=urn,proto3" json:"urn,omitempty"` - Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` - Service string `protobuf:"bytes,4,opt,name=service,proto3" json:"service,omitempty"` - Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"` - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - Data *structpb.Struct `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"` - Labels map[string]string `protobuf:"bytes,8,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Owners []*User `protobuf:"bytes,9,rep,name=owners,proto3" json:"owners,omitempty"` - Version string `protobuf:"bytes,10,opt,name=version,proto3" json:"version,omitempty"` - UpdatedBy *User `protobuf:"bytes,11,opt,name=updated_by,json=updatedBy,proto3" json:"updated_by,omitempty"` - Changelog []*Change `protobuf:"bytes,12,rep,name=changelog,proto3" json:"changelog,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,14,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - Url string `protobuf:"bytes,15,opt,name=url,proto3" json:"url,omitempty"` - Probes []*Probe `protobuf:"bytes,16,rep,name=probes,proto3" json:"probes,omitempty"` - IsDeleted bool `protobuf:"varint,17,opt,name=is_deleted,json=isDeleted,proto3" json:"is_deleted,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *Asset) Reset() { - *x = Asset{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[91] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *Asset) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Asset) ProtoMessage() {} - -func (x *Asset) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[91] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Asset.ProtoReflect.Descriptor instead. -func (*Asset) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{91} -} - -func (x *Asset) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *Asset) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *Asset) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *Asset) GetService() string { - if x != nil { - return x.Service - } - return "" -} - -func (x *Asset) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *Asset) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *Asset) GetData() *structpb.Struct { - if x != nil { - return x.Data - } - return nil -} - -func (x *Asset) GetLabels() map[string]string { - if x != nil { - return x.Labels - } - return nil -} - -func (x *Asset) GetOwners() []*User { - if x != nil { - return x.Owners - } - return nil -} - -func (x *Asset) GetVersion() string { - if x != nil { - return x.Version - } - return "" -} - -func (x *Asset) GetUpdatedBy() *User { - if x != nil { - return x.UpdatedBy - } - return nil -} - -func (x *Asset) GetChangelog() []*Change { - if x != nil { - return x.Changelog - } - return nil -} - -func (x *Asset) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -func (x *Asset) GetUpdatedAt() *timestamppb.Timestamp { - if x != nil { - return x.UpdatedAt - } - return nil -} - -func (x *Asset) GetUrl() string { - if x != nil { - return x.Url - } - return "" -} - -func (x *Asset) GetProbes() []*Probe { - if x != nil { - return x.Probes - } - return nil -} - -func (x *Asset) GetIsDeleted() bool { - if x != nil { - return x.IsDeleted - } - return false -} - -type Probe struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - AssetUrn string `protobuf:"bytes,2,opt,name=asset_urn,json=assetUrn,proto3" json:"asset_urn,omitempty"` - Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` - StatusReason string `protobuf:"bytes,4,opt,name=status_reason,json=statusReason,proto3" json:"status_reason,omitempty"` - Metadata *structpb.Struct `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"` - Timestamp *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *Probe) Reset() { - *x = Probe{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[92] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *Probe) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Probe) ProtoMessage() {} - -func (x *Probe) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[92] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Probe.ProtoReflect.Descriptor instead. -func (*Probe) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{92} -} - -func (x *Probe) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *Probe) GetAssetUrn() string { - if x != nil { - return x.AssetUrn - } - return "" -} - -func (x *Probe) GetStatus() string { - if x != nil { - return x.Status - } - return "" -} - -func (x *Probe) GetStatusReason() string { - if x != nil { - return x.StatusReason - } - return "" -} - -func (x *Probe) GetMetadata() *structpb.Struct { - if x != nil { - return x.Metadata - } - return nil -} - -func (x *Probe) GetTimestamp() *timestamppb.Timestamp { - if x != nil { - return x.Timestamp - } - return nil -} - -func (x *Probe) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -type Discussion struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` - Body string `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` - Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` - State string `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"` - Labels []string `protobuf:"bytes,6,rep,name=labels,proto3" json:"labels,omitempty"` - Assets []string `protobuf:"bytes,7,rep,name=assets,proto3" json:"assets,omitempty"` - Assignees []string `protobuf:"bytes,8,rep,name=assignees,proto3" json:"assignees,omitempty"` - Owner *User `protobuf:"bytes,9,opt,name=owner,proto3" json:"owner,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *Discussion) Reset() { - *x = Discussion{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[93] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *Discussion) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Discussion) ProtoMessage() {} - -func (x *Discussion) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[93] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Discussion.ProtoReflect.Descriptor instead. -func (*Discussion) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{93} -} - -func (x *Discussion) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *Discussion) GetTitle() string { - if x != nil { - return x.Title - } - return "" -} - -func (x *Discussion) GetBody() string { - if x != nil { - return x.Body - } - return "" -} - -func (x *Discussion) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *Discussion) GetState() string { - if x != nil { - return x.State - } - return "" -} - -func (x *Discussion) GetLabels() []string { - if x != nil { - return x.Labels - } - return nil -} - -func (x *Discussion) GetAssets() []string { - if x != nil { - return x.Assets - } - return nil -} - -func (x *Discussion) GetAssignees() []string { - if x != nil { - return x.Assignees - } - return nil -} - -func (x *Discussion) GetOwner() *User { - if x != nil { - return x.Owner - } - return nil -} - -func (x *Discussion) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -func (x *Discussion) GetUpdatedAt() *timestamppb.Timestamp { - if x != nil { - return x.UpdatedAt - } - return nil -} - -type Comment struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - DiscussionId string `protobuf:"bytes,2,opt,name=discussion_id,json=discussionId,proto3" json:"discussion_id,omitempty"` - Body string `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` - Owner *User `protobuf:"bytes,4,opt,name=owner,proto3" json:"owner,omitempty"` - UpdatedBy *User `protobuf:"bytes,5,opt,name=updated_by,json=updatedBy,proto3" json:"updated_by,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *Comment) Reset() { - *x = Comment{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[94] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *Comment) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Comment) ProtoMessage() {} - -func (x *Comment) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[94] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Comment.ProtoReflect.Descriptor instead. -func (*Comment) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{94} -} - -func (x *Comment) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *Comment) GetDiscussionId() string { - if x != nil { - return x.DiscussionId - } - return "" -} - -func (x *Comment) GetBody() string { - if x != nil { - return x.Body - } - return "" -} - -func (x *Comment) GetOwner() *User { - if x != nil { - return x.Owner - } - return nil -} - -func (x *Comment) GetUpdatedBy() *User { - if x != nil { - return x.UpdatedBy - } - return nil -} - -func (x *Comment) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -func (x *Comment) GetUpdatedAt() *timestamppb.Timestamp { - if x != nil { - return x.UpdatedAt - } - return nil -} - -type LineageEdge struct { - state protoimpl.MessageState `protogen:"open.v1"` - Source string `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"` - Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"` - Prop *structpb.Struct `protobuf:"bytes,3,opt,name=prop,proto3" json:"prop,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *LineageEdge) Reset() { - *x = LineageEdge{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[95] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *LineageEdge) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*LineageEdge) ProtoMessage() {} - -func (x *LineageEdge) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[95] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use LineageEdge.ProtoReflect.Descriptor instead. -func (*LineageEdge) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{95} -} - -func (x *LineageEdge) GetSource() string { - if x != nil { - return x.Source - } - return "" -} - -func (x *LineageEdge) GetTarget() string { - if x != nil { - return x.Target - } - return "" -} - -func (x *LineageEdge) GetProp() *structpb.Struct { - if x != nil { - return x.Prop - } - return nil -} - -type LineageNode struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - // Deprecated: Marked as deprecated in raystack/compass/v1beta1/service.proto. - Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` - // Deprecated: Marked as deprecated in raystack/compass/v1beta1/service.proto. - Service string `protobuf:"bytes,3,opt,name=service,proto3" json:"service,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *LineageNode) Reset() { - *x = LineageNode{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[96] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *LineageNode) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*LineageNode) ProtoMessage() {} - -func (x *LineageNode) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[96] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use LineageNode.ProtoReflect.Descriptor instead. -func (*LineageNode) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{96} -} - -func (x *LineageNode) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -// Deprecated: Marked as deprecated in raystack/compass/v1beta1/service.proto. -func (x *LineageNode) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -// Deprecated: Marked as deprecated in raystack/compass/v1beta1/service.proto. -func (x *LineageNode) GetService() string { - if x != nil { - return x.Service - } - return "" -} - -type Tag struct { - state protoimpl.MessageState `protogen:"open.v1"` - AssetId string `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` - TemplateUrn string `protobuf:"bytes,2,opt,name=template_urn,json=templateUrn,proto3" json:"template_urn,omitempty"` - TagValues []*TagValue `protobuf:"bytes,3,rep,name=tag_values,json=tagValues,proto3" json:"tag_values,omitempty"` - TemplateDisplayName string `protobuf:"bytes,4,opt,name=template_display_name,json=templateDisplayName,proto3" json:"template_display_name,omitempty"` - TemplateDescription string `protobuf:"bytes,5,opt,name=template_description,json=templateDescription,proto3" json:"template_description,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *Tag) Reset() { - *x = Tag{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[97] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *Tag) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Tag) ProtoMessage() {} - -func (x *Tag) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[97] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Tag.ProtoReflect.Descriptor instead. -func (*Tag) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{97} -} - -func (x *Tag) GetAssetId() string { - if x != nil { - return x.AssetId - } - return "" -} - -func (x *Tag) GetTemplateUrn() string { - if x != nil { - return x.TemplateUrn - } - return "" -} - -func (x *Tag) GetTagValues() []*TagValue { - if x != nil { - return x.TagValues - } - return nil -} - -func (x *Tag) GetTemplateDisplayName() string { - if x != nil { - return x.TemplateDisplayName - } - return "" -} - -func (x *Tag) GetTemplateDescription() string { - if x != nil { - return x.TemplateDescription - } - return "" -} - -type TagValue struct { - state protoimpl.MessageState `protogen:"open.v1"` - FieldId uint32 `protobuf:"varint,1,opt,name=field_id,json=fieldId,proto3" json:"field_id,omitempty"` - FieldValue *structpb.Value `protobuf:"bytes,2,opt,name=field_value,json=fieldValue,proto3" json:"field_value,omitempty"` - FieldUrn string `protobuf:"bytes,3,opt,name=field_urn,json=fieldUrn,proto3" json:"field_urn,omitempty"` - FieldDisplayName string `protobuf:"bytes,4,opt,name=field_display_name,json=fieldDisplayName,proto3" json:"field_display_name,omitempty"` - FieldDescription string `protobuf:"bytes,5,opt,name=field_description,json=fieldDescription,proto3" json:"field_description,omitempty"` - FieldDataType string `protobuf:"bytes,6,opt,name=field_data_type,json=fieldDataType,proto3" json:"field_data_type,omitempty"` - FieldOptions []string `protobuf:"bytes,7,rep,name=field_options,json=fieldOptions,proto3" json:"field_options,omitempty"` - FieldRequired bool `protobuf:"varint,8,opt,name=field_required,json=fieldRequired,proto3" json:"field_required,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *TagValue) Reset() { - *x = TagValue{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[98] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *TagValue) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TagValue) ProtoMessage() {} - -func (x *TagValue) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[98] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TagValue.ProtoReflect.Descriptor instead. -func (*TagValue) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{98} -} - -func (x *TagValue) GetFieldId() uint32 { - if x != nil { - return x.FieldId - } - return 0 -} - -func (x *TagValue) GetFieldValue() *structpb.Value { - if x != nil { - return x.FieldValue - } - return nil -} - -func (x *TagValue) GetFieldUrn() string { - if x != nil { - return x.FieldUrn - } - return "" -} - -func (x *TagValue) GetFieldDisplayName() string { - if x != nil { - return x.FieldDisplayName - } - return "" -} - -func (x *TagValue) GetFieldDescription() string { - if x != nil { - return x.FieldDescription - } - return "" -} - -func (x *TagValue) GetFieldDataType() string { - if x != nil { - return x.FieldDataType - } - return "" -} - -func (x *TagValue) GetFieldOptions() []string { - if x != nil { - return x.FieldOptions - } - return nil -} - -func (x *TagValue) GetFieldRequired() bool { - if x != nil { - return x.FieldRequired - } - return false -} - -func (x *TagValue) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -func (x *TagValue) GetUpdatedAt() *timestamppb.Timestamp { - if x != nil { - return x.UpdatedAt - } - return nil -} - -type TagTemplate struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - Fields []*TagTemplateField `protobuf:"bytes,4,rep,name=fields,proto3" json:"fields,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *TagTemplate) Reset() { - *x = TagTemplate{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[99] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *TagTemplate) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TagTemplate) ProtoMessage() {} - -func (x *TagTemplate) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[99] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TagTemplate.ProtoReflect.Descriptor instead. -func (*TagTemplate) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{99} -} - -func (x *TagTemplate) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *TagTemplate) GetDisplayName() string { - if x != nil { - return x.DisplayName - } - return "" -} - -func (x *TagTemplate) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *TagTemplate) GetFields() []*TagTemplateField { - if x != nil { - return x.Fields - } - return nil -} - -func (x *TagTemplate) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -func (x *TagTemplate) GetUpdatedAt() *timestamppb.Timestamp { - if x != nil { - return x.UpdatedAt - } - return nil -} - -type TagTemplateField struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Urn string `protobuf:"bytes,2,opt,name=urn,proto3" json:"urn,omitempty"` - DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` - DataType string `protobuf:"bytes,5,opt,name=data_type,json=dataType,proto3" json:"data_type,omitempty"` - Options []string `protobuf:"bytes,6,rep,name=options,proto3" json:"options,omitempty"` - Required bool `protobuf:"varint,7,opt,name=required,proto3" json:"required,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *TagTemplateField) Reset() { - *x = TagTemplateField{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[100] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *TagTemplateField) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TagTemplateField) ProtoMessage() {} - -func (x *TagTemplateField) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[100] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TagTemplateField.ProtoReflect.Descriptor instead. -func (*TagTemplateField) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{100} -} - -func (x *TagTemplateField) GetId() uint32 { - if x != nil { - return x.Id - } - return 0 -} - -func (x *TagTemplateField) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *TagTemplateField) GetDisplayName() string { - if x != nil { - return x.DisplayName - } - return "" -} - -func (x *TagTemplateField) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *TagTemplateField) GetDataType() string { - if x != nil { - return x.DataType - } - return "" -} - -func (x *TagTemplateField) GetOptions() []string { - if x != nil { - return x.Options - } - return nil -} - -func (x *TagTemplateField) GetRequired() bool { - if x != nil { - return x.Required - } - return false -} - -func (x *TagTemplateField) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -func (x *TagTemplateField) GetUpdatedAt() *timestamppb.Timestamp { - if x != nil { - return x.UpdatedAt - } - return nil -} - -type Type struct { - state protoimpl.MessageState `protogen:"open.v1"` - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Count uint32 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *Type) Reset() { - *x = Type{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[101] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *Type) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Type) ProtoMessage() {} - -func (x *Type) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[101] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Type.ProtoReflect.Descriptor instead. -func (*Type) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{101} -} - -func (x *Type) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *Type) GetCount() uint32 { - if x != nil { - return x.Count - } - return 0 -} - -type Namespace struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` - Metadata *structpb.Struct `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *Namespace) Reset() { - *x = Namespace{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[102] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *Namespace) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Namespace) ProtoMessage() {} - -func (x *Namespace) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[102] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Namespace.ProtoReflect.Descriptor instead. -func (*Namespace) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{102} -} - -func (x *Namespace) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *Namespace) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *Namespace) GetState() string { - if x != nil { - return x.State - } - return "" -} - -func (x *Namespace) GetMetadata() *structpb.Struct { - if x != nil { - return x.Metadata - } - return nil -} - -type Entity struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Urn string `protobuf:"bytes,2,opt,name=urn,proto3" json:"urn,omitempty"` - Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` - Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` - Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` - Properties *structpb.Struct `protobuf:"bytes,6,opt,name=properties,proto3" json:"properties,omitempty"` - Source string `protobuf:"bytes,7,opt,name=source,proto3" json:"source,omitempty"` - ValidFrom *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=valid_from,json=validFrom,proto3" json:"valid_from,omitempty"` - ValidTo *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=valid_to,json=validTo,proto3" json:"valid_to,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *Entity) Reset() { - *x = Entity{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[103] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *Entity) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Entity) ProtoMessage() {} - -func (x *Entity) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[103] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Entity.ProtoReflect.Descriptor instead. -func (*Entity) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{103} -} - -func (x *Entity) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *Entity) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *Entity) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *Entity) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *Entity) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *Entity) GetProperties() *structpb.Struct { - if x != nil { - return x.Properties - } - return nil -} - -func (x *Entity) GetSource() string { - if x != nil { - return x.Source - } - return "" -} - -func (x *Entity) GetValidFrom() *timestamppb.Timestamp { - if x != nil { - return x.ValidFrom - } - return nil -} - -func (x *Entity) GetValidTo() *timestamppb.Timestamp { - if x != nil { - return x.ValidTo - } - return nil -} - -func (x *Entity) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -func (x *Entity) GetUpdatedAt() *timestamppb.Timestamp { - if x != nil { - return x.UpdatedAt - } - return nil -} - -type Edge struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - SourceUrn string `protobuf:"bytes,2,opt,name=source_urn,json=sourceUrn,proto3" json:"source_urn,omitempty"` - TargetUrn string `protobuf:"bytes,3,opt,name=target_urn,json=targetUrn,proto3" json:"target_urn,omitempty"` - Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` - Properties *structpb.Struct `protobuf:"bytes,5,opt,name=properties,proto3" json:"properties,omitempty"` - Source string `protobuf:"bytes,6,opt,name=source,proto3" json:"source,omitempty"` - ValidFrom *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=valid_from,json=validFrom,proto3" json:"valid_from,omitempty"` - ValidTo *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=valid_to,json=validTo,proto3" json:"valid_to,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *Edge) Reset() { - *x = Edge{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[104] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *Edge) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Edge) ProtoMessage() {} - -func (x *Edge) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[104] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Edge.ProtoReflect.Descriptor instead. -func (*Edge) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{104} -} - -func (x *Edge) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *Edge) GetSourceUrn() string { - if x != nil { - return x.SourceUrn - } - return "" -} - -func (x *Edge) GetTargetUrn() string { - if x != nil { - return x.TargetUrn - } - return "" -} - -func (x *Edge) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *Edge) GetProperties() *structpb.Struct { - if x != nil { - return x.Properties - } - return nil -} - -func (x *Edge) GetSource() string { - if x != nil { - return x.Source - } - return "" -} - -func (x *Edge) GetValidFrom() *timestamppb.Timestamp { - if x != nil { - return x.ValidFrom - } - return nil -} - -func (x *Edge) GetValidTo() *timestamppb.Timestamp { - if x != nil { - return x.ValidTo - } - return nil -} - -func (x *Edge) GetCreatedAt() *timestamppb.Timestamp { - if x != nil { - return x.CreatedAt - } - return nil -} - -type GetAllEntitiesRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Types string `protobuf:"bytes,1,opt,name=types,proto3" json:"types,omitempty"` - Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"` - Q string `protobuf:"bytes,3,opt,name=q,proto3" json:"q,omitempty"` - Size uint32 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"` - Offset uint32 `protobuf:"varint,5,opt,name=offset,proto3" json:"offset,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetAllEntitiesRequest) Reset() { - *x = GetAllEntitiesRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[105] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetAllEntitiesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetAllEntitiesRequest) ProtoMessage() {} - -func (x *GetAllEntitiesRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[105] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetAllEntitiesRequest.ProtoReflect.Descriptor instead. -func (*GetAllEntitiesRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{105} -} - -func (x *GetAllEntitiesRequest) GetTypes() string { - if x != nil { - return x.Types - } - return "" -} - -func (x *GetAllEntitiesRequest) GetSource() string { - if x != nil { - return x.Source - } - return "" -} - -func (x *GetAllEntitiesRequest) GetQ() string { - if x != nil { - return x.Q - } - return "" -} - -func (x *GetAllEntitiesRequest) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *GetAllEntitiesRequest) GetOffset() uint32 { - if x != nil { - return x.Offset - } - return 0 -} - -type GetAllEntitiesResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data []*Entity `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - Total uint32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetAllEntitiesResponse) Reset() { - *x = GetAllEntitiesResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[106] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetAllEntitiesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetAllEntitiesResponse) ProtoMessage() {} - -func (x *GetAllEntitiesResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[106] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetAllEntitiesResponse.ProtoReflect.Descriptor instead. -func (*GetAllEntitiesResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{106} -} - -func (x *GetAllEntitiesResponse) GetData() []*Entity { - if x != nil { - return x.Data - } - return nil -} - -func (x *GetAllEntitiesResponse) GetTotal() uint32 { - if x != nil { - return x.Total - } - return 0 -} - -type GetEntityByIDRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetEntityByIDRequest) Reset() { - *x = GetEntityByIDRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[107] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetEntityByIDRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetEntityByIDRequest) ProtoMessage() {} - -func (x *GetEntityByIDRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[107] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetEntityByIDRequest.ProtoReflect.Descriptor instead. -func (*GetEntityByIDRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{107} -} - -func (x *GetEntityByIDRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -type GetEntityByIDResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data *Entity `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetEntityByIDResponse) Reset() { - *x = GetEntityByIDResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[108] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetEntityByIDResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetEntityByIDResponse) ProtoMessage() {} - -func (x *GetEntityByIDResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[108] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetEntityByIDResponse.ProtoReflect.Descriptor instead. -func (*GetEntityByIDResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{108} -} - -func (x *GetEntityByIDResponse) GetData() *Entity { - if x != nil { - return x.Data - } - return nil -} - -type UpsertEntityRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` - Properties *structpb.Struct `protobuf:"bytes,5,opt,name=properties,proto3" json:"properties,omitempty"` - Source string `protobuf:"bytes,6,opt,name=source,proto3" json:"source,omitempty"` - Upstreams []string `protobuf:"bytes,7,rep,name=upstreams,proto3" json:"upstreams,omitempty"` - Downstreams []string `protobuf:"bytes,8,rep,name=downstreams,proto3" json:"downstreams,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpsertEntityRequest) Reset() { - *x = UpsertEntityRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[109] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpsertEntityRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpsertEntityRequest) ProtoMessage() {} - -func (x *UpsertEntityRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[109] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpsertEntityRequest.ProtoReflect.Descriptor instead. -func (*UpsertEntityRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{109} -} - -func (x *UpsertEntityRequest) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *UpsertEntityRequest) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *UpsertEntityRequest) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *UpsertEntityRequest) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *UpsertEntityRequest) GetProperties() *structpb.Struct { - if x != nil { - return x.Properties - } - return nil -} - -func (x *UpsertEntityRequest) GetSource() string { - if x != nil { - return x.Source - } - return "" -} - -func (x *UpsertEntityRequest) GetUpstreams() []string { - if x != nil { - return x.Upstreams - } - return nil -} - -func (x *UpsertEntityRequest) GetDownstreams() []string { - if x != nil { - return x.Downstreams - } - return nil -} - -type UpsertEntityResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpsertEntityResponse) Reset() { - *x = UpsertEntityResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[110] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpsertEntityResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpsertEntityResponse) ProtoMessage() {} - -func (x *UpsertEntityResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[110] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpsertEntityResponse.ProtoReflect.Descriptor instead. -func (*UpsertEntityResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{110} -} - -func (x *UpsertEntityResponse) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -type DeleteEntityRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DeleteEntityRequest) Reset() { - *x = DeleteEntityRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[111] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DeleteEntityRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteEntityRequest) ProtoMessage() {} - -func (x *DeleteEntityRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[111] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteEntityRequest.ProtoReflect.Descriptor instead. -func (*DeleteEntityRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{111} -} - -func (x *DeleteEntityRequest) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -type DeleteEntityResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DeleteEntityResponse) Reset() { - *x = DeleteEntityResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[112] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DeleteEntityResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteEntityResponse) ProtoMessage() {} - -func (x *DeleteEntityResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[112] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteEntityResponse.ProtoReflect.Descriptor instead. -func (*DeleteEntityResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{112} -} - -type SearchEntitiesRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` - Types string `protobuf:"bytes,2,opt,name=types,proto3" json:"types,omitempty"` - Source string `protobuf:"bytes,3,opt,name=source,proto3" json:"source,omitempty"` - Mode string `protobuf:"bytes,4,opt,name=mode,proto3" json:"mode,omitempty"` // keyword, semantic, hybrid - Size uint32 `protobuf:"varint,5,opt,name=size,proto3" json:"size,omitempty"` - Offset uint32 `protobuf:"varint,6,opt,name=offset,proto3" json:"offset,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *SearchEntitiesRequest) Reset() { - *x = SearchEntitiesRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[113] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *SearchEntitiesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SearchEntitiesRequest) ProtoMessage() {} - -func (x *SearchEntitiesRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[113] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SearchEntitiesRequest.ProtoReflect.Descriptor instead. -func (*SearchEntitiesRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{113} -} - -func (x *SearchEntitiesRequest) GetText() string { - if x != nil { - return x.Text - } - return "" -} - -func (x *SearchEntitiesRequest) GetTypes() string { - if x != nil { - return x.Types - } - return "" -} - -func (x *SearchEntitiesRequest) GetSource() string { - if x != nil { - return x.Source - } - return "" -} - -func (x *SearchEntitiesRequest) GetMode() string { - if x != nil { - return x.Mode - } - return "" -} - -func (x *SearchEntitiesRequest) GetSize() uint32 { - if x != nil { - return x.Size - } - return 0 -} - -func (x *SearchEntitiesRequest) GetOffset() uint32 { - if x != nil { - return x.Offset - } - return 0 -} - -type SearchEntitiesResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data []*Entity `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *SearchEntitiesResponse) Reset() { - *x = SearchEntitiesResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[114] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *SearchEntitiesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SearchEntitiesResponse) ProtoMessage() {} - -func (x *SearchEntitiesResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[114] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SearchEntitiesResponse.ProtoReflect.Descriptor instead. -func (*SearchEntitiesResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{114} -} - -func (x *SearchEntitiesResponse) GetData() []*Entity { - if x != nil { - return x.Data - } - return nil -} - -type SuggestEntitiesRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *SuggestEntitiesRequest) Reset() { - *x = SuggestEntitiesRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[115] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *SuggestEntitiesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SuggestEntitiesRequest) ProtoMessage() {} - -func (x *SuggestEntitiesRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[115] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SuggestEntitiesRequest.ProtoReflect.Descriptor instead. -func (*SuggestEntitiesRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{115} -} - -func (x *SuggestEntitiesRequest) GetText() string { - if x != nil { - return x.Text - } - return "" -} - -type SuggestEntitiesResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data []string `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *SuggestEntitiesResponse) Reset() { - *x = SuggestEntitiesResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[116] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *SuggestEntitiesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SuggestEntitiesResponse) ProtoMessage() {} - -func (x *SuggestEntitiesResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[116] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SuggestEntitiesResponse.ProtoReflect.Descriptor instead. -func (*SuggestEntitiesResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{116} -} - -func (x *SuggestEntitiesResponse) GetData() []string { - if x != nil { - return x.Data - } - return nil -} - -type GetEntityTypesRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetEntityTypesRequest) Reset() { - *x = GetEntityTypesRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[117] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetEntityTypesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetEntityTypesRequest) ProtoMessage() {} - -func (x *GetEntityTypesRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[117] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetEntityTypesRequest.ProtoReflect.Descriptor instead. -func (*GetEntityTypesRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{117} -} - -type GetEntityTypesResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data []*Type `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetEntityTypesResponse) Reset() { - *x = GetEntityTypesResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[118] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetEntityTypesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetEntityTypesResponse) ProtoMessage() {} - -func (x *GetEntityTypesResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[118] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetEntityTypesResponse.ProtoReflect.Descriptor instead. -func (*GetEntityTypesResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{118} -} - -func (x *GetEntityTypesResponse) GetData() []*Type { - if x != nil { - return x.Data - } - return nil -} - -type GetEntityContextRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - Depth uint32 `protobuf:"varint,2,opt,name=depth,proto3" json:"depth,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetEntityContextRequest) Reset() { - *x = GetEntityContextRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[119] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetEntityContextRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetEntityContextRequest) ProtoMessage() {} - -func (x *GetEntityContextRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[119] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetEntityContextRequest.ProtoReflect.Descriptor instead. -func (*GetEntityContextRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{119} -} - -func (x *GetEntityContextRequest) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *GetEntityContextRequest) GetDepth() uint32 { - if x != nil { - return x.Depth - } - return 0 -} - -type GetEntityContextResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Entity *Entity `protobuf:"bytes,1,opt,name=entity,proto3" json:"entity,omitempty"` - Edges []*Edge `protobuf:"bytes,2,rep,name=edges,proto3" json:"edges,omitempty"` - Related []*Entity `protobuf:"bytes,3,rep,name=related,proto3" json:"related,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetEntityContextResponse) Reset() { - *x = GetEntityContextResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[120] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetEntityContextResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetEntityContextResponse) ProtoMessage() {} - -func (x *GetEntityContextResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[120] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetEntityContextResponse.ProtoReflect.Descriptor instead. -func (*GetEntityContextResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{120} -} - -func (x *GetEntityContextResponse) GetEntity() *Entity { - if x != nil { - return x.Entity - } - return nil -} - -func (x *GetEntityContextResponse) GetEdges() []*Edge { - if x != nil { - return x.Edges - } - return nil -} - -func (x *GetEntityContextResponse) GetRelated() []*Entity { - if x != nil { - return x.Related - } - return nil -} - -type GetEntityImpactRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - Depth uint32 `protobuf:"varint,2,opt,name=depth,proto3" json:"depth,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetEntityImpactRequest) Reset() { - *x = GetEntityImpactRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[121] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetEntityImpactRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetEntityImpactRequest) ProtoMessage() {} - -func (x *GetEntityImpactRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[121] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetEntityImpactRequest.ProtoReflect.Descriptor instead. -func (*GetEntityImpactRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{121} -} - -func (x *GetEntityImpactRequest) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *GetEntityImpactRequest) GetDepth() uint32 { - if x != nil { - return x.Depth - } - return 0 -} - -type GetEntityImpactResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Edges []*Edge `protobuf:"bytes,1,rep,name=edges,proto3" json:"edges,omitempty"` - Affected []*Entity `protobuf:"bytes,2,rep,name=affected,proto3" json:"affected,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetEntityImpactResponse) Reset() { - *x = GetEntityImpactResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[122] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetEntityImpactResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetEntityImpactResponse) ProtoMessage() {} - -func (x *GetEntityImpactResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[122] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetEntityImpactResponse.ProtoReflect.Descriptor instead. -func (*GetEntityImpactResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{122} -} - -func (x *GetEntityImpactResponse) GetEdges() []*Edge { - if x != nil { - return x.Edges - } - return nil -} - -func (x *GetEntityImpactResponse) GetAffected() []*Entity { - if x != nil { - return x.Affected - } - return nil -} - -type UpsertEdgeRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - SourceUrn string `protobuf:"bytes,1,opt,name=source_urn,json=sourceUrn,proto3" json:"source_urn,omitempty"` - TargetUrn string `protobuf:"bytes,2,opt,name=target_urn,json=targetUrn,proto3" json:"target_urn,omitempty"` - Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` - Properties *structpb.Struct `protobuf:"bytes,4,opt,name=properties,proto3" json:"properties,omitempty"` - Source string `protobuf:"bytes,5,opt,name=source,proto3" json:"source,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpsertEdgeRequest) Reset() { - *x = UpsertEdgeRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[123] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpsertEdgeRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpsertEdgeRequest) ProtoMessage() {} - -func (x *UpsertEdgeRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[123] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpsertEdgeRequest.ProtoReflect.Descriptor instead. -func (*UpsertEdgeRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{123} -} - -func (x *UpsertEdgeRequest) GetSourceUrn() string { - if x != nil { - return x.SourceUrn - } - return "" -} - -func (x *UpsertEdgeRequest) GetTargetUrn() string { - if x != nil { - return x.TargetUrn - } - return "" -} - -func (x *UpsertEdgeRequest) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *UpsertEdgeRequest) GetProperties() *structpb.Struct { - if x != nil { - return x.Properties - } - return nil -} - -func (x *UpsertEdgeRequest) GetSource() string { - if x != nil { - return x.Source - } - return "" -} - -type UpsertEdgeResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpsertEdgeResponse) Reset() { - *x = UpsertEdgeResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[124] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpsertEdgeResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpsertEdgeResponse) ProtoMessage() {} - -func (x *UpsertEdgeResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[124] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpsertEdgeResponse.ProtoReflect.Descriptor instead. -func (*UpsertEdgeResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{124} -} - -func (x *UpsertEdgeResponse) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -type GetEdgesRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - Direction string `protobuf:"bytes,2,opt,name=direction,proto3" json:"direction,omitempty"` // outgoing, incoming, both (default: both) - Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` // filter by edge type - CurrentOnly bool `protobuf:"varint,4,opt,name=current_only,json=currentOnly,proto3" json:"current_only,omitempty"` // only current edges (valid_to IS NULL) - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetEdgesRequest) Reset() { - *x = GetEdgesRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[125] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetEdgesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetEdgesRequest) ProtoMessage() {} - -func (x *GetEdgesRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[125] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetEdgesRequest.ProtoReflect.Descriptor instead. -func (*GetEdgesRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{125} -} - -func (x *GetEdgesRequest) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *GetEdgesRequest) GetDirection() string { - if x != nil { - return x.Direction - } - return "" -} - -func (x *GetEdgesRequest) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *GetEdgesRequest) GetCurrentOnly() bool { - if x != nil { - return x.CurrentOnly - } - return false -} - -type GetEdgesResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Data []*Edge `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetEdgesResponse) Reset() { - *x = GetEdgesResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[126] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetEdgesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetEdgesResponse) ProtoMessage() {} - -func (x *GetEdgesResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[126] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetEdgesResponse.ProtoReflect.Descriptor instead. -func (*GetEdgesResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{126} -} - -func (x *GetEdgesResponse) GetData() []*Edge { - if x != nil { - return x.Data - } - return nil -} - -type DeleteEdgeRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - SourceUrn string `protobuf:"bytes,1,opt,name=source_urn,json=sourceUrn,proto3" json:"source_urn,omitempty"` - TargetUrn string `protobuf:"bytes,2,opt,name=target_urn,json=targetUrn,proto3" json:"target_urn,omitempty"` - Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DeleteEdgeRequest) Reset() { - *x = DeleteEdgeRequest{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[127] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DeleteEdgeRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteEdgeRequest) ProtoMessage() {} - -func (x *DeleteEdgeRequest) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[127] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteEdgeRequest.ProtoReflect.Descriptor instead. -func (*DeleteEdgeRequest) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{127} -} - -func (x *DeleteEdgeRequest) GetSourceUrn() string { - if x != nil { - return x.SourceUrn - } - return "" -} - -func (x *DeleteEdgeRequest) GetTargetUrn() string { - if x != nil { - return x.TargetUrn - } - return "" -} - -func (x *DeleteEdgeRequest) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -type DeleteEdgeResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *DeleteEdgeResponse) Reset() { - *x = DeleteEdgeResponse{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[128] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *DeleteEdgeResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteEdgeResponse) ProtoMessage() {} - -func (x *DeleteEdgeResponse) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[128] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteEdgeResponse.ProtoReflect.Descriptor instead. -func (*DeleteEdgeResponse) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{128} -} - -type GetGraphResponse_ProbesInfo struct { - state protoimpl.MessageState `protogen:"open.v1"` - Latest *Probe `protobuf:"bytes,1,opt,name=latest,proto3" json:"latest,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetGraphResponse_ProbesInfo) Reset() { - *x = GetGraphResponse_ProbesInfo{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[132] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetGraphResponse_ProbesInfo) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetGraphResponse_ProbesInfo) ProtoMessage() {} - -func (x *GetGraphResponse_ProbesInfo) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[132] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetGraphResponse_ProbesInfo.ProtoReflect.Descriptor instead. -func (*GetGraphResponse_ProbesInfo) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{28, 0} -} - -func (x *GetGraphResponse_ProbesInfo) GetLatest() *Probe { - if x != nil { - return x.Latest - } - return nil -} - -type GetGraphResponse_NodeAttributes struct { - state protoimpl.MessageState `protogen:"open.v1"` - Probes *GetGraphResponse_ProbesInfo `protobuf:"bytes,1,opt,name=probes,proto3" json:"probes,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *GetGraphResponse_NodeAttributes) Reset() { - *x = GetGraphResponse_NodeAttributes{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[133] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *GetGraphResponse_NodeAttributes) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetGraphResponse_NodeAttributes) ProtoMessage() {} - -func (x *GetGraphResponse_NodeAttributes) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[133] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetGraphResponse_NodeAttributes.ProtoReflect.Descriptor instead. -func (*GetGraphResponse_NodeAttributes) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{28, 1} -} - -func (x *GetGraphResponse_NodeAttributes) GetProbes() *GetGraphResponse_ProbesInfo { - if x != nil { - return x.Probes - } - return nil -} - -type UpsertAssetRequest_Asset struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - Service string `protobuf:"bytes,4,opt,name=service,proto3" json:"service,omitempty"` - Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` - Data *structpb.Struct `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"` - Labels map[string]string `protobuf:"bytes,7,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Owners []*User `protobuf:"bytes,8,rep,name=owners,proto3" json:"owners,omitempty"` - Url string `protobuf:"bytes,9,opt,name=url,proto3" json:"url,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpsertAssetRequest_Asset) Reset() { - *x = UpsertAssetRequest_Asset{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[137] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpsertAssetRequest_Asset) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpsertAssetRequest_Asset) ProtoMessage() {} - -func (x *UpsertAssetRequest_Asset) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[137] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpsertAssetRequest_Asset.ProtoReflect.Descriptor instead. -func (*UpsertAssetRequest_Asset) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{35, 0} -} - -func (x *UpsertAssetRequest_Asset) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *UpsertAssetRequest_Asset) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *UpsertAssetRequest_Asset) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *UpsertAssetRequest_Asset) GetService() string { - if x != nil { - return x.Service - } - return "" -} - -func (x *UpsertAssetRequest_Asset) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *UpsertAssetRequest_Asset) GetData() *structpb.Struct { - if x != nil { - return x.Data - } - return nil -} - -func (x *UpsertAssetRequest_Asset) GetLabels() map[string]string { - if x != nil { - return x.Labels - } - return nil -} - -func (x *UpsertAssetRequest_Asset) GetOwners() []*User { - if x != nil { - return x.Owners - } - return nil -} - -func (x *UpsertAssetRequest_Asset) GetUrl() string { - if x != nil { - return x.Url - } - return "" -} - -type UpsertPatchAssetRequest_Asset struct { - state protoimpl.MessageState `protogen:"open.v1"` - Urn string `protobuf:"bytes,1,opt,name=urn,proto3" json:"urn,omitempty"` - Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` - Name *wrapperspb.StringValue `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - Service string `protobuf:"bytes,4,opt,name=service,proto3" json:"service,omitempty"` - Description *wrapperspb.StringValue `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` - Data *structpb.Struct `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"` - Labels map[string]string `protobuf:"bytes,7,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Owners []*User `protobuf:"bytes,8,rep,name=owners,proto3" json:"owners,omitempty"` - Url string `protobuf:"bytes,9,opt,name=url,proto3" json:"url,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *UpsertPatchAssetRequest_Asset) Reset() { - *x = UpsertPatchAssetRequest_Asset{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[139] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *UpsertPatchAssetRequest_Asset) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpsertPatchAssetRequest_Asset) ProtoMessage() {} - -func (x *UpsertPatchAssetRequest_Asset) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[139] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use UpsertPatchAssetRequest_Asset.ProtoReflect.Descriptor instead. -func (*UpsertPatchAssetRequest_Asset) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{37, 0} -} - -func (x *UpsertPatchAssetRequest_Asset) GetUrn() string { - if x != nil { - return x.Urn - } - return "" -} - -func (x *UpsertPatchAssetRequest_Asset) GetType() string { - if x != nil { - return x.Type - } - return "" -} - -func (x *UpsertPatchAssetRequest_Asset) GetName() *wrapperspb.StringValue { - if x != nil { - return x.Name - } - return nil -} - -func (x *UpsertPatchAssetRequest_Asset) GetService() string { - if x != nil { - return x.Service - } - return "" -} - -func (x *UpsertPatchAssetRequest_Asset) GetDescription() *wrapperspb.StringValue { - if x != nil { - return x.Description - } - return nil -} - -func (x *UpsertPatchAssetRequest_Asset) GetData() *structpb.Struct { - if x != nil { - return x.Data - } - return nil -} - -func (x *UpsertPatchAssetRequest_Asset) GetLabels() map[string]string { - if x != nil { - return x.Labels - } - return nil -} - -func (x *UpsertPatchAssetRequest_Asset) GetOwners() []*User { - if x != nil { - return x.Owners - } - return nil -} - -func (x *UpsertPatchAssetRequest_Asset) GetUrl() string { - if x != nil { - return x.Url - } - return "" -} - -type CreateAssetProbeRequest_Probe struct { - state protoimpl.MessageState `protogen:"open.v1"` - Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` - StatusReason string `protobuf:"bytes,2,opt,name=status_reason,json=statusReason,proto3" json:"status_reason,omitempty"` - Metadata *structpb.Struct `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` - Timestamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Id string `protobuf:"bytes,5,opt,name=id,proto3" json:"id,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *CreateAssetProbeRequest_Probe) Reset() { - *x = CreateAssetProbeRequest_Probe{} - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[141] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *CreateAssetProbeRequest_Probe) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateAssetProbeRequest_Probe) ProtoMessage() {} +func (*ListNamespacesResponse) ProtoMessage() {} -func (x *CreateAssetProbeRequest_Probe) ProtoReflect() protoreflect.Message { - mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[141] +func (x *ListNamespacesResponse) ProtoReflect() protoreflect.Message { + mi := &file_raystack_compass_v1beta1_service_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7870,402 +2664,23 @@ func (x *CreateAssetProbeRequest_Probe) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CreateAssetProbeRequest_Probe.ProtoReflect.Descriptor instead. -func (*CreateAssetProbeRequest_Probe) Descriptor() ([]byte, []int) { - return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{47, 0} -} - -func (x *CreateAssetProbeRequest_Probe) GetStatus() string { - if x != nil { - return x.Status - } - return "" -} - -func (x *CreateAssetProbeRequest_Probe) GetStatusReason() string { - if x != nil { - return x.StatusReason - } - return "" -} - -func (x *CreateAssetProbeRequest_Probe) GetMetadata() *structpb.Struct { - if x != nil { - return x.Metadata - } - return nil +// Deprecated: Use ListNamespacesResponse.ProtoReflect.Descriptor instead. +func (*ListNamespacesResponse) Descriptor() ([]byte, []int) { + return file_raystack_compass_v1beta1_service_proto_rawDescGZIP(), []int{48} } -func (x *CreateAssetProbeRequest_Probe) GetTimestamp() *timestamppb.Timestamp { +func (x *ListNamespacesResponse) GetNamespaces() []*Namespace { if x != nil { - return x.Timestamp + return x.Namespaces } return nil } -func (x *CreateAssetProbeRequest_Probe) GetId() string { - if x != nil { - return x.Id - } - return "" -} - var File_raystack_compass_v1beta1_service_proto protoreflect.FileDescriptor const file_raystack_compass_v1beta1_service_proto_rawDesc = "" + "\n" + - "&raystack/compass/v1beta1/service.proto\x12\x18raystack.compass.v1beta1\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x1bbuf/validate/validate.proto\"\x94\x02\n" + - "\x18GetAllDiscussionsRequest\x12\x12\n" + - "\x04type\x18\x01 \x01(\tR\x04type\x12\x14\n" + - "\x05state\x18\x02 \x01(\tR\x05state\x12\x14\n" + - "\x05owner\x18\x03 \x01(\tR\x05owner\x12\x1a\n" + - "\bassignee\x18\x04 \x01(\tR\bassignee\x12\x14\n" + - "\x05asset\x18\x05 \x01(\tR\x05asset\x12\x16\n" + - "\x06labels\x18\x06 \x01(\tR\x06labels\x12\x12\n" + - "\x04sort\x18\a \x01(\tR\x04sort\x12\x1c\n" + - "\tdirection\x18\b \x01(\tR\tdirection\x12\x1b\n" + - "\x04size\x18\t \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + - "\x06offset\x18\n" + - " \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"U\n" + - "\x19GetAllDiscussionsResponse\x128\n" + - "\x04data\x18\x01 \x03(\v2$.raystack.compass.v1beta1.DiscussionR\x04data\"\xeb\x01\n" + - "\x17CreateDiscussionRequest\x12\x1d\n" + - "\x05title\x18\x02 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x05title\x12\x1b\n" + - "\x04body\x18\x03 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x04body\x12\x12\n" + - "\x04type\x18\x04 \x01(\tR\x04type\x12\x14\n" + - "\x05state\x18\x05 \x01(\tR\x05state\x12 \n" + - "\x06labels\x18\x06 \x03(\tB\b\xbaH\x05\x92\x01\x02\x18\x01R\x06labels\x12 \n" + - "\x06assets\x18\a \x03(\tB\b\xbaH\x05\x92\x01\x02\x18\x01R\x06assets\x12&\n" + - "\tassignees\x18\b \x03(\tB\b\xbaH\x05\x92\x01\x02\x18\x01R\tassignees\"*\n" + - "\x18CreateDiscussionResponse\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\"&\n" + - "\x14GetDiscussionRequest\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\"Q\n" + - "\x15GetDiscussionResponse\x128\n" + - "\x04data\x18\x01 \x01(\v2$.raystack.compass.v1beta1.DiscussionR\x04data\"\xe8\x01\n" + - "\x16PatchDiscussionRequest\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12\x14\n" + - "\x05title\x18\x02 \x01(\tR\x05title\x12\x12\n" + - "\x04body\x18\x03 \x01(\tR\x04body\x12\x12\n" + - "\x04type\x18\x04 \x01(\tR\x04type\x12\x14\n" + - "\x05state\x18\x05 \x01(\tR\x05state\x12 \n" + - "\x06labels\x18\x06 \x03(\tB\b\xbaH\x05\x92\x01\x02\x18\x01R\x06labels\x12 \n" + - "\x06assets\x18\a \x03(\tB\b\xbaH\x05\x92\x01\x02\x18\x01R\x06assets\x12&\n" + - "\tassignees\x18\b \x03(\tB\b\xbaH\x05\x92\x01\x02\x18\x01R\tassignees\"X\n" + - "\x14CreateCommentRequest\x12#\n" + - "\rdiscussion_id\x18\x01 \x01(\tR\fdiscussionId\x12\x1b\n" + - "\x04body\x18\x02 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x04body\"\x19\n" + - "\x17PatchDiscussionResponse\"'\n" + - "\x15CreateCommentResponse\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\"\xac\x01\n" + - "\x15GetAllCommentsRequest\x12#\n" + - "\rdiscussion_id\x18\x01 \x01(\tR\fdiscussionId\x12\x12\n" + - "\x04sort\x18\x02 \x01(\tR\x04sort\x12\x1c\n" + - "\tdirection\x18\x03 \x01(\tR\tdirection\x12\x1b\n" + - "\x04size\x18\x04 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + - "\x06offset\x18\x05 \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"O\n" + - "\x16GetAllCommentsResponse\x125\n" + - "\x04data\x18\x01 \x03(\v2!.raystack.compass.v1beta1.CommentR\x04data\"H\n" + - "\x11GetCommentRequest\x12#\n" + - "\rdiscussion_id\x18\x01 \x01(\tR\fdiscussionId\x12\x0e\n" + - "\x02id\x18\x02 \x01(\tR\x02id\"K\n" + - "\x12GetCommentResponse\x125\n" + - "\x04data\x18\x01 \x01(\v2!.raystack.compass.v1beta1.CommentR\x04data\"h\n" + - "\x14UpdateCommentRequest\x12#\n" + - "\rdiscussion_id\x18\x01 \x01(\tR\fdiscussionId\x12\x0e\n" + - "\x02id\x18\x02 \x01(\tR\x02id\x12\x1b\n" + - "\x04body\x18\x03 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x04body\"\x17\n" + - "\x15UpdateCommentResponse\"K\n" + - "\x14DeleteCommentRequest\x12#\n" + - "\rdiscussion_id\x18\x01 \x01(\tR\fdiscussionId\x12\x0e\n" + - "\x02id\x18\x02 \x01(\tR\x02id\"\x17\n" + - "\x15DeleteCommentResponse\"\x85\x04\n" + - "\x13SearchAssetsRequest\x12\x12\n" + - "\x04text\x18\x01 \x01(\tR\x04text\x12\x16\n" + - "\x06rankby\x18\x02 \x01(\tR\x06rankby\x12\x1b\n" + - "\x04size\x18\x03 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12Q\n" + - "\x06filter\x18\x04 \x03(\v29.raystack.compass.v1beta1.SearchAssetsRequest.FilterEntryR\x06filter\x12N\n" + - "\x05query\x18\x05 \x03(\v28.raystack.compass.v1beta1.SearchAssetsRequest.QueryEntryR\x05query\x12/\n" + - "\x0einclude_fields\x18\x06 \x03(\tB\b\xbaH\x05\x92\x01\x02\x18\x01R\rincludeFields\x12\x1f\n" + - "\x06offset\x18\a \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\x12;\n" + - "\x05flags\x18\b \x01(\v2%.raystack.compass.v1beta1.SearchFlagsR\x05flags\x1a9\n" + - "\vFilterEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a8\n" + - "\n" + - "QueryEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x87\x01\n" + - "\vSearchFlags\x12(\n" + - "\x10is_column_search\x18\x01 \x01(\bR\x0eisColumnSearch\x12#\n" + - "\rdisable_fuzzy\x18\x02 \x01(\bR\fdisableFuzzy\x12)\n" + - "\x10enable_highlight\x18\x03 \x01(\bR\x0fenableHighlight\"K\n" + - "\x14SearchAssetsResponse\x123\n" + - "\x04data\x18\x01 \x03(\v2\x1f.raystack.compass.v1beta1.AssetR\x04data\"*\n" + - "\x14SuggestAssetsRequest\x12\x12\n" + - "\x04text\x18\x01 \x01(\tR\x04text\"+\n" + - "\x15SuggestAssetsResponse\x12\x12\n" + - "\x04data\x18\x01 \x03(\tR\x04data\"\x89\x02\n" + - "\x12GroupAssetsRequest\x12\"\n" + - "\agroupby\x18\x01 \x03(\tB\b\xbaH\x05\x92\x01\x02\b\x01R\agroupby\x12P\n" + - "\x06filter\x18\x02 \x03(\v28.raystack.compass.v1beta1.GroupAssetsRequest.FilterEntryR\x06filter\x12%\n" + - "\x0einclude_fields\x18\x03 \x03(\tR\rincludeFields\x12\x1b\n" + - "\x04size\x18\x04 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x1a9\n" + - "\vFilterEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"^\n" + - "\x13GroupAssetsResponse\x12G\n" + - "\fasset_groups\x18\x01 \x03(\v2$.raystack.compass.v1beta1.AssetGroupR\vassetGroups\"\x8e\x01\n" + - "\n" + - "AssetGroup\x12G\n" + - "\fgroup_fields\x18\x01 \x03(\v2$.raystack.compass.v1beta1.GroupFieldR\vgroupFields\x127\n" + - "\x06assets\x18\x02 \x03(\v2\x1f.raystack.compass.v1beta1.AssetR\x06assets\"J\n" + - "\n" + - "GroupField\x12\x1b\n" + - "\tgroup_key\x18\x01 \x01(\tR\bgroupKey\x12\x1f\n" + - "\vgroup_value\x18\x02 \x01(\tR\n" + - "groupValue\"\xe1\x01\n" + - "\x0fGetGraphRequest\x12\x10\n" + - "\x03urn\x18\x01 \x01(\tR\x03urn\x12\x14\n" + - "\x05level\x18\x02 \x01(\rR\x05level\x12;\n" + - "\tdirection\x18\x03 \x01(\tB\x1d\xbaH\x1ar\x18R\bupstreamR\n" + - "downstreamR\x00R\tdirection\x12,\n" + - "\x0fwith_attributes\x18\x04 \x01(\bH\x00R\x0ewithAttributes\x88\x01\x01\x12'\n" + - "\x0finclude_deleted\x18\x05 \x01(\bR\x0eincludeDeletedB\x12\n" + - "\x10_with_attributes\"\xc8\x03\n" + - "\x10GetGraphResponse\x129\n" + - "\x04data\x18\x01 \x03(\v2%.raystack.compass.v1beta1.LineageEdgeR\x04data\x12X\n" + - "\n" + - "node_attrs\x18\x02 \x03(\v29.raystack.compass.v1beta1.GetGraphResponse.NodeAttrsEntryR\tnodeAttrs\x1aE\n" + - "\n" + - "ProbesInfo\x127\n" + - "\x06latest\x18\x01 \x01(\v2\x1f.raystack.compass.v1beta1.ProbeR\x06latest\x1a_\n" + - "\x0eNodeAttributes\x12M\n" + - "\x06probes\x18\x01 \x01(\v25.raystack.compass.v1beta1.GetGraphResponse.ProbesInfoR\x06probes\x1aw\n" + - "\x0eNodeAttrsEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12O\n" + - "\x05value\x18\x02 \x01(\v29.raystack.compass.v1beta1.GetGraphResponse.NodeAttributesR\x05value:\x028\x01\"\xf4\x01\n" + - "\x12GetAllTypesRequest\x12\f\n" + - "\x01q\x18\x01 \x01(\tR\x01q\x12\x19\n" + - "\bq_fields\x18\x02 \x01(\tR\aqFields\x12\x14\n" + - "\x05types\x18\x03 \x01(\tR\x05types\x12\x1a\n" + - "\bservices\x18\x04 \x01(\tR\bservices\x12J\n" + - "\x04data\x18\x05 \x03(\v26.raystack.compass.v1beta1.GetAllTypesRequest.DataEntryR\x04data\x1a7\n" + - "\tDataEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"I\n" + - "\x13GetAllTypesResponse\x122\n" + - "\x04data\x18\x01 \x03(\v2\x1e.raystack.compass.v1beta1.TypeR\x04data\"\xa4\x03\n" + - "\x13GetAllAssetsRequest\x12\f\n" + - "\x01q\x18\x01 \x01(\tR\x01q\x12\x19\n" + - "\bq_fields\x18\x02 \x01(\tR\aqFields\x12\x14\n" + - "\x05types\x18\x03 \x01(\tR\x05types\x12\x1a\n" + - "\bservices\x18\x04 \x01(\tR\bservices\x12\x12\n" + - "\x04sort\x18\x05 \x01(\tR\x04sort\x12\x1c\n" + - "\tdirection\x18\x06 \x01(\tR\tdirection\x12K\n" + - "\x04data\x18\a \x03(\v27.raystack.compass.v1beta1.GetAllAssetsRequest.DataEntryR\x04data\x12\x1b\n" + - "\x04size\x18\b \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + - "\x06offset\x18\t \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\x12\x1d\n" + - "\n" + - "with_total\x18\n" + - " \x01(\bR\twithTotal\x12\x1d\n" + - "\n" + - "is_deleted\x18\v \x01(\bR\tisDeleted\x1a7\n" + - "\tDataEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"a\n" + - "\x14GetAllAssetsResponse\x123\n" + - "\x04data\x18\x01 \x03(\v2\x1f.raystack.compass.v1beta1.AssetR\x04data\x12\x14\n" + - "\x05total\x18\x02 \x01(\rR\x05total\"%\n" + - "\x13GetAssetByIDRequest\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\"K\n" + - "\x14GetAssetByIDResponse\x123\n" + - "\x04data\x18\x01 \x01(\v2\x1f.raystack.compass.v1beta1.AssetR\x04data\"\x97\x05\n" + - "\x12UpsertAssetRequest\x12H\n" + - "\x05asset\x18\x01 \x01(\v22.raystack.compass.v1beta1.UpsertAssetRequest.AssetR\x05asset\x12C\n" + - "\tupstreams\x18\x02 \x03(\v2%.raystack.compass.v1beta1.LineageNodeR\tupstreams\x12G\n" + - "\vdownstreams\x18\x03 \x03(\v2%.raystack.compass.v1beta1.LineageNodeR\vdownstreams\x12\x1f\n" + - "\vupdate_only\x18\x04 \x01(\bR\n" + - "updateOnly\x1a\x87\x03\n" + - "\x05Asset\x12\x10\n" + - "\x03urn\x18\x01 \x01(\tR\x03urn\x12\x12\n" + - "\x04type\x18\x02 \x01(\tR\x04type\x12\x12\n" + - "\x04name\x18\x03 \x01(\tR\x04name\x12\x18\n" + - "\aservice\x18\x04 \x01(\tR\aservice\x12 \n" + - "\vdescription\x18\x05 \x01(\tR\vdescription\x12+\n" + - "\x04data\x18\x06 \x01(\v2\x17.google.protobuf.StructR\x04data\x12V\n" + - "\x06labels\x18\a \x03(\v2>.raystack.compass.v1beta1.UpsertAssetRequest.Asset.LabelsEntryR\x06labels\x126\n" + - "\x06owners\x18\b \x03(\v2\x1e.raystack.compass.v1beta1.UserR\x06owners\x12\x10\n" + - "\x03url\x18\t \x01(\tR\x03url\x1a9\n" + - "\vLabelsEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"%\n" + - "\x13UpsertAssetResponse\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\"\x8f\x06\n" + - "\x17UpsertPatchAssetRequest\x12M\n" + - "\x05asset\x18\x01 \x01(\v27.raystack.compass.v1beta1.UpsertPatchAssetRequest.AssetR\x05asset\x12C\n" + - "\tupstreams\x18\x02 \x03(\v2%.raystack.compass.v1beta1.LineageNodeR\tupstreams\x12G\n" + - "\vdownstreams\x18\x03 \x03(\v2%.raystack.compass.v1beta1.LineageNodeR\vdownstreams\x12+\n" + - "\x11overwrite_lineage\x18\x04 \x01(\bR\x10overwriteLineage\x12\x1f\n" + - "\vupdate_only\x18\x05 \x01(\bR\n" + - "updateOnly\x1a\xc8\x03\n" + - "\x05Asset\x12\x10\n" + - "\x03urn\x18\x01 \x01(\tR\x03urn\x12\x12\n" + - "\x04type\x18\x02 \x01(\tR\x04type\x120\n" + - "\x04name\x18\x03 \x01(\v2\x1c.google.protobuf.StringValueR\x04name\x12\x18\n" + - "\aservice\x18\x04 \x01(\tR\aservice\x12>\n" + - "\vdescription\x18\x05 \x01(\v2\x1c.google.protobuf.StringValueR\vdescription\x12+\n" + - "\x04data\x18\x06 \x01(\v2\x17.google.protobuf.StructR\x04data\x12[\n" + - "\x06labels\x18\a \x03(\v2C.raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.LabelsEntryR\x06labels\x126\n" + - "\x06owners\x18\b \x03(\v2\x1e.raystack.compass.v1beta1.UserR\x06owners\x12\x10\n" + - "\x03url\x18\t \x01(\tR\x03url\x1a9\n" + - "\vLabelsEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"*\n" + - "\x18UpsertPatchAssetResponse\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\"$\n" + - "\x12DeleteAssetRequest\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\"\x15\n" + - "\x13DeleteAssetResponse\"i\n" + - "\x19GetAssetStargazersRequest\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12\x1b\n" + - "\x04size\x18\x02 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + - "\x06offset\x18\x03 \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"P\n" + - "\x1aGetAssetStargazersResponse\x122\n" + - "\x04data\x18\x01 \x03(\v2\x1e.raystack.compass.v1beta1.UserR\x04data\"m\n" + - "\x1dGetAssetVersionHistoryRequest\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12\x1b\n" + - "\x04size\x18\x02 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + - "\x06offset\x18\x03 \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"U\n" + - "\x1eGetAssetVersionHistoryResponse\x123\n" + - "\x04data\x18\x01 \x03(\v2\x1f.raystack.compass.v1beta1.AssetR\x04data\"D\n" + - "\x18GetAssetByVersionRequest\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12\x18\n" + - "\aversion\x18\x02 \x01(\tR\aversion\"P\n" + - "\x19GetAssetByVersionResponse\x123\n" + - "\x04data\x18\x01 \x01(\v2\x1f.raystack.compass.v1beta1.AssetR\x04data\"\xdd\x02\n" + - "\x17CreateAssetProbeRequest\x12$\n" + - "\tasset_urn\x18\x01 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\bassetUrn\x12M\n" + - "\x05probe\x18\x02 \x01(\v27.raystack.compass.v1beta1.CreateAssetProbeRequest.ProbeR\x05probe\x1a\xcc\x01\n" + - "\x05Probe\x12\x1f\n" + - "\x06status\x18\x01 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x06status\x12#\n" + - "\rstatus_reason\x18\x02 \x01(\tR\fstatusReason\x123\n" + - "\bmetadata\x18\x03 \x01(\v2\x17.google.protobuf.StructR\bmetadata\x128\n" + - "\ttimestamp\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x12\x0e\n" + - "\x02id\x18\x05 \x01(\tR\x02id\"*\n" + - "\x18CreateAssetProbeResponse\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\"t\n" + - "\x1bGetUserStarredAssetsRequest\x12\x17\n" + - "\auser_id\x18\x01 \x01(\tR\x06userId\x12\x1b\n" + - "\x04size\x18\x02 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + - "\x06offset\x18\x03 \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"S\n" + - "\x1cGetUserStarredAssetsResponse\x123\n" + - "\x04data\x18\x01 \x03(\v2\x1f.raystack.compass.v1beta1.AssetR\x04data\"Y\n" + - "\x19GetMyStarredAssetsRequest\x12\x1b\n" + - "\x04size\x18\x01 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + - "\x06offset\x18\x02 \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"Q\n" + - "\x1aGetMyStarredAssetsResponse\x123\n" + - "\x04data\x18\x01 \x03(\v2\x1f.raystack.compass.v1beta1.AssetR\x04data\"5\n" + - "\x18GetMyStarredAssetRequest\x12\x19\n" + - "\basset_id\x18\x01 \x01(\tR\aassetId\"P\n" + - "\x19GetMyStarredAssetResponse\x123\n" + - "\x04data\x18\x01 \x01(\v2\x1f.raystack.compass.v1beta1.AssetR\x04data\"-\n" + - "\x10StarAssetRequest\x12\x19\n" + - "\basset_id\x18\x01 \x01(\tR\aassetId\"#\n" + - "\x11StarAssetResponse\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\"/\n" + - "\x12UnstarAssetRequest\x12\x19\n" + - "\basset_id\x18\x01 \x01(\tR\aassetId\"\x15\n" + - "\x13UnstarAssetResponse\"\xf9\x01\n" + - "\x17GetMyDiscussionsRequest\x12\x16\n" + - "\x06filter\x18\x01 \x01(\tR\x06filter\x12\x12\n" + - "\x04type\x18\x02 \x01(\tR\x04type\x12\x14\n" + - "\x05state\x18\x03 \x01(\tR\x05state\x12\x14\n" + - "\x05asset\x18\x04 \x01(\tR\x05asset\x12\x16\n" + - "\x06labels\x18\x05 \x01(\tR\x06labels\x12\x12\n" + - "\x04sort\x18\x06 \x01(\tR\x04sort\x12\x1c\n" + - "\tdirection\x18\a \x01(\tR\tdirection\x12\x1b\n" + - "\x04size\x18\b \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + - "\x06offset\x18\t \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"T\n" + - "\x18GetMyDiscussionsResponse\x128\n" + - "\x04data\x18\x01 \x03(\v2$.raystack.compass.v1beta1.DiscussionR\x04data\"\xff\x01\n" + - "\x15CreateTagAssetRequest\x12\x19\n" + - "\basset_id\x18\x01 \x01(\tR\aassetId\x12!\n" + - "\ftemplate_urn\x18\x02 \x01(\tR\vtemplateUrn\x12A\n" + - "\n" + - "tag_values\x18\x03 \x03(\v2\".raystack.compass.v1beta1.TagValueR\ttagValues\x122\n" + - "\x15template_display_name\x18\x04 \x01(\tR\x13templateDisplayName\x121\n" + - "\x14template_description\x18\x05 \x01(\tR\x13templateDescription\"K\n" + - "\x16CreateTagAssetResponse\x121\n" + - "\x04data\x18\x01 \x01(\v2\x1d.raystack.compass.v1beta1.TagR\x04data\"_\n" + - "\x1fGetTagByAssetAndTemplateRequest\x12\x19\n" + - "\basset_id\x18\x01 \x01(\tR\aassetId\x12!\n" + - "\ftemplate_urn\x18\x03 \x01(\tR\vtemplateUrn\"U\n" + - " GetTagByAssetAndTemplateResponse\x121\n" + - "\x04data\x18\x01 \x01(\v2\x1d.raystack.compass.v1beta1.TagR\x04data\"\xff\x01\n" + - "\x15UpdateTagAssetRequest\x12\x19\n" + - "\basset_id\x18\x01 \x01(\tR\aassetId\x12!\n" + - "\ftemplate_urn\x18\x02 \x01(\tR\vtemplateUrn\x12A\n" + - "\n" + - "tag_values\x18\x03 \x03(\v2\".raystack.compass.v1beta1.TagValueR\ttagValues\x122\n" + - "\x15template_display_name\x18\x04 \x01(\tR\x13templateDisplayName\x121\n" + - "\x14template_description\x18\x05 \x01(\tR\x13templateDescription\"K\n" + - "\x16UpdateTagAssetResponse\x121\n" + - "\x04data\x18\x01 \x01(\v2\x1d.raystack.compass.v1beta1.TagR\x04data\"U\n" + - "\x15DeleteTagAssetRequest\x12\x19\n" + - "\basset_id\x18\x01 \x01(\tR\aassetId\x12!\n" + - "\ftemplate_urn\x18\x02 \x01(\tR\vtemplateUrn\"\x18\n" + - "\x16DeleteTagAssetResponse\"5\n" + - "\x18GetAllTagsByAssetRequest\x12\x19\n" + - "\basset_id\x18\x01 \x01(\tR\aassetId\"N\n" + - "\x19GetAllTagsByAssetResponse\x121\n" + - "\x04data\x18\x01 \x03(\v2\x1d.raystack.compass.v1beta1.TagR\x04data\"-\n" + - "\x19GetAllTagTemplatesRequest\x12\x10\n" + - "\x03urn\x18\x01 \x01(\tR\x03urn\"W\n" + - "\x1aGetAllTagTemplatesResponse\x129\n" + - "\x04data\x18\x01 \x03(\v2%.raystack.compass.v1beta1.TagTemplateR\x04data\"\xb5\x01\n" + - "\x18CreateTagTemplateRequest\x12\x10\n" + - "\x03urn\x18\x01 \x01(\tR\x03urn\x12!\n" + - "\fdisplay_name\x18\x02 \x01(\tR\vdisplayName\x12 \n" + - "\vdescription\x18\x03 \x01(\tR\vdescription\x12B\n" + - "\x06fields\x18\x04 \x03(\v2*.raystack.compass.v1beta1.TagTemplateFieldR\x06fields\"V\n" + - "\x19CreateTagTemplateResponse\x129\n" + - "\x04data\x18\x01 \x01(\v2%.raystack.compass.v1beta1.TagTemplateR\x04data\":\n" + - "\x15GetTagTemplateRequest\x12!\n" + - "\ftemplate_urn\x18\x01 \x01(\tR\vtemplateUrn\"S\n" + - "\x16GetTagTemplateResponse\x129\n" + - "\x04data\x18\x01 \x01(\v2%.raystack.compass.v1beta1.TagTemplateR\x04data\"\xc6\x01\n" + - "\x18UpdateTagTemplateRequest\x12!\n" + - "\ftemplate_urn\x18\x01 \x01(\tR\vtemplateUrn\x12!\n" + - "\fdisplay_name\x18\x02 \x01(\tR\vdisplayName\x12 \n" + - "\vdescription\x18\x03 \x01(\tR\vdescription\x12B\n" + - "\x06fields\x18\x04 \x03(\v2*.raystack.compass.v1beta1.TagTemplateFieldR\x06fields\"V\n" + - "\x19UpdateTagTemplateResponse\x129\n" + - "\x04data\x18\x01 \x01(\v2%.raystack.compass.v1beta1.TagTemplateR\x04data\"=\n" + - "\x18DeleteTagTemplateRequest\x12!\n" + - "\ftemplate_urn\x18\x01 \x01(\tR\vtemplateUrn\"\x1b\n" + - "\x19DeleteTagTemplateResponse\"\x90\x01\n" + - "\x16CreateNamespaceRequest\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12\x1b\n" + - "\x04name\x18\x02 \x01(\tB\a\xbaH\x04r\x02\x10\x03R\x04name\x12\x14\n" + - "\x05state\x18\x03 \x01(\tR\x05state\x123\n" + - "\bmetadata\x18\x04 \x01(\v2\x17.google.protobuf.StructR\bmetadata\")\n" + - "\x17CreateNamespaceResponse\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\"'\n" + - "\x13GetNamespaceRequest\x12\x10\n" + - "\x03urn\x18\x01 \x01(\tR\x03urn\"Y\n" + - "\x14GetNamespaceResponse\x12A\n" + - "\tnamespace\x18\x01 \x01(\v2#.raystack.compass.v1beta1.NamespaceR\tnamespace\"u\n" + - "\x16UpdateNamespaceRequest\x12\x10\n" + - "\x03urn\x18\x01 \x01(\tR\x03urn\x12\x14\n" + - "\x05state\x18\x02 \x01(\tR\x05state\x123\n" + - "\bmetadata\x18\x03 \x01(\v2\x17.google.protobuf.StructR\bmetadata\"\x19\n" + - "\x17UpdateNamespaceResponse\"\x17\n" + - "\x15ListNamespacesRequest\"]\n" + - "\x16ListNamespacesResponse\x12C\n" + - "\n" + - "namespaces\x18\x01 \x03(\v2#.raystack.compass.v1beta1.NamespaceR\n" + - "namespaces\"\xd2\x01\n" + + "&raystack/compass/v1beta1/service.proto\x12\x18raystack.compass.v1beta1\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1bbuf/validate/validate.proto\"\xd2\x01\n" + "\x04User\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + "\x04uuid\x18\x02 \x01(\tR\x04uuid\x12\x14\n" + @@ -8274,133 +2689,7 @@ const file_raystack_compass_v1beta1_service_proto_rawDesc = "" + "\n" + "created_at\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" + "\n" + - "updated_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\"\x84\x01\n" + - "\x06Change\x12\x12\n" + - "\x04type\x18\x01 \x01(\tR\x04type\x12\x12\n" + - "\x04path\x18\x02 \x03(\tR\x04path\x12*\n" + - "\x04from\x18\x03 \x01(\v2\x16.google.protobuf.ValueR\x04from\x12&\n" + - "\x02to\x18\x04 \x01(\v2\x16.google.protobuf.ValueR\x02to\"\xeb\x05\n" + - "\x05Asset\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12\x10\n" + - "\x03urn\x18\x02 \x01(\tR\x03urn\x12\x12\n" + - "\x04type\x18\x03 \x01(\tR\x04type\x12\x18\n" + - "\aservice\x18\x04 \x01(\tR\aservice\x12\x12\n" + - "\x04name\x18\x05 \x01(\tR\x04name\x12 \n" + - "\vdescription\x18\x06 \x01(\tR\vdescription\x12+\n" + - "\x04data\x18\a \x01(\v2\x17.google.protobuf.StructR\x04data\x12C\n" + - "\x06labels\x18\b \x03(\v2+.raystack.compass.v1beta1.Asset.LabelsEntryR\x06labels\x126\n" + - "\x06owners\x18\t \x03(\v2\x1e.raystack.compass.v1beta1.UserR\x06owners\x12\x18\n" + - "\aversion\x18\n" + - " \x01(\tR\aversion\x12=\n" + - "\n" + - "updated_by\x18\v \x01(\v2\x1e.raystack.compass.v1beta1.UserR\tupdatedBy\x12>\n" + - "\tchangelog\x18\f \x03(\v2 .raystack.compass.v1beta1.ChangeR\tchangelog\x129\n" + - "\n" + - "created_at\x18\r \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" + - "\n" + - "updated_at\x18\x0e \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\x12\x10\n" + - "\x03url\x18\x0f \x01(\tR\x03url\x127\n" + - "\x06probes\x18\x10 \x03(\v2\x1f.raystack.compass.v1beta1.ProbeR\x06probes\x12\x1d\n" + - "\n" + - "is_deleted\x18\x11 \x01(\bR\tisDeleted\x1a9\n" + - "\vLabelsEntry\x12\x10\n" + - "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x9b\x02\n" + - "\x05Probe\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12\x1b\n" + - "\tasset_urn\x18\x02 \x01(\tR\bassetUrn\x12\x16\n" + - "\x06status\x18\x03 \x01(\tR\x06status\x12#\n" + - "\rstatus_reason\x18\x04 \x01(\tR\fstatusReason\x123\n" + - "\bmetadata\x18\x05 \x01(\v2\x17.google.protobuf.StructR\bmetadata\x128\n" + - "\ttimestamp\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x129\n" + - "\n" + - "created_at\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\"\xea\x02\n" + - "\n" + - "Discussion\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12\x14\n" + - "\x05title\x18\x02 \x01(\tR\x05title\x12\x12\n" + - "\x04body\x18\x03 \x01(\tR\x04body\x12\x12\n" + - "\x04type\x18\x04 \x01(\tR\x04type\x12\x14\n" + - "\x05state\x18\x05 \x01(\tR\x05state\x12\x16\n" + - "\x06labels\x18\x06 \x03(\tR\x06labels\x12\x16\n" + - "\x06assets\x18\a \x03(\tR\x06assets\x12\x1c\n" + - "\tassignees\x18\b \x03(\tR\tassignees\x124\n" + - "\x05owner\x18\t \x01(\v2\x1e.raystack.compass.v1beta1.UserR\x05owner\x129\n" + - "\n" + - "created_at\x18\n" + - " \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" + - "\n" + - "updated_at\x18\v \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\"\xbd\x02\n" + - "\aComment\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12#\n" + - "\rdiscussion_id\x18\x02 \x01(\tR\fdiscussionId\x12\x12\n" + - "\x04body\x18\x03 \x01(\tR\x04body\x124\n" + - "\x05owner\x18\x04 \x01(\v2\x1e.raystack.compass.v1beta1.UserR\x05owner\x12=\n" + - "\n" + - "updated_by\x18\x05 \x01(\v2\x1e.raystack.compass.v1beta1.UserR\tupdatedBy\x129\n" + - "\n" + - "created_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" + - "\n" + - "updated_at\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\"j\n" + - "\vLineageEdge\x12\x16\n" + - "\x06source\x18\x01 \x01(\tR\x06source\x12\x16\n" + - "\x06target\x18\x02 \x01(\tR\x06target\x12+\n" + - "\x04prop\x18\x03 \x01(\v2\x17.google.protobuf.StructR\x04prop\"U\n" + - "\vLineageNode\x12\x10\n" + - "\x03urn\x18\x01 \x01(\tR\x03urn\x12\x16\n" + - "\x04type\x18\x02 \x01(\tB\x02\x18\x01R\x04type\x12\x1c\n" + - "\aservice\x18\x03 \x01(\tB\x02\x18\x01R\aservice\"\xed\x01\n" + - "\x03Tag\x12\x19\n" + - "\basset_id\x18\x01 \x01(\tR\aassetId\x12!\n" + - "\ftemplate_urn\x18\x02 \x01(\tR\vtemplateUrn\x12A\n" + - "\n" + - "tag_values\x18\x03 \x03(\v2\".raystack.compass.v1beta1.TagValueR\ttagValues\x122\n" + - "\x15template_display_name\x18\x04 \x01(\tR\x13templateDisplayName\x121\n" + - "\x14template_description\x18\x05 \x01(\tR\x13templateDescription\"\xc0\x03\n" + - "\bTagValue\x12\x19\n" + - "\bfield_id\x18\x01 \x01(\rR\afieldId\x127\n" + - "\vfield_value\x18\x02 \x01(\v2\x16.google.protobuf.ValueR\n" + - "fieldValue\x12\x1b\n" + - "\tfield_urn\x18\x03 \x01(\tR\bfieldUrn\x12,\n" + - "\x12field_display_name\x18\x04 \x01(\tR\x10fieldDisplayName\x12+\n" + - "\x11field_description\x18\x05 \x01(\tR\x10fieldDescription\x12&\n" + - "\x0ffield_data_type\x18\x06 \x01(\tR\rfieldDataType\x12#\n" + - "\rfield_options\x18\a \x03(\tR\ffieldOptions\x12%\n" + - "\x0efield_required\x18\b \x01(\bR\rfieldRequired\x129\n" + - "\n" + - "created_at\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" + - "\n" + - "updated_at\x18\n" + - " \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\"\x9e\x02\n" + - "\vTagTemplate\x12\x10\n" + - "\x03urn\x18\x01 \x01(\tR\x03urn\x12!\n" + - "\fdisplay_name\x18\x02 \x01(\tR\vdisplayName\x12 \n" + - "\vdescription\x18\x03 \x01(\tR\vdescription\x12B\n" + - "\x06fields\x18\x04 \x03(\v2*.raystack.compass.v1beta1.TagTemplateFieldR\x06fields\x129\n" + - "\n" + - "created_at\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" + - "\n" + - "updated_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\"\xc2\x02\n" + - "\x10TagTemplateField\x12\x0e\n" + - "\x02id\x18\x01 \x01(\rR\x02id\x12\x10\n" + - "\x03urn\x18\x02 \x01(\tR\x03urn\x12!\n" + - "\fdisplay_name\x18\x03 \x01(\tR\vdisplayName\x12 \n" + - "\vdescription\x18\x04 \x01(\tR\vdescription\x12\x1b\n" + - "\tdata_type\x18\x05 \x01(\tR\bdataType\x12\x18\n" + - "\aoptions\x18\x06 \x03(\tR\aoptions\x12\x1a\n" + - "\brequired\x18\a \x01(\bR\brequired\x129\n" + - "\n" + - "created_at\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" + - "\n" + - "updated_at\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\"0\n" + - "\x04Type\x12\x12\n" + - "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" + - "\x05count\x18\x02 \x01(\rR\x05count\"\x83\x01\n" + - "\tNamespace\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12\x1b\n" + - "\x04name\x18\x02 \x01(\tB\a\xbaH\x04r\x02\x10\x03R\x04name\x12\x14\n" + - "\x05state\x18\x03 \x01(\tR\x05state\x123\n" + - "\bmetadata\x18\x04 \x01(\v2\x17.google.protobuf.StructR\bmetadata\"\xad\x03\n" + + "updated_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\"\xad\x03\n" + "\x06Entity\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x10\n" + "\x03urn\x18\x02 \x01(\tR\x03urn\x12\x12\n" + @@ -8434,7 +2723,15 @@ const file_raystack_compass_v1beta1_service_proto_rawDesc = "" + "valid_from\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\tvalidFrom\x125\n" + "\bvalid_to\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\avalidTo\x129\n" + "\n" + - "created_at\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\"\x91\x01\n" + + "created_at\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\"0\n" + + "\x04Type\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" + + "\x05count\x18\x02 \x01(\rR\x05count\"\x83\x01\n" + + "\tNamespace\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1b\n" + + "\x04name\x18\x02 \x01(\tB\a\xbaH\x04r\x02\x10\x03R\x04name\x12\x14\n" + + "\x05state\x18\x03 \x01(\tR\x05state\x123\n" + + "\bmetadata\x18\x04 \x01(\v2\x17.google.protobuf.StructR\bmetadata\"\x91\x01\n" + "\x15GetAllEntitiesRequest\x12\x14\n" + "\x05types\x18\x01 \x01(\tR\x05types\x12\x16\n" + "\x06source\x18\x02 \x01(\tR\x06source\x12\f\n" + @@ -8518,52 +2815,57 @@ const file_raystack_compass_v1beta1_service_proto_rawDesc = "" + "\n" + "target_urn\x18\x02 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\ttargetUrn\x12\x1b\n" + "\x04type\x18\x03 \x01(\tB\a\xbaH\x04r\x02\x10\x01R\x04type\"\x14\n" + - "\x12DeleteEdgeResponse2\xc53\n" + - "\x0eCompassService\x12~\n" + - "\x11GetAllDiscussions\x122.raystack.compass.v1beta1.GetAllDiscussionsRequest\x1a3.raystack.compass.v1beta1.GetAllDiscussionsResponse\"\x00\x12{\n" + - "\x10CreateDiscussion\x121.raystack.compass.v1beta1.CreateDiscussionRequest\x1a2.raystack.compass.v1beta1.CreateDiscussionResponse\"\x00\x12r\n" + - "\rGetDiscussion\x12..raystack.compass.v1beta1.GetDiscussionRequest\x1a/.raystack.compass.v1beta1.GetDiscussionResponse\"\x00\x12x\n" + - "\x0fPatchDiscussion\x120.raystack.compass.v1beta1.PatchDiscussionRequest\x1a1.raystack.compass.v1beta1.PatchDiscussionResponse\"\x00\x12r\n" + - "\rCreateComment\x12..raystack.compass.v1beta1.CreateCommentRequest\x1a/.raystack.compass.v1beta1.CreateCommentResponse\"\x00\x12u\n" + - "\x0eGetAllComments\x12/.raystack.compass.v1beta1.GetAllCommentsRequest\x1a0.raystack.compass.v1beta1.GetAllCommentsResponse\"\x00\x12i\n" + + "\x12DeleteEdgeResponse\"0\n" + + "\x11StarEntityRequest\x12\x1b\n" + + "\tentity_id\x18\x01 \x01(\tR\bentityId\"$\n" + + "\x12StarEntityResponse\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"2\n" + + "\x13UnstarEntityRequest\x12\x1b\n" + + "\tentity_id\x18\x01 \x01(\tR\bentityId\"\x16\n" + + "\x14UnstarEntityResponse\"v\n" + + "\x1dGetUserStarredEntitiesRequest\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\x12\x1b\n" + + "\x04size\x18\x02 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + + "\x06offset\x18\x03 \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"V\n" + + "\x1eGetUserStarredEntitiesResponse\x124\n" + + "\x04data\x18\x01 \x03(\v2 .raystack.compass.v1beta1.EntityR\x04data\"[\n" + + "\x1bGetMyStarredEntitiesRequest\x12\x1b\n" + + "\x04size\x18\x01 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + + "\x06offset\x18\x02 \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"T\n" + + "\x1cGetMyStarredEntitiesResponse\x124\n" + + "\x04data\x18\x01 \x03(\v2 .raystack.compass.v1beta1.EntityR\x04data\"8\n" + + "\x19GetMyStarredEntityRequest\x12\x1b\n" + + "\tentity_id\x18\x01 \x01(\tR\bentityId\"R\n" + + "\x1aGetMyStarredEntityResponse\x124\n" + + "\x04data\x18\x01 \x01(\v2 .raystack.compass.v1beta1.EntityR\x04data\"j\n" + + "\x1aGetEntityStargazersRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1b\n" + + "\x04size\x18\x02 \x01(\rB\a\xbaH\x04*\x02(\x00R\x04size\x12\x1f\n" + + "\x06offset\x18\x03 \x01(\rB\a\xbaH\x04*\x02(\x00R\x06offset\"Q\n" + + "\x1bGetEntityStargazersResponse\x122\n" + + "\x04data\x18\x01 \x03(\v2\x1e.raystack.compass.v1beta1.UserR\x04data\"\x90\x01\n" + + "\x16CreateNamespaceRequest\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1b\n" + + "\x04name\x18\x02 \x01(\tB\a\xbaH\x04r\x02\x10\x03R\x04name\x12\x14\n" + + "\x05state\x18\x03 \x01(\tR\x05state\x123\n" + + "\bmetadata\x18\x04 \x01(\v2\x17.google.protobuf.StructR\bmetadata\")\n" + + "\x17CreateNamespaceResponse\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\"'\n" + + "\x13GetNamespaceRequest\x12\x10\n" + + "\x03urn\x18\x01 \x01(\tR\x03urn\"Y\n" + + "\x14GetNamespaceResponse\x12A\n" + + "\tnamespace\x18\x01 \x01(\v2#.raystack.compass.v1beta1.NamespaceR\tnamespace\"u\n" + + "\x16UpdateNamespaceRequest\x12\x10\n" + + "\x03urn\x18\x01 \x01(\tR\x03urn\x12\x14\n" + + "\x05state\x18\x02 \x01(\tR\x05state\x123\n" + + "\bmetadata\x18\x03 \x01(\v2\x17.google.protobuf.StructR\bmetadata\"\x19\n" + + "\x17UpdateNamespaceResponse\"\x17\n" + + "\x15ListNamespacesRequest\"]\n" + + "\x16ListNamespacesResponse\x12C\n" + "\n" + - "GetComment\x12+.raystack.compass.v1beta1.GetCommentRequest\x1a,.raystack.compass.v1beta1.GetCommentResponse\"\x00\x12r\n" + - "\rUpdateComment\x12..raystack.compass.v1beta1.UpdateCommentRequest\x1a/.raystack.compass.v1beta1.UpdateCommentResponse\"\x00\x12r\n" + - "\rDeleteComment\x12..raystack.compass.v1beta1.DeleteCommentRequest\x1a/.raystack.compass.v1beta1.DeleteCommentResponse\"\x00\x12o\n" + - "\fSearchAssets\x12-.raystack.compass.v1beta1.SearchAssetsRequest\x1a..raystack.compass.v1beta1.SearchAssetsResponse\"\x00\x12r\n" + - "\rSuggestAssets\x12..raystack.compass.v1beta1.SuggestAssetsRequest\x1a/.raystack.compass.v1beta1.SuggestAssetsResponse\"\x00\x12l\n" + - "\vGroupAssets\x12,.raystack.compass.v1beta1.GroupAssetsRequest\x1a-.raystack.compass.v1beta1.GroupAssetsResponse\"\x00\x12c\n" + - "\bGetGraph\x12).raystack.compass.v1beta1.GetGraphRequest\x1a*.raystack.compass.v1beta1.GetGraphResponse\"\x00\x12l\n" + - "\vGetAllTypes\x12,.raystack.compass.v1beta1.GetAllTypesRequest\x1a-.raystack.compass.v1beta1.GetAllTypesResponse\"\x00\x12o\n" + - "\fGetAllAssets\x12-.raystack.compass.v1beta1.GetAllAssetsRequest\x1a..raystack.compass.v1beta1.GetAllAssetsResponse\"\x00\x12o\n" + - "\fGetAssetByID\x12-.raystack.compass.v1beta1.GetAssetByIDRequest\x1a..raystack.compass.v1beta1.GetAssetByIDResponse\"\x00\x12l\n" + - "\vUpsertAsset\x12,.raystack.compass.v1beta1.UpsertAssetRequest\x1a-.raystack.compass.v1beta1.UpsertAssetResponse\"\x00\x12{\n" + - "\x10UpsertPatchAsset\x121.raystack.compass.v1beta1.UpsertPatchAssetRequest\x1a2.raystack.compass.v1beta1.UpsertPatchAssetResponse\"\x00\x12l\n" + - "\vDeleteAsset\x12,.raystack.compass.v1beta1.DeleteAssetRequest\x1a-.raystack.compass.v1beta1.DeleteAssetResponse\"\x00\x12\x81\x01\n" + - "\x12GetAssetStargazers\x123.raystack.compass.v1beta1.GetAssetStargazersRequest\x1a4.raystack.compass.v1beta1.GetAssetStargazersResponse\"\x00\x12\x8d\x01\n" + - "\x16GetAssetVersionHistory\x127.raystack.compass.v1beta1.GetAssetVersionHistoryRequest\x1a8.raystack.compass.v1beta1.GetAssetVersionHistoryResponse\"\x00\x12~\n" + - "\x11GetAssetByVersion\x122.raystack.compass.v1beta1.GetAssetByVersionRequest\x1a3.raystack.compass.v1beta1.GetAssetByVersionResponse\"\x00\x12{\n" + - "\x10CreateAssetProbe\x121.raystack.compass.v1beta1.CreateAssetProbeRequest\x1a2.raystack.compass.v1beta1.CreateAssetProbeResponse\"\x00\x12\x87\x01\n" + - "\x14GetUserStarredAssets\x125.raystack.compass.v1beta1.GetUserStarredAssetsRequest\x1a6.raystack.compass.v1beta1.GetUserStarredAssetsResponse\"\x00\x12\x81\x01\n" + - "\x12GetMyStarredAssets\x123.raystack.compass.v1beta1.GetMyStarredAssetsRequest\x1a4.raystack.compass.v1beta1.GetMyStarredAssetsResponse\"\x00\x12~\n" + - "\x11GetMyStarredAsset\x122.raystack.compass.v1beta1.GetMyStarredAssetRequest\x1a3.raystack.compass.v1beta1.GetMyStarredAssetResponse\"\x00\x12f\n" + - "\tStarAsset\x12*.raystack.compass.v1beta1.StarAssetRequest\x1a+.raystack.compass.v1beta1.StarAssetResponse\"\x00\x12l\n" + - "\vUnstarAsset\x12,.raystack.compass.v1beta1.UnstarAssetRequest\x1a-.raystack.compass.v1beta1.UnstarAssetResponse\"\x00\x12{\n" + - "\x10GetMyDiscussions\x121.raystack.compass.v1beta1.GetMyDiscussionsRequest\x1a2.raystack.compass.v1beta1.GetMyDiscussionsResponse\"\x00\x12u\n" + - "\x0eCreateTagAsset\x12/.raystack.compass.v1beta1.CreateTagAssetRequest\x1a0.raystack.compass.v1beta1.CreateTagAssetResponse\"\x00\x12\x93\x01\n" + - "\x18GetTagByAssetAndTemplate\x129.raystack.compass.v1beta1.GetTagByAssetAndTemplateRequest\x1a:.raystack.compass.v1beta1.GetTagByAssetAndTemplateResponse\"\x00\x12u\n" + - "\x0eUpdateTagAsset\x12/.raystack.compass.v1beta1.UpdateTagAssetRequest\x1a0.raystack.compass.v1beta1.UpdateTagAssetResponse\"\x00\x12u\n" + - "\x0eDeleteTagAsset\x12/.raystack.compass.v1beta1.DeleteTagAssetRequest\x1a0.raystack.compass.v1beta1.DeleteTagAssetResponse\"\x00\x12~\n" + - "\x11GetAllTagsByAsset\x122.raystack.compass.v1beta1.GetAllTagsByAssetRequest\x1a3.raystack.compass.v1beta1.GetAllTagsByAssetResponse\"\x00\x12\x81\x01\n" + - "\x12GetAllTagTemplates\x123.raystack.compass.v1beta1.GetAllTagTemplatesRequest\x1a4.raystack.compass.v1beta1.GetAllTagTemplatesResponse\"\x00\x12~\n" + - "\x11CreateTagTemplate\x122.raystack.compass.v1beta1.CreateTagTemplateRequest\x1a3.raystack.compass.v1beta1.CreateTagTemplateResponse\"\x00\x12u\n" + - "\x0eGetTagTemplate\x12/.raystack.compass.v1beta1.GetTagTemplateRequest\x1a0.raystack.compass.v1beta1.GetTagTemplateResponse\"\x00\x12~\n" + - "\x11UpdateTagTemplate\x122.raystack.compass.v1beta1.UpdateTagTemplateRequest\x1a3.raystack.compass.v1beta1.UpdateTagTemplateResponse\"\x00\x12~\n" + - "\x11DeleteTagTemplate\x122.raystack.compass.v1beta1.DeleteTagTemplateRequest\x1a3.raystack.compass.v1beta1.DeleteTagTemplateResponse\"\x00\x12x\n" + - "\x0fCreateNamespace\x120.raystack.compass.v1beta1.CreateNamespaceRequest\x1a1.raystack.compass.v1beta1.CreateNamespaceResponse\"\x00\x12o\n" + - "\fGetNamespace\x12-.raystack.compass.v1beta1.GetNamespaceRequest\x1a..raystack.compass.v1beta1.GetNamespaceResponse\"\x00\x12x\n" + - "\x0fUpdateNamespace\x120.raystack.compass.v1beta1.UpdateNamespaceRequest\x1a1.raystack.compass.v1beta1.UpdateNamespaceResponse\"\x00\x12u\n" + - "\x0eListNamespaces\x12/.raystack.compass.v1beta1.ListNamespacesRequest\x1a0.raystack.compass.v1beta1.ListNamespacesResponse\"\x00\x12u\n" + + "namespaces\x18\x01 \x03(\v2#.raystack.compass.v1beta1.NamespaceR\n" + + "namespaces2\xd4\x14\n" + + "\x0eCompassService\x12u\n" + "\x0eGetAllEntities\x12/.raystack.compass.v1beta1.GetAllEntitiesRequest\x1a0.raystack.compass.v1beta1.GetAllEntitiesResponse\"\x00\x12r\n" + "\rGetEntityByID\x12..raystack.compass.v1beta1.GetEntityByIDRequest\x1a/.raystack.compass.v1beta1.GetEntityByIDResponse\"\x00\x12o\n" + "\fUpsertEntity\x12-.raystack.compass.v1beta1.UpsertEntityRequest\x1a..raystack.compass.v1beta1.UpsertEntityResponse\"\x00\x12o\n" + @@ -8577,7 +2879,18 @@ const file_raystack_compass_v1beta1_service_proto_rawDesc = "" + "UpsertEdge\x12+.raystack.compass.v1beta1.UpsertEdgeRequest\x1a,.raystack.compass.v1beta1.UpsertEdgeResponse\"\x00\x12c\n" + "\bGetEdges\x12).raystack.compass.v1beta1.GetEdgesRequest\x1a*.raystack.compass.v1beta1.GetEdgesResponse\"\x00\x12i\n" + "\n" + - "DeleteEdge\x12+.raystack.compass.v1beta1.DeleteEdgeRequest\x1a,.raystack.compass.v1beta1.DeleteEdgeResponse\"\x00B\xf7\x01\n" + + "DeleteEdge\x12+.raystack.compass.v1beta1.DeleteEdgeRequest\x1a,.raystack.compass.v1beta1.DeleteEdgeResponse\"\x00\x12i\n" + + "\n" + + "StarEntity\x12+.raystack.compass.v1beta1.StarEntityRequest\x1a,.raystack.compass.v1beta1.StarEntityResponse\"\x00\x12o\n" + + "\fUnstarEntity\x12-.raystack.compass.v1beta1.UnstarEntityRequest\x1a..raystack.compass.v1beta1.UnstarEntityResponse\"\x00\x12\x8d\x01\n" + + "\x16GetUserStarredEntities\x127.raystack.compass.v1beta1.GetUserStarredEntitiesRequest\x1a8.raystack.compass.v1beta1.GetUserStarredEntitiesResponse\"\x00\x12\x87\x01\n" + + "\x14GetMyStarredEntities\x125.raystack.compass.v1beta1.GetMyStarredEntitiesRequest\x1a6.raystack.compass.v1beta1.GetMyStarredEntitiesResponse\"\x00\x12\x81\x01\n" + + "\x12GetMyStarredEntity\x123.raystack.compass.v1beta1.GetMyStarredEntityRequest\x1a4.raystack.compass.v1beta1.GetMyStarredEntityResponse\"\x00\x12\x84\x01\n" + + "\x13GetEntityStargazers\x124.raystack.compass.v1beta1.GetEntityStargazersRequest\x1a5.raystack.compass.v1beta1.GetEntityStargazersResponse\"\x00\x12x\n" + + "\x0fCreateNamespace\x120.raystack.compass.v1beta1.CreateNamespaceRequest\x1a1.raystack.compass.v1beta1.CreateNamespaceResponse\"\x00\x12o\n" + + "\fGetNamespace\x12-.raystack.compass.v1beta1.GetNamespaceRequest\x1a..raystack.compass.v1beta1.GetNamespaceResponse\"\x00\x12x\n" + + "\x0fUpdateNamespace\x120.raystack.compass.v1beta1.UpdateNamespaceRequest\x1a1.raystack.compass.v1beta1.UpdateNamespaceResponse\"\x00\x12u\n" + + "\x0eListNamespaces\x12/.raystack.compass.v1beta1.ListNamespacesRequest\x1a0.raystack.compass.v1beta1.ListNamespacesResponse\"\x00B\xf7\x01\n" + "\x1ccom.raystack.compass.v1beta1B\fServiceProtoP\x01ZGgithub.com/raystack/compass/gen/raystack/compass/v1beta1;compassv1beta1\xa2\x02\x03RCX\xaa\x02\x18Raystack.Compass.V1beta1\xca\x02\x18Raystack\\Compass\\V1beta1\xe2\x02$Raystack\\Compass\\V1beta1\\GPBMetadata\xea\x02\x1aRaystack::Compass::V1beta1b\x06proto3" var ( @@ -8592,388 +2905,142 @@ func file_raystack_compass_v1beta1_service_proto_rawDescGZIP() []byte { return file_raystack_compass_v1beta1_service_proto_rawDescData } -var file_raystack_compass_v1beta1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 143) +var file_raystack_compass_v1beta1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 49) var file_raystack_compass_v1beta1_service_proto_goTypes = []any{ - (*GetAllDiscussionsRequest)(nil), // 0: raystack.compass.v1beta1.GetAllDiscussionsRequest - (*GetAllDiscussionsResponse)(nil), // 1: raystack.compass.v1beta1.GetAllDiscussionsResponse - (*CreateDiscussionRequest)(nil), // 2: raystack.compass.v1beta1.CreateDiscussionRequest - (*CreateDiscussionResponse)(nil), // 3: raystack.compass.v1beta1.CreateDiscussionResponse - (*GetDiscussionRequest)(nil), // 4: raystack.compass.v1beta1.GetDiscussionRequest - (*GetDiscussionResponse)(nil), // 5: raystack.compass.v1beta1.GetDiscussionResponse - (*PatchDiscussionRequest)(nil), // 6: raystack.compass.v1beta1.PatchDiscussionRequest - (*CreateCommentRequest)(nil), // 7: raystack.compass.v1beta1.CreateCommentRequest - (*PatchDiscussionResponse)(nil), // 8: raystack.compass.v1beta1.PatchDiscussionResponse - (*CreateCommentResponse)(nil), // 9: raystack.compass.v1beta1.CreateCommentResponse - (*GetAllCommentsRequest)(nil), // 10: raystack.compass.v1beta1.GetAllCommentsRequest - (*GetAllCommentsResponse)(nil), // 11: raystack.compass.v1beta1.GetAllCommentsResponse - (*GetCommentRequest)(nil), // 12: raystack.compass.v1beta1.GetCommentRequest - (*GetCommentResponse)(nil), // 13: raystack.compass.v1beta1.GetCommentResponse - (*UpdateCommentRequest)(nil), // 14: raystack.compass.v1beta1.UpdateCommentRequest - (*UpdateCommentResponse)(nil), // 15: raystack.compass.v1beta1.UpdateCommentResponse - (*DeleteCommentRequest)(nil), // 16: raystack.compass.v1beta1.DeleteCommentRequest - (*DeleteCommentResponse)(nil), // 17: raystack.compass.v1beta1.DeleteCommentResponse - (*SearchAssetsRequest)(nil), // 18: raystack.compass.v1beta1.SearchAssetsRequest - (*SearchFlags)(nil), // 19: raystack.compass.v1beta1.SearchFlags - (*SearchAssetsResponse)(nil), // 20: raystack.compass.v1beta1.SearchAssetsResponse - (*SuggestAssetsRequest)(nil), // 21: raystack.compass.v1beta1.SuggestAssetsRequest - (*SuggestAssetsResponse)(nil), // 22: raystack.compass.v1beta1.SuggestAssetsResponse - (*GroupAssetsRequest)(nil), // 23: raystack.compass.v1beta1.GroupAssetsRequest - (*GroupAssetsResponse)(nil), // 24: raystack.compass.v1beta1.GroupAssetsResponse - (*AssetGroup)(nil), // 25: raystack.compass.v1beta1.AssetGroup - (*GroupField)(nil), // 26: raystack.compass.v1beta1.GroupField - (*GetGraphRequest)(nil), // 27: raystack.compass.v1beta1.GetGraphRequest - (*GetGraphResponse)(nil), // 28: raystack.compass.v1beta1.GetGraphResponse - (*GetAllTypesRequest)(nil), // 29: raystack.compass.v1beta1.GetAllTypesRequest - (*GetAllTypesResponse)(nil), // 30: raystack.compass.v1beta1.GetAllTypesResponse - (*GetAllAssetsRequest)(nil), // 31: raystack.compass.v1beta1.GetAllAssetsRequest - (*GetAllAssetsResponse)(nil), // 32: raystack.compass.v1beta1.GetAllAssetsResponse - (*GetAssetByIDRequest)(nil), // 33: raystack.compass.v1beta1.GetAssetByIDRequest - (*GetAssetByIDResponse)(nil), // 34: raystack.compass.v1beta1.GetAssetByIDResponse - (*UpsertAssetRequest)(nil), // 35: raystack.compass.v1beta1.UpsertAssetRequest - (*UpsertAssetResponse)(nil), // 36: raystack.compass.v1beta1.UpsertAssetResponse - (*UpsertPatchAssetRequest)(nil), // 37: raystack.compass.v1beta1.UpsertPatchAssetRequest - (*UpsertPatchAssetResponse)(nil), // 38: raystack.compass.v1beta1.UpsertPatchAssetResponse - (*DeleteAssetRequest)(nil), // 39: raystack.compass.v1beta1.DeleteAssetRequest - (*DeleteAssetResponse)(nil), // 40: raystack.compass.v1beta1.DeleteAssetResponse - (*GetAssetStargazersRequest)(nil), // 41: raystack.compass.v1beta1.GetAssetStargazersRequest - (*GetAssetStargazersResponse)(nil), // 42: raystack.compass.v1beta1.GetAssetStargazersResponse - (*GetAssetVersionHistoryRequest)(nil), // 43: raystack.compass.v1beta1.GetAssetVersionHistoryRequest - (*GetAssetVersionHistoryResponse)(nil), // 44: raystack.compass.v1beta1.GetAssetVersionHistoryResponse - (*GetAssetByVersionRequest)(nil), // 45: raystack.compass.v1beta1.GetAssetByVersionRequest - (*GetAssetByVersionResponse)(nil), // 46: raystack.compass.v1beta1.GetAssetByVersionResponse - (*CreateAssetProbeRequest)(nil), // 47: raystack.compass.v1beta1.CreateAssetProbeRequest - (*CreateAssetProbeResponse)(nil), // 48: raystack.compass.v1beta1.CreateAssetProbeResponse - (*GetUserStarredAssetsRequest)(nil), // 49: raystack.compass.v1beta1.GetUserStarredAssetsRequest - (*GetUserStarredAssetsResponse)(nil), // 50: raystack.compass.v1beta1.GetUserStarredAssetsResponse - (*GetMyStarredAssetsRequest)(nil), // 51: raystack.compass.v1beta1.GetMyStarredAssetsRequest - (*GetMyStarredAssetsResponse)(nil), // 52: raystack.compass.v1beta1.GetMyStarredAssetsResponse - (*GetMyStarredAssetRequest)(nil), // 53: raystack.compass.v1beta1.GetMyStarredAssetRequest - (*GetMyStarredAssetResponse)(nil), // 54: raystack.compass.v1beta1.GetMyStarredAssetResponse - (*StarAssetRequest)(nil), // 55: raystack.compass.v1beta1.StarAssetRequest - (*StarAssetResponse)(nil), // 56: raystack.compass.v1beta1.StarAssetResponse - (*UnstarAssetRequest)(nil), // 57: raystack.compass.v1beta1.UnstarAssetRequest - (*UnstarAssetResponse)(nil), // 58: raystack.compass.v1beta1.UnstarAssetResponse - (*GetMyDiscussionsRequest)(nil), // 59: raystack.compass.v1beta1.GetMyDiscussionsRequest - (*GetMyDiscussionsResponse)(nil), // 60: raystack.compass.v1beta1.GetMyDiscussionsResponse - (*CreateTagAssetRequest)(nil), // 61: raystack.compass.v1beta1.CreateTagAssetRequest - (*CreateTagAssetResponse)(nil), // 62: raystack.compass.v1beta1.CreateTagAssetResponse - (*GetTagByAssetAndTemplateRequest)(nil), // 63: raystack.compass.v1beta1.GetTagByAssetAndTemplateRequest - (*GetTagByAssetAndTemplateResponse)(nil), // 64: raystack.compass.v1beta1.GetTagByAssetAndTemplateResponse - (*UpdateTagAssetRequest)(nil), // 65: raystack.compass.v1beta1.UpdateTagAssetRequest - (*UpdateTagAssetResponse)(nil), // 66: raystack.compass.v1beta1.UpdateTagAssetResponse - (*DeleteTagAssetRequest)(nil), // 67: raystack.compass.v1beta1.DeleteTagAssetRequest - (*DeleteTagAssetResponse)(nil), // 68: raystack.compass.v1beta1.DeleteTagAssetResponse - (*GetAllTagsByAssetRequest)(nil), // 69: raystack.compass.v1beta1.GetAllTagsByAssetRequest - (*GetAllTagsByAssetResponse)(nil), // 70: raystack.compass.v1beta1.GetAllTagsByAssetResponse - (*GetAllTagTemplatesRequest)(nil), // 71: raystack.compass.v1beta1.GetAllTagTemplatesRequest - (*GetAllTagTemplatesResponse)(nil), // 72: raystack.compass.v1beta1.GetAllTagTemplatesResponse - (*CreateTagTemplateRequest)(nil), // 73: raystack.compass.v1beta1.CreateTagTemplateRequest - (*CreateTagTemplateResponse)(nil), // 74: raystack.compass.v1beta1.CreateTagTemplateResponse - (*GetTagTemplateRequest)(nil), // 75: raystack.compass.v1beta1.GetTagTemplateRequest - (*GetTagTemplateResponse)(nil), // 76: raystack.compass.v1beta1.GetTagTemplateResponse - (*UpdateTagTemplateRequest)(nil), // 77: raystack.compass.v1beta1.UpdateTagTemplateRequest - (*UpdateTagTemplateResponse)(nil), // 78: raystack.compass.v1beta1.UpdateTagTemplateResponse - (*DeleteTagTemplateRequest)(nil), // 79: raystack.compass.v1beta1.DeleteTagTemplateRequest - (*DeleteTagTemplateResponse)(nil), // 80: raystack.compass.v1beta1.DeleteTagTemplateResponse - (*CreateNamespaceRequest)(nil), // 81: raystack.compass.v1beta1.CreateNamespaceRequest - (*CreateNamespaceResponse)(nil), // 82: raystack.compass.v1beta1.CreateNamespaceResponse - (*GetNamespaceRequest)(nil), // 83: raystack.compass.v1beta1.GetNamespaceRequest - (*GetNamespaceResponse)(nil), // 84: raystack.compass.v1beta1.GetNamespaceResponse - (*UpdateNamespaceRequest)(nil), // 85: raystack.compass.v1beta1.UpdateNamespaceRequest - (*UpdateNamespaceResponse)(nil), // 86: raystack.compass.v1beta1.UpdateNamespaceResponse - (*ListNamespacesRequest)(nil), // 87: raystack.compass.v1beta1.ListNamespacesRequest - (*ListNamespacesResponse)(nil), // 88: raystack.compass.v1beta1.ListNamespacesResponse - (*User)(nil), // 89: raystack.compass.v1beta1.User - (*Change)(nil), // 90: raystack.compass.v1beta1.Change - (*Asset)(nil), // 91: raystack.compass.v1beta1.Asset - (*Probe)(nil), // 92: raystack.compass.v1beta1.Probe - (*Discussion)(nil), // 93: raystack.compass.v1beta1.Discussion - (*Comment)(nil), // 94: raystack.compass.v1beta1.Comment - (*LineageEdge)(nil), // 95: raystack.compass.v1beta1.LineageEdge - (*LineageNode)(nil), // 96: raystack.compass.v1beta1.LineageNode - (*Tag)(nil), // 97: raystack.compass.v1beta1.Tag - (*TagValue)(nil), // 98: raystack.compass.v1beta1.TagValue - (*TagTemplate)(nil), // 99: raystack.compass.v1beta1.TagTemplate - (*TagTemplateField)(nil), // 100: raystack.compass.v1beta1.TagTemplateField - (*Type)(nil), // 101: raystack.compass.v1beta1.Type - (*Namespace)(nil), // 102: raystack.compass.v1beta1.Namespace - (*Entity)(nil), // 103: raystack.compass.v1beta1.Entity - (*Edge)(nil), // 104: raystack.compass.v1beta1.Edge - (*GetAllEntitiesRequest)(nil), // 105: raystack.compass.v1beta1.GetAllEntitiesRequest - (*GetAllEntitiesResponse)(nil), // 106: raystack.compass.v1beta1.GetAllEntitiesResponse - (*GetEntityByIDRequest)(nil), // 107: raystack.compass.v1beta1.GetEntityByIDRequest - (*GetEntityByIDResponse)(nil), // 108: raystack.compass.v1beta1.GetEntityByIDResponse - (*UpsertEntityRequest)(nil), // 109: raystack.compass.v1beta1.UpsertEntityRequest - (*UpsertEntityResponse)(nil), // 110: raystack.compass.v1beta1.UpsertEntityResponse - (*DeleteEntityRequest)(nil), // 111: raystack.compass.v1beta1.DeleteEntityRequest - (*DeleteEntityResponse)(nil), // 112: raystack.compass.v1beta1.DeleteEntityResponse - (*SearchEntitiesRequest)(nil), // 113: raystack.compass.v1beta1.SearchEntitiesRequest - (*SearchEntitiesResponse)(nil), // 114: raystack.compass.v1beta1.SearchEntitiesResponse - (*SuggestEntitiesRequest)(nil), // 115: raystack.compass.v1beta1.SuggestEntitiesRequest - (*SuggestEntitiesResponse)(nil), // 116: raystack.compass.v1beta1.SuggestEntitiesResponse - (*GetEntityTypesRequest)(nil), // 117: raystack.compass.v1beta1.GetEntityTypesRequest - (*GetEntityTypesResponse)(nil), // 118: raystack.compass.v1beta1.GetEntityTypesResponse - (*GetEntityContextRequest)(nil), // 119: raystack.compass.v1beta1.GetEntityContextRequest - (*GetEntityContextResponse)(nil), // 120: raystack.compass.v1beta1.GetEntityContextResponse - (*GetEntityImpactRequest)(nil), // 121: raystack.compass.v1beta1.GetEntityImpactRequest - (*GetEntityImpactResponse)(nil), // 122: raystack.compass.v1beta1.GetEntityImpactResponse - (*UpsertEdgeRequest)(nil), // 123: raystack.compass.v1beta1.UpsertEdgeRequest - (*UpsertEdgeResponse)(nil), // 124: raystack.compass.v1beta1.UpsertEdgeResponse - (*GetEdgesRequest)(nil), // 125: raystack.compass.v1beta1.GetEdgesRequest - (*GetEdgesResponse)(nil), // 126: raystack.compass.v1beta1.GetEdgesResponse - (*DeleteEdgeRequest)(nil), // 127: raystack.compass.v1beta1.DeleteEdgeRequest - (*DeleteEdgeResponse)(nil), // 128: raystack.compass.v1beta1.DeleteEdgeResponse - nil, // 129: raystack.compass.v1beta1.SearchAssetsRequest.FilterEntry - nil, // 130: raystack.compass.v1beta1.SearchAssetsRequest.QueryEntry - nil, // 131: raystack.compass.v1beta1.GroupAssetsRequest.FilterEntry - (*GetGraphResponse_ProbesInfo)(nil), // 132: raystack.compass.v1beta1.GetGraphResponse.ProbesInfo - (*GetGraphResponse_NodeAttributes)(nil), // 133: raystack.compass.v1beta1.GetGraphResponse.NodeAttributes - nil, // 134: raystack.compass.v1beta1.GetGraphResponse.NodeAttrsEntry - nil, // 135: raystack.compass.v1beta1.GetAllTypesRequest.DataEntry - nil, // 136: raystack.compass.v1beta1.GetAllAssetsRequest.DataEntry - (*UpsertAssetRequest_Asset)(nil), // 137: raystack.compass.v1beta1.UpsertAssetRequest.Asset - nil, // 138: raystack.compass.v1beta1.UpsertAssetRequest.Asset.LabelsEntry - (*UpsertPatchAssetRequest_Asset)(nil), // 139: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset - nil, // 140: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.LabelsEntry - (*CreateAssetProbeRequest_Probe)(nil), // 141: raystack.compass.v1beta1.CreateAssetProbeRequest.Probe - nil, // 142: raystack.compass.v1beta1.Asset.LabelsEntry - (*structpb.Struct)(nil), // 143: google.protobuf.Struct - (*timestamppb.Timestamp)(nil), // 144: google.protobuf.Timestamp - (*structpb.Value)(nil), // 145: google.protobuf.Value - (*wrapperspb.StringValue)(nil), // 146: google.protobuf.StringValue + (*User)(nil), // 0: raystack.compass.v1beta1.User + (*Entity)(nil), // 1: raystack.compass.v1beta1.Entity + (*Edge)(nil), // 2: raystack.compass.v1beta1.Edge + (*Type)(nil), // 3: raystack.compass.v1beta1.Type + (*Namespace)(nil), // 4: raystack.compass.v1beta1.Namespace + (*GetAllEntitiesRequest)(nil), // 5: raystack.compass.v1beta1.GetAllEntitiesRequest + (*GetAllEntitiesResponse)(nil), // 6: raystack.compass.v1beta1.GetAllEntitiesResponse + (*GetEntityByIDRequest)(nil), // 7: raystack.compass.v1beta1.GetEntityByIDRequest + (*GetEntityByIDResponse)(nil), // 8: raystack.compass.v1beta1.GetEntityByIDResponse + (*UpsertEntityRequest)(nil), // 9: raystack.compass.v1beta1.UpsertEntityRequest + (*UpsertEntityResponse)(nil), // 10: raystack.compass.v1beta1.UpsertEntityResponse + (*DeleteEntityRequest)(nil), // 11: raystack.compass.v1beta1.DeleteEntityRequest + (*DeleteEntityResponse)(nil), // 12: raystack.compass.v1beta1.DeleteEntityResponse + (*SearchEntitiesRequest)(nil), // 13: raystack.compass.v1beta1.SearchEntitiesRequest + (*SearchEntitiesResponse)(nil), // 14: raystack.compass.v1beta1.SearchEntitiesResponse + (*SuggestEntitiesRequest)(nil), // 15: raystack.compass.v1beta1.SuggestEntitiesRequest + (*SuggestEntitiesResponse)(nil), // 16: raystack.compass.v1beta1.SuggestEntitiesResponse + (*GetEntityTypesRequest)(nil), // 17: raystack.compass.v1beta1.GetEntityTypesRequest + (*GetEntityTypesResponse)(nil), // 18: raystack.compass.v1beta1.GetEntityTypesResponse + (*GetEntityContextRequest)(nil), // 19: raystack.compass.v1beta1.GetEntityContextRequest + (*GetEntityContextResponse)(nil), // 20: raystack.compass.v1beta1.GetEntityContextResponse + (*GetEntityImpactRequest)(nil), // 21: raystack.compass.v1beta1.GetEntityImpactRequest + (*GetEntityImpactResponse)(nil), // 22: raystack.compass.v1beta1.GetEntityImpactResponse + (*UpsertEdgeRequest)(nil), // 23: raystack.compass.v1beta1.UpsertEdgeRequest + (*UpsertEdgeResponse)(nil), // 24: raystack.compass.v1beta1.UpsertEdgeResponse + (*GetEdgesRequest)(nil), // 25: raystack.compass.v1beta1.GetEdgesRequest + (*GetEdgesResponse)(nil), // 26: raystack.compass.v1beta1.GetEdgesResponse + (*DeleteEdgeRequest)(nil), // 27: raystack.compass.v1beta1.DeleteEdgeRequest + (*DeleteEdgeResponse)(nil), // 28: raystack.compass.v1beta1.DeleteEdgeResponse + (*StarEntityRequest)(nil), // 29: raystack.compass.v1beta1.StarEntityRequest + (*StarEntityResponse)(nil), // 30: raystack.compass.v1beta1.StarEntityResponse + (*UnstarEntityRequest)(nil), // 31: raystack.compass.v1beta1.UnstarEntityRequest + (*UnstarEntityResponse)(nil), // 32: raystack.compass.v1beta1.UnstarEntityResponse + (*GetUserStarredEntitiesRequest)(nil), // 33: raystack.compass.v1beta1.GetUserStarredEntitiesRequest + (*GetUserStarredEntitiesResponse)(nil), // 34: raystack.compass.v1beta1.GetUserStarredEntitiesResponse + (*GetMyStarredEntitiesRequest)(nil), // 35: raystack.compass.v1beta1.GetMyStarredEntitiesRequest + (*GetMyStarredEntitiesResponse)(nil), // 36: raystack.compass.v1beta1.GetMyStarredEntitiesResponse + (*GetMyStarredEntityRequest)(nil), // 37: raystack.compass.v1beta1.GetMyStarredEntityRequest + (*GetMyStarredEntityResponse)(nil), // 38: raystack.compass.v1beta1.GetMyStarredEntityResponse + (*GetEntityStargazersRequest)(nil), // 39: raystack.compass.v1beta1.GetEntityStargazersRequest + (*GetEntityStargazersResponse)(nil), // 40: raystack.compass.v1beta1.GetEntityStargazersResponse + (*CreateNamespaceRequest)(nil), // 41: raystack.compass.v1beta1.CreateNamespaceRequest + (*CreateNamespaceResponse)(nil), // 42: raystack.compass.v1beta1.CreateNamespaceResponse + (*GetNamespaceRequest)(nil), // 43: raystack.compass.v1beta1.GetNamespaceRequest + (*GetNamespaceResponse)(nil), // 44: raystack.compass.v1beta1.GetNamespaceResponse + (*UpdateNamespaceRequest)(nil), // 45: raystack.compass.v1beta1.UpdateNamespaceRequest + (*UpdateNamespaceResponse)(nil), // 46: raystack.compass.v1beta1.UpdateNamespaceResponse + (*ListNamespacesRequest)(nil), // 47: raystack.compass.v1beta1.ListNamespacesRequest + (*ListNamespacesResponse)(nil), // 48: raystack.compass.v1beta1.ListNamespacesResponse + (*timestamppb.Timestamp)(nil), // 49: google.protobuf.Timestamp + (*structpb.Struct)(nil), // 50: google.protobuf.Struct } var file_raystack_compass_v1beta1_service_proto_depIdxs = []int32{ - 93, // 0: raystack.compass.v1beta1.GetAllDiscussionsResponse.data:type_name -> raystack.compass.v1beta1.Discussion - 93, // 1: raystack.compass.v1beta1.GetDiscussionResponse.data:type_name -> raystack.compass.v1beta1.Discussion - 94, // 2: raystack.compass.v1beta1.GetAllCommentsResponse.data:type_name -> raystack.compass.v1beta1.Comment - 94, // 3: raystack.compass.v1beta1.GetCommentResponse.data:type_name -> raystack.compass.v1beta1.Comment - 129, // 4: raystack.compass.v1beta1.SearchAssetsRequest.filter:type_name -> raystack.compass.v1beta1.SearchAssetsRequest.FilterEntry - 130, // 5: raystack.compass.v1beta1.SearchAssetsRequest.query:type_name -> raystack.compass.v1beta1.SearchAssetsRequest.QueryEntry - 19, // 6: raystack.compass.v1beta1.SearchAssetsRequest.flags:type_name -> raystack.compass.v1beta1.SearchFlags - 91, // 7: raystack.compass.v1beta1.SearchAssetsResponse.data:type_name -> raystack.compass.v1beta1.Asset - 131, // 8: raystack.compass.v1beta1.GroupAssetsRequest.filter:type_name -> raystack.compass.v1beta1.GroupAssetsRequest.FilterEntry - 25, // 9: raystack.compass.v1beta1.GroupAssetsResponse.asset_groups:type_name -> raystack.compass.v1beta1.AssetGroup - 26, // 10: raystack.compass.v1beta1.AssetGroup.group_fields:type_name -> raystack.compass.v1beta1.GroupField - 91, // 11: raystack.compass.v1beta1.AssetGroup.assets:type_name -> raystack.compass.v1beta1.Asset - 95, // 12: raystack.compass.v1beta1.GetGraphResponse.data:type_name -> raystack.compass.v1beta1.LineageEdge - 134, // 13: raystack.compass.v1beta1.GetGraphResponse.node_attrs:type_name -> raystack.compass.v1beta1.GetGraphResponse.NodeAttrsEntry - 135, // 14: raystack.compass.v1beta1.GetAllTypesRequest.data:type_name -> raystack.compass.v1beta1.GetAllTypesRequest.DataEntry - 101, // 15: raystack.compass.v1beta1.GetAllTypesResponse.data:type_name -> raystack.compass.v1beta1.Type - 136, // 16: raystack.compass.v1beta1.GetAllAssetsRequest.data:type_name -> raystack.compass.v1beta1.GetAllAssetsRequest.DataEntry - 91, // 17: raystack.compass.v1beta1.GetAllAssetsResponse.data:type_name -> raystack.compass.v1beta1.Asset - 91, // 18: raystack.compass.v1beta1.GetAssetByIDResponse.data:type_name -> raystack.compass.v1beta1.Asset - 137, // 19: raystack.compass.v1beta1.UpsertAssetRequest.asset:type_name -> raystack.compass.v1beta1.UpsertAssetRequest.Asset - 96, // 20: raystack.compass.v1beta1.UpsertAssetRequest.upstreams:type_name -> raystack.compass.v1beta1.LineageNode - 96, // 21: raystack.compass.v1beta1.UpsertAssetRequest.downstreams:type_name -> raystack.compass.v1beta1.LineageNode - 139, // 22: raystack.compass.v1beta1.UpsertPatchAssetRequest.asset:type_name -> raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset - 96, // 23: raystack.compass.v1beta1.UpsertPatchAssetRequest.upstreams:type_name -> raystack.compass.v1beta1.LineageNode - 96, // 24: raystack.compass.v1beta1.UpsertPatchAssetRequest.downstreams:type_name -> raystack.compass.v1beta1.LineageNode - 89, // 25: raystack.compass.v1beta1.GetAssetStargazersResponse.data:type_name -> raystack.compass.v1beta1.User - 91, // 26: raystack.compass.v1beta1.GetAssetVersionHistoryResponse.data:type_name -> raystack.compass.v1beta1.Asset - 91, // 27: raystack.compass.v1beta1.GetAssetByVersionResponse.data:type_name -> raystack.compass.v1beta1.Asset - 141, // 28: raystack.compass.v1beta1.CreateAssetProbeRequest.probe:type_name -> raystack.compass.v1beta1.CreateAssetProbeRequest.Probe - 91, // 29: raystack.compass.v1beta1.GetUserStarredAssetsResponse.data:type_name -> raystack.compass.v1beta1.Asset - 91, // 30: raystack.compass.v1beta1.GetMyStarredAssetsResponse.data:type_name -> raystack.compass.v1beta1.Asset - 91, // 31: raystack.compass.v1beta1.GetMyStarredAssetResponse.data:type_name -> raystack.compass.v1beta1.Asset - 93, // 32: raystack.compass.v1beta1.GetMyDiscussionsResponse.data:type_name -> raystack.compass.v1beta1.Discussion - 98, // 33: raystack.compass.v1beta1.CreateTagAssetRequest.tag_values:type_name -> raystack.compass.v1beta1.TagValue - 97, // 34: raystack.compass.v1beta1.CreateTagAssetResponse.data:type_name -> raystack.compass.v1beta1.Tag - 97, // 35: raystack.compass.v1beta1.GetTagByAssetAndTemplateResponse.data:type_name -> raystack.compass.v1beta1.Tag - 98, // 36: raystack.compass.v1beta1.UpdateTagAssetRequest.tag_values:type_name -> raystack.compass.v1beta1.TagValue - 97, // 37: raystack.compass.v1beta1.UpdateTagAssetResponse.data:type_name -> raystack.compass.v1beta1.Tag - 97, // 38: raystack.compass.v1beta1.GetAllTagsByAssetResponse.data:type_name -> raystack.compass.v1beta1.Tag - 99, // 39: raystack.compass.v1beta1.GetAllTagTemplatesResponse.data:type_name -> raystack.compass.v1beta1.TagTemplate - 100, // 40: raystack.compass.v1beta1.CreateTagTemplateRequest.fields:type_name -> raystack.compass.v1beta1.TagTemplateField - 99, // 41: raystack.compass.v1beta1.CreateTagTemplateResponse.data:type_name -> raystack.compass.v1beta1.TagTemplate - 99, // 42: raystack.compass.v1beta1.GetTagTemplateResponse.data:type_name -> raystack.compass.v1beta1.TagTemplate - 100, // 43: raystack.compass.v1beta1.UpdateTagTemplateRequest.fields:type_name -> raystack.compass.v1beta1.TagTemplateField - 99, // 44: raystack.compass.v1beta1.UpdateTagTemplateResponse.data:type_name -> raystack.compass.v1beta1.TagTemplate - 143, // 45: raystack.compass.v1beta1.CreateNamespaceRequest.metadata:type_name -> google.protobuf.Struct - 102, // 46: raystack.compass.v1beta1.GetNamespaceResponse.namespace:type_name -> raystack.compass.v1beta1.Namespace - 143, // 47: raystack.compass.v1beta1.UpdateNamespaceRequest.metadata:type_name -> google.protobuf.Struct - 102, // 48: raystack.compass.v1beta1.ListNamespacesResponse.namespaces:type_name -> raystack.compass.v1beta1.Namespace - 144, // 49: raystack.compass.v1beta1.User.created_at:type_name -> google.protobuf.Timestamp - 144, // 50: raystack.compass.v1beta1.User.updated_at:type_name -> google.protobuf.Timestamp - 145, // 51: raystack.compass.v1beta1.Change.from:type_name -> google.protobuf.Value - 145, // 52: raystack.compass.v1beta1.Change.to:type_name -> google.protobuf.Value - 143, // 53: raystack.compass.v1beta1.Asset.data:type_name -> google.protobuf.Struct - 142, // 54: raystack.compass.v1beta1.Asset.labels:type_name -> raystack.compass.v1beta1.Asset.LabelsEntry - 89, // 55: raystack.compass.v1beta1.Asset.owners:type_name -> raystack.compass.v1beta1.User - 89, // 56: raystack.compass.v1beta1.Asset.updated_by:type_name -> raystack.compass.v1beta1.User - 90, // 57: raystack.compass.v1beta1.Asset.changelog:type_name -> raystack.compass.v1beta1.Change - 144, // 58: raystack.compass.v1beta1.Asset.created_at:type_name -> google.protobuf.Timestamp - 144, // 59: raystack.compass.v1beta1.Asset.updated_at:type_name -> google.protobuf.Timestamp - 92, // 60: raystack.compass.v1beta1.Asset.probes:type_name -> raystack.compass.v1beta1.Probe - 143, // 61: raystack.compass.v1beta1.Probe.metadata:type_name -> google.protobuf.Struct - 144, // 62: raystack.compass.v1beta1.Probe.timestamp:type_name -> google.protobuf.Timestamp - 144, // 63: raystack.compass.v1beta1.Probe.created_at:type_name -> google.protobuf.Timestamp - 89, // 64: raystack.compass.v1beta1.Discussion.owner:type_name -> raystack.compass.v1beta1.User - 144, // 65: raystack.compass.v1beta1.Discussion.created_at:type_name -> google.protobuf.Timestamp - 144, // 66: raystack.compass.v1beta1.Discussion.updated_at:type_name -> google.protobuf.Timestamp - 89, // 67: raystack.compass.v1beta1.Comment.owner:type_name -> raystack.compass.v1beta1.User - 89, // 68: raystack.compass.v1beta1.Comment.updated_by:type_name -> raystack.compass.v1beta1.User - 144, // 69: raystack.compass.v1beta1.Comment.created_at:type_name -> google.protobuf.Timestamp - 144, // 70: raystack.compass.v1beta1.Comment.updated_at:type_name -> google.protobuf.Timestamp - 143, // 71: raystack.compass.v1beta1.LineageEdge.prop:type_name -> google.protobuf.Struct - 98, // 72: raystack.compass.v1beta1.Tag.tag_values:type_name -> raystack.compass.v1beta1.TagValue - 145, // 73: raystack.compass.v1beta1.TagValue.field_value:type_name -> google.protobuf.Value - 144, // 74: raystack.compass.v1beta1.TagValue.created_at:type_name -> google.protobuf.Timestamp - 144, // 75: raystack.compass.v1beta1.TagValue.updated_at:type_name -> google.protobuf.Timestamp - 100, // 76: raystack.compass.v1beta1.TagTemplate.fields:type_name -> raystack.compass.v1beta1.TagTemplateField - 144, // 77: raystack.compass.v1beta1.TagTemplate.created_at:type_name -> google.protobuf.Timestamp - 144, // 78: raystack.compass.v1beta1.TagTemplate.updated_at:type_name -> google.protobuf.Timestamp - 144, // 79: raystack.compass.v1beta1.TagTemplateField.created_at:type_name -> google.protobuf.Timestamp - 144, // 80: raystack.compass.v1beta1.TagTemplateField.updated_at:type_name -> google.protobuf.Timestamp - 143, // 81: raystack.compass.v1beta1.Namespace.metadata:type_name -> google.protobuf.Struct - 143, // 82: raystack.compass.v1beta1.Entity.properties:type_name -> google.protobuf.Struct - 144, // 83: raystack.compass.v1beta1.Entity.valid_from:type_name -> google.protobuf.Timestamp - 144, // 84: raystack.compass.v1beta1.Entity.valid_to:type_name -> google.protobuf.Timestamp - 144, // 85: raystack.compass.v1beta1.Entity.created_at:type_name -> google.protobuf.Timestamp - 144, // 86: raystack.compass.v1beta1.Entity.updated_at:type_name -> google.protobuf.Timestamp - 143, // 87: raystack.compass.v1beta1.Edge.properties:type_name -> google.protobuf.Struct - 144, // 88: raystack.compass.v1beta1.Edge.valid_from:type_name -> google.protobuf.Timestamp - 144, // 89: raystack.compass.v1beta1.Edge.valid_to:type_name -> google.protobuf.Timestamp - 144, // 90: raystack.compass.v1beta1.Edge.created_at:type_name -> google.protobuf.Timestamp - 103, // 91: raystack.compass.v1beta1.GetAllEntitiesResponse.data:type_name -> raystack.compass.v1beta1.Entity - 103, // 92: raystack.compass.v1beta1.GetEntityByIDResponse.data:type_name -> raystack.compass.v1beta1.Entity - 143, // 93: raystack.compass.v1beta1.UpsertEntityRequest.properties:type_name -> google.protobuf.Struct - 103, // 94: raystack.compass.v1beta1.SearchEntitiesResponse.data:type_name -> raystack.compass.v1beta1.Entity - 101, // 95: raystack.compass.v1beta1.GetEntityTypesResponse.data:type_name -> raystack.compass.v1beta1.Type - 103, // 96: raystack.compass.v1beta1.GetEntityContextResponse.entity:type_name -> raystack.compass.v1beta1.Entity - 104, // 97: raystack.compass.v1beta1.GetEntityContextResponse.edges:type_name -> raystack.compass.v1beta1.Edge - 103, // 98: raystack.compass.v1beta1.GetEntityContextResponse.related:type_name -> raystack.compass.v1beta1.Entity - 104, // 99: raystack.compass.v1beta1.GetEntityImpactResponse.edges:type_name -> raystack.compass.v1beta1.Edge - 103, // 100: raystack.compass.v1beta1.GetEntityImpactResponse.affected:type_name -> raystack.compass.v1beta1.Entity - 143, // 101: raystack.compass.v1beta1.UpsertEdgeRequest.properties:type_name -> google.protobuf.Struct - 104, // 102: raystack.compass.v1beta1.GetEdgesResponse.data:type_name -> raystack.compass.v1beta1.Edge - 92, // 103: raystack.compass.v1beta1.GetGraphResponse.ProbesInfo.latest:type_name -> raystack.compass.v1beta1.Probe - 132, // 104: raystack.compass.v1beta1.GetGraphResponse.NodeAttributes.probes:type_name -> raystack.compass.v1beta1.GetGraphResponse.ProbesInfo - 133, // 105: raystack.compass.v1beta1.GetGraphResponse.NodeAttrsEntry.value:type_name -> raystack.compass.v1beta1.GetGraphResponse.NodeAttributes - 143, // 106: raystack.compass.v1beta1.UpsertAssetRequest.Asset.data:type_name -> google.protobuf.Struct - 138, // 107: raystack.compass.v1beta1.UpsertAssetRequest.Asset.labels:type_name -> raystack.compass.v1beta1.UpsertAssetRequest.Asset.LabelsEntry - 89, // 108: raystack.compass.v1beta1.UpsertAssetRequest.Asset.owners:type_name -> raystack.compass.v1beta1.User - 146, // 109: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.name:type_name -> google.protobuf.StringValue - 146, // 110: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.description:type_name -> google.protobuf.StringValue - 143, // 111: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.data:type_name -> google.protobuf.Struct - 140, // 112: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.labels:type_name -> raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.LabelsEntry - 89, // 113: raystack.compass.v1beta1.UpsertPatchAssetRequest.Asset.owners:type_name -> raystack.compass.v1beta1.User - 143, // 114: raystack.compass.v1beta1.CreateAssetProbeRequest.Probe.metadata:type_name -> google.protobuf.Struct - 144, // 115: raystack.compass.v1beta1.CreateAssetProbeRequest.Probe.timestamp:type_name -> google.protobuf.Timestamp - 0, // 116: raystack.compass.v1beta1.CompassService.GetAllDiscussions:input_type -> raystack.compass.v1beta1.GetAllDiscussionsRequest - 2, // 117: raystack.compass.v1beta1.CompassService.CreateDiscussion:input_type -> raystack.compass.v1beta1.CreateDiscussionRequest - 4, // 118: raystack.compass.v1beta1.CompassService.GetDiscussion:input_type -> raystack.compass.v1beta1.GetDiscussionRequest - 6, // 119: raystack.compass.v1beta1.CompassService.PatchDiscussion:input_type -> raystack.compass.v1beta1.PatchDiscussionRequest - 7, // 120: raystack.compass.v1beta1.CompassService.CreateComment:input_type -> raystack.compass.v1beta1.CreateCommentRequest - 10, // 121: raystack.compass.v1beta1.CompassService.GetAllComments:input_type -> raystack.compass.v1beta1.GetAllCommentsRequest - 12, // 122: raystack.compass.v1beta1.CompassService.GetComment:input_type -> raystack.compass.v1beta1.GetCommentRequest - 14, // 123: raystack.compass.v1beta1.CompassService.UpdateComment:input_type -> raystack.compass.v1beta1.UpdateCommentRequest - 16, // 124: raystack.compass.v1beta1.CompassService.DeleteComment:input_type -> raystack.compass.v1beta1.DeleteCommentRequest - 18, // 125: raystack.compass.v1beta1.CompassService.SearchAssets:input_type -> raystack.compass.v1beta1.SearchAssetsRequest - 21, // 126: raystack.compass.v1beta1.CompassService.SuggestAssets:input_type -> raystack.compass.v1beta1.SuggestAssetsRequest - 23, // 127: raystack.compass.v1beta1.CompassService.GroupAssets:input_type -> raystack.compass.v1beta1.GroupAssetsRequest - 27, // 128: raystack.compass.v1beta1.CompassService.GetGraph:input_type -> raystack.compass.v1beta1.GetGraphRequest - 29, // 129: raystack.compass.v1beta1.CompassService.GetAllTypes:input_type -> raystack.compass.v1beta1.GetAllTypesRequest - 31, // 130: raystack.compass.v1beta1.CompassService.GetAllAssets:input_type -> raystack.compass.v1beta1.GetAllAssetsRequest - 33, // 131: raystack.compass.v1beta1.CompassService.GetAssetByID:input_type -> raystack.compass.v1beta1.GetAssetByIDRequest - 35, // 132: raystack.compass.v1beta1.CompassService.UpsertAsset:input_type -> raystack.compass.v1beta1.UpsertAssetRequest - 37, // 133: raystack.compass.v1beta1.CompassService.UpsertPatchAsset:input_type -> raystack.compass.v1beta1.UpsertPatchAssetRequest - 39, // 134: raystack.compass.v1beta1.CompassService.DeleteAsset:input_type -> raystack.compass.v1beta1.DeleteAssetRequest - 41, // 135: raystack.compass.v1beta1.CompassService.GetAssetStargazers:input_type -> raystack.compass.v1beta1.GetAssetStargazersRequest - 43, // 136: raystack.compass.v1beta1.CompassService.GetAssetVersionHistory:input_type -> raystack.compass.v1beta1.GetAssetVersionHistoryRequest - 45, // 137: raystack.compass.v1beta1.CompassService.GetAssetByVersion:input_type -> raystack.compass.v1beta1.GetAssetByVersionRequest - 47, // 138: raystack.compass.v1beta1.CompassService.CreateAssetProbe:input_type -> raystack.compass.v1beta1.CreateAssetProbeRequest - 49, // 139: raystack.compass.v1beta1.CompassService.GetUserStarredAssets:input_type -> raystack.compass.v1beta1.GetUserStarredAssetsRequest - 51, // 140: raystack.compass.v1beta1.CompassService.GetMyStarredAssets:input_type -> raystack.compass.v1beta1.GetMyStarredAssetsRequest - 53, // 141: raystack.compass.v1beta1.CompassService.GetMyStarredAsset:input_type -> raystack.compass.v1beta1.GetMyStarredAssetRequest - 55, // 142: raystack.compass.v1beta1.CompassService.StarAsset:input_type -> raystack.compass.v1beta1.StarAssetRequest - 57, // 143: raystack.compass.v1beta1.CompassService.UnstarAsset:input_type -> raystack.compass.v1beta1.UnstarAssetRequest - 59, // 144: raystack.compass.v1beta1.CompassService.GetMyDiscussions:input_type -> raystack.compass.v1beta1.GetMyDiscussionsRequest - 61, // 145: raystack.compass.v1beta1.CompassService.CreateTagAsset:input_type -> raystack.compass.v1beta1.CreateTagAssetRequest - 63, // 146: raystack.compass.v1beta1.CompassService.GetTagByAssetAndTemplate:input_type -> raystack.compass.v1beta1.GetTagByAssetAndTemplateRequest - 65, // 147: raystack.compass.v1beta1.CompassService.UpdateTagAsset:input_type -> raystack.compass.v1beta1.UpdateTagAssetRequest - 67, // 148: raystack.compass.v1beta1.CompassService.DeleteTagAsset:input_type -> raystack.compass.v1beta1.DeleteTagAssetRequest - 69, // 149: raystack.compass.v1beta1.CompassService.GetAllTagsByAsset:input_type -> raystack.compass.v1beta1.GetAllTagsByAssetRequest - 71, // 150: raystack.compass.v1beta1.CompassService.GetAllTagTemplates:input_type -> raystack.compass.v1beta1.GetAllTagTemplatesRequest - 73, // 151: raystack.compass.v1beta1.CompassService.CreateTagTemplate:input_type -> raystack.compass.v1beta1.CreateTagTemplateRequest - 75, // 152: raystack.compass.v1beta1.CompassService.GetTagTemplate:input_type -> raystack.compass.v1beta1.GetTagTemplateRequest - 77, // 153: raystack.compass.v1beta1.CompassService.UpdateTagTemplate:input_type -> raystack.compass.v1beta1.UpdateTagTemplateRequest - 79, // 154: raystack.compass.v1beta1.CompassService.DeleteTagTemplate:input_type -> raystack.compass.v1beta1.DeleteTagTemplateRequest - 81, // 155: raystack.compass.v1beta1.CompassService.CreateNamespace:input_type -> raystack.compass.v1beta1.CreateNamespaceRequest - 83, // 156: raystack.compass.v1beta1.CompassService.GetNamespace:input_type -> raystack.compass.v1beta1.GetNamespaceRequest - 85, // 157: raystack.compass.v1beta1.CompassService.UpdateNamespace:input_type -> raystack.compass.v1beta1.UpdateNamespaceRequest - 87, // 158: raystack.compass.v1beta1.CompassService.ListNamespaces:input_type -> raystack.compass.v1beta1.ListNamespacesRequest - 105, // 159: raystack.compass.v1beta1.CompassService.GetAllEntities:input_type -> raystack.compass.v1beta1.GetAllEntitiesRequest - 107, // 160: raystack.compass.v1beta1.CompassService.GetEntityByID:input_type -> raystack.compass.v1beta1.GetEntityByIDRequest - 109, // 161: raystack.compass.v1beta1.CompassService.UpsertEntity:input_type -> raystack.compass.v1beta1.UpsertEntityRequest - 111, // 162: raystack.compass.v1beta1.CompassService.DeleteEntity:input_type -> raystack.compass.v1beta1.DeleteEntityRequest - 113, // 163: raystack.compass.v1beta1.CompassService.SearchEntities:input_type -> raystack.compass.v1beta1.SearchEntitiesRequest - 115, // 164: raystack.compass.v1beta1.CompassService.SuggestEntities:input_type -> raystack.compass.v1beta1.SuggestEntitiesRequest - 117, // 165: raystack.compass.v1beta1.CompassService.GetEntityTypes:input_type -> raystack.compass.v1beta1.GetEntityTypesRequest - 119, // 166: raystack.compass.v1beta1.CompassService.GetEntityContext:input_type -> raystack.compass.v1beta1.GetEntityContextRequest - 121, // 167: raystack.compass.v1beta1.CompassService.GetEntityImpact:input_type -> raystack.compass.v1beta1.GetEntityImpactRequest - 123, // 168: raystack.compass.v1beta1.CompassService.UpsertEdge:input_type -> raystack.compass.v1beta1.UpsertEdgeRequest - 125, // 169: raystack.compass.v1beta1.CompassService.GetEdges:input_type -> raystack.compass.v1beta1.GetEdgesRequest - 127, // 170: raystack.compass.v1beta1.CompassService.DeleteEdge:input_type -> raystack.compass.v1beta1.DeleteEdgeRequest - 1, // 171: raystack.compass.v1beta1.CompassService.GetAllDiscussions:output_type -> raystack.compass.v1beta1.GetAllDiscussionsResponse - 3, // 172: raystack.compass.v1beta1.CompassService.CreateDiscussion:output_type -> raystack.compass.v1beta1.CreateDiscussionResponse - 5, // 173: raystack.compass.v1beta1.CompassService.GetDiscussion:output_type -> raystack.compass.v1beta1.GetDiscussionResponse - 8, // 174: raystack.compass.v1beta1.CompassService.PatchDiscussion:output_type -> raystack.compass.v1beta1.PatchDiscussionResponse - 9, // 175: raystack.compass.v1beta1.CompassService.CreateComment:output_type -> raystack.compass.v1beta1.CreateCommentResponse - 11, // 176: raystack.compass.v1beta1.CompassService.GetAllComments:output_type -> raystack.compass.v1beta1.GetAllCommentsResponse - 13, // 177: raystack.compass.v1beta1.CompassService.GetComment:output_type -> raystack.compass.v1beta1.GetCommentResponse - 15, // 178: raystack.compass.v1beta1.CompassService.UpdateComment:output_type -> raystack.compass.v1beta1.UpdateCommentResponse - 17, // 179: raystack.compass.v1beta1.CompassService.DeleteComment:output_type -> raystack.compass.v1beta1.DeleteCommentResponse - 20, // 180: raystack.compass.v1beta1.CompassService.SearchAssets:output_type -> raystack.compass.v1beta1.SearchAssetsResponse - 22, // 181: raystack.compass.v1beta1.CompassService.SuggestAssets:output_type -> raystack.compass.v1beta1.SuggestAssetsResponse - 24, // 182: raystack.compass.v1beta1.CompassService.GroupAssets:output_type -> raystack.compass.v1beta1.GroupAssetsResponse - 28, // 183: raystack.compass.v1beta1.CompassService.GetGraph:output_type -> raystack.compass.v1beta1.GetGraphResponse - 30, // 184: raystack.compass.v1beta1.CompassService.GetAllTypes:output_type -> raystack.compass.v1beta1.GetAllTypesResponse - 32, // 185: raystack.compass.v1beta1.CompassService.GetAllAssets:output_type -> raystack.compass.v1beta1.GetAllAssetsResponse - 34, // 186: raystack.compass.v1beta1.CompassService.GetAssetByID:output_type -> raystack.compass.v1beta1.GetAssetByIDResponse - 36, // 187: raystack.compass.v1beta1.CompassService.UpsertAsset:output_type -> raystack.compass.v1beta1.UpsertAssetResponse - 38, // 188: raystack.compass.v1beta1.CompassService.UpsertPatchAsset:output_type -> raystack.compass.v1beta1.UpsertPatchAssetResponse - 40, // 189: raystack.compass.v1beta1.CompassService.DeleteAsset:output_type -> raystack.compass.v1beta1.DeleteAssetResponse - 42, // 190: raystack.compass.v1beta1.CompassService.GetAssetStargazers:output_type -> raystack.compass.v1beta1.GetAssetStargazersResponse - 44, // 191: raystack.compass.v1beta1.CompassService.GetAssetVersionHistory:output_type -> raystack.compass.v1beta1.GetAssetVersionHistoryResponse - 46, // 192: raystack.compass.v1beta1.CompassService.GetAssetByVersion:output_type -> raystack.compass.v1beta1.GetAssetByVersionResponse - 48, // 193: raystack.compass.v1beta1.CompassService.CreateAssetProbe:output_type -> raystack.compass.v1beta1.CreateAssetProbeResponse - 50, // 194: raystack.compass.v1beta1.CompassService.GetUserStarredAssets:output_type -> raystack.compass.v1beta1.GetUserStarredAssetsResponse - 52, // 195: raystack.compass.v1beta1.CompassService.GetMyStarredAssets:output_type -> raystack.compass.v1beta1.GetMyStarredAssetsResponse - 54, // 196: raystack.compass.v1beta1.CompassService.GetMyStarredAsset:output_type -> raystack.compass.v1beta1.GetMyStarredAssetResponse - 56, // 197: raystack.compass.v1beta1.CompassService.StarAsset:output_type -> raystack.compass.v1beta1.StarAssetResponse - 58, // 198: raystack.compass.v1beta1.CompassService.UnstarAsset:output_type -> raystack.compass.v1beta1.UnstarAssetResponse - 60, // 199: raystack.compass.v1beta1.CompassService.GetMyDiscussions:output_type -> raystack.compass.v1beta1.GetMyDiscussionsResponse - 62, // 200: raystack.compass.v1beta1.CompassService.CreateTagAsset:output_type -> raystack.compass.v1beta1.CreateTagAssetResponse - 64, // 201: raystack.compass.v1beta1.CompassService.GetTagByAssetAndTemplate:output_type -> raystack.compass.v1beta1.GetTagByAssetAndTemplateResponse - 66, // 202: raystack.compass.v1beta1.CompassService.UpdateTagAsset:output_type -> raystack.compass.v1beta1.UpdateTagAssetResponse - 68, // 203: raystack.compass.v1beta1.CompassService.DeleteTagAsset:output_type -> raystack.compass.v1beta1.DeleteTagAssetResponse - 70, // 204: raystack.compass.v1beta1.CompassService.GetAllTagsByAsset:output_type -> raystack.compass.v1beta1.GetAllTagsByAssetResponse - 72, // 205: raystack.compass.v1beta1.CompassService.GetAllTagTemplates:output_type -> raystack.compass.v1beta1.GetAllTagTemplatesResponse - 74, // 206: raystack.compass.v1beta1.CompassService.CreateTagTemplate:output_type -> raystack.compass.v1beta1.CreateTagTemplateResponse - 76, // 207: raystack.compass.v1beta1.CompassService.GetTagTemplate:output_type -> raystack.compass.v1beta1.GetTagTemplateResponse - 78, // 208: raystack.compass.v1beta1.CompassService.UpdateTagTemplate:output_type -> raystack.compass.v1beta1.UpdateTagTemplateResponse - 80, // 209: raystack.compass.v1beta1.CompassService.DeleteTagTemplate:output_type -> raystack.compass.v1beta1.DeleteTagTemplateResponse - 82, // 210: raystack.compass.v1beta1.CompassService.CreateNamespace:output_type -> raystack.compass.v1beta1.CreateNamespaceResponse - 84, // 211: raystack.compass.v1beta1.CompassService.GetNamespace:output_type -> raystack.compass.v1beta1.GetNamespaceResponse - 86, // 212: raystack.compass.v1beta1.CompassService.UpdateNamespace:output_type -> raystack.compass.v1beta1.UpdateNamespaceResponse - 88, // 213: raystack.compass.v1beta1.CompassService.ListNamespaces:output_type -> raystack.compass.v1beta1.ListNamespacesResponse - 106, // 214: raystack.compass.v1beta1.CompassService.GetAllEntities:output_type -> raystack.compass.v1beta1.GetAllEntitiesResponse - 108, // 215: raystack.compass.v1beta1.CompassService.GetEntityByID:output_type -> raystack.compass.v1beta1.GetEntityByIDResponse - 110, // 216: raystack.compass.v1beta1.CompassService.UpsertEntity:output_type -> raystack.compass.v1beta1.UpsertEntityResponse - 112, // 217: raystack.compass.v1beta1.CompassService.DeleteEntity:output_type -> raystack.compass.v1beta1.DeleteEntityResponse - 114, // 218: raystack.compass.v1beta1.CompassService.SearchEntities:output_type -> raystack.compass.v1beta1.SearchEntitiesResponse - 116, // 219: raystack.compass.v1beta1.CompassService.SuggestEntities:output_type -> raystack.compass.v1beta1.SuggestEntitiesResponse - 118, // 220: raystack.compass.v1beta1.CompassService.GetEntityTypes:output_type -> raystack.compass.v1beta1.GetEntityTypesResponse - 120, // 221: raystack.compass.v1beta1.CompassService.GetEntityContext:output_type -> raystack.compass.v1beta1.GetEntityContextResponse - 122, // 222: raystack.compass.v1beta1.CompassService.GetEntityImpact:output_type -> raystack.compass.v1beta1.GetEntityImpactResponse - 124, // 223: raystack.compass.v1beta1.CompassService.UpsertEdge:output_type -> raystack.compass.v1beta1.UpsertEdgeResponse - 126, // 224: raystack.compass.v1beta1.CompassService.GetEdges:output_type -> raystack.compass.v1beta1.GetEdgesResponse - 128, // 225: raystack.compass.v1beta1.CompassService.DeleteEdge:output_type -> raystack.compass.v1beta1.DeleteEdgeResponse - 171, // [171:226] is the sub-list for method output_type - 116, // [116:171] is the sub-list for method input_type - 116, // [116:116] is the sub-list for extension type_name - 116, // [116:116] is the sub-list for extension extendee - 0, // [0:116] is the sub-list for field type_name + 49, // 0: raystack.compass.v1beta1.User.created_at:type_name -> google.protobuf.Timestamp + 49, // 1: raystack.compass.v1beta1.User.updated_at:type_name -> google.protobuf.Timestamp + 50, // 2: raystack.compass.v1beta1.Entity.properties:type_name -> google.protobuf.Struct + 49, // 3: raystack.compass.v1beta1.Entity.valid_from:type_name -> google.protobuf.Timestamp + 49, // 4: raystack.compass.v1beta1.Entity.valid_to:type_name -> google.protobuf.Timestamp + 49, // 5: raystack.compass.v1beta1.Entity.created_at:type_name -> google.protobuf.Timestamp + 49, // 6: raystack.compass.v1beta1.Entity.updated_at:type_name -> google.protobuf.Timestamp + 50, // 7: raystack.compass.v1beta1.Edge.properties:type_name -> google.protobuf.Struct + 49, // 8: raystack.compass.v1beta1.Edge.valid_from:type_name -> google.protobuf.Timestamp + 49, // 9: raystack.compass.v1beta1.Edge.valid_to:type_name -> google.protobuf.Timestamp + 49, // 10: raystack.compass.v1beta1.Edge.created_at:type_name -> google.protobuf.Timestamp + 50, // 11: raystack.compass.v1beta1.Namespace.metadata:type_name -> google.protobuf.Struct + 1, // 12: raystack.compass.v1beta1.GetAllEntitiesResponse.data:type_name -> raystack.compass.v1beta1.Entity + 1, // 13: raystack.compass.v1beta1.GetEntityByIDResponse.data:type_name -> raystack.compass.v1beta1.Entity + 50, // 14: raystack.compass.v1beta1.UpsertEntityRequest.properties:type_name -> google.protobuf.Struct + 1, // 15: raystack.compass.v1beta1.SearchEntitiesResponse.data:type_name -> raystack.compass.v1beta1.Entity + 3, // 16: raystack.compass.v1beta1.GetEntityTypesResponse.data:type_name -> raystack.compass.v1beta1.Type + 1, // 17: raystack.compass.v1beta1.GetEntityContextResponse.entity:type_name -> raystack.compass.v1beta1.Entity + 2, // 18: raystack.compass.v1beta1.GetEntityContextResponse.edges:type_name -> raystack.compass.v1beta1.Edge + 1, // 19: raystack.compass.v1beta1.GetEntityContextResponse.related:type_name -> raystack.compass.v1beta1.Entity + 2, // 20: raystack.compass.v1beta1.GetEntityImpactResponse.edges:type_name -> raystack.compass.v1beta1.Edge + 1, // 21: raystack.compass.v1beta1.GetEntityImpactResponse.affected:type_name -> raystack.compass.v1beta1.Entity + 50, // 22: raystack.compass.v1beta1.UpsertEdgeRequest.properties:type_name -> google.protobuf.Struct + 2, // 23: raystack.compass.v1beta1.GetEdgesResponse.data:type_name -> raystack.compass.v1beta1.Edge + 1, // 24: raystack.compass.v1beta1.GetUserStarredEntitiesResponse.data:type_name -> raystack.compass.v1beta1.Entity + 1, // 25: raystack.compass.v1beta1.GetMyStarredEntitiesResponse.data:type_name -> raystack.compass.v1beta1.Entity + 1, // 26: raystack.compass.v1beta1.GetMyStarredEntityResponse.data:type_name -> raystack.compass.v1beta1.Entity + 0, // 27: raystack.compass.v1beta1.GetEntityStargazersResponse.data:type_name -> raystack.compass.v1beta1.User + 50, // 28: raystack.compass.v1beta1.CreateNamespaceRequest.metadata:type_name -> google.protobuf.Struct + 4, // 29: raystack.compass.v1beta1.GetNamespaceResponse.namespace:type_name -> raystack.compass.v1beta1.Namespace + 50, // 30: raystack.compass.v1beta1.UpdateNamespaceRequest.metadata:type_name -> google.protobuf.Struct + 4, // 31: raystack.compass.v1beta1.ListNamespacesResponse.namespaces:type_name -> raystack.compass.v1beta1.Namespace + 5, // 32: raystack.compass.v1beta1.CompassService.GetAllEntities:input_type -> raystack.compass.v1beta1.GetAllEntitiesRequest + 7, // 33: raystack.compass.v1beta1.CompassService.GetEntityByID:input_type -> raystack.compass.v1beta1.GetEntityByIDRequest + 9, // 34: raystack.compass.v1beta1.CompassService.UpsertEntity:input_type -> raystack.compass.v1beta1.UpsertEntityRequest + 11, // 35: raystack.compass.v1beta1.CompassService.DeleteEntity:input_type -> raystack.compass.v1beta1.DeleteEntityRequest + 13, // 36: raystack.compass.v1beta1.CompassService.SearchEntities:input_type -> raystack.compass.v1beta1.SearchEntitiesRequest + 15, // 37: raystack.compass.v1beta1.CompassService.SuggestEntities:input_type -> raystack.compass.v1beta1.SuggestEntitiesRequest + 17, // 38: raystack.compass.v1beta1.CompassService.GetEntityTypes:input_type -> raystack.compass.v1beta1.GetEntityTypesRequest + 19, // 39: raystack.compass.v1beta1.CompassService.GetEntityContext:input_type -> raystack.compass.v1beta1.GetEntityContextRequest + 21, // 40: raystack.compass.v1beta1.CompassService.GetEntityImpact:input_type -> raystack.compass.v1beta1.GetEntityImpactRequest + 23, // 41: raystack.compass.v1beta1.CompassService.UpsertEdge:input_type -> raystack.compass.v1beta1.UpsertEdgeRequest + 25, // 42: raystack.compass.v1beta1.CompassService.GetEdges:input_type -> raystack.compass.v1beta1.GetEdgesRequest + 27, // 43: raystack.compass.v1beta1.CompassService.DeleteEdge:input_type -> raystack.compass.v1beta1.DeleteEdgeRequest + 29, // 44: raystack.compass.v1beta1.CompassService.StarEntity:input_type -> raystack.compass.v1beta1.StarEntityRequest + 31, // 45: raystack.compass.v1beta1.CompassService.UnstarEntity:input_type -> raystack.compass.v1beta1.UnstarEntityRequest + 33, // 46: raystack.compass.v1beta1.CompassService.GetUserStarredEntities:input_type -> raystack.compass.v1beta1.GetUserStarredEntitiesRequest + 35, // 47: raystack.compass.v1beta1.CompassService.GetMyStarredEntities:input_type -> raystack.compass.v1beta1.GetMyStarredEntitiesRequest + 37, // 48: raystack.compass.v1beta1.CompassService.GetMyStarredEntity:input_type -> raystack.compass.v1beta1.GetMyStarredEntityRequest + 39, // 49: raystack.compass.v1beta1.CompassService.GetEntityStargazers:input_type -> raystack.compass.v1beta1.GetEntityStargazersRequest + 41, // 50: raystack.compass.v1beta1.CompassService.CreateNamespace:input_type -> raystack.compass.v1beta1.CreateNamespaceRequest + 43, // 51: raystack.compass.v1beta1.CompassService.GetNamespace:input_type -> raystack.compass.v1beta1.GetNamespaceRequest + 45, // 52: raystack.compass.v1beta1.CompassService.UpdateNamespace:input_type -> raystack.compass.v1beta1.UpdateNamespaceRequest + 47, // 53: raystack.compass.v1beta1.CompassService.ListNamespaces:input_type -> raystack.compass.v1beta1.ListNamespacesRequest + 6, // 54: raystack.compass.v1beta1.CompassService.GetAllEntities:output_type -> raystack.compass.v1beta1.GetAllEntitiesResponse + 8, // 55: raystack.compass.v1beta1.CompassService.GetEntityByID:output_type -> raystack.compass.v1beta1.GetEntityByIDResponse + 10, // 56: raystack.compass.v1beta1.CompassService.UpsertEntity:output_type -> raystack.compass.v1beta1.UpsertEntityResponse + 12, // 57: raystack.compass.v1beta1.CompassService.DeleteEntity:output_type -> raystack.compass.v1beta1.DeleteEntityResponse + 14, // 58: raystack.compass.v1beta1.CompassService.SearchEntities:output_type -> raystack.compass.v1beta1.SearchEntitiesResponse + 16, // 59: raystack.compass.v1beta1.CompassService.SuggestEntities:output_type -> raystack.compass.v1beta1.SuggestEntitiesResponse + 18, // 60: raystack.compass.v1beta1.CompassService.GetEntityTypes:output_type -> raystack.compass.v1beta1.GetEntityTypesResponse + 20, // 61: raystack.compass.v1beta1.CompassService.GetEntityContext:output_type -> raystack.compass.v1beta1.GetEntityContextResponse + 22, // 62: raystack.compass.v1beta1.CompassService.GetEntityImpact:output_type -> raystack.compass.v1beta1.GetEntityImpactResponse + 24, // 63: raystack.compass.v1beta1.CompassService.UpsertEdge:output_type -> raystack.compass.v1beta1.UpsertEdgeResponse + 26, // 64: raystack.compass.v1beta1.CompassService.GetEdges:output_type -> raystack.compass.v1beta1.GetEdgesResponse + 28, // 65: raystack.compass.v1beta1.CompassService.DeleteEdge:output_type -> raystack.compass.v1beta1.DeleteEdgeResponse + 30, // 66: raystack.compass.v1beta1.CompassService.StarEntity:output_type -> raystack.compass.v1beta1.StarEntityResponse + 32, // 67: raystack.compass.v1beta1.CompassService.UnstarEntity:output_type -> raystack.compass.v1beta1.UnstarEntityResponse + 34, // 68: raystack.compass.v1beta1.CompassService.GetUserStarredEntities:output_type -> raystack.compass.v1beta1.GetUserStarredEntitiesResponse + 36, // 69: raystack.compass.v1beta1.CompassService.GetMyStarredEntities:output_type -> raystack.compass.v1beta1.GetMyStarredEntitiesResponse + 38, // 70: raystack.compass.v1beta1.CompassService.GetMyStarredEntity:output_type -> raystack.compass.v1beta1.GetMyStarredEntityResponse + 40, // 71: raystack.compass.v1beta1.CompassService.GetEntityStargazers:output_type -> raystack.compass.v1beta1.GetEntityStargazersResponse + 42, // 72: raystack.compass.v1beta1.CompassService.CreateNamespace:output_type -> raystack.compass.v1beta1.CreateNamespaceResponse + 44, // 73: raystack.compass.v1beta1.CompassService.GetNamespace:output_type -> raystack.compass.v1beta1.GetNamespaceResponse + 46, // 74: raystack.compass.v1beta1.CompassService.UpdateNamespace:output_type -> raystack.compass.v1beta1.UpdateNamespaceResponse + 48, // 75: raystack.compass.v1beta1.CompassService.ListNamespaces:output_type -> raystack.compass.v1beta1.ListNamespacesResponse + 54, // [54:76] is the sub-list for method output_type + 32, // [32:54] is the sub-list for method input_type + 32, // [32:32] is the sub-list for extension type_name + 32, // [32:32] is the sub-list for extension extendee + 0, // [0:32] is the sub-list for field type_name } func init() { file_raystack_compass_v1beta1_service_proto_init() } @@ -8981,14 +3048,13 @@ func file_raystack_compass_v1beta1_service_proto_init() { if File_raystack_compass_v1beta1_service_proto != nil { return } - file_raystack_compass_v1beta1_service_proto_msgTypes[27].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_raystack_compass_v1beta1_service_proto_rawDesc), len(file_raystack_compass_v1beta1_service_proto_rawDesc)), NumEnums: 0, - NumMessages: 143, + NumMessages: 49, NumExtensions: 0, NumServices: 1, }, diff --git a/handler/asset.go b/handler/asset.go deleted file mode 100644 index 9ce6a0ca..00000000 --- a/handler/asset.go +++ /dev/null @@ -1,720 +0,0 @@ -package handler - -//go:generate mockery --name=AssetService -r --case underscore --with-expecter --structname AssetService --filename asset_service.go --output=./mocks -import ( - "context" - "errors" - "fmt" - "time" - - "connectrpc.com/connect" - "github.com/r3labs/diff/v3" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/star" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "google.golang.org/protobuf/types/known/structpb" - "google.golang.org/protobuf/types/known/timestamppb" -) - -type AssetService interface { - GetAllAssets(ctx context.Context, flt asset.Filter, withTotal bool) ([]asset.Asset, uint32, error) - GetAssetByID(ctx context.Context, id string) (asset.Asset, error) - GetAssetByVersion(ctx context.Context, id string, version string) (asset.Asset, error) - GetAssetVersionHistory(ctx context.Context, flt asset.Filter, id string) ([]asset.Asset, error) - UpsertAsset(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset, upstreams, downstreams []string) (string, error) - UpsertAssetWithoutLineage(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset) (string, error) - DeleteAsset(ctx context.Context, ns *namespace.Namespace, id string) error - - GetLineage(ctx context.Context, urn string, query asset.LineageQuery) (asset.Lineage, error) - GetTypes(ctx context.Context, flt asset.Filter) (map[asset.Type]int, error) - - SearchAssets(ctx context.Context, cfg asset.SearchConfig) (results []asset.SearchResult, err error) - SuggestAssets(ctx context.Context, cfg asset.SearchConfig) (suggestions []string, err error) - - AddProbe(ctx context.Context, ns *namespace.Namespace, assetURN string, probe *asset.Probe) error - - GroupAssets(ctx context.Context, cfg asset.GroupConfig) ([]asset.GroupResult, error) -} - -func (server *Handler) GetAllAssets(ctx context.Context, req *connect.Request[compassv1beta1.GetAllAssetsRequest]) (*connect.Response[compassv1beta1.GetAllAssetsResponse], error) { - - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - fb := asset.NewFilterBuilder(). - Types(req.Msg.GetTypes()). - Services(req.Msg.GetServices()). - Q(req.Msg.GetQ()). - QFields(req.Msg.GetQFields()). - Size(int(req.Msg.GetSize())). - Offset(int(req.Msg.GetOffset())). - SortBy(req.Msg.GetSort()). - SortDirection(req.Msg.GetDirection()). - Data(req.Msg.GetData()) - if req.Msg.GetIsDeleted() { - fb = fb.IsDeleted(true) - } - flt, err := fb.Build() - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(err))) - } - - assets, totalCount, err := server.assetService.GetAllAssets(ctx, flt, req.Msg.GetWithTotal()) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - var assetsProto []*compassv1beta1.Asset - for _, a := range assets { - ap, err := assetToProto(a, false) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - assetsProto = append(assetsProto, ap) - } - - response := &compassv1beta1.GetAllAssetsResponse{ - Data: assetsProto, - } - - if req.Msg.GetWithTotal() { - response.Total = totalCount - } - - return connect.NewResponse(response), nil -} - -func (server *Handler) GetAssetByID(ctx context.Context, req *connect.Request[compassv1beta1.GetAssetByIDRequest]) (*connect.Response[compassv1beta1.GetAssetByIDResponse], error) { - - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - ast, err := server.assetService.GetAssetByID(ctx, req.Msg.GetId()) - if err != nil { - if errors.As(err, new(asset.InvalidError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if errors.As(err, new(asset.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - return nil, internalServerError(ctx, "internal error", err) - } - - astProto, err := assetToProto(ast, false) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.GetAssetByIDResponse{ - Data: astProto, - }), nil -} - -func (server *Handler) GetAssetStargazers(ctx context.Context, req *connect.Request[compassv1beta1.GetAssetStargazersRequest]) (*connect.Response[compassv1beta1.GetAssetStargazersResponse], error) { - - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - users, err := server.starService.GetStargazers(ctx, star.Filter{ - Size: int(req.Msg.GetSize()), - Offset: int(req.Msg.GetOffset()), - }, req.Msg.GetId()) - if err != nil { - if errors.Is(err, star.ErrEmptyUserID) || errors.Is(err, star.ErrEmptyAssetID) || errors.As(err, new(star.InvalidError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if errors.As(err, new(star.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - return nil, internalServerError(ctx, "internal error", err) - } - - usersPB := []*compassv1beta1.User{} - for _, us := range users { - usersPB = append(usersPB, userToProto(us)) - } - - return connect.NewResponse(&compassv1beta1.GetAssetStargazersResponse{ - Data: usersPB, - }), nil -} - -func (server *Handler) GetAssetVersionHistory(ctx context.Context, req *connect.Request[compassv1beta1.GetAssetVersionHistoryRequest]) (*connect.Response[compassv1beta1.GetAssetVersionHistoryResponse], error) { - - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - assetVersions, err := server.assetService.GetAssetVersionHistory(ctx, asset.Filter{ - Size: int(req.Msg.GetSize()), - Offset: int(req.Msg.GetOffset()), - }, req.Msg.GetId()) - if err != nil { - if errors.As(err, new(asset.InvalidError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if errors.As(err, new(asset.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - return nil, internalServerError(ctx, "internal error", err) - } - - assetsPB := []*compassv1beta1.Asset{} - for _, av := range assetVersions { - avPB, err := assetToProto(av, true) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - assetsPB = append(assetsPB, avPB) - } - - return connect.NewResponse(&compassv1beta1.GetAssetVersionHistoryResponse{ - Data: assetsPB, - }), nil -} - -func (server *Handler) GetAssetByVersion(ctx context.Context, req *connect.Request[compassv1beta1.GetAssetByVersionRequest]) (*connect.Response[compassv1beta1.GetAssetByVersionResponse], error) { - - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - if _, err := asset.ParseVersion(req.Msg.GetVersion()); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - - ast, err := server.assetService.GetAssetByVersion(ctx, req.Msg.GetId(), req.Msg.GetVersion()) - if err != nil { - if errors.As(err, new(asset.InvalidError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if errors.As(err, new(asset.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - return nil, internalServerError(ctx, "internal error", err) - } - - assetPB, err := assetToProto(ast, true) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.GetAssetByVersionResponse{ - Data: assetPB, - }), nil -} - -func (server *Handler) UpsertAsset(ctx context.Context, req *connect.Request[compassv1beta1.UpsertAssetRequest]) (*connect.Response[compassv1beta1.UpsertAssetResponse], error) { - - ns := middleware.FetchNamespaceFromContext(ctx) - userID, err := server.validateUserInCtx(ctx, ns) - if err != nil { - return nil, err - } - - baseAsset := req.Msg.GetAsset() - if baseAsset == nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("asset cannot be empty")) - } - - ast := server.buildAsset(baseAsset) - ast.UpdatedBy.ID = userID - - assetID, err := server.upsertAsset( - ctx, - ns, - ast, - "asset_upsert", - req.Msg.GetUpstreams(), - req.Msg.GetDownstreams(), - ) - if err != nil { - if req.Msg.GetUpdateOnly() && errors.As(err, new(asset.NotFoundError)) { - return connect.NewResponse(&compassv1beta1.UpsertAssetResponse{Id: ""}), nil - } - return nil, err - } - - return connect.NewResponse(&compassv1beta1.UpsertAssetResponse{ - Id: assetID, - }), nil -} - -func (server *Handler) UpsertPatchAsset(ctx context.Context, req *connect.Request[compassv1beta1.UpsertPatchAssetRequest]) (*connect.Response[compassv1beta1.UpsertPatchAssetResponse], error) { - - ns := middleware.FetchNamespaceFromContext(ctx) - userID, err := server.validateUserInCtx(ctx, ns) - if err != nil { - return nil, err - } - - baseAsset := req.Msg.GetAsset() - if baseAsset == nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("asset cannot be empty")) - } - - urn, err := server.validatePatchAsset(baseAsset) - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - - ast, err := server.assetService.GetAssetByID(ctx, urn) - if err != nil { - if errors.As(err, &asset.NotFoundError{}) { - if req.Msg.GetUpdateOnly() { - return connect.NewResponse(&compassv1beta1.UpsertPatchAssetResponse{Id: ""}), nil - } - } else { - return nil, internalServerError(ctx, "internal error", err) - } - } - - patchAssetMap := decodePatchAssetToMap(baseAsset) - ast.Patch(patchAssetMap) - ast.UpdatedBy.ID = userID - - var assetID string - if len(req.Msg.Upstreams) != 0 || len(req.Msg.Downstreams) != 0 || req.Msg.OverwriteLineage { - assetID, err = server.upsertAsset( - ctx, ns, ast, "asset_upsert_patch", req.Msg.GetUpstreams(), req.Msg.GetDownstreams(), - ) - } else { - assetID, err = server.upsertAssetWithoutLineage(ctx, ns, ast) - } - if err != nil { - return nil, err - } - - return connect.NewResponse(&compassv1beta1.UpsertPatchAssetResponse{ - Id: assetID, - }), nil -} - -func (server *Handler) DeleteAsset(ctx context.Context, req *connect.Request[compassv1beta1.DeleteAssetRequest]) (*connect.Response[compassv1beta1.DeleteAssetResponse], error) { - - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - if err := server.assetService.DeleteAsset(ctx, ns, req.Msg.GetId()); err != nil { - if errors.As(err, new(asset.InvalidError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if errors.As(err, new(asset.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.DeleteAssetResponse{}), nil -} - -func (server *Handler) CreateAssetProbe(ctx context.Context, req *connect.Request[compassv1beta1.CreateAssetProbeRequest]) (*connect.Response[compassv1beta1.CreateAssetProbeResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - - if req.Msg.Probe.Status == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("status is required")) - } - if !req.Msg.Probe.Timestamp.IsValid() { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("timestamp is required")) - } - - probe := asset.Probe{ - Status: req.Msg.Probe.Status, - StatusReason: req.Msg.Probe.StatusReason, - Metadata: req.Msg.Probe.Metadata.AsMap(), - Timestamp: req.Msg.Probe.Timestamp.AsTime(), - } - if err := server.assetService.AddProbe(ctx, ns, req.Msg.AssetUrn, &probe); err != nil { - if errors.As(err, &asset.NotFoundError{}) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.CreateAssetProbeResponse{ - Id: probe.ID, - }), nil -} - -func (server *Handler) upsertAsset( - ctx context.Context, - ns *namespace.Namespace, - ast asset.Asset, - mode string, - reqUpstreams, - reqDownstreams []*compassv1beta1.LineageNode, -) (assetID string, err error) { - if err := server.validateAsset(ast); err != nil { - return "", connect.NewError(connect.CodeInvalidArgument, err) - } - - upstreams := make([]string, 0, len(reqUpstreams)) - for _, pb := range reqUpstreams { - upstreams = append(upstreams, pb.Urn) - } - downstreams := make([]string, 0, len(reqDownstreams)) - for _, pb := range reqDownstreams { - downstreams = append(downstreams, pb.Urn) - } - - assetID, err = server.assetService.UpsertAsset(ctx, ns, &ast, upstreams, downstreams) - if errors.As(err, new(asset.InvalidError)) { - return "", connect.NewError(connect.CodeInvalidArgument, err) - } else if err != nil { - return "", internalServerError(ctx, "internal error", err) - } - - return -} - -func (server *Handler) upsertAssetWithoutLineage(ctx context.Context, ns *namespace.Namespace, ast asset.Asset) (string, error) { - if err := server.validateAsset(ast); err != nil { - return "", connect.NewError(connect.CodeInvalidArgument, err) - } - - assetID, err := server.assetService.UpsertAssetWithoutLineage(ctx, ns, &ast) - if err != nil { - if errors.As(err, new(asset.InvalidError)) { - return "", connect.NewError(connect.CodeInvalidArgument, err) - } - return "", internalServerError(ctx, "internal error", err) - } - - return assetID, nil -} - -func (server *Handler) buildAsset(baseAsset *compassv1beta1.UpsertAssetRequest_Asset) asset.Asset { - ast := asset.Asset{ - URN: baseAsset.GetUrn(), - Service: baseAsset.GetService(), - Type: asset.Type(baseAsset.GetType()), - Name: baseAsset.GetName(), - Description: baseAsset.GetDescription(), - Data: baseAsset.GetData().AsMap(), - URL: baseAsset.Url, - Labels: baseAsset.GetLabels(), - } - - var owners []user.User - for _, owner := range baseAsset.GetOwners() { - owners = append(owners, user.User{ - ID: owner.Id, - UUID: owner.Uuid, - Email: owner.Email, - Provider: owner.Provider, - }) - } - ast.Owners = owners - - return ast -} - -func (server *Handler) validateAsset(ast asset.Asset) error { - if ast.URN == "" { - return fmt.Errorf("urn is required") - } - if ast.Type == "" { - return fmt.Errorf("type is required") - } - if !ast.Type.IsValid() { - return fmt.Errorf("type is invalid") - } - if ast.Name == "" { - return fmt.Errorf("name is required") - } - if ast.Data == nil { - return fmt.Errorf("data is required") - } - if ast.Service == "" { - return fmt.Errorf("service is required") - } - - return nil -} - -func (server *Handler) validatePatchAsset(ast *compassv1beta1.UpsertPatchAssetRequest_Asset) (urn string, err error) { - if urn = ast.GetUrn(); urn == "" { - return "", fmt.Errorf("urn is required and can't be empty") - } - - typ := ast.GetType() - if typ == "" { - return "", fmt.Errorf("type is required and can't be empty") - } - - if !asset.Type(typ).IsValid() { - return "", fmt.Errorf("type is invalid") - } - - if service := ast.GetService(); service == "" { - return "", fmt.Errorf("service is required and can't be empty") - } - - return urn, nil -} - -func decodePatchAssetToMap(pb *compassv1beta1.UpsertPatchAssetRequest_Asset) map[string]interface{} { - if pb == nil { - return nil - } - m := map[string]interface{}{} - m["urn"] = pb.GetUrn() - m["type"] = pb.GetType() - m["service"] = pb.GetService() - if pb.GetName() != nil { - m["name"] = pb.GetName().Value - } - if pb.GetDescription() != nil { - m["description"] = pb.GetDescription().Value - } - if pb.GetData() != nil { - m["data"] = pb.GetData().AsMap() - } - if len(pb.Url) > 0 { - m["url"] = pb.Url - } - if pb.GetLabels() != nil { - m["labels"] = pb.GetLabels() - } - if len(pb.GetOwners()) > 0 { - ownersMap := []map[string]interface{}{} - ownersPB := pb.GetOwners() - for _, ownerPB := range ownersPB { - ownerMap := map[string]interface{}{} - if ownerPB.GetId() != "" { - ownerMap["id"] = ownerPB.GetId() - } - if ownerPB.GetUuid() != "" { - ownerMap["uuid"] = ownerPB.GetUuid() - } - if ownerPB.GetEmail() != "" { - ownerMap["email"] = ownerPB.GetEmail() - } - if ownerPB.GetProvider() != "" { - ownerMap["provider"] = ownerPB.GetProvider() - } - ownersMap = append(ownersMap, ownerMap) - } - m["owners"] = ownersMap - } - - return m -} - -// assetToProto transforms struct to proto -func assetToProto(a asset.Asset, withChangelog bool) (assetPB *compassv1beta1.Asset, err error) { - var data *structpb.Struct - if len(a.Data) > 0 { - data, err = structpb.NewStruct(a.Data) - if err != nil { - return - } - } - - owners := []*compassv1beta1.User{} - for _, o := range a.Owners { - owners = append(owners, userToProto(o)) - } - - var changelogProto []*compassv1beta1.Change - if withChangelog { - changelogProto, err = changelogToProto(a.Changelog) - if err != nil { - return nil, err - } - } - - var createdAtPB *timestamppb.Timestamp - if !a.CreatedAt.IsZero() { - createdAtPB = timestamppb.New(a.CreatedAt) - } - - var updatedAtPB *timestamppb.Timestamp - if !a.UpdatedAt.IsZero() { - updatedAtPB = timestamppb.New(a.UpdatedAt) - } - - var probes []*compassv1beta1.Probe - for _, probe := range a.Probes { - probeProto, err := probeToProto(probe) - if err != nil { - return assetPB, fmt.Errorf("error converting probe to proto: %w", err) - } - probes = append(probes, probeProto) - } - - assetPB = &compassv1beta1.Asset{ - Id: a.ID, - Urn: a.URN, - Type: string(a.Type), - Service: a.Service, - Name: a.Name, - Description: a.Description, - Data: data, - Url: a.URL, - Labels: a.Labels, - Owners: owners, - Version: a.Version, - UpdatedBy: userToProto(a.UpdatedBy), - Changelog: changelogProto, - CreatedAt: createdAtPB, - UpdatedAt: updatedAtPB, - Probes: probes, - IsDeleted: a.IsDeleted, - } - return -} - -// probeToProto transforms asset.Probe struct to proto -func probeToProto(probe asset.Probe) (*compassv1beta1.Probe, error) { - res := &compassv1beta1.Probe{ - Id: probe.ID, - AssetUrn: probe.AssetURN, - Status: probe.Status, - StatusReason: probe.StatusReason, - Timestamp: timestamppb.New(probe.Timestamp), - CreatedAt: timestamppb.New(probe.CreatedAt), - } - - if probe.Metadata != nil { - m, err := structpb.NewStruct(probe.Metadata) - if err != nil { - return nil, fmt.Errorf("error creating probe metadata: %w", err) - } - - res.Metadata = m - } - - return res, nil -} - -// changelogToProto transforms changelog struct to proto -func changelogToProto(cl diff.Changelog) ([]*compassv1beta1.Change, error) { - if len(cl) == 0 { - return nil, nil - } - var protoChanges []*compassv1beta1.Change - for _, ch := range cl { - chProto, err := diffChangeToProto(ch) - if err != nil { - return nil, err - } - - protoChanges = append(protoChanges, chProto) - } - return protoChanges, nil -} - -func diffChangeToProto(dc diff.Change) (*compassv1beta1.Change, error) { - from, err := structpb.NewValue(dc.From) - if err != nil { - return nil, err - } - to, err := structpb.NewValue(dc.To) - if err != nil { - return nil, err - } - - return &compassv1beta1.Change{ - Type: dc.Type, - Path: dc.Path, - From: from, - To: to, - }, nil -} - -// assetFromProto transforms proto to struct -// changelog is not populated by user, it should always be processed and coming from the server -func assetFromProto(pb *compassv1beta1.Asset) asset.Asset { - var assetOwners []user.User - for _, op := range pb.GetOwners() { - if op == nil { - continue - } - assetOwners = append(assetOwners, userFromProto(op)) - } - - var dataValue map[string]interface{} - if pb.GetData() != nil { - dataValue = pb.GetData().AsMap() - } - - var createdAt time.Time - if pb.GetCreatedAt() != nil { - createdAt = pb.GetCreatedAt().AsTime() - } - - var updatedAt time.Time - if pb.GetUpdatedAt() != nil { - updatedAt = pb.GetUpdatedAt().AsTime() - } - - var updatedBy user.User - if pb.GetUpdatedBy() != nil { - updatedBy = userFromProto(pb.GetUpdatedBy()) - } - - var clog diff.Changelog - if len(pb.GetChangelog()) > 0 { - for _, cg := range pb.GetChangelog() { - if cg == nil { - continue - } - clog = append(clog, diffChangeFromProto(cg)) - } - } - - return asset.Asset{ - ID: pb.GetId(), - URN: pb.GetUrn(), - Type: asset.Type(pb.GetType()), - Service: pb.GetService(), - Name: pb.GetName(), - Description: pb.GetDescription(), - Data: dataValue, - Labels: pb.GetLabels(), - Owners: assetOwners, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - Version: pb.GetVersion(), - Changelog: clog, - UpdatedBy: updatedBy, - } -} - -// diffChangeFromProto converts Change proto to diff.Change -func diffChangeFromProto(pb *compassv1beta1.Change) diff.Change { - var fromItf interface{} - if pb.GetFrom() != nil { - fromItf = pb.GetFrom().AsInterface() - } - - var toItf interface{} - if pb.GetTo() != nil { - toItf = pb.GetTo().AsInterface() - } - - return diff.Change{ - Type: pb.GetType(), - Path: pb.GetPath(), - From: fromItf, - To: toItf, - } -} diff --git a/handler/asset_test.go b/handler/asset_test.go deleted file mode 100644 index 4ca70a4a..00000000 --- a/handler/asset_test.go +++ /dev/null @@ -1,1686 +0,0 @@ -package handler - -import ( - "context" - "errors" - "fmt" - "reflect" - "testing" - "time" - - "connectrpc.com/connect" - "github.com/google/go-cmp/cmp" - "github.com/google/uuid" - "github.com/r3labs/diff/v3" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/star" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/handler/mocks" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - - "google.golang.org/protobuf/testing/protocmp" - "google.golang.org/protobuf/types/known/structpb" - "google.golang.org/protobuf/types/known/timestamppb" - "google.golang.org/protobuf/types/known/wrapperspb" -) - -func TestGetAllAssets(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - ) - type testCase struct { - Description string - Request *compassv1beta1.GetAllAssetsRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.AssetService, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.GetAllAssetsResponse) error - } - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.SharedState, - Metadata: nil, - } - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - defaultFilter, _ := asset.NewFilterBuilder().Build() - - var testCases = []testCase{ - { - Description: `should return internal server error if fetching fails`, - ExpectStatus: connect.CodeInternal, - Request: &compassv1beta1.GetAllAssetsRequest{}, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAllAssets(ctx, defaultFilter, false).Return([]asset.Asset{}, 0, errors.New("unknown error")) - }, - }, - { - Description: `should return internal server error if fetching total fails`, - Request: &compassv1beta1.GetAllAssetsRequest{ - WithTotal: true, - }, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAllAssets(ctx, defaultFilter, true).Return([]asset.Asset{}, 0, errors.New("unknown error")) - }, - }, - { - Description: `should successfully get config from request`, - Request: &compassv1beta1.GetAllAssetsRequest{ - Types: "table,topic", - Services: "bigquery,kafka", - Sort: "type", - Direction: "asc", - Data: map[string]string{ - "dataset": "booking", - "project": "p-godata-id", - }, - Q: "internal", - QFields: "name,urn", - Size: 30, - Offset: 50, - WithTotal: false, - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - cfg := asset.Filter{ - Types: []asset.Type{"table", "topic"}, - Services: []string{"bigquery", "kafka"}, - Size: 30, - Offset: 50, - SortBy: "type", - SortDirection: "asc", - QueryFields: []string{"name", "urn"}, - Query: "internal", - Data: map[string][]string{ - "dataset": {"booking"}, - "project": {"p-godata-id"}, - }, - } - as.EXPECT().GetAllAssets(ctx, cfg, false).Return([]asset.Asset{}, 0, nil) - }, - }, - { - Description: "should return status OK along with list of assets", - ExpectStatus: 0, - Request: &compassv1beta1.GetAllAssetsRequest{}, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAllAssets(ctx, defaultFilter, false).Return([]asset.Asset{ - {ID: "testid-1"}, - {ID: "testid-2", Owners: []user.User{{Email: "dummy@trash.com"}}}, - }, 0, nil) - }, - PostCheck: func(resp *compassv1beta1.GetAllAssetsResponse) error { - expected := &compassv1beta1.GetAllAssetsResponse{ - Data: []*compassv1beta1.Asset{ - {Id: "testid-1"}, - {Id: "testid-2", Owners: []*compassv1beta1.User{{Email: "dummy@trash.com"}}}, - }, - } - - if d := cmp.Diff(resp, expected, protocmp.Transform()); d != "" { - return fmt.Errorf("expected response to be %+v, was %+v\n\tdiff: %s", expected, resp, d) - } - return nil - }, - }, - { - Description: "should return total in the payload if with_total flag is given", - ExpectStatus: 0, - Request: &compassv1beta1.GetAllAssetsRequest{ - Types: "job", - Services: "kafka", - Size: 10, - Offset: 5, - WithTotal: true, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAllAssets(ctx, asset.Filter{ - Types: []asset.Type{"job"}, - Services: []string{"kafka"}, - Size: 10, - Offset: 5, - }, true).Return([]asset.Asset{ - {ID: "testid-1"}, - {ID: "testid-2"}, - {ID: "testid-3"}, - }, 150, nil) - }, - PostCheck: func(resp *compassv1beta1.GetAllAssetsResponse) error { - expected := &compassv1beta1.GetAllAssetsResponse{ - Total: 150, - Data: []*compassv1beta1.Asset{ - {Id: "testid-1"}, - {Id: "testid-2"}, - {Id: "testid-3"}, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - - mockUserSvc := new(mocks.UserService) - mockAssetSvc := new(mocks.AssetService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetSvc, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockAssetSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, mockAssetSvc, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.GetAllAssets(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestGetAssetByID(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - assetID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "base-test", - State: namespace.SharedState, - Metadata: nil, - } - now = time.Now() - ast = asset.Asset{ - ID: assetID, - Owners: []user.User{{Email: "dummy@trash.com"}}, - Probes: []asset.Probe{ - { - ID: uuid.NewString(), - AssetURN: assetID, - Status: "RUNNING", - StatusReason: "reason-1", - Metadata: map[string]interface{}{ - "foo": "bar", - }, - Timestamp: now, - CreatedAt: now.Add(-24 * time.Hour), - }, - { - ID: uuid.NewString(), - AssetURN: assetID, - Status: "FAILED", - StatusReason: "reason-2", - Timestamp: now.Add(2 * time.Hour), - CreatedAt: now.Add(-26 * time.Hour), - }, - }, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - - type testCase struct { - Description string - ExpectStatus connect.Code - Setup func(context.Context, *mocks.AssetService, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.GetAssetByIDResponse) error - } - - var testCases = []testCase{ - { - Description: `should return invalid argument if asset id is not uuid`, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetByID(ctx, assetID).Return(asset.Asset{}, asset.InvalidError{AssetID: assetID}) - }, - }, - { - Description: `should return not found if asset doesn't exist`, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetByID(ctx, assetID).Return(asset.Asset{}, asset.NotFoundError{AssetID: assetID}) - }, - }, - { - Description: `should return internal server error if fetching fails`, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetByID(ctx, assetID).Return(asset.Asset{}, errors.New("unknown error")) - }, - }, - { - Description: "should return http 200 status along with the asset, if found", - ExpectStatus: 0, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetByID(ctx, assetID).Return(ast, nil) - }, - PostCheck: func(resp *compassv1beta1.GetAssetByIDResponse) error { - expected := &compassv1beta1.GetAssetByIDResponse{ - Data: &compassv1beta1.Asset{ - Id: assetID, - Owners: []*compassv1beta1.User{{Email: "dummy@trash.com"}}, - Probes: []*compassv1beta1.Probe{ - { - Id: ast.Probes[0].ID, - AssetUrn: ast.Probes[0].AssetURN, - Status: ast.Probes[0].Status, - StatusReason: ast.Probes[0].StatusReason, - Metadata: newStructpb(t, ast.Probes[0].Metadata), - Timestamp: timestamppb.New(ast.Probes[0].Timestamp), - CreatedAt: timestamppb.New(ast.Probes[0].CreatedAt), - }, - { - Id: ast.Probes[1].ID, - AssetUrn: ast.Probes[1].AssetURN, - Status: ast.Probes[1].Status, - StatusReason: ast.Probes[1].StatusReason, - Timestamp: timestamppb.New(ast.Probes[1].Timestamp), - CreatedAt: timestamppb.New(ast.Probes[1].CreatedAt), - }, - }, - }, - } - if d := cmp.Diff(resp, expected, protocmp.Transform()); d != "" { - return fmt.Errorf("mismatch (-want +got):\n%s", d) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := mocks.NewUserService(t) - mockAssetSvc := mocks.NewAssetService(t) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetSvc, mockNamespaceSvc) - } - defer mockNamespaceSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, mockAssetSvc, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.GetAssetByID(ctx, connect.NewRequest(&compassv1beta1.GetAssetByIDRequest{ - Id: assetID, - })) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestUpsertAsset(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - assetID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "base-test", - State: namespace.SharedState, - Metadata: nil, - } - validPayload = &compassv1beta1.UpsertAssetRequest{ - Asset: &compassv1beta1.UpsertAssetRequest_Asset{ - Urn: "test dagger", - Type: "table", - Name: "new-name", - Service: "kafka", - Data: &structpb.Struct{}, - Url: "https://sample-url.com", - Owners: []*compassv1beta1.User{{Id: "id", Uuid: "", Email: "email@email.com", Provider: "provider"}}, - }, - Upstreams: []*compassv1beta1.LineageNode{ - { - Urn: "upstream-1", - Type: "job", - Service: "optimus", - }, - }, - Downstreams: []*compassv1beta1.LineageNode{ - { - Urn: "downstream-1", - Type: "dashboard", - Service: "metabase", - }, - { - Urn: "downstream-2", - Type: "dashboard", - Service: "tableau", - }, - }, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.UpsertAssetRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.AssetService, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.UpsertAssetResponse) error - } - - var testCases = []testCase{ - { - Description: "empty payload will return invalid argument", - Request: &compassv1beta1.UpsertAssetRequest{}, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "empty asset will return invalid argument", - Request: &compassv1beta1.UpsertAssetRequest{Asset: &compassv1beta1.UpsertAssetRequest_Asset{}}, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "empty urn will return invalid argument", - Request: &compassv1beta1.UpsertAssetRequest{ - Asset: &compassv1beta1.UpsertAssetRequest_Asset{ - Urn: "", - Name: "some-name", - Data: &structpb.Struct{}, - Service: "some-service", - Type: "table", - }, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "empty service will return invalid argument", - Request: &compassv1beta1.UpsertAssetRequest{ - Asset: &compassv1beta1.UpsertAssetRequest_Asset{ - Urn: "some-urn", - Name: "some-name", - Data: &structpb.Struct{}, - Service: "", - Type: "table", - }, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "empty type will return invalid argument", - Request: &compassv1beta1.UpsertAssetRequest{ - Asset: &compassv1beta1.UpsertAssetRequest_Asset{ - Urn: "some-urn", - Name: "some-name", - Data: &structpb.Struct{}, - Service: "some-service", - Type: "", - }, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "invalid type will return invalid argument", - Request: &compassv1beta1.UpsertAssetRequest{ - Asset: &compassv1beta1.UpsertAssetRequest_Asset{ - Urn: "some-urn", - Name: "some-name", - Data: &structpb.Struct{}, - Service: "some-service", - Type: "invalid type", - }, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "should return internal server error when upserting asset service failed", - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - expectedErr := errors.New("unknown error") - as.EXPECT().UpsertAsset( - ctx, - ns, - mock.AnythingOfType("*asset.Asset"), - mock.AnythingOfType("[]string"), - mock.AnythingOfType("[]string"), - ).Return("", expectedErr) - }, - Request: validPayload, - ExpectStatus: connect.CodeInternal, - }, - { - Description: "should return OK and asset's ID if the asset is successfully created/updated", - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - ast := asset.Asset{ - URN: "test dagger", - Type: asset.TypeTable, - Name: "new-name", - Service: "kafka", - UpdatedBy: user.User{ID: userID}, - Data: map[string]interface{}{}, - URL: "https://sample-url.com", - Owners: []user.User{{ID: "id", UUID: "", Email: "email@email.com", Provider: "provider"}}, - } - upstreams := []string{"upstream-1"} - downstreams := []string{"downstream-1", "downstream-2"} - - assetWithID := ast - assetWithID.ID = assetID - - as.EXPECT().UpsertAsset(ctx, ns, &ast, upstreams, downstreams).Return(assetWithID.ID, nil).Run(func(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset, upstreams, downstreams []string) { - ast.ID = assetWithID.ID - }) - }, - Request: validPayload, - ExpectStatus: 0, - PostCheck: func(resp *compassv1beta1.UpsertAssetResponse) error { - expected := &compassv1beta1.UpsertAssetResponse{ - Id: assetID, - } - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - - mockUserSvc := new(mocks.UserService) - mockAssetSvc := new(mocks.AssetService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetSvc, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockAssetSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, mockAssetSvc, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.UpsertAsset(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestUpsertPatchAsset(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - assetID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "base-test", - State: namespace.SharedState, - Metadata: nil, - } - validPayload = &compassv1beta1.UpsertPatchAssetRequest{ - Asset: &compassv1beta1.UpsertPatchAssetRequest_Asset{ - Urn: "test dagger", - Type: "table", - Name: wrapperspb.String("new-name"), - Service: "kafka", - Data: &structpb.Struct{}, - Url: "https://sample-url.com", - Owners: []*compassv1beta1.User{{Id: "id", Uuid: "", Email: "email@email.com", Provider: "provider"}}, - }, - Upstreams: []*compassv1beta1.LineageNode{ - { - Urn: "upstream-1", - Type: "job", - Service: "optimus", - }, - }, - Downstreams: []*compassv1beta1.LineageNode{ - { - Urn: "downstream-1", - Type: "dashboard", - Service: "metabase", - }, - { - Urn: "downstream-2", - Type: "dashboard", - Service: "tableau", - }, - }, - } - currentAsset = asset.Asset{ - URN: "test dagger", - Type: asset.TypeTable, - Name: "old-name", // this value will be updated - Service: "kafka", - UpdatedBy: user.User{ID: userID}, - Data: map[string]interface{}{}, - URL: "https://sample-url-old.com", - Owners: []user.User{{ID: "id", UUID: "", Email: "email@email.com", Provider: "provider"}}, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.UpsertPatchAssetRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.AssetService, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.UpsertPatchAssetResponse) error - } - - var testCases = []testCase{ - { - Description: "empty payload will return invalid argument", - Request: &compassv1beta1.UpsertPatchAssetRequest{}, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "empty asset will return invalid argument", - Request: &compassv1beta1.UpsertPatchAssetRequest{Asset: &compassv1beta1.UpsertPatchAssetRequest_Asset{}}, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "empty urn will return invalid argument", - Request: &compassv1beta1.UpsertPatchAssetRequest{ - Asset: &compassv1beta1.UpsertPatchAssetRequest_Asset{ - Urn: "", - Name: wrapperspb.String("some-name"), - Data: &structpb.Struct{}, - Service: "some-service", - Type: "table", - }, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "empty service will return invalid argument", - Request: &compassv1beta1.UpsertPatchAssetRequest{ - Asset: &compassv1beta1.UpsertPatchAssetRequest_Asset{ - Urn: "some-urn", - Name: wrapperspb.String("some-name"), - Data: &structpb.Struct{}, - Service: "", - Type: "table", - }, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "empty type will return invalid argument", - Request: &compassv1beta1.UpsertPatchAssetRequest{ - Asset: &compassv1beta1.UpsertPatchAssetRequest_Asset{ - Urn: "some-urn", - Name: wrapperspb.String("some-name"), - Data: &structpb.Struct{}, - Service: "some-service", - Type: "", - }, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "invalid type will return invalid argument", - Request: &compassv1beta1.UpsertPatchAssetRequest{ - Asset: &compassv1beta1.UpsertPatchAssetRequest_Asset{ - Urn: "some-urn", - Name: wrapperspb.String("some-name"), - Data: &structpb.Struct{}, - Service: "some-service", - Type: "invalid type", - }, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "should return internal server error when finding asset failed", - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - expectedErr := errors.New("unknown error") - as.EXPECT().GetAssetByID(ctx, "test dagger").Return(currentAsset, expectedErr) - }, - Request: validPayload, - ExpectStatus: connect.CodeInternal, - }, - { - Description: "should return internal server error when upserting asset service failed", - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - expectedErr := errors.New("unknown error") - as.EXPECT().GetAssetByID(ctx, "test dagger").Return(currentAsset, nil) - as.EXPECT().UpsertAsset(ctx, ns, mock.AnythingOfType("*asset.Asset"), mock.AnythingOfType("[]string"), mock.AnythingOfType("[]string")).Return("1234-5678", expectedErr) - }, - Request: validPayload, - ExpectStatus: connect.CodeInternal, - }, - { - Description: "should return OK and asset's ID if the asset is successfully created/patched", - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - patchedAsset := asset.Asset{ - URN: "test dagger", - Type: asset.TypeTable, - Name: "new-name", - Service: "kafka", - UpdatedBy: user.User{ID: userID}, - Data: map[string]interface{}{}, - URL: "https://sample-url.com", - Owners: []user.User{{ID: "id", UUID: "", Email: "email@email.com", Provider: "provider"}}, - } - upstreams := []string{"upstream-1"} - downstreams := []string{"downstream-1", "downstream-2"} - - assetWithID := patchedAsset - assetWithID.ID = assetID - - as.EXPECT().GetAssetByID(ctx, "test dagger").Return(currentAsset, nil) - as.EXPECT().UpsertAsset(ctx, ns, &patchedAsset, upstreams, downstreams).Return(assetWithID.ID, nil).Run(func(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset, upstreams, downstreams []string) { - patchedAsset.ID = assetWithID.ID - }) - }, - Request: validPayload, - ExpectStatus: 0, - PostCheck: func(resp *compassv1beta1.UpsertPatchAssetResponse) error { - expected := &compassv1beta1.UpsertPatchAssetResponse{ - Id: assetID, - } - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - - }, - }, - { - Description: "without explicit overwrite_lineage, should upsert asset without lineage", - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - patchedAsset := asset.Asset{ - URN: "test dagger", - Type: asset.TypeTable, - Name: "new-name", - Service: "kafka", - UpdatedBy: user.User{ID: userID}, - Data: map[string]interface{}{}, - URL: "https://sample-url-old.com", - Owners: []user.User{{ID: "id", UUID: "", Email: "email@email.com", Provider: "provider"}}, - } - - assetWithID := patchedAsset - assetWithID.ID = assetID - - as.EXPECT().GetAssetByID(ctx, "test dagger").Return(currentAsset, nil) - as.EXPECT().UpsertAssetWithoutLineage(ctx, ns, &patchedAsset). - Return(assetWithID.ID, nil). - Run(func(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset) { - patchedAsset.ID = assetWithID.ID - }) - }, - Request: &compassv1beta1.UpsertPatchAssetRequest{ - Asset: &compassv1beta1.UpsertPatchAssetRequest_Asset{ - Urn: "test dagger", - Type: "table", - Name: wrapperspb.String("new-name"), - Service: "kafka", - Data: &structpb.Struct{}, - Owners: []*compassv1beta1.User{{Id: "id", Uuid: "", Email: "email@email.com", Provider: "provider"}}, - }, - }, - ExpectStatus: 0, - PostCheck: func(resp *compassv1beta1.UpsertPatchAssetResponse) error { - expected := &compassv1beta1.UpsertPatchAssetResponse{ - Id: assetID, - } - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - - }, - }, - { - Description: "with explicit overwrite_lineage, should upsert asset when lineage is not in the request", - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - patchedAsset := asset.Asset{ - URN: "test dagger", - Type: asset.TypeTable, - Name: "new-name", - Service: "kafka", - UpdatedBy: user.User{ID: userID}, - Data: map[string]interface{}{}, - URL: "https://sample-url-old.com", - Owners: []user.User{{ID: "id", UUID: "", Email: "email@email.com", Provider: "provider"}}, - } - - assetWithID := patchedAsset - assetWithID.ID = assetID - - as.EXPECT().GetAssetByID(ctx, "test dagger").Return(currentAsset, nil) - as.EXPECT().UpsertAsset(ctx, ns, &patchedAsset, []string{}, []string{}). - Return(assetWithID.ID, nil). - Run(func(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset, _, _ []string) { - patchedAsset.ID = assetWithID.ID - }) - }, - Request: &compassv1beta1.UpsertPatchAssetRequest{ - Asset: &compassv1beta1.UpsertPatchAssetRequest_Asset{ - Urn: "test dagger", - Type: "table", - Name: wrapperspb.String("new-name"), - Service: "kafka", - Data: &structpb.Struct{}, - Owners: []*compassv1beta1.User{{Id: "id", Uuid: "", Email: "email@email.com", Provider: "provider"}}, - }, - OverwriteLineage: true, - }, - ExpectStatus: 0, - PostCheck: func(resp *compassv1beta1.UpsertPatchAssetResponse) error { - expected := &compassv1beta1.UpsertPatchAssetResponse{ - Id: assetID, - } - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - - mockUserSvc := new(mocks.UserService) - mockAssetSvc := new(mocks.AssetService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetSvc, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockAssetSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, mockAssetSvc, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.UpsertPatchAsset(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestDeleteAsset(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "base-test", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type TestCase struct { - Description string - AssetID string - ExpectStatus connect.Code - Setup func(ctx context.Context, as *mocks.AssetService, astID string, nss *mocks.NamespaceService) - } - - var testCases = []TestCase{ - { - Description: "should return invalid argument when asset id is not uuid", - AssetID: "not-uuid", - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, astID string, nss *mocks.NamespaceService) { - as.EXPECT().DeleteAsset(ctx, ns, "not-uuid").Return(asset.InvalidError{AssetID: astID}) - }, - }, - { - Description: "should return not found when asset cannot be found", - AssetID: assetID, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, as *mocks.AssetService, astID string, nss *mocks.NamespaceService) { - as.EXPECT().DeleteAsset(ctx, ns, astID).Return(asset.NotFoundError{AssetID: astID}) - }, - }, - { - Description: "should return 500 on error deleting asset", - AssetID: assetID, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, as *mocks.AssetService, astID string, nss *mocks.NamespaceService) { - as.EXPECT().DeleteAsset(ctx, ns, astID).Return(errors.New("error deleting asset")) - }, - }, - { - Description: "should return OK on success", - AssetID: assetID, - ExpectStatus: 0, - Setup: func(ctx context.Context, as *mocks.AssetService, astID string, nss *mocks.NamespaceService) { - as.EXPECT().DeleteAsset(ctx, ns, astID).Return(nil) - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - - mockUserSvc := new(mocks.UserService) - mockAssetSvc := new(mocks.AssetService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetSvc, assetID, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockAssetSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, mockAssetSvc, nil, nil, nil, nil, mockUserSvc) - - _, err := handler.DeleteAsset(ctx, connect.NewRequest(&compassv1beta1.DeleteAssetRequest{ - Id: tc.AssetID, - })) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - }) - } -} - -func TestGetAssetStargazers(t *testing.T) { - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - var ( - offset = 10 - size = 20 - defaultStarCfg = star.Filter{Offset: offset, Size: size} - assetID = uuid.NewString() - userID = uuid.NewString() - userUUID = uuid.NewString() - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type TestCase struct { - Description string - Request *compassv1beta1.GetAssetStargazersRequest - ExpectStatus connect.Code - Setup func(ctx context.Context, ss *mocks.StarService, nss *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.GetAssetStargazersResponse) error - } - - var testCases = []TestCase{ - { - Description: "should return internal server error if failed to fetch star repository", - ExpectStatus: connect.CodeInternal, - Request: &compassv1beta1.GetAssetStargazersRequest{ - Id: assetID, - Size: uint32(size), - Offset: uint32(offset), - }, - Setup: func(ctx context.Context, ss *mocks.StarService, nss *mocks.NamespaceService) { - ss.EXPECT().GetStargazers(ctx, defaultStarCfg, assetID).Return(nil, errors.New("some error")) - }, - }, - { - Description: "should return not found if star repository return not found error", - ExpectStatus: connect.CodeNotFound, - Request: &compassv1beta1.GetAssetStargazersRequest{ - Id: assetID, - Size: uint32(size), - Offset: uint32(offset), - }, - Setup: func(ctx context.Context, ss *mocks.StarService, nss *mocks.NamespaceService) { - ss.EXPECT().GetStargazers(ctx, defaultStarCfg, assetID).Return(nil, star.NotFoundError{}) - }, - }, - { - Description: "should return OK if star repository return nil error", - ExpectStatus: 0, - Request: &compassv1beta1.GetAssetStargazersRequest{ - Id: assetID, - Size: uint32(size), - Offset: uint32(offset), - }, - Setup: func(ctx context.Context, ss *mocks.StarService, nss *mocks.NamespaceService) { - ss.EXPECT().GetStargazers(ctx, defaultStarCfg, assetID).Return(nil, nil) - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - - mockUserSvc := new(mocks.UserService) - mockStarSvc := new(mocks.StarService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockStarSvc, mockNamespaceSvc) - } - defer mockStarSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, mockStarSvc, nil, nil, nil, mockUserSvc) - - got, err := handler.GetAssetStargazers(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestGetAssetVersionHistory(t *testing.T) { - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - var ( - assetID = uuid.NewString() - userID = uuid.NewString() - userUUID = uuid.NewString() - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type TestCase struct { - Description string - Request *compassv1beta1.GetAssetVersionHistoryRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.AssetService, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.GetAssetVersionHistoryResponse) error - } - - var testCases = []TestCase{ - { - Description: `should return invalid argument if asset id is not uuid`, - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.GetAssetVersionHistoryRequest{ - Id: assetID, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetVersionHistory(ctx, asset.Filter{}, assetID).Return([]asset.Asset{}, asset.InvalidError{AssetID: assetID}) - }, - }, - { - Description: `should return internal server error if fetching fails`, - ExpectStatus: connect.CodeInternal, - Request: &compassv1beta1.GetAssetVersionHistoryRequest{ - Id: assetID, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetVersionHistory(ctx, asset.Filter{}, assetID).Return([]asset.Asset{}, errors.New("unknown error")) - }, - }, - { - Description: `should parse querystring to get config`, - Request: &compassv1beta1.GetAssetVersionHistoryRequest{ - Id: assetID, - Size: 30, - Offset: 50, - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetVersionHistory(ctx, asset.Filter{ - Size: 30, - Offset: 50, - }, assetID).Return([]asset.Asset{}, nil) - }, - }, - { - Description: "should return status OK along with list of asset versions", - ExpectStatus: 0, - Request: &compassv1beta1.GetAssetVersionHistoryRequest{ - Id: assetID, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetVersionHistory(ctx, asset.Filter{}, assetID).Return([]asset.Asset{ - {ID: "testid-1"}, - {ID: "testid-2"}, - }, nil) - }, - PostCheck: func(resp *compassv1beta1.GetAssetVersionHistoryResponse) error { - expected := &compassv1beta1.GetAssetVersionHistoryResponse{ - Data: []*compassv1beta1.Asset{ - { - Id: "testid-1", - }, - { - Id: "testid-2", - }, - }, - } - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - - mockUserSvc := new(mocks.UserService) - mockAssetSvc := new(mocks.AssetService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetSvc, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockAssetSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, mockAssetSvc, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.GetAssetVersionHistory(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestGetAssetByVersion(t *testing.T) { - - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - assetID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "base-test", - State: namespace.SharedState, - Metadata: nil, - } - version = "0.2" - ast = asset.Asset{ - ID: assetID, - Version: version, - Owners: []user.User{{Email: "dummy@trash.com"}}, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type TestCase struct { - Description string - Request *compassv1beta1.GetAssetByVersionRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.AssetService, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.GetAssetByVersionResponse) error - } - - var testCases = []TestCase{ - { - Description: `should return invalid argument if asset id is not uuid`, - Request: &compassv1beta1.GetAssetByVersionRequest{ - Id: assetID, - Version: version, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetByVersion(ctx, assetID, version).Return(asset.Asset{}, asset.InvalidError{AssetID: assetID}) - }, - }, - { - Description: `should return not found if asset doesn't exist`, - ExpectStatus: connect.CodeNotFound, - Request: &compassv1beta1.GetAssetByVersionRequest{ - Id: assetID, - Version: version, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetByVersion(ctx, assetID, version).Return(asset.Asset{}, asset.NotFoundError{AssetID: assetID}) - }, - }, - { - Description: `should return internal server error if fetching fails`, - ExpectStatus: connect.CodeInternal, - Request: &compassv1beta1.GetAssetByVersionRequest{ - Id: assetID, - Version: version, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetByVersion(ctx, assetID, version).Return(asset.Asset{}, errors.New("unknown error")) - }, - }, - { - Description: "should return status OK along with the asset if found", - ExpectStatus: 0, - Request: &compassv1beta1.GetAssetByVersionRequest{ - Id: assetID, - Version: version, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT().GetAssetByVersion(ctx, assetID, version).Return(ast, nil) - }, - PostCheck: func(resp *compassv1beta1.GetAssetByVersionResponse) error { - expected := &compassv1beta1.GetAssetByVersionResponse{ - Data: &compassv1beta1.Asset{ - Id: assetID, - Owners: []*compassv1beta1.User{{Email: "dummy@trash.com"}}, - Version: version, - }, - } - if d := cmp.Diff(resp, expected, protocmp.Transform()); d != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - - mockUserSvc := new(mocks.UserService) - mockAssetSvc := new(mocks.AssetService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetSvc, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockAssetSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, mockAssetSvc, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.GetAssetByVersion(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestCreateAssetProbe(t *testing.T) { - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - assetURN = "test-urn" - now = time.Now().UTC() - probeID = uuid.NewString() - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.CreateAssetProbeRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.AssetService, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.CreateAssetProbeResponse) error - } - - var testCases = []testCase{ - { - Description: `should return error if status is missing`, - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.CreateAssetProbeRequest{ - AssetUrn: assetURN, - Probe: &compassv1beta1.CreateAssetProbeRequest_Probe{ - Timestamp: timestamppb.New(now), - }, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: `should return error if timestamp is missing`, - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.CreateAssetProbeRequest{ - AssetUrn: assetURN, - Probe: &compassv1beta1.CreateAssetProbeRequest_Probe{ - Status: "RUNNING", - }, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: `should return not found if asset doesn't exist`, - ExpectStatus: connect.CodeNotFound, - Request: &compassv1beta1.CreateAssetProbeRequest{ - AssetUrn: assetURN, - Probe: &compassv1beta1.CreateAssetProbeRequest_Probe{ - Status: "RUNNING", - Timestamp: timestamppb.New(now), - }, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT(). - AddProbe(ctx, ns, assetURN, mock.AnythingOfType("*asset.Probe")). - Return(asset.NotFoundError{URN: assetURN}) - }, - }, - { - Description: `should return internal server error if adding probe fails`, - ExpectStatus: connect.CodeInternal, - Request: &compassv1beta1.CreateAssetProbeRequest{ - AssetUrn: assetURN, - Probe: &compassv1beta1.CreateAssetProbeRequest_Probe{ - Status: "RUNNING", - Timestamp: timestamppb.New(now), - }, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - as.EXPECT(). - AddProbe(ctx, ns, assetURN, mock.AnythingOfType("*asset.Probe")). - Return(errors.New("unknown error")) - }, - }, - { - Description: "should return probe on success", - ExpectStatus: 0, - Request: &compassv1beta1.CreateAssetProbeRequest{ - AssetUrn: assetURN, - Probe: &compassv1beta1.CreateAssetProbeRequest_Probe{ - Status: "FINISHED", - StatusReason: "test reason", - Timestamp: timestamppb.New(now), - Metadata: newStructpb(t, map[string]interface{}{ - "foo1": "bar1", - "foo2": "bar2", - }), - }, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - expectedProbe := &asset.Probe{ - Status: "FINISHED", - StatusReason: "test reason", - Timestamp: now, - Metadata: map[string]interface{}{ - "foo1": "bar1", - "foo2": "bar2", - }, - } - as.EXPECT().AddProbe(ctx, ns, assetURN, expectedProbe).Run(func(ctx context.Context, ns *namespace.Namespace, assetURN string, probe *asset.Probe) { - probe.ID = probeID - }).Return(nil) - }, - PostCheck: func(resp *compassv1beta1.CreateAssetProbeResponse) error { - expected := &compassv1beta1.CreateAssetProbeResponse{ - Id: probeID, - } - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - - mockUserSvc := mocks.NewUserService(t) - mockAssetSvc := mocks.NewAssetService(t) - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - if tc.Setup != nil { - tc.Setup(ctx, mockAssetSvc, mockNamespaceSvc) - } - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, mockAssetSvc, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.CreateAssetProbe(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestAssetToProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - dataPB, err := structpb.NewStruct(map[string]interface{}{ - "data1": "datavalue1", - }) - if err != nil { - t.Fatal(err) - } - - type testCase struct { - Title string - Asset asset.Asset - ExpectProto *compassv1beta1.Asset - } - - var testCases = []testCase{ - { - Title: "should return nil data pb, label pb, empty owners pb, nil changelog pb, no timestamp pb if data is empty", - Asset: asset.Asset{ID: "id1", URN: "urn1"}, - ExpectProto: &compassv1beta1.Asset{Id: "id1", Urn: "urn1"}, - }, - { - Title: "should return full pb if all fileds are not zero", - Asset: asset.Asset{ - ID: "id1", - URN: "urn1", - Data: map[string]interface{}{ - "data1": "datavalue1", - }, - Owners: []user.User{{Email: "dummy@trash.com"}}, - Labels: map[string]string{ - "label1": "labelvalue1", - }, - Changelog: diff.Changelog{ - diff.Change{ - From: "1", - To: "2", - Path: []string{"path1/path2"}, - }, - }, - CreatedAt: timeDummy, - UpdatedAt: timeDummy, - }, - ExpectProto: &compassv1beta1.Asset{ - Id: "id1", - Urn: "urn1", - Data: dataPB, - Owners: []*compassv1beta1.User{{Email: "dummy@trash.com"}}, - Labels: map[string]string{ - "label1": "labelvalue1", - }, - Changelog: []*compassv1beta1.Change{ - { - - From: structpb.NewStringValue("1"), - To: structpb.NewStringValue("2"), - Path: []string{"path1/path2"}, - }, - }, - CreatedAt: timestamppb.New(timeDummy), - UpdatedAt: timestamppb.New(timeDummy), - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got, err := assetToProto(tc.Asset, true) - if err != nil { - t.Error(err) - } - if diff := cmp.Diff(got, tc.ExpectProto, protocmp.Transform()); diff != "" { - t.Errorf("expected response to be %+v, was %+v", tc.ExpectProto, got) - } - }) - } -} - -func TestAssetFromProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - dataPB, err := structpb.NewStruct(map[string]interface{}{ - "data1": "datavalue1", - }) - if err != nil { - t.Fatal(err) - } - - type testCase struct { - Title string - AssetPB *compassv1beta1.Asset - ExpectAsset asset.Asset - } - - var testCases = []testCase{ - { - Title: "should return empty labels, data, and owners if all pb empty", - AssetPB: &compassv1beta1.Asset{Id: "id1"}, - ExpectAsset: asset.Asset{ID: "id1"}, - }, - { - Title: "should return non empty labels, data, and owners if all pb is not empty", - AssetPB: &compassv1beta1.Asset{ - Id: "id1", - Urn: "urn1", - Name: "name1", - Data: dataPB, - Labels: map[string]string{ - "label1": "labelvalue1", - }, - Owners: []*compassv1beta1.User{ - { - Id: "uid1", - }, - { - Id: "uid2", - }, - }, - Changelog: []*compassv1beta1.Change{ - { - - From: structpb.NewStringValue("1"), - To: structpb.NewStringValue("2"), - Path: []string{"path1/path2"}, - }, - }, - CreatedAt: timestamppb.New(timeDummy), - UpdatedAt: timestamppb.New(timeDummy), - }, - ExpectAsset: asset.Asset{ - ID: "id1", - URN: "urn1", - Name: "name1", - Data: map[string]interface{}{ - "data1": "datavalue1", - }, - Labels: map[string]string{ - "label1": "labelvalue1", - }, - Owners: []user.User{ - { - ID: "uid1", - }, - { - ID: "uid2", - }, - }, - Changelog: diff.Changelog{ - diff.Change{ - From: "1", - To: "2", - Path: []string{"path1/path2"}, - }, - }, - CreatedAt: timeDummy, - UpdatedAt: timeDummy, - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := assetFromProto(tc.AssetPB) - if reflect.DeepEqual(got, tc.ExpectAsset) == false { - t.Errorf("expected returned asset to be %+v, was %+v", tc.ExpectAsset, got) - } - }) - } -} - -func newStructpb(t *testing.T, v map[string]interface{}) *structpb.Struct { - res, err := structpb.NewStruct(v) - require.NoError(t, err) - - return res -} diff --git a/handler/comment.go b/handler/comment.go deleted file mode 100644 index acc2ab38..00000000 --- a/handler/comment.go +++ /dev/null @@ -1,279 +0,0 @@ -package handler - -import ( - "context" - "errors" - "strings" - "time" - - "connectrpc.com/connect" - "github.com/raystack/compass/core/discussion" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "google.golang.org/protobuf/types/known/timestamppb" -) - -// CreateComment will create a new comment of a discussion -// field body is mandatory -func (server *Handler) CreateComment(ctx context.Context, req *connect.Request[compassv1beta1.CreateCommentRequest]) (*connect.Response[compassv1beta1.CreateCommentResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - userID, err := server.validateUserInCtx(ctx, ns) - if err != nil { - return nil, err - } - - if err := server.validateIDInteger(req.Msg.DiscussionId); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(discussion.InvalidError{DiscussionID: req.Msg.DiscussionId}))) - } - - cmt := discussion.Comment{ - DiscussionID: req.Msg.DiscussionId, - Body: req.Msg.Body, - Owner: user.User{ID: userID}, - UpdatedBy: user.User{ID: userID}, - } - - if err := cmt.Validate(); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - - id, err := server.discussionService.CreateComment(ctx, ns, &cmt) - if errors.As(err, new(discussion.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.CreateCommentResponse{Id: id}), nil -} - -// GetAllComments returns all comments of a discussion -func (server *Handler) GetAllComments(ctx context.Context, req *connect.Request[compassv1beta1.GetAllCommentsRequest]) (*connect.Response[compassv1beta1.GetAllCommentsResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - if err := server.validateIDInteger(req.Msg.DiscussionId); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(discussion.InvalidError{DiscussionID: req.Msg.DiscussionId}))) - } - - flt, err := server.buildGetAllCommentsFilter(req.Msg) - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(err))) - } - - cmts, err := server.discussionService.GetComments(ctx, req.Msg.DiscussionId, flt) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - commentsProto := []*compassv1beta1.Comment{} - for _, cmt := range cmts { - commentsProto = append(commentsProto, commentToProto(cmt)) - } - - return connect.NewResponse(&compassv1beta1.GetAllCommentsResponse{Data: commentsProto}), nil -} - -// GetComment returns a comment discussion by id from path -func (server *Handler) GetComment(ctx context.Context, req *connect.Request[compassv1beta1.GetCommentRequest]) (*connect.Response[compassv1beta1.GetCommentResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - if err := server.validateIDInteger(req.Msg.DiscussionId); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(discussion.InvalidError{DiscussionID: req.Msg.DiscussionId}))) - } - - if err := server.validateIDInteger(req.Msg.Id); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(discussion.InvalidError{DiscussionID: req.Msg.DiscussionId, CommentID: req.Msg.Id}))) - } - - cmt, err := server.discussionService.GetComment(ctx, req.Msg.Id, req.Msg.DiscussionId) - if errors.As(err, new(discussion.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.GetCommentResponse{Data: commentToProto(cmt)}), nil -} - -// UpdateComment is an api to update a comment by discussion id -func (server *Handler) UpdateComment(ctx context.Context, req *connect.Request[compassv1beta1.UpdateCommentRequest]) (*connect.Response[compassv1beta1.UpdateCommentResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - userID, err := server.validateUserInCtx(ctx, ns) - if err != nil { - return nil, err - } - - if err := server.validateIDInteger(req.Msg.DiscussionId); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(discussion.InvalidError{DiscussionID: req.Msg.DiscussionId}))) - } - - if err := server.validateIDInteger(req.Msg.Id); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(discussion.InvalidError{DiscussionID: req.Msg.DiscussionId, CommentID: req.Msg.Id}))) - } - - cmt := discussion.Comment{ - ID: req.Msg.Id, - DiscussionID: req.Msg.DiscussionId, - Body: req.Msg.Body, - UpdatedBy: user.User{ID: userID}, - } - - if err := cmt.Validate(); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - - err = server.discussionService.UpdateComment(ctx, &cmt) - if errors.As(err, new(discussion.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.UpdateCommentResponse{}), nil -} - -// DeleteComment is an api to delete a comment by discussion id -func (server *Handler) DeleteComment(ctx context.Context, req *connect.Request[compassv1beta1.DeleteCommentRequest]) (*connect.Response[compassv1beta1.DeleteCommentResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - if err := server.validateIDInteger(req.Msg.DiscussionId); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(discussion.InvalidError{DiscussionID: req.Msg.DiscussionId}))) - } - - if err := server.validateIDInteger(req.Msg.Id); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(discussion.InvalidError{DiscussionID: req.Msg.DiscussionId, CommentID: req.Msg.Id}))) - } - - err := server.discussionService.DeleteComment(ctx, req.Msg.Id, req.Msg.DiscussionId) - if errors.As(err, new(discussion.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.DeleteCommentResponse{}), nil -} - -func (server *Handler) buildGetAllDiscussionsFilter(req *compassv1beta1.GetAllDiscussionsRequest) (discussion.Filter, error) { - - fl := discussion.Filter{ - Type: req.GetType(), - State: req.GetState(), - Owner: req.GetOwner(), - SortBy: req.GetSort(), - SortDirection: req.GetDirection(), - } - - assignees := req.GetAssignee() - if assignees != "" { - fl.Assignees = strings.Split(assignees, ",") - } - - assets := req.GetAsset() - if assets != "" { - fl.Assets = strings.Split(assets, ",") - } - - labels := req.GetLabels() - if labels != "" { - fl.Labels = strings.Split(labels, ",") - } - - fl.Size = int(req.GetSize()) - fl.Offset = int(req.GetOffset()) - - if err := fl.Validate(); err != nil { - return discussion.Filter{}, err - } - - fl.AssignDefault() - - return fl, nil -} - -func (server *Handler) buildGetAllCommentsFilter(req *compassv1beta1.GetAllCommentsRequest) (discussion.Filter, error) { - - fl := discussion.Filter{ - SortBy: req.GetSort(), - SortDirection: req.GetDirection(), - } - - fl.Size = int(req.GetSize()) - fl.Offset = int(req.GetOffset()) - - if err := fl.Validate(); err != nil { - return discussion.Filter{}, err - } - - fl.AssignDefault() - - return fl, nil -} - -// commentToProto transforms struct to proto -func commentToProto(c discussion.Comment) *compassv1beta1.Comment { - - var createdAtPB *timestamppb.Timestamp - if !c.CreatedAt.IsZero() { - createdAtPB = timestamppb.New(c.CreatedAt) - } - - var updatedAtPB *timestamppb.Timestamp - if !c.UpdatedAt.IsZero() { - updatedAtPB = timestamppb.New(c.UpdatedAt) - } - - return &compassv1beta1.Comment{ - Id: c.ID, - DiscussionId: c.DiscussionID, - Body: c.Body, - Owner: userToProto(c.Owner), - UpdatedBy: userToProto(c.UpdatedBy), - CreatedAt: createdAtPB, - UpdatedAt: updatedAtPB, - } -} - -// commentFromProto transforms proto to struct -func commentFromProto(pb *compassv1beta1.Comment) discussion.Comment { - var createdAt time.Time - if pb.GetCreatedAt() != nil { - createdAt = pb.GetCreatedAt().AsTime() - } - - var updatedAt time.Time - if pb.GetUpdatedAt() != nil { - updatedAt = pb.GetUpdatedAt().AsTime() - } - - var owner user.User - if pb.GetOwner() != nil { - owner = userFromProto(pb.GetOwner()) - } - - var updatedBy user.User - if pb.GetUpdatedBy() != nil { - updatedBy = userFromProto(pb.GetUpdatedBy()) - } - - return discussion.Comment{ - ID: pb.GetId(), - DiscussionID: pb.GetDiscussionId(), - Body: pb.GetBody(), - Owner: owner, - UpdatedBy: updatedBy, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} diff --git a/handler/comment_test.go b/handler/comment_test.go deleted file mode 100644 index 5c9e2767..00000000 --- a/handler/comment_test.go +++ /dev/null @@ -1,779 +0,0 @@ -package handler - -import ( - "context" - "errors" - "fmt" - "reflect" - "testing" - "time" - - "connectrpc.com/connect" - "github.com/google/go-cmp/cmp" - "github.com/google/uuid" - "github.com/raystack/compass/core/discussion" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/handler/mocks" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "github.com/stretchr/testify/mock" - - - "google.golang.org/protobuf/testing/protocmp" - "google.golang.org/protobuf/types/known/timestamppb" -) - -func TestCreateComment(t *testing.T) { - var ( - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - userID = uuid.NewString() - userUUID = uuid.NewString() - discussionID = "11111" - validRequest = &compassv1beta1.CreateCommentRequest{ - DiscussionId: discussionID, - Body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type TestCase struct { - Description string - Request *compassv1beta1.CreateCommentRequest - ExpectStatus connect.Code - Result string - Setup func(context.Context, *mocks.DiscussionService, *mocks.NamespaceService) - } - - var testCases = []TestCase{ - { - Description: "should return invalid request if empty request", - Request: &compassv1beta1.CreateCommentRequest{ - DiscussionId: discussionID, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "should return invalid request if discussion_id is not integer", - Request: &compassv1beta1.CreateCommentRequest{ - DiscussionId: "test", - Body: validRequest.Body, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "should return invalid request if discussion_id is < 1", - Request: &compassv1beta1.CreateCommentRequest{ - DiscussionId: "0", - Body: validRequest.Body, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "should return internal server error if the comment creation failed", - Request: &compassv1beta1.CreateCommentRequest{ - DiscussionId: validRequest.GetDiscussionId(), - Body: validRequest.GetBody(), - }, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - expectedErr := errors.New("unknown error") - ds.EXPECT().CreateComment(ctx, ns, mock.AnythingOfType("*discussion.Comment")).Return("", expectedErr) - }, - }, - { - Description: "should return OK and comment ID if the comment is successfully created", - Request: &compassv1beta1.CreateCommentRequest{ - DiscussionId: validRequest.GetDiscussionId(), - Body: validRequest.GetBody(), - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().CreateComment(ctx, ns, mock.AnythingOfType("*discussion.Comment")).Return("", nil) - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockSvc := new(mocks.DiscussionService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockSvc, mockNamespaceSvc) - } - defer mockNamespaceSvc.AssertExpectations(t) - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, mockSvc, nil, nil, mockUserSvc) - - got, err := handler.CreateComment(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if err == nil && got != nil && got.Msg.GetId() != tc.Result { - t.Errorf("expected result to return id %s, returned id %s instead", tc.Result, got.Msg.Id) - return - } - }) - } -} - -func TestGetAllComments(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - discussionID = "11111" - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.GetAllCommentsRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.DiscussionService, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.GetAllCommentsResponse) error - } - var testCases = []testCase{ - { - Description: `should return invalid argument if discussion_id is not integer`, - Request: &compassv1beta1.GetAllCommentsRequest{ - DiscussionId: "test", - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - }, - }, - { - Description: `should return invalid argument if discussion_id is < 1`, - Request: &compassv1beta1.GetAllCommentsRequest{ - DiscussionId: "0", - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - }, - }, - { - Description: `should return internal server error if fetching fails`, - Request: &compassv1beta1.GetAllCommentsRequest{ - DiscussionId: discussionID, - }, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetComments(ctx, discussionID, discussion.Filter{ - Type: "all", - State: "open", - SortBy: "created_at", - SortDirection: "desc", - }).Return([]discussion.Comment{}, errors.New("unknown error")) - }, - }, - { - Description: `should successfully parse querystring to get filter`, - Request: &compassv1beta1.GetAllCommentsRequest{ - DiscussionId: discussionID, - Sort: "updated_at", - Direction: "asc", - Size: 30, - Offset: 50, - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetComments(ctx, discussionID, discussion.Filter{ - Type: "all", - State: discussion.StateOpen.String(), - SortBy: "updated_at", - SortDirection: "asc", - Size: 30, - Offset: 50, - }).Return([]discussion.Comment{}, nil) - }, - }, - { - Description: "should return status OK along with list of comments", - Request: &compassv1beta1.GetAllCommentsRequest{ - DiscussionId: discussionID, - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetComments(ctx, discussionID, discussion.Filter{ - Type: "all", - State: discussion.StateOpen.String(), - SortBy: "created_at", - SortDirection: "desc", - }).Return([]discussion.Comment{ - {ID: "1122"}, - {ID: "2233"}, - }, nil) - }, - PostCheck: func(resp *compassv1beta1.GetAllCommentsResponse) error { - expected := &compassv1beta1.GetAllCommentsResponse{ - Data: []*compassv1beta1.Comment{ - {Id: "1122"}, - {Id: "2233"}, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockSvc := new(mocks.DiscussionService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockSvc, mockNamespaceSvc) - } - defer mockNamespaceSvc.AssertExpectations(t) - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, mockSvc, nil, nil, mockUserSvc) - - got, err := handler.GetAllComments(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestGetComment(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - discussionID = "123" - commentID = "11" - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.GetCommentRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.DiscussionService, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.GetCommentResponse) error - } - var testCases = []testCase{ - { - Description: `should return internal server error if fetching fails`, - ExpectStatus: connect.CodeInternal, - Request: &compassv1beta1.GetCommentRequest{ - Id: commentID, - DiscussionId: discussionID, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetComment(ctx, commentID, discussionID).Return(discussion.Comment{}, errors.New("unknown error")) - }, - }, - { - Description: `should return invalid argument if discussion id not integer`, - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.GetCommentRequest{ - Id: commentID, - DiscussionId: "random", - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - }, - }, - { - Description: `should return invalid argument if discussion id < 0`, - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.GetCommentRequest{ - Id: commentID, - DiscussionId: "-1", - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - }, - }, - { - Description: `should return invalid argument if comment id not integer`, - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.GetCommentRequest{ - Id: "random", - DiscussionId: discussionID, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - }, - }, - { - Description: `should return invalid argument if comment id < 0`, - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.GetCommentRequest{ - Id: "-1", - DiscussionId: discussionID, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - }, - }, - { - Description: `should return Not Found if comment or discussion not found`, - ExpectStatus: connect.CodeNotFound, - Request: &compassv1beta1.GetCommentRequest{ - Id: commentID, - DiscussionId: discussionID, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetComment(ctx, commentID, discussionID).Return(discussion.Comment{}, discussion.NotFoundError{DiscussionID: discussionID, CommentID: commentID}) - }, - }, - { - Description: "should return status OK along with comment of a discussion", - ExpectStatus: 0, - Request: &compassv1beta1.GetCommentRequest{ - Id: commentID, - DiscussionId: discussionID, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetComment(ctx, commentID, discussionID).Return(discussion.Comment{ID: commentID, DiscussionID: discussionID}, nil) - }, - PostCheck: func(resp *compassv1beta1.GetCommentResponse) error { - expected := &compassv1beta1.GetCommentResponse{ - Data: &compassv1beta1.Comment{ - Id: commentID, - DiscussionId: discussionID, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockSvc := new(mocks.DiscussionService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockSvc, mockNamespaceSvc) - } - defer mockNamespaceSvc.AssertExpectations(t) - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, mockSvc, nil, nil, mockUserSvc) - - got, err := handler.GetComment(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestUpdateComment(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - discussionID = "123" - commentID = "11" - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - var validRequest = &compassv1beta1.UpdateCommentRequest{ - Id: commentID, - DiscussionId: discussionID, - Body: "lorem ipsum", - } - testCases := []struct { - Description string - Request *compassv1beta1.UpdateCommentRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.DiscussionService, *mocks.NamespaceService) - }{ - { - Description: "discussion id is not integer return bad request", - Request: &compassv1beta1.UpdateCommentRequest{ - Id: commentID, - DiscussionId: "random", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "discussion id is < 0 return bad request", - Request: &compassv1beta1.UpdateCommentRequest{ - Id: commentID, - DiscussionId: "-1", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "comment id is not integer return bad request", - Request: &compassv1beta1.UpdateCommentRequest{ - Id: "random", - DiscussionId: discussionID, - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "comment id is < 0 return bad request", - Request: &compassv1beta1.UpdateCommentRequest{ - Id: "-1", - DiscussionId: discussionID, - }, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "empty object return bad request", - Request: &compassv1beta1.UpdateCommentRequest{ - Id: commentID, - DiscussionId: discussionID, - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "empty body return bad request", - Request: &compassv1beta1.UpdateCommentRequest{ - Id: commentID, - DiscussionId: discussionID, - Body: "", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return internal server error if the update comment failed", - Request: validRequest, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - cmt := &discussion.Comment{ - ID: validRequest.Id, - DiscussionID: validRequest.DiscussionId, - Body: validRequest.Body, - UpdatedBy: user.User{ID: userID}, - } - expectedErr := errors.New("unknown error") - ds.EXPECT().UpdateComment(ctx, cmt).Return(expectedErr) - }, - }, - { - Description: "should return Not Found if the discussion id or comment id not found", - Request: validRequest, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - cmt := &discussion.Comment{ - ID: validRequest.Id, - DiscussionID: validRequest.DiscussionId, - Body: validRequest.Body, - UpdatedBy: user.User{ID: userID}, - } - expectedErr := discussion.NotFoundError{DiscussionID: discussionID, CommentID: commentID} - ds.EXPECT().UpdateComment(ctx, cmt).Return(expectedErr) - }, - }, - { - Description: "should return status OK if the comment is successfully updated", - Request: validRequest, - ExpectStatus: 0, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - cmt := &discussion.Comment{ - ID: validRequest.Id, - DiscussionID: validRequest.DiscussionId, - Body: validRequest.Body, - UpdatedBy: user.User{ID: userID}, - } - ds.EXPECT().UpdateComment(ctx, cmt).Return(nil) - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockSvc := new(mocks.DiscussionService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockSvc, mockNamespaceSvc) - } - defer mockNamespaceSvc.AssertExpectations(t) - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - handler := New(mockNamespaceSvc, nil, nil, mockSvc, nil, nil, mockUserSvc) - - _, err := handler.UpdateComment(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - }) - } -} - -func TestDeleteComment(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - discussionID = "123" - commentID = "11" - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - testCases := []struct { - Description string - Request *compassv1beta1.DeleteCommentRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.DiscussionService, *mocks.NamespaceService) - }{ - { - Description: "discussion id is not integer return bad request", - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.DeleteCommentRequest{ - Id: commentID, - DiscussionId: "random", - }, - }, - { - Description: "discussion id is < 0 return bad request", - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.DeleteCommentRequest{ - Id: commentID, - DiscussionId: "-1", - }, - }, - { - Description: "comment id is not integer return bad request", - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.DeleteCommentRequest{ - Id: "random", - DiscussionId: discussionID, - }, - }, - { - Description: "comment id is < 0 return bad request", - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.DeleteCommentRequest{ - Id: "-1", - DiscussionId: discussionID, - }, - }, - { - Description: "should return internal server error if the delete comment failed", - ExpectStatus: connect.CodeInternal, - Request: &compassv1beta1.DeleteCommentRequest{ - Id: commentID, - DiscussionId: discussionID, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - expectedErr := errors.New("unknown error") - ds.EXPECT().DeleteComment(ctx, commentID, discussionID).Return(expectedErr) - }, - }, - { - Description: "should return invalid argument if the discussion id or comment id not found", - ExpectStatus: connect.CodeNotFound, - Request: &compassv1beta1.DeleteCommentRequest{ - Id: commentID, - DiscussionId: discussionID, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - expectedErr := discussion.NotFoundError{DiscussionID: discussionID, CommentID: commentID} - ds.EXPECT().DeleteComment(ctx, commentID, discussionID).Return(expectedErr) - }, - }, - { - Description: "should return OK if the comment is successfully deleted", - ExpectStatus: 0, - Request: &compassv1beta1.DeleteCommentRequest{ - Id: commentID, - DiscussionId: discussionID, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().DeleteComment(ctx, commentID, discussionID).Return(nil) - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockSvc := new(mocks.DiscussionService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockSvc, mockNamespaceSvc) - } - defer mockNamespaceSvc.AssertExpectations(t) - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, mockSvc, nil, nil, mockUserSvc) - - _, err := handler.DeleteComment(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - }) - } -} - -func TestCommentToProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - Comment discussion.Comment - ExpectProto *compassv1beta1.Comment - } - - var testCases = []testCase{ - { - Title: "should return no timestamp pb if timestamp is zero", - Comment: discussion.Comment{ID: "id1"}, - ExpectProto: &compassv1beta1.Comment{Id: "id1"}, - }, - { - Title: "should return timestamp pb if timestamp is not zero", - Comment: discussion.Comment{ID: "id1", CreatedAt: timeDummy, UpdatedAt: timeDummy}, - ExpectProto: &compassv1beta1.Comment{Id: "id1", CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := commentToProto(tc.Comment) - if diff := cmp.Diff(got, tc.ExpectProto, protocmp.Transform()); diff != "" { - t.Errorf("expected response to be %+v, was %+v", tc.ExpectProto, got) - } - }) - } -} - -func TestCommentFromProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - PB *compassv1beta1.Comment - Expect discussion.Comment - } - - var testCases = []testCase{ - { - Title: "should return non empty time.Time, owner, and updated by if pb is not empty or zero", - PB: &compassv1beta1.Comment{Id: "id1", Owner: &compassv1beta1.User{Id: "uid1"}, UpdatedBy: &compassv1beta1.User{Id: "uid1"}, CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - Expect: discussion.Comment{ID: "id1", Owner: user.User{ID: "uid1"}, UpdatedBy: user.User{ID: "uid1"}, CreatedAt: timeDummy, UpdatedAt: timeDummy}, - }, - { - Title: "should return empty time.Time, owner, and updated by if pb is empty or zero", - PB: &compassv1beta1.Comment{Id: "id1"}, - Expect: discussion.Comment{ID: "id1"}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := commentFromProto(tc.PB) - if reflect.DeepEqual(got, tc.Expect) == false { - t.Errorf("expected returned asset to be %+v, was %+v", tc.Expect, got) - } - }) - } -} diff --git a/handler/discussion.go b/handler/discussion.go deleted file mode 100644 index bad0e5d1..00000000 --- a/handler/discussion.go +++ /dev/null @@ -1,227 +0,0 @@ -package handler - -//go:generate mockery --name=DiscussionService -r --case underscore --with-expecter --structname DiscussionService --filename discussion_service.go --output=./mocks -import ( - "context" - "errors" - "strconv" - "time" - - "connectrpc.com/connect" - "github.com/raystack/compass/core/discussion" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "google.golang.org/protobuf/types/known/timestamppb" -) - -type DiscussionService interface { - GetDiscussions(ctx context.Context, filter discussion.Filter) ([]discussion.Discussion, error) - CreateDiscussion(ctx context.Context, ns *namespace.Namespace, discussion *discussion.Discussion) (string, error) - GetDiscussion(ctx context.Context, did string) (discussion.Discussion, error) - PatchDiscussion(ctx context.Context, discussion *discussion.Discussion) error - GetComments(ctx context.Context, discussionID string, filter discussion.Filter) ([]discussion.Comment, error) - CreateComment(ctx context.Context, ns *namespace.Namespace, cmt *discussion.Comment) (string, error) - GetComment(ctx context.Context, commentID string, discussionID string) (discussion.Comment, error) - UpdateComment(ctx context.Context, cmt *discussion.Comment) error - DeleteComment(ctx context.Context, commentID string, discussionID string) error -} - -// GetAllDiscussions returns all discussion based on filter in query params -// supported query params are type,state,owner,assignee,asset,labels (supporterd array separated by comma) -// query params sort,direction to sort asc or desc -// query params size,offset for pagination -func (server *Handler) GetAllDiscussions(ctx context.Context, req *connect.Request[compassv1beta1.GetAllDiscussionsRequest]) (*connect.Response[compassv1beta1.GetAllDiscussionsResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - flt, err := server.buildGetAllDiscussionsFilter(req.Msg) - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(err))) - } - - dscs, err := server.discussionService.GetDiscussions(ctx, flt) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - discussionsProto := []*compassv1beta1.Discussion{} - for _, dsc := range dscs { - discussionsProto = append(discussionsProto, discussionToProto(dsc)) - } - - return connect.NewResponse(&compassv1beta1.GetAllDiscussionsResponse{Data: discussionsProto}), nil -} - -// CreateDiscussion will create a new discussion -// field title, body, and type are mandatory -func (server *Handler) CreateDiscussion(ctx context.Context, req *connect.Request[compassv1beta1.CreateDiscussionRequest]) (*connect.Response[compassv1beta1.CreateDiscussionResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - userID, err := server.validateUserInCtx(ctx, ns) - if err != nil { - return nil, err - } - - dsc := discussion.Discussion{ - Title: req.Msg.Title, - Body: req.Msg.Body, - Type: discussion.Type(req.Msg.Type), - State: discussion.GetStateEnum(req.Msg.State), - Labels: req.Msg.GetLabels(), - Assets: req.Msg.Assets, - Assignees: req.Msg.Assignees, - Owner: user.User{ID: userID}, - } - - if err := dsc.Validate(); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - - id, err := server.discussionService.CreateDiscussion(ctx, ns, &dsc) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.CreateDiscussionResponse{Id: id}), nil -} - -func (server *Handler) GetDiscussion(ctx context.Context, req *connect.Request[compassv1beta1.GetDiscussionRequest]) (*connect.Response[compassv1beta1.GetDiscussionResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - if err := server.validateIDInteger(req.Msg.Id); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(discussion.ErrInvalidID))) - } - - dsc, err := server.discussionService.GetDiscussion(ctx, req.Msg.Id) - if errors.As(err, new(discussion.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.GetDiscussionResponse{Data: discussionToProto(dsc)}), nil -} - -// PatchDiscussion updates a specific field in discussion -// empty array in assets,labels,assignees will be considered -// and clear all assets,labels,assignees from the discussion -func (server *Handler) PatchDiscussion(ctx context.Context, req *connect.Request[compassv1beta1.PatchDiscussionRequest]) (*connect.Response[compassv1beta1.PatchDiscussionResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - if err := server.validateIDInteger(req.Msg.Id); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(discussion.ErrInvalidID))) - } - - dsc := discussion.Discussion{ - ID: req.Msg.GetId(), - Title: req.Msg.GetTitle(), - Body: req.Msg.GetBody(), - Type: discussion.Type(req.Msg.GetType()), - State: discussion.State(req.Msg.GetState()), - Labels: req.Msg.GetLabels(), - Assets: req.Msg.GetAssets(), - Assignees: req.Msg.GetAssignees(), - } - - if isEmpty := dsc.IsEmpty(); isEmpty { - err := errors.New("empty discussion body") - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(bodyParserErrorMsg(err))) - } - - if err := dsc.ValidateConstraint(); err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - - err := server.discussionService.PatchDiscussion(ctx, &dsc) - if errors.Is(err, discussion.ErrInvalidID) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if errors.As(err, new(discussion.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.PatchDiscussionResponse{}), nil -} - -func (server *Handler) validateIDInteger(id string) error { - idInt, err := strconv.ParseInt(id, 10, 32) - if err != nil { - return err - } - - if idInt < 1 { - return errors.New("id cannot be < 1") - } - - return nil -} - -// discussionToProto transforms struct to proto -func discussionToProto(d discussion.Discussion) *compassv1beta1.Discussion { - - var createdAtPB *timestamppb.Timestamp - if !d.CreatedAt.IsZero() { - createdAtPB = timestamppb.New(d.CreatedAt) - } - - var updatedAtPB *timestamppb.Timestamp - if !d.UpdatedAt.IsZero() { - updatedAtPB = timestamppb.New(d.UpdatedAt) - } - - return &compassv1beta1.Discussion{ - Id: d.ID, - Title: d.Title, - Body: d.Body, - Type: d.Type.String(), - State: d.State.String(), - Labels: d.Labels, - Assets: d.Assets, - Assignees: d.Assignees, - Owner: userToProto(d.Owner), - CreatedAt: createdAtPB, - UpdatedAt: updatedAtPB, - } -} - -// discussionFromProto transforms proto to struct -func discussionFromProto(pb *compassv1beta1.Discussion) discussion.Discussion { - var createdAt time.Time - if pb.GetCreatedAt() != nil { - createdAt = pb.GetCreatedAt().AsTime() - } - - var updatedAt time.Time - if pb.GetUpdatedAt() != nil { - updatedAt = pb.GetUpdatedAt().AsTime() - } - - var owner user.User - if pb.GetOwner() != nil { - owner = userFromProto(pb.GetOwner()) - } - - return discussion.Discussion{ - ID: pb.GetId(), - Title: pb.GetTitle(), - Body: pb.GetBody(), - Type: discussion.GetTypeEnum(pb.GetType()), - State: discussion.GetStateEnum(pb.GetState()), - Labels: pb.GetLabels(), - Assets: pb.GetAssets(), - Assignees: pb.GetAssignees(), - Owner: owner, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} diff --git a/handler/discussion_test.go b/handler/discussion_test.go deleted file mode 100644 index 1fa77241..00000000 --- a/handler/discussion_test.go +++ /dev/null @@ -1,621 +0,0 @@ -package handler - -import ( - "context" - "errors" - "fmt" - "reflect" - "testing" - "time" - - "connectrpc.com/connect" - "github.com/google/go-cmp/cmp" - "github.com/google/uuid" - "github.com/raystack/compass/core/discussion" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/handler/mocks" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - - - "google.golang.org/protobuf/testing/protocmp" - "google.golang.org/protobuf/types/known/timestamppb" -) - -func TestGetAllDiscussions(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.GetAllDiscussionsRequest - Setup func(context.Context, *mocks.DiscussionService, *mocks.NamespaceService) - ExpectStatus connect.Code - PostCheck func(resp *compassv1beta1.GetAllDiscussionsResponse) error - } - - var testCases = []testCase{ - { - Description: `should return internal server error if fetching fails`, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetDiscussions(ctx, discussion.Filter{ - Type: "all", - State: discussion.StateOpen.String(), - SortBy: "created_at", - SortDirection: "desc", - }).Return([]discussion.Discussion{}, errors.New("unknown error")) - }, - ExpectStatus: connect.CodeInternal, - }, - { - Description: `should parse querystring to get filter`, - Request: &compassv1beta1.GetAllDiscussionsRequest{ - Type: discussion.TypeIssues.String(), - State: discussion.StateClosed.String(), - Labels: "label1,label2,label4", - Assignee: "646130cf-3dde-4d61-99e9-6070dd369597", - Asset: "e5d81dcd-3046-4d33-b1ac-efdd221e621d", - Owner: "62326386-dc9d-4ae5-9448-e54c720f856d", - Sort: "updated_at", - Direction: "asc", - Size: 30, - Offset: 50, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetDiscussions(ctx, discussion.Filter{ - Type: discussion.TypeIssues.String(), - State: discussion.StateClosed.String(), - Assignees: []string{"646130cf-3dde-4d61-99e9-6070dd369597"}, - Assets: []string{"e5d81dcd-3046-4d33-b1ac-efdd221e621d"}, - Owner: "62326386-dc9d-4ae5-9448-e54c720f856d", - Labels: []string{"label1", "label2", "label4"}, - SortBy: "updated_at", - SortDirection: "asc", - Size: 30, - Offset: 50, - }).Return([]discussion.Discussion{}, nil) - }, - ExpectStatus: 0, - }, - { - Description: "should return status OK along with list of discussions", - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetDiscussions(ctx, discussion.Filter{ - Type: "all", - State: discussion.StateOpen.String(), - SortBy: "created_at", - SortDirection: "desc", - }).Return([]discussion.Discussion{ - {ID: "1122"}, - {ID: "2233"}, - }, nil) - }, - PostCheck: func(resp *compassv1beta1.GetAllDiscussionsResponse) error { - expected := &compassv1beta1.GetAllDiscussionsResponse{ - Data: []*compassv1beta1.Discussion{ - {Id: "1122"}, - {Id: "2233"}, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - ExpectStatus: 0, - }, - } - - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockSvc := new(mocks.DiscussionService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockSvc, mockNamespaceSvc) - } - defer mockNamespaceSvc.AssertExpectations(t) - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, mockSvc, nil, nil, mockUserSvc) - - got, err := handler.GetAllDiscussions(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - assert.Error(t, err) - return - } - } - }) - } -} - -func TestCreateDiscussion(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - var validRequest = &compassv1beta1.CreateDiscussionRequest{ - Title: "Lorem Ipsum", - Body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - Type: discussion.TypeQAndA.String(), - } - - type testCase struct { - Description string - Request *compassv1beta1.CreateDiscussionRequest - Setup func(context.Context, *mocks.DiscussionService, *mocks.NamespaceService) - ExpectStatus connect.Code - } - - var testCases = []testCase{ - { - Description: "should return invalid argument if empty object", - Request: &compassv1beta1.CreateDiscussionRequest{}, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return invalid argument if empty title", - Request: &compassv1beta1.CreateDiscussionRequest{ - Body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - Type: discussion.TypeQAndA.String(), - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return invalid argument if no body", - Request: &compassv1beta1.CreateDiscussionRequest{ - Title: "Lorem Ipsum", - Type: discussion.TypeQAndA.String(), - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return invalid argument if empty body", - Request: &compassv1beta1.CreateDiscussionRequest{ - Title: "Lorem Ipsum", - Body: "", - Type: discussion.TypeQAndA.String(), - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return invalid argument if wrong type", - Request: &compassv1beta1.CreateDiscussionRequest{ - Title: "Lorem Ipsum", - Body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - Type: "wrongtype", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return internal server error if the discussion creation fails", - Request: validRequest, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().CreateDiscussion(ctx, ns, mock.AnythingOfType("*discussion.Discussion")).Return("", errors.New("some error")) - }, - }, - { - Description: "should return invalid argument if empty type", - Request: &compassv1beta1.CreateDiscussionRequest{ - Title: "Lorem Ipsum", - Body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - Type: "", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return OK and discussion ID if the discussion is successfully created", - Request: validRequest, - ExpectStatus: 0, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - dsc := discussion.Discussion{ - Title: "Lorem Ipsum", - Body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - Type: discussion.TypeQAndA, - State: discussion.StateOpen, - Owner: user.User{ID: userID}, - } - discussionWithID := dsc - discussionWithID.ID = "12" - ds.EXPECT().CreateDiscussion(ctx, ns, &dsc).Run(func(ctx context.Context, ns *namespace.Namespace, dsc *discussion.Discussion) { - dsc.ID = discussionWithID.ID - }).Return(discussionWithID.ID, nil) - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockSvc := new(mocks.DiscussionService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockSvc, mockNamespaceSvc) - } - defer mockNamespaceSvc.AssertExpectations(t) - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, mockSvc, nil, nil, mockUserSvc) - _, err := handler.CreateDiscussion(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - }) - } -} - -func TestGetDiscussion(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - discussionID = "123" - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type TestCase struct { - Description string - Request *compassv1beta1.GetDiscussionRequest - Setup func(context.Context, *mocks.DiscussionService, *mocks.NamespaceService) - ExpectStatus connect.Code - PostCheck func(resp *compassv1beta1.GetDiscussionResponse) error - } - - var testCases = []TestCase{ - { - Description: `should return internal server error if fetching fails`, - ExpectStatus: connect.CodeInternal, - Request: &compassv1beta1.GetDiscussionRequest{ - Id: discussionID, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetDiscussion(ctx, discussionID).Return(discussion.Discussion{}, errors.New("unknown error")) - }, - }, - { - Description: `should return invalid argument if discussion id not integer`, - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.GetDiscussionRequest{ - Id: "random", - }, - }, - { - Description: `should return invalid argument if discussion id < 0`, - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.GetDiscussionRequest{ - Id: "-1", - }, - }, - { - Description: `should return not found if discussion not found`, - ExpectStatus: connect.CodeNotFound, - Request: &compassv1beta1.GetDiscussionRequest{ - Id: discussionID, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetDiscussion(ctx, discussionID).Return(discussion.Discussion{}, discussion.NotFoundError{DiscussionID: discussionID}) - }, - }, - { - Description: "should return status OK along with discussions", - ExpectStatus: 0, - Request: &compassv1beta1.GetDiscussionRequest{ - Id: discussionID, - }, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().GetDiscussion(ctx, discussionID).Return(discussion.Discussion{ID: discussionID}, nil) - }, - PostCheck: func(resp *compassv1beta1.GetDiscussionResponse) error { - expected := &compassv1beta1.GetDiscussionResponse{ - Data: &compassv1beta1.Discussion{ - Id: discussionID, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockSvc := new(mocks.DiscussionService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockSvc, mockNamespaceSvc) - } - defer mockNamespaceSvc.AssertExpectations(t) - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - handler := New(mockNamespaceSvc, nil, nil, mockSvc, nil, nil, mockUserSvc) - - got, err := handler.GetDiscussion(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - assert.Error(t, err) - return - } - } - }) - } -} - -func TestPatchDiscussion(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - discussionID = "123" - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - var validRequest = &compassv1beta1.PatchDiscussionRequest{Id: discussionID, Title: "lorem ipsum"} - - type TestCase struct { - Description string - Request *compassv1beta1.PatchDiscussionRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.DiscussionService, *mocks.NamespaceService) - } - - testCases := []TestCase{ - { - Description: "should return invalid argument if discussion id is not integer return invalid argument", - Request: &compassv1beta1.PatchDiscussionRequest{ - Id: "random", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return invalid argument if discussion id is < 0 return invalid argument", - Request: &compassv1beta1.PatchDiscussionRequest{ - Id: "-1", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return invalid argument if empty object return invalid argument", - Request: &compassv1beta1.PatchDiscussionRequest{ - Id: discussionID, - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return invalid argument if invalid type return invalid argument", - Request: &compassv1beta1.PatchDiscussionRequest{ - Id: discussionID, - Type: "random", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return invalid argument if invalid state return invalid argument", - Request: &compassv1beta1.PatchDiscussionRequest{ - Id: discussionID, - State: "random", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return invalid argument if assignees more than limit should return invalid argument", - Request: &compassv1beta1.PatchDiscussionRequest{ - Id: discussionID, - Assignees: []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}, - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return invalid argument if assets more than limit should return invalid argument", - Request: &compassv1beta1.PatchDiscussionRequest{ - Id: discussionID, - Assets: []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}, - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return invalid argument if labels more than limit should return invalid argument", - Request: &compassv1beta1.PatchDiscussionRequest{ - Id: discussionID, - Labels: []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}, - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: "should return internal server error if the discussion patch fails", - Request: validRequest, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - expectedErr := errors.New("unknown error") - ds.EXPECT().PatchDiscussion(ctx, mock.AnythingOfType("*discussion.Discussion")).Return(expectedErr) - }, - }, - { - Description: "should return Not Found if the discussion id is invalid", - Request: validRequest, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - expectedErr := discussion.NotFoundError{DiscussionID: discussionID} - ds.EXPECT().PatchDiscussion(ctx, mock.AnythingOfType("*discussion.Discussion")).Return(expectedErr) - }, - }, - { - Description: "should return OK if the discussion is successfully patched", - Request: validRequest, - ExpectStatus: 0, - Setup: func(ctx context.Context, ds *mocks.DiscussionService, nss *mocks.NamespaceService) { - ds.EXPECT().PatchDiscussion(ctx, mock.AnythingOfType("*discussion.Discussion")).Return(nil) - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockSvc := new(mocks.DiscussionService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockSvc, mockNamespaceSvc) - } - defer mockNamespaceSvc.AssertExpectations(t) - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, mockSvc, nil, nil, mockUserSvc) - _, err := handler.PatchDiscussion(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - }) - } -} - -func TestDiscussionToProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - Discussion discussion.Discussion - ExpectProto *compassv1beta1.Discussion - } - - var testCases = []testCase{ - { - Title: "should return no timestamp pb if timestamp is zero", - Discussion: discussion.Discussion{ID: "id1"}, - ExpectProto: &compassv1beta1.Discussion{Id: "id1"}, - }, - { - Title: "should return timestamp pb if timestamp is not zero", - Discussion: discussion.Discussion{ID: "id1", CreatedAt: timeDummy, UpdatedAt: timeDummy}, - ExpectProto: &compassv1beta1.Discussion{Id: "id1", CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := discussionToProto(tc.Discussion) - if diff := cmp.Diff(got, tc.ExpectProto, protocmp.Transform()); diff != "" { - t.Errorf("expected response to be %+v, was %+v", tc.ExpectProto, got) - } - }) - } -} - -func TestDiscussionFromProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - DiscussionPB *compassv1beta1.Discussion - ExpectDiscussion discussion.Discussion - } - - var testCases = []testCase{ - { - Title: "should return non empty time.Time and owner if pb is not empty or zero", - DiscussionPB: &compassv1beta1.Discussion{Id: "id1", Owner: &compassv1beta1.User{Id: "uid1"}, CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - ExpectDiscussion: discussion.Discussion{ID: "id1", Owner: user.User{ID: "uid1"}, Type: "openended", State: "open", CreatedAt: timeDummy, UpdatedAt: timeDummy}, - }, - { - Title: "should return empty time.Time and owner if pb is empty or zero", - DiscussionPB: &compassv1beta1.Discussion{Id: "id1"}, - ExpectDiscussion: discussion.Discussion{ID: "id1", Type: "openended", State: "open"}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := discussionFromProto(tc.DiscussionPB) - if reflect.DeepEqual(got, tc.ExpectDiscussion) == false { - t.Errorf("expected returned asset to be %+v, was %+v", tc.ExpectDiscussion, got) - } - }) - } -} diff --git a/handler/handler.go b/handler/handler.go index 865490c8..c43e9afd 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -14,57 +14,31 @@ import ( ) type Handler struct { - namespaceService NamespaceService - assetService AssetService - starService StarService - discussionService DiscussionService - tagService TagService - tagTemplateService TagTemplateService - userService UserService - entityService EntityServiceV2 - edgeService EdgeServiceV2 + namespaceService NamespaceService + starService StarService + userService UserService + entityService EntityServiceV2 + edgeService EdgeServiceV2 } var ( errMissingUserInfo = errors.New("missing user information") ) -// HandlerOption configures the Handler. -type HandlerOption func(*Handler) - -// WithEntityService adds the v2 entity service. -func WithEntityService(svc EntityServiceV2) HandlerOption { - return func(h *Handler) { h.entityService = svc } -} - -// WithEdgeService adds the v2 edge service. -func WithEdgeService(svc EdgeServiceV2) HandlerOption { - return func(h *Handler) { h.edgeService = svc } -} - func New( namespaceService NamespaceService, - assetService AssetService, starService StarService, - discussionService DiscussionService, - tagService TagService, - tagTemplateService TagTemplateService, userService UserService, - opts ...HandlerOption, + entityService EntityServiceV2, + edgeService EdgeServiceV2, ) *Handler { - h := &Handler{ - namespaceService: namespaceService, - assetService: assetService, - starService: starService, - discussionService: discussionService, - tagService: tagService, - tagTemplateService: tagTemplateService, - userService: userService, - } - for _, opt := range opts { - opt(h) + return &Handler{ + namespaceService: namespaceService, + starService: starService, + userService: userService, + entityService: entityService, + edgeService: edgeService, } - return h } func (server *Handler) validateUserInCtx(ctx context.Context, ns *namespace.Namespace) (string, error) { diff --git a/handler/lineage.go b/handler/lineage.go deleted file mode 100644 index 9118d1b8..00000000 --- a/handler/lineage.go +++ /dev/null @@ -1,97 +0,0 @@ -package handler - -import ( - "context" - "errors" - "fmt" - - "connectrpc.com/connect" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "google.golang.org/protobuf/types/known/structpb" -) - -func (server *Handler) GetGraph(ctx context.Context, req *connect.Request[compassv1beta1.GetGraphRequest]) (*connect.Response[compassv1beta1.GetGraphResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - direction := asset.LineageDirection(req.Msg.GetDirection()) - if !direction.IsValid() { - return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("invalid direction value")) - } - - // Default to true for backward compatibility - withAttributes := true - if req.Msg.WithAttributes != nil { - withAttributes = *req.Msg.WithAttributes - } - - lineage, err := server.assetService.GetLineage(ctx, req.Msg.GetUrn(), asset.LineageQuery{ - Level: int(req.Msg.GetLevel()), - Direction: direction, - WithAttributes: withAttributes, - IncludeDeleted: req.Msg.GetIncludeDeleted(), - }) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - edges := make([]*compassv1beta1.LineageEdge, 0, len(lineage.Edges)) - for _, edge := range lineage.Edges { - edgePB, err := lineageEdgeToProto(edge) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - edges = append(edges, edgePB) - } - - nodeAttrs := make(map[string]*compassv1beta1.GetGraphResponse_NodeAttributes, len(lineage.NodeAttrs)) - for urn, attrs := range lineage.NodeAttrs { - probesInfo, err := probesInfoToProto(attrs.Probes) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - nodeAttrs[urn] = &compassv1beta1.GetGraphResponse_NodeAttributes{ - Probes: probesInfo, - } - } - - return connect.NewResponse(&compassv1beta1.GetGraphResponse{ - Data: edges, - NodeAttrs: nodeAttrs, - }), nil -} - -func lineageEdgeToProto(e asset.LineageEdge) (*compassv1beta1.LineageEdge, error) { - var ( - propPB *structpb.Struct - err error - ) - - if len(e.Prop) > 0 { - propPB, err = structpb.NewStruct(e.Prop) - if err != nil { - return nil, err - } - } - return &compassv1beta1.LineageEdge{ - Source: e.Source, - Target: e.Target, - Prop: propPB, - }, nil -} - -func probesInfoToProto(probes asset.ProbesInfo) (*compassv1beta1.GetGraphResponse_ProbesInfo, error) { - latest, err := probeToProto(probes.Latest) - if err != nil { - return nil, fmt.Errorf("convert probe to proto representation: %w", err) - } - - return &compassv1beta1.GetGraphResponse_ProbesInfo{ - Latest: latest, - }, nil -} diff --git a/handler/lineage_test.go b/handler/lineage_test.go deleted file mode 100644 index ca5f9c5e..00000000 --- a/handler/lineage_test.go +++ /dev/null @@ -1,120 +0,0 @@ -package handler - -import ( - "context" - "testing" - "time" - - "connectrpc.com/connect" - "github.com/google/go-cmp/cmp" - "github.com/google/uuid" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/handler/mocks" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - - - "google.golang.org/protobuf/testing/protocmp" - "google.golang.org/protobuf/types/known/timestamppb" -) - -func TestGetLineageGraph(t *testing.T) { - // TODO[2022-10-13|@sudo-suhas]: Add comprehensive tests - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - t.Run("get Lineage", func(t *testing.T) { - t.Run("should return a graph containing the requested resource, along with it's related resources", func(t *testing.T) { - nodeURN := "job-1" - level := 8 - direction := asset.LineageDirectionUpstream - ts := time.Unix(1665659885, 0) - tspb := timestamppb.New(ts) - - lineage := asset.Lineage{ - Edges: []asset.LineageEdge{ - {Source: "job-1", Target: "table-2"}, - {Source: "table-2", Target: "table-31"}, - {Source: "table-31", Target: "dashboard-30"}, - }, - NodeAttrs: map[string]asset.NodeAttributes{ - "job-1": { - Probes: asset.ProbesInfo{ - Latest: asset.Probe{Status: "SUCCESS", Timestamp: ts, CreatedAt: ts}, - }, - }, - "table-2": { - Probes: asset.ProbesInfo{ - Latest: asset.Probe{Status: "FAILED", Timestamp: ts, CreatedAt: ts}, - }, - }, - }, - } - mockSvc := new(mocks.AssetService) - mockUserSvc := new(mocks.UserService) - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - mockSvc.EXPECT().GetLineage(ctx, nodeURN, asset.LineageQuery{Level: level, Direction: direction, WithAttributes: true}).Return(lineage, nil) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, mockSvc, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.GetGraph(ctx, connect.NewRequest(&compassv1beta1.GetGraphRequest{ - Urn: nodeURN, - Level: uint32(level), - Direction: string(direction), - })) - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - - expected := &compassv1beta1.GetGraphResponse{ - Data: []*compassv1beta1.LineageEdge{ - { - Source: "job-1", - Target: "table-2", - }, - { - Source: "table-2", - Target: "table-31", - }, - { - Source: "table-31", - Target: "dashboard-30", - }, - }, - NodeAttrs: map[string]*compassv1beta1.GetGraphResponse_NodeAttributes{ - "job-1": { - Probes: &compassv1beta1.GetGraphResponse_ProbesInfo{ - Latest: &compassv1beta1.Probe{Status: "SUCCESS", Timestamp: tspb, CreatedAt: tspb}, - }, - }, - "table-2": { - Probes: &compassv1beta1.GetGraphResponse_ProbesInfo{ - Latest: &compassv1beta1.Probe{Status: "FAILED", Timestamp: tspb, CreatedAt: tspb}, - }, - }, - }, - } - if diff := cmp.Diff(got.Msg, expected, protocmp.Transform()); diff != "" { - t.Errorf("expected: %+v\ngot: %+v\ndiff: %s\n", expected, got.Msg, diff) - } - }) - - }) -} diff --git a/handler/mocks/asset_service.go b/handler/mocks/asset_service.go deleted file mode 100644 index 87cb4568..00000000 --- a/handler/mocks/asset_service.go +++ /dev/null @@ -1,708 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - asset "github.com/raystack/compass/core/asset" - - mock "github.com/stretchr/testify/mock" - - namespace "github.com/raystack/compass/core/namespace" -) - -// AssetService is an autogenerated mock type for the AssetService type -type AssetService struct { - mock.Mock -} - -type AssetService_Expecter struct { - mock *mock.Mock -} - -func (_m *AssetService) EXPECT() *AssetService_Expecter { - return &AssetService_Expecter{mock: &_m.Mock} -} - -// AddProbe provides a mock function with given fields: ctx, ns, assetURN, probe -func (_m *AssetService) AddProbe(ctx context.Context, ns *namespace.Namespace, assetURN string, probe *asset.Probe) error { - ret := _m.Called(ctx, ns, assetURN, probe) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string, *asset.Probe) error); ok { - r0 = rf(ctx, ns, assetURN, probe) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AssetService_AddProbe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddProbe' -type AssetService_AddProbe_Call struct { - *mock.Call -} - -// AddProbe is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - assetURN string -// - probe *asset.Probe -func (_e *AssetService_Expecter) AddProbe(ctx interface{}, ns interface{}, assetURN interface{}, probe interface{}) *AssetService_AddProbe_Call { - return &AssetService_AddProbe_Call{Call: _e.mock.On("AddProbe", ctx, ns, assetURN, probe)} -} - -func (_c *AssetService_AddProbe_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, assetURN string, probe *asset.Probe)) *AssetService_AddProbe_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(string), args[3].(*asset.Probe)) - }) - return _c -} - -func (_c *AssetService_AddProbe_Call) Return(_a0 error) *AssetService_AddProbe_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *AssetService_AddProbe_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, string, *asset.Probe) error) *AssetService_AddProbe_Call { - _c.Call.Return(run) - return _c -} - -// DeleteAsset provides a mock function with given fields: ctx, ns, id -func (_m *AssetService) DeleteAsset(ctx context.Context, ns *namespace.Namespace, id string) error { - ret := _m.Called(ctx, ns, id) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string) error); ok { - r0 = rf(ctx, ns, id) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AssetService_DeleteAsset_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteAsset' -type AssetService_DeleteAsset_Call struct { - *mock.Call -} - -// DeleteAsset is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - id string -func (_e *AssetService_Expecter) DeleteAsset(ctx interface{}, ns interface{}, id interface{}) *AssetService_DeleteAsset_Call { - return &AssetService_DeleteAsset_Call{Call: _e.mock.On("DeleteAsset", ctx, ns, id)} -} - -func (_c *AssetService_DeleteAsset_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, id string)) *AssetService_DeleteAsset_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(string)) - }) - return _c -} - -func (_c *AssetService_DeleteAsset_Call) Return(_a0 error) *AssetService_DeleteAsset_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *AssetService_DeleteAsset_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, string) error) *AssetService_DeleteAsset_Call { - _c.Call.Return(run) - return _c -} - -// GetAllAssets provides a mock function with given fields: ctx, flt, withTotal -func (_m *AssetService) GetAllAssets(ctx context.Context, flt asset.Filter, withTotal bool) ([]asset.Asset, uint32, error) { - ret := _m.Called(ctx, flt, withTotal) - - var r0 []asset.Asset - var r1 uint32 - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter, bool) ([]asset.Asset, uint32, error)); ok { - return rf(ctx, flt, withTotal) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter, bool) []asset.Asset); ok { - r0 = rf(ctx, flt, withTotal) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]asset.Asset) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.Filter, bool) uint32); ok { - r1 = rf(ctx, flt, withTotal) - } else { - r1 = ret.Get(1).(uint32) - } - - if rf, ok := ret.Get(2).(func(context.Context, asset.Filter, bool) error); ok { - r2 = rf(ctx, flt, withTotal) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - -// AssetService_GetAllAssets_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllAssets' -type AssetService_GetAllAssets_Call struct { - *mock.Call -} - -// GetAllAssets is a helper method to define mock.On call -// - ctx context.Context -// - flt asset.Filter -// - withTotal bool -func (_e *AssetService_Expecter) GetAllAssets(ctx interface{}, flt interface{}, withTotal interface{}) *AssetService_GetAllAssets_Call { - return &AssetService_GetAllAssets_Call{Call: _e.mock.On("GetAllAssets", ctx, flt, withTotal)} -} - -func (_c *AssetService_GetAllAssets_Call) Run(run func(ctx context.Context, flt asset.Filter, withTotal bool)) *AssetService_GetAllAssets_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.Filter), args[2].(bool)) - }) - return _c -} - -func (_c *AssetService_GetAllAssets_Call) Return(_a0 []asset.Asset, _a1 uint32, _a2 error) *AssetService_GetAllAssets_Call { - _c.Call.Return(_a0, _a1, _a2) - return _c -} - -func (_c *AssetService_GetAllAssets_Call) RunAndReturn(run func(context.Context, asset.Filter, bool) ([]asset.Asset, uint32, error)) *AssetService_GetAllAssets_Call { - _c.Call.Return(run) - return _c -} - -// GetAssetByID provides a mock function with given fields: ctx, id -func (_m *AssetService) GetAssetByID(ctx context.Context, id string) (asset.Asset, error) { - ret := _m.Called(ctx, id) - - var r0 asset.Asset - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (asset.Asset, error)); ok { - return rf(ctx, id) - } - if rf, ok := ret.Get(0).(func(context.Context, string) asset.Asset); ok { - r0 = rf(ctx, id) - } else { - r0 = ret.Get(0).(asset.Asset) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetService_GetAssetByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAssetByID' -type AssetService_GetAssetByID_Call struct { - *mock.Call -} - -// GetAssetByID is a helper method to define mock.On call -// - ctx context.Context -// - id string -func (_e *AssetService_Expecter) GetAssetByID(ctx interface{}, id interface{}) *AssetService_GetAssetByID_Call { - return &AssetService_GetAssetByID_Call{Call: _e.mock.On("GetAssetByID", ctx, id)} -} - -func (_c *AssetService_GetAssetByID_Call) Run(run func(ctx context.Context, id string)) *AssetService_GetAssetByID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *AssetService_GetAssetByID_Call) Return(_a0 asset.Asset, _a1 error) *AssetService_GetAssetByID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetService_GetAssetByID_Call) RunAndReturn(run func(context.Context, string) (asset.Asset, error)) *AssetService_GetAssetByID_Call { - _c.Call.Return(run) - return _c -} - -// GetAssetByVersion provides a mock function with given fields: ctx, id, version -func (_m *AssetService) GetAssetByVersion(ctx context.Context, id string, version string) (asset.Asset, error) { - ret := _m.Called(ctx, id, version) - - var r0 asset.Asset - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (asset.Asset, error)); ok { - return rf(ctx, id, version) - } - if rf, ok := ret.Get(0).(func(context.Context, string, string) asset.Asset); ok { - r0 = rf(ctx, id, version) - } else { - r0 = ret.Get(0).(asset.Asset) - } - - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, id, version) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetService_GetAssetByVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAssetByVersion' -type AssetService_GetAssetByVersion_Call struct { - *mock.Call -} - -// GetAssetByVersion is a helper method to define mock.On call -// - ctx context.Context -// - id string -// - version string -func (_e *AssetService_Expecter) GetAssetByVersion(ctx interface{}, id interface{}, version interface{}) *AssetService_GetAssetByVersion_Call { - return &AssetService_GetAssetByVersion_Call{Call: _e.mock.On("GetAssetByVersion", ctx, id, version)} -} - -func (_c *AssetService_GetAssetByVersion_Call) Run(run func(ctx context.Context, id string, version string)) *AssetService_GetAssetByVersion_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) - }) - return _c -} - -func (_c *AssetService_GetAssetByVersion_Call) Return(_a0 asset.Asset, _a1 error) *AssetService_GetAssetByVersion_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetService_GetAssetByVersion_Call) RunAndReturn(run func(context.Context, string, string) (asset.Asset, error)) *AssetService_GetAssetByVersion_Call { - _c.Call.Return(run) - return _c -} - -// GetAssetVersionHistory provides a mock function with given fields: ctx, flt, id -func (_m *AssetService) GetAssetVersionHistory(ctx context.Context, flt asset.Filter, id string) ([]asset.Asset, error) { - ret := _m.Called(ctx, flt, id) - - var r0 []asset.Asset - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter, string) ([]asset.Asset, error)); ok { - return rf(ctx, flt, id) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter, string) []asset.Asset); ok { - r0 = rf(ctx, flt, id) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]asset.Asset) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.Filter, string) error); ok { - r1 = rf(ctx, flt, id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetService_GetAssetVersionHistory_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAssetVersionHistory' -type AssetService_GetAssetVersionHistory_Call struct { - *mock.Call -} - -// GetAssetVersionHistory is a helper method to define mock.On call -// - ctx context.Context -// - flt asset.Filter -// - id string -func (_e *AssetService_Expecter) GetAssetVersionHistory(ctx interface{}, flt interface{}, id interface{}) *AssetService_GetAssetVersionHistory_Call { - return &AssetService_GetAssetVersionHistory_Call{Call: _e.mock.On("GetAssetVersionHistory", ctx, flt, id)} -} - -func (_c *AssetService_GetAssetVersionHistory_Call) Run(run func(ctx context.Context, flt asset.Filter, id string)) *AssetService_GetAssetVersionHistory_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.Filter), args[2].(string)) - }) - return _c -} - -func (_c *AssetService_GetAssetVersionHistory_Call) Return(_a0 []asset.Asset, _a1 error) *AssetService_GetAssetVersionHistory_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetService_GetAssetVersionHistory_Call) RunAndReturn(run func(context.Context, asset.Filter, string) ([]asset.Asset, error)) *AssetService_GetAssetVersionHistory_Call { - _c.Call.Return(run) - return _c -} - -// GetLineage provides a mock function with given fields: ctx, urn, query -func (_m *AssetService) GetLineage(ctx context.Context, urn string, query asset.LineageQuery) (asset.Lineage, error) { - ret := _m.Called(ctx, urn, query) - - var r0 asset.Lineage - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, asset.LineageQuery) (asset.Lineage, error)); ok { - return rf(ctx, urn, query) - } - if rf, ok := ret.Get(0).(func(context.Context, string, asset.LineageQuery) asset.Lineage); ok { - r0 = rf(ctx, urn, query) - } else { - r0 = ret.Get(0).(asset.Lineage) - } - - if rf, ok := ret.Get(1).(func(context.Context, string, asset.LineageQuery) error); ok { - r1 = rf(ctx, urn, query) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetService_GetLineage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLineage' -type AssetService_GetLineage_Call struct { - *mock.Call -} - -// GetLineage is a helper method to define mock.On call -// - ctx context.Context -// - urn string -// - query asset.LineageQuery -func (_e *AssetService_Expecter) GetLineage(ctx interface{}, urn interface{}, query interface{}) *AssetService_GetLineage_Call { - return &AssetService_GetLineage_Call{Call: _e.mock.On("GetLineage", ctx, urn, query)} -} - -func (_c *AssetService_GetLineage_Call) Run(run func(ctx context.Context, urn string, query asset.LineageQuery)) *AssetService_GetLineage_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(asset.LineageQuery)) - }) - return _c -} - -func (_c *AssetService_GetLineage_Call) Return(_a0 asset.Lineage, _a1 error) *AssetService_GetLineage_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetService_GetLineage_Call) RunAndReturn(run func(context.Context, string, asset.LineageQuery) (asset.Lineage, error)) *AssetService_GetLineage_Call { - _c.Call.Return(run) - return _c -} - -// GetTypes provides a mock function with given fields: ctx, flt -func (_m *AssetService) GetTypes(ctx context.Context, flt asset.Filter) (map[asset.Type]int, error) { - ret := _m.Called(ctx, flt) - - var r0 map[asset.Type]int - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter) (map[asset.Type]int, error)); ok { - return rf(ctx, flt) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.Filter) map[asset.Type]int); ok { - r0 = rf(ctx, flt) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[asset.Type]int) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.Filter) error); ok { - r1 = rf(ctx, flt) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetService_GetTypes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTypes' -type AssetService_GetTypes_Call struct { - *mock.Call -} - -// GetTypes is a helper method to define mock.On call -// - ctx context.Context -// - flt asset.Filter -func (_e *AssetService_Expecter) GetTypes(ctx interface{}, flt interface{}) *AssetService_GetTypes_Call { - return &AssetService_GetTypes_Call{Call: _e.mock.On("GetTypes", ctx, flt)} -} - -func (_c *AssetService_GetTypes_Call) Run(run func(ctx context.Context, flt asset.Filter)) *AssetService_GetTypes_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.Filter)) - }) - return _c -} - -func (_c *AssetService_GetTypes_Call) Return(_a0 map[asset.Type]int, _a1 error) *AssetService_GetTypes_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetService_GetTypes_Call) RunAndReturn(run func(context.Context, asset.Filter) (map[asset.Type]int, error)) *AssetService_GetTypes_Call { - _c.Call.Return(run) - return _c -} - -// SearchAssets provides a mock function with given fields: ctx, cfg -func (_m *AssetService) SearchAssets(ctx context.Context, cfg asset.SearchConfig) ([]asset.SearchResult, error) { - ret := _m.Called(ctx, cfg) - - var r0 []asset.SearchResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.SearchConfig) ([]asset.SearchResult, error)); ok { - return rf(ctx, cfg) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.SearchConfig) []asset.SearchResult); ok { - r0 = rf(ctx, cfg) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]asset.SearchResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.SearchConfig) error); ok { - r1 = rf(ctx, cfg) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetService_SearchAssets_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SearchAssets' -type AssetService_SearchAssets_Call struct { - *mock.Call -} - -// SearchAssets is a helper method to define mock.On call -// - ctx context.Context -// - cfg asset.SearchConfig -func (_e *AssetService_Expecter) SearchAssets(ctx interface{}, cfg interface{}) *AssetService_SearchAssets_Call { - return &AssetService_SearchAssets_Call{Call: _e.mock.On("SearchAssets", ctx, cfg)} -} - -func (_c *AssetService_SearchAssets_Call) Run(run func(ctx context.Context, cfg asset.SearchConfig)) *AssetService_SearchAssets_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.SearchConfig)) - }) - return _c -} - -func (_c *AssetService_SearchAssets_Call) Return(results []asset.SearchResult, err error) *AssetService_SearchAssets_Call { - _c.Call.Return(results, err) - return _c -} - -func (_c *AssetService_SearchAssets_Call) RunAndReturn(run func(context.Context, asset.SearchConfig) ([]asset.SearchResult, error)) *AssetService_SearchAssets_Call { - _c.Call.Return(run) - return _c -} - -// SuggestAssets provides a mock function with given fields: ctx, cfg -func (_m *AssetService) SuggestAssets(ctx context.Context, cfg asset.SearchConfig) ([]string, error) { - ret := _m.Called(ctx, cfg) - - var r0 []string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.SearchConfig) ([]string, error)); ok { - return rf(ctx, cfg) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.SearchConfig) []string); ok { - r0 = rf(ctx, cfg) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, asset.SearchConfig) error); ok { - r1 = rf(ctx, cfg) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetService_SuggestAssets_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SuggestAssets' -type AssetService_SuggestAssets_Call struct { - *mock.Call -} - -// SuggestAssets is a helper method to define mock.On call -// - ctx context.Context -// - cfg asset.SearchConfig -func (_e *AssetService_Expecter) SuggestAssets(ctx interface{}, cfg interface{}) *AssetService_SuggestAssets_Call { - return &AssetService_SuggestAssets_Call{Call: _e.mock.On("SuggestAssets", ctx, cfg)} -} - -func (_c *AssetService_SuggestAssets_Call) Run(run func(ctx context.Context, cfg asset.SearchConfig)) *AssetService_SuggestAssets_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(asset.SearchConfig)) - }) - return _c -} - -func (_c *AssetService_SuggestAssets_Call) Return(suggestions []string, err error) *AssetService_SuggestAssets_Call { - _c.Call.Return(suggestions, err) - return _c -} - -func (_c *AssetService_SuggestAssets_Call) RunAndReturn(run func(context.Context, asset.SearchConfig) ([]string, error)) *AssetService_SuggestAssets_Call { - _c.Call.Return(run) - return _c -} - -// UpsertAsset provides a mock function with given fields: ctx, ns, ast, upstreams, downstreams -func (_m *AssetService) UpsertAsset(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset, upstreams []string, downstreams []string) (string, error) { - ret := _m.Called(ctx, ns, ast, upstreams, downstreams) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *asset.Asset, []string, []string) (string, error)); ok { - return rf(ctx, ns, ast, upstreams, downstreams) - } - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *asset.Asset, []string, []string) string); ok { - r0 = rf(ctx, ns, ast, upstreams, downstreams) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(context.Context, *namespace.Namespace, *asset.Asset, []string, []string) error); ok { - r1 = rf(ctx, ns, ast, upstreams, downstreams) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetService_UpsertAsset_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpsertAsset' -type AssetService_UpsertAsset_Call struct { - *mock.Call -} - -// UpsertAsset is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - ast *asset.Asset -// - upstreams []string -// - downstreams []string -func (_e *AssetService_Expecter) UpsertAsset(ctx interface{}, ns interface{}, ast interface{}, upstreams interface{}, downstreams interface{}) *AssetService_UpsertAsset_Call { - return &AssetService_UpsertAsset_Call{Call: _e.mock.On("UpsertAsset", ctx, ns, ast, upstreams, downstreams)} -} - -func (_c *AssetService_UpsertAsset_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset, upstreams []string, downstreams []string)) *AssetService_UpsertAsset_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*asset.Asset), args[3].([]string), args[4].([]string)) - }) - return _c -} - -func (_c *AssetService_UpsertAsset_Call) Return(_a0 string, _a1 error) *AssetService_UpsertAsset_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetService_UpsertAsset_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *asset.Asset, []string, []string) (string, error)) *AssetService_UpsertAsset_Call { - _c.Call.Return(run) - return _c -} - -// UpsertAssetWithoutLineage provides a mock function with given fields: ctx, ns, ast -func (_m *AssetService) UpsertAssetWithoutLineage(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset) (string, error) { - ret := _m.Called(ctx, ns, ast) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *asset.Asset) (string, error)); ok { - return rf(ctx, ns, ast) - } - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *asset.Asset) string); ok { - r0 = rf(ctx, ns, ast) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(context.Context, *namespace.Namespace, *asset.Asset) error); ok { - r1 = rf(ctx, ns, ast) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// AssetService_UpsertAssetWithoutLineage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpsertAssetWithoutLineage' -type AssetService_UpsertAssetWithoutLineage_Call struct { - *mock.Call -} - -// UpsertAssetWithoutLineage is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - ast *asset.Asset -func (_e *AssetService_Expecter) UpsertAssetWithoutLineage(ctx interface{}, ns interface{}, ast interface{}) *AssetService_UpsertAssetWithoutLineage_Call { - return &AssetService_UpsertAssetWithoutLineage_Call{Call: _e.mock.On("UpsertAssetWithoutLineage", ctx, ns, ast)} -} - -func (_c *AssetService_UpsertAssetWithoutLineage_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset)) *AssetService_UpsertAssetWithoutLineage_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*asset.Asset)) - }) - return _c -} - -func (_c *AssetService_UpsertAssetWithoutLineage_Call) Return(_a0 string, _a1 error) *AssetService_UpsertAssetWithoutLineage_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *AssetService_UpsertAssetWithoutLineage_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *asset.Asset) (string, error)) *AssetService_UpsertAssetWithoutLineage_Call { - _c.Call.Return(run) - return _c -} - -// GroupAssets provides a mock function with given fields: ctx, cfg -func (_m *AssetService) GroupAssets(ctx context.Context, cfg asset.GroupConfig) ([]asset.GroupResult, error) { - ret := _m.Called(ctx, cfg) - var r0 []asset.GroupResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, asset.GroupConfig) ([]asset.GroupResult, error)); ok { - return rf(ctx, cfg) - } - if rf, ok := ret.Get(0).(func(context.Context, asset.GroupConfig) []asset.GroupResult); ok { - r0 = rf(ctx, cfg) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]asset.GroupResult) - } - } - if rf, ok := ret.Get(1).(func(context.Context, asset.GroupConfig) error); ok { - r1 = rf(ctx, cfg) - } else { - r1 = ret.Error(1) - } - return r0, r1 -} - -type mockConstructorTestingTNewAssetService interface { - mock.TestingT - Cleanup(func()) -} - -// NewAssetService creates a new instance of AssetService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewAssetService(t mockConstructorTestingTNewAssetService) *AssetService { - mock := &AssetService{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/handler/mocks/discussion_service.go b/handler/mocks/discussion_service.go deleted file mode 100644 index 088703ee..00000000 --- a/handler/mocks/discussion_service.go +++ /dev/null @@ -1,497 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - discussion "github.com/raystack/compass/core/discussion" - - mock "github.com/stretchr/testify/mock" - - namespace "github.com/raystack/compass/core/namespace" -) - -// DiscussionService is an autogenerated mock type for the DiscussionService type -type DiscussionService struct { - mock.Mock -} - -type DiscussionService_Expecter struct { - mock *mock.Mock -} - -func (_m *DiscussionService) EXPECT() *DiscussionService_Expecter { - return &DiscussionService_Expecter{mock: &_m.Mock} -} - -// CreateComment provides a mock function with given fields: ctx, ns, cmt -func (_m *DiscussionService) CreateComment(ctx context.Context, ns *namespace.Namespace, cmt *discussion.Comment) (string, error) { - ret := _m.Called(ctx, ns, cmt) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *discussion.Comment) (string, error)); ok { - return rf(ctx, ns, cmt) - } - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *discussion.Comment) string); ok { - r0 = rf(ctx, ns, cmt) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(context.Context, *namespace.Namespace, *discussion.Comment) error); ok { - r1 = rf(ctx, ns, cmt) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionService_CreateComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateComment' -type DiscussionService_CreateComment_Call struct { - *mock.Call -} - -// CreateComment is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - cmt *discussion.Comment -func (_e *DiscussionService_Expecter) CreateComment(ctx interface{}, ns interface{}, cmt interface{}) *DiscussionService_CreateComment_Call { - return &DiscussionService_CreateComment_Call{Call: _e.mock.On("CreateComment", ctx, ns, cmt)} -} - -func (_c *DiscussionService_CreateComment_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, cmt *discussion.Comment)) *DiscussionService_CreateComment_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*discussion.Comment)) - }) - return _c -} - -func (_c *DiscussionService_CreateComment_Call) Return(_a0 string, _a1 error) *DiscussionService_CreateComment_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionService_CreateComment_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *discussion.Comment) (string, error)) *DiscussionService_CreateComment_Call { - _c.Call.Return(run) - return _c -} - -// CreateDiscussion provides a mock function with given fields: ctx, ns, _a2 -func (_m *DiscussionService) CreateDiscussion(ctx context.Context, ns *namespace.Namespace, _a2 *discussion.Discussion) (string, error) { - ret := _m.Called(ctx, ns, _a2) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *discussion.Discussion) (string, error)); ok { - return rf(ctx, ns, _a2) - } - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *discussion.Discussion) string); ok { - r0 = rf(ctx, ns, _a2) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(context.Context, *namespace.Namespace, *discussion.Discussion) error); ok { - r1 = rf(ctx, ns, _a2) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionService_CreateDiscussion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateDiscussion' -type DiscussionService_CreateDiscussion_Call struct { - *mock.Call -} - -// CreateDiscussion is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - _a2 *discussion.Discussion -func (_e *DiscussionService_Expecter) CreateDiscussion(ctx interface{}, ns interface{}, _a2 interface{}) *DiscussionService_CreateDiscussion_Call { - return &DiscussionService_CreateDiscussion_Call{Call: _e.mock.On("CreateDiscussion", ctx, ns, _a2)} -} - -func (_c *DiscussionService_CreateDiscussion_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, _a2 *discussion.Discussion)) *DiscussionService_CreateDiscussion_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*discussion.Discussion)) - }) - return _c -} - -func (_c *DiscussionService_CreateDiscussion_Call) Return(_a0 string, _a1 error) *DiscussionService_CreateDiscussion_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionService_CreateDiscussion_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *discussion.Discussion) (string, error)) *DiscussionService_CreateDiscussion_Call { - _c.Call.Return(run) - return _c -} - -// DeleteComment provides a mock function with given fields: ctx, commentID, discussionID -func (_m *DiscussionService) DeleteComment(ctx context.Context, commentID string, discussionID string) error { - ret := _m.Called(ctx, commentID, discussionID) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { - r0 = rf(ctx, commentID, discussionID) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DiscussionService_DeleteComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteComment' -type DiscussionService_DeleteComment_Call struct { - *mock.Call -} - -// DeleteComment is a helper method to define mock.On call -// - ctx context.Context -// - commentID string -// - discussionID string -func (_e *DiscussionService_Expecter) DeleteComment(ctx interface{}, commentID interface{}, discussionID interface{}) *DiscussionService_DeleteComment_Call { - return &DiscussionService_DeleteComment_Call{Call: _e.mock.On("DeleteComment", ctx, commentID, discussionID)} -} - -func (_c *DiscussionService_DeleteComment_Call) Run(run func(ctx context.Context, commentID string, discussionID string)) *DiscussionService_DeleteComment_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) - }) - return _c -} - -func (_c *DiscussionService_DeleteComment_Call) Return(_a0 error) *DiscussionService_DeleteComment_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *DiscussionService_DeleteComment_Call) RunAndReturn(run func(context.Context, string, string) error) *DiscussionService_DeleteComment_Call { - _c.Call.Return(run) - return _c -} - -// GetComment provides a mock function with given fields: ctx, commentID, discussionID -func (_m *DiscussionService) GetComment(ctx context.Context, commentID string, discussionID string) (discussion.Comment, error) { - ret := _m.Called(ctx, commentID, discussionID) - - var r0 discussion.Comment - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (discussion.Comment, error)); ok { - return rf(ctx, commentID, discussionID) - } - if rf, ok := ret.Get(0).(func(context.Context, string, string) discussion.Comment); ok { - r0 = rf(ctx, commentID, discussionID) - } else { - r0 = ret.Get(0).(discussion.Comment) - } - - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, commentID, discussionID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionService_GetComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetComment' -type DiscussionService_GetComment_Call struct { - *mock.Call -} - -// GetComment is a helper method to define mock.On call -// - ctx context.Context -// - commentID string -// - discussionID string -func (_e *DiscussionService_Expecter) GetComment(ctx interface{}, commentID interface{}, discussionID interface{}) *DiscussionService_GetComment_Call { - return &DiscussionService_GetComment_Call{Call: _e.mock.On("GetComment", ctx, commentID, discussionID)} -} - -func (_c *DiscussionService_GetComment_Call) Run(run func(ctx context.Context, commentID string, discussionID string)) *DiscussionService_GetComment_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) - }) - return _c -} - -func (_c *DiscussionService_GetComment_Call) Return(_a0 discussion.Comment, _a1 error) *DiscussionService_GetComment_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionService_GetComment_Call) RunAndReturn(run func(context.Context, string, string) (discussion.Comment, error)) *DiscussionService_GetComment_Call { - _c.Call.Return(run) - return _c -} - -// GetComments provides a mock function with given fields: ctx, discussionID, filter -func (_m *DiscussionService) GetComments(ctx context.Context, discussionID string, filter discussion.Filter) ([]discussion.Comment, error) { - ret := _m.Called(ctx, discussionID, filter) - - var r0 []discussion.Comment - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, discussion.Filter) ([]discussion.Comment, error)); ok { - return rf(ctx, discussionID, filter) - } - if rf, ok := ret.Get(0).(func(context.Context, string, discussion.Filter) []discussion.Comment); ok { - r0 = rf(ctx, discussionID, filter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]discussion.Comment) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string, discussion.Filter) error); ok { - r1 = rf(ctx, discussionID, filter) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionService_GetComments_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetComments' -type DiscussionService_GetComments_Call struct { - *mock.Call -} - -// GetComments is a helper method to define mock.On call -// - ctx context.Context -// - discussionID string -// - filter discussion.Filter -func (_e *DiscussionService_Expecter) GetComments(ctx interface{}, discussionID interface{}, filter interface{}) *DiscussionService_GetComments_Call { - return &DiscussionService_GetComments_Call{Call: _e.mock.On("GetComments", ctx, discussionID, filter)} -} - -func (_c *DiscussionService_GetComments_Call) Run(run func(ctx context.Context, discussionID string, filter discussion.Filter)) *DiscussionService_GetComments_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(discussion.Filter)) - }) - return _c -} - -func (_c *DiscussionService_GetComments_Call) Return(_a0 []discussion.Comment, _a1 error) *DiscussionService_GetComments_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionService_GetComments_Call) RunAndReturn(run func(context.Context, string, discussion.Filter) ([]discussion.Comment, error)) *DiscussionService_GetComments_Call { - _c.Call.Return(run) - return _c -} - -// GetDiscussion provides a mock function with given fields: ctx, did -func (_m *DiscussionService) GetDiscussion(ctx context.Context, did string) (discussion.Discussion, error) { - ret := _m.Called(ctx, did) - - var r0 discussion.Discussion - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (discussion.Discussion, error)); ok { - return rf(ctx, did) - } - if rf, ok := ret.Get(0).(func(context.Context, string) discussion.Discussion); ok { - r0 = rf(ctx, did) - } else { - r0 = ret.Get(0).(discussion.Discussion) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, did) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionService_GetDiscussion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDiscussion' -type DiscussionService_GetDiscussion_Call struct { - *mock.Call -} - -// GetDiscussion is a helper method to define mock.On call -// - ctx context.Context -// - did string -func (_e *DiscussionService_Expecter) GetDiscussion(ctx interface{}, did interface{}) *DiscussionService_GetDiscussion_Call { - return &DiscussionService_GetDiscussion_Call{Call: _e.mock.On("GetDiscussion", ctx, did)} -} - -func (_c *DiscussionService_GetDiscussion_Call) Run(run func(ctx context.Context, did string)) *DiscussionService_GetDiscussion_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *DiscussionService_GetDiscussion_Call) Return(_a0 discussion.Discussion, _a1 error) *DiscussionService_GetDiscussion_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionService_GetDiscussion_Call) RunAndReturn(run func(context.Context, string) (discussion.Discussion, error)) *DiscussionService_GetDiscussion_Call { - _c.Call.Return(run) - return _c -} - -// GetDiscussions provides a mock function with given fields: ctx, filter -func (_m *DiscussionService) GetDiscussions(ctx context.Context, filter discussion.Filter) ([]discussion.Discussion, error) { - ret := _m.Called(ctx, filter) - - var r0 []discussion.Discussion - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, discussion.Filter) ([]discussion.Discussion, error)); ok { - return rf(ctx, filter) - } - if rf, ok := ret.Get(0).(func(context.Context, discussion.Filter) []discussion.Discussion); ok { - r0 = rf(ctx, filter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]discussion.Discussion) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, discussion.Filter) error); ok { - r1 = rf(ctx, filter) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DiscussionService_GetDiscussions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDiscussions' -type DiscussionService_GetDiscussions_Call struct { - *mock.Call -} - -// GetDiscussions is a helper method to define mock.On call -// - ctx context.Context -// - filter discussion.Filter -func (_e *DiscussionService_Expecter) GetDiscussions(ctx interface{}, filter interface{}) *DiscussionService_GetDiscussions_Call { - return &DiscussionService_GetDiscussions_Call{Call: _e.mock.On("GetDiscussions", ctx, filter)} -} - -func (_c *DiscussionService_GetDiscussions_Call) Run(run func(ctx context.Context, filter discussion.Filter)) *DiscussionService_GetDiscussions_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(discussion.Filter)) - }) - return _c -} - -func (_c *DiscussionService_GetDiscussions_Call) Return(_a0 []discussion.Discussion, _a1 error) *DiscussionService_GetDiscussions_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *DiscussionService_GetDiscussions_Call) RunAndReturn(run func(context.Context, discussion.Filter) ([]discussion.Discussion, error)) *DiscussionService_GetDiscussions_Call { - _c.Call.Return(run) - return _c -} - -// PatchDiscussion provides a mock function with given fields: ctx, _a1 -func (_m *DiscussionService) PatchDiscussion(ctx context.Context, _a1 *discussion.Discussion) error { - ret := _m.Called(ctx, _a1) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *discussion.Discussion) error); ok { - r0 = rf(ctx, _a1) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DiscussionService_PatchDiscussion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PatchDiscussion' -type DiscussionService_PatchDiscussion_Call struct { - *mock.Call -} - -// PatchDiscussion is a helper method to define mock.On call -// - ctx context.Context -// - _a1 *discussion.Discussion -func (_e *DiscussionService_Expecter) PatchDiscussion(ctx interface{}, _a1 interface{}) *DiscussionService_PatchDiscussion_Call { - return &DiscussionService_PatchDiscussion_Call{Call: _e.mock.On("PatchDiscussion", ctx, _a1)} -} - -func (_c *DiscussionService_PatchDiscussion_Call) Run(run func(ctx context.Context, _a1 *discussion.Discussion)) *DiscussionService_PatchDiscussion_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*discussion.Discussion)) - }) - return _c -} - -func (_c *DiscussionService_PatchDiscussion_Call) Return(_a0 error) *DiscussionService_PatchDiscussion_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *DiscussionService_PatchDiscussion_Call) RunAndReturn(run func(context.Context, *discussion.Discussion) error) *DiscussionService_PatchDiscussion_Call { - _c.Call.Return(run) - return _c -} - -// UpdateComment provides a mock function with given fields: ctx, cmt -func (_m *DiscussionService) UpdateComment(ctx context.Context, cmt *discussion.Comment) error { - ret := _m.Called(ctx, cmt) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *discussion.Comment) error); ok { - r0 = rf(ctx, cmt) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DiscussionService_UpdateComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateComment' -type DiscussionService_UpdateComment_Call struct { - *mock.Call -} - -// UpdateComment is a helper method to define mock.On call -// - ctx context.Context -// - cmt *discussion.Comment -func (_e *DiscussionService_Expecter) UpdateComment(ctx interface{}, cmt interface{}) *DiscussionService_UpdateComment_Call { - return &DiscussionService_UpdateComment_Call{Call: _e.mock.On("UpdateComment", ctx, cmt)} -} - -func (_c *DiscussionService_UpdateComment_Call) Run(run func(ctx context.Context, cmt *discussion.Comment)) *DiscussionService_UpdateComment_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*discussion.Comment)) - }) - return _c -} - -func (_c *DiscussionService_UpdateComment_Call) Return(_a0 error) *DiscussionService_UpdateComment_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *DiscussionService_UpdateComment_Call) RunAndReturn(run func(context.Context, *discussion.Comment) error) *DiscussionService_UpdateComment_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTNewDiscussionService interface { - mock.TestingT - Cleanup(func()) -} - -// NewDiscussionService creates a new instance of DiscussionService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewDiscussionService(t mockConstructorTestingTNewDiscussionService) *DiscussionService { - mock := &DiscussionService{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/handler/mocks/star_service.go b/handler/mocks/star_service.go deleted file mode 100644 index 3bdd1e89..00000000 --- a/handler/mocks/star_service.go +++ /dev/null @@ -1,310 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - asset "github.com/raystack/compass/core/asset" - - mock "github.com/stretchr/testify/mock" - - namespace "github.com/raystack/compass/core/namespace" - - star "github.com/raystack/compass/core/star" - - user "github.com/raystack/compass/core/user" -) - -// StarService is an autogenerated mock type for the StarService type -type StarService struct { - mock.Mock -} - -type StarService_Expecter struct { - mock *mock.Mock -} - -func (_m *StarService) EXPECT() *StarService_Expecter { - return &StarService_Expecter{mock: &_m.Mock} -} - -// GetStargazers provides a mock function with given fields: _a0, _a1, _a2 -func (_m *StarService) GetStargazers(_a0 context.Context, _a1 star.Filter, _a2 string) ([]user.User, error) { - ret := _m.Called(_a0, _a1, _a2) - - var r0 []user.User - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, star.Filter, string) ([]user.User, error)); ok { - return rf(_a0, _a1, _a2) - } - if rf, ok := ret.Get(0).(func(context.Context, star.Filter, string) []user.User); ok { - r0 = rf(_a0, _a1, _a2) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]user.User) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, star.Filter, string) error); ok { - r1 = rf(_a0, _a1, _a2) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// StarService_GetStargazers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStargazers' -type StarService_GetStargazers_Call struct { - *mock.Call -} - -// GetStargazers is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 star.Filter -// - _a2 string -func (_e *StarService_Expecter) GetStargazers(_a0 interface{}, _a1 interface{}, _a2 interface{}) *StarService_GetStargazers_Call { - return &StarService_GetStargazers_Call{Call: _e.mock.On("GetStargazers", _a0, _a1, _a2)} -} - -func (_c *StarService_GetStargazers_Call) Run(run func(_a0 context.Context, _a1 star.Filter, _a2 string)) *StarService_GetStargazers_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(star.Filter), args[2].(string)) - }) - return _c -} - -func (_c *StarService_GetStargazers_Call) Return(_a0 []user.User, _a1 error) *StarService_GetStargazers_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *StarService_GetStargazers_Call) RunAndReturn(run func(context.Context, star.Filter, string) ([]user.User, error)) *StarService_GetStargazers_Call { - _c.Call.Return(run) - return _c -} - -// GetStarredAssetByUserID provides a mock function with given fields: _a0, _a1, _a2 -func (_m *StarService) GetStarredAssetByUserID(_a0 context.Context, _a1 string, _a2 string) (asset.Asset, error) { - ret := _m.Called(_a0, _a1, _a2) - - var r0 asset.Asset - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (asset.Asset, error)); ok { - return rf(_a0, _a1, _a2) - } - if rf, ok := ret.Get(0).(func(context.Context, string, string) asset.Asset); ok { - r0 = rf(_a0, _a1, _a2) - } else { - r0 = ret.Get(0).(asset.Asset) - } - - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(_a0, _a1, _a2) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// StarService_GetStarredAssetByUserID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStarredAssetByUserID' -type StarService_GetStarredAssetByUserID_Call struct { - *mock.Call -} - -// GetStarredAssetByUserID is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 string -// - _a2 string -func (_e *StarService_Expecter) GetStarredAssetByUserID(_a0 interface{}, _a1 interface{}, _a2 interface{}) *StarService_GetStarredAssetByUserID_Call { - return &StarService_GetStarredAssetByUserID_Call{Call: _e.mock.On("GetStarredAssetByUserID", _a0, _a1, _a2)} -} - -func (_c *StarService_GetStarredAssetByUserID_Call) Run(run func(_a0 context.Context, _a1 string, _a2 string)) *StarService_GetStarredAssetByUserID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) - }) - return _c -} - -func (_c *StarService_GetStarredAssetByUserID_Call) Return(_a0 asset.Asset, _a1 error) *StarService_GetStarredAssetByUserID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *StarService_GetStarredAssetByUserID_Call) RunAndReturn(run func(context.Context, string, string) (asset.Asset, error)) *StarService_GetStarredAssetByUserID_Call { - _c.Call.Return(run) - return _c -} - -// GetStarredAssetsByUserID provides a mock function with given fields: _a0, _a1, _a2 -func (_m *StarService) GetStarredAssetsByUserID(_a0 context.Context, _a1 star.Filter, _a2 string) ([]asset.Asset, error) { - ret := _m.Called(_a0, _a1, _a2) - - var r0 []asset.Asset - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, star.Filter, string) ([]asset.Asset, error)); ok { - return rf(_a0, _a1, _a2) - } - if rf, ok := ret.Get(0).(func(context.Context, star.Filter, string) []asset.Asset); ok { - r0 = rf(_a0, _a1, _a2) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]asset.Asset) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, star.Filter, string) error); ok { - r1 = rf(_a0, _a1, _a2) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// StarService_GetStarredAssetsByUserID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStarredAssetsByUserID' -type StarService_GetStarredAssetsByUserID_Call struct { - *mock.Call -} - -// GetStarredAssetsByUserID is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 star.Filter -// - _a2 string -func (_e *StarService_Expecter) GetStarredAssetsByUserID(_a0 interface{}, _a1 interface{}, _a2 interface{}) *StarService_GetStarredAssetsByUserID_Call { - return &StarService_GetStarredAssetsByUserID_Call{Call: _e.mock.On("GetStarredAssetsByUserID", _a0, _a1, _a2)} -} - -func (_c *StarService_GetStarredAssetsByUserID_Call) Run(run func(_a0 context.Context, _a1 star.Filter, _a2 string)) *StarService_GetStarredAssetsByUserID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(star.Filter), args[2].(string)) - }) - return _c -} - -func (_c *StarService_GetStarredAssetsByUserID_Call) Return(_a0 []asset.Asset, _a1 error) *StarService_GetStarredAssetsByUserID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *StarService_GetStarredAssetsByUserID_Call) RunAndReturn(run func(context.Context, star.Filter, string) ([]asset.Asset, error)) *StarService_GetStarredAssetsByUserID_Call { - _c.Call.Return(run) - return _c -} - -// Stars provides a mock function with given fields: _a0, _a1, _a2, _a3 -func (_m *StarService) Stars(_a0 context.Context, _a1 *namespace.Namespace, _a2 string, _a3 string) (string, error) { - ret := _m.Called(_a0, _a1, _a2, _a3) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string, string) (string, error)); ok { - return rf(_a0, _a1, _a2, _a3) - } - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string, string) string); ok { - r0 = rf(_a0, _a1, _a2, _a3) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(context.Context, *namespace.Namespace, string, string) error); ok { - r1 = rf(_a0, _a1, _a2, _a3) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// StarService_Stars_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stars' -type StarService_Stars_Call struct { - *mock.Call -} - -// Stars is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 *namespace.Namespace -// - _a2 string -// - _a3 string -func (_e *StarService_Expecter) Stars(_a0 interface{}, _a1 interface{}, _a2 interface{}, _a3 interface{}) *StarService_Stars_Call { - return &StarService_Stars_Call{Call: _e.mock.On("Stars", _a0, _a1, _a2, _a3)} -} - -func (_c *StarService_Stars_Call) Run(run func(_a0 context.Context, _a1 *namespace.Namespace, _a2 string, _a3 string)) *StarService_Stars_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(string), args[3].(string)) - }) - return _c -} - -func (_c *StarService_Stars_Call) Return(_a0 string, _a1 error) *StarService_Stars_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *StarService_Stars_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, string, string) (string, error)) *StarService_Stars_Call { - _c.Call.Return(run) - return _c -} - -// Unstars provides a mock function with given fields: _a0, _a1, _a2 -func (_m *StarService) Unstars(_a0 context.Context, _a1 string, _a2 string) error { - ret := _m.Called(_a0, _a1, _a2) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { - r0 = rf(_a0, _a1, _a2) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// StarService_Unstars_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unstars' -type StarService_Unstars_Call struct { - *mock.Call -} - -// Unstars is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 string -// - _a2 string -func (_e *StarService_Expecter) Unstars(_a0 interface{}, _a1 interface{}, _a2 interface{}) *StarService_Unstars_Call { - return &StarService_Unstars_Call{Call: _e.mock.On("Unstars", _a0, _a1, _a2)} -} - -func (_c *StarService_Unstars_Call) Run(run func(_a0 context.Context, _a1 string, _a2 string)) *StarService_Unstars_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) - }) - return _c -} - -func (_c *StarService_Unstars_Call) Return(_a0 error) *StarService_Unstars_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *StarService_Unstars_Call) RunAndReturn(run func(context.Context, string, string) error) *StarService_Unstars_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTNewStarService interface { - mock.TestingT - Cleanup(func()) -} - -// NewStarService creates a new instance of StarService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewStarService(t mockConstructorTestingTNewStarService) *StarService { - mock := &StarService{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/handler/mocks/tag_service.go b/handler/mocks/tag_service.go deleted file mode 100644 index 8a40a6eb..00000000 --- a/handler/mocks/tag_service.go +++ /dev/null @@ -1,323 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - mock "github.com/stretchr/testify/mock" - - namespace "github.com/raystack/compass/core/namespace" - - tag "github.com/raystack/compass/core/tag" -) - -// TagService is an autogenerated mock type for the TagService type -type TagService struct { - mock.Mock -} - -type TagService_Expecter struct { - mock *mock.Mock -} - -func (_m *TagService) EXPECT() *TagService_Expecter { - return &TagService_Expecter{mock: &_m.Mock} -} - -// CreateTag provides a mock function with given fields: ctx, ns, _a2 -func (_m *TagService) CreateTag(ctx context.Context, ns *namespace.Namespace, _a2 *tag.Tag) error { - ret := _m.Called(ctx, ns, _a2) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *tag.Tag) error); ok { - r0 = rf(ctx, ns, _a2) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagService_CreateTag_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateTag' -type TagService_CreateTag_Call struct { - *mock.Call -} - -// CreateTag is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - _a2 *tag.Tag -func (_e *TagService_Expecter) CreateTag(ctx interface{}, ns interface{}, _a2 interface{}) *TagService_CreateTag_Call { - return &TagService_CreateTag_Call{Call: _e.mock.On("CreateTag", ctx, ns, _a2)} -} - -func (_c *TagService_CreateTag_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, _a2 *tag.Tag)) *TagService_CreateTag_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*tag.Tag)) - }) - return _c -} - -func (_c *TagService_CreateTag_Call) Return(_a0 error) *TagService_CreateTag_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagService_CreateTag_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *tag.Tag) error) *TagService_CreateTag_Call { - _c.Call.Return(run) - return _c -} - -// DeleteTag provides a mock function with given fields: ctx, assetID, templateURN -func (_m *TagService) DeleteTag(ctx context.Context, assetID string, templateURN string) error { - ret := _m.Called(ctx, assetID, templateURN) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { - r0 = rf(ctx, assetID, templateURN) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagService_DeleteTag_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteTag' -type TagService_DeleteTag_Call struct { - *mock.Call -} - -// DeleteTag is a helper method to define mock.On call -// - ctx context.Context -// - assetID string -// - templateURN string -func (_e *TagService_Expecter) DeleteTag(ctx interface{}, assetID interface{}, templateURN interface{}) *TagService_DeleteTag_Call { - return &TagService_DeleteTag_Call{Call: _e.mock.On("DeleteTag", ctx, assetID, templateURN)} -} - -func (_c *TagService_DeleteTag_Call) Run(run func(ctx context.Context, assetID string, templateURN string)) *TagService_DeleteTag_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) - }) - return _c -} - -func (_c *TagService_DeleteTag_Call) Return(_a0 error) *TagService_DeleteTag_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagService_DeleteTag_Call) RunAndReturn(run func(context.Context, string, string) error) *TagService_DeleteTag_Call { - _c.Call.Return(run) - return _c -} - -// FindTagByAssetIDAndTemplateURN provides a mock function with given fields: ctx, assetID, templateURN -func (_m *TagService) FindTagByAssetIDAndTemplateURN(ctx context.Context, assetID string, templateURN string) (tag.Tag, error) { - ret := _m.Called(ctx, assetID, templateURN) - - var r0 tag.Tag - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (tag.Tag, error)); ok { - return rf(ctx, assetID, templateURN) - } - if rf, ok := ret.Get(0).(func(context.Context, string, string) tag.Tag); ok { - r0 = rf(ctx, assetID, templateURN) - } else { - r0 = ret.Get(0).(tag.Tag) - } - - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, assetID, templateURN) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TagService_FindTagByAssetIDAndTemplateURN_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindTagByAssetIDAndTemplateURN' -type TagService_FindTagByAssetIDAndTemplateURN_Call struct { - *mock.Call -} - -// FindTagByAssetIDAndTemplateURN is a helper method to define mock.On call -// - ctx context.Context -// - assetID string -// - templateURN string -func (_e *TagService_Expecter) FindTagByAssetIDAndTemplateURN(ctx interface{}, assetID interface{}, templateURN interface{}) *TagService_FindTagByAssetIDAndTemplateURN_Call { - return &TagService_FindTagByAssetIDAndTemplateURN_Call{Call: _e.mock.On("FindTagByAssetIDAndTemplateURN", ctx, assetID, templateURN)} -} - -func (_c *TagService_FindTagByAssetIDAndTemplateURN_Call) Run(run func(ctx context.Context, assetID string, templateURN string)) *TagService_FindTagByAssetIDAndTemplateURN_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) - }) - return _c -} - -func (_c *TagService_FindTagByAssetIDAndTemplateURN_Call) Return(_a0 tag.Tag, _a1 error) *TagService_FindTagByAssetIDAndTemplateURN_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *TagService_FindTagByAssetIDAndTemplateURN_Call) RunAndReturn(run func(context.Context, string, string) (tag.Tag, error)) *TagService_FindTagByAssetIDAndTemplateURN_Call { - _c.Call.Return(run) - return _c -} - -// GetTagsByAssetID provides a mock function with given fields: ctx, assetID -func (_m *TagService) GetTagsByAssetID(ctx context.Context, assetID string) ([]tag.Tag, error) { - ret := _m.Called(ctx, assetID) - - var r0 []tag.Tag - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) ([]tag.Tag, error)); ok { - return rf(ctx, assetID) - } - if rf, ok := ret.Get(0).(func(context.Context, string) []tag.Tag); ok { - r0 = rf(ctx, assetID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]tag.Tag) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, assetID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TagService_GetTagsByAssetID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTagsByAssetID' -type TagService_GetTagsByAssetID_Call struct { - *mock.Call -} - -// GetTagsByAssetID is a helper method to define mock.On call -// - ctx context.Context -// - assetID string -func (_e *TagService_Expecter) GetTagsByAssetID(ctx interface{}, assetID interface{}) *TagService_GetTagsByAssetID_Call { - return &TagService_GetTagsByAssetID_Call{Call: _e.mock.On("GetTagsByAssetID", ctx, assetID)} -} - -func (_c *TagService_GetTagsByAssetID_Call) Run(run func(ctx context.Context, assetID string)) *TagService_GetTagsByAssetID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *TagService_GetTagsByAssetID_Call) Return(_a0 []tag.Tag, _a1 error) *TagService_GetTagsByAssetID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *TagService_GetTagsByAssetID_Call) RunAndReturn(run func(context.Context, string) ([]tag.Tag, error)) *TagService_GetTagsByAssetID_Call { - _c.Call.Return(run) - return _c -} - -// UpdateTag provides a mock function with given fields: ctx, _a1 -func (_m *TagService) UpdateTag(ctx context.Context, _a1 *tag.Tag) error { - ret := _m.Called(ctx, _a1) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *tag.Tag) error); ok { - r0 = rf(ctx, _a1) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagService_UpdateTag_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateTag' -type TagService_UpdateTag_Call struct { - *mock.Call -} - -// UpdateTag is a helper method to define mock.On call -// - ctx context.Context -// - _a1 *tag.Tag -func (_e *TagService_Expecter) UpdateTag(ctx interface{}, _a1 interface{}) *TagService_UpdateTag_Call { - return &TagService_UpdateTag_Call{Call: _e.mock.On("UpdateTag", ctx, _a1)} -} - -func (_c *TagService_UpdateTag_Call) Run(run func(ctx context.Context, _a1 *tag.Tag)) *TagService_UpdateTag_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*tag.Tag)) - }) - return _c -} - -func (_c *TagService_UpdateTag_Call) Return(_a0 error) *TagService_UpdateTag_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagService_UpdateTag_Call) RunAndReturn(run func(context.Context, *tag.Tag) error) *TagService_UpdateTag_Call { - _c.Call.Return(run) - return _c -} - -// Validate provides a mock function with given fields: _a0 -func (_m *TagService) Validate(_a0 *tag.Tag) error { - ret := _m.Called(_a0) - - var r0 error - if rf, ok := ret.Get(0).(func(*tag.Tag) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagService_Validate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Validate' -type TagService_Validate_Call struct { - *mock.Call -} - -// Validate is a helper method to define mock.On call -// - _a0 *tag.Tag -func (_e *TagService_Expecter) Validate(_a0 interface{}) *TagService_Validate_Call { - return &TagService_Validate_Call{Call: _e.mock.On("Validate", _a0)} -} - -func (_c *TagService_Validate_Call) Run(run func(_a0 *tag.Tag)) *TagService_Validate_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*tag.Tag)) - }) - return _c -} - -func (_c *TagService_Validate_Call) Return(_a0 error) *TagService_Validate_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagService_Validate_Call) RunAndReturn(run func(*tag.Tag) error) *TagService_Validate_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTNewTagService interface { - mock.TestingT - Cleanup(func()) -} - -// NewTagService creates a new instance of TagService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTagService(t mockConstructorTestingTNewTagService) *TagService { - mock := &TagService{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/handler/mocks/tag_template_service.go b/handler/mocks/tag_template_service.go deleted file mode 100644 index a9eb59c4..00000000 --- a/handler/mocks/tag_template_service.go +++ /dev/null @@ -1,323 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - mock "github.com/stretchr/testify/mock" - - namespace "github.com/raystack/compass/core/namespace" - - tag "github.com/raystack/compass/core/tag" -) - -// TagTemplateService is an autogenerated mock type for the TagTemplateService type -type TagTemplateService struct { - mock.Mock -} - -type TagTemplateService_Expecter struct { - mock *mock.Mock -} - -func (_m *TagTemplateService) EXPECT() *TagTemplateService_Expecter { - return &TagTemplateService_Expecter{mock: &_m.Mock} -} - -// CreateTemplate provides a mock function with given fields: ctx, ns, template -func (_m *TagTemplateService) CreateTemplate(ctx context.Context, ns *namespace.Namespace, template *tag.Template) error { - ret := _m.Called(ctx, ns, template) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, *tag.Template) error); ok { - r0 = rf(ctx, ns, template) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagTemplateService_CreateTemplate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateTemplate' -type TagTemplateService_CreateTemplate_Call struct { - *mock.Call -} - -// CreateTemplate is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - template *tag.Template -func (_e *TagTemplateService_Expecter) CreateTemplate(ctx interface{}, ns interface{}, template interface{}) *TagTemplateService_CreateTemplate_Call { - return &TagTemplateService_CreateTemplate_Call{Call: _e.mock.On("CreateTemplate", ctx, ns, template)} -} - -func (_c *TagTemplateService_CreateTemplate_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, template *tag.Template)) *TagTemplateService_CreateTemplate_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(*tag.Template)) - }) - return _c -} - -func (_c *TagTemplateService_CreateTemplate_Call) Return(_a0 error) *TagTemplateService_CreateTemplate_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagTemplateService_CreateTemplate_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, *tag.Template) error) *TagTemplateService_CreateTemplate_Call { - _c.Call.Return(run) - return _c -} - -// DeleteTemplate provides a mock function with given fields: ctx, urn -func (_m *TagTemplateService) DeleteTemplate(ctx context.Context, urn string) error { - ret := _m.Called(ctx, urn) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { - r0 = rf(ctx, urn) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagTemplateService_DeleteTemplate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteTemplate' -type TagTemplateService_DeleteTemplate_Call struct { - *mock.Call -} - -// DeleteTemplate is a helper method to define mock.On call -// - ctx context.Context -// - urn string -func (_e *TagTemplateService_Expecter) DeleteTemplate(ctx interface{}, urn interface{}) *TagTemplateService_DeleteTemplate_Call { - return &TagTemplateService_DeleteTemplate_Call{Call: _e.mock.On("DeleteTemplate", ctx, urn)} -} - -func (_c *TagTemplateService_DeleteTemplate_Call) Run(run func(ctx context.Context, urn string)) *TagTemplateService_DeleteTemplate_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *TagTemplateService_DeleteTemplate_Call) Return(_a0 error) *TagTemplateService_DeleteTemplate_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagTemplateService_DeleteTemplate_Call) RunAndReturn(run func(context.Context, string) error) *TagTemplateService_DeleteTemplate_Call { - _c.Call.Return(run) - return _c -} - -// GetTemplate provides a mock function with given fields: ctx, urn -func (_m *TagTemplateService) GetTemplate(ctx context.Context, urn string) (tag.Template, error) { - ret := _m.Called(ctx, urn) - - var r0 tag.Template - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (tag.Template, error)); ok { - return rf(ctx, urn) - } - if rf, ok := ret.Get(0).(func(context.Context, string) tag.Template); ok { - r0 = rf(ctx, urn) - } else { - r0 = ret.Get(0).(tag.Template) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, urn) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TagTemplateService_GetTemplate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTemplate' -type TagTemplateService_GetTemplate_Call struct { - *mock.Call -} - -// GetTemplate is a helper method to define mock.On call -// - ctx context.Context -// - urn string -func (_e *TagTemplateService_Expecter) GetTemplate(ctx interface{}, urn interface{}) *TagTemplateService_GetTemplate_Call { - return &TagTemplateService_GetTemplate_Call{Call: _e.mock.On("GetTemplate", ctx, urn)} -} - -func (_c *TagTemplateService_GetTemplate_Call) Run(run func(ctx context.Context, urn string)) *TagTemplateService_GetTemplate_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *TagTemplateService_GetTemplate_Call) Return(_a0 tag.Template, _a1 error) *TagTemplateService_GetTemplate_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *TagTemplateService_GetTemplate_Call) RunAndReturn(run func(context.Context, string) (tag.Template, error)) *TagTemplateService_GetTemplate_Call { - _c.Call.Return(run) - return _c -} - -// GetTemplates provides a mock function with given fields: ctx, templateURN -func (_m *TagTemplateService) GetTemplates(ctx context.Context, templateURN string) ([]tag.Template, error) { - ret := _m.Called(ctx, templateURN) - - var r0 []tag.Template - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) ([]tag.Template, error)); ok { - return rf(ctx, templateURN) - } - if rf, ok := ret.Get(0).(func(context.Context, string) []tag.Template); ok { - r0 = rf(ctx, templateURN) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]tag.Template) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, templateURN) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// TagTemplateService_GetTemplates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTemplates' -type TagTemplateService_GetTemplates_Call struct { - *mock.Call -} - -// GetTemplates is a helper method to define mock.On call -// - ctx context.Context -// - templateURN string -func (_e *TagTemplateService_Expecter) GetTemplates(ctx interface{}, templateURN interface{}) *TagTemplateService_GetTemplates_Call { - return &TagTemplateService_GetTemplates_Call{Call: _e.mock.On("GetTemplates", ctx, templateURN)} -} - -func (_c *TagTemplateService_GetTemplates_Call) Run(run func(ctx context.Context, templateURN string)) *TagTemplateService_GetTemplates_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *TagTemplateService_GetTemplates_Call) Return(_a0 []tag.Template, _a1 error) *TagTemplateService_GetTemplates_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *TagTemplateService_GetTemplates_Call) RunAndReturn(run func(context.Context, string) ([]tag.Template, error)) *TagTemplateService_GetTemplates_Call { - _c.Call.Return(run) - return _c -} - -// UpdateTemplate provides a mock function with given fields: ctx, ns, templateURN, template -func (_m *TagTemplateService) UpdateTemplate(ctx context.Context, ns *namespace.Namespace, templateURN string, template *tag.Template) error { - ret := _m.Called(ctx, ns, templateURN, template) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string, *tag.Template) error); ok { - r0 = rf(ctx, ns, templateURN, template) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagTemplateService_UpdateTemplate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateTemplate' -type TagTemplateService_UpdateTemplate_Call struct { - *mock.Call -} - -// UpdateTemplate is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - templateURN string -// - template *tag.Template -func (_e *TagTemplateService_Expecter) UpdateTemplate(ctx interface{}, ns interface{}, templateURN interface{}, template interface{}) *TagTemplateService_UpdateTemplate_Call { - return &TagTemplateService_UpdateTemplate_Call{Call: _e.mock.On("UpdateTemplate", ctx, ns, templateURN, template)} -} - -func (_c *TagTemplateService_UpdateTemplate_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, templateURN string, template *tag.Template)) *TagTemplateService_UpdateTemplate_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(string), args[3].(*tag.Template)) - }) - return _c -} - -func (_c *TagTemplateService_UpdateTemplate_Call) Return(_a0 error) *TagTemplateService_UpdateTemplate_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagTemplateService_UpdateTemplate_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, string, *tag.Template) error) *TagTemplateService_UpdateTemplate_Call { - _c.Call.Return(run) - return _c -} - -// Validate provides a mock function with given fields: template -func (_m *TagTemplateService) Validate(template tag.Template) error { - ret := _m.Called(template) - - var r0 error - if rf, ok := ret.Get(0).(func(tag.Template) error); ok { - r0 = rf(template) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// TagTemplateService_Validate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Validate' -type TagTemplateService_Validate_Call struct { - *mock.Call -} - -// Validate is a helper method to define mock.On call -// - template tag.Template -func (_e *TagTemplateService_Expecter) Validate(template interface{}) *TagTemplateService_Validate_Call { - return &TagTemplateService_Validate_Call{Call: _e.mock.On("Validate", template)} -} - -func (_c *TagTemplateService_Validate_Call) Run(run func(template tag.Template)) *TagTemplateService_Validate_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(tag.Template)) - }) - return _c -} - -func (_c *TagTemplateService_Validate_Call) Return(_a0 error) *TagTemplateService_Validate_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *TagTemplateService_Validate_Call) RunAndReturn(run func(tag.Template) error) *TagTemplateService_Validate_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTNewTagTemplateService interface { - mock.TestingT - Cleanup(func()) -} - -// NewTagTemplateService creates a new instance of TagTemplateService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTagTemplateService(t mockConstructorTestingTNewTagTemplateService) *TagTemplateService { - mock := &TagTemplateService{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/handler/namespace_test.go b/handler/namespace_test.go deleted file mode 100644 index 21ea9f20..00000000 --- a/handler/namespace_test.go +++ /dev/null @@ -1,349 +0,0 @@ -package handler - -import ( - "context" - "errors" - "testing" - - "connectrpc.com/connect" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/handler/mocks" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - - - "google.golang.org/protobuf/types/known/structpb" -) - -func TestHandler_ListNamespaces(t *testing.T) { - var ( - userUUID = uuid.NewString() - mockedNamespaces = []*namespace.Namespace{ - { - ID: uuid.New(), - Name: "tenant-1", - State: namespace.SharedState, - Metadata: nil, - }, - { - ID: uuid.New(), - Name: "tenant-2", - State: namespace.DedicatedState, - Metadata: nil, - }, - } - ) - type testCase struct { - name string - Request *compassv1beta1.ListNamespacesRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.ListNamespacesResponse) error - } - var testCases = []testCase{ - { - name: "list namespace items successfully", - Request: &compassv1beta1.ListNamespacesRequest{}, - ExpectStatus: 0, - Setup: func(ctx context.Context, nss *mocks.NamespaceService) { - nss.EXPECT().List(ctx).Return(mockedNamespaces, nil) - }, - PostCheck: func(resp *compassv1beta1.ListNamespacesResponse) error { - assert.Equal(t, len(resp.Namespaces), len(mockedNamespaces)) - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - - mockUserSvc := new(mocks.UserService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - handler := New(mockNamespaceSvc, nil, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.ListNamespaces(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestHandler_GetNamespaces(t *testing.T) { - var ( - userUUID = uuid.NewString() - mockedNamespaces = []*namespace.Namespace{ - { - ID: uuid.New(), - Name: "tenant-1", - State: namespace.SharedState, - Metadata: nil, - }, - } - ) - type testCase struct { - name string - Request *compassv1beta1.GetNamespaceRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.GetNamespaceResponse) error - } - var testCases = []testCase{ - { - name: "get namespace by its id if urn contains id", - Request: &compassv1beta1.GetNamespaceRequest{ - Urn: mockedNamespaces[0].ID.String(), - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, nss *mocks.NamespaceService) { - nss.EXPECT().GetByID(ctx, mockedNamespaces[0].ID).Return(mockedNamespaces[0], nil) - }, - PostCheck: func(resp *compassv1beta1.GetNamespaceResponse) error { - assert.Equal(t, resp.GetNamespace().Name, mockedNamespaces[0].Name) - assert.Equal(t, resp.GetNamespace().Id, mockedNamespaces[0].ID.String()) - return nil - }, - }, - { - name: "get namespace by its name if urn contains name", - Request: &compassv1beta1.GetNamespaceRequest{ - Urn: mockedNamespaces[0].Name, - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, nss *mocks.NamespaceService) { - nss.EXPECT().GetByName(ctx, mockedNamespaces[0].Name).Return(mockedNamespaces[0], nil) - }, - PostCheck: func(resp *compassv1beta1.GetNamespaceResponse) error { - assert.Equal(t, resp.GetNamespace().Name, mockedNamespaces[0].Name) - assert.Equal(t, resp.GetNamespace().Id, mockedNamespaces[0].ID.String()) - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - - mockUserSvc := new(mocks.UserService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - handler := New(mockNamespaceSvc, nil, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.GetNamespace(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestHandler_CreateNamespaces(t *testing.T) { - var ( - userUUID = uuid.NewString() - mockedNamespaces = []*namespace.Namespace{ - { - ID: uuid.New(), - Name: "tenant-1", - State: namespace.SharedState, - Metadata: map[string]interface{}{ - "key": "value data", - }, - }, - } - ) - mockedNamespace0Meta, err := structpb.NewStruct(mockedNamespaces[0].Metadata) - assert.NoError(t, err) - - type testCase struct { - name string - Request *compassv1beta1.CreateNamespaceRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.CreateNamespaceResponse) error - } - var testCases = []testCase{ - { - name: "create a namespace and return its id as response", - Request: &compassv1beta1.CreateNamespaceRequest{ - Name: mockedNamespaces[0].Name, - State: mockedNamespaces[0].State.String(), - Metadata: mockedNamespace0Meta, - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, nss *mocks.NamespaceService) { - nss.EXPECT().Create(ctx, mock.AnythingOfType("*namespace.Namespace")).Return(mockedNamespaces[0].ID.String(), nil) - }, - PostCheck: func(resp *compassv1beta1.CreateNamespaceResponse) error { - assert.NotNil(t, resp.Id) - return nil - }, - }, - { - name: "throw an error if namespace already exists", - Request: &compassv1beta1.CreateNamespaceRequest{ - Name: mockedNamespaces[0].Name, - State: mockedNamespaces[0].State.String(), - Metadata: mockedNamespace0Meta, - }, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, nss *mocks.NamespaceService) { - nss.EXPECT().Create(ctx, mock.AnythingOfType("*namespace.Namespace")).Return("", errors.New("already exists")) - }, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - - mockUserSvc := new(mocks.UserService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - handler := New(mockNamespaceSvc, nil, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.CreateNamespace(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestHandler_UpdateNamespaces(t *testing.T) { - var ( - userUUID = uuid.NewString() - mockedNamespaces = []*namespace.Namespace{ - { - ID: uuid.New(), - Name: "tenant-1", - State: namespace.SharedState, - Metadata: nil, - }, - } - ) - type testCase struct { - name string - Request *compassv1beta1.UpdateNamespaceRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.UpdateNamespaceResponse) error - } - var testCases = []testCase{ - { - name: "update an existing namespace state and metadata if urn is a uuid", - Request: &compassv1beta1.UpdateNamespaceRequest{ - Urn: mockedNamespaces[0].ID.String(), - State: mockedNamespaces[0].State.String(), - Metadata: nil, - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, nss *mocks.NamespaceService) { - nss.EXPECT().Update(ctx, &namespace.Namespace{ - ID: mockedNamespaces[0].ID, - Name: "", - State: mockedNamespaces[0].State, - Metadata: nil, - }).Return(nil) - }, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - - mockUserSvc := new(mocks.UserService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - handler := New(mockNamespaceSvc, nil, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.UpdateNamespace(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} diff --git a/handler/option.go b/handler/option.go deleted file mode 100644 index ec7789ad..00000000 --- a/handler/option.go +++ /dev/null @@ -1,3 +0,0 @@ -package handler - -type Option func(*Handler) diff --git a/handler/search.go b/handler/search.go deleted file mode 100644 index ce050521..00000000 --- a/handler/search.go +++ /dev/null @@ -1,147 +0,0 @@ -package handler - -import ( - "context" - "fmt" - "strings" - - "connectrpc.com/connect" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" -) - -func (server *Handler) SearchAssets(ctx context.Context, req *connect.Request[compassv1beta1.SearchAssetsRequest]) (*connect.Response[compassv1beta1.SearchAssetsResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - cfg := asset.SearchConfig{ - Text: strings.TrimSpace(req.Msg.GetText()), - MaxResults: int(req.Msg.GetSize()), - Offset: int(req.Msg.GetOffset()), - Filters: filterConfigFromValues(req.Msg.GetFilter()), - RankBy: req.Msg.GetRankby(), - Queries: req.Msg.GetQuery(), - IncludeFields: req.Msg.GetIncludeFields(), - Flags: getSearchFlagsFromProto(req.Msg.GetFlags()), - Namespace: ns, - } - - results, err := server.assetService.SearchAssets(ctx, cfg) - if err != nil { - return nil, internalServerError(ctx, "error searching asset", err) - } - - assetsPB := []*compassv1beta1.Asset{} - for _, sr := range results { - assetPB, err := assetToProto(sr.ToAsset(), false) - if err != nil { - return nil, internalServerError(ctx, "error converting assets to proto", err) - } - assetsPB = append(assetsPB, assetPB) - } - - return connect.NewResponse(&compassv1beta1.SearchAssetsResponse{ - Data: assetsPB, - }), nil -} - -func (server *Handler) SuggestAssets(ctx context.Context, req *connect.Request[compassv1beta1.SuggestAssetsRequest]) (*connect.Response[compassv1beta1.SuggestAssetsResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - text := strings.TrimSpace(req.Msg.GetText()) - if text == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("'text' must be specified")) - } - - cfg := asset.SearchConfig{ - Text: text, - Namespace: ns, - } - suggestions, err := server.assetService.SuggestAssets(ctx, cfg) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.SuggestAssetsResponse{ - Data: suggestions, - }), nil -} - -func (server *Handler) GroupAssets(ctx context.Context, req *connect.Request[compassv1beta1.GroupAssetsRequest]) (*connect.Response[compassv1beta1.GroupAssetsResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - if len(req.Msg.GetGroupby()) == 0 { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("groupby must be specified")) - } - - cfg := asset.GroupConfig{ - GroupBy: req.Msg.GetGroupby(), - Filters: filterConfigFromValues(req.Msg.GetFilter()), - IncludeFields: req.Msg.GetIncludeFields(), - Size: int(req.Msg.GetSize()), - Namespace: ns, - } - - results, err := server.assetService.GroupAssets(ctx, cfg) - if err != nil { - return nil, internalServerError(ctx, "error grouping assets", err) - } - - var groups []*compassv1beta1.AssetGroup - for _, gr := range results { - var fields []*compassv1beta1.GroupField - for _, f := range gr.Fields { - fields = append(fields, &compassv1beta1.GroupField{ - GroupKey: f.Key, - GroupValue: f.Value, - }) - } - var assets []*compassv1beta1.Asset - for _, a := range gr.Assets { - ap, err := assetToProto(a, false) - if err != nil { - return nil, internalServerError(ctx, "error converting asset to proto", err) - } - assets = append(assets, ap) - } - groups = append(groups, &compassv1beta1.AssetGroup{ - GroupFields: fields, - Assets: assets, - }) - } - - return connect.NewResponse(&compassv1beta1.GroupAssetsResponse{ - AssetGroups: groups, - }), nil -} - -func getSearchFlagsFromProto(flags *compassv1beta1.SearchFlags) asset.SearchFlags { - if flags == nil { - return asset.SearchFlags{} - } - return asset.SearchFlags{ - DisableFuzzy: flags.GetDisableFuzzy(), - EnableHighlight: flags.GetEnableHighlight(), - IsColumnSearch: flags.GetIsColumnSearch(), - } -} - -func filterConfigFromValues(fltMap map[string]string) map[string][]string { - var filter = make(map[string][]string) - for key, value := range fltMap { - var filterValues []string - filterValues = append(filterValues, strings.Split(value, ",")...) - - filter[key] = filterValues - } - return filter -} diff --git a/handler/search_test.go b/handler/search_test.go deleted file mode 100644 index 61b17de5..00000000 --- a/handler/search_test.go +++ /dev/null @@ -1,373 +0,0 @@ -package handler - -import ( - "context" - "fmt" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/middleware" - "testing" - - "connectrpc.com/connect" - "github.com/google/go-cmp/cmp" - "github.com/google/uuid" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/handler/mocks" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "github.com/stretchr/testify/mock" - - - "google.golang.org/protobuf/testing/protocmp" -) - -func TestSearch(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "base-test", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.SearchAssetsRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.AssetService, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.SearchAssetsResponse) error - } - - var testCases = []testCase{ - { - Description: "should allow empty text search", - ExpectStatus: 0, - Request: &compassv1beta1.SearchAssetsRequest{}, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - cfg := asset.SearchConfig{ - Filters: make(map[string][]string), - Queries: map[string]string(nil), - Namespace: ns, - } - as.EXPECT().SearchAssets(ctx, cfg).Return([]asset.SearchResult{}, nil) - }, - }, - { - Description: "should report internal server if asset searcher fails", - Request: &compassv1beta1.SearchAssetsRequest{ - Text: "test", - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - err := fmt.Errorf("service unavailable") - as.EXPECT().SearchAssets(ctx, mock.AnythingOfType("asset.SearchConfig")). - Return([]asset.SearchResult{}, err) - }, - ExpectStatus: connect.CodeInternal, - }, - { - Description: "should pass filter to search config format", - Request: &compassv1beta1.SearchAssetsRequest{ - Text: "resource", - Filter: map[string]string{ - "data.landscape": "th", - "type": "topic", - "service": "kafka,rabbitmq", - }, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - cfg := asset.SearchConfig{ - Text: "resource", - Filters: map[string][]string{ - "type": {"topic"}, - "service": {"kafka", "rabbitmq"}, - "data.landscape": {"th"}, - }, - Namespace: ns, - } - - as.EXPECT().SearchAssets(ctx, cfg).Return([]asset.SearchResult{}, nil) - }, - }, - { - Description: "should pass queries to search config format", - Request: &compassv1beta1.SearchAssetsRequest{ - Text: "resource", - Filter: map[string]string{ - "data.landscape": "th", - "type": "topic", - "service": "kafka,rabbitmq", - }, - Query: map[string]string{ - "data.columns.name": "timestamp", - "owners.email": "john.doe@email.com", - }, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - cfg := asset.SearchConfig{ - Text: "resource", - Filters: map[string][]string{ - "type": {"topic"}, - "service": {"kafka", "rabbitmq"}, - "data.landscape": {"th"}, - }, - Queries: map[string]string{ - "data.columns.name": "timestamp", - "owners.email": "john.doe@email.com", - }, - Namespace: ns, - } - - as.EXPECT().SearchAssets(ctx, cfg).Return([]asset.SearchResult{}, nil) - }, - }, - { - Description: "should return the matched documents", - Request: &compassv1beta1.SearchAssetsRequest{ - Text: "test", - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - cfg := asset.SearchConfig{ - Text: "test", - Filters: make(map[string][]string), - Queries: map[string]string(nil), - Namespace: ns, - } - response := []asset.SearchResult{ - { - Type: "test", - ID: "test-resource", - Description: "some description", - Service: "test-service", - Labels: map[string]string{ - "entity": "raystack", - "landscape": "id", - }, - }, - } - as.EXPECT().SearchAssets(ctx, cfg).Return(response, nil) - }, - PostCheck: func(resp *compassv1beta1.SearchAssetsResponse) error { - expected := &compassv1beta1.SearchAssetsResponse{ - Data: []*compassv1beta1.Asset{ - { - Id: "test-resource", - Description: "some description", - Service: "test-service", - Type: "test", - Labels: map[string]string{ - "entity": "raystack", - "landscape": "id", - }, - }, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - { - Description: "should return the requested number of assets", - Request: &compassv1beta1.SearchAssetsRequest{ - Text: "resource", - Size: 10, - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - cfg := asset.SearchConfig{ - Text: "resource", - MaxResults: 10, - Filters: make(map[string][]string), - Queries: map[string]string(nil), - Namespace: ns, - } - - var results []asset.SearchResult - for i := 0; i < cfg.MaxResults; i++ { - urn := fmt.Sprintf("resource-%d", i+1) - name := fmt.Sprintf("resource %d", i+1) - r := asset.SearchResult{ - ID: urn, - Type: "table", - Description: name, - Service: "kafka", - Labels: map[string]string{ - "landscape": "id", - "entity": "raystack", - }, - } - - results = append(results, r) - } - - as.EXPECT().SearchAssets(ctx, cfg).Return(results, nil) - }, - PostCheck: func(resp *compassv1beta1.SearchAssetsResponse) error { - expectedSize := 10 - actualSize := len(resp.Data) - if expectedSize != actualSize { - return fmt.Errorf("expected search request to return %d results, returned %d results instead", expectedSize, actualSize) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockSvc := new(mocks.AssetService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockSvc, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, mockSvc, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.SearchAssets(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestSuggest(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "base-test", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.SuggestAssetsRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.AssetService, *mocks.NamespaceService) - PostCheck func(resp *compassv1beta1.SuggestAssetsResponse) error - } - - var testCases = []testCase{ - { - Description: "should return invalid arguments if 'text' parameter is empty or missing", - ExpectStatus: connect.CodeInvalidArgument, - Request: &compassv1beta1.SuggestAssetsRequest{}, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - }, - }, - { - Description: "should report internal server error if searcher fails", - Request: &compassv1beta1.SuggestAssetsRequest{ - Text: "test", - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - cfg := asset.SearchConfig{ - Text: "test", - Namespace: ns, - } - as.EXPECT().SuggestAssets(ctx, cfg).Return([]string{}, fmt.Errorf("service unavailable")) - }, - ExpectStatus: connect.CodeInternal, - }, - { - Description: "should return suggestions", - Request: &compassv1beta1.SuggestAssetsRequest{ - Text: "test", - }, - Setup: func(ctx context.Context, as *mocks.AssetService, nss *mocks.NamespaceService) { - cfg := asset.SearchConfig{ - Text: "test", - Namespace: ns, - } - response := []string{ - "test", - "test2", - "t est", - "t_est", - } - - as.EXPECT().SuggestAssets(ctx, cfg).Return(response, nil) - }, - PostCheck: func(resp *compassv1beta1.SuggestAssetsResponse) error { - expected := &compassv1beta1.SuggestAssetsResponse{ - Data: []string{ - "test", - "test2", - "t est", - "t_est", - }, - } - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockSvc := new(mocks.AssetService) - mockNamespaceSvc := new(mocks.NamespaceService) - if tc.Setup != nil { - tc.Setup(ctx, mockSvc, mockNamespaceSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockSvc.AssertExpectations(t) - defer mockNamespaceSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, mockSvc, nil, nil, nil, nil, mockUserSvc) - - got, err := handler.SuggestAssets(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} diff --git a/handler/star.go b/handler/star.go index 273d8ce1..b0366dee 100644 --- a/handler/star.go +++ b/handler/star.go @@ -1,19 +1,19 @@ package handler -//go:generate mockery --name=StarService -r --case underscore --with-expecter --structname StarService --filename star_service.go --output=./mocks import ( "context" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/asset" + "github.com/raystack/compass/core/entity" + "github.com/raystack/compass/core/namespace" "github.com/raystack/compass/core/star" "github.com/raystack/compass/core/user" ) +// StarService defines star operations for the handler. type StarService interface { - GetStarredAssetsByUserID(context.Context, star.Filter, string) ([]asset.Asset, error) - GetStarredAssetByUserID(context.Context, string, string) (asset.Asset, error) - GetStargazers(context.Context, star.Filter, string) ([]user.User, error) - Stars(context.Context, *namespace.Namespace, string, string) (string, error) - Unstars(context.Context, string, string) error + GetStarredEntitiesByUserID(ctx context.Context, flt star.Filter, userID string) ([]entity.Entity, error) + GetStarredEntityByUserID(ctx context.Context, userID string, entityID string) (entity.Entity, error) + Stars(ctx context.Context, ns *namespace.Namespace, userID string, entityID string) (string, error) + Unstars(ctx context.Context, userID string, entityID string) error + GetStargazers(ctx context.Context, flt star.Filter, entityID string) ([]user.User, error) } diff --git a/handler/tag.go b/handler/tag.go deleted file mode 100644 index 04f1bb85..00000000 --- a/handler/tag.go +++ /dev/null @@ -1,350 +0,0 @@ -package handler - -//go:generate mockery --name=TagService -r --case underscore --with-expecter --structname TagService --filename tag_service.go --output=./mocks -import ( - "context" - "errors" - "fmt" - "time" - - "connectrpc.com/connect" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/tag" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "google.golang.org/protobuf/types/known/structpb" - "google.golang.org/protobuf/types/known/timestamppb" -) - -var ( - errEmptyAssetID = errors.New("asset id is empty") - errNilTagService = errors.New("tag service is nil") - errEmptyTemplateURN = errors.New("template urn is empty") -) - -type TagService interface { - Validate(tag *tag.Tag) error - CreateTag(ctx context.Context, ns *namespace.Namespace, tag *tag.Tag) error - GetTagsByAssetID(ctx context.Context, assetID string) ([]tag.Tag, error) - FindTagByAssetIDAndTemplateURN(ctx context.Context, assetID, templateURN string) (tag.Tag, error) - DeleteTag(ctx context.Context, assetID, templateURN string) error - UpdateTag(ctx context.Context, tag *tag.Tag) error -} - -// GetTagByAssetAndTemplate handles get tag by asset requests -func (server *Handler) GetTagByAssetAndTemplate(ctx context.Context, req *connect.Request[compassv1beta1.GetTagByAssetAndTemplateRequest]) (*connect.Response[compassv1beta1.GetTagByAssetAndTemplateResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - if server.tagService == nil { - return nil, internalServerError(ctx, "nil tag service", errNilTagService) - } - - if req.Msg.GetAssetId() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, errEmptyAssetID) - } - if req.Msg.GetTemplateUrn() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, errEmptyTemplateURN) - } - - tg, err := server.tagService.FindTagByAssetIDAndTemplateURN(ctx, req.Msg.GetAssetId(), req.Msg.GetTemplateUrn()) - if err != nil { - if errors.As(err, new(tag.NotFoundError)) || errors.As(err, new(tag.TemplateNotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - return nil, internalServerError(ctx, "error finding a tag with asset and template", err) - } - - tagPB, err := tagToProto(tg) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.GetTagByAssetAndTemplateResponse{ - Data: tagPB, - }), nil -} - -// CreateTagAsset handles tag creation requests -func (server *Handler) CreateTagAsset(ctx context.Context, req *connect.Request[compassv1beta1.CreateTagAssetRequest]) (*connect.Response[compassv1beta1.CreateTagAssetResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - if server.tagService == nil { - return nil, internalServerError(ctx, "nil tag service", errNilTagService) - } - - if req.Msg.GetAssetId() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, errEmptyAssetID) - } - if req.Msg.GetTemplateUrn() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, errEmptyTemplateURN) - } - if len(req.Msg.GetTagValues()) == 0 { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("empty tag values")) - } - - var tagValues []tag.TagValue - for _, tvPB := range req.Msg.GetTagValues() { - tagValues = append(tagValues, tagValueFromProto(tvPB)) - } - - tagDomain := tag.Tag{ - AssetID: req.Msg.GetAssetId(), - TemplateURN: req.Msg.GetTemplateUrn(), - TagValues: tagValues, - TemplateDisplayName: req.Msg.GetTemplateDisplayName(), - TemplateDescription: req.Msg.GetTemplateDescription(), - } - - err := server.tagService.CreateTag(ctx, ns, &tagDomain) - if errors.As(err, new(tag.DuplicateError)) { - return nil, connect.NewError(connect.CodeAlreadyExists, err) - } - if errors.As(err, new(tag.TemplateNotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - if errors.As(err, new(tag.ValidationError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if err != nil { - return nil, internalServerError(ctx, "error creating tag", err) - } - - tagPB, err := tagToProto(tagDomain) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.CreateTagAssetResponse{ - Data: tagPB, - }), nil -} - -// UpdateTagAsset handles tag update requests -func (server *Handler) UpdateTagAsset(ctx context.Context, req *connect.Request[compassv1beta1.UpdateTagAssetRequest]) (*connect.Response[compassv1beta1.UpdateTagAssetResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - if server.tagService == nil { - return nil, internalServerError(ctx, "nil tag service", errNilTagService) - } - - if req.Msg.GetAssetId() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, errEmptyAssetID) - } - if req.Msg.GetTemplateUrn() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, errEmptyTemplateURN) - } - - if len(req.Msg.GetTagValues()) == 0 { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("empty tag values")) - } - - var tagValues []tag.TagValue - for _, tvPB := range req.Msg.GetTagValues() { - tagValues = append(tagValues, tagValueFromProto(tvPB)) - } - - tagDomain := tag.Tag{ - AssetID: req.Msg.GetAssetId(), - TemplateURN: req.Msg.GetTemplateUrn(), - TagValues: tagValues, - TemplateDisplayName: req.Msg.GetTemplateDisplayName(), - TemplateDescription: req.Msg.GetTemplateDescription(), - } - - err := server.tagService.UpdateTag(ctx, &tagDomain) - if err != nil { - if errors.As(err, new(tag.NotFoundError)) || errors.As(err, new(tag.TemplateNotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - if errors.As(err, new(tag.ValidationError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - return nil, internalServerError(ctx, "error updating an asset's tag", err) - } - - tagPB, err := tagToProto(tagDomain) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.UpdateTagAssetResponse{ - Data: tagPB, - }), nil -} - -// DeleteTagAsset handles delete tag by asset and template requests -func (server *Handler) DeleteTagAsset(ctx context.Context, req *connect.Request[compassv1beta1.DeleteTagAssetRequest]) (*connect.Response[compassv1beta1.DeleteTagAssetResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - if server.tagService == nil { - return nil, internalServerError(ctx, "nil tag service", errNilTagService) - } - - if req.Msg.GetAssetId() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, errEmptyAssetID) - } - if req.Msg.GetTemplateUrn() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, errEmptyTemplateURN) - } - - err := server.tagService.DeleteTag(ctx, req.Msg.GetAssetId(), req.Msg.GetTemplateUrn()) - if err != nil { - if errors.As(err, new(tag.TemplateNotFoundError)) || errors.As(err, new(tag.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - return nil, internalServerError(ctx, "error deleting a tag", err) - } - - return connect.NewResponse(&compassv1beta1.DeleteTagAssetResponse{}), nil -} - -// GetAllTagsByAsset handles get all tags by asset requests -func (server *Handler) GetAllTagsByAsset(ctx context.Context, req *connect.Request[compassv1beta1.GetAllTagsByAssetRequest]) (*connect.Response[compassv1beta1.GetAllTagsByAssetResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - if server.tagService == nil { - return nil, internalServerError(ctx, "nil tag service", errNilTagService) - } - - if req.Msg.GetAssetId() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, errEmptyAssetID) - } - - tags, err := server.tagService.GetTagsByAssetID(ctx, req.Msg.GetAssetId()) - if err != nil { - return nil, internalServerError(ctx, "error getting asset tags", err) - } - - var tagsPB []*compassv1beta1.Tag - for _, tg := range tags { - tgPB, err := tagToProto(tg) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - tagsPB = append(tagsPB, tgPB) - } - - return connect.NewResponse(&compassv1beta1.GetAllTagsByAssetResponse{ - Data: tagsPB, - }), nil -} - -// tagToProto convert domain to protobuf -func tagToProto(t tag.Tag) (*compassv1beta1.Tag, error) { - var tagValuesPB []*compassv1beta1.TagValue - for _, tv := range t.TagValues { - tvPB, err := tagValueToProto(tv) - if err != nil { - return nil, err - } - tagValuesPB = append(tagValuesPB, tvPB) - } - - return &compassv1beta1.Tag{ - AssetId: t.AssetID, - TemplateUrn: t.TemplateURN, - TagValues: tagValuesPB, - TemplateDisplayName: t.TemplateDisplayName, - TemplateDescription: t.TemplateDescription, - }, nil -} - -// tagFromProto converts proto to tag.Tag -func tagFromProto(pb *compassv1beta1.Tag) tag.Tag { - var tagValues []tag.TagValue - if pb.GetTagValues() != nil { - for _, tvPB := range pb.GetTagValues() { - tv := tagValueFromProto(tvPB) - tagValues = append(tagValues, tv) - } - } - - return tag.Tag{ - AssetID: pb.GetAssetId(), - TemplateURN: pb.GetTemplateUrn(), - TagValues: tagValues, - TemplateDisplayName: pb.GetTemplateDisplayName(), - TemplateDescription: pb.GetTemplateDescription(), - } -} - -// tagValueToProto convert domain to protobuf -func tagValueToProto(tv tag.TagValue) (*compassv1beta1.TagValue, error) { - var err error - var createdAtPB *timestamppb.Timestamp - if !tv.CreatedAt.IsZero() { - createdAtPB = timestamppb.New(tv.CreatedAt) - } - - var updatedAtPB *timestamppb.Timestamp - if !tv.UpdatedAt.IsZero() { - updatedAtPB = timestamppb.New(tv.UpdatedAt) - } - - var fieldValuePB *structpb.Value - if tv.FieldValue != nil { - fieldValuePB, err = structpb.NewValue(tv.FieldValue) - if err != nil { - return nil, err - } - } - - return &compassv1beta1.TagValue{ - FieldId: uint32(tv.FieldID), - FieldValue: fieldValuePB, - FieldUrn: tv.FieldURN, - FieldDisplayName: tv.FieldDisplayName, - FieldDescription: tv.FieldDescription, - FieldDataType: tv.FieldDataType, - FieldOptions: tv.FieldOptions, - FieldRequired: tv.FieldRequired, - CreatedAt: createdAtPB, - UpdatedAt: updatedAtPB, - }, nil -} - -// tagValueFromProto converts proto to tag.TagValue -func tagValueFromProto(pb *compassv1beta1.TagValue) tag.TagValue { - var createdAt time.Time - if pb.GetCreatedAt() != nil { - createdAt = pb.GetCreatedAt().AsTime() - } - - var updatedAt time.Time - if pb.GetUpdatedAt() != nil { - updatedAt = pb.GetUpdatedAt().AsTime() - } - - var fieldValue interface{} - if pb.GetFieldValue() != nil { - fieldValue = pb.GetFieldValue().AsInterface() - } - - return tag.TagValue{ - FieldID: uint(pb.GetFieldId()), - FieldValue: fieldValue, - FieldURN: pb.GetFieldUrn(), - FieldDisplayName: pb.GetFieldDisplayName(), - FieldDescription: pb.GetFieldDescription(), - FieldDataType: pb.GetFieldDataType(), - FieldOptions: pb.GetFieldOptions(), - FieldRequired: pb.GetFieldRequired(), - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} diff --git a/handler/tag_template.go b/handler/tag_template.go deleted file mode 100644 index 8e071d82..00000000 --- a/handler/tag_template.go +++ /dev/null @@ -1,276 +0,0 @@ -package handler - -//go:generate mockery --name=TagTemplateService -r --case underscore --with-expecter --structname TagTemplateService --filename tag_template_service.go --output=./mocks -import ( - "context" - "errors" - "fmt" - "time" - - "connectrpc.com/connect" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/tag" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "google.golang.org/protobuf/types/known/timestamppb" -) - -type TagTemplateService interface { - Validate(template tag.Template) error - CreateTemplate(ctx context.Context, ns *namespace.Namespace, template *tag.Template) error - GetTemplates(ctx context.Context, templateURN string) ([]tag.Template, error) - UpdateTemplate(ctx context.Context, ns *namespace.Namespace, templateURN string, template *tag.Template) error - GetTemplate(ctx context.Context, urn string) (tag.Template, error) - DeleteTemplate(ctx context.Context, urn string) error -} - -// GetAllTagTemplates handles template read requests -func (server *Handler) GetAllTagTemplates(ctx context.Context, req *connect.Request[compassv1beta1.GetAllTagTemplatesRequest]) (*connect.Response[compassv1beta1.GetAllTagTemplatesResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - listOfDomainTemplate, err := server.tagTemplateService.GetTemplates(ctx, req.Msg.GetUrn()) - if err != nil { - return nil, internalServerError(ctx, "error finding templates", err) - } - - var templatesPB []*compassv1beta1.TagTemplate - for _, template := range listOfDomainTemplate { - templatesPB = append(templatesPB, tagTemplateToProto(template)) - } - - return connect.NewResponse(&compassv1beta1.GetAllTagTemplatesResponse{ - Data: templatesPB, - }), nil -} - -// CreateTagTemplate handles template creation requests -func (server *Handler) CreateTagTemplate(ctx context.Context, req *connect.Request[compassv1beta1.CreateTagTemplateRequest]) (*connect.Response[compassv1beta1.CreateTagTemplateResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - if req.Msg.GetUrn() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("empty urn")) - } - if req.Msg.GetDisplayName() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("empty display name")) - } - if req.Msg.GetDescription() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("empty description")) - } - if req.Msg.GetFields() == nil { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("empty fields")) - } - - var templateFields []tag.Field - for _, fPB := range req.Msg.GetFields() { - templateFields = append(templateFields, tagTemplateFieldFromProto(fPB)) - } - - template := tag.Template{ - URN: req.Msg.GetUrn(), - DisplayName: req.Msg.GetDisplayName(), - Description: req.Msg.GetDescription(), - Fields: templateFields, - } - err := server.tagTemplateService.CreateTemplate(ctx, ns, &template) - if errors.As(err, new(tag.DuplicateTemplateError)) { - return nil, connect.NewError(connect.CodeAlreadyExists, err) - } - if err != nil { - return nil, internalServerError(ctx, "error creating tag template", err) - } - - return connect.NewResponse(&compassv1beta1.CreateTagTemplateResponse{ - Data: tagTemplateToProto(template), - }), nil -} - -// GetTagTemplate handles template read requests based on URN -func (server *Handler) GetTagTemplate(ctx context.Context, req *connect.Request[compassv1beta1.GetTagTemplateRequest]) (*connect.Response[compassv1beta1.GetTagTemplateResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - domainTemplate, err := server.tagTemplateService.GetTemplate(ctx, req.Msg.GetTemplateUrn()) - if err != nil { - if errors.As(err, new(tag.TemplateNotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - return nil, internalServerError(ctx, "error finding a template", err) - } - - return connect.NewResponse(&compassv1beta1.GetTagTemplateResponse{ - Data: tagTemplateToProto(domainTemplate), - }), nil -} - -func (server *Handler) UpdateTagTemplate(ctx context.Context, req *connect.Request[compassv1beta1.UpdateTagTemplateRequest]) (*connect.Response[compassv1beta1.UpdateTagTemplateResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - if req.Msg.GetDisplayName() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("empty display name")) - } - if req.Msg.GetDescription() == "" { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("empty description")) - } - if req.Msg.GetFields() == nil { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("empty fields")) - } - - var templateFields []tag.Field - for _, fPB := range req.Msg.GetFields() { - templateFields = append(templateFields, tagTemplateFieldFromProto(fPB)) - } - - template := tag.Template{ - URN: req.Msg.GetTemplateUrn(), - DisplayName: req.Msg.GetDisplayName(), - Description: req.Msg.GetDescription(), - Fields: templateFields, - } - if err := server.tagTemplateService.UpdateTemplate(ctx, ns, req.Msg.TemplateUrn, &template); err != nil { - if errors.As(err, new(tag.TemplateNotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - if errors.As(err, new(tag.ValidationError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - return nil, internalServerError(ctx, "error updating template", err) - } - - return connect.NewResponse(&compassv1beta1.UpdateTagTemplateResponse{ - Data: tagTemplateToProto(template), - }), nil -} - -// DeleteTagTemplate handles template delete request based on URN -func (server *Handler) DeleteTagTemplate(ctx context.Context, req *connect.Request[compassv1beta1.DeleteTagTemplateRequest]) (*connect.Response[compassv1beta1.DeleteTagTemplateResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - err := server.tagTemplateService.DeleteTemplate(ctx, req.Msg.GetTemplateUrn()) - if errors.As(err, new(tag.TemplateNotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } - if err != nil { - return nil, internalServerError(ctx, "error deleting a template", err) - } - return connect.NewResponse(&compassv1beta1.DeleteTagTemplateResponse{}), nil -} - -// tagTemplateToProto convert domain to protobuf -func tagTemplateToProto(t tag.Template) *compassv1beta1.TagTemplate { - var templateFieldsPB []*compassv1beta1.TagTemplateField - for _, tf := range t.Fields { - templateFieldsPB = append(templateFieldsPB, tagTemplateFieldToProto(tf)) - } - - var createdAtPB *timestamppb.Timestamp - if !t.CreatedAt.IsZero() { - createdAtPB = timestamppb.New(t.CreatedAt) - } - - var updatedAtPB *timestamppb.Timestamp - if !t.UpdatedAt.IsZero() { - updatedAtPB = timestamppb.New(t.UpdatedAt) - } - - return &compassv1beta1.TagTemplate{ - Urn: t.URN, - DisplayName: t.DisplayName, - Description: t.Description, - Fields: templateFieldsPB, - CreatedAt: createdAtPB, - UpdatedAt: updatedAtPB, - } -} - -// tagTemplateFromProto converts proto to tag.Template -func tagTemplateFromProto(pb *compassv1beta1.TagTemplate) tag.Template { - var createdAt time.Time - if pb.GetCreatedAt() != nil { - createdAt = pb.GetCreatedAt().AsTime() - } - - var updatedAt time.Time - if pb.GetUpdatedAt() != nil { - updatedAt = pb.GetUpdatedAt().AsTime() - } - - var fields []tag.Field - if pb.GetFields() != nil { - for _, tfPB := range pb.GetFields() { - fields = append(fields, tagTemplateFieldFromProto(tfPB)) - } - } - - return tag.Template{ - URN: pb.GetUrn(), - DisplayName: pb.GetDisplayName(), - Description: pb.GetDescription(), - Fields: fields, - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} - -// tagTemplateFieldToProto convert domain to protobuf -func tagTemplateFieldToProto(f tag.Field) *compassv1beta1.TagTemplateField { - var createdAtPB *timestamppb.Timestamp - if !f.CreatedAt.IsZero() { - createdAtPB = timestamppb.New(f.CreatedAt) - } - - var updatedAtPB *timestamppb.Timestamp - if !f.UpdatedAt.IsZero() { - updatedAtPB = timestamppb.New(f.UpdatedAt) - } - - return &compassv1beta1.TagTemplateField{ - Id: uint32(f.ID), - Urn: f.URN, - DisplayName: f.DisplayName, - Description: f.Description, - DataType: f.DataType, - Options: f.Options, - Required: f.Required, - CreatedAt: createdAtPB, - UpdatedAt: updatedAtPB, - } -} - -// tagTemplateFieldFromProto converts proto to tag.Field -func tagTemplateFieldFromProto(pb *compassv1beta1.TagTemplateField) tag.Field { - var createdAt time.Time - if pb.GetCreatedAt() != nil { - createdAt = pb.GetCreatedAt().AsTime() - } - - var updatedAt time.Time - if pb.GetUpdatedAt() != nil { - updatedAt = pb.GetUpdatedAt().AsTime() - } - - return tag.Field{ - ID: uint(pb.GetId()), - URN: pb.GetUrn(), - DisplayName: pb.GetDisplayName(), - Description: pb.GetDescription(), - DataType: pb.GetDataType(), - Options: pb.GetOptions(), - Required: pb.GetRequired(), - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} diff --git a/handler/tag_template_test.go b/handler/tag_template_test.go deleted file mode 100644 index 6cf63363..00000000 --- a/handler/tag_template_test.go +++ /dev/null @@ -1,698 +0,0 @@ -package handler - -import ( - "context" - "errors" - "fmt" - "reflect" - "testing" - "time" - - "connectrpc.com/connect" - "github.com/google/go-cmp/cmp" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/tag" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/handler/mocks" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - - - "google.golang.org/protobuf/testing/protocmp" - "google.golang.org/protobuf/types/known/timestamppb" -) - -var sampleTemplate = tag.Template{ - URN: "governance_policy", - DisplayName: "Governance Policy", - Description: "Template that is mandatory to be used.", - Fields: []tag.Field{ - { - ID: 1, - URN: "classification", - DisplayName: "classification", - Description: "The classification of this asset", - DataType: "enumerated", - Required: true, - Options: []string{"Public", "Restricted"}, - }, - { - ID: 2, - URN: "is_encrypted", - DisplayName: "Is Encrypted?", - Description: "Specify whether this asset is encrypted or not.", - DataType: "boolean", - Required: true, - }, - }, -} - -var sampleTemplatePB = &compassv1beta1.TagTemplate{ - Urn: sampleTemplate.URN, - DisplayName: sampleTemplate.DisplayName, - Description: sampleTemplate.Description, - Fields: []*compassv1beta1.TagTemplateField{ - { - Id: 1, - Urn: "classification", - DisplayName: "classification", - Description: "The classification of this asset", - DataType: "enumerated", - Required: true, - Options: []string{"Public", "Restricted"}, - }, - { - Id: 2, - Urn: "is_encrypted", - DisplayName: "Is Encrypted?", - Description: "Specify whether this asset is encrypted or not.", - DataType: "boolean", - Required: true, - }, - }, -} - -func TestGetAllTagTemplates(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.GetAllTagTemplatesRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.TagService, *mocks.TagTemplateService) - PostCheck func(resp *compassv1beta1.GetAllTagTemplatesResponse) error - } - - var testCases = []testCase{ - { - Description: `should return internal server error if found unexpected error`, - Request: &compassv1beta1.GetAllTagTemplatesRequest{ - Urn: sampleTemplate.URN, - }, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().GetTemplates(ctx, sampleTemplate.URN).Return(nil, errors.New("unexpected error")) - }, - }, - { - Description: `should return ok and templates if found template based on the query`, - Request: &compassv1beta1.GetAllTagTemplatesRequest{ - Urn: sampleTemplate.URN, - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().GetTemplates(ctx, sampleTemplate.URN).Return([]tag.Template{sampleTemplate}, nil) - }, - PostCheck: func(resp *compassv1beta1.GetAllTagTemplatesResponse) error { - expected := &compassv1beta1.GetAllTagTemplatesResponse{ - Data: []*compassv1beta1.TagTemplate{ - sampleTemplatePB, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, { - Description: `should return all templates if no urn query params`, - Request: &compassv1beta1.GetAllTagTemplatesRequest{}, - ExpectStatus: 0, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().GetTemplates(ctx, "").Return([]tag.Template{sampleTemplate}, nil) - }, - PostCheck: func(resp *compassv1beta1.GetAllTagTemplatesResponse) error { - expected := &compassv1beta1.GetAllTagTemplatesResponse{ - Data: []*compassv1beta1.TagTemplate{ - sampleTemplatePB, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockTagSvc := new(mocks.TagService) - mockTemplateSvc := new(mocks.TagTemplateService) - if tc.Setup != nil { - tc.Setup(ctx, mockTagSvc, mockTemplateSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockTagSvc.AssertExpectations(t) - defer mockTemplateSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, nil, mockTagSvc, mockTemplateSvc, mockUserSvc) - - got, err := handler.GetAllTagTemplates(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestCreateTagTemplate(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - validRequest = &compassv1beta1.CreateTagTemplateRequest{ - Urn: sampleTemplatePB.GetUrn(), - DisplayName: sampleTemplatePB.GetDisplayName(), - Description: sampleTemplatePB.GetDescription(), - Fields: sampleTemplatePB.GetFields(), - } - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.CreateTagTemplateRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.TagService, *mocks.TagTemplateService) - PostCheck func(resp *compassv1beta1.CreateTagTemplateResponse) error - } - - var testCases = []testCase{ - { - Description: `should return already exist if duplicate template`, - Request: validRequest, - ExpectStatus: connect.CodeAlreadyExists, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().CreateTemplate(ctx, ns, &sampleTemplate).Return(tag.DuplicateTemplateError{URN: sampleTemplate.URN}) - }, - }, - { - Description: `should return internal server error if found error during insert`, - Request: validRequest, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().CreateTemplate(ctx, ns, &sampleTemplate).Return(errors.New("unexpected error during insert")) - }, - }, - { - Description: `should return ok and domain is inserted if found no error`, - Request: validRequest, - ExpectStatus: 0, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().CreateTemplate(ctx, ns, &sampleTemplate).Return(nil) - }, - PostCheck: func(resp *compassv1beta1.CreateTagTemplateResponse) error { - expected := &compassv1beta1.CreateTagTemplateResponse{ - Data: sampleTemplatePB, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockTagSvc := new(mocks.TagService) - mockTemplateSvc := new(mocks.TagTemplateService) - if tc.Setup != nil { - tc.Setup(ctx, mockTagSvc, mockTemplateSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockTagSvc.AssertExpectations(t) - defer mockTemplateSvc.AssertExpectations(t) - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, nil, mockTagSvc, mockTemplateSvc, mockUserSvc) - - got, err := handler.CreateTagTemplate(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestGetTagTemplate(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - validRequest = &compassv1beta1.GetTagTemplateRequest{ - TemplateUrn: sampleTemplatePB.GetUrn(), - } - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.GetTagTemplateRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.TagService, *mocks.TagTemplateService) - PostCheck func(resp *compassv1beta1.GetTagTemplateResponse) error - } - - var testCases = []testCase{ - { - Description: `should return not found if template is not found`, - Request: validRequest, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().GetTemplate(ctx, sampleTemplate.URN).Return(tag.Template{}, tag.TemplateNotFoundError{URN: sampleTemplate.URN}) - }, - }, - { - Description: `should return ok and template if domain template is found`, - Request: validRequest, - ExpectStatus: 0, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().GetTemplate(ctx, sampleTemplate.URN).Return(sampleTemplate, nil) - }, - PostCheck: func(resp *compassv1beta1.GetTagTemplateResponse) error { - expected := &compassv1beta1.GetTagTemplateResponse{ - Data: sampleTemplatePB, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockTagSvc := new(mocks.TagService) - mockTemplateSvc := new(mocks.TagTemplateService) - if tc.Setup != nil { - tc.Setup(ctx, mockTagSvc, mockTemplateSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockTagSvc.AssertExpectations(t) - defer mockTemplateSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, nil, mockTagSvc, mockTemplateSvc, mockUserSvc) - got, err := handler.GetTagTemplate(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestUpdateTagTemplate(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - validRequest = &compassv1beta1.UpdateTagTemplateRequest{ - TemplateUrn: sampleTemplatePB.GetUrn(), - DisplayName: sampleTemplatePB.GetDisplayName(), - Description: sampleTemplatePB.GetDescription(), - Fields: sampleTemplatePB.GetFields(), - } - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.UpdateTagTemplateRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.TagService, *mocks.TagTemplateService) - PostCheck func(resp *compassv1beta1.UpdateTagTemplateResponse) error - } - - var testCases = []testCase{ - { - Description: `should return not found if template is not found`, - Request: validRequest, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().UpdateTemplate(ctx, ns, sampleTemplate.URN, &sampleTemplate).Return(tag.TemplateNotFoundError{URN: sampleTemplate.URN}) - }, - }, - { - Description: `should return invalid argument if there is validation error`, - Request: validRequest, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().UpdateTemplate(ctx, ns, sampleTemplate.URN, &sampleTemplate).Return(tag.ValidationError{Err: errors.New("validation error")}) - }, - }, - { - Description: `should return internal server error if encountered error during update`, - Request: validRequest, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().UpdateTemplate(ctx, ns, sampleTemplate.URN, &sampleTemplate).Return(errors.New("unexpected error")) - }, - }, - { - Description: `should return status ok and its message if successfully updated`, - Request: validRequest, - ExpectStatus: 0, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().UpdateTemplate(ctx, ns, sampleTemplate.URN, &sampleTemplate).Run(func(ctx context.Context, ns *namespace.Namespace, templateURN string, template *tag.Template) { - template.UpdatedAt = time.Now() - }).Return(nil) - }, - PostCheck: func(resp *compassv1beta1.UpdateTagTemplateResponse) error { - expectedTemplatePB := sampleTemplatePB - expectedTemplatePB.UpdatedAt = resp.GetData().GetUpdatedAt() - expected := &compassv1beta1.UpdateTagTemplateResponse{ - Data: sampleTemplatePB, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockTagSvc := new(mocks.TagService) - mockTemplateSvc := new(mocks.TagTemplateService) - if tc.Setup != nil { - tc.Setup(ctx, mockTagSvc, mockTemplateSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockTagSvc.AssertExpectations(t) - defer mockTemplateSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, nil, mockTagSvc, mockTemplateSvc, mockUserSvc) - got, err := handler.UpdateTagTemplate(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestDeleteTagTemplate(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - validRequest = &compassv1beta1.DeleteTagTemplateRequest{ - TemplateUrn: sampleTemplatePB.GetUrn(), - } - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.DeleteTagTemplateRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.TagService, *mocks.TagTemplateService) - } - - var testCases = []testCase{ - { - Description: `should return not found if template is not found`, - Request: validRequest, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().DeleteTemplate(ctx, sampleTemplate.URN).Return(tag.TemplateNotFoundError{URN: sampleTemplate.URN}) - }, - }, - { - Description: `should return status ok and template if domain template is found`, - Request: validRequest, - ExpectStatus: 0, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - tts.EXPECT().DeleteTemplate(ctx, sampleTemplate.URN).Return(nil) - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockTagSvc := new(mocks.TagService) - mockTemplateSvc := new(mocks.TagTemplateService) - if tc.Setup != nil { - tc.Setup(ctx, mockTagSvc, mockTemplateSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockTagSvc.AssertExpectations(t) - defer mockTemplateSvc.AssertExpectations(t) - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, nil, mockTagSvc, mockTemplateSvc, mockUserSvc) - - _, err := handler.DeleteTagTemplate(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - }) - } -} - -func TestTemplateToProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - Template tag.Template - ExpectProto *compassv1beta1.TagTemplate - } - - var testCases = []testCase{ - { - Title: "should return no timestamp pb and empty template field pb if timestamp and template field are empty", - Template: tag.Template{URN: "urn", DisplayName: "display-name", Description: "description"}, - ExpectProto: &compassv1beta1.TagTemplate{Urn: "urn", DisplayName: "display-name", Description: "description"}, - }, - { - Title: "should return timestamp pb and template field pb if timestamp and template field are not empty", - Template: tag.Template{URN: "urn", DisplayName: "display-name", Description: "description", Fields: []tag.Field{{ID: 12, URN: "urn1"}}, CreatedAt: timeDummy, UpdatedAt: timeDummy}, - ExpectProto: &compassv1beta1.TagTemplate{Urn: "urn", DisplayName: "display-name", Description: "description", Fields: []*compassv1beta1.TagTemplateField{{Id: 12, Urn: "urn1"}}, CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := tagTemplateToProto(tc.Template) - if diff := cmp.Diff(got, tc.ExpectProto, protocmp.Transform()); diff != "" { - t.Errorf("expected response to be %+v, was %+v", tc.ExpectProto, got) - } - }) - } -} - -func TestTagTemplateFromProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - PB *compassv1beta1.TagTemplate - Expect tag.Template - } - - var testCases = []testCase{ - { - Title: "should return non empty time.Time and field if timestamp pb and field pb are not empty or zero", - PB: &compassv1beta1.TagTemplate{Urn: "urn", DisplayName: "display-name", Description: "description", Fields: []*compassv1beta1.TagTemplateField{{Id: 12, Urn: "urn1"}}, CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - Expect: tag.Template{URN: "urn", DisplayName: "display-name", Description: "description", Fields: []tag.Field{{ID: 12, URN: "urn1"}}, CreatedAt: timeDummy, UpdatedAt: timeDummy}, - }, - { - Title: "should return empty time.Time and empty field if timestamp pb and field pb are empty or zero", - PB: &compassv1beta1.TagTemplate{Urn: "urn", DisplayName: "display-name", Description: "description"}, - Expect: tag.Template{URN: "urn", DisplayName: "display-name", Description: "description"}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := tagTemplateFromProto(tc.PB) - if reflect.DeepEqual(got, tc.Expect) == false { - t.Errorf("expected returned asset to be %+v, was %+v", tc.Expect, got) - } - }) - } -} - -func TestTemplateFieldToProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - Field tag.Field - ExpectProto *compassv1beta1.TagTemplateField - } - - var testCases = []testCase{ - { - Title: "should return no timestamp pb if timestamp is empty", - Field: tag.Field{ID: 123, URN: "urn"}, - ExpectProto: &compassv1beta1.TagTemplateField{Id: 123, Urn: "urn"}, - }, - { - Title: "should return timestamp pb if timestamp is not empty or zero", - Field: tag.Field{ID: 123, URN: "urn", CreatedAt: timeDummy, UpdatedAt: timeDummy}, - ExpectProto: &compassv1beta1.TagTemplateField{Id: 123, Urn: "urn", CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := tagTemplateFieldToProto(tc.Field) - if diff := cmp.Diff(got, tc.ExpectProto, protocmp.Transform()); diff != "" { - t.Errorf("expected response to be %+v, was %+v", tc.ExpectProto, got) - } - }) - } -} - -func TestTagTemplateFieldFromProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - PB *compassv1beta1.TagTemplateField - Expect tag.Field - } - - var testCases = []testCase{ - { - Title: "should return non empty time.Time if timestamp pb is not empty", - PB: &compassv1beta1.TagTemplateField{Id: 123, Urn: "urn", CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - Expect: tag.Field{ID: 123, URN: "urn", CreatedAt: timeDummy, UpdatedAt: timeDummy}, - }, - { - Title: "should return empty time.Time if timestamp pb is empty or zero", - PB: &compassv1beta1.TagTemplateField{Id: 123, Urn: "urn"}, - Expect: tag.Field{ID: 123, URN: "urn"}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := tagTemplateFieldFromProto(tc.PB) - if reflect.DeepEqual(got, tc.Expect) == false { - t.Errorf("expected returned asset to be %+v, was %+v", tc.Expect, got) - } - }) - } -} diff --git a/handler/tag_test.go b/handler/tag_test.go deleted file mode 100644 index 45d3b0e8..00000000 --- a/handler/tag_test.go +++ /dev/null @@ -1,847 +0,0 @@ -package handler - -import ( - "context" - "errors" - "fmt" - "reflect" - "testing" - "time" - - "connectrpc.com/connect" - "github.com/google/go-cmp/cmp" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/tag" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/handler/mocks" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - - - "google.golang.org/protobuf/testing/protocmp" - "google.golang.org/protobuf/types/known/structpb" - "google.golang.org/protobuf/types/known/timestamppb" -) - -var assetID = uuid.NewString() -var sampleTag = tag.Tag{ - AssetID: assetID, - TemplateURN: "governance_policy", - TemplateDisplayName: "Governance Policy", - TemplateDescription: "Template that is mandatory to be used.", - TagValues: []tag.TagValue{ - { - FieldID: 1, - FieldValue: "Public", - FieldURN: "classification", - FieldDisplayName: "classification", - FieldDescription: "The classification of this asset", - FieldDataType: "enumerated", - FieldRequired: true, - FieldOptions: []string{"Public", "Restricted"}, - }, - { - FieldID: 2, - FieldValue: true, - FieldURN: "is_encrypted", - FieldDisplayName: "Is Encrypted?", - FieldDescription: "Specify whether this asset is encrypted or not.", - FieldDataType: "boolean", - FieldRequired: true, - }, - }, -} - -var sampleTagPB = &compassv1beta1.Tag{ - AssetId: assetID, - TemplateUrn: "governance_policy", - TemplateDisplayName: "Governance Policy", - TemplateDescription: "Template that is mandatory to be used.", - TagValues: []*compassv1beta1.TagValue{ - { - FieldId: 1, - FieldValue: structpb.NewStringValue("Public"), - FieldUrn: "classification", - FieldDisplayName: "classification", - FieldDescription: "The classification of this asset", - FieldDataType: "enumerated", - FieldRequired: true, - FieldOptions: []string{"Public", "Restricted"}, - }, - { - FieldId: 2, - FieldValue: structpb.NewBoolValue(true), - FieldUrn: "is_encrypted", - FieldDisplayName: "Is Encrypted?", - FieldDescription: "Specify whether this asset is encrypted or not.", - FieldDataType: "boolean", - FieldRequired: true, - }, - }, -} - -func TestGetTagByAssetAndTemplate(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.GetTagByAssetAndTemplateRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.TagService, *mocks.TagTemplateService) - PostCheck func(resp *compassv1beta1.GetTagByAssetAndTemplateResponse) error - } - - var testCases = []testCase{ - { - Description: `should return invalid argument if asset id is empty`, - Request: &compassv1beta1.GetTagByAssetAndTemplateRequest{ - AssetId: "", - TemplateUrn: "sample-template", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: `should return invalid argument if template urn is empty`, - Request: &compassv1beta1.GetTagByAssetAndTemplateRequest{ - AssetId: assetID, - TemplateUrn: "", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: `should return not found if template does not exist`, - Request: &compassv1beta1.GetTagByAssetAndTemplateRequest{ - AssetId: assetID, - TemplateUrn: sampleTemplate.URN, - }, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().FindTagByAssetIDAndTemplateURN(ctx, assetID, sampleTemplate.URN).Return(tag.Tag{}, tag.TemplateNotFoundError{URN: sampleTemplate.URN}) - }, - }, - { - Description: `should return not found if tag does not exist`, - Request: &compassv1beta1.GetTagByAssetAndTemplateRequest{ - AssetId: assetID, - TemplateUrn: sampleTemplate.URN, - }, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().FindTagByAssetIDAndTemplateURN(ctx, assetID, sampleTemplate.URN).Return(tag.Tag{}, tag.NotFoundError{ - AssetID: assetID, - Template: sampleTemplate.URN, - }) - }, - }, - { - Description: `should return internal server error if found unexpected error`, - Request: &compassv1beta1.GetTagByAssetAndTemplateRequest{ - AssetId: assetID, - TemplateUrn: sampleTemplate.URN, - }, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().FindTagByAssetIDAndTemplateURN(ctx, assetID, sampleTemplate.URN).Return(tag.Tag{}, errors.New("unexpected error")) - }, - }, - { - Description: `should return ok and tag`, - Request: &compassv1beta1.GetTagByAssetAndTemplateRequest{ - AssetId: assetID, - TemplateUrn: sampleTemplate.URN, - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().FindTagByAssetIDAndTemplateURN(ctx, assetID, sampleTemplate.URN).Return(sampleTag, nil) - }, - PostCheck: func(resp *compassv1beta1.GetTagByAssetAndTemplateResponse) error { - var tagValuesPB []*compassv1beta1.TagValue - for _, tv := range sampleTag.TagValues { - tvPB, err := tagValueToProto(tv) - if err != nil { - return err - } - tagValuesPB = append(tagValuesPB, tvPB) - } - - expected := &compassv1beta1.GetTagByAssetAndTemplateResponse{ - Data: &compassv1beta1.Tag{ - AssetId: sampleTag.AssetID, - TemplateUrn: sampleTag.TemplateURN, - TagValues: tagValuesPB, - TemplateDisplayName: sampleTag.TemplateDisplayName, - TemplateDescription: sampleTag.TemplateDescription, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockTagSvc := new(mocks.TagService) - mockTemplateSvc := new(mocks.TagTemplateService) - if tc.Setup != nil { - tc.Setup(ctx, mockTagSvc, mockTemplateSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockTagSvc.AssertExpectations(t) - defer mockTemplateSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, nil, mockTagSvc, mockTemplateSvc, mockUserSvc) - - got, err := handler.GetTagByAssetAndTemplate(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestCreateTagAsset(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - validRequest = &compassv1beta1.CreateTagAssetRequest{ - AssetId: sampleTagPB.GetAssetId(), - TemplateUrn: sampleTagPB.GetTemplateUrn(), - TagValues: sampleTagPB.TagValues, - TemplateDisplayName: sampleTagPB.TemplateDisplayName, - TemplateDescription: sampleTagPB.TemplateDescription, - } - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.CreateTagAssetRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.TagService, *mocks.TagTemplateService) - PostCheck func(resp *compassv1beta1.CreateTagAssetResponse) error - } - - var testCases = []testCase{ - { - Description: `should return invalid argument if asset id is empty`, - Request: &compassv1beta1.CreateTagAssetRequest{ - AssetId: "", - TemplateUrn: sampleTagPB.GetTemplateUrn(), - TagValues: sampleTagPB.TagValues, - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: `should return invalid argument if template urn is empty`, - Request: &compassv1beta1.CreateTagAssetRequest{ - AssetId: assetID, - TemplateUrn: "", - TagValues: sampleTagPB.TagValues, - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: `should return invalid argument if tag values is empty`, - Request: &compassv1beta1.CreateTagAssetRequest{ - AssetId: assetID, - TemplateUrn: sampleTagPB.GetTemplateUrn(), - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: `should return not found if template does not exist`, - Request: validRequest, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().CreateTag(ctx, ns, &sampleTag).Return(tag.TemplateNotFoundError{URN: sampleTemplate.URN}) - }, - }, - { - Description: `should return invalid argument if there is validation error`, - Request: validRequest, - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().CreateTag(ctx, ns, &sampleTag).Return(tag.ValidationError{Err: errors.New("validation error")}) - }, - }, - { - Description: `should return internal server error if found error during insert`, - Request: validRequest, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().CreateTag(ctx, ns, &sampleTag).Return(errors.New("unexpected error during insert")) - }, - }, - { - Description: `should return already exist if found duplicated asset during insert`, - Request: validRequest, - ExpectStatus: connect.CodeAlreadyExists, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().CreateTag(ctx, ns, &sampleTag).Return(tag.DuplicateError{}) - }, - }, - { - Description: `should return ok and domain is inserted if found no error`, - Request: validRequest, - ExpectStatus: 0, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().CreateTag(ctx, ns, &sampleTag).Return(nil) - }, - PostCheck: func(resp *compassv1beta1.CreateTagAssetResponse) error { - expected := &compassv1beta1.CreateTagAssetResponse{ - Data: sampleTagPB, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockTagSvc := new(mocks.TagService) - mockTemplateSvc := new(mocks.TagTemplateService) - if tc.Setup != nil { - tc.Setup(ctx, mockTagSvc, mockTemplateSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockTagSvc.AssertExpectations(t) - defer mockTemplateSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, nil, mockTagSvc, mockTemplateSvc, mockUserSvc) - - got, err := handler.CreateTagAsset(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestUpdateTagAsset(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - validRequest = &compassv1beta1.UpdateTagAssetRequest{ - AssetId: sampleTagPB.GetAssetId(), - TemplateUrn: sampleTagPB.GetTemplateUrn(), - TagValues: sampleTagPB.TagValues, - TemplateDisplayName: sampleTagPB.TemplateDisplayName, - TemplateDescription: sampleTagPB.TemplateDescription, - } - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.UpdateTagAssetRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.TagService, *mocks.TagTemplateService) - PostCheck func(resp *compassv1beta1.UpdateTagAssetResponse) error - } - - var testCases = []testCase{ - { - Description: `should return invalid argument if asset id is empty`, - Request: &compassv1beta1.UpdateTagAssetRequest{ - AssetId: "", - TemplateUrn: sampleTagPB.GetTemplateUrn(), - TagValues: sampleTagPB.TagValues, - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: `should return invalid argument if template urn is empty`, - Request: &compassv1beta1.UpdateTagAssetRequest{ - AssetId: assetID, - TemplateUrn: "", - TagValues: sampleTagPB.TagValues, - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: `should return invalid argument if tag values is empty`, - Request: &compassv1beta1.UpdateTagAssetRequest{ - AssetId: assetID, - TemplateUrn: sampleTagPB.GetTemplateUrn(), - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: `should return not found if tag could not be found`, - Request: validRequest, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().UpdateTag(ctx, &sampleTag).Return(tag.NotFoundError{}) - }, - }, - { - Description: `should return internal server error if found error during update`, - Request: validRequest, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().UpdateTag(ctx, &sampleTag).Return(errors.New("unexpected error during update")) - }, - }, - { - Description: `should return ok and domain is updated if found no error`, - Request: validRequest, - ExpectStatus: 0, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().UpdateTag(ctx, &sampleTag).Return(nil) - }, - PostCheck: func(resp *compassv1beta1.UpdateTagAssetResponse) error { - expected := &compassv1beta1.UpdateTagAssetResponse{ - Data: sampleTagPB, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockTagSvc := new(mocks.TagService) - mockTemplateSvc := new(mocks.TagTemplateService) - if tc.Setup != nil { - tc.Setup(ctx, mockTagSvc, mockTemplateSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockTagSvc.AssertExpectations(t) - defer mockTemplateSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, nil, mockTagSvc, mockTemplateSvc, mockUserSvc) - - got, err := handler.UpdateTagAsset(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestDeleteTagAsset(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.DeleteTagAssetRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.TagService, *mocks.TagTemplateService) - } - - var testCases = []testCase{ - { - Description: `should return invalid argument if asset id is empty`, - Request: &compassv1beta1.DeleteTagAssetRequest{ - AssetId: "", - TemplateUrn: sampleTagPB.GetTemplateUrn(), - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: `should return invalid argument if template urn is empty`, - Request: &compassv1beta1.DeleteTagAssetRequest{ - AssetId: assetID, - TemplateUrn: "", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: `should return not found if template does not exist`, - Request: &compassv1beta1.DeleteTagAssetRequest{ - AssetId: assetID, - TemplateUrn: sampleTagPB.GetTemplateUrn(), - }, - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().DeleteTag(ctx, assetID, sampleTagPB.TemplateUrn).Return(tag.TemplateNotFoundError{}) - }, - }, - { - Description: `should return internal server error found unexpected error`, - Request: &compassv1beta1.DeleteTagAssetRequest{ - AssetId: assetID, - TemplateUrn: sampleTagPB.GetTemplateUrn(), - }, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().DeleteTag(ctx, assetID, sampleTagPB.TemplateUrn).Return(errors.New("unexpected error")) - }, - }, - { - Description: `should return ok if delete success`, - Request: &compassv1beta1.DeleteTagAssetRequest{ - AssetId: assetID, - TemplateUrn: sampleTagPB.GetTemplateUrn(), - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().DeleteTag(ctx, assetID, sampleTagPB.TemplateUrn).Return(nil) - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockTagSvc := new(mocks.TagService) - mockTemplateSvc := new(mocks.TagTemplateService) - if tc.Setup != nil { - tc.Setup(ctx, mockTagSvc, mockTemplateSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockTagSvc.AssertExpectations(t) - defer mockTemplateSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, nil, mockTagSvc, mockTemplateSvc, mockUserSvc) - - _, err := handler.DeleteTagAsset(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - }) - } -} - -func TestGetAllTagsByAsset(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - validRequest = &compassv1beta1.GetAllTagsByAssetRequest{ - AssetId: assetID, - } - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - type testCase struct { - Description string - Request *compassv1beta1.GetAllTagsByAssetRequest - ExpectStatus connect.Code - Setup func(context.Context, *mocks.TagService, *mocks.TagTemplateService) - PostCheck func(resp *compassv1beta1.GetAllTagsByAssetResponse) error - } - - var testCases = []testCase{ - { - Description: `should return invalid argument if asset id is empty`, - Request: &compassv1beta1.GetAllTagsByAssetRequest{ - AssetId: "", - }, - ExpectStatus: connect.CodeInvalidArgument, - }, - { - Description: `should return internal server error if found unexpected error`, - Request: validRequest, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().GetTagsByAssetID(ctx, sampleTagPB.AssetId).Return(nil, errors.New("unexpected error")) - }, - }, - { - Description: `should return ok and tags for the specified asset`, - Request: validRequest, - ExpectStatus: 0, - Setup: func(ctx context.Context, ts *mocks.TagService, tts *mocks.TagTemplateService) { - ts.EXPECT().GetTagsByAssetID(ctx, sampleTagPB.AssetId).Return([]tag.Tag{sampleTag}, nil) - }, - PostCheck: func(resp *compassv1beta1.GetAllTagsByAssetResponse) error { - expected := &compassv1beta1.GetAllTagsByAssetResponse{ - Data: []*compassv1beta1.Tag{sampleTagPB}, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - mockUserSvc := new(mocks.UserService) - mockTagSvc := new(mocks.TagService) - mockTemplateSvc := new(mocks.TagTemplateService) - if tc.Setup != nil { - tc.Setup(ctx, mockTagSvc, mockTemplateSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockTagSvc.AssertExpectations(t) - defer mockTemplateSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, nil, mockTagSvc, mockTemplateSvc, mockUserSvc) - - got, err := handler.GetAllTagsByAsset(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestTagToProto(t *testing.T) { - type testCase struct { - Title string - Tag tag.Tag - ExpectProto *compassv1beta1.Tag - } - - var testCases = []testCase{ - { - Title: "should return empty field value pb if tag values is empty", - Tag: tag.Tag{AssetID: "1111-2222-3333-4444"}, - ExpectProto: &compassv1beta1.Tag{AssetId: "1111-2222-3333-4444"}, - }, - { - Title: "should return tag value pb if tag values is not empty", - Tag: tag.Tag{AssetID: "1111-2222-3333-4444", TagValues: []tag.TagValue{{FieldID: 123, FieldURN: "urn"}}}, - ExpectProto: &compassv1beta1.Tag{AssetId: "1111-2222-3333-4444", TagValues: []*compassv1beta1.TagValue{{FieldId: 123, FieldUrn: "urn"}}}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got, err := tagToProto(tc.Tag) - if err != nil { - t.Fatal(err) - } - if diff := cmp.Diff(got, tc.ExpectProto, protocmp.Transform()); diff != "" { - t.Errorf("expected response to be %+v, was %+v", tc.ExpectProto, got) - } - }) - } -} - -func TestTagFromProto(t *testing.T) { - type testCase struct { - Title string - PB *compassv1beta1.Tag - Expect tag.Tag - } - - var testCases = []testCase{ - { - Title: "should return non empty tag values if tag values pb are not empty", - PB: &compassv1beta1.Tag{AssetId: "1111-2222-3333-4444", TagValues: []*compassv1beta1.TagValue{{FieldId: 123, FieldUrn: "urn"}}}, - Expect: tag.Tag{AssetID: "1111-2222-3333-4444", TagValues: []tag.TagValue{{FieldID: 123, FieldURN: "urn"}}}, - }, - { - Title: "should return empty tag values if tag values pb are empty", - PB: &compassv1beta1.Tag{AssetId: "1111-2222-3333-4444"}, - Expect: tag.Tag{AssetID: "1111-2222-3333-4444"}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := tagFromProto(tc.PB) - if reflect.DeepEqual(got, tc.Expect) == false { - t.Errorf("expected returned asset to be %+v, was %+v", tc.Expect, got) - } - }) - } -} - -func TestTagValueToProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - TagValue tag.TagValue - ExpectProto *compassv1beta1.TagValue - } - - var testCases = []testCase{ - { - Title: "should return no timestamp pb and empty field value pb if timestamp and field value are empty or zero", - TagValue: tag.TagValue{FieldID: 123, FieldURN: "urn"}, - ExpectProto: &compassv1beta1.TagValue{FieldId: 123, FieldUrn: "urn"}, - }, - { - Title: "should return timestamp pb and field value pb if timestamp and field value are not empty or zero", - TagValue: tag.TagValue{FieldID: 123, FieldURN: "urn", FieldValue: "a value", CreatedAt: timeDummy, UpdatedAt: timeDummy}, - ExpectProto: &compassv1beta1.TagValue{FieldId: 123, FieldUrn: "urn", FieldValue: structpb.NewStringValue("a value"), CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got, err := tagValueToProto(tc.TagValue) - if err != nil { - t.Fatal(err) - } - if diff := cmp.Diff(got, tc.ExpectProto, protocmp.Transform()); diff != "" { - t.Errorf("expected response to be %+v, was %+v", tc.ExpectProto, got) - } - }) - } -} - -func TestTagValueFromProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - PB *compassv1beta1.TagValue - Expect tag.TagValue - } - - var testCases = []testCase{ - { - Title: "should return non empty time.Time and field value if timestamp pb and field value pb are not empty or zero", - PB: &compassv1beta1.TagValue{FieldId: 123, FieldUrn: "urn", FieldValue: structpb.NewStringValue("a value"), CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - Expect: tag.TagValue{FieldID: 123, FieldURN: "urn", FieldValue: "a value", CreatedAt: timeDummy, UpdatedAt: timeDummy}, - }, - { - Title: "should return empty time.Time and empty field value if timestamp pb and field value pb are empty or zero", - PB: &compassv1beta1.TagValue{FieldId: 123, FieldUrn: "urn"}, - Expect: tag.TagValue{FieldID: 123, FieldURN: "urn"}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := tagValueFromProto(tc.PB) - if reflect.DeepEqual(got, tc.Expect) == false { - t.Errorf("expected returned asset to be %+v, was %+v", tc.Expect, got) - } - }) - } -} diff --git a/handler/type.go b/handler/type.go deleted file mode 100644 index 3f8024b5..00000000 --- a/handler/type.go +++ /dev/null @@ -1,42 +0,0 @@ -package handler - -import ( - "context" - "fmt" - - "connectrpc.com/connect" - "github.com/raystack/compass/core/asset" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" -) - -func (server *Handler) GetAllTypes(ctx context.Context, req *connect.Request[compassv1beta1.GetAllTypesRequest]) (*connect.Response[compassv1beta1.GetAllTypesResponse], error) { - - flt, err := asset.NewFilterBuilder(). - Types(req.Msg.GetTypes()). - Services(req.Msg.GetServices()). - Q(req.Msg.GetQ()). - QFields(req.Msg.GetQFields()). - Data(req.Msg.GetData()). - Build() - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("%s", bodyParserErrorMsg(err))) - } - - typesNameMap, err := server.assetService.GetTypes(ctx, flt) - if err != nil { - return nil, internalServerError(ctx, "error fetching types", err) - } - - results := []*compassv1beta1.Type{} - for _, typName := range asset.AllSupportedTypes { - count := typesNameMap[typName] - results = append(results, &compassv1beta1.Type{ - Name: typName.String(), - Count: uint32(count), - }) - } - - return connect.NewResponse(&compassv1beta1.GetAllTypesResponse{ - Data: results, - }), nil -} diff --git a/handler/type_test.go b/handler/type_test.go deleted file mode 100644 index 15b90352..00000000 --- a/handler/type_test.go +++ /dev/null @@ -1,152 +0,0 @@ -package handler - -import ( - "context" - "errors" - "fmt" - "testing" - - "connectrpc.com/connect" - "github.com/google/go-cmp/cmp" - "github.com/google/uuid" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/handler/mocks" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - - - "google.golang.org/protobuf/testing/protocmp" -) - -func TestGetTypes(t *testing.T) { - var ( - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - type testCase struct { - Description string - ExpectStatus connect.Code - Setup func(tc *testCase, ctx context.Context, as *mocks.AssetService) - PostCheck func(resp *compassv1beta1.GetAllTypesResponse) error - } - - var testCases = []testCase{ - { - Description: "should return internal server error if failing to fetch types", - ExpectStatus: connect.CodeInternal, - Setup: func(tc *testCase, ctx context.Context, as *mocks.AssetService) { - as.EXPECT().GetTypes(ctx, asset.Filter{}).Return(map[asset.Type]int{}, errors.New("failed to fetch type")) - }, - }, - { - Description: "should return internal server error if failing to fetch counts", - ExpectStatus: connect.CodeInternal, - Setup: func(tc *testCase, ctx context.Context, as *mocks.AssetService) { - as.EXPECT().GetTypes(ctx, asset.Filter{}).Return(map[asset.Type]int{}, errors.New("failed to fetch assets count")) - }, - }, - { - Description: "should return all valid types with its asset count", - ExpectStatus: 0, - Setup: func(tc *testCase, ctx context.Context, as *mocks.AssetService) { - as.EXPECT().GetTypes(ctx, asset.Filter{}).Return(map[asset.Type]int{ - asset.Type("table"): 10, - asset.Type("topic"): 30, - asset.Type("job"): 15, - }, nil) - }, - PostCheck: func(resp *compassv1beta1.GetAllTypesResponse) error { - expected := &compassv1beta1.GetAllTypesResponse{ - Data: []*compassv1beta1.Type{ - { - Name: "table", - Count: 10, - }, - { - Name: "job", - Count: 15, - }, - { - Name: "dashboard", - Count: 0, - }, - { - Name: "topic", - Count: 30, - }, - { - Name: "feature_table", - Count: 0, - }, - { - Name: "application", - Count: 0, - }, - { - Name: "model", - Count: 0, - }, - { - Name: "query", - Count: 0, - }, - { - Name: "metric", - Count: 0, - }, - { - Name: "experiment", - Count: 0, - }, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - - mockSvc := new(mocks.AssetService) - defer mockSvc.AssertExpectations(t) - tc.Setup(&tc, ctx, mockSvc) - - defer mockSvc.AssertExpectations(t) - - handler := New(nil, mockSvc, nil, nil, nil, nil, nil) - - got, err := handler.GetAllTypes(ctx, connect.NewRequest(&compassv1beta1.GetAllTypesRequest{})) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} diff --git a/handler/user.go b/handler/user.go index 9f242da1..950cca80 100644 --- a/handler/user.go +++ b/handler/user.go @@ -1,311 +1,135 @@ package handler -//go:generate mockery --name=UserService -r --case underscore --with-expecter --structname UserService --filename user_service.go --output=./mocks import ( "context" "errors" - "strings" - "time" "connectrpc.com/connect" - "github.com/raystack/compass/core/discussion" "github.com/raystack/compass/core/namespace" "github.com/raystack/compass/core/star" "github.com/raystack/compass/core/user" - "github.com/raystack/compass/core/validator" "github.com/raystack/compass/internal/middleware" compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "google.golang.org/protobuf/types/known/timestamppb" ) type UserService interface { ValidateUser(ctx context.Context, ns *namespace.Namespace, uuid, email string) (string, error) } -func (server *Handler) GetUserStarredAssets(ctx context.Context, req *connect.Request[compassv1beta1.GetUserStarredAssetsRequest]) (*connect.Response[compassv1beta1.GetUserStarredAssetsResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - if _, err := server.validateUserInCtx(ctx, ns); err != nil { - return nil, err - } - - starFilter := star.Filter{ +func (server *Handler) GetUserStarredEntities(ctx context.Context, req *connect.Request[compassv1beta1.GetUserStarredEntitiesRequest]) (*connect.Response[compassv1beta1.GetUserStarredEntitiesResponse], error) { + entities, err := server.starService.GetStarredEntitiesByUserID(ctx, star.Filter{ Size: int(req.Msg.GetSize()), Offset: int(req.Msg.GetOffset()), - } - - starredAssets, err := server.starService.GetStarredAssetsByUserID(ctx, starFilter, req.Msg.GetUserId()) - - if errors.Is(err, star.ErrEmptyUserID) || errors.As(err, new(star.InvalidError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if errors.As(err, new(star.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } + }, req.Msg.GetUserId()) if err != nil { - return nil, internalServerError(ctx, "internal error", err) + return nil, internalServerError(ctx, "error getting starred entities", err) } - var starredAssetsPB []*compassv1beta1.Asset - for _, ast := range starredAssets { - astPB, err := assetToProto(ast, false) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - starredAssetsPB = append(starredAssetsPB, astPB) + data := make([]*compassv1beta1.Entity, len(entities)) + for i, e := range entities { + data[i] = entityToProto(e) } - - return connect.NewResponse(&compassv1beta1.GetUserStarredAssetsResponse{ - Data: starredAssetsPB, - }), nil + return connect.NewResponse(&compassv1beta1.GetUserStarredEntitiesResponse{Data: data}), nil } -func (server *Handler) GetMyStarredAssets(ctx context.Context, req *connect.Request[compassv1beta1.GetMyStarredAssetsRequest]) (*connect.Response[compassv1beta1.GetMyStarredAssetsResponse], error) { +func (server *Handler) GetMyStarredEntities(ctx context.Context, req *connect.Request[compassv1beta1.GetMyStarredEntitiesRequest]) (*connect.Response[compassv1beta1.GetMyStarredEntitiesResponse], error) { ns := middleware.FetchNamespaceFromContext(ctx) userID, err := server.validateUserInCtx(ctx, ns) if err != nil { return nil, err } - starFilter := star.Filter{ + entities, err := server.starService.GetStarredEntitiesByUserID(ctx, star.Filter{ Size: int(req.Msg.GetSize()), Offset: int(req.Msg.GetOffset()), - } - - starredAssets, err := server.starService.GetStarredAssetsByUserID(ctx, starFilter, userID) - - if errors.Is(err, star.ErrEmptyUserID) || errors.As(err, new(star.InvalidError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if errors.As(err, new(star.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } + }, userID) if err != nil { - return nil, internalServerError(ctx, "internal error", err) + return nil, internalServerError(ctx, "error getting my starred entities", err) } - var starredAssetsPB []*compassv1beta1.Asset - for _, ast := range starredAssets { - astPB, err := assetToProto(ast, false) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - starredAssetsPB = append(starredAssetsPB, astPB) + data := make([]*compassv1beta1.Entity, len(entities)) + for i, e := range entities { + data[i] = entityToProto(e) } - - return connect.NewResponse(&compassv1beta1.GetMyStarredAssetsResponse{ - Data: starredAssetsPB, - }), nil + return connect.NewResponse(&compassv1beta1.GetMyStarredEntitiesResponse{Data: data}), nil } -func (server *Handler) GetMyStarredAsset(ctx context.Context, req *connect.Request[compassv1beta1.GetMyStarredAssetRequest]) (*connect.Response[compassv1beta1.GetMyStarredAssetResponse], error) { +func (server *Handler) GetMyStarredEntity(ctx context.Context, req *connect.Request[compassv1beta1.GetMyStarredEntityRequest]) (*connect.Response[compassv1beta1.GetMyStarredEntityResponse], error) { ns := middleware.FetchNamespaceFromContext(ctx) userID, err := server.validateUserInCtx(ctx, ns) if err != nil { return nil, err } - ast, err := server.starService.GetStarredAssetByUserID(ctx, userID, req.Msg.GetAssetId()) - if errors.Is(err, star.ErrEmptyAssetID) || errors.Is(err, star.ErrEmptyUserID) || errors.As(err, new(star.InvalidError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - if errors.As(err, new(star.NotFoundError)) { - return nil, connect.NewError(connect.CodeNotFound, err) - } + ent, err := server.starService.GetStarredEntityByUserID(ctx, userID, req.Msg.GetEntityId()) if err != nil { - return nil, internalServerError(ctx, "internal error", err) + return nil, internalServerError(ctx, "error getting starred entity", err) } - astPB, err := assetToProto(ast, false) - if err != nil { - return nil, internalServerError(ctx, "internal error", err) - } - - return connect.NewResponse(&compassv1beta1.GetMyStarredAssetResponse{ - Data: astPB, - }), nil + return connect.NewResponse(&compassv1beta1.GetMyStarredEntityResponse{Data: entityToProto(ent)}), nil } -func (server *Handler) StarAsset(ctx context.Context, req *connect.Request[compassv1beta1.StarAssetRequest]) (*connect.Response[compassv1beta1.StarAssetResponse], error) { +func (server *Handler) StarEntity(ctx context.Context, req *connect.Request[compassv1beta1.StarEntityRequest]) (*connect.Response[compassv1beta1.StarEntityResponse], error) { ns := middleware.FetchNamespaceFromContext(ctx) userID, err := server.validateUserInCtx(ctx, ns) if err != nil { return nil, err } - starID, err := server.starService.Stars(ctx, ns, userID, req.Msg.GetAssetId()) + id, err := server.starService.Stars(ctx, ns, userID, req.Msg.GetEntityId()) if err != nil { - if errors.Is(err, star.ErrEmptyAssetID) || errors.Is(err, star.ErrEmptyUserID) || errors.As(err, new(star.InvalidError)) { + if errors.Is(err, star.ErrEmptyUserID) || errors.Is(err, star.ErrEmptyEntityID) || errors.As(err, new(star.InvalidError)) { return nil, connect.NewError(connect.CodeInvalidArgument, err) } if errors.As(err, new(star.UserNotFoundError)) { - return nil, connect.NewError(connect.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeNotFound, err) } if errors.As(err, new(star.DuplicateRecordError)) { - // idempotent - return connect.NewResponse(&compassv1beta1.StarAssetResponse{ - Id: starID, - }), nil + return nil, connect.NewError(connect.CodeAlreadyExists, err) } - return nil, internalServerError(ctx, "internal error", err) + return nil, internalServerError(ctx, "error starring entity", err) } - return connect.NewResponse(&compassv1beta1.StarAssetResponse{ - Id: starID, - }), nil + return connect.NewResponse(&compassv1beta1.StarEntityResponse{Id: id}), nil } -func (server *Handler) UnstarAsset(ctx context.Context, req *connect.Request[compassv1beta1.UnstarAssetRequest]) (*connect.Response[compassv1beta1.UnstarAssetResponse], error) { +func (server *Handler) UnstarEntity(ctx context.Context, req *connect.Request[compassv1beta1.UnstarEntityRequest]) (*connect.Response[compassv1beta1.UnstarEntityResponse], error) { ns := middleware.FetchNamespaceFromContext(ctx) userID, err := server.validateUserInCtx(ctx, ns) if err != nil { return nil, err } - err = server.starService.Unstars(ctx, userID, req.Msg.GetAssetId()) - if err != nil { - if errors.Is(err, star.ErrEmptyAssetID) || errors.Is(err, star.ErrEmptyUserID) || errors.As(err, new(star.InvalidError)) { + if err := server.starService.Unstars(ctx, userID, req.Msg.GetEntityId()); err != nil { + if errors.Is(err, star.ErrEmptyUserID) || errors.Is(err, star.ErrEmptyEntityID) || errors.As(err, new(star.InvalidError)) { return nil, connect.NewError(connect.CodeInvalidArgument, err) } if errors.As(err, new(star.NotFoundError)) { return nil, connect.NewError(connect.CodeNotFound, err) } - return nil, internalServerError(ctx, "internal error", err) + return nil, internalServerError(ctx, "error unstarring entity", err) } - return connect.NewResponse(&compassv1beta1.UnstarAssetResponse{}), nil + return connect.NewResponse(&compassv1beta1.UnstarEntityResponse{}), nil } -func (server *Handler) GetMyDiscussions(ctx context.Context, req *connect.Request[compassv1beta1.GetMyDiscussionsRequest]) (*connect.Response[compassv1beta1.GetMyDiscussionsResponse], error) { - ns := middleware.FetchNamespaceFromContext(ctx) - userID, err := server.validateUserInCtx(ctx, ns) - if err != nil { - return nil, err - } - - flt, err := server.buildGetDiscussionsFilter(req.Msg, userID) - if err != nil { - return nil, connect.NewError(connect.CodeInvalidArgument, err) - } - - dscs, err := server.discussionService.GetDiscussions(ctx, flt) +func (server *Handler) GetEntityStargazers(ctx context.Context, req *connect.Request[compassv1beta1.GetEntityStargazersRequest]) (*connect.Response[compassv1beta1.GetEntityStargazersResponse], error) { + users, err := server.starService.GetStargazers(ctx, star.Filter{ + Size: int(req.Msg.GetSize()), + Offset: int(req.Msg.GetOffset()), + }, req.Msg.GetId()) if err != nil { - return nil, internalServerError(ctx, "internal error", err) + return nil, internalServerError(ctx, "error getting stargazers", err) } - var dscsPB []*compassv1beta1.Discussion - for _, dsc := range dscs { - dscsPB = append(dscsPB, discussionToProto(dsc)) + data := make([]*compassv1beta1.User, len(users)) + for i, u := range users { + data[i] = &compassv1beta1.User{Id: u.ID, Uuid: u.UUID, Email: u.Email} } - - return connect.NewResponse(&compassv1beta1.GetMyDiscussionsResponse{ - Data: dscsPB, - }), nil + return connect.NewResponse(&compassv1beta1.GetEntityStargazersResponse{Data: data}), nil } -func (server *Handler) buildGetDiscussionsFilter(req *compassv1beta1.GetMyDiscussionsRequest, userID string) (discussion.Filter, error) { - fl := discussion.Filter{ - Type: req.GetType(), - State: req.GetState(), - SortBy: req.GetSort(), - SortDirection: req.GetDirection(), - Size: int(req.GetSize()), - Offset: int(req.GetOffset()), - } - - filterQuery := req.GetFilter() - if err := validator.ValidateOneOf(filterQuery, "assigned", "created", "all"); err != nil { - return discussion.Filter{}, err - } - - if len(strings.TrimSpace(filterQuery)) > 0 { - if filterQuery != "created" && filterQuery != "all" { - filterQuery = "assigned" // default value - } - } - - switch filterQuery { - case "all": - fl.Owner = userID - fl.Assignees = []string{userID} - fl.DisjointAssigneeOwner = true - case "created": - fl.Owner = userID - default: - fl.Assignees = []string{userID} - } - - assets := req.GetAsset() - if assets != "" { - fl.Assets = strings.Split(assets, ",") - } - - labels := req.GetLabels() - if labels != "" { - fl.Labels = strings.Split(labels, ",") - } - - if err := fl.Validate(); err != nil { - return discussion.Filter{}, err - } - - fl.AssignDefault() - return fl, nil -} - -// userToProto transforms struct with some fields only to proto -func userToProto(u user.User) *compassv1beta1.User { - if u == (user.User{}) { - return nil - } - return &compassv1beta1.User{ - Uuid: u.UUID, - Email: u.Email, - } -} - -// userToFullProto transforms struct with all fields to proto -func userToFullProto(u user.User) *compassv1beta1.User { - if u == (user.User{}) { - return nil - } - var createdAtPB *timestamppb.Timestamp - if !u.CreatedAt.IsZero() { - createdAtPB = timestamppb.New(u.CreatedAt) - } - - var updatedAtPB *timestamppb.Timestamp - if !u.UpdatedAt.IsZero() { - updatedAtPB = timestamppb.New(u.UpdatedAt) - } - - return &compassv1beta1.User{ - Id: u.ID, - Uuid: u.UUID, - Email: u.Email, - Provider: u.Provider, - CreatedAt: createdAtPB, - UpdatedAt: updatedAtPB, - } -} - -// userFromProto transforms proto to struct -func userFromProto(proto *compassv1beta1.User) user.User { - var createdAt time.Time - if proto.GetCreatedAt() != nil { - createdAt = proto.GetCreatedAt().AsTime() - } - - var updatedAt time.Time - if proto.GetUpdatedAt() != nil { - updatedAt = proto.GetUpdatedAt().AsTime() - } - - return user.User{ - ID: proto.GetId(), - UUID: proto.GetUuid(), - Email: proto.GetEmail(), - Provider: proto.GetProvider(), - CreatedAt: createdAt, - UpdatedAt: updatedAt, - } -} +// suppress unused import warnings +var ( + _ = user.FromContext +) diff --git a/handler/user_test.go b/handler/user_test.go deleted file mode 100644 index 85f8d94d..00000000 --- a/handler/user_test.go +++ /dev/null @@ -1,851 +0,0 @@ -package handler - -import ( - "context" - "errors" - "fmt" - "reflect" - "testing" - "time" - - "connectrpc.com/connect" - "github.com/google/go-cmp/cmp" - "github.com/google/uuid" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/discussion" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/star" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/handler/mocks" - "github.com/raystack/compass/internal/middleware" - compassv1beta1 "github.com/raystack/compass/gen/raystack/compass/v1beta1" - "google.golang.org/protobuf/testing/protocmp" - "google.golang.org/protobuf/types/known/timestamppb" -) - -func TestGetUserStarredAssets(t *testing.T) { - var ( - userUUID = uuid.NewString() - userID = uuid.NewString() - offset = 2 - size = 10 - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - type testCase struct { - Description string - ExpectStatus connect.Code - Setup func(context.Context, *mocks.StarService) - PostCheck func(resp *compassv1beta1.GetUserStarredAssetsResponse) error - } - - var testCases = []testCase{ - { - Description: "should return internal server error if failed to fetch starred", - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetsByUserID(ctx, star.Filter{Offset: offset, Size: size}, userID).Return(nil, errors.New("failed to fetch starred")) - }, - }, - { - Description: "should return invalid argument if star repository return invalid error", - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetsByUserID(ctx, star.Filter{Offset: offset, Size: size}, userID).Return(nil, star.InvalidError{}) - }, - }, - { - Description: "should return not found if starred not found", - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetsByUserID(ctx, star.Filter{Offset: offset, Size: size}, userID).Return(nil, star.NotFoundError{}) - }, - }, - { - Description: "should return starred assets of a user if no error", - ExpectStatus: 0, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetsByUserID(ctx, star.Filter{Offset: offset, Size: size}, userID).Return([]asset.Asset{ - {ID: "1", URN: "asset-urn-1", Type: "asset-type"}, - {ID: "2", URN: "asset-urn-2", Type: "asset-type"}, - {ID: "3", URN: "asset-urn-3", Type: "asset-type"}, - }, nil) - }, - PostCheck: func(resp *compassv1beta1.GetUserStarredAssetsResponse) error { - expected := &compassv1beta1.GetUserStarredAssetsResponse{ - Data: []*compassv1beta1.Asset{ - { - Id: "1", - Urn: "asset-urn-1", - Type: "asset-type", - }, - { - Id: "2", - Urn: "asset-urn-2", - Type: "asset-type", - }, - { - Id: "3", - Urn: "asset-urn-3", - Type: "asset-type", - }, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - - - mockUserSvc := new(mocks.UserService) - mockStarSvc := new(mocks.StarService) - if tc.Setup != nil { - tc.Setup(ctx, mockStarSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockStarSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, mockStarSvc, nil, nil, nil, mockUserSvc) - - got, err := handler.GetUserStarredAssets(ctx, connect.NewRequest(&compassv1beta1.GetUserStarredAssetsRequest{ - UserId: userID, - Offset: uint32(offset), - Size: uint32(size), - })) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestGetMyStarredAssets(t *testing.T) { - var ( - userUUID = uuid.NewString() - userID = uuid.NewString() - offset = 2 - size = 10 - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - type testCase struct { - Description string - ExpectStatus connect.Code - Setup func(context.Context, *mocks.StarService) - PostCheck func(resp *compassv1beta1.GetMyStarredAssetsResponse) error - } - - var testCases = []testCase{ - { - Description: "should return internal server error if failed to fetch starred", - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetsByUserID(ctx, star.Filter{Offset: offset, Size: size}, userID).Return(nil, errors.New("failed to fetch starred")) - }, - }, - { - Description: "should return invalid argument if star repository return invalid error", - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetsByUserID(ctx, star.Filter{Offset: offset, Size: size}, userID).Return(nil, star.InvalidError{}) - }, - }, - { - Description: "should return not found if starred not found", - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetsByUserID(ctx, star.Filter{Offset: offset, Size: size}, userID).Return(nil, star.NotFoundError{}) - }, - }, - { - Description: "should return starred assets of a user if no error", - ExpectStatus: 0, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetsByUserID(ctx, star.Filter{Offset: offset, Size: size}, userID).Return([]asset.Asset{ - {ID: "1", URN: "asset-urn-1", Type: "asset-type"}, - {ID: "2", URN: "asset-urn-2", Type: "asset-type"}, - {ID: "3", URN: "asset-urn-3", Type: "asset-type"}, - }, nil) - }, - PostCheck: func(resp *compassv1beta1.GetMyStarredAssetsResponse) error { - expected := &compassv1beta1.GetMyStarredAssetsResponse{ - Data: []*compassv1beta1.Asset{ - { - Id: "1", - Urn: "asset-urn-1", - Type: "asset-type", - }, - { - Id: "2", - Urn: "asset-urn-2", - Type: "asset-type", - }, - { - Id: "3", - Urn: "asset-urn-3", - Type: "asset-type", - }, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - - - mockUserSvc := new(mocks.UserService) - mockStarSvc := new(mocks.StarService) - if tc.Setup != nil { - tc.Setup(ctx, mockStarSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockStarSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, mockStarSvc, nil, nil, nil, mockUserSvc) - - got, err := handler.GetMyStarredAssets(ctx, connect.NewRequest(&compassv1beta1.GetMyStarredAssetsRequest{ - Offset: uint32(offset), - Size: uint32(size), - })) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestGetMyStarredAsset(t *testing.T) { - var ( - userUUID = uuid.NewString() - userID = uuid.NewString() - assetID = uuid.NewString() - assetType = "an-asset-type" - assetURN = "dummy-asset-urn" - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - type testCase struct { - Description string - ExpectStatus connect.Code - Setup func(context.Context, *mocks.StarService) - PostCheck func(resp *compassv1beta1.GetMyStarredAssetResponse) error - } - - var testCases = []testCase{ - { - Description: "should return invalid argument if asset id is empty", - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetByUserID(ctx, userID, assetID).Return(asset.Asset{}, star.ErrEmptyAssetID) - }, - }, - { - Description: "should return invalid argument if repository return invalid error", - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetByUserID(ctx, userID, assetID).Return(asset.Asset{}, star.InvalidError{}) - }, - }, - { - Description: "should return not found if star not found", - ExpectStatus: connect.CodeNotFound, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetByUserID(ctx, userID, assetID).Return(asset.Asset{}, star.NotFoundError{}) - }, - }, - { - Description: "should return internal server error if failed to fetch a starred asset", - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetByUserID(ctx, userID, assetID).Return(asset.Asset{}, errors.New("failed to fetch starred")) - }, - }, - { - Description: "should return a starred assets of a user if no error", - ExpectStatus: 0, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().GetStarredAssetByUserID(ctx, userID, assetID).Return(asset.Asset{Type: asset.Type(assetType), URN: assetURN}, nil) - }, - PostCheck: func(resp *compassv1beta1.GetMyStarredAssetResponse) error { - expected := &compassv1beta1.GetMyStarredAssetResponse{ - Data: &compassv1beta1.Asset{ - Urn: assetURN, - Type: assetType, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - - - mockUserSvc := new(mocks.UserService) - mockStarSvc := new(mocks.StarService) - if tc.Setup != nil { - tc.Setup(ctx, mockStarSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockStarSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, mockStarSvc, nil, nil, nil, mockUserSvc) - - got, err := handler.GetMyStarredAsset(ctx, connect.NewRequest(&compassv1beta1.GetMyStarredAssetRequest{ - AssetId: assetID, - })) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestStarAsset(t *testing.T) { - var ( - userID = uuid.NewString() - assetID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - type testCase struct { - Description string - ExpectStatus connect.Code - Setup func(context.Context, *mocks.StarService) - } - - var testCases = []testCase{ - { - Description: "should return invalid argument if asset id in param is invalid", - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().Stars(ctx, ns, userID, assetID).Return("", star.ErrEmptyAssetID) - }, - }, - { - Description: "should return invalid argument if star repository return invalid error", - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().Stars(ctx, ns, userID, assetID).Return("", star.InvalidError{}) - }, - }, - { - Description: "should return invalid argument if user not found", - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().Stars(ctx, ns, userID, assetID).Return("", star.UserNotFoundError{UserID: userID}) - }, - }, - { - Description: "should return internal server error if failed to star an asset", - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().Stars(ctx, ns, userID, assetID).Return("", errors.New("failed to star an asset")) - }, - }, - { - Description: "should return ok if starring success", - ExpectStatus: 0, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().Stars(ctx, ns, userID, assetID).Return("1234", nil) - }, - }, - { - Description: "should return ok if asset is already starred", - ExpectStatus: 0, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().Stars(ctx, ns, userID, assetID).Return("", star.DuplicateRecordError{}) - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - - - mockUserSvc := new(mocks.UserService) - mockStarSvc := new(mocks.StarService) - if tc.Setup != nil { - tc.Setup(ctx, mockStarSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockStarSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, mockStarSvc, nil, nil, nil, mockUserSvc) - - _, err := handler.StarAsset(ctx, connect.NewRequest(&compassv1beta1.StarAssetRequest{ - AssetId: assetID, - })) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - }) - } -} - -func TestUnstarAsset(t *testing.T) { - var ( - userID = uuid.NewString() - assetID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - type testCase struct { - Description string - ExpectStatus connect.Code - Setup func(context.Context, *mocks.StarService) - } - - var testCases = []testCase{ - { - Description: "should return invalid argument if asset id in param is empty", - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().Unstars(ctx, userID, assetID).Return(star.ErrEmptyAssetID) - }, - }, - { - Description: "should return invalid argument if star repository return invalid error", - ExpectStatus: connect.CodeInvalidArgument, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().Unstars(ctx, userID, assetID).Return(star.InvalidError{}) - }, - }, - { - Description: "should return internal server error if failed to unstar an asset", - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().Unstars(ctx, userID, assetID).Return(errors.New("failed to star an asset")) - }, - }, - { - Description: "should return ok if unstarring success", - ExpectStatus: 0, - Setup: func(ctx context.Context, ss *mocks.StarService) { - ss.EXPECT().Unstars(ctx, userID, assetID).Return(nil) - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - - - mockUserSvc := new(mocks.UserService) - mockStarSvc := new(mocks.StarService) - if tc.Setup != nil { - tc.Setup(ctx, mockStarSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockStarSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, mockStarSvc, nil, nil, nil, mockUserSvc) - - _, err := handler.UnstarAsset(ctx, connect.NewRequest(&compassv1beta1.UnstarAssetRequest{ - AssetId: assetID, - })) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - }) - } -} - -func TestGetMyDiscussions(t *testing.T) { - var ( - userID = uuid.NewString() - userUUID = uuid.NewString() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - ) - type testCase struct { - Description string - ExpectStatus connect.Code - Request *compassv1beta1.GetMyDiscussionsRequest - Setup func(context.Context, *mocks.DiscussionService) - PostCheck func(resp *compassv1beta1.GetMyDiscussionsResponse) error - } - - var testCases = []testCase{ - { - Description: `should return internal server error if fetching fails`, - Request: &compassv1beta1.GetMyDiscussionsRequest{}, - ExpectStatus: connect.CodeInternal, - Setup: func(ctx context.Context, ds *mocks.DiscussionService) { - ds.EXPECT().GetDiscussions(ctx, discussion.Filter{ - Type: "all", - State: discussion.StateOpen.String(), - Assignees: []string{userID}, - SortBy: "created_at", - SortDirection: "desc", - DisjointAssigneeOwner: false, - }).Return([]discussion.Discussion{}, errors.New("unknown error")) - }, - }, - { - Description: `should parse querystring to get filter`, - Request: &compassv1beta1.GetMyDiscussionsRequest{ - Type: "issues", - State: "closed", - Labels: "label1,label2,label4", - Asset: "e5d81dcd-3046-4d33-b1ac-efdd221e621d", - Sort: "updated_at", - Direction: "asc", - Size: 30, - Offset: 50, - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, ds *mocks.DiscussionService) { - ds.EXPECT().GetDiscussions(ctx, discussion.Filter{ - Type: "issues", - State: "closed", - Assignees: []string{userID}, - Assets: []string{"e5d81dcd-3046-4d33-b1ac-efdd221e621d"}, - Labels: []string{"label1", "label2", "label4"}, - SortBy: "updated_at", - SortDirection: "asc", - Size: 30, - Offset: 50, - DisjointAssigneeOwner: false, - }).Return([]discussion.Discussion{}, nil) - }, - }, { - Description: `should search by assigned or created if filter is all`, - Request: &compassv1beta1.GetMyDiscussionsRequest{ - Filter: "all", - }, - ExpectStatus: 0, - Setup: func(ctx context.Context, ds *mocks.DiscussionService) { - ds.EXPECT().GetDiscussions(ctx, discussion.Filter{ - Type: "all", - State: "open", - Assignees: []string{userID}, - Owner: userID, - SortBy: "created_at", - SortDirection: "desc", - DisjointAssigneeOwner: true, - }).Return([]discussion.Discussion{}, nil) - }, - }, - { - Description: `should set filter to default if empty`, - ExpectStatus: 0, - Request: &compassv1beta1.GetMyDiscussionsRequest{}, - Setup: func(ctx context.Context, ds *mocks.DiscussionService) { - ds.EXPECT().GetDiscussions(ctx, discussion.Filter{ - Type: "all", - State: "open", - Assignees: []string{userID}, - SortBy: "created_at", - SortDirection: "desc", - Size: 0, - Offset: 0, - DisjointAssigneeOwner: false, - }).Return([]discussion.Discussion{}, nil) - }, - }, - { - Description: "should return ok along with list of discussions", - ExpectStatus: 0, - Request: &compassv1beta1.GetMyDiscussionsRequest{}, - Setup: func(ctx context.Context, ds *mocks.DiscussionService) { - ds.EXPECT().GetDiscussions(ctx, discussion.Filter{ - Type: "all", - State: discussion.StateOpen.String(), - Assignees: []string{userID}, - SortBy: "created_at", - SortDirection: "desc", - DisjointAssigneeOwner: false, - }).Return([]discussion.Discussion{ - {ID: "1122"}, - {ID: "2233"}, - }, nil) - }, - PostCheck: func(resp *compassv1beta1.GetMyDiscussionsResponse) error { - expected := &compassv1beta1.GetMyDiscussionsResponse{ - Data: []*compassv1beta1.Discussion{ - {Id: "1122"}, - {Id: "2233"}, - }, - } - - if diff := cmp.Diff(resp, expected, protocmp.Transform()); diff != "" { - return fmt.Errorf("expected response to be %+v, was %+v", expected, resp) - } - return nil - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Description, func(t *testing.T) { - ctx := user.NewContext(context.Background(), user.User{UUID: userUUID}) - ctx = middleware.BuildContextWithNamespace(ctx, ns) - - - mockUserSvc := new(mocks.UserService) - mockDiscussionSvc := new(mocks.DiscussionService) - if tc.Setup != nil { - tc.Setup(ctx, mockDiscussionSvc) - } - defer mockUserSvc.AssertExpectations(t) - defer mockDiscussionSvc.AssertExpectations(t) - - mockNamespaceSvc := new(mocks.NamespaceService) - defer mockNamespaceSvc.AssertExpectations(t) - mockUserSvc.EXPECT().ValidateUser(ctx, ns, userUUID, "").Return(userID, nil) - - handler := New(mockNamespaceSvc, nil, nil, mockDiscussionSvc, nil, nil, mockUserSvc) - - got, err := handler.GetMyDiscussions(ctx, connect.NewRequest(tc.Request)) - if tc.ExpectStatus == 0 { - if err != nil { - t.Errorf("expected no error but got: %v", err) - return - } - } else { - code := connect.CodeOf(err) - if code != tc.ExpectStatus { - t.Errorf("expected handler to return Code %s, returned Code %s instead", tc.ExpectStatus.String(), code.String()) - return - } - } - if tc.PostCheck != nil { - if err := tc.PostCheck(got.Msg); err != nil { - t.Error(err) - return - } - } - }) - } -} - -func TestUserToProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - User user.User - ExpectProto *compassv1beta1.User - } - - var testCases = []testCase{ - { - Title: "should return nil if UUID is empty", - User: user.User{}, - ExpectProto: nil, - }, - { - Title: "should return fields without timestamp", - User: user.User{UUID: "uuid1", Email: "email@email.com", Provider: "provider", CreatedAt: timeDummy, UpdatedAt: timeDummy}, - ExpectProto: &compassv1beta1.User{Uuid: "uuid1", Email: "email@email.com"}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := userToProto(tc.User) - if diff := cmp.Diff(got, tc.ExpectProto, protocmp.Transform()); diff != "" { - t.Errorf("expected response to be %+v, was %+v", tc.ExpectProto, got) - } - }) - } -} - -func TestUserToFullProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - User user.User - ExpectProto *compassv1beta1.User - } - - var testCases = []testCase{ - { - Title: "should return nil if UUID is empty", - User: user.User{}, - ExpectProto: nil, - }, - { - Title: "should return without timestamp pb if timestamp is zero", - User: user.User{UUID: "uuid1", Provider: "provider"}, - ExpectProto: &compassv1beta1.User{Uuid: "uuid1", Provider: "provider"}, - }, - { - Title: "should return with timestamp pb if timestamp is not zero", - User: user.User{UUID: "uuid1", Provider: "provider", CreatedAt: timeDummy, UpdatedAt: timeDummy}, - ExpectProto: &compassv1beta1.User{Uuid: "uuid1", Provider: "provider", CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := userToFullProto(tc.User) - if diff := cmp.Diff(got, tc.ExpectProto, protocmp.Transform()); diff != "" { - t.Errorf("expected response to be %+v, was %+v", tc.ExpectProto, got) - } - }) - } -} - -func TestUserFromProto(t *testing.T) { - timeDummy := time.Date(2000, time.January, 7, 0, 0, 0, 0, time.UTC) - type testCase struct { - Title string - UserPB *compassv1beta1.User - ExpectUser user.User - } - - var testCases = []testCase{ - { - Title: "should return non empty time.Time if timestamp pb is not zero", - UserPB: &compassv1beta1.User{Uuid: "uuid1", Provider: "provider", CreatedAt: timestamppb.New(timeDummy), UpdatedAt: timestamppb.New(timeDummy)}, - ExpectUser: user.User{UUID: "uuid1", Provider: "provider", CreatedAt: timeDummy, UpdatedAt: timeDummy}, - }, - { - Title: "should return empty time.Time if timestamp pb is zero", - UserPB: &compassv1beta1.User{Uuid: "uuid1", Provider: "provider"}, - ExpectUser: user.User{UUID: "uuid1", Provider: "provider"}, - }, - } - for _, tc := range testCases { - t.Run(tc.Title, func(t *testing.T) { - - got := userFromProto(tc.UserPB) - if reflect.DeepEqual(got, tc.ExpectUser) == false { - t.Errorf("expected returned asset to be %+v, was %+v", tc.ExpectUser, got) - } - }) - } -} diff --git a/internal/config/config.go b/internal/config/config.go index fdb7c05f..8126b711 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -5,18 +5,16 @@ import ( "github.com/raystack/compass/internal/client" "github.com/raystack/compass/internal/telemetry" - esStore "github.com/raystack/compass/store/elasticsearch" "github.com/raystack/compass/store/postgres" ) // Config is the root configuration for the compass application. type Config struct { - LogLevel string `yaml:"log_level" mapstructure:"log_level" default:"info"` - Telemetry telemetry.Config `mapstructure:"telemetry"` - Elasticsearch esStore.Config `mapstructure:"elasticsearch"` - DB postgres.Config `mapstructure:"db"` - Service ServerConfig `mapstructure:"service"` - Client client.Config `mapstructure:"client"` + LogLevel string `yaml:"log_level" mapstructure:"log_level" default:"info"` + Telemetry telemetry.Config `mapstructure:"telemetry"` + DB postgres.Config `mapstructure:"db"` + Service ServerConfig `mapstructure:"service"` + Client client.Config `mapstructure:"client"` } // ServerConfig holds HTTP server configuration. diff --git a/internal/mcp/format.go b/internal/mcp/format.go deleted file mode 100644 index 1759f2f9..00000000 --- a/internal/mcp/format.go +++ /dev/null @@ -1,201 +0,0 @@ -package mcp - -import ( - "fmt" - "strings" - - "github.com/raystack/compass/core/asset" -) - -// formatAsset formats an asset as LLM-friendly markdown text. -func formatAsset(a asset.Asset) string { - var b strings.Builder - - fmt.Fprintf(&b, "## %s (%s)\n", a.Name, a.Type) - fmt.Fprintf(&b, "Service: %s | URN: %s\n", a.Service, a.URN) - - if a.Description != "" { - fmt.Fprintf(&b, "Description: %s\n", a.Description) - } - - if len(a.Owners) > 0 { - names := make([]string, 0, len(a.Owners)) - for _, o := range a.Owners { - if o.Email != "" { - names = append(names, o.Email) - } else { - names = append(names, o.UUID) - } - } - fmt.Fprintf(&b, "Owners: %s\n", strings.Join(names, ", ")) - } - - if a.URL != "" { - fmt.Fprintf(&b, "URL: %s\n", a.URL) - } - - if len(a.Labels) > 0 { - pairs := make([]string, 0, len(a.Labels)) - for k, v := range a.Labels { - pairs = append(pairs, fmt.Sprintf("%s=%s", k, v)) - } - fmt.Fprintf(&b, "Labels: %s\n", strings.Join(pairs, ", ")) - } - - formatAssetData(&b, a.Data) - - return b.String() -} - -// formatAssetData formats the Data map, extracting schema columns if present. -func formatAssetData(b *strings.Builder, data map[string]interface{}) { - if data == nil { - return - } - - // Extract schema/columns if present (common in table/topic assets) - if columns, ok := extractColumns(data); ok && len(columns) > 0 { - fmt.Fprintf(b, "\nColumns (%d):\n", len(columns)) - for _, col := range columns { - name, _ := col["name"].(string) - dataType, _ := col["data_type"].(string) - desc, _ := col["description"].(string) - - if desc != "" { - fmt.Fprintf(b, " - %s (%s): %s\n", name, dataType, desc) - } else { - fmt.Fprintf(b, " - %s (%s)\n", name, dataType) - } - } - } -} - -// extractColumns tries to find column definitions in asset data. -func extractColumns(data map[string]interface{}) ([]map[string]interface{}, bool) { - // Try common paths: data.columns, data.schema.columns - if cols, ok := data["columns"]; ok { - return toMapSlice(cols) - } - if schema, ok := data["schema"].(map[string]interface{}); ok { - if cols, ok := schema["columns"]; ok { - return toMapSlice(cols) - } - } - return nil, false -} - -func toMapSlice(v interface{}) ([]map[string]interface{}, bool) { - slice, ok := v.([]interface{}) - if !ok { - return nil, false - } - result := make([]map[string]interface{}, 0, len(slice)) - for _, item := range slice { - if m, ok := item.(map[string]interface{}); ok { - result = append(result, m) - } - } - return result, len(result) > 0 -} - -// formatSearchResult formats a search result as a compact line. -func formatSearchResult(sr asset.SearchResult) string { - var b strings.Builder - fmt.Fprintf(&b, "- **%s** (%s) — service: %s, urn: %s", sr.Title, sr.Type, sr.Service, sr.URN) - if sr.Description != "" { - desc := sr.Description - if len(desc) > 120 { - desc = desc[:120] + "..." - } - fmt.Fprintf(&b, "\n %s", desc) - } - return b.String() -} - -// formatSearchResults formats a list of search results. -func formatSearchResults(results []asset.SearchResult) string { - if len(results) == 0 { - return "No assets found." - } - - var b strings.Builder - fmt.Fprintf(&b, "Found %d assets:\n\n", len(results)) - for _, sr := range results { - b.WriteString(formatSearchResult(sr)) - b.WriteString("\n") - } - return b.String() -} - -// formatLineage formats lineage data as readable text. -func formatLineage(urn string, lineage asset.Lineage) string { - if len(lineage.Edges) == 0 { - return fmt.Sprintf("No lineage found for %s.", urn) - } - - var b strings.Builder - fmt.Fprintf(&b, "Lineage for %s (%d edges):\n\n", urn, len(lineage.Edges)) - - upstreams := make([]string, 0) - downstreams := make([]string, 0) - - for _, edge := range lineage.Edges { - if edge.Target == urn { - upstreams = append(upstreams, edge.Source) - } else if edge.Source == urn { - downstreams = append(downstreams, edge.Target) - } else { - // Transitive edges - fmt.Fprintf(&b, " %s → %s\n", edge.Source, edge.Target) - } - } - - if len(upstreams) > 0 { - b.WriteString("Upstream (sources):\n") - for _, u := range upstreams { - fmt.Fprintf(&b, " ← %s\n", u) - } - } - - if len(downstreams) > 0 { - b.WriteString("Downstream (consumers):\n") - for _, d := range downstreams { - fmt.Fprintf(&b, " → %s\n", d) - } - } - - return b.String() -} - -// formatTypes formats asset type counts. -func formatTypes(types map[asset.Type]int) string { - if len(types) == 0 { - return "No asset types found." - } - - var b strings.Builder - b.WriteString("Asset types:\n\n") - for t, count := range types { - fmt.Fprintf(&b, "- %s: %d assets\n", t, count) - } - return b.String() -} - -// formatAssets formats a list of assets as a summary list. -func formatAssets(assets []asset.Asset, total uint32) string { - if len(assets) == 0 { - return "No assets found." - } - - var b strings.Builder - if total > 0 { - fmt.Fprintf(&b, "Showing %d of %d assets:\n\n", len(assets), total) - } else { - fmt.Fprintf(&b, "Found %d assets:\n\n", len(assets)) - } - - for _, a := range assets { - fmt.Fprintf(&b, "- **%s** (%s) — service: %s, urn: %s\n", a.Name, a.Type, a.Service, a.URN) - } - return b.String() -} diff --git a/internal/mcp/handlers.go b/internal/mcp/handlers.go deleted file mode 100644 index 66aac1f2..00000000 --- a/internal/mcp/handlers.go +++ /dev/null @@ -1,127 +0,0 @@ -package mcp - -import ( - "context" - "strings" - - "github.com/mark3labs/mcp-go/mcp" - "github.com/raystack/compass/core/asset" -) - -func (s *Server) handleSearchAssets(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - text := mcp.ParseString(req, "text", "") - if text == "" { - return mcp.NewToolResultError("'text' parameter is required"), nil - } - - size := mcp.ParseInt(req, "size", 10) - - cfg := asset.SearchConfig{ - Text: strings.TrimSpace(text), - MaxResults: size, - Namespace: s.namespace, - } - - if types := mcp.ParseString(req, "types", ""); types != "" { - cfg.Filters = map[string][]string{ - "type": strings.Split(types, ","), - } - } - if services := mcp.ParseString(req, "services", ""); services != "" { - if cfg.Filters == nil { - cfg.Filters = make(map[string][]string) - } - cfg.Filters["service"] = strings.Split(services, ",") - } - - results, err := s.assetService.SearchAssets(ctx, cfg) - if err != nil { - return mcp.NewToolResultError("failed to search assets: " + err.Error()), nil - } - - return mcp.NewToolResultText(formatSearchResults(results)), nil -} - -func (s *Server) handleGetAsset(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - id := mcp.ParseString(req, "id", "") - if id == "" { - return mcp.NewToolResultError("'id' parameter is required"), nil - } - - a, err := s.assetService.GetAssetByID(ctx, id) - if err != nil { - return mcp.NewToolResultError("failed to get asset: " + err.Error()), nil - } - - return mcp.NewToolResultText(formatAsset(a)), nil -} - -func (s *Server) handleGetLineage(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - urn := mcp.ParseString(req, "urn", "") - if urn == "" { - return mcp.NewToolResultError("'urn' parameter is required"), nil - } - - direction := asset.LineageDirection(mcp.ParseString(req, "direction", "")) - if direction != "" && direction != asset.LineageDirectionUpstream && direction != asset.LineageDirectionDownstream { - return mcp.NewToolResultError("'direction' must be 'upstream', 'downstream', or empty for both"), nil - } - - level := mcp.ParseInt(req, "level", 1) - - lineage, err := s.assetService.GetLineage(ctx, urn, asset.LineageQuery{ - Level: level, - Direction: direction, - WithAttributes: true, - }) - if err != nil { - return mcp.NewToolResultError("failed to get lineage: " + err.Error()), nil - } - - return mcp.NewToolResultText(formatLineage(urn, lineage)), nil -} - -func (s *Server) handleListTypes(ctx context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) { - flt, err := asset.NewFilterBuilder().Build() - if err != nil { - return mcp.NewToolResultError("failed to build filter: " + err.Error()), nil - } - - types, err := s.assetService.GetTypes(ctx, flt) - if err != nil { - return mcp.NewToolResultError("failed to list types: " + err.Error()), nil - } - - return mcp.NewToolResultText(formatTypes(types)), nil -} - -func (s *Server) handleGetAllAssets(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - size := mcp.ParseInt(req, "size", 20) - offset := mcp.ParseInt(req, "offset", 0) - - fb := asset.NewFilterBuilder(). - Size(size). - Offset(offset) - - if types := mcp.ParseString(req, "types", ""); types != "" { - fb = fb.Types(types) - } - if services := mcp.ParseString(req, "services", ""); services != "" { - fb = fb.Services(services) - } - if q := mcp.ParseString(req, "q", ""); q != "" { - fb = fb.Q(q) - } - - flt, err := fb.Build() - if err != nil { - return mcp.NewToolResultError("invalid filter: " + err.Error()), nil - } - - assets, total, err := s.assetService.GetAllAssets(ctx, flt, true) - if err != nil { - return mcp.NewToolResultError("failed to get assets: " + err.Error()), nil - } - - return mcp.NewToolResultText(formatAssets(assets, total)), nil -} diff --git a/internal/mcp/handlers_test.go b/internal/mcp/handlers_test.go deleted file mode 100644 index b916dbbe..00000000 --- a/internal/mcp/handlers_test.go +++ /dev/null @@ -1,298 +0,0 @@ -package mcp - -import ( - "context" - "fmt" - "testing" - - "github.com/mark3labs/mcp-go/mcp" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/user" -) - -// mockAssetService is a test double for the AssetService interface. -type mockAssetService struct { - searchAssetsFunc func(ctx context.Context, cfg asset.SearchConfig) ([]asset.SearchResult, error) - getAssetByIDFunc func(ctx context.Context, id string) (asset.Asset, error) - getLineageFunc func(ctx context.Context, urn string, query asset.LineageQuery) (asset.Lineage, error) - getTypesFunc func(ctx context.Context, flt asset.Filter) (map[asset.Type]int, error) - getAllAssetsFunc func(ctx context.Context, flt asset.Filter, withTotal bool) ([]asset.Asset, uint32, error) -} - -func (m *mockAssetService) SearchAssets(ctx context.Context, cfg asset.SearchConfig) ([]asset.SearchResult, error) { - if m.searchAssetsFunc != nil { - return m.searchAssetsFunc(ctx, cfg) - } - return nil, nil -} - -func (m *mockAssetService) GetAssetByID(ctx context.Context, id string) (asset.Asset, error) { - if m.getAssetByIDFunc != nil { - return m.getAssetByIDFunc(ctx, id) - } - return asset.Asset{}, nil -} - -func (m *mockAssetService) GetLineage(ctx context.Context, urn string, query asset.LineageQuery) (asset.Lineage, error) { - if m.getLineageFunc != nil { - return m.getLineageFunc(ctx, urn, query) - } - return asset.Lineage{}, nil -} - -func (m *mockAssetService) GetTypes(ctx context.Context, flt asset.Filter) (map[asset.Type]int, error) { - if m.getTypesFunc != nil { - return m.getTypesFunc(ctx, flt) - } - return nil, nil -} - -func (m *mockAssetService) GetAllAssets(ctx context.Context, flt asset.Filter, withTotal bool) ([]asset.Asset, uint32, error) { - if m.getAllAssetsFunc != nil { - return m.getAllAssetsFunc(ctx, flt, withTotal) - } - return nil, 0, nil -} - -func newTestServer(svc *mockAssetService) *Server { - return New(svc, namespace.DefaultNamespace) -} - -func callToolRequest(args map[string]any) mcp.CallToolRequest { - return mcp.CallToolRequest{ - Params: mcp.CallToolParams{ - Arguments: args, - }, - } -} - -func TestHandleSearchAssets(t *testing.T) { - ctx := context.Background() - - t.Run("returns error when text is empty", func(t *testing.T) { - s := newTestServer(&mockAssetService{}) - result, err := s.handleSearchAssets(ctx, callToolRequest(map[string]any{})) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !result.IsError { - t.Error("expected error result") - } - }) - - t.Run("returns search results", func(t *testing.T) { - svc := &mockAssetService{ - searchAssetsFunc: func(_ context.Context, cfg asset.SearchConfig) ([]asset.SearchResult, error) { - if cfg.Text != "orders" { - t.Errorf("expected text 'orders', got '%s'", cfg.Text) - } - return []asset.SearchResult{ - {ID: "1", URN: "urn:bq:orders", Title: "orders", Type: "table", Service: "bigquery"}, - }, nil - }, - } - s := newTestServer(svc) - result, err := s.handleSearchAssets(ctx, callToolRequest(map[string]any{"text": "orders"})) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if result.IsError { - t.Error("unexpected error result") - } - text := getTextContent(result) - if text == "" { - t.Error("expected non-empty text content") - } - }) - - t.Run("passes filters correctly", func(t *testing.T) { - svc := &mockAssetService{ - searchAssetsFunc: func(_ context.Context, cfg asset.SearchConfig) ([]asset.SearchResult, error) { - if cfg.Filters["type"][0] != "table" { - t.Errorf("expected type filter 'table', got %v", cfg.Filters["type"]) - } - if cfg.Filters["service"][0] != "bigquery" { - t.Errorf("expected service filter 'bigquery', got %v", cfg.Filters["service"]) - } - return []asset.SearchResult{}, nil - }, - } - s := newTestServer(svc) - _, err := s.handleSearchAssets(ctx, callToolRequest(map[string]any{ - "text": "test", - "types": "table", - "services": "bigquery", - })) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - }) - - t.Run("returns error on service failure", func(t *testing.T) { - svc := &mockAssetService{ - searchAssetsFunc: func(_ context.Context, _ asset.SearchConfig) ([]asset.SearchResult, error) { - return nil, fmt.Errorf("connection refused") - }, - } - s := newTestServer(svc) - result, err := s.handleSearchAssets(ctx, callToolRequest(map[string]any{"text": "test"})) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !result.IsError { - t.Error("expected error result") - } - }) -} - -func TestHandleGetAsset(t *testing.T) { - ctx := context.Background() - - t.Run("returns error when id is empty", func(t *testing.T) { - s := newTestServer(&mockAssetService{}) - result, err := s.handleGetAsset(ctx, callToolRequest(map[string]any{})) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !result.IsError { - t.Error("expected error result") - } - }) - - t.Run("returns asset details", func(t *testing.T) { - svc := &mockAssetService{ - getAssetByIDFunc: func(_ context.Context, id string) (asset.Asset, error) { - return asset.Asset{ - ID: "123", - URN: "urn:bq:orders", - Name: "orders", - Type: asset.Type("table"), - Service: "bigquery", - Description: "Main orders table", - Owners: []user.User{{Email: "alice@co.com"}}, - }, nil - }, - } - s := newTestServer(svc) - result, err := s.handleGetAsset(ctx, callToolRequest(map[string]any{"id": "123"})) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - text := getTextContent(result) - if text == "" { - t.Error("expected non-empty text content") - } - }) -} - -func TestHandleGetLineage(t *testing.T) { - ctx := context.Background() - - t.Run("returns error when urn is empty", func(t *testing.T) { - s := newTestServer(&mockAssetService{}) - result, err := s.handleGetLineage(ctx, callToolRequest(map[string]any{})) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !result.IsError { - t.Error("expected error result") - } - }) - - t.Run("returns lineage", func(t *testing.T) { - svc := &mockAssetService{ - getLineageFunc: func(_ context.Context, urn string, q asset.LineageQuery) (asset.Lineage, error) { - return asset.Lineage{ - Edges: []asset.LineageEdge{ - {Source: "urn:bq:raw_orders", Target: urn}, - {Source: urn, Target: "urn:bq:order_summary"}, - }, - }, nil - }, - } - s := newTestServer(svc) - result, err := s.handleGetLineage(ctx, callToolRequest(map[string]any{"urn": "urn:bq:orders"})) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - text := getTextContent(result) - if text == "" { - t.Error("expected non-empty text content") - } - }) - - t.Run("validates direction", func(t *testing.T) { - s := newTestServer(&mockAssetService{}) - result, err := s.handleGetLineage(ctx, callToolRequest(map[string]any{ - "urn": "urn:bq:orders", - "direction": "invalid", - })) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !result.IsError { - t.Error("expected error result for invalid direction") - } - }) -} - -func TestHandleListTypes(t *testing.T) { - ctx := context.Background() - - t.Run("returns types", func(t *testing.T) { - svc := &mockAssetService{ - getTypesFunc: func(_ context.Context, _ asset.Filter) (map[asset.Type]int, error) { - return map[asset.Type]int{ - "table": 42, - "topic": 10, - }, nil - }, - } - s := newTestServer(svc) - result, err := s.handleListTypes(ctx, callToolRequest(nil)) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - text := getTextContent(result) - if text == "" { - t.Error("expected non-empty text content") - } - }) -} - -func TestHandleGetAllAssets(t *testing.T) { - ctx := context.Background() - - t.Run("returns assets with pagination", func(t *testing.T) { - svc := &mockAssetService{ - getAllAssetsFunc: func(_ context.Context, flt asset.Filter, withTotal bool) ([]asset.Asset, uint32, error) { - if !withTotal { - t.Error("expected withTotal to be true") - } - return []asset.Asset{ - {ID: "1", URN: "urn:bq:orders", Name: "orders", Type: "table", Service: "bigquery"}, - }, 100, nil - }, - } - s := newTestServer(svc) - result, err := s.handleGetAllAssets(ctx, callToolRequest(map[string]any{"size": 10})) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - text := getTextContent(result) - if text == "" { - t.Error("expected non-empty text content") - } - }) -} - -// getTextContent extracts text from the first TextContent in a CallToolResult. -func getTextContent(result *mcp.CallToolResult) string { - for _, c := range result.Content { - if tc, ok := c.(mcp.TextContent); ok { - return tc.Text - } - } - return "" -} diff --git a/internal/mcp/server.go b/internal/mcp/server.go index c11d73a1..a6a4c526 100644 --- a/internal/mcp/server.go +++ b/internal/mcp/server.go @@ -5,52 +5,30 @@ import ( "net/http" mcpserver "github.com/mark3labs/mcp-go/server" - "github.com/raystack/compass/core/asset" "github.com/raystack/compass/core/entity" "github.com/raystack/compass/core/namespace" ) -// AssetService defines the asset operations needed by the MCP server. -type AssetService interface { - SearchAssets(ctx context.Context, cfg asset.SearchConfig) ([]asset.SearchResult, error) - GetAssetByID(ctx context.Context, id string) (asset.Asset, error) - GetLineage(ctx context.Context, urn string, query asset.LineageQuery) (asset.Lineage, error) - GetTypes(ctx context.Context, flt asset.Filter) (map[asset.Type]int, error) - GetAllAssets(ctx context.Context, flt asset.Filter, withTotal bool) ([]asset.Asset, uint32, error) -} - -// EntityServiceV2 defines the v2 entity operations for MCP tools. -type EntityServiceV2 interface { +// EntityService defines entity operations needed by the MCP server. +type EntityService interface { Search(ctx context.Context, cfg entity.SearchConfig) ([]entity.SearchResult, error) GetContext(ctx context.Context, ns *namespace.Namespace, urn string, depth int) (*entity.ContextGraph, error) GetImpact(ctx context.Context, ns *namespace.Namespace, urn string, depth int) ([]entity.Edge, error) } -// Server is the MCP server that exposes Compass catalog as AI-agent tools. +// Server is the MCP server that exposes Compass as AI-agent tools. type Server struct { - assetService AssetService - entityService EntityServiceV2 + entityService EntityService namespace *namespace.Namespace mcpServer *mcpserver.MCPServer httpServer *mcpserver.StreamableHTTPServer } -// Option configures the MCP server. -type Option func(*Server) - -// WithEntityService adds the v2 entity service for new MCP tools. -func WithEntityService(svc EntityServiceV2) Option { - return func(s *Server) { s.entityService = svc } -} - -// New creates a new MCP server with the given dependencies. -func New(assetSvc AssetService, ns *namespace.Namespace, opts ...Option) *Server { +// New creates a new MCP server. +func New(entitySvc EntityService, ns *namespace.Namespace) *Server { s := &Server{ - assetService: assetSvc, - namespace: ns, - } - for _, opt := range opts { - opt(s) + entityService: entitySvc, + namespace: ns, } mcpSrv := mcpserver.NewMCPServer( @@ -59,14 +37,6 @@ func New(assetSvc AssetService, ns *namespace.Namespace, opts ...Option) *Server mcpserver.WithToolCapabilities(false), ) - // v1 asset tools (retained) - mcpSrv.AddTool(searchAssetsTool(), s.handleSearchAssets) - mcpSrv.AddTool(getAssetTool(), s.handleGetAsset) - mcpSrv.AddTool(getLineageTool(), s.handleGetLineage) - mcpSrv.AddTool(listTypesTool(), s.handleListTypes) - mcpSrv.AddTool(getAllAssetsTool(), s.handleGetAllAssets) - - // v2 entity tools mcpSrv.AddTool(searchEntitiesTool(), s.handleSearchEntities) mcpSrv.AddTool(getContextTool(), s.handleGetContext) mcpSrv.AddTool(impactAnalysisTool(), s.handleImpact) @@ -77,7 +47,7 @@ func New(assetSvc AssetService, ns *namespace.Namespace, opts ...Option) *Server return s } -// Handler returns an http.Handler for mounting the MCP server on an existing mux. +// Handler returns an http.Handler for mounting the MCP server. func (s *Server) Handler() http.Handler { return s.httpServer } diff --git a/internal/mcp/server_test.go b/internal/mcp/server_test.go deleted file mode 100644 index 112ca107..00000000 --- a/internal/mcp/server_test.go +++ /dev/null @@ -1,229 +0,0 @@ -package mcp - -import ( - "context" - "strings" - "testing" - - mcpclient "github.com/mark3labs/mcp-go/client" - "github.com/mark3labs/mcp-go/mcp" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/core/user" -) - -// TestMCPEndToEnd tests the full MCP flow: initialize → list tools → call tools -// using the in-process transport (no network, but exercises the full mcp-go stack). -func TestMCPEndToEnd(t *testing.T) { - svc := &mockAssetService{ - searchAssetsFunc: func(_ context.Context, cfg asset.SearchConfig) ([]asset.SearchResult, error) { - return []asset.SearchResult{ - {ID: "1", URN: "urn:bq:dataset.orders", Title: "orders", Type: "table", Service: "bigquery", Description: "Main orders table"}, - {ID: "2", URN: "urn:bq:dataset.customers", Title: "customers", Type: "table", Service: "bigquery", Description: "Customer records"}, - }, nil - }, - getAssetByIDFunc: func(_ context.Context, id string) (asset.Asset, error) { - return asset.Asset{ - ID: "1", - URN: "urn:bq:dataset.orders", - Name: "orders", - Type: "table", - Service: "bigquery", - Description: "Main orders table with all customer transactions", - Owners: []user.User{{Email: "alice@company.com"}, {Email: "bob@company.com"}}, - Data: map[string]interface{}{ - "columns": []interface{}{ - map[string]interface{}{"name": "order_id", "data_type": "INTEGER", "description": "Primary key"}, - map[string]interface{}{"name": "customer_id", "data_type": "INTEGER", "description": "FK to customers"}, - map[string]interface{}{"name": "amount", "data_type": "FLOAT", "description": "Order total in USD"}, - }, - }, - }, nil - }, - getLineageFunc: func(_ context.Context, urn string, q asset.LineageQuery) (asset.Lineage, error) { - return asset.Lineage{ - Edges: []asset.LineageEdge{ - {Source: "urn:bq:raw_orders", Target: urn}, - {Source: urn, Target: "urn:bq:order_summary"}, - }, - }, nil - }, - getTypesFunc: func(_ context.Context, _ asset.Filter) (map[asset.Type]int, error) { - return map[asset.Type]int{ - "table": 42, - "topic": 15, - "dashboard": 8, - }, nil - }, - getAllAssetsFunc: func(_ context.Context, flt asset.Filter, _ bool) ([]asset.Asset, uint32, error) { - return []asset.Asset{ - {ID: "1", URN: "urn:bq:dataset.orders", Name: "orders", Type: "table", Service: "bigquery"}, - {ID: "2", URN: "urn:bq:dataset.customers", Name: "customers", Type: "table", Service: "bigquery"}, - }, 100, nil - }, - } - - srv := New(svc, namespace.DefaultNamespace) - ctx := context.Background() - - // Create in-process MCP client (exercises the full mcp-go protocol stack) - client, err := mcpclient.NewInProcessClient(srv.mcpServer) - if err != nil { - t.Fatalf("failed to create client: %v", err) - } - defer client.Close() - - if err := client.Start(ctx); err != nil { - t.Fatalf("failed to start client: %v", err) - } - - // Step 1: Initialize - initResult, err := client.Initialize(ctx, mcp.InitializeRequest{}) - if err != nil { - t.Fatalf("initialize failed: %v", err) - } - t.Logf("Server: %s v%s", initResult.ServerInfo.Name, initResult.ServerInfo.Version) - - if initResult.ServerInfo.Name != "compass" { - t.Errorf("expected server name 'compass', got '%s'", initResult.ServerInfo.Name) - } - - // Step 2: List tools - tools, err := client.ListTools(ctx, mcp.ListToolsRequest{}) - if err != nil { - t.Fatalf("list tools failed: %v", err) - } - t.Logf("Available tools (%d):", len(tools.Tools)) - for _, tool := range tools.Tools { - t.Logf(" - %s: %s", tool.Name, tool.Description) - } - - expectedTools := []string{"search_assets", "get_asset", "get_lineage", "list_types", "get_all_assets"} - if len(tools.Tools) != len(expectedTools) { - t.Fatalf("expected %d tools, got %d", len(expectedTools), len(tools.Tools)) - } - toolNames := make(map[string]bool) - for _, tool := range tools.Tools { - toolNames[tool.Name] = true - } - for _, name := range expectedTools { - if !toolNames[name] { - t.Errorf("missing tool: %s", name) - } - } - - // Step 3: Call search_assets - t.Run("search_assets", func(t *testing.T) { - result, err := client.CallTool(ctx, mcp.CallToolRequest{ - Params: mcp.CallToolParams{ - Name: "search_assets", - Arguments: map[string]any{"text": "orders"}, - }, - }) - if err != nil { - t.Fatalf("call tool failed: %v", err) - } - text := extractText(result) - t.Logf("Result:\n%s", text) - - if !strings.Contains(text, "orders") { - t.Error("expected result to contain 'orders'") - } - if !strings.Contains(text, "Found 2 assets") { - t.Error("expected result to mention 2 assets found") - } - }) - - // Step 4: Call get_asset - t.Run("get_asset", func(t *testing.T) { - result, err := client.CallTool(ctx, mcp.CallToolRequest{ - Params: mcp.CallToolParams{ - Name: "get_asset", - Arguments: map[string]any{"id": "urn:bq:dataset.orders"}, - }, - }) - if err != nil { - t.Fatalf("call tool failed: %v", err) - } - text := extractText(result) - t.Logf("Result:\n%s", text) - - if !strings.Contains(text, "orders") { - t.Error("expected result to contain 'orders'") - } - if !strings.Contains(text, "alice@company.com") { - t.Error("expected result to contain owner email") - } - if !strings.Contains(text, "order_id") { - t.Error("expected result to contain column info") - } - }) - - // Step 5: Call get_lineage - t.Run("get_lineage", func(t *testing.T) { - result, err := client.CallTool(ctx, mcp.CallToolRequest{ - Params: mcp.CallToolParams{ - Name: "get_lineage", - Arguments: map[string]any{"urn": "urn:bq:dataset.orders"}, - }, - }) - if err != nil { - t.Fatalf("call tool failed: %v", err) - } - text := extractText(result) - t.Logf("Result:\n%s", text) - - if !strings.Contains(text, "raw_orders") { - t.Error("expected result to contain upstream 'raw_orders'") - } - if !strings.Contains(text, "order_summary") { - t.Error("expected result to contain downstream 'order_summary'") - } - }) - - // Step 6: Call list_types - t.Run("list_types", func(t *testing.T) { - result, err := client.CallTool(ctx, mcp.CallToolRequest{ - Params: mcp.CallToolParams{ - Name: "list_types", - }, - }) - if err != nil { - t.Fatalf("call tool failed: %v", err) - } - text := extractText(result) - t.Logf("Result:\n%s", text) - - if !strings.Contains(text, "table") { - t.Error("expected result to contain 'table'") - } - }) - - // Step 7: Call get_all_assets - t.Run("get_all_assets", func(t *testing.T) { - result, err := client.CallTool(ctx, mcp.CallToolRequest{ - Params: mcp.CallToolParams{ - Name: "get_all_assets", - Arguments: map[string]any{"size": 10}, - }, - }) - if err != nil { - t.Fatalf("call tool failed: %v", err) - } - text := extractText(result) - t.Logf("Result:\n%s", text) - - if !strings.Contains(text, "Showing 2 of 100 assets") { - t.Error("expected result to show pagination info") - } - }) -} - -func extractText(result *mcp.CallToolResult) string { - for _, c := range result.Content { - if tc, ok := c.(mcp.TextContent); ok { - return tc.Text - } - } - return "" -} diff --git a/internal/mcp/tools.go b/internal/mcp/tools.go deleted file mode 100644 index 543d7413..00000000 --- a/internal/mcp/tools.go +++ /dev/null @@ -1,77 +0,0 @@ -package mcp - -import ( - "github.com/mark3labs/mcp-go/mcp" -) - -func searchAssetsTool() mcp.Tool { - return mcp.NewTool("search_assets", - mcp.WithDescription("Search for data assets in the Compass catalog. Returns matching tables, topics, dashboards, and other assets."), - mcp.WithString("text", - mcp.Required(), - mcp.Description("Search query text"), - ), - mcp.WithString("types", - mcp.Description("Comma-separated asset types to filter by (e.g. table,topic,dashboard)"), - ), - mcp.WithString("services", - mcp.Description("Comma-separated services to filter by (e.g. bigquery,kafka)"), - ), - mcp.WithNumber("size", - mcp.Description("Maximum number of results to return (default: 10)"), - ), - ) -} - -func getAssetTool() mcp.Tool { - return mcp.NewTool("get_asset", - mcp.WithDescription("Get full details of a data asset by its ID (UUID) or URN. Returns schema, owners, description, labels, and metadata."), - mcp.WithString("id", - mcp.Required(), - mcp.Description("Asset ID (UUID) or URN"), - ), - ) -} - -func getLineageTool() mcp.Tool { - return mcp.NewTool("get_lineage", - mcp.WithDescription("Get the lineage graph for a data asset. Shows upstream sources and downstream consumers."), - mcp.WithString("urn", - mcp.Required(), - mcp.Description("URN of the asset to get lineage for"), - ), - mcp.WithString("direction", - mcp.Description("Lineage direction: upstream, downstream, or both (default: both)"), - ), - mcp.WithNumber("level", - mcp.Description("Number of hops to traverse (default: 1)"), - ), - ) -} - -func listTypesTool() mcp.Tool { - return mcp.NewTool("list_types", - mcp.WithDescription("List all asset types in the catalog with their counts."), - ) -} - -func getAllAssetsTool() mcp.Tool { - return mcp.NewTool("get_all_assets", - mcp.WithDescription("Browse and filter data assets in the catalog with pagination."), - mcp.WithString("types", - mcp.Description("Comma-separated asset types to filter by (e.g. table,topic)"), - ), - mcp.WithString("services", - mcp.Description("Comma-separated services to filter by (e.g. bigquery,kafka)"), - ), - mcp.WithString("q", - mcp.Description("Query string to filter assets by name"), - ), - mcp.WithNumber("size", - mcp.Description("Number of results per page (default: 20)"), - ), - mcp.WithNumber("offset", - mcp.Description("Offset for pagination (default: 0)"), - ), - ) -} diff --git a/internal/server/bootstrap.go b/internal/server/bootstrap.go index b7cf7ba7..ce7aeedf 100644 --- a/internal/server/bootstrap.go +++ b/internal/server/bootstrap.go @@ -8,18 +8,13 @@ import ( "os" "strings" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/discussion" "github.com/raystack/compass/core/entity" "github.com/raystack/compass/core/namespace" "github.com/raystack/compass/core/star" - "github.com/raystack/compass/core/tag" "github.com/raystack/compass/core/user" - "github.com/raystack/compass/handler" "github.com/raystack/compass/internal/config" compassmcp "github.com/raystack/compass/internal/mcp" "github.com/raystack/compass/internal/telemetry" - esStore "github.com/raystack/compass/store/elasticsearch" "github.com/raystack/compass/store/postgres" ) @@ -54,11 +49,6 @@ func Start(ctx context.Context, cfg *config.Config, version string) error { } defer otelCleanup() - esClient, err := initElasticsearch(cfg.Elasticsearch) - if err != nil { - return err - } - pgClient, err := initPostgres(cfg.DB) if err != nil { return err @@ -71,55 +61,24 @@ func Start(ctx context.Context, cfg *config.Config, version string) error { slog.Warn("db closed") }() - // init tag - tagRepository, err := postgres.NewTagRepository(pgClient) - if err != nil { - return fmt.Errorf("failed to create new tag repository: %w", err) - } - tagTemplateRepository, err := postgres.NewTagTemplateRepository(pgClient) - if err != nil { - return fmt.Errorf("failed to create new tag template repository: %w", err) - } - tagTemplateService := tag.NewTemplateService(tagTemplateRepository) - tagService := tag.NewService(tagRepository, tagTemplateService) - // init user userRepository, err := postgres.NewUserRepository(pgClient) if err != nil { - return fmt.Errorf("failed to create new user repository: %w", err) + return fmt.Errorf("failed to create user repository: %w", err) } userService := user.NewService(userRepository) - assetRepository, err := postgres.NewAssetRepository(pgClient, userRepository, 0, cfg.Service.Identity.ProviderDefaultName) - if err != nil { - return fmt.Errorf("failed to create new asset repository: %w", err) - } - discoveryRepository := esStore.NewDiscoveryRepository(esClient) - lineageRepository, err := postgres.NewLineageRepository(pgClient) - if err != nil { - return fmt.Errorf("failed to create new lineage repository: %w", err) - } - assetService := asset.NewService(assetRepository, discoveryRepository, lineageRepository) - - // init discussion - discussionRepository, err := postgres.NewDiscussionRepository(pgClient, 0) - if err != nil { - return fmt.Errorf("failed to create new discussion repository: %w", err) - } - discussionService := discussion.NewService(discussionRepository) - // init star starRepository, err := postgres.NewStarRepository(pgClient) if err != nil { - return fmt.Errorf("failed to create new star repository: %w", err) + return fmt.Errorf("failed to create star repository: %w", err) } starService := star.NewService(starRepository) // init namespace - namespaceService := namespace.NewService(postgres.NewNamespaceRepository(pgClient), discoveryRepository) + namespaceService := namespace.NewService(postgres.NewNamespaceRepository(pgClient), nil) - // init entity v2 system (runs alongside existing asset system) - // All search is Postgres-native: tsvector + pg_trgm + pgvector. No ES dependency. + // init entity system (Postgres-native: tsvector + pg_trgm + pgvector) entityRepo, err := postgres.NewEntityRepository(pgClient) if err != nil { return fmt.Errorf("failed to create entity repository: %w", err) @@ -134,24 +93,18 @@ func Start(ctx context.Context, cfg *config.Config, version string) error { } entityService := entity.NewService(entityRepo, edgeRepo, entitySearchRepo) - // init MCP server (v1 asset tools + v2 entity tools) - mcpServer := compassmcp.New(assetService, namespace.DefaultNamespace, - compassmcp.WithEntityService(entityService), - ) + // init MCP server + mcpServer := compassmcp.New(entityService, namespace.DefaultNamespace) return Serve( ctx, cfg.Service, mcpServer, namespaceService, - assetService, starService, - discussionService, - tagService, - tagTemplateService, userService, - handler.WithEntityService(entityService), - handler.WithEdgeService(edgeRepo), + entityService, + edgeRepo, ) } @@ -160,11 +113,6 @@ func Migrate(ctx context.Context, cfg *config.Config, version string) error { InitLogger(cfg.LogLevel) slog.InfoContext(ctx, "compass is migrating", "version", version) - esClient, err := initElasticsearch(cfg.Elasticsearch) - if err != nil { - return err - } - pgClient, err := initPostgres(cfg.DB) if err != nil { return err @@ -177,9 +125,7 @@ func Migrate(ctx context.Context, cfg *config.Config, version string) error { } // create default namespace - nsService := namespace.NewService( - postgres.NewNamespaceRepository(pgClient), - esStore.NewDiscoveryRepository(esClient)) + nsService := namespace.NewService(postgres.NewNamespaceRepository(pgClient), nil) if _, err = nsService.GetByID(ctx, namespace.DefaultNamespace.ID); errors.Is(err, namespace.ErrNotFound) { if _, err := nsService.MigrateDefault(ctx); err != nil { return fmt.Errorf("problem with migration %w", err) @@ -210,19 +156,6 @@ func MigrateDown(ctx context.Context, cfg *config.Config, version string) error return nil } -func initElasticsearch(cfg esStore.Config) (*esStore.Client, error) { - esClient, err := esStore.NewClient(cfg) - if err != nil { - return nil, fmt.Errorf("failed to create new elasticsearch client: %w", err) - } - got, err := esClient.Init() - if err != nil { - return nil, fmt.Errorf("failed to establish connection to elasticsearch: %w", err) - } - slog.Info("connected to elasticsearch", "info", got) - return esClient, nil -} - func initPostgres(cfg postgres.Config) (*postgres.Client, error) { pgClient, err := postgres.NewClient(cfg) if err != nil { diff --git a/internal/server/server.go b/internal/server/server.go index a08e6aa0..5f3b7216 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -28,25 +28,19 @@ func Serve( cfg config.ServerConfig, mcpServer *compassmcp.Server, namespaceService handler.NamespaceService, - assetService handler.AssetService, starService handler.StarService, - discussionService handler.DiscussionService, - tagService handler.TagService, - tagTemplateService handler.TagTemplateService, userService handler.UserService, - handlerOpts ...handler.HandlerOption, + entityService handler.EntityServiceV2, + edgeService handler.EdgeServiceV2, ) error { logger := slog.Default().With("component", "server") v1beta1Handler := handler.New( namespaceService, - assetService, starService, - discussionService, - tagService, - tagTemplateService, userService, - handlerOpts..., + entityService, + edgeService, ) // Build interceptor chain diff --git a/store/elasticsearch/discovery_repository.go b/store/elasticsearch/discovery_repository.go deleted file mode 100644 index ca019f29..00000000 --- a/store/elasticsearch/discovery_repository.go +++ /dev/null @@ -1,183 +0,0 @@ -package elasticsearch - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "github.com/raystack/compass/core/namespace" - "io" - "strings" - - "github.com/raystack/compass/core/asset" -) - -// DiscoveryRepository implements discovery.Repository -// with elasticsearch as the backing store. -type DiscoveryRepository struct { - cli *Client - refresh string -} - -type AssetModel struct { - asset.Asset - NamespaceID string `json:"namespace_id"` -} - -func NewDiscoveryRepository(cli *Client, opts ...func(*DiscoveryRepository)) *DiscoveryRepository { - repo := &DiscoveryRepository{ - cli: cli, - refresh: "false", - } - for _, opt := range opts { - opt(repo) - } - return repo -} - -// WithInstantRefresh refresh the affected shards to make insert operations visible to search instantly -func WithInstantRefresh() func(*DiscoveryRepository) { - return func(repository *DiscoveryRepository) { - repository.refresh = "true" - } -} - -func (repo *DiscoveryRepository) CreateNamespace(ctx context.Context, ns *namespace.Namespace) error { - // check if index exists - if exists, err := repo.cli.IndexExists(ctx, ns); err != nil { - return err - } else if !exists { - // doesn't exist yet, create one - if err := repo.cli.CreateIndex(ctx, BuildIndexNameFromNamespace(ns), DefaultShardCountPerIndex); err != nil { - return err - } - } - // create alias over index, doesn't matter if its shared or dedicated - return repo.cli.CreateIdxAlias(ctx, ns) -} - -func (repo *DiscoveryRepository) Upsert(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset) error { - if ast.ID == "" { - return asset.ErrEmptyID - } - if !ast.Type.IsValid() { - return asset.ErrUnknownType - } - - body, err := repo.createUpsertBody(ns, ast) - if err != nil { - return asset.DiscoveryError{Err: fmt.Errorf("error serialising payload: %w", err)} - } - res, err := repo.cli.client.Bulk( - body, - repo.cli.client.Bulk.WithContext(ctx), - repo.cli.client.Bulk.WithRefresh(repo.refresh), - ) - if err != nil { - return asset.DiscoveryError{Err: err} - } - defer res.Body.Close() - if res.IsError() { - return asset.DiscoveryError{Err: fmt.Errorf("error response from elasticsearch: %s", errorReasonFromResponse(res))} - } - return nil -} - -func (repo *DiscoveryRepository) DeleteByID(ctx context.Context, ns *namespace.Namespace, assetID string) error { - if assetID == "" { - return asset.ErrEmptyID - } - - return repo.deleteWithQuery(ctx, strings.NewReader(fmt.Sprintf(`{"query":{"term":{"_id": "%s"}}}`, assetID))) -} - -func (repo *DiscoveryRepository) DeleteByURN(ctx context.Context, ns *namespace.Namespace, assetURN string) error { - if assetURN == "" { - return asset.ErrEmptyURN - } - - return repo.deleteWithQuery(ctx, strings.NewReader(fmt.Sprintf(`{"query":{"term":{"urn.keyword": "%s"}}}`, assetURN))) -} - -// SoftDeleteByURN marks an asset as deleted in the ES index using UpdateByQuery -func (repo *DiscoveryRepository) SoftDeleteByURN(ctx context.Context, ns *namespace.Namespace, assetURN string) error { - if assetURN == "" { - return asset.ErrEmptyURN - } - - body := fmt.Sprintf(`{ - "script": { - "source": "ctx._source.is_deleted = true", - "lang": "painless" - }, - "query": { - "term": { - "urn.keyword": "%s" - } - } - }`, assetURN) - - res, err := repo.cli.client.UpdateByQuery( - []string{defaultSearchIndexAlias}, - repo.cli.client.UpdateByQuery.WithBody(strings.NewReader(body)), - repo.cli.client.UpdateByQuery.WithContext(ctx), - repo.cli.client.UpdateByQuery.WithRefresh(true), - repo.cli.client.UpdateByQuery.WithIgnoreUnavailable(true), - ) - if err != nil { - return asset.DiscoveryError{Err: fmt.Errorf("error soft deleting asset: %w", err)} - } - defer res.Body.Close() - if res.IsError() { - return asset.DiscoveryError{Err: fmt.Errorf("error response from elasticsearch: %s", errorReasonFromResponse(res))} - } - - return nil -} - -func (repo *DiscoveryRepository) deleteWithQuery(ctx context.Context, qry io.Reader) error { - res, err := repo.cli.client.DeleteByQuery( - []string{defaultSearchIndexAlias}, - qry, - repo.cli.client.DeleteByQuery.WithContext(ctx), - repo.cli.client.DeleteByQuery.WithRefresh(true), - repo.cli.client.DeleteByQuery.WithIgnoreUnavailable(true), - ) - if err != nil { - return asset.DiscoveryError{Err: fmt.Errorf("error deleting asset: %w", err)} - } - defer res.Body.Close() - if res.IsError() { - return asset.DiscoveryError{Err: fmt.Errorf("error response from elasticsearch: %s", errorReasonFromResponse(res))} - } - - return nil -} - -func (repo *DiscoveryRepository) createUpsertBody(ns *namespace.Namespace, ast *asset.Asset) (io.Reader, error) { - payload := bytes.NewBuffer(nil) - err := repo.writeInsertAction(payload, ns, ast) - if err != nil { - return nil, fmt.Errorf("createBulkInsertPayload: %w", err) - } - - err = json.NewEncoder(payload).Encode(AssetModel{ - Asset: *ast, - NamespaceID: ns.ID.String(), - }) - if err != nil { - return nil, fmt.Errorf("error serialising asset: %w", err) - } - return payload, nil -} - -func (repo *DiscoveryRepository) writeInsertAction(w io.Writer, ns *namespace.Namespace, ast *asset.Asset) error { - action := map[string]interface{}{ - "index": map[string]interface{}{ - "_index": BuildAliasNameFromNamespace(ns), - "_id": ast.ID, - }, - } - - return json.NewEncoder(w).Encode(action) -} diff --git a/store/elasticsearch/discovery_repository_test.go b/store/elasticsearch/discovery_repository_test.go deleted file mode 100644 index a6023a22..00000000 --- a/store/elasticsearch/discovery_repository_test.go +++ /dev/null @@ -1,315 +0,0 @@ -package elasticsearch_test - -import ( - "context" - "encoding/json" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "strings" - "testing" - "time" - - "github.com/raystack/compass/core/asset" - store "github.com/raystack/compass/store/elasticsearch" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -type testTotalHits struct { - Value int64 `json:"value"` - Relation string `json:"relation"` -} - -func TestDiscoveryRepositoryUpsert(t *testing.T) { - var ( - ctx = context.Background() - ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.DedicatedState, - Metadata: nil, - } - indexAlias = store.BuildAliasNameFromNamespace(ns) - ) - - t.Run("should return error if id empty", func(t *testing.T) { - cli, err := esTestServer.NewClient() - require.NoError(t, err) - esClient, err := store.NewClient( - store.Config{}, - store.WithClient(cli), - ) - require.NoError(t, err) - - repo := store.NewDiscoveryRepository(esClient) - err = repo.CreateNamespace(ctx, ns) - assert.NoError(t, err) - - err = repo.Upsert(ctx, ns, &asset.Asset{ - ID: "", - Type: asset.TypeTable, - Service: indexAlias, - }) - assert.ErrorIs(t, err, asset.ErrEmptyID) - }) - - t.Run("should return error if type is not known", func(t *testing.T) { - cli, err := esTestServer.NewClient() - require.NoError(t, err) - esClient, err := store.NewClient( - store.Config{}, - store.WithClient(cli), - ) - require.NoError(t, err) - - repo := store.NewDiscoveryRepository(esClient) - err = repo.CreateNamespace(ctx, ns) - assert.NoError(t, err) - - err = repo.Upsert(ctx, ns, &asset.Asset{ - ID: "sample-id", - Type: asset.Type("unknown-type"), - Service: indexAlias, - }) - assert.ErrorIs(t, err, asset.ErrUnknownType) - }) - - t.Run("should insert asset to the correct index by its service", func(t *testing.T) { - ast := &asset.Asset{ - ID: "sample-id", - URN: "sample-urn", - Type: asset.TypeTable, - Service: indexAlias, - Name: "sample-name", - Description: "sample-description", - Data: map[string]interface{}{ - "foo": map[string]interface{}{ - "company": "raystack", - }, - }, - Labels: map[string]string{ - "bar": "foo", - }, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - } - - cli, err := esTestServer.NewClient() - require.NoError(t, err) - esClient, err := store.NewClient( - store.Config{}, - store.WithClient(cli), - ) - require.NoError(t, err) - - repo := store.NewDiscoveryRepository(esClient) - err = repo.CreateNamespace(ctx, ns) - assert.NoError(t, err) - err = repo.Upsert(ctx, ns, ast) - assert.NoError(t, err) - - res, err := cli.Get(indexAlias, ast.ID) - require.NoError(t, err) - require.False(t, res.IsError()) - - var payload struct { - Source asset.Asset `json:"_source"` - } - err = json.NewDecoder(res.Body).Decode(&payload) - require.NoError(t, err) - - assert.Equal(t, ast.ID, payload.Source.ID) - assert.Equal(t, ast.URN, payload.Source.URN) - assert.Equal(t, ast.Type, payload.Source.Type) - assert.Equal(t, ast.Service, payload.Source.Service) - assert.Equal(t, ast.Name, payload.Source.Name) - assert.Equal(t, ast.Description, payload.Source.Description) - assert.Equal(t, ast.Data, payload.Source.Data) - assert.Equal(t, ast.Labels, payload.Source.Labels) - assert.WithinDuration(t, ast.CreatedAt, payload.Source.CreatedAt, 0) - assert.WithinDuration(t, ast.UpdatedAt, payload.Source.UpdatedAt, 0) - }) - - t.Run("should update existing asset if ID exists", func(t *testing.T) { - existingAsset := &asset.Asset{ - ID: "existing-id", - URN: "existing-urn", - Type: asset.TypeTable, - Service: indexAlias, - Name: "existing-name", - Description: "existing-description", - } - newAsset := existingAsset - newAsset.URN = "new-urn" - newAsset.Name = "new-name" - newAsset.Description = "new-description" - - cli, err := esTestServer.NewClient() - require.NoError(t, err) - esClient, err := store.NewClient( - store.Config{}, - store.WithClient(cli), - ) - require.NoError(t, err) - - repo := store.NewDiscoveryRepository(esClient) - err = repo.CreateNamespace(ctx, ns) - assert.NoError(t, err) - - err = repo.Upsert(ctx, ns, existingAsset) - assert.NoError(t, err) - err = repo.Upsert(ctx, ns, newAsset) - assert.NoError(t, err) - - res, err := cli.Get(indexAlias, existingAsset.ID) - require.NoError(t, err) - require.False(t, res.IsError()) - - var payload struct { - Source asset.Asset `json:"_source"` - } - err = json.NewDecoder(res.Body).Decode(&payload) - require.NoError(t, err) - - assert.Equal(t, existingAsset.ID, payload.Source.ID) - assert.Equal(t, newAsset.URN, payload.Source.URN) - assert.Equal(t, newAsset.Name, payload.Source.Name) - assert.Equal(t, newAsset.Description, payload.Source.Description) - }) -} - -func TestDiscoveryRepositoryDeleteByID(t *testing.T) { - nsID, _ := uuid.NewUUID() - var ( - ctx = context.Background() - bigqueryService = "bigquery-test" - ns = &namespace.Namespace{ - ID: nsID, - Name: "umbrella", - State: namespace.SharedState, - Metadata: nil, - } - ) - - t.Run("should return error if id empty", func(t *testing.T) { - cli, err := esTestServer.NewClient() - require.NoError(t, err) - esClient, err := store.NewClient( - store.Config{}, - store.WithClient(cli), - ) - require.NoError(t, err) - - repo := store.NewDiscoveryRepository(esClient) - err = repo.CreateNamespace(ctx, ns) - assert.NoError(t, err) - - err = repo.DeleteByID(ctx, ns, "") - assert.ErrorIs(t, err, asset.ErrEmptyID) - }) - - t.Run("should not return error on success", func(t *testing.T) { - ast := &asset.Asset{ - ID: "delete-id", - Type: asset.TypeTable, - Service: bigqueryService, - URN: "some-urn", - } - - cli, err := esTestServer.NewClient() - require.NoError(t, err) - esClient, err := store.NewClient( - store.Config{}, - store.WithClient(cli), - ) - require.NoError(t, err) - - repo := store.NewDiscoveryRepository(esClient) - err = repo.CreateNamespace(ctx, ns) - assert.NoError(t, err) - - err = repo.Upsert(ctx, ns, ast) - require.NoError(t, err) - - err = repo.DeleteByID(ctx, ns, ast.ID) - assert.NoError(t, err) - - res, err := cli.Search( - cli.Search.WithBody(strings.NewReader(`{"query":{"term":{"_id": "delete-id"}}}`)), - cli.Search.WithIndex("_all"), - ) - require.NoError(t, err) - assert.False(t, res.IsError()) - - var body struct { - Hits struct { - Total testTotalHits `json:"total"` - } `json:"hits"` - } - require.NoError(t, json.NewDecoder(res.Body).Decode(&body)) - - assert.Equal(t, int64(0), body.Hits.Total.Value) - }) -} - -func TestDiscoveryRepositoryDeleteByURN(t *testing.T) { - nsID, _ := uuid.NewUUID() - var ( - ctx = context.Background() - bigqueryService = "bigquery-test" - ns = &namespace.Namespace{ - ID: nsID, - Name: "umbrella", - State: namespace.SharedState, - Metadata: nil, - } - ) - - cli, err := esTestServer.NewClient() - require.NoError(t, err) - - esClient, err := store.NewClient( - store.Config{}, store.WithClient(cli), - ) - require.NoError(t, err) - - repo := store.NewDiscoveryRepository(esClient) - err = repo.CreateNamespace(ctx, ns) - assert.NoError(t, err) - - t.Run("should return error if the given urn is empty", func(t *testing.T) { - err = repo.DeleteByURN(ctx, ns, "") - assert.ErrorIs(t, err, asset.ErrEmptyURN) - }) - - t.Run("should not return error on success", func(t *testing.T) { - ast := &asset.Asset{ - ID: "delete-id", - Type: asset.TypeTable, - Service: bigqueryService, - URN: "some-urn", - } - - err = repo.Upsert(ctx, ns, ast) - require.NoError(t, err) - - err = repo.DeleteByURN(ctx, ns, ast.URN) - assert.NoError(t, err) - - res, err := cli.Search( - cli.Search.WithBody(strings.NewReader(`{"query":{"term":{"urn.keyword": "some-urn"}}}`)), - cli.Search.WithIndex("_all"), - ) - require.NoError(t, err) - assert.False(t, res.IsError()) - - var body struct { - Hits struct { - Total testTotalHits `json:"total"` - } `json:"hits"` - } - require.NoError(t, json.NewDecoder(res.Body).Decode(&body)) - - assert.Equal(t, int64(0), body.Hits.Total.Value) - }) -} diff --git a/store/elasticsearch/discovery_search_repository.go b/store/elasticsearch/discovery_search_repository.go deleted file mode 100644 index bbaaa51f..00000000 --- a/store/elasticsearch/discovery_search_repository.go +++ /dev/null @@ -1,527 +0,0 @@ -package elasticsearch - -import ( - "context" - "encoding/json" - "fmt" - "io" - "strings" - - "github.com/raystack/compass/core/asset" -) - -const ( - defaultMaxResults = 200 - defaultMinScore = 0.01 - defaultFunctionScoreQueryScoreMode = "sum" - suggesterName = "name-phrase-suggest" -) - -var defaultIncludedFields = []string{"id", "namespace_id", "urn", "type", "service", "name", "description", "data", "labels", "created_at", "updated_at"} - -// Search the asset store -func (repo *DiscoveryRepository) Search(ctx context.Context, cfg asset.SearchConfig) ([]asset.SearchResult, error) { - if cfg.Namespace == nil { - return nil, asset.DiscoveryError{Err: fmt.Errorf("namespace cannot be empty")} - } - maxResults := cfg.MaxResults - if maxResults <= 0 { - maxResults = defaultMaxResults - } - offset := cfg.Offset - if offset < 0 { - offset = 0 - } - - includedFields := defaultIncludedFields - if len(cfg.IncludeFields) > 0 { - includedFields = cfg.IncludeFields - } - - query, err := repo.buildQuery(ctx, cfg) - if err != nil { - return nil, asset.DiscoveryError{Err: fmt.Errorf("error building query %w", err)} - } - - res, err := repo.cli.client.Search( - repo.cli.client.Search.WithBody(query), - repo.cli.client.Search.WithIndex(BuildAliasNameFromNamespace(cfg.Namespace)), - repo.cli.client.Search.WithSize(maxResults), - repo.cli.client.Search.WithFrom(offset), - repo.cli.client.Search.WithIgnoreUnavailable(true), - repo.cli.client.Search.WithSourceIncludes(includedFields...), - repo.cli.client.Search.WithContext(ctx), - ) - if err != nil { - return nil, asset.DiscoveryError{Err: fmt.Errorf("error executing search %w", err)} - } - - defer res.Body.Close() - var response searchResponse - err = json.NewDecoder(res.Body).Decode(&response) - if err != nil { - return nil, asset.DiscoveryError{Err: fmt.Errorf("error decoding search response %w", err)} - } - - return repo.toSearchResults(response.Hits.Hits), nil -} - -func (repo *DiscoveryRepository) Suggest(ctx context.Context, cfg asset.SearchConfig) (results []string, err error) { - if err := cfg.Validate(); err != nil { - return nil, err - } - maxResults := cfg.MaxResults - if maxResults <= 0 { - maxResults = defaultMaxResults - } - - query, err := repo.buildSuggestQuery(ctx, cfg) - if err != nil { - err = asset.DiscoveryError{Err: fmt.Errorf("error building query: %s", err)} - return - } - res, err := repo.cli.client.Search( - repo.cli.client.Search.WithBody(query), - repo.cli.client.Search.WithIndex(BuildAliasNameFromNamespace(cfg.Namespace)), - repo.cli.client.Search.WithSize(maxResults), - repo.cli.client.Search.WithIgnoreUnavailable(true), - repo.cli.client.Search.WithContext(ctx), - ) - if err != nil { - err = asset.DiscoveryError{Err: fmt.Errorf("error executing search %w", err)} - return - } - if res.IsError() { - err = asset.DiscoveryError{Err: fmt.Errorf("error when searching %s", errorReasonFromResponse(res))} - return - } - - var response searchResponse - err = json.NewDecoder(res.Body).Decode(&response) - if err != nil { - err = asset.DiscoveryError{Err: fmt.Errorf("error decoding search response %w", err)} - return - } - results, err = repo.toSuggestions(response) - if err != nil { - err = asset.DiscoveryError{Err: fmt.Errorf("error mapping response to suggestion %w", err)} - } - - return -} - -func (repo *DiscoveryRepository) buildQuery(ctx context.Context, cfg asset.SearchConfig) (io.Reader, error) { - boolQ := newBoolQuery() - - buildTextQuery(boolQ, cfg) - buildFilterTermQueries(boolQ, cfg.Filters) - buildMustMatchQueries(boolQ, cfg) - - query := buildFunctionScoreQuery(boolQ, cfg) - - searchBody := map[string]interface{}{ - "query": query, - "min_score": defaultMinScore, - } - - if cfg.Flags.EnableHighlight { - searchBody["highlight"] = map[string]interface{}{ - "fields": map[string]interface{}{ - "*": map[string]interface{}{}, - }, - } - } - - payload, err := json.Marshal(searchBody) - if err != nil { - return nil, err - } - - return strings.NewReader(string(payload)), nil -} - -func (repo *DiscoveryRepository) buildSuggestQuery(ctx context.Context, cfg asset.SearchConfig) (io.Reader, error) { - searchBody := map[string]interface{}{ - "suggest": map[string]interface{}{ - suggesterName: map[string]interface{}{ - "prefix": cfg.Text, - "completion": map[string]interface{}{ - "field": "name.suggest", - "skip_duplicates": true, - "size": 5, - }, - }, - }, - } - - payload, err := json.Marshal(searchBody) - if err != nil { - return nil, fmt.Errorf("error building reader %w", err) - } - - return strings.NewReader(string(payload)), nil -} - -// boolQuery is a JSON map builder for ES bool queries -type boolQuery struct { - should []interface{} - filter []interface{} - must []interface{} - minimumShouldMatch string -} - -func newBoolQuery() *boolQuery { - return &boolQuery{} -} - -func (q *boolQuery) toMap() map[string]interface{} { - m := map[string]interface{}{} - if len(q.should) > 0 { - m["should"] = q.should - } - if len(q.filter) > 0 { - m["filter"] = q.filter - } - if len(q.must) > 0 { - m["must"] = q.must - } - if q.minimumShouldMatch != "" { - m["minimum_should_match"] = q.minimumShouldMatch - } - return map[string]interface{}{"bool": m} -} - -func buildTextQuery(boolQ *boolQuery, cfg asset.SearchConfig) { - text := strings.TrimSpace(cfg.Text) - if text == "" { - boolQ.should = append(boolQ.should, map[string]interface{}{"match_all": map[string]interface{}{}}) - return - } - - boostedFields := []string{ - "urn^10", - "name^5", - } - - // Phrase match for highest relevance - boolQ.should = append(boolQ.should, map[string]interface{}{ - "multi_match": map[string]interface{}{ - "query": text, - "fields": boostedFields, - "type": "phrase", - }, - }) - - // Multi match with AND operator - boolQ.should = append(boolQ.should, map[string]interface{}{ - "multi_match": map[string]interface{}{ - "query": text, - "fields": boostedFields, - "operator": "and", - }, - }) - - // Standard multi match - boolQ.should = append(boolQ.should, map[string]interface{}{ - "multi_match": map[string]interface{}{ - "query": text, - "fields": boostedFields, - }, - }) - - if !cfg.Flags.DisableFuzzy { - // Fuzzy match on boosted fields - boolQ.should = append(boolQ.should, map[string]interface{}{ - "multi_match": map[string]interface{}{ - "query": text, - "fields": boostedFields, - "fuzziness": "AUTO", - }, - }) - - // Fuzzy match on all fields - boolQ.should = append(boolQ.should, map[string]interface{}{ - "multi_match": map[string]interface{}{ - "query": text, - "fuzziness": "AUTO", - }, - }) - } - - boolQ.minimumShouldMatch = "1" -} - -func buildMustMatchQueries(boolQ *boolQuery, cfg asset.SearchConfig) { - if len(cfg.Queries) == 0 { - return - } - - for field, value := range cfg.Queries { - matchQ := map[string]interface{}{ - "query": value, - } - if !cfg.Flags.DisableFuzzy { - matchQ["fuzziness"] = "AUTO" - } - boolQ.must = append(boolQ.must, map[string]interface{}{ - "match": map[string]interface{}{ - field: matchQ, - }, - }) - } -} - -func buildFilterTermQueries(boolQ *boolQuery, filters map[string][]string) { - if len(filters) == 0 { - return - } - - for key, rawValues := range filters { - if len(rawValues) < 1 { - continue - } - - keywordKey := fmt.Sprintf("%s.keyword", key) - if len(rawValues) == 1 { - boolQ.filter = append(boolQ.filter, map[string]interface{}{ - "term": map[string]interface{}{ - keywordKey: rawValues[0], - }, - }) - } else { - boolQ.filter = append(boolQ.filter, map[string]interface{}{ - "terms": map[string]interface{}{ - keywordKey: rawValues, - }, - }) - } - } -} - -func buildFunctionScoreQuery(boolQ *boolQuery, cfg asset.SearchConfig) interface{} { - text := strings.TrimSpace(cfg.Text) - - // Add exact match boost - if text != "" { - boolQ.should = append(boolQ.should, map[string]interface{}{ - "term": map[string]interface{}{ - "name.keyword": map[string]interface{}{ - "value": text, - "boost": 100, - }, - }, - }) - } - - queryMap := boolQ.toMap() - - if cfg.RankBy == "" { - return queryMap - } - - return map[string]interface{}{ - "function_score": map[string]interface{}{ - "query": queryMap, - "score_mode": defaultFunctionScoreQueryScoreMode, - "functions": []interface{}{ - map[string]interface{}{ - "field_value_factor": map[string]interface{}{ - "field": cfg.RankBy, - "modifier": "log1p", - "missing": 1.0, - }, - "weight": 1.0, - }, - }, - }, - } -} - -func (repo *DiscoveryRepository) toSearchResults(hits []searchHit) []asset.SearchResult { - results := make([]asset.SearchResult, len(hits)) - for i, hit := range hits { - r := hit.Source - id := r.ID - if id == "" { // this is for backward compatibility for asset without ID - id = r.URN - } - - data := r.Data - if len(hit.HighLight) > 0 { - if data == nil { - data = make(map[string]interface{}) - } - data["_highlight"] = hit.HighLight - } - - results[i] = asset.SearchResult{ - Type: r.Type.String(), - ID: id, - URN: r.URN, - Description: r.Description, - Title: r.Name, - Service: r.Service, - Labels: r.Labels, - Data: data, - } - } - return results -} - -func (repo *DiscoveryRepository) toSuggestions(response searchResponse) (results []string, err error) { - suggests, exists := response.Suggest[suggesterName] - if !exists { - err = fmt.Errorf("suggester key does not exist") - return - } - results = []string{} - for _, s := range suggests { - for _, option := range s.Options { - results = append(results, option.Text) - } - } - - return -} - -const defaultGroupsSize = 10 - -// GroupAssets groups assets by specified fields using ES composite aggregation -func (repo *DiscoveryRepository) GroupAssets(ctx context.Context, cfg asset.GroupConfig) ([]asset.GroupResult, error) { - if cfg.Namespace == nil { - return nil, asset.DiscoveryError{Err: fmt.Errorf("namespace cannot be empty")} - } - - size := cfg.Size - if size <= 0 { - size = defaultGroupsSize - } - - // Build composite aggregation sources from group-by fields - sources := make([]map[string]interface{}, 0, len(cfg.GroupBy)) - for _, field := range cfg.GroupBy { - sources = append(sources, map[string]interface{}{ - field: map[string]interface{}{ - "terms": map[string]interface{}{ - "field": fmt.Sprintf("%s.keyword", field), - }, - }, - }) - } - - // Build filter query - boolQ := newBoolQuery() - for _, field := range cfg.GroupBy { - boolQ.filter = append(boolQ.filter, map[string]interface{}{ - "exists": map[string]interface{}{ - "field": fmt.Sprintf("%s.keyword", field), - }, - }) - } - buildFilterTermQueries(boolQ, cfg.Filters) - - includedFields := defaultIncludedFields - if len(cfg.IncludeFields) > 0 { - includedFields = cfg.IncludeFields - } - - payload := map[string]interface{}{ - "size": 0, - "query": boolQ.toMap(), - "aggs": map[string]interface{}{ - "group_result": map[string]interface{}{ - "composite": map[string]interface{}{ - "size": size, - "sources": sources, - }, - "aggs": map[string]interface{}{ - "top_assets": map[string]interface{}{ - "top_hits": map[string]interface{}{ - "size": size, - "_source": includedFields, - }, - }, - }, - }, - }, - } - - body, err := json.Marshal(payload) - if err != nil { - return nil, asset.DiscoveryError{Err: fmt.Errorf("error encoding query: %w", err)} - } - - res, err := repo.cli.client.Search( - repo.cli.client.Search.WithBody(strings.NewReader(string(body))), - repo.cli.client.Search.WithIndex(BuildAliasNameFromNamespace(cfg.Namespace)), - repo.cli.client.Search.WithIgnoreUnavailable(true), - repo.cli.client.Search.WithContext(ctx), - ) - if err != nil { - return nil, asset.DiscoveryError{Err: fmt.Errorf("error executing group query: %w", err)} - } - defer res.Body.Close() - - if res.IsError() { - return nil, asset.DiscoveryError{Err: fmt.Errorf("error response from elasticsearch: %s", errorReasonFromResponse(res))} - } - - var response groupResponse - if err := json.NewDecoder(res.Body).Decode(&response); err != nil { - return nil, asset.DiscoveryError{Err: fmt.Errorf("error decoding group response: %w", err)} - } - - return repo.toGroupResults(response, cfg.GroupBy), nil -} - -type groupResponse struct { - Aggregations struct { - GroupResult struct { - Buckets []groupBucket `json:"buckets"` - } `json:"group_result"` - } `json:"aggregations"` -} - -type groupBucket struct { - Key map[string]string `json:"key"` - DocCount int `json:"doc_count"` - TopAssets struct { - Hits struct { - Hits []searchHit `json:"hits"` - } `json:"hits"` - } `json:"top_assets"` -} - -func (repo *DiscoveryRepository) toGroupResults(response groupResponse, groupBy []string) []asset.GroupResult { - var results []asset.GroupResult - for _, bucket := range response.Aggregations.GroupResult.Buckets { - var fields []asset.GroupField - for _, key := range groupBy { - fields = append(fields, asset.GroupField{ - Key: key, - Value: bucket.Key[key], - }) - } - - var assets []asset.Asset - for _, hit := range bucket.TopAssets.Hits.Hits { - r := hit.Source - assets = append(assets, asset.Asset{ - ID: r.ID, - URN: r.URN, - Type: r.Type, - Name: r.Name, - Service: r.Service, - Description: r.Description, - Data: r.Data, - Labels: r.Labels, - }) - } - - results = append(results, asset.GroupResult{ - Fields: fields, - Assets: assets, - }) - } - return results -} diff --git a/store/elasticsearch/discovery_search_repository_test.go b/store/elasticsearch/discovery_search_repository_test.go deleted file mode 100644 index fc996534..00000000 --- a/store/elasticsearch/discovery_search_repository_test.go +++ /dev/null @@ -1,282 +0,0 @@ -package elasticsearch_test - -import ( - "context" - "encoding/json" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "os" - "testing" - - "github.com/raystack/compass/core/asset" - store "github.com/raystack/compass/store/elasticsearch" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -type searchTestData struct { - Assets []asset.Asset `json:"assets"` -} - -func TestSearcherSearch(t *testing.T) { - ctx := context.TODO() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.DedicatedState, - Metadata: nil, - } - - t.Run("fixtures", func(t *testing.T) { - cli, err := esTestServer.NewClient() - require.NoError(t, err) - esClient, err := store.NewClient( - store.Config{}, - store.WithClient(cli), - ) - require.NoError(t, err) - - err = loadTestFixture(esClient, ns, "./testdata/search-test-fixture.json") - require.NoError(t, err) - - repo := store.NewDiscoveryRepository(esClient) - - type searchTest struct { - Description string - Config asset.SearchConfig - Expected []asset.SearchResult - MatchTotalRows bool - } - tests := []searchTest{ - { - Description: "should fetch assets which has text in any of its fields", - Config: asset.SearchConfig{ - Text: "topic", - Namespace: ns, - }, - Expected: []asset.SearchResult{ - {Type: "topic", ID: "consumer-topic"}, - {Type: "topic", ID: "order-topic"}, - {Type: "topic", ID: "purchase-topic"}, - {Type: "topic", ID: "consumer-mq-2"}, - {Type: "topic", ID: "transaction"}, - }, - }, - { - Description: "should enable fuzzy search", - Config: asset.SearchConfig{ - Text: "tpic", - Namespace: ns, - }, - Expected: []asset.SearchResult{ - {Type: "topic", ID: "consumer-topic"}, - {Type: "topic", ID: "order-topic"}, - {Type: "topic", ID: "purchase-topic"}, - {Type: "topic", ID: "consumer-mq-2"}, - {Type: "topic", ID: "transaction"}, - }, - }, - { - Description: "should put more weight on id fields", - Config: asset.SearchConfig{ - Text: "invoice", - Namespace: ns, - }, - Expected: []asset.SearchResult{ - {Type: "table", ID: "us1-apple-invoice"}, - {Type: "table", ID: "au2-microsoft-invoice"}, - {Type: "topic", ID: "transaction"}, - }, - }, - { - Description: "should filter by service if given", - Config: asset.SearchConfig{ - Text: "invoice", - Filters: map[string][]string{ - "service": {"rabbitmq", "postgres"}, - }, - Namespace: ns, - }, - Expected: []asset.SearchResult{ - {Type: "table", ID: "au2-microsoft-invoice"}, - {Type: "topic", ID: "transaction"}, - }, - }, - { - Description: "should match documents based on filter criteria", - Config: asset.SearchConfig{ - Text: "topic", - Filters: map[string][]string{ - "data.company": {"raystack"}, - }, - Namespace: ns, - }, - Expected: []asset.SearchResult{ - {Type: "topic", ID: "consumer-topic"}, - {Type: "topic", ID: "order-topic"}, - {Type: "topic", ID: "consumer-mq-2"}, - {Type: "topic", ID: "transaction"}, - }, - }, - { - Description: "should not return assets without fields specified in filters", - Config: asset.SearchConfig{ - Text: "invoice topic", - Filters: map[string][]string{ - "data.country": {"id"}, - "data.environment": {"production"}, - "data.company": {"raystack"}, - }, - Namespace: ns, - }, - Expected: []asset.SearchResult{ - {Type: "topic", ID: "consumer-topic"}, - {Type: "topic", ID: "consumer-mq-2"}, - }, - }, - { - Description: "should return 'consumer-topic' if filter owner email with 'john.doe@email.com'", - Config: asset.SearchConfig{ - Text: "topic", - Filters: map[string][]string{ - "owners.email": {"john.doe@email.com"}, - }, - Namespace: ns, - }, - Expected: []asset.SearchResult{ - {Type: "topic", ID: "consumer-topic"}, - }, - }, - { - Description: "should return a descendingly sorted based on usage count in search results if rank by usage in the config", - Config: asset.SearchConfig{ - Text: "bigquery", - RankBy: "data.profile.usage_count", - Namespace: ns, - }, - Expected: []asset.SearchResult{ - {Type: "table", ID: "bigquery::gcpproject/dataset/tablename-common"}, - {Type: "table", ID: "bigquery::gcpproject/dataset/tablename-mid"}, - {Type: "table", ID: "bigquery::gcpproject/dataset/tablename-1"}, - }, - }, - { - Description: "should return consumer-topic if search by query description field with text 'rabbitmq' and owners name 'johndoe'", - Config: asset.SearchConfig{ - Text: "consumer", - Queries: map[string]string{ - "description": "rabbitmq", - "owners.email": "john.doe", - }, - Namespace: ns, - }, - Expected: []asset.SearchResult{ - {Type: "topic", ID: "consumer-topic"}, - }, - }, - { - Description: "should return 'bigquery::gcpproject/dataset/tablename-common' resource on top if search by query table column name field with text 'tablename-common-column1'", - Config: asset.SearchConfig{ - Text: "tablename", - Queries: map[string]string{ - "data.schema.columns.name": "common", - }, - Namespace: ns, - }, - Expected: []asset.SearchResult{ - {Type: "table", ID: "bigquery::gcpproject/dataset/tablename-common"}, - }, - }, - } - for _, test := range tests { - t.Run(test.Description, func(t *testing.T) { - results, err := repo.Search(ctx, test.Config) - require.NoError(t, err) - - require.Equal(t, len(test.Expected), len(results)) - for _, res := range test.Expected { - assert.True(t, isContain(results, res)) - } - }) - } - }) -} - -func isContain(bag []asset.SearchResult, item asset.SearchResult) bool { - for _, current := range bag { - if current.Type == item.Type && current.ID == item.ID { - return true - } - } - return false -} - -func TestSearcherSuggest(t *testing.T) { - ctx := context.TODO() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.DedicatedState, - Metadata: nil, - } - cli, err := esTestServer.NewClient() - require.NoError(t, err) - esClient, err := store.NewClient( - store.Config{}, - store.WithClient(cli), - ) - require.NoError(t, err) - - err = loadTestFixture(esClient, ns, "./testdata/suggest-test-fixture.json") - require.NoError(t, err) - - repo := store.NewDiscoveryRepository(esClient) - - t.Run("fixtures", func(t *testing.T) { - testCases := []struct { - term string - expected []string - }{ - {"wallet", []string{"wallet-usage", "wallet/event", "wallet_usage"}}, - {"wallet_usa", []string{"wallet-usage", "wallet_usage"}}, - {"test_t", []string{"test_table"}}, - {"te", []string{"test_table"}}, - } - - for i, tc := range testCases { - config := asset.SearchConfig{Text: tc.term, Namespace: ns} - actual, err := repo.Suggest(ctx, config) - assert.NoError(t, err) - - assert.Equal(t, tc.expected, actual, "suggestions are not as expected for term: %s and index: %d", tc.term, i) - } - }) -} - -func loadTestFixture(esClient *store.Client, ns *namespace.Namespace, filePath string) (err error) { - testFixtureJSON, err := os.ReadFile(filePath) - if err != nil { - return - } - - var data []searchTestData - err = json.Unmarshal(testFixtureJSON, &data) - if err != nil { - return - } - - ctx := context.TODO() - for _, testdata := range data { - repo := store.NewDiscoveryRepository(esClient, store.WithInstantRefresh()) - if err = repo.CreateNamespace(ctx, ns); err != nil { - return err - } - for _, ast := range testdata.Assets { - if err := repo.Upsert(ctx, ns, &ast); err != nil { - return err - } - } - } - - return err -} diff --git a/store/elasticsearch/es.go b/store/elasticsearch/es.go deleted file mode 100644 index 8ef53c21..00000000 --- a/store/elasticsearch/es.go +++ /dev/null @@ -1,284 +0,0 @@ -package elasticsearch - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "strings" - - "github.com/elastic/go-elasticsearch/v8" - "github.com/elastic/go-elasticsearch/v8/esapi" - "github.com/google/uuid" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/namespace" -) - -const ( - // name of the search index - defaultSearchIndexAlias = "universe" - - // DefaultSharedIndexName use single shared index for small tenants - DefaultSharedIndexName = "compass-idx-default" - - // DefaultShardCountPerIndex provides shard count in an index. For large scale, it should be at least 12 - DefaultShardCountPerIndex = 6 - - // DedicatedTenantIndexPrefix is used to avoid index conflicts with system managed indices - DedicatedTenantIndexPrefix = "compass-idx" - - // TenantIndexAliasPrefix is used to avoid index/alias conflicts, convention is same for - // dedicated and shared tenants - TenantIndexAliasPrefix = "compass-alias" -) - -type Config struct { - Brokers string `mapstructure:"brokers" default:"http://localhost:9200"` - Username string `mapstructure:"username"` - Password string `mapstructure:"password"` - RequestTimeout int `mapstructure:"request_timeout" default:"10"` -} - -type Route struct { - // Index could be shared or a dedicated, if dedicated it will be identified by namespace name - // for most cases it will be `DefaultSharedIndexName` - Index string `json:"index"` - // ReadKey route search query to respective shards - // for most cases it will be namespace id - ReadKey string `json:"read_key"` - // WriteKey route index query to respective shards - // for most cases it will be namespace id - WriteKey string `json:"write_key"` - // FilterKey finds set of documents uniquely for a tenant - // for most cases it will be namespace id - FilterKey string `json:"filter_key"` -} - -var ( - DefaultRoute = &Route{ - Index: DefaultSharedIndexName, - ReadKey: uuid.Nil.String(), - WriteKey: uuid.Nil.String(), - FilterKey: uuid.Nil.String(), - } -) - -// totalHits represents the total hits from an ES search response -type totalHits struct { - Value int64 `json:"value"` - Relation string `json:"relation"` -} - -// suggestionOption represents a single suggestion option from ES -type suggestionOption struct { - Text string `json:"text"` - Score float64 `json:"_score"` -} - -type searchHit struct { - Index string `json:"_index"` - Source asset.Asset `json:"_source"` - HighLight map[string][]string `json:"highlight"` -} - -type aggregationBucket struct { - Key string `json:"key"` - DocCount int `json:"doc_count"` -} - -type searchResponse struct { - ScrollID string `json:"_scroll_id"` - Hits struct { - Total totalHits `json:"total"` - Hits []searchHit `json:"hits"` - } `json:"hits"` - Suggest map[string][]struct { - Text string `json:"text"` - Offset int `json:"offset"` - Length float32 `json:"length"` - Options []suggestionOption `json:"options"` - } `json:"suggest"` - Aggregations struct { - AggregationName struct { - DocCountErrorUpperBound int `json:"doc_count_error_upper_bound"` - SumOtherDocCount int `json:"sum_other_doc_count"` - Buckets []aggregationBucket - } `json:"aggregation_name"` - } `json:"aggregations"` -} - -// extract error reason from an elasticsearch response -// returns the raw message in case it fails -func errorReasonFromResponse(res *esapi.Response) string { - var ( - response struct { - Error struct { - Reason string `json:"reason"` - } `json:"error"` - } - copy bytes.Buffer - ) - reader := io.TeeReader(res.Body, ©) - err := json.NewDecoder(reader).Decode(&response) - if err != nil { - return fmt.Sprintf("raw response = %s", copy.String()) - } - return response.Error.Reason -} - -type Client struct { - client *elasticsearch.Client -} - -func NewClient(config Config, opts ...ClientOption) (*Client, error) { - c := &Client{} - - for _, opt := range opts { - opt(c) - } - - if c.client != nil { - return c, nil - } - - brokers := strings.Split(config.Brokers, ",") - esCfg := elasticsearch.Config{ - Addresses: brokers, - // Retry on 429 TooManyRequests statuses as well - RetryOnStatus: []int{502, 503, 504, 429}, - MaxRetries: 3, - } - if config.Username != "" { - esCfg.Username = config.Username - } - if config.Password != "" { - esCfg.Password = config.Password - } - esClient, err := elasticsearch.NewClient(esCfg) - if err != nil { - return nil, err - } - c.client = esClient - - return c, nil -} - -func (c *Client) Init() (string, error) { - res, err := c.client.Info() - if err != nil { - return "", err - } - defer res.Body.Close() - if res.IsError() { - return "", errors.New(res.Status()) - } - var info = struct { - ClusterName string `json:"cluster_name"` - Version struct { - Number string `json:"number"` - } `json:"version"` - }{} - - err = json.NewDecoder(res.Body).Decode(&info) - if err != nil { - return "", err - } - - return fmt.Sprintf("%q (server version %s)", info.ClusterName, info.Version.Number), nil -} - -func (c *Client) CreateIndex(ctx context.Context, name string, shardCount int) error { - indexSettings := buildIndexSettings(shardCount) - - res, err := c.client.Indices.Create( - name, - c.client.Indices.Create.WithBody(strings.NewReader(indexSettings)), - c.client.Indices.Create.WithContext(ctx), - ) - if err != nil { - return asset.DiscoveryError{Err: err} - } - defer res.Body.Close() - if res.IsError() { - reason := errorReasonFromResponse(res) - // Ignore "resource_already_exists_exception" which can happen due to race conditions - if strings.Contains(reason, "resource_already_exists_exception") { - return nil - } - return fmt.Errorf("error creating index %q: %s", name, reason) - } - return nil -} - -func buildIndexSettings(shardCount int) string { - return fmt.Sprintf(indexSettingsTemplate, serviceIndexMapping, defaultSearchIndexAlias, shardCount) -} - -func (c *Client) CreateIdxAlias(ctx context.Context, ns *namespace.Namespace) error { - var indexSettings string - if ns.State == namespace.SharedState { - indexSettings = buildIndexAliasSettings(indexSharedAliasSettingsTemplate, ns) - } else { - indexSettings = buildIndexAliasSettings(indexDedicatedAliasSettingsTemplate, ns) - } - res, err := esapi.IndicesUpdateAliasesRequest{ - Body: strings.NewReader(indexSettings), - }.Do(ctx, c.client) - if err != nil { - return asset.DiscoveryError{Err: err} - } - defer res.Body.Close() - if res.IsError() { - return fmt.Errorf("error creating index alias %q: %s", ns.Name, errorReasonFromResponse(res)) - } - return nil -} - -func BuildAliasNameFromNamespace(ns *namespace.Namespace) string { - return fmt.Sprintf("%s-%s", TenantIndexAliasPrefix, ns.Name) -} - -func BuildIndexNameFromNamespace(ns *namespace.Namespace) string { - index := DefaultSharedIndexName - if ns.State == namespace.DedicatedState { - index = fmt.Sprintf("%s-%s", DedicatedTenantIndexPrefix, ns.Name) - } - return index -} - -func buildRouteFromNamespace(ns *namespace.Namespace) Route { - return Route{ - Index: BuildIndexNameFromNamespace(ns), - ReadKey: ns.ID.String(), - WriteKey: ns.ID.String(), - FilterKey: ns.ID.String(), - } -} - -func buildIndexAliasSettings(template string, ns *namespace.Namespace) string { - aliasName := BuildAliasNameFromNamespace(ns) - route := buildRouteFromNamespace(ns) - return strings.NewReplacer( - "{{alias_name}}", aliasName, - "{{index_name}}", route.Index, - "{{filter_id}}", route.FilterKey, - "{{write_id}}", route.WriteKey, - "{{read_id}}", route.ReadKey, - ).Replace(template) -} - -// IndexExists checks for the existence of an index -func (c *Client) IndexExists(ctx context.Context, ns *namespace.Namespace) (bool, error) { - indexName := BuildIndexNameFromNamespace(ns) - res, err := c.client.Indices.Exists( - []string{indexName}, - c.client.Indices.Exists.WithContext(ctx), - ) - if err != nil { - return false, fmt.Errorf("indexExists: %w", err) - } - defer res.Body.Close() - return res.StatusCode == 200, nil -} diff --git a/store/elasticsearch/es_test.go b/store/elasticsearch/es_test.go deleted file mode 100644 index e2922a1b..00000000 --- a/store/elasticsearch/es_test.go +++ /dev/null @@ -1,159 +0,0 @@ -package elasticsearch_test - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "reflect" - "strings" - "testing" - - "github.com/elastic/go-elasticsearch/v8/esapi" - "github.com/elastic/go-elasticsearch/v8" - store "github.com/raystack/compass/store/elasticsearch" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestElasticsearch(t *testing.T) { - ctx := context.Background() - t.Run("Create", func(t *testing.T) { - var testCases = []struct { - Title string - Service string - ShouldFail bool - Validate func(esClient *store.Client, cli *elasticsearch.Client, indexName string) error - }{ - { - Title: "should successfully write the document to elasticsearch", - Service: daggerService, - ShouldFail: false, - }, - { - Title: "should create the index ${service} in elasticsearch", - Service: daggerService, - ShouldFail: false, - Validate: func(esClient *store.Client, cli *elasticsearch.Client, indexName string) error { - idxRequest := &esapi.IndicesExistsRequest{ - Index: []string{ - indexName, - }, - } - res, err := idxRequest.Do(context.Background(), cli) - if err != nil { - return fmt.Errorf("failed to query elasticsearch for index %q: %w", indexName, err) - } - defer res.Body.Close() - if res.IsError() { - return fmt.Errorf("elasticsearch: error querying existence of %q index: %s", indexName, res.Status()) - } - return nil - }, - }, - { - Title: "should not accept any service that has the same name as the search index", - Service: "universe", // defaultSearchIndexAlias - ShouldFail: true, - }, - { - Title: "should alias the type to the search index", - Service: daggerService, - Validate: func(esClient *store.Client, cli *elasticsearch.Client, indexName string) error { - searchIndex := "universe" - req, err := http.NewRequest("GET", "/_alias/"+searchIndex, nil) - if err != nil { - return fmt.Errorf("error creating request: %w", err) - } - res, err := cli.Perform(req) - if err != nil { - return fmt.Errorf("error calling elasticsearch alias API: %w", err) - } - defer res.Body.Close() - - aliases := make(map[string]interface{}) - err = json.NewDecoder(res.Body).Decode(&aliases) - if err != nil { - return fmt.Errorf("error decoding elasticsearch response: %w", err) - } - if _, created := aliases[indexName]; !created { - return fmt.Errorf("expected %q index to be aliased to %q, but it was not", indexName, searchIndex) - } - return nil - }, - }, - { - Title: "created index should be able to correctly tokenize CamelCase text", - Service: daggerService, - Validate: func(esClient *store.Client, cli *elasticsearch.Client, indexName string) error { - textToAnalyze := "HelloWorld" - analyzerPath := fmt.Sprintf("/%s/_analyze", indexName) - analyzerPayload := fmt.Sprintf(`{"analyzer": "my_analyzer", "text": %q}`, textToAnalyze) - - req, err := http.NewRequest("POST", analyzerPath, strings.NewReader(analyzerPayload)) - if err != nil { - return fmt.Errorf("error creating analyzer request: %w", err) - } - req.Header.Add("content-type", "application/json") - - res, err := cli.Perform(req) - if err != nil { - return fmt.Errorf("error invoking analyzer: %v", err) - } - defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return fmt.Errorf("elasticsearch returned non-200 response: %d", res.StatusCode) - } - var response struct { - Tokens []struct { - Token string `json:"token"` - } `json:"tokens"` - } - err = json.NewDecoder(res.Body).Decode(&response) - if err != nil { - return fmt.Errorf("error decoding response: %w", err) - } - expectTokens := []string{"hello", "world"} - analyzedTokens := []string{} - for _, tok := range response.Tokens { - analyzedTokens = append(analyzedTokens, tok.Token) - } - - if reflect.DeepEqual(expectTokens, analyzedTokens) == false { - return fmt.Errorf("expected analyzer to tokenize %q as %v, was %v", textToAnalyze, expectTokens, analyzedTokens) - } - return nil - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.Title, func(t *testing.T) { - cli, err := esTestServer.NewClient() - require.NoError(t, err) - esClient, err := store.NewClient( - store.Config{}, - store.WithClient(cli), - ) - require.NoError(t, err) - _, err = esClient.Init() - assert.NoError(t, err) - err = esClient.CreateIndex(ctx, testCase.Service, store.DefaultShardCountPerIndex) - if testCase.ShouldFail { - assert.Error(t, err) - return - } else if err != nil { - t.Errorf("repository returned unexpected error: %v", err) - return - } - - if testCase.Validate != nil { - if err := testCase.Validate(esClient, cli, testCase.Service); err != nil { - t.Error(err) - return - } - } - }) - } - }) -} diff --git a/store/elasticsearch/init_test.go b/store/elasticsearch/init_test.go deleted file mode 100644 index 92a89808..00000000 --- a/store/elasticsearch/init_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package elasticsearch_test - -import ( - "fmt" - "os" - "testing" - - "github.com/raystack/compass/store/elasticsearch/testutil" -) - -var ( - daggerService = "dagger" - esTestServer *testutil.ElasticsearchTestServer -) - -func TestMain(m *testing.M) { - // TODO(Aman): this block makes it impossible to skip starting - // an elasticsearch server. That means you can't run unit tests - // standalone :/ - esTestServer = testutil.NewElasticsearchTestServer() - - exitCode := m.Run() - - if err := esTestServer.Close(); err != nil { - fmt.Println("Error closing elasticsearch test server:", err) - return - } - os.Exit(exitCode) -} diff --git a/store/elasticsearch/options.go b/store/elasticsearch/options.go deleted file mode 100644 index ae716c16..00000000 --- a/store/elasticsearch/options.go +++ /dev/null @@ -1,11 +0,0 @@ -package elasticsearch - -import "github.com/elastic/go-elasticsearch/v8" - -type ClientOption func(*Client) - -func WithClient(cli *elasticsearch.Client) ClientOption { - return func(c *Client) { - c.client = cli - } -} diff --git a/store/elasticsearch/schema.go b/store/elasticsearch/schema.go deleted file mode 100644 index eca9ad28..00000000 --- a/store/elasticsearch/schema.go +++ /dev/null @@ -1,139 +0,0 @@ -package elasticsearch - -// used as body to create index requests -// aliases the index to defaultSearchIndexAlias -// and sets up the camelcase analyzer -var indexSettingsTemplate = `{ - "mappings": %s, - "aliases": { - %q: {} - }, - "settings": { - "index": { - "number_of_shards": %d, - "mapping.ignore_malformed": true - }, - "analysis": { - "analyzer": { - "my_analyzer": { - "type": "custom", - "tokenizer": "my_tokenizer", - "filter": ["lowercase", "english_stemmer"] - } - }, - "filter": { - "english_stemmer": { - "type": "stemmer", - "language": "English" - } - }, - "tokenizer": { - "my_tokenizer": { - "type": "pattern", - "pattern": "([^\\p{L}\\d]+)|(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)|(?<=[\\p{L}&&[^\\p{Lu}]])(?=\\p{Lu})|(?<=\\p{Lu})(?=\\p{Lu}[\\p{L}&&[^\\p{Lu}]])" - } - } - } - } -}` - -var serviceIndexMapping = `{ - "properties": { - "namespace_id": { - "type": "keyword" - }, - "urn": { - "type": "text", - "analyzer": "my_analyzer", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256.0 - } - } - }, - "name": { - "type": "text", - "analyzer": "my_analyzer", - "fields": { - "suggest": { - "type": "completion" - }, - "keyword": { - "type": "keyword", - "ignore_above": 256.0 - } - } - }, - "service": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256.0 - } - } - }, - "type": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256.0 - } - } - }, - "description": { - "type": "text" - }, - "labels": { - "type": "object" - } - } -}` - -// indexSharedAliasSettingsTemplate is used as body to create index alias requests for shared tenants -// item read/write calls will be routed to specific shards and then filtered before fetching by tenant id -var indexSharedAliasSettingsTemplate = `{ - "actions": [ - { - "remove": { - "alias": "{{alias_name}}", - "index": "{{index_name}}" - } - }, - { - "add": { - "index": "{{index_name}}", - "alias": "{{alias_name}}", - "filter": { - "term": { - "namespace_id": "{{filter_id}}" - } - }, - "index_routing": "{{write_id}}", - "search_routing": "{{read_id}}" - } - } - ] -}` - -// indexDedicatedAliasSettingsTemplate is used as body to create index alias requests for dedicated tenants -// for dedicated tenants, it's not required to route read/write and filter items based on namespace -// as the whole index belongs to tenant -var indexDedicatedAliasSettingsTemplate = `{ - "actions": [ - { - "remove": { - "alias": "{{alias_name}}", - "index": "{{index_name}}" - } - }, - { - "add": { - "index": "{{index_name}}", - "alias": "{{alias_name}}" - } - } - ] -}` diff --git a/store/elasticsearch/testdata/search-test-fixture.json b/store/elasticsearch/testdata/search-test-fixture.json deleted file mode 100644 index 0a923a36..00000000 --- a/store/elasticsearch/testdata/search-test-fixture.json +++ /dev/null @@ -1,437 +0,0 @@ -[ - { - "assets": [ - { - "id": "order-topic", - "urn": "order-topic", - "name": "order-topic", - "service": "kafka", - "description": "Topic for each submitted order", - "data": { - "topic_name": "order-topic", - "description": "Topic for each submitted order", - "company": "raystack", - "environment": "integration", - "country": "us", - "partition": 250 - }, - "type": "topic" - }, - { - "id": "purchase-topic", - "urn": "purchase-topic", - "name": "purchase-topic", - "service": "kafka", - "description": "Topic for each submitted purchase", - "data": { - "topic_name": "purchase-topic", - "description": "Topic for each submitted purchase", - "company": "microsoft", - "environment": "integration", - "country": "id", - "partition": 100 - }, - "type": "topic" - }, - { - "id": "consumer-topic", - "urn": "consumer-topic", - "name": "consumer-topic", - "service": "rabbitmq", - "description": "Update on every rabbitmq customer creation/update", - "data": { - "topic_name": "consumer-topic", - "description": "Update on every rabbitmq customer creation/update", - "company": "raystack", - "environment": "production", - "country": "id", - "partition": 50 - }, - "owners": [ - { - "urn": "owner::topic/1", - "role": "user", - "email": "john.doe@email.com" - } - ], - "type": "topic" - }, - { - "id": "consumer-mq-2", - "urn": "consumer-mq-2", - "name": "consumer-mq-2", - "service": "rabbitmq", - "description": "Another rabbitmq topic", - "data": { - "topic_name": "consumer-mq-2", - "description": "Another rabbitmq topic", - "company": "raystack", - "environment": "production", - "country": "id", - "partition": 50 - }, - "owners": [ - { - "urn": "owner::topic/22", - "role": "user", - "email": "mary.jane@email.com" - } - ], - "type": "topic" - }, - { - "id": "transaction", - "urn": "transaction", - "name": "transaction", - "service": "rabbitmq", - "description": "This publishes all the invoices from each of invoice storage where the invoice will be filtered and checked using invoice filterer and invoice checker", - "data": { - "topic_name": "transaction", - "description": "This publishes all the invoices from each of invoice storage where the invoice will be filtered and checked using invoice filterer and invoice checker", - "company": "raystack", - "environment": "production", - "partition": 1 - }, - "type": "topic" - } - ] - }, - { - "assets": [ - { - "id": "au2-microsoft-invoice", - "urn": "au2-microsoft-invoice", - "name": "microsoft-invoice", - "service": "postgres", - "description": "Transaction records for every microsoft purchase", - "data": { - "table_id": "au2-microsoft-invoice", - "table_name": "microsoft-invoice", - "company": "microsoft", - "environment": "integration", - "country": "us", - "description": "Transaction records for every microsoft purchase", - "total_rows": 100, - "schema": [ - { - "name": "id" - }, - { - "name": "username", - "description": "purchaser username" - }, - { - "name": "item_id", - "description": "item identifications" - } - ] - }, - "type": "table" - }, - { - "id": "us1-apple-invoice", - "urn": "us1-apple-invoice", - "name": "apple-invoice", - "service": "mysql", - "description": "Transaction records for every Apple purchase", - "data": { - "table_id": "us1-apple-invoice", - "table_name": "apple-invoice", - "company": "apple", - "environment": "production", - "country": "id", - "description": "Transaction records for every Apple purchase", - "total_rows": 100, - "schema": [ - { - "name": "id" - }, - { - "name": "user_id", - "description": "purchaser user idenfitication" - }, - { - "name": "item_id", - "description": "item identifications" - } - ] - }, - "type": "table" - }, - { - "id": "bigquery::gcpproject/dataset/tablename-1", - "urn": "bigquery::gcpproject/dataset/tablename-1", - "name": "tablename-1", - "service": "bigquery", - "description": "A sample of table record", - "data": { - "preview": {}, - "profile": { - "common_join": [ - { - "conditions": [ - "ON target.column_1 = source.column_1 and target.column_3 = source.column_3 and DATE(target.event_timestamp) = DATE(source.event_timestamp)" - ], - "count": 1, - "urn": "bigquery::gcpproject/dataset/tablename-mid" - } - ], - "filter_conditions": [ - "WHERE t.column_5 = 'success' AND t.item_id = \"280481a2-2384-4b81-aa3e-214ac60b31db\" AND event_timestamp >= TIMESTAMP(\"2021-10-29\", \"UTC\") AND event_timestamp < TIMESTAMP(\"2021-11-22T02:01:06Z\")" - ], - "usage_count": 1 - }, - "properties": { - "attributes": { - "dataset": "dataset", - "full_qualified_name": "gcpproject:dataset.tablename-1", - "partition_field": "event_timestamp", - "project": "gcpproject", - "type": "TABLE" - }, - "labels": { - "owner": "user_1" - } - }, - "schema": { - "columns": [ - { - "data_type": "STRING", - "is_nullable": true, - "name": "tablename-1-column1", - "properties": { - "attributes": { - "mode": "NULLABLE" - } - } - }, - { - "data_type": "STRING", - "is_nullable": true, - "name": "tablename-1-column2", - "properties": { - "attributes": { - "mode": "NULLABLE" - } - } - }, - { - "data_type": "BIGNUMERIC", - "is_nullable": true, - "name": "tablename-1-column3", - "properties": { - "attributes": { - "mode": "NULLABLE" - } - } - } - ] - }, - "resource": { - "name": "tablename-1", - "service": "bigquery", - "urn": "bigquery::gcpproject/dataset/tablename-1" - } - }, - "owners": [ - { - "urn": "owner::bq/unique", - "name": "Mrs Unique", - "role": "user", - "email": "mrs.unique@email.com" - } - ], - "type": "table" - }, - { - "id": "bigquery::gcpproject/dataset/tablename-common", - "urn": "bigquery::gcpproject/dataset/tablename-common", - "name": "tablename-common", - "service": "bigquery", - "description": "A sample of table record with high usage", - "data": { - "preview": {}, - "profile": { - "common_join": [ - { - "conditions": [ - "ON target.column_1 = source.column_1 and target.column_3 = source.column_3 and DATE(target.event_timestamp) = DATE(source.event_timestamp)" - ], - "count": 1, - "urn": "bigquery::gcpproject/dataset/tablename-mid" - } - ], - "filter_conditions": [ - "WHERE t.column_5 = 'success' AND t.item_id = \"280481a2-2384-4b81-aa3e-214ac60b31db\" AND event_timestamp >= TIMESTAMP(\"2021-10-29\", \"UTC\") AND event_timestamp < TIMESTAMP(\"2021-11-22T02:01:06Z\")" - ], - "usage_count": 10 - }, - "properties": { - "attributes": { - "dataset": "dataset", - "full_qualified_name": "gcpproject:dataset.tablename-common", - "partition_field": "event_timestamp", - "project": "gcpproject", - "type": "TABLE" - }, - "labels": { - "owner": "user_1" - } - }, - "schema": { - "columns": [ - { - "data_type": "STRING", - "is_nullable": true, - "name": "tablename-common-column1", - "properties": { - "attributes": { - "mode": "NULLABLE" - } - } - }, - { - "data_type": "STRING", - "is_nullable": true, - "name": "tablename-common-column2", - "properties": { - "attributes": { - "mode": "NULLABLE" - } - } - }, - { - "data_type": "BIGNUMERIC", - "is_nullable": true, - "name": "tablename-common-column3", - "properties": { - "attributes": { - "mode": "NULLABLE" - } - } - } - ] - }, - "resource": { - "name": "tablename-common", - "service": "bigquery", - "urn": "bigquery::gcpproject/dataset/tablename-common" - } - }, - "owners": [ - { - "urn": "owner::bq/3", - "name": "Mr.X", - "role": "admin", - "email": "mr.x@email.com" - }, - { - "urn": "owner::bq/4", - "name": "Mrs.Y", - "role": "user", - "email": "mr.y@email.com" - } - ], - "type": "table" - }, - { - "id": "bigquery::gcpproject/dataset/tablename-mid", - "urn": "bigquery::gcpproject/dataset/tablename-mid", - "name": "tablename-mid", - "service": "bigquery", - "description": "A sample of table record with mid usage", - "data": { - "preview": {}, - "profile": { - "common_join": [ - { - "conditions": [ - "ON target.column_1 = source.column_1 and target.column_3 = source.column_3 and DATE(target.event_timestamp) = DATE(source.event_timestamp)" - ], - "count": 1, - "urn": "bigquery::gcpproject/dataset/tablename-high" - }, - { - "conditions": [ - "ON target.column_1 = source.column_1 and target.column_3 = source.column_3 and DATE(target.event_timestamp) = DATE(source.event_timestamp)" - ], - "count": 1, - "urn": "bigquery::gcpproject/dataset/tablename-1" - } - ], - "filter_conditions": [ - "WHERE t.column_5 = 'success' AND t.item_id = \"280481a2-2384-4b81-aa3e-214ac60b31db\" AND event_timestamp >= TIMESTAMP(\"2021-10-29\", \"UTC\") AND event_timestamp < TIMESTAMP(\"2021-11-22T02:01:06Z\")" - ], - "usage_count": 5 - }, - "properties": { - "attributes": { - "dataset": "dataset", - "full_qualified_name": "gcpproject:dataset.tablename-mid", - "partition_field": "event_timestamp", - "project": "gcpproject", - "type": "TABLE" - }, - "labels": { - "owner": "user_1" - } - }, - "schema": { - "columns": [ - { - "data_type": "STRING", - "is_nullable": true, - "name": "tablename-mid-column1", - "properties": { - "attributes": { - "mode": "NULLABLE" - } - } - }, - { - "data_type": "STRING", - "is_nullable": true, - "name": "tablename-mid-column2", - "properties": { - "attributes": { - "mode": "NULLABLE" - } - } - }, - { - "data_type": "BIGNUMERIC", - "is_nullable": true, - "name": "tablename-mid-column3", - "properties": { - "attributes": { - "mode": "NULLABLE" - } - } - } - ] - }, - "resource": { - "name": "tablename-mid", - "service": "bigquery", - "urn": "bigquery::gcpproject/dataset/tablename-mid" - } - }, - "owners": [ - { - "urn": "owner::bq/1", - "name": "John Smith", - "role": "user", - "email": "john.smith@email.com" - }, - { - "urn": "owner::bq/2", - "name": "Paul Smith", - "role": "user", - "email": "paul.smith@email.com" - } - ], - "type": "table" - } - ] - } -] diff --git a/store/elasticsearch/testdata/suggest-test-fixture.json b/store/elasticsearch/testdata/suggest-test-fixture.json deleted file mode 100644 index 49c262d3..00000000 --- a/store/elasticsearch/testdata/suggest-test-fixture.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "assets": [ - {"id": "wallet/event","name": "wallet/event", "urn": "wallet/event","service": "kafka","type": "topic"}, - {"id": "wallet-usage","name": "wallet-usage", "urn": "wallet-usage","service": "kafka","type": "topic"}, - {"id": "wallet_usage","name": "wallet_usage", "urn": "wallet_usage","service": "kafka","type": "topic"}, - {"id": "pay_wall", "name": "pay_wall", "urn": "pay_wall","service": "kafka","type": "topic"}, - {"id": "failed_purchae","name": "failed_purchase", "urn": "failed_purchase","service": "kafka","type": "topic"}, - {"id": "successful_purchase","name": "successful_purchase", "urn": "successful_purchase","service": "kafka","type": "topic"}, - {"id": "test_table","name": "test_table", "urn": "test_table","service": "kafka","type": "topic"} - ] - }, - { - "assets": [ - {"id": "invoice" ,"name": "invoice", "urn": "invoice", "service": "bigquery","type": "table"}, - {"id": "user.address","name": "user.address", "urn": "user.address", "service": "bigquery","type": "table"}, - {"id": "user_wallet", "name": "user_wallet", "urn": "user_wallet", "service": "bigquery","type": "table"}, - {"id": "product","name": "product", "urn": "product", "service": "bigquery","type": "table"}, - {"id": "product_category","name": "product_category", "urn": "product_category", "service": "bigquery","type": "table"} - ] - } -] diff --git a/store/elasticsearch/testutil/elastic_search.go b/store/elasticsearch/testutil/elastic_search.go deleted file mode 100644 index d4da448f..00000000 --- a/store/elasticsearch/testutil/elastic_search.go +++ /dev/null @@ -1,223 +0,0 @@ -package testutil - -import ( - "fmt" - "io" - "net/http" - "net/url" - "os" - "os/exec" - "strings" - "time" - - "github.com/elastic/go-elasticsearch/v8" -) - -var ( - elasticSearchCmdLine = []string{ - "docker", "run", - "-d", "-P", "--rm", - "-e", "discovery.type=single-node", - "-e", "path.data=/opt/elasticsearch/volatile/data", - "-e", "path.logs=/opt/elasticsearch/volatile/logs", - "-e", "bootstrap.memory_lock=true", - "-e", "ES_JAVA_OPTS=-Xms128m -Xmx128m -server", - "-e", "ES_HEAP_SIZE=128m", - "-e", "MAX_LOCKED_MEMORY=100000", - "-e", "xpack.security.enabled=false", - "--memory-swappiness=0", - "--memory-swap=0", - "--tmpfs", "/opt/elasticsearch/volatile/data:rw", - "--tmpfs", "/opt/elasticsearch/volatile/logs:rw", - "--tmpfs", "/tmp:rw", - "--ulimit", "memlock=-1:-1", - "docker.elastic.co/elasticsearch/elasticsearch:8.17.1", - } - // "9200/tcp" refers to the default container port where elasticsearch server runs - esHostQuery = `{{index .NetworkSettings.Ports "9200/tcp" 0 "HostIp"}}:{{index .NetworkSettings.Ports "9200/tcp" 0 "HostPort"}}` -) - -// ElasticsearchTestServer is a single node elastic-search -// cluster running inside docker. -// use NewElasticsearchTestServer to instantiate the server -type ElasticsearchTestServer struct { - url *url.URL - containerID string - client *elasticsearch.Client -} - -// NewElasticsearchTestServer creates a new instance of elasticsearch test server. -// It runs a single node elasticsearch cluster in docker, exposing the REST -// API over a random ephemeral port. -// OR if the environment variable ES_TEST_SERVER_URL is set, it acts as -// a dumb proxy to it. -// The idea is to be able to easily run integration tests in local environments, -// while also being able to leverage a running ES instance for testing (for instance in CI pipelines) -// Make sure to call server.Close() once you're done, otherwise the docker -// container may be left running indefinitely in the background. -func NewElasticsearchTestServer() *ElasticsearchTestServer { - var server ElasticsearchTestServer - defer func() { - if p := recover(); p != nil { - server.Close() - panic(p) - } - }() - - esURL, ok := os.LookupEnv("ES_TEST_SERVER_URL") - if ok { - // use TestServer as a proxy to an existing elasticsearch instance - u, err := url.Parse(esURL) - if err != nil { - panic(fmt.Sprintf("error parsing elastisearch url: %v", err)) - } - server.url = u - } else { - // run a new elasticsearch server inside a docker container - idBytes, err := exec.Command(elasticSearchCmdLine[0], elasticSearchCmdLine[1:]...).Output() - if err != nil { - exitErr, ok := err.(*exec.ExitError) - if ok { - err = fmt.Errorf("%v: %s", err, exitErr.Stderr) - } - panic(fmt.Sprintf("failed to start elasticsearch server: %v", err)) - } - server.containerID = strings.TrimSpace(string(idBytes)) - - // obtain the ephemeral host port which is bound to the container port - hostBytes, err := exec.Command("docker", "inspect", "-f", esHostQuery, server.containerID).Output() - if err != nil { - panic(fmt.Sprintf("unable to obtain metadata for elasticsearch server: %v", err)) - } - - // add the server url to server - server.url = &url.URL{ - Scheme: "http", - Host: strings.TrimSpace(string(hostBytes)), - } - } - - // wait for the elasticsearch server to come up - timeout := 5 * time.Minute - if err := server.wait4Ready(timeout); err != nil { - panic(fmt.Sprintf("error checking elasticsearch status: %v", err)) - } - - // create the client - var err error - server.client, err = elasticsearch.NewClient( - elasticsearch.Config{ - Addresses: []string{ - server.url.String(), - }, - // uncomment below code to debug request and response to elasticsearch - //Logger: &estransport.ColorLogger{ - // Output: os.Stdout, - // EnableRequestBody: true, - // EnableResponseBody: true, - //}, - }, - ) - if err != nil { - panic(fmt.Sprintf("error creating elasticsearch client: %v", err)) - } - - return &server -} - -// NewClient returns an elasticsearch client for the test server -// Calling this method issues a DELETE /_all call to the elasticsearch -// server, effectively resetting it. -func (srv *ElasticsearchTestServer) NewClient() (*elasticsearch.Client, error) { - if err := srv.purge(srv.client); err != nil { - return nil, fmt.Errorf("error purging elasticsearch: %w", err) - } - return srv.client, nil -} - -func (srv *ElasticsearchTestServer) Close() error { - if strings.TrimSpace(srv.containerID) == "" { - return nil - } - return exec.Command("docker", "kill", srv.containerID).Run() -} - -func (srv *ElasticsearchTestServer) purge(cli *elasticsearch.Client) (err error) { - defer func() { - if err != nil { - err = fmt.Errorf("purge: %w", err) - } - }() - - // List all non-system indices first. ES 8.x protects system indices - // (dot-prefixed) from deletion, so we must discover user indices - // explicitly and delete only those. - catReq, err := http.NewRequest("GET", "/_cat/indices?h=index&format=json&expand_wildcards=open,closed", nil) - if err != nil { - return err - } - catRes, err := cli.Perform(catReq) - if err != nil { - return err - } - defer catRes.Body.Close() - body, err := io.ReadAll(catRes.Body) - if err != nil { - return err - } - - // Extract index names from the JSON array of {"index":"name"} objects. - // Use simple string parsing to avoid adding an encoding/json dependency - // just for tests. The response looks like: [{"index":"foo"},{"index":"bar"}] - var indices []string - for _, part := range strings.Split(string(body), "\"index\":\"") { - if idx := strings.Index(part, "\""); idx > 0 { - name := part[:idx] - // Skip system indices (dot-prefixed) - if !strings.HasPrefix(name, ".") { - indices = append(indices, name) - } - } - } - - // Nothing to delete on a fresh ES instance. - if len(indices) == 0 { - return nil - } - - target := strings.Join(indices, ",") - delReq, err := http.NewRequest("DELETE", "/"+target, nil) - if err != nil { - return err - } - q := delReq.URL.Query() - q.Set("ignore_unavailable", "true") - delReq.URL.RawQuery = q.Encode() - delRes, err := cli.Perform(delReq) - if err != nil { - return err - } - defer delRes.Body.Close() - if delRes.StatusCode > 299 { - respBody, _ := io.ReadAll(delRes.Body) - return fmt.Errorf("elasticsearch server returned status code %d: %s", delRes.StatusCode, respBody) - } - return nil -} - -func (srv *ElasticsearchTestServer) wait4Ready(timeout time.Duration) error { - catURL := srv.url.ResolveReference(&url.URL{Path: "/_cat"}) - deadline := time.Now().Add(timeout) - for time.Now().Before(deadline) { - time.Sleep(100 * time.Millisecond) - res, err := http.Get(catURL.String()) - if err != nil { - continue - } - res.Body.Close() - if res.StatusCode == 200 { - return nil - } - } - return fmt.Errorf("timed out after %s", timeout) -} diff --git a/store/postgres/asset_model.go b/store/postgres/asset_model.go deleted file mode 100644 index b6b4bcaa..00000000 --- a/store/postgres/asset_model.go +++ /dev/null @@ -1,195 +0,0 @@ -package postgres - -import ( - "database/sql/driver" - "encoding/json" - "errors" - "fmt" - "time" - - "github.com/jmoiron/sqlx/types" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/user" - "github.com/r3labs/diff/v3" -) - -type AssetModel struct { - ID string `db:"id"` - NamespaceID string `db:"namespace_id"` - URN string `db:"urn"` - Type string `db:"type"` - Name string `db:"name"` - Service string `db:"service"` - Description string `db:"description"` - Data JSONMap `db:"data"` - URL string `db:"url"` - Labels JSONMap `db:"labels"` - Version string `db:"version"` - IsDeleted bool `db:"is_deleted"` - UpdatedBy UserModel `db:"updated_by"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` - RefreshedAt *time.Time `db:"refreshed_at"` - // version specific information - Changelog types.JSONText `db:"changelog"` - Owners types.JSONText `db:"owners"` -} - -func (a *AssetModel) toAsset(owners []user.User) asset.Asset { - return asset.Asset{ - ID: a.ID, - URN: a.URN, - Type: asset.Type(a.Type), - Name: a.Name, - Service: a.Service, - Description: a.Description, - Data: a.Data, - URL: a.URL, - Labels: a.buildLabels(), - Owners: owners, - IsDeleted: a.IsDeleted, - Version: a.Version, - UpdatedBy: a.UpdatedBy.toUser(), - CreatedAt: a.CreatedAt, - UpdatedAt: a.UpdatedAt, - RefreshedAt: a.RefreshedAt, - } -} - -func (a *AssetModel) toAssetVersion() (asset.Asset, error) { - var clog diff.Changelog - if len(a.Changelog) > 0 && string(a.Changelog) != "{}" { - if err := a.Changelog.Unmarshal(&clog); err != nil { - return asset.Asset{}, err - } - } - - return asset.Asset{ - ID: a.ID, - URN: a.URN, - Type: asset.Type(a.Type), - Service: a.Service, - Version: a.Version, - Changelog: clog, - UpdatedBy: a.UpdatedBy.toUser(), - CreatedAt: a.CreatedAt, - }, nil -} - -func (a *AssetModel) toVersionedAsset(latestAssetVersion asset.Asset) (asset.Asset, error) { - var owners []user.User - if len(a.Owners) > 0 && string(a.Owners) != "{}" { - if err := a.Owners.Unmarshal(&owners); err != nil { - return asset.Asset{}, err - } - } - - var clog diff.Changelog - if len(a.Changelog) > 0 && string(a.Changelog) != "{}" { - if err := a.Changelog.Unmarshal(&clog); err != nil { - return asset.Asset{}, err - } - } - - return asset.Asset{ - ID: latestAssetVersion.ID, - URN: latestAssetVersion.URN, - Type: latestAssetVersion.Type, - Name: a.Name, - Service: latestAssetVersion.Service, - Description: a.Description, - Data: a.Data, - Labels: a.buildLabels(), - Owners: owners, - Version: a.Version, - UpdatedBy: a.UpdatedBy.toUser(), - CreatedAt: a.CreatedAt, - UpdatedAt: a.UpdatedAt, - Changelog: clog, - }, nil -} - -func (a *AssetModel) buildLabels() map[string]string { - if a.Labels == nil { - return nil - } - - result := make(map[string]string) - for key, value := range a.Labels { - strKey := fmt.Sprintf("%v", key) - strValue := fmt.Sprintf("%v", value) - - result[strKey] = strValue - } - - return result -} - -type AssetProbeModel struct { - ID string `db:"id"` - AssetURN string `db:"asset_urn"` - Status string `db:"status"` - StatusReason string `db:"status_reason"` - Metadata JSONMap `db:"metadata"` - Timestamp time.Time `db:"timestamp"` - CreatedAt time.Time `db:"created_at"` -} - -func (m *AssetProbeModel) toAssetProbe() asset.Probe { - return asset.Probe{ - ID: m.ID, - AssetURN: m.AssetURN, - Status: m.Status, - StatusReason: m.StatusReason, - Metadata: m.Metadata, - Timestamp: m.Timestamp, - CreatedAt: m.CreatedAt, - } -} - -type JSONMap map[string]interface{} - -func (m JSONMap) Value() (driver.Value, error) { - if m == nil { - return nil, nil - } - ba, err := m.MarshalJSON() - return string(ba), err -} - -func (m *JSONMap) Scan(value interface{}) error { - if value == nil { - *m = nil - return nil - } - var ba []byte - switch v := value.(type) { - case []byte: - ba = v - case string: - ba = []byte(v) - default: - return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value)) - } - t := map[string]interface{}{} - err := json.Unmarshal(ba, &t) - *m = JSONMap(t) - return err -} - -// MarshalJSON to output encoded []byte -func (m JSONMap) MarshalJSON() ([]byte, error) { - if m == nil { - return []byte("null"), nil - } - t := (map[string]interface{})(m) - return json.Marshal(t) -} - -// UnmarshalJSON to deserialize []byte -func (m *JSONMap) UnmarshalJSON(b []byte) error { - t := map[string]interface{}{} - err := json.Unmarshal(b, &t) - *m = JSONMap(t) - return err -} diff --git a/store/postgres/asset_model_test.go b/store/postgres/asset_model_test.go deleted file mode 100644 index 24ac7a20..00000000 --- a/store/postgres/asset_model_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package postgres_test - -import ( - "testing" - - "github.com/raystack/compass/store/postgres" - "github.com/stretchr/testify/assert" -) - -func TestJSONMap(t *testing.T) { - t.Run("return no error for valid type of value", func(t *testing.T) { - value := []byte(`{"key1":"val1","key2":"val2"}`) - m := postgres.JSONMap{} - err := m.Scan(value) - assert.NoError(t, err) - s, err := m.Value() - assert.Equal(t, string(value), s) - assert.NoError(t, err) - b, err := m.MarshalJSON() - assert.NoError(t, err) - err = m.UnmarshalJSON(b) - assert.NoError(t, err) - }) -} diff --git a/store/postgres/asset_repository.go b/store/postgres/asset_repository.go deleted file mode 100644 index 7117f3ce..00000000 --- a/store/postgres/asset_repository.go +++ /dev/null @@ -1,1058 +0,0 @@ -package postgres - -import ( - "context" - "database/sql" - "encoding/json" - "errors" - "fmt" - "github.com/raystack/compass/core/namespace" - "strings" - "time" - - sq "github.com/Masterminds/squirrel" - "github.com/jmoiron/sqlx" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/user" - "github.com/r3labs/diff/v3" -) - -// AssetRepository is a type that manages user operation to the primary database -type AssetRepository struct { - client *Client - userRepo *UserRepository - defaultGetMaxSize int - defaultUserProvider string -} - -// GetAll retrieves list of assets with filters -func (r *AssetRepository) GetAll(ctx context.Context, flt asset.Filter) ([]asset.Asset, error) { - if err := flt.Validate(); err != nil { - return nil, err - } - - builder := r.getAssetSQL().Offset(uint64(flt.Offset)) - size := flt.Size - - if size > 0 { - builder = r.getAssetSQL().Limit(uint64(size)).Offset(uint64(flt.Offset)) - } - builder = r.BuildFilterQuery(builder, flt) - builder = r.buildOrderQuery(builder, flt) - query, args, err := r.buildSQL(builder) - if err != nil { - return nil, fmt.Errorf("error building query: %w", err) - } - - var ams []*AssetModel - err = r.client.SelectContext(ctx, &ams, query, args...) - if err != nil { - return nil, fmt.Errorf("error getting asset list: %w", err) - } - - assets := []asset.Asset{} - for _, am := range ams { - assets = append(assets, am.toAsset(nil)) - } - - return assets, nil -} - -// GetTypes fetches types with assets count for all available types -// and returns them as a map[typeName]count -func (r *AssetRepository) GetTypes(ctx context.Context, flt asset.Filter) (map[asset.Type]int, error) { - if err := flt.Validate(); err != nil { - return nil, err - } - builder := r.getAssetsGroupByCountSQL("type") - builder = r.BuildFilterQuery(builder, flt) - query, args, err := r.buildSQL(builder) - if err != nil { - return nil, fmt.Errorf("error building get type query: %w", err) - } - - results := make(map[asset.Type]int) - - err = r.client.QueryFn(ctx, func(conn *sqlx.Conn) error { - rows, ferr := conn.QueryxContext(ctx, query, args...) - if ferr != nil { - return fmt.Errorf("error getting type of assets: %w", ferr) - } - for rows.Next() { - row := make(map[string]interface{}) - err = rows.MapScan(row) - if ferr != nil { - return ferr - } - typeStr, ok := row["type"].(string) - if !ok { - return ferr - } - typeCount, ok := row["count"].(int64) - if !ok { - return ferr - } - typeName := asset.Type(typeStr) - if typeName.IsValid() { - results[typeName] = int(typeCount) - } - } - return nil - }) - if err != nil { - return nil, err - } - - return results, nil -} - -// GetCount retrieves number of assets for every type -func (r *AssetRepository) GetCount(ctx context.Context, flt asset.Filter) (total int, err error) { - if err := flt.Validate(); err != nil { - return 0, err - } - builder := sq.Select("count(1)").From("assets") - builder = r.BuildFilterQuery(builder, flt) - query, args, err := r.buildSQL(builder) - if err != nil { - err = fmt.Errorf("error building count query: %w", err) - return - } - err = r.client.GetContext(ctx, &total, query, args...) - if err != nil { - err = fmt.Errorf("error getting asset list: %w", err) - } - - return -} - -// GetByID retrieves asset by its ID -func (r *AssetRepository) GetByID(ctx context.Context, id string) (asset.Asset, error) { - if !isValidUUID(id) { - return asset.Asset{}, asset.InvalidError{AssetID: id} - } - - ast, err := r.getWithPredicate(ctx, sq.Eq{"a.id": id}) - if errors.Is(err, sql.ErrNoRows) { - return asset.Asset{}, asset.NotFoundError{AssetID: id} - } - if err != nil { - return asset.Asset{}, fmt.Errorf("error getting asset with ID = %q: %w", id, err) - } - - return ast, nil -} - -func (r *AssetRepository) GetByURN(ctx context.Context, urn string) (asset.Asset, error) { - ast, err := r.getWithPredicate(ctx, sq.Eq{"a.urn": urn}) - if errors.Is(err, sql.ErrNoRows) { - return asset.Asset{}, asset.NotFoundError{URN: urn} - } - if err != nil { - return asset.Asset{}, fmt.Errorf("error getting asset with URN = %q: %w", urn, err) - } - - return ast, nil -} - -func (r *AssetRepository) getWithPredicate(ctx context.Context, pred sq.Eq) (asset.Asset, error) { - builder := r.getAssetSQL(). - Where(pred). - Limit(1) - query, args, err := r.buildSQL(builder) - if err != nil { - return asset.Asset{}, fmt.Errorf("error building query: %w", err) - } - - var am AssetModel - err = r.client.GetContext(ctx, &am, query, args...) - if err != nil { - return asset.Asset{}, err - } - - owners, err := r.getOwners(ctx, am.ID) - if err != nil { - return asset.Asset{}, err - } - - return am.toAsset(owners), nil -} - -// GetVersionHistory retrieves the versions of an asset -func (r *AssetRepository) GetVersionHistory(ctx context.Context, flt asset.Filter, id string) (avs []asset.Asset, err error) { - if !isValidUUID(id) { - err = asset.InvalidError{AssetID: id} - return - } - if err := flt.Validate(); err != nil { - return nil, err - } - - size := flt.Size - if size == 0 { - size = r.defaultGetMaxSize - } - - builder := r.getAssetVersionSQL(). - Where(sq.Eq{"a.asset_id": id}). - OrderBy("string_to_array(version, '.')::int[] DESC"). - Limit(uint64(size)). - Offset(uint64(flt.Offset)) - query, args, err := r.buildSQL(builder) - if err != nil { - err = fmt.Errorf("error building query: %w", err) - return - } - - var assetModels []AssetModel - err = r.client.SelectContext(ctx, &assetModels, query, args...) - if err != nil { - err = fmt.Errorf("failed fetching last versions: %w", err) - return - } - - if len(assetModels) == 0 { - err = asset.NotFoundError{AssetID: id} - return - } - - for _, am := range assetModels { - av, ferr := am.toAssetVersion() - if ferr != nil { - err = fmt.Errorf("failed converting asset model to asset version: %w", ferr) - return - } - avs = append(avs, av) - } - - return avs, nil -} - -// GetByVersionWithID retrieves the specific asset version -func (r *AssetRepository) GetByVersionWithID(ctx context.Context, id string, version string) (asset.Asset, error) { - if !isValidUUID(id) { - return asset.Asset{}, asset.InvalidError{AssetID: id} - } - - ast, err := r.getByVersion(ctx, id, version, r.GetByID, sq.Eq{ - "a.asset_id": id, - "a.version": version, - }) - if errors.Is(err, sql.ErrNoRows) { - return asset.Asset{}, asset.NotFoundError{AssetID: id} - } - if err != nil { - return asset.Asset{}, err - } - - return ast, nil -} - -func (r *AssetRepository) GetByVersionWithURN(ctx context.Context, urn string, version string) (asset.Asset, error) { - ast, err := r.getByVersion(ctx, urn, version, r.GetByURN, sq.Eq{ - "a.urn": urn, - "a.version": version, - }) - if errors.Is(err, sql.ErrNoRows) { - return asset.Asset{}, asset.NotFoundError{URN: urn} - } - if err != nil { - return asset.Asset{}, err - } - - return ast, nil -} - -type getAssetFunc func(context.Context, string) (asset.Asset, error) - -func (r *AssetRepository) getByVersion( - ctx context.Context, id, version string, get getAssetFunc, pred sq.Eq, -) (asset.Asset, error) { - latest, err := get(ctx, id) - if err != nil { - return asset.Asset{}, err - } - - if latest.Version == version { - return latest, nil - } - - var ast AssetModel - builder := r.getAssetVersionSQL(). - Where(pred) - query, args, err := r.buildSQL(builder) - if err != nil { - return asset.Asset{}, fmt.Errorf("error building query: %w", err) - } - - err = r.client.GetContext(ctx, &ast, query, args...) - if err != nil { - return asset.Asset{}, fmt.Errorf("failed fetching asset version: %w", err) - } - - return ast.toVersionedAsset(latest) -} - -// Upsert creates a new asset if it does not exist yet. -// It updates if asset does exist. -// Checking existence is done using "urn", "type", and "service" fields. -func (r *AssetRepository) Upsert(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset) (string, error) { - fetchedAsset, err := r.GetByURN(ctx, ast.URN) - if errors.As(err, new(asset.NotFoundError)) { - err = nil - } - if err != nil { - return "", fmt.Errorf("error getting asset by URN: %w", err) - } - - if fetchedAsset.ID == "" { - // insert flow - id, err := r.insert(ctx, ns, ast) - if err != nil { - return id, fmt.Errorf("error inserting asset to DB: %w", err) - } - return id, nil - } - - // update flow - changelog, err := fetchedAsset.Diff(ast) - if err != nil { - return "", fmt.Errorf("error diffing two assets: %w", err) - } - - err = r.update(ctx, ns, fetchedAsset.ID, ast, &fetchedAsset, changelog) - if err != nil { - return "", fmt.Errorf("error updating asset to DB: %w", err) - } - - return fetchedAsset.ID, nil -} - -// DeleteByID removes asset using its ID -func (r *AssetRepository) DeleteByID(ctx context.Context, id string) error { - if !isValidUUID(id) { - return asset.InvalidError{AssetID: id} - } - - affectedRows, err := r.deleteWithPredicate(ctx, sq.Eq{"id": id}) - if err != nil { - return fmt.Errorf("error deleting asset with ID = %q: %w", id, err) - } - if affectedRows == 0 { - return asset.NotFoundError{AssetID: id} - } - - return nil -} - -func (r *AssetRepository) DeleteByURN(ctx context.Context, urn string) error { - affectedRows, err := r.deleteWithPredicate(ctx, sq.Eq{"urn": urn}) - if err != nil { - return fmt.Errorf("error deleting asset with URN = %q: %w", urn, err) - } - if affectedRows == 0 { - return asset.NotFoundError{URN: urn} - } - - return nil -} - -// SoftDeleteByID marks an asset as deleted by its ID -func (r *AssetRepository) SoftDeleteByID(ctx context.Context, id string) (string, error) { - if !isValidUUID(id) { - return "", asset.InvalidError{AssetID: id} - } - - return r.softDeleteWithPredicate(ctx, sq.Eq{"id": id, "is_deleted": false}) -} - -// SoftDeleteByURN marks an asset as deleted by its URN -func (r *AssetRepository) SoftDeleteByURN(ctx context.Context, urn string) (string, error) { - return r.softDeleteWithPredicate(ctx, sq.Eq{"urn": urn, "is_deleted": false}) -} - -func (r *AssetRepository) softDeleteWithPredicate(ctx context.Context, pred sq.Eq) (string, error) { - now := time.Now().UTC() - query, args, err := r.buildSQL(sq.Update("assets"). - Set("is_deleted", true). - Set("updated_at", now). - Set("refreshed_at", now). - Where(pred). - Suffix("RETURNING urn")) - if err != nil { - return "", fmt.Errorf("error building query: %w", err) - } - - var urn string - err = r.client.QueryFn(ctx, func(conn *sqlx.Conn) error { - return conn.QueryRowxContext(ctx, query, args...).Scan(&urn) - }) - if errors.Is(err, sql.ErrNoRows) { - return "", asset.ErrAssetAlreadyDeleted - } - if err != nil { - return "", fmt.Errorf("error soft deleting asset: %w", err) - } - - return urn, nil -} - -// GetCountByIsDeleted returns count of assets by deletion status -func (r *AssetRepository) GetCountByIsDeleted(ctx context.Context, isDeleted bool) (int, error) { - var total int - query, args, err := r.buildSQL(sq.Select("count(1)").From("assets").Where(sq.Eq{"is_deleted": isDeleted})) - if err != nil { - return 0, fmt.Errorf("error building count query: %w", err) - } - err = r.client.GetContext(ctx, &total, query, args...) - if err != nil { - return 0, fmt.Errorf("error counting assets: %w", err) - } - return total, nil -} - -// HardDeleteByURNs permanently removes assets by their URNs -func (r *AssetRepository) HardDeleteByURNs(ctx context.Context, urns []string) error { - if len(urns) == 0 { - return nil - } - - query, args, err := r.buildSQL(sq.Delete("assets").Where(sq.Eq{"urn": urns})) - if err != nil { - return fmt.Errorf("error building query: %w", err) - } - - _, err = r.client.ExecContext(ctx, query, args...) - if err != nil { - return fmt.Errorf("error hard deleting assets: %w", err) - } - - return nil -} - -func (r *AssetRepository) AddProbe(ctx context.Context, ns *namespace.Namespace, assetURN string, probe *asset.Probe) error { - probe.AssetURN = assetURN - probe.CreatedAt = time.Now().UTC() - if probe.Timestamp.IsZero() { - probe.Timestamp = probe.CreatedAt - } else { - probe.Timestamp = probe.Timestamp.UTC() - } - - query, args, err := sq.Insert("asset_probes"). - Columns("asset_urn", "status", "status_reason", "metadata", "timestamp", "created_at", "namespace_id"). - Values(assetURN, probe.Status, probe.StatusReason, probe.Metadata, probe.Timestamp, probe.CreatedAt, ns.ID). - Suffix("RETURNING \"id\""). - PlaceholderFormat(sq.Dollar). - ToSql() - if err != nil { - return fmt.Errorf("error building insert asset probe query: %w", err) - } - - err = r.client.QueryFn(ctx, func(conn *sqlx.Conn) error { - return conn.QueryRowxContext(ctx, query, args...).Scan(&probe.ID) - }) - if errors.Is(checkPostgresError(err), errForeignKeyViolation) { - return asset.NotFoundError{URN: assetURN} - } else if err != nil { - return fmt.Errorf("error running insert asset probe query: %w", err) - } - - return nil -} - -func (r *AssetRepository) GetProbes(ctx context.Context, assetURN string) ([]asset.Probe, error) { - query, args, err := sq.Select( - "id", "asset_urn", "status", "status_reason", "metadata", "timestamp", "created_at", - ).From("asset_probes"). - OrderBy("timestamp DESC", "created_at DESC", "id DESC"). - Where(sq.Eq{"asset_urn": assetURN}). - PlaceholderFormat(sq.Dollar). - ToSql() - if err != nil { - return nil, fmt.Errorf("error building get asset probes query: %w", err) - } - - var models []AssetProbeModel - if err := r.client.SelectContext(ctx, &models, query, args...); err != nil { - return nil, fmt.Errorf("error running get asset probes query: %w", err) - } - - results := []asset.Probe{} - for _, m := range models { - results = append(results, m.toAssetProbe()) - } - - return results, nil -} - -func (r *AssetRepository) GetProbesWithFilter(ctx context.Context, flt asset.ProbesFilter) (map[string][]asset.Probe, error) { - stmt := sq.Select( - "id", "asset_urn", "status", "status_reason", "metadata", "timestamp", "created_at", - ).From("asset_probes"). - OrderBy("asset_urn", "timestamp DESC") - - if len(flt.AssetURNs) > 0 { - stmt = stmt.Where(sq.Eq{"asset_urn": flt.AssetURNs}) - } - if !flt.NewerThan.IsZero() { - stmt = stmt.Where(sq.GtOrEq{"timestamp": flt.NewerThan}) - } - if !flt.OlderThan.IsZero() { - stmt = stmt.Where(sq.LtOrEq{"timestamp": flt.OlderThan}) - } - if flt.MaxRows > 0 { - stmt = stmt.Column("RANK() OVER (PARTITION BY asset_urn ORDER BY timestamp desc) rank_number") - stmt = sq.Select( - "id", "asset_urn", "status", "status_reason", "metadata", "timestamp", "created_at", - ).FromSelect(stmt, "ap"). - Where(sq.LtOrEq{"rank_number": flt.MaxRows}) - } - - query, args, err := stmt.PlaceholderFormat(sq.Dollar).ToSql() - if err != nil { - return nil, fmt.Errorf("get probes with filter: build query: %w", err) - } - - var probes []AssetProbeModel - if err := r.client.SelectContext(ctx, &probes, query, args...); err != nil { - return nil, fmt.Errorf("error running get asset probes query: %w", err) - } - - results := make(map[string][]asset.Probe, len(probes)) - for _, p := range probes { - results[p.AssetURN] = append(results[p.AssetURN], p.toAssetProbe()) - } - - return results, nil -} - -func (r *AssetRepository) deleteWithPredicate(ctx context.Context, pred sq.Eq) (int64, error) { - query, args, err := r.buildSQL(sq.Delete("assets").Where(pred)) - if err != nil { - return 0, fmt.Errorf("error building query: %w", err) - } - - res, err := r.client.ExecContext(ctx, query, args...) - if err != nil { - return 0, err - } - - affectedRows, err := res.RowsAffected() - if err != nil { - return 0, fmt.Errorf("error getting affected rows: %w", err) - } - - return affectedRows, nil -} - -func (r *AssetRepository) insert(ctx context.Context, ns *namespace.Namespace, ast *asset.Asset) (id string, err error) { - err = r.client.RunWithinTx(ctx, func(tx *sqlx.Tx) error { - now := time.Now().UTC() - ast.CreatedAt = now - ast.UpdatedAt = now - query, args, err := sq.Insert("assets"). - Columns("urn", "namespace_id", "type", "service", "name", "description", "data", "url", "labels", "updated_by", "version", "created_at", "updated_at", "refreshed_at"). - Values(ast.URN, ns.ID, ast.Type, ast.Service, ast.Name, ast.Description, ast.Data, ast.URL, ast.Labels, ast.UpdatedBy.ID, asset.BaseVersion, now, now, now). - Suffix("RETURNING \"id\""). - PlaceholderFormat(sq.Dollar). - ToSql() - if err != nil { - return fmt.Errorf("error building insert query: %w", err) - } - - ast.Version = asset.BaseVersion - - err = tx.QueryRowContext(ctx, query, args...).Scan(&id) - if err != nil { - return fmt.Errorf("error running insert query: %w", err) - } - - users, err := r.createOrFetchUsers(ctx, tx, ns, ast.Owners) - if err != nil { - return fmt.Errorf("error creating and fetching owners: %w", err) - } - - err = r.insertOwners(ctx, tx, id, users) - if err != nil { - return fmt.Errorf("error running insert owners query: %w", err) - } - - // insert versions - ast.ID = id - if err = r.insertAssetVersion(ctx, tx, ns, ast, diff.Changelog{}); err != nil { - return err - } - - return nil - }) - - return -} - -func (r *AssetRepository) update(ctx context.Context, ns *namespace.Namespace, assetID string, newAsset *asset.Asset, oldAsset *asset.Asset, clog diff.Changelog) error { - if !isValidUUID(assetID) { - return asset.InvalidError{AssetID: assetID} - } - - if len(clog) == 0 { - return nil - } - - return r.client.RunWithinTx(ctx, func(tx *sqlx.Tx) error { - // update assets - newVersion, err := asset.IncreaseMinorVersion(oldAsset.Version) - if err != nil { - return err - } - newAsset.Version = newVersion - newAsset.ID = oldAsset.ID - newAsset.CreatedAt = oldAsset.CreatedAt - - now := time.Now().UTC() - newAsset.UpdatedAt = now - query, args, err := r.buildSQL(sq.Update("assets"). - Set("urn", newAsset.URN). - Set("type", newAsset.Type). - Set("service", newAsset.Service). - Set("name", newAsset.Name). - Set("description", newAsset.Description). - Set("data", newAsset.Data). - Set("url", newAsset.URL). - Set("labels", newAsset.Labels). - Set("updated_at", newAsset.UpdatedAt). - Set("refreshed_at", now). - Set("is_deleted", false). - Set("updated_by", newAsset.UpdatedBy.ID). - Set("version", newAsset.Version). - Where(sq.Eq{"id": assetID}).Where(sq.Eq{"namespace_id": ns.ID})) - if err != nil { - return fmt.Errorf("build query: %w", err) - } - - if err := r.execContext(ctx, tx, query, args...); err != nil { - return fmt.Errorf("error running update asset query: %w", err) - } - - // insert versions - if err = r.insertAssetVersion(ctx, tx, ns, newAsset, clog); err != nil { - return err - } - - // managing owners - newAssetOwners, err := r.createOrFetchUsers(ctx, tx, ns, newAsset.Owners) - if err != nil { - return fmt.Errorf("error creating and fetching owners: %w", err) - } - toInserts, toRemoves := r.compareOwners(oldAsset.Owners, newAssetOwners) - if err := r.insertOwners(ctx, tx, assetID, toInserts); err != nil { - return fmt.Errorf("error inserting asset's new owners: %w", err) - } - if err := r.removeOwners(ctx, tx, assetID, toRemoves); err != nil { - return fmt.Errorf("error removing asset's old owners: %w", err) - } - - return nil - }) -} - -func (r *AssetRepository) insertAssetVersion(ctx context.Context, execer sqlx.ExecerContext, ns *namespace.Namespace, oldAsset *asset.Asset, clog diff.Changelog) (err error) { - if oldAsset == nil { - err = asset.ErrNilAsset - return - } - - if clog == nil { - err = fmt.Errorf("changelog is nil when insert to asset version") - return - } - - jsonChangelog, err := json.Marshal(clog) - if err != nil { - return err - } - query, args, err := sq.Insert("assets_versions"). - Columns("asset_id", "urn", "type", "service", "name", "description", "data", "labels", "created_at", "updated_at", "updated_by", "version", "owners", "changelog", "namespace_id"). - Values(oldAsset.ID, oldAsset.URN, oldAsset.Type, oldAsset.Service, oldAsset.Name, oldAsset.Description, oldAsset.Data, oldAsset.Labels, - oldAsset.CreatedAt, oldAsset.UpdatedAt, oldAsset.UpdatedBy.ID, oldAsset.Version, oldAsset.Owners, jsonChangelog, ns.ID). - PlaceholderFormat(sq.Dollar). - ToSql() - if err != nil { - return fmt.Errorf("error building insert query: %w", err) - } - - if err = r.execContext(ctx, execer, query, args...); err != nil { - return fmt.Errorf("error running insert asset version query: %w", err) - } - - return -} - -func (r *AssetRepository) getOwners(ctx context.Context, assetID string) (owners []user.User, err error) { - - if !isValidUUID(assetID) { - return nil, asset.InvalidError{AssetID: assetID} - } - - var userModels UserModels - - query := ` - SELECT - u.id as "id", - u.uuid as "uuid", - u.email as "email", - u.provider as "provider" - FROM asset_owners ao - JOIN users u on ao.user_id = u.id - WHERE asset_id = $1` - - err = r.client.SelectContext(ctx, &userModels, query, assetID) - if err != nil { - err = fmt.Errorf("error getting asset's owners: %w", err) - } - - owners = userModels.toUsers() - - return -} - -// insertOwners inserts relation of asset id and user id -func (r *AssetRepository) insertOwners(ctx context.Context, execer sqlx.ExecerContext, assetID string, owners []user.User) error { - if len(owners) == 0 { - return nil - } - - if !isValidUUID(assetID) { - return asset.InvalidError{AssetID: assetID} - } - - sqlb := sq.Insert("asset_owners"). - Columns("asset_id", "user_id") - for _, o := range owners { - sqlb = sqlb.Values(assetID, o.ID) - } - - qry, args, err := sqlb.PlaceholderFormat(sq.Dollar).ToSql() - if err != nil { - return fmt.Errorf("build insert owners SQL: %w", err) - } - - if err := r.execContext(ctx, execer, qry, args...); err != nil { - return fmt.Errorf("error running insert owners query: %w", err) - } - - return nil -} - -func (r *AssetRepository) removeOwners(ctx context.Context, execer sqlx.ExecerContext, assetID string, owners []user.User) (err error) { - if len(owners) == 0 { - return - } - - if !isValidUUID(assetID) { - return asset.InvalidError{AssetID: assetID} - } - - var user_ids []string - var args = []interface{}{assetID} - for i, owner := range owners { - user_ids = append(user_ids, fmt.Sprintf("$%d", i+2)) - args = append(args, owner.ID) - } - query := fmt.Sprintf( - "DELETE FROM asset_owners WHERE asset_id = $1 AND user_id in (%s)", - strings.Join(user_ids, ","), - ) - err = r.execContext(ctx, execer, query, args...) - if err != nil { - err = fmt.Errorf("error running delete owners query: %w", err) - } - - return -} - -func (r *AssetRepository) compareOwners(current, newOwners []user.User) (toInserts, toRemove []user.User) { - if len(current) == 0 && len(newOwners) == 0 { - return - } - - currMap := map[string]int{} - for _, curr := range current { - currMap[curr.ID] = 1 - } - - for _, n := range newOwners { - _, exists := currMap[n.ID] - if exists { - // if exists, it means that both new and current have it. - // we remove it from the map, - // so that what's left in the map is the that only exists in current - // and have to be removed - delete(currMap, n.ID) - } else { - toInserts = append(toInserts, user.User{ID: n.ID}) - } - } - - for id := range currMap { - toRemove = append(toRemove, user.User{ID: id}) - } - - return -} - -func (r *AssetRepository) createOrFetchUsers(ctx context.Context, tx *sqlx.Tx, ns *namespace.Namespace, users []user.User) ([]user.User, error) { - var results []user.User - seen := make(map[string]bool) - for _, u := range users { - var ( - userID string - fetchedUser user.User - err error - ) - if u.UUID != "" { - fetchedUser, err = r.userRepo.GetByUUID(ctx, u.UUID) - } else { - fetchedUser, err = r.userRepo.GetByEmail(ctx, u.Email) - } - if err == nil { - userID = fetchedUser.ID - } - if errors.As(err, &user.NotFoundError{}) { - u.Provider = r.defaultUserProvider - userID, err = r.userRepo.CreateWithTx(ctx, tx, ns, &u) - if err != nil { - return nil, fmt.Errorf("error creating owner: %w", err) - } - } - if err != nil { - return nil, fmt.Errorf("error getting owner's ID: %w", err) - } - - // deduplicate owners by resolved user ID - if seen[userID] { - continue - } - seen[userID] = true - - u.ID = userID - results = append(results, u) - } - - return results, nil -} - -func (r *AssetRepository) execContext(ctx context.Context, execer sqlx.ExecerContext, query string, args ...interface{}) error { - res, err := execer.ExecContext(ctx, query, args...) - if err != nil { - return fmt.Errorf("error running query: %w", err) - } - - affectedRows, err := res.RowsAffected() - if err != nil { - return fmt.Errorf("error getting affected rows: %w", err) - } - if affectedRows == 0 { - return errors.New("query affected 0 rows") - } - - return nil -} - -type sqlBuilder interface { - ToSql() (string, []interface{}, error) -} - -func (r *AssetRepository) buildSQL(builder sqlBuilder) (query string, args []interface{}, err error) { - query, args, err = builder.ToSql() - if err != nil { - err = fmt.Errorf("error transforming to sql") - return - } - query, err = sq.Dollar.ReplacePlaceholders(query) - if err != nil { - err = fmt.Errorf("error replacing placeholders to dollar") - return - } - - return -} - -func (r *AssetRepository) getAssetsGroupByCountSQL(columnName string) sq.SelectBuilder { - return sq.Select(columnName, "count(1)"). - From("assets"). - GroupBy(columnName) -} - -func (r *AssetRepository) getAssetSQL() sq.SelectBuilder { - return sq.Select(` - a.id as id, - a.namespace_id as namespace_id, - a.urn as urn, - a.type as type, - a.name as name, - a.service as service, - a.description as description, - a.data as data, - COALESCE(a.url, '') as url, - a.labels as labels, - a.version as version, - COALESCE(a.is_deleted, false) as is_deleted, - a.created_at as created_at, - a.updated_at as updated_at, - a.refreshed_at as refreshed_at, - u.id as "updated_by.id", - u.uuid as "updated_by.uuid", - u.email as "updated_by.email", - u.provider as "updated_by.provider", - u.created_at as "updated_by.created_at", - u.updated_at as "updated_by.updated_at" - `). - From("assets a"). - LeftJoin("users u ON a.updated_by = u.id") -} - -func (r *AssetRepository) getAssetVersionSQL() sq.SelectBuilder { - return sq.Select(` - a.asset_id as id, - a.urn as urn, - a.type as type, - a.name as name, - a.service as service, - a.description as description, - a.data as data, - a.labels as labels, - a.version as version, - a.created_at as created_at, - a.updated_at as updated_at, - a.changelog as changelog, - a.owners as owners, - u.id as "updated_by.id", - u.uuid as "updated_by.uuid", - u.email as "updated_by.email", - u.provider as "updated_by.provider", - u.created_at as "updated_by.created_at", - u.updated_at as "updated_by.updated_at" - `). - From("assets_versions a"). - LeftJoin("users u ON a.updated_by = u.id") -} - -// BuildFilterQuery retrieves the sql query based on applied filter in the queryString -func (r *AssetRepository) BuildFilterQuery(builder sq.SelectBuilder, flt asset.Filter) sq.SelectBuilder { - if flt.IsDeleted != nil { - builder = builder.Where(sq.Eq{"is_deleted": *flt.IsDeleted}) - } - - if len(flt.Types) > 0 { - builder = builder.Where(sq.Eq{"type": flt.Types}) - } - - if len(flt.Services) > 0 { - builder = builder.Where(sq.Eq{"service": flt.Services}) - } - - if len(flt.QueryFields) > 0 && flt.Query != "" { - orClause := sq.Or{} - - for _, field := range flt.QueryFields { - finalQuery := field - - if strings.Contains(field, "data") { - finalQuery = r.buildDataField( - strings.TrimPrefix(field, "data."), - false, - ) - } - orClause = append(orClause, sq.ILike{ - finalQuery: fmt.Sprint("%", flt.Query, "%"), - }) - } - builder = builder.Where(orClause) - } - - if len(flt.Data) > 0 { - for key, vals := range flt.Data { - if len(vals) == 1 && vals[0] == "_nonempty" { - field := r.buildDataField(key, true) - whereClause := sq.And{ - sq.NotEq{field: nil}, // IS NOT NULL (field exists) - sq.NotEq{field: "null"}, // field is not "null" JSON - sq.NotEq{field: "[]"}, // field is not empty array - sq.NotEq{field: "{}"}, // field is not empty object - sq.NotEq{field: "\"\""}, // field is not empty string - } - builder = builder.Where(whereClause) - } else { - dataOrClause := sq.Or{} - for _, v := range vals { - finalQuery := r.buildDataField(key, false) - dataOrClause = append(dataOrClause, sq.Eq{finalQuery: v}) - } - - builder = builder.Where(dataOrClause) - } - } - } - - return builder -} - -// buildFilterQuery retrieves the ordered sql query based on the sorting filter used in queryString -func (r *AssetRepository) buildOrderQuery(builder sq.SelectBuilder, flt asset.Filter) sq.SelectBuilder { - if flt.SortBy == "" { - return builder - } - - orderDirection := "ASC" - if flt.SortDirection != "" { - orderDirection = flt.SortDirection - } - - return builder.OrderBy(flt.SortBy + " " + orderDirection) -} - -// buildDataField is a helper function to build nested data fields -func (r *AssetRepository) buildDataField(key string, asJsonB bool) (finalQuery string) { - var queries []string - - queries = append(queries, "data") - nestedParams := strings.Split(key, ".") - totalParams := len(nestedParams) - for i := 0; i < totalParams-1; i++ { - nestedQuery := fmt.Sprintf("->'%s'", nestedParams[i]) - queries = append(queries, nestedQuery) - } - - var lastParam string - if asJsonB { - lastParam = fmt.Sprintf("->'%s'", nestedParams[totalParams-1]) - } else { - lastParam = fmt.Sprintf("->>'%s'", nestedParams[totalParams-1]) - } - - queries = append(queries, lastParam) - finalQuery = strings.Join(queries, "") - - return finalQuery -} - -// NewAssetRepository initializes user repository clients -func NewAssetRepository(c *Client, userRepo *UserRepository, defaultGetMaxSize int, defaultUserProvider string) (*AssetRepository, error) { - if c == nil { - return nil, errors.New("postgres client is nil") - } - if defaultGetMaxSize == 0 { - defaultGetMaxSize = DefaultMaxResultSize - } - if defaultUserProvider == "" { - defaultUserProvider = "unknown" - } - - return &AssetRepository{ - client: c, - defaultGetMaxSize: defaultGetMaxSize, - defaultUserProvider: defaultUserProvider, - userRepo: userRepo, - }, nil -} diff --git a/store/postgres/asset_repository_test.go b/store/postgres/asset_repository_test.go deleted file mode 100644 index f14f3550..00000000 --- a/store/postgres/asset_repository_test.go +++ /dev/null @@ -1,1870 +0,0 @@ -package postgres_test - -import ( - "context" - "encoding/json" - "fmt" - "os" - "sort" - "strings" - "testing" - "time" - - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/middleware" - - _ "embed" - - sq "github.com/Masterminds/squirrel" - "github.com/google/go-cmp/cmp" - "github.com/google/uuid" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/store/postgres" - "github.com/ory/dockertest/v3" - "github.com/r3labs/diff/v3" - "github.com/stretchr/testify/suite" -) - -var defaultAssetUpdaterUserID = uuid.NewString() - -//go:embed testdata/mock-asset-data.json -var testFixtureData []byte - -type AssetRepositoryTestSuite struct { - suite.Suite - ctx context.Context - client *postgres.Client - pool *dockertest.Pool - resource *dockertest.Resource - repository *postgres.AssetRepository - userRepo *postgres.UserRepository - users []user.User - assets []*asset.Asset - builder sq.SelectBuilder - ns *namespace.Namespace -} - -func (r *AssetRepositoryTestSuite) SetupSuite() { - var err error - - r.client, r.pool, r.resource, err = newTestClient() - if err != nil { - r.T().Fatal(err) - } - r.ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.DedicatedState, - Metadata: nil, - } - r.ctx = middleware.BuildContextWithNamespace(context.Background(), r.ns) - r.userRepo, err = postgres.NewUserRepository(r.client) - if err != nil { - r.T().Fatal(err) - } - - r.repository, err = postgres.NewAssetRepository(r.client, r.userRepo, defaultGetMaxSize, defaultProviderName) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *AssetRepositoryTestSuite) createUsers(userRepo user.Repository) []user.User { - var err error - users := []user.User{} - - user1 := user.User{UUID: uuid.NewString(), Email: "user-test-1@raystack.io", Provider: defaultProviderName} - user1.ID, err = userRepo.Create(r.ctx, r.ns, &user1) - r.Require().NoError(err) - users = append(users, user1) - - user2 := user.User{UUID: uuid.NewString(), Email: "user-test-2@raystack.io", Provider: defaultProviderName} - user2.ID, err = userRepo.Create(r.ctx, r.ns, &user2) - r.Require().NoError(err) - users = append(users, user2) - - user3 := user.User{UUID: uuid.NewString(), Email: "user-test-3@raystack.io", Provider: defaultProviderName} - user3.ID, err = userRepo.Create(r.ctx, r.ns, &user3) - r.Require().NoError(err) - users = append(users, user3) - - user4 := user.User{UUID: uuid.NewString(), Email: "user-test-4@raystack.io", Provider: defaultProviderName} - user4.ID, err = userRepo.Create(r.ctx, r.ns, &user4) - r.Require().NoError(err) - users = append(users, user4) - - return users -} - -func (r *AssetRepositoryTestSuite) TearDownSuite() { - // Clean tests - err := r.client.Close() - if err != nil { - r.T().Fatal(err) - } - err = purgeDocker(r.pool, r.resource) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *AssetRepositoryTestSuite) BeforeTest(suiteName, testName string) { - err := setup(r.ctx, r.client) - r.NoError(err) - - r.users = r.createUsers(r.userRepo) - r.assets = r.insertRecord() -} - -func (r *AssetRepositoryTestSuite) insertRecord() []*asset.Asset { - var err error - var data []*asset.Asset - if err = json.Unmarshal(testFixtureData, &data); err != nil { - r.T().Error(err) - return nil - } - - for idx, d := range data { - d.Version = asset.BaseVersion - d.UpdatedBy = r.users[0] - - data[idx].ID, err = r.repository.Upsert(r.ctx, r.ns, d) - r.Require().NoError(err) - r.Require().NotEmpty(data[idx].ID) - } - return data -} - -func (r *AssetRepositoryTestSuite) TestBuildFilterQuery() { - r.builder = sq.Select(`a.test as test`) - - testCases := []struct { - description string - config asset.Filter - expectedQuery string - }{ - { - description: "should return sql query with types filter", - config: asset.Filter{ - Types: []asset.Type{asset.TypeTable}, - }, - expectedQuery: `type IN ($1)`, - }, - { - description: "should return sql query with services filter", - config: asset.Filter{ - Services: []string{"mysql", "kafka"}, - }, - expectedQuery: `service IN ($1,$2)`, - }, - { - description: "should return sql query with query fields filter", - config: asset.Filter{ - QueryFields: []string{"name", "description"}, - Query: "demo", - }, - expectedQuery: `(name ILIKE $1 OR description ILIKE $2)`, - }, - { - description: "should return sql query with nested data query filter", - config: asset.Filter{ - QueryFields: []string{"data.landscape.properties.project-id", "description"}, - Query: "compass_002", - }, - expectedQuery: `(data->'landscape'->'properties'->>'project-id' ILIKE $1 OR description ILIKE $2)`, - }, - { - // NOTE: Cannot have more than one key in map because golang's map does not guarantee order thus producing - // inconsistent test. - description: "should return sql query with asset's data fields filter", - config: asset.Filter{ - Data: map[string][]string{ - "entity": {"raystack"}, - }, - }, - expectedQuery: `(data->>'entity' = $1)`, - }, - { - description: "should return sql query with asset's nested data fields filter", - config: asset.Filter{ - Data: map[string][]string{ - "landscape.properties.project-id": {"compass_001"}, - }, - }, - expectedQuery: `(data->'landscape'->'properties'->>'project-id' = $1)`, - }, - { - description: "should return sql query with asset's nested multiple data fields filter ", - config: asset.Filter{ - Data: map[string][]string{ - "properties.attributes.entity": {"alpha", "beta"}, - }, - }, - expectedQuery: `(data->'properties'->'attributes'->>'entity' = $1 OR data->'properties'->'attributes'->>'entity' = $2)`, - }, - } - - for _, testCase := range testCases { - r.Run(testCase.description, func() { - result := r.repository.BuildFilterQuery(r.builder, testCase.config) - query, _, err := result.ToSql() - r.Require().NoError(err) - query, err = sq.Dollar.ReplacePlaceholders(query) - r.Require().NoError(err) - - actualQuery := strings.Split(query, "WHERE ") - r.Equal(testCase.expectedQuery, actualQuery[1]) - }) - } -} - -func (r *AssetRepositoryTestSuite) TestGetAll() { - - r.Run("should return all assets without filtering based on size", func() { - expectedSize := 12 - - results, err := r.repository.GetAll(r.ctx, asset.Filter{}) - r.Require().NoError(err) - r.Require().Len(results, expectedSize) - for i := 0; i < expectedSize; i++ { - r.assertAsset(r.assets[i], &results[i]) - } - }) - - r.Run("should override default size using GetConfig.Size", func() { - size := 6 - - results, err := r.repository.GetAll(r.ctx, asset.Filter{ - Size: size, - }) - r.Require().NoError(err) - r.Require().Len(results, size) - for i := 0; i < size; i++ { - r.assertAsset(r.assets[i], &results[i]) - } - }) - - r.Run("should fetch assets by offset defined in GetConfig.Offset", func() { - offset := 2 - - results, err := r.repository.GetAll(r.ctx, asset.Filter{ - Offset: offset, - }) - r.Require().NoError(err) - for i := offset; i > len(results)+offset; i++ { - r.assertAsset(r.assets[i], &results[i-offset]) - } - }) - - r.Run("should filter using type", func() { - results, err := r.repository.GetAll(r.ctx, asset.Filter{ - Types: []asset.Type{asset.TypeTable}, - SortBy: "type", - SortDirection: "desc", - }) - r.Require().NoError(err) - - expectedURNs := []string{"twelfth-mock", "i-undefined-dfgdgd-avi", "e-test-grant2"} - sort.Slice(expectedURNs, func(i, j int) bool { - return expectedURNs[i] < expectedURNs[j] - }) - sort.Slice(results, func(i, j int) bool { - return results[i].URN < results[j].URN - }) - r.Equal(len(expectedURNs), len(results)) - for i := range results { - r.Equal(expectedURNs[i], results[i].URN) - } - }) - - r.Run("should filter using service", func() { - results, err := r.repository.GetAll(r.ctx, asset.Filter{ - Services: []string{"mysql", "kafka"}, - SortBy: "service", - }) - r.Require().NoError(err) - - expectedURNs := []string{"c-demo-kafka", "f-john-test-001", "i-test-grant", "i-undefined-dfgdgd-avi"} - sort.Slice(expectedURNs, func(i, j int) bool { - return expectedURNs[i] < expectedURNs[j] - }) - sort.Slice(results, func(i, j int) bool { - return results[i].URN < results[j].URN - }) - r.Equal(len(expectedURNs), len(results)) - for i := range results { - r.Equal(expectedURNs[i], results[i].URN) - } - }) - - r.Run("should filter using query fields", func() { - results, err := r.repository.GetAll(r.ctx, asset.Filter{ - QueryFields: []string{"name", "description"}, - Query: "demo", - SortBy: "service", - }) - r.Require().NoError(err) - - expectedURNs := []string{"c-demo-kafka", "e-test-grant2"} - sort.Slice(expectedURNs, func(i, j int) bool { - return expectedURNs[i] < expectedURNs[j] - }) - sort.Slice(results, func(i, j int) bool { - return results[i].URN < results[j].URN - }) - r.Equal(len(expectedURNs), len(results)) - for i := range results { - r.Equal(expectedURNs[i], results[i].URN) - } - }) - - r.Run("should filter only using nested query data fields", func() { - results, err := r.repository.GetAll(r.ctx, asset.Filter{ - QueryFields: []string{"data.landscape.properties.project-id", "data.title"}, - Query: "compass_001", - SortBy: "service", - }) - r.Require().NoError(err) - - expectedURNs := []string{"i-test-grant", "j-xcvcx"} - sort.Slice(expectedURNs, func(i, j int) bool { - return expectedURNs[i] < expectedURNs[j] - }) - sort.Slice(results, func(i, j int) bool { - return results[i].URN < results[j].URN - }) - r.Equal(len(expectedURNs), len(results)) - for i := range results { - r.Equal(expectedURNs[i], results[i].URN) - } - }) - - r.Run("should filter using query field with nested query data fields", func() { - results, err := r.repository.GetAll(r.ctx, asset.Filter{ - QueryFields: []string{"data.landscape.properties.project-id", "description"}, - Query: "compass_002", - SortBy: "service", - }) - r.Require().NoError(err) - - expectedURNs := []string{"g-jane-kafka-1a", "h-test-new-kafka"} - sort.Slice(expectedURNs, func(i, j int) bool { - return expectedURNs[i] < expectedURNs[j] - }) - sort.Slice(results, func(i, j int) bool { - return results[i].URN < results[j].URN - }) - r.Equal(len(expectedURNs), len(results)) - for i := range results { - r.Equal(expectedURNs[i], results[i].URN) - } - }) - - r.Run("should filter using asset's data fields", func() { - results, err := r.repository.GetAll(r.ctx, asset.Filter{ - Data: map[string][]string{ - "entity": {"raystack"}, - "country": {"th"}, - }, - }) - r.Require().NoError(err) - - expectedURNs := []string{"e-test-grant2", "h-test-new-kafka", "i-test-grant"} - r.Equal(len(expectedURNs), len(results)) - for i := range results { - r.Equal(expectedURNs[i], results[i].URN) - } - }) - - r.Run("should filter using asset's nested data fields", func() { - results, err := r.repository.GetAll(r.ctx, asset.Filter{ - Data: map[string][]string{ - "landscape.properties.project-id": {"compass_001"}, - "country": {"vn"}, - }, - }) - r.Require().NoError(err) - - expectedURNs := []string{"j-xcvcx"} - r.Equal(len(expectedURNs), len(results)) - for i := range results { - r.Equal(expectedURNs[i], results[i].URN) - } - }) - - r.Run("should filter using asset's nonempty data fields", func() { - results, err := r.repository.GetAll(r.ctx, asset.Filter{ - Data: map[string][]string{ - "properties.dependencies": {"_nonempty"}, - }, - }) - r.Require().NoError(err) - - expectedURNs := []string{"nine-mock", "eleven-mock"} - r.Equal(len(expectedURNs), len(results)) - for i := range results { - r.Equal(expectedURNs[i], results[i].URN) - } - }) - - r.Run("should filter using asset's different nonempty data fields", func() { - results, err := r.repository.GetAll(r.ctx, asset.Filter{ - Data: map[string][]string{ - "properties.dependencies": {"_nonempty"}, - "entity": {"raystack"}, - "urn": {"j-xcvcx"}, - "country": {"vn"}, - }, - }) - r.Require().NoError(err) - - expectedURNs := []string{"nine-mock"} - r.Equal(len(expectedURNs), len(results)) - for i := range results { - r.Equal(expectedURNs[i], results[i].URN) - } - }) -} - -func (r *AssetRepositoryTestSuite) TestGetTypes() { - type testCase struct { - Description string - Filter asset.Filter - Expected map[asset.Type]int - } - - testCases := []testCase{ - { - Description: "should return maps of asset count without filter", - Filter: asset.Filter{}, - Expected: map[asset.Type]int{ - asset.TypeDashboard: 5, - asset.TypeJob: 1, - asset.TypeTable: 3, - asset.TypeTopic: 3, - }, - }, - { - Description: "should filter using service", - Filter: asset.Filter{ - Services: []string{"mysql", "kafka"}, - SortBy: "service", - }, - Expected: map[asset.Type]int{ - asset.TypeTable: 1, - asset.TypeTopic: 3, - }, - }, - { - Description: "should filter using query fields", - Filter: asset.Filter{ - QueryFields: []string{"name", "description"}, - Query: "demo", - SortBy: "service", - }, - Expected: map[asset.Type]int{ - asset.TypeTable: 1, - asset.TypeTopic: 1, - }, - }, - { - Description: "should filter only using nested query data fields", - Filter: asset.Filter{ - QueryFields: []string{"data.landscape.properties.project-id", "data.title"}, - Query: "compass_001", - SortBy: "service", - }, - Expected: map[asset.Type]int{ - asset.TypeDashboard: 1, - asset.TypeTopic: 1, - }, - }, - - { - Description: "should filter using query field with nested query data fields", - Filter: asset.Filter{ - QueryFields: []string{"data.landscape.properties.project-id", "description"}, - Query: "compass_002", - SortBy: "service", - }, - Expected: map[asset.Type]int{ - asset.TypeDashboard: 1, - asset.TypeJob: 1, - }, - }, - { - Description: "should filter using asset's data fields", - Filter: asset.Filter{ - Data: map[string][]string{ - "entity": {"raystack"}, - "country": {"th"}, - }, - }, - Expected: map[asset.Type]int{ - asset.TypeJob: 1, - asset.TypeTable: 1, - asset.TypeTopic: 1, - }, - }, - { - Description: "should filter using asset's nested data fields", - Filter: asset.Filter{ - Data: map[string][]string{ - "landscape.properties.project-id": {"compass_001"}, - "country": {"vn"}, - }, - }, - Expected: map[asset.Type]int{ - asset.TypeDashboard: 1, - }, - }, - { - Description: "should filter using asset's nonempty data fields", - Filter: asset.Filter{ - Data: map[string][]string{ - "properties.dependencies": {"_nonempty"}, - }, - }, - Expected: map[asset.Type]int{ - asset.TypeDashboard: 2, - }, - }, - { - Description: "should filter using asset's different nonempty data fields", - Filter: asset.Filter{ - Data: map[string][]string{ - "properties.dependencies": {"_nonempty"}, - "entity": {"raystack"}, - "urn": {"j-xcvcx"}, - "country": {"vn"}, - }, - }, - Expected: map[asset.Type]int{ - asset.TypeDashboard: 1, - }, - }, - } - - for _, tc := range testCases { - r.Run(tc.Description, func() { - typeMap, err := r.repository.GetTypes(context.Background(), tc.Filter) - r.NoError(err) - - keys := make([]string, 0, len(typeMap)) - - for k := range typeMap { - keys = append(keys, k.String()) - } - sort.Strings(keys) - - sortedMap := make(map[asset.Type]int) - for _, k := range keys { - sortedMap[asset.Type(k)] = typeMap[asset.Type(k)] - } - - if !cmp.Equal(tc.Expected, sortedMap) { - r.T().Fatalf("expected is %+v but got %+v", tc.Expected, sortedMap) - } - }) - } -} - -func (r *AssetRepositoryTestSuite) TestGetCount() { - // populate assets - total := 12 - typ := asset.TypeJob - service := []string{"service-getcount"} - for i := 0; i < total; i++ { - ast := &asset.Asset{ - URN: fmt.Sprintf("urn-getcount-%d", i), - Type: typ, - Service: service[0], - UpdatedBy: r.users[0], - } - id, err := r.repository.Upsert(r.ctx, r.ns, ast) - r.Require().NoError(err) - r.Require().NotEmpty(id) - ast.ID = id - } - - r.Run("should return total assets with filter", func() { - actual, err := r.repository.GetCount(r.ctx, asset.Filter{ - Types: []asset.Type{typ}, - Services: service, - }) - r.Require().NoError(err) - r.Equal(total, actual) - }) -} - -func (r *AssetRepositoryTestSuite) TestGetByID() { - r.Run("return error from client if asset not an uuid", func() { - _, err := r.repository.GetByID(r.ctx, "invalid-uuid") - r.Error(err) - r.Contains(err.Error(), "invalid asset id: \"invalid-uuid\"") - }) - - r.Run("return NotFoundError if asset does not exist", func() { - uuid := "2aabb450-f986-44e2-a6db-7996861d5004" - _, err := r.repository.GetByID(r.ctx, uuid) - r.ErrorAs(err, &asset.NotFoundError{AssetID: uuid}) - }) - - r.Run("return correct asset from db", func() { - asset1 := asset.Asset{ - URN: "urn-gbi-1", - Type: "table", - Service: "bigquery", - Version: asset.BaseVersion, - UpdatedBy: r.users[1], - } - asset2 := asset.Asset{ - URN: "urn-gbi-2", - Type: "topic", - Service: "kafka", - Version: asset.BaseVersion, - UpdatedBy: r.users[1], - } - - var err error - id, err := r.repository.Upsert(r.ctx, r.ns, &asset1) - r.Require().NoError(err) - r.NotEmpty(id) - asset1.ID = id - - id, err = r.repository.Upsert(r.ctx, r.ns, &asset2) - r.Require().NoError(err) - r.NotEmpty(id) - asset2.ID = id - - result, err := r.repository.GetByID(r.ctx, asset2.ID) - r.NoError(err) - asset2.UpdatedBy = r.users[1] - r.assertAsset(&asset2, &result) - }) - - r.Run("return owners if any", func() { - - ast := asset.Asset{ - URN: "urn-gbi-3", - Type: "table", - Service: "bigquery", - Owners: []user.User{ - r.users[1], - r.users[2], - }, - UpdatedBy: r.users[1], - } - - id, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - r.Require().NotEmpty(id) - ast.ID = id - - result, err := r.repository.GetByID(r.ctx, ast.ID) - r.NoError(err) - r.Len(result.Owners, len(ast.Owners)) - for i, owner := range result.Owners { - r.Equal(ast.Owners[i].ID, owner.ID) - } - }) -} - -func (r *AssetRepositoryTestSuite) TestGetByURN() { - r.Run("return NotFoundError if asset does not exist", func() { - urn := "urn-gbi-1" - _, err := r.repository.GetByURN(r.ctx, urn) - r.ErrorAs(err, &asset.NotFoundError{URN: urn}) - }) - - r.Run("return correct asset from db", func() { - asset1 := asset.Asset{ - URN: "urn-gbi-1", - Type: "table", - Service: "bigquery", - Version: asset.BaseVersion, - UpdatedBy: r.users[1], - } - asset2 := asset.Asset{ - URN: "urn-gbi-2", - Type: "topic", - Service: "kafka", - Version: asset.BaseVersion, - UpdatedBy: r.users[1], - } - - id, err := r.repository.Upsert(r.ctx, r.ns, &asset1) - r.Require().NoError(err) - r.NotEmpty(id) - asset1.ID = id - - id, err = r.repository.Upsert(r.ctx, r.ns, &asset2) - r.Require().NoError(err) - r.NotEmpty(id) - asset2.ID = id - - result, err := r.repository.GetByURN(r.ctx, "urn-gbi-2") - r.NoError(err) - r.assertAsset(&asset2, &result) - }) - - r.Run("return owners if any", func() { - ast := asset.Asset{ - URN: "urn-gbi-3", - Type: "table", - Service: "bigquery", - Owners: []user.User{ - r.users[1], - r.users[2], - }, - UpdatedBy: r.users[1], - } - - _, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - - result, err := r.repository.GetByURN(r.ctx, ast.URN) - r.NoError(err) - r.Len(result.Owners, len(ast.Owners)) - for i, owner := range result.Owners { - r.Equal(ast.Owners[i].ID, owner.ID) - } - }) -} - -func (r *AssetRepositoryTestSuite) TestVersions() { - assetURN := uuid.NewString() + "urn-u-2-version" - // v0.1 - astVersioning := asset.Asset{ - URN: assetURN, - Type: "table", - Service: "bigquery", - UpdatedBy: r.users[1], - } - - id, err := r.repository.Upsert(r.ctx, r.ns, &astVersioning) - r.Require().NoError(err) - r.Require().NotEmpty(id) - astVersioning.ID = id - - // v0.2 - astVersioning.Description = "new description in v0.2" - id, err = r.repository.Upsert(r.ctx, r.ns, &astVersioning) - r.Require().NoError(err) - r.Require().Equal(id, astVersioning.ID) - - // v0.3 - astVersioning.Owners = []user.User{ - { - Email: "user@raystack.io", - }, - { - Email: "meteor@raystack.io", - Provider: "meteor", - }, - } - id, err = r.repository.Upsert(r.ctx, r.ns, &astVersioning) - r.Require().NoError(err) - r.Require().Equal(id, astVersioning.ID) - - // v0.4 - astVersioning.Data = map[string]interface{}{ - "data1": float64(12345), - } - id, err = r.repository.Upsert(r.ctx, r.ns, &astVersioning) - r.Require().NoError(err) - r.Require().Equal(id, astVersioning.ID) - - // v0.5 - astVersioning.Labels = map[string]string{ - "key1": "value1", - } - - id, err = r.repository.Upsert(r.ctx, r.ns, &astVersioning) - r.Require().NoError(err) - r.Require().Equal(id, astVersioning.ID) - - r.Run("should return 3 last versions of an assets if there are exist", func() { - - expectedAssetVersions := []asset.Asset{ - { - ID: astVersioning.ID, - URN: assetURN, - Type: "table", - Service: "bigquery", - Version: "0.5", - Changelog: diff.Changelog{ - diff.Change{Type: "create", Path: []string{"labels", "key1"}, From: interface{}(nil), To: "value1"}, - }, - UpdatedBy: r.users[1], - }, - { - ID: astVersioning.ID, - URN: assetURN, - Type: "table", - Service: "bigquery", - Version: "0.4", - Changelog: diff.Changelog{ - diff.Change{Type: "create", Path: []string{"data", "data1"}, From: interface{}(nil), To: float64(12345)}, - }, - UpdatedBy: r.users[1], - }, - { - ID: astVersioning.ID, - URN: assetURN, - Type: "table", - Service: "bigquery", - Version: "0.3", - Changelog: diff.Changelog{ - diff.Change{Type: "create", Path: []string{"owners", "0", "email"}, From: interface{}(nil), To: "user@raystack.io"}, - diff.Change{Type: "create", Path: []string{"owners", "1", "email"}, From: interface{}(nil), To: "meteor@raystack.io"}, - }, - UpdatedBy: r.users[1], - }, - } - - assetVersions, err := r.repository.GetVersionHistory(r.ctx, asset.Filter{Size: 3}, astVersioning.ID) - r.NoError(err) - // making updatedby user time empty to make ast comparable - for i := 0; i < len(assetVersions); i++ { - clearTimestamps(&assetVersions[i]) - } - r.Equal(expectedAssetVersions, assetVersions) - }) - - r.Run("should return current version of an assets", func() { - expected := asset.Asset{ - ID: astVersioning.ID, - URN: assetURN, - Type: "table", - Service: "bigquery", - Description: "new description in v0.2", - Data: map[string]interface{}{"data1": float64(12345)}, - Labels: map[string]string{"key1": "value1"}, - Version: "0.5", - UpdatedBy: r.users[1], - } - - ast, err := r.repository.GetByID(r.ctx, astVersioning.ID) - // hard to get the internally generated user id, we exclude the owners from the assertion - astOwners := ast.Owners - ast.Owners = nil - r.NoError(err) - // making updatedby user time empty to make ast comparable - clearTimestamps(&ast) - r.Equal(expected, ast) - - r.Len(astOwners, 2) - }) - - r.Run("should return current version of an assets with by version", func() { - expected := asset.Asset{ - ID: astVersioning.ID, - URN: assetURN, - Type: "table", - Service: "bigquery", - Description: "new description in v0.2", - Data: map[string]interface{}{"data1": float64(12345)}, - Labels: map[string]string{"key1": "value1"}, - Version: "0.5", - UpdatedBy: r.users[1], - } - - ast, err := r.repository.GetByVersionWithID(r.ctx, astVersioning.ID, "0.5") - // hard to get the internally generated user id, we exclude the owners from the assertion - astOwners := ast.Owners - ast.Owners = nil - r.NoError(err) - // making updatedby user time empty to make ast comparable - clearTimestamps(&ast) - r.Equal(expected, ast) - - r.Len(astOwners, 2) - - ast, err = r.repository.GetByVersionWithURN(r.ctx, astVersioning.URN, "0.5") - // hard to get the internally generated user id, we exclude the owners from the assertion - astOwners = ast.Owners - ast.Owners = nil - r.NoError(err) - // making updatedby user time empty to make ast comparable - clearTimestamps(&ast) - r.Equal(expected, ast) - r.Len(astOwners, 2) - }) - - r.Run("should return a specific version of an asset", func() { - version := "0.3" - expected := asset.Asset{ - ID: astVersioning.ID, - URN: assetURN, - Type: "table", - Service: "bigquery", - Description: "new description in v0.2", - Version: "0.3", - Changelog: diff.Changelog{ - diff.Change{Type: "create", Path: []string{"owners", "0", "email"}, From: interface{}(nil), To: "user@raystack.io"}, - diff.Change{Type: "create", Path: []string{"owners", "1", "email"}, From: interface{}(nil), To: "meteor@raystack.io"}, - }, - UpdatedBy: r.users[1], - } - expectedOwners := []user.User{ - { - Email: "user@raystack.io", - }, - { - Email: "meteor@raystack.io", - Provider: "meteor", - }, - } - astVer, err := r.repository.GetByVersionWithID(r.ctx, astVersioning.ID, version) - // hard to get the internally generated user id, we exclude the owners from the assertion - astOwners := astVer.Owners - astVer.Owners = nil - r.Assert().NoError(err) - // making updatedby user time empty to make ast comparable - clearTimestamps(&astVer) - r.Assert().Equal(expected, astVer) - - for i := 0; i < len(astOwners); i++ { - astOwners[i].ID = "" - } - r.Assert().Equal(expectedOwners, astOwners) - - astVer, err = r.repository.GetByVersionWithURN(r.ctx, astVersioning.URN, version) - // hard to get the internally generated user id, we exclude the owners from the assertion - astOwners = astVer.Owners - astVer.Owners = nil - r.Assert().NoError(err) - // making updatedby user time empty to make ast comparable - clearTimestamps(&astVer) - r.Assert().Equal(expected, astVer) - - for i := 0; i < len(astOwners); i++ { - astOwners[i].ID = "" - } - r.Assert().Equal(expectedOwners, astOwners) - }) -} - -func (r *AssetRepositoryTestSuite) TestUpsert() { - r.Run("on insert", func() { - r.Run("set ID to asset and version to base version", func() { - ast := asset.Asset{ - URN: "urn-u-1", - Type: "table", - Service: "bigquery", - URL: "https://sample-url.com", - UpdatedBy: r.users[0], - } - id, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Equal(asset.BaseVersion, ast.Version) - r.NoError(err) - r.NotEmpty(id) - ast.ID = id - - assetInDB, err := r.repository.GetByID(r.ctx, ast.ID) - r.Require().NoError(err) - r.NotEqual(time.Time{}, assetInDB.CreatedAt) - r.NotEqual(time.Time{}, assetInDB.UpdatedAt) - r.assertAsset(&ast, &assetInDB) - - ast2 := ast - ast2.Description = "create a new version" // to force fetch from asset_versions. - _, err = r.repository.Upsert(r.ctx, r.ns, &ast2) - r.NoError(err) - assetv1, err := r.repository.GetByVersionWithID(r.ctx, ast.ID, asset.BaseVersion) - r.NoError(err) - r.Equal("0.1", assetv1.Version) - }) - - r.Run("should store owners if any", func() { - ast := asset.Asset{ - URN: "urn-u-3", - Type: "table", - Service: "bigquery", - Owners: []user.User{ - stripUserID(r.users[1]), - {Email: r.users[2].Email}, - }, - UpdatedBy: r.users[0], - } - - id, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - r.Require().NotEmpty(id) - ast.ID = id - - actual, err := r.repository.GetByID(r.ctx, ast.ID) - r.NoError(err) - - r.Len(actual.Owners, len(ast.Owners)) - r.Equal(r.users[1].ID, actual.Owners[0].ID) - r.Equal(r.users[2].ID, actual.Owners[1].ID) - }) - - r.Run("should create owners as users if they do not exist yet", func() { - ast := asset.Asset{ - URN: "urn-u-3a", - Type: "table", - Service: "bigquery", - Owners: []user.User{ - {Email: "newuser@example.com"}, - {UUID: "108151e5-4c9f-4951-a8e1-6966b5aa2bb6"}, - }, - UpdatedBy: r.users[0], - } - - id, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - r.NotEmpty(id) - - actual, err := r.repository.GetByID(r.ctx, id) - r.NoError(err) - - r.Len(actual.Owners, len(ast.Owners)) - r.Equal(ast.Owners[0].Email, actual.Owners[0].Email) - r.Equal(ast.Owners[1].UUID, actual.Owners[1].UUID) - }) - }) - - r.Run("on update", func() { - r.Run("should not create nor updating the asset if asset is identical", func() { - ast := asset.Asset{ - URN: "urn-u-2", - Type: "table", - Service: "bigquery", - UpdatedBy: r.users[0], - } - identicalAsset := ast - - id, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - r.NotEmpty(id) - ast.ID = id - - id, err = r.repository.Upsert(r.ctx, r.ns, &identicalAsset) - r.Require().NoError(err) - r.NotEmpty(id) - identicalAsset.ID = id - - r.Equal(ast.ID, identicalAsset.ID) - }) - - r.Run("should update the asset if asset is not identical", func() { - ast := asset.Asset{ - URN: "urn-u-2", - Type: "table", - Service: "bigquery", - URL: "https://sample-url-old.com", - UpdatedBy: r.users[0], - } - - id, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - r.NotEmpty(id) - ast.ID = id - - updated := ast - updated.URL = "https://sample-url.com" - - id, err = r.repository.Upsert(r.ctx, r.ns, &updated) - r.Require().NoError(err) - r.NotEmpty(id) - updated.ID = id - - r.Equal(ast.ID, updated.ID) - - actual, err := r.repository.GetByID(r.ctx, ast.ID) - r.NoError(err) - - r.Equal(updated.URL, actual.URL) - }) - - r.Run("should delete old owners if it does not exist on new asset", func() { - ast := asset.Asset{ - URN: "urn-u-4", - Type: "table", - Service: "bigquery", - Owners: []user.User{ - stripUserID(r.users[1]), - stripUserID(r.users[2]), - }, - UpdatedBy: r.users[0], - } - newAsset := ast - newAsset.Owners = []user.User{ - stripUserID(r.users[2]), - } - - id, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - r.NotEmpty(id) - ast.ID = id - - id, err = r.repository.Upsert(r.ctx, r.ns, &newAsset) - r.Require().NoError(err) - r.NotEmpty(id) - newAsset.ID = id - - actual, err := r.repository.GetByID(r.ctx, ast.ID) - r.NoError(err) - r.Len(actual.Owners, len(newAsset.Owners)) - r.Equal(r.users[2].ID, actual.Owners[0].ID) - }) - - r.Run("should create new owners if it does not exist on old asset", func() { - ast := asset.Asset{ - URN: "urn-u-4", - Type: "table", - Service: "bigquery", - Owners: []user.User{ - stripUserID(r.users[1]), - }, - UpdatedBy: r.users[0], - } - newAsset := ast - newAsset.Owners = []user.User{ - stripUserID(r.users[1]), - stripUserID(r.users[2]), - } - - id, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - r.NotEmpty(id) - ast.ID = id - - id, err = r.repository.Upsert(r.ctx, r.ns, &newAsset) - r.Require().NoError(err) - r.NotEmpty(id) - newAsset.ID = id - - actual, err := r.repository.GetByID(r.ctx, ast.ID) - r.NoError(err) - r.Len(actual.Owners, len(newAsset.Owners)) - r.Equal(r.users[1].ID, actual.Owners[0].ID) - r.Equal(r.users[2].ID, actual.Owners[1].ID) - }) - - r.Run("should create users from owners if owner emails do not exist yet", func() { - ast := asset.Asset{ - URN: "urn-u-4a", - Type: "table", - Service: "bigquery", - Owners: []user.User{ - stripUserID(r.users[1]), - }, - UpdatedBy: r.users[0], - } - newAsset := ast - newAsset.Owners = []user.User{ - stripUserID(r.users[1]), - {Email: "newuser@example.com"}, - } - - id, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - r.NotEmpty(id) - ast.ID = id - - id, err = r.repository.Upsert(r.ctx, r.ns, &newAsset) - r.Require().NoError(err) - r.NotEmpty(id) - newAsset.ID = id - - actual, err := r.repository.GetByID(r.ctx, ast.ID) - r.NoError(err) - r.Len(actual.Owners, len(newAsset.Owners)) - r.NotEmpty(actual.Owners[0].ID) - r.Equal(r.users[1].ID, actual.Owners[0].ID) - r.NotEmpty(actual.Owners[1].ID) - r.Equal(newAsset.Owners[1].Email, actual.Owners[1].Email) - }) - }) -} - -func (r *AssetRepositoryTestSuite) TestDeleteByID() { - r.Run("return error from client if any", func() { - err := r.repository.DeleteByID(r.ctx, "invalid-uuid") - r.Error(err) - r.Contains(err.Error(), "invalid asset id: \"invalid-uuid\"") - }) - - r.Run("return NotFoundError if asset does not exist", func() { - uuid := "2aabb450-f986-44e2-a6db-7996861d5004" - err := r.repository.DeleteByID(r.ctx, uuid) - r.ErrorAs(err, &asset.NotFoundError{AssetID: uuid}) - }) - - r.Run("should delete correct asset", func() { - asset1 := asset.Asset{ - URN: "urn-del-1", - Type: "table", - Service: "bigquery", - UpdatedBy: user.User{ID: defaultAssetUpdaterUserID}, - } - asset2 := asset.Asset{ - URN: "urn-del-2", - Type: "topic", - Service: "kafka", - Version: asset.BaseVersion, - UpdatedBy: user.User{ID: defaultAssetUpdaterUserID}, - } - - var err error - id, err := r.repository.Upsert(r.ctx, r.ns, &asset1) - r.Require().NoError(err) - r.Require().NotEmpty(id) - asset1.ID = id - - id, err = r.repository.Upsert(r.ctx, r.ns, &asset2) - r.Require().NoError(err) - r.Require().NotEmpty(id) - asset2.ID = id - - err = r.repository.DeleteByID(r.ctx, asset1.ID) - r.NoError(err) - - _, err = r.repository.GetByID(r.ctx, asset1.ID) - r.ErrorAs(err, &asset.NotFoundError{AssetID: asset1.ID}) - - asset2FromDB, err := r.repository.GetByID(r.ctx, asset2.ID) - r.NoError(err) - r.Equal(asset2.ID, asset2FromDB.ID) - - // cleanup - err = r.repository.DeleteByID(r.ctx, asset2.ID) - r.NoError(err) - }) -} - -func (r *AssetRepositoryTestSuite) TestDeleteByURN() { - r.Run("return NotFoundError if asset does not exist", func() { - urn := "urn-test-1" - err := r.repository.DeleteByURN(r.ctx, urn) - r.ErrorAs(err, &asset.NotFoundError{URN: urn}) - }) - - r.Run("should delete correct asset", func() { - asset1 := asset.Asset{ - URN: "urn-del-1", - Type: "table", - Service: "bigquery", - UpdatedBy: user.User{ID: defaultAssetUpdaterUserID}, - } - asset2 := asset.Asset{ - URN: "urn-del-2", - Type: "topic", - Service: "kafka", - Version: asset.BaseVersion, - UpdatedBy: user.User{ID: defaultAssetUpdaterUserID}, - } - - _, err := r.repository.Upsert(r.ctx, r.ns, &asset1) - r.Require().NoError(err) - - id, err := r.repository.Upsert(r.ctx, r.ns, &asset2) - r.Require().NoError(err) - - err = r.repository.DeleteByURN(r.ctx, asset1.URN) - r.NoError(err) - - _, err = r.repository.GetByURN(r.ctx, asset1.URN) - r.ErrorAs(err, &asset.NotFoundError{URN: asset1.URN}) - - asset2FromDB, err := r.repository.GetByURN(r.ctx, asset2.URN) - r.NoError(err) - r.Equal(id, asset2FromDB.ID) - - // cleanup - err = r.repository.DeleteByURN(r.ctx, asset2.URN) - r.NoError(err) - }) -} - -func (r *AssetRepositoryTestSuite) TestAddProbe() { - r.Run("return NotFoundError if asset does not exist", func() { - urn := "invalid-urn" - probe := asset.Probe{} - err := r.repository.AddProbe(r.ctx, r.ns, urn, &probe) - r.ErrorAs(err, &asset.NotFoundError{URN: urn}) - }) - - r.Run("should populate CreatedAt and persist probe", func() { - ast := asset.Asset{ - URN: "urn-add-probe-1", - Type: asset.TypeJob, - Service: "airflow", - UpdatedBy: user.User{ID: defaultAssetUpdaterUserID}, - } - probe := asset.Probe{ - Status: "COMPLETED", - StatusReason: "Sample Reason", - Timestamp: time.Now().Add(2 * time.Minute), - Metadata: map[string]interface{}{ - "foo": "bar", - }, - } - - _, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - - err = r.repository.AddProbe(r.ctx, r.ns, ast.URN, &probe) - r.NoError(err) - - // assert populated fields - r.NotEmpty(probe.ID) - r.Equal(ast.URN, probe.AssetURN) - r.False(probe.CreatedAt.IsZero()) - - // assert probe is persisted - probesFromDB, err := r.repository.GetProbes(r.ctx, ast.URN) - r.Require().NoError(err) - r.Require().Len(probesFromDB, 1) - - probeFromDB := probesFromDB[0] - r.Equal(probe.ID, probeFromDB.ID) - r.Equal(probe.AssetURN, probeFromDB.AssetURN) - r.Equal(probe.Status, probeFromDB.Status) - r.Equal(probe.StatusReason, probeFromDB.StatusReason) - r.Equal(probe.Metadata, probeFromDB.Metadata) - // we use `1µs` instead of `0` for the delta due to postgres might round precision before storing - r.WithinDuration(probe.Timestamp, probeFromDB.Timestamp, 1*time.Microsecond) - r.WithinDuration(probe.CreatedAt, probeFromDB.CreatedAt, 1*time.Microsecond) - - // cleanup - err = r.repository.DeleteByURN(r.ctx, ast.URN) - r.Require().NoError(err) - }) - - r.Run("should populate Timestamp if empty", func() { - ast := asset.Asset{ - URN: "urn-add-probe-2", - Type: asset.TypeJob, - Service: "optimus", - UpdatedBy: user.User{ID: defaultAssetUpdaterUserID}, - } - otherAst := asset.Asset{ - URN: "urn-add-probe-3", - Type: asset.TypeJob, - Service: "airflow", - UpdatedBy: user.User{ID: defaultAssetUpdaterUserID}, - } - probe := asset.Probe{ - Status: "RUNNING", - } - otherProbe := asset.Probe{ - Status: "RUNNING", - } - - _, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - _, err = r.repository.Upsert(r.ctx, r.ns, &otherAst) - r.Require().NoError(err) - - err = r.repository.AddProbe(r.ctx, r.ns, ast.URN, &probe) - r.NoError(err) - - // assert populated fields - r.False(probe.CreatedAt.IsZero()) - r.Equal(probe.CreatedAt, probe.Timestamp) - - err = r.repository.AddProbe(r.ctx, r.ns, otherAst.URN, &otherProbe) - r.NoError(err) - - // assert probe is persisted - probesFromDB, err := r.repository.GetProbes(r.ctx, ast.URN) - r.Require().NoError(err) - r.Require().Len(probesFromDB, 1) - - probeFromDB := probesFromDB[0] - r.Equal(probe.ID, probeFromDB.ID) - r.WithinDuration(probe.Timestamp, probeFromDB.Timestamp, 1*time.Microsecond) - r.WithinDuration(probe.CreatedAt, probeFromDB.CreatedAt, 1*time.Microsecond) - r.WithinDuration(probeFromDB.CreatedAt, probeFromDB.Timestamp, 1*time.Microsecond) - - // cleanup - err = r.repository.DeleteByURN(r.ctx, ast.URN) - r.Require().NoError(err) - }) -} - -func (r *AssetRepositoryTestSuite) TestGetProbes() { - r.Run("should return list of probes by asset urn", func() { - ast := asset.Asset{ - URN: "urn-add-probe-1", - Type: asset.TypeJob, - Service: "airflow", - UpdatedBy: user.User{ID: defaultAssetUpdaterUserID}, - } - p1 := asset.Probe{ - Status: "COMPLETED", - Timestamp: time.Now().UTC().Add(3 * time.Minute), - Metadata: map[string]interface{}{ - "foo": "bar", - }, - } - p2 := asset.Probe{ - Status: "FAILED", - StatusReason: "sample error", - Timestamp: time.Now().UTC().Add(2 * time.Minute), - Metadata: map[string]interface{}{ - "bar": "foo", - }, - } - p3 := asset.Probe{ - Status: "RUNNING", - Timestamp: time.Now().UTC().Add(1 * time.Minute), - } - - _, err := r.repository.Upsert(r.ctx, r.ns, &ast) - r.Require().NoError(err) - - err = r.repository.AddProbe(r.ctx, r.ns, ast.URN, &p1) - r.NoError(err) - err = r.repository.AddProbe(r.ctx, r.ns, ast.URN, &p2) - r.NoError(err) - err = r.repository.AddProbe(r.ctx, r.ns, ast.URN, &p3) - r.NoError(err) - - // assert probe is persisted - actual, err := r.repository.GetProbes(r.ctx, ast.URN) - r.Require().NoError(err) - r.Require().Len(actual, 3) - - expected := []asset.Probe{p1, p2, p3} - r.Equal(expected[0].ID, actual[0].ID) - r.Equal(expected[1].ID, actual[1].ID) - r.Equal(expected[2].ID, actual[2].ID) - - r.Equal(expected[0].ID, actual[0].ID) - r.Equal(expected[0].AssetURN, actual[0].AssetURN) - r.Equal(expected[0].Status, actual[0].Status) - r.Equal(expected[0].StatusReason, actual[0].StatusReason) - r.Equal(expected[0].Metadata, actual[0].Metadata) - r.WithinDuration(expected[0].Timestamp, actual[0].Timestamp, 1*time.Microsecond) - r.WithinDuration(expected[0].CreatedAt, actual[0].CreatedAt, 1*time.Microsecond) - - // cleanup - err = r.repository.DeleteByURN(r.ctx, ast.URN) - r.Require().NoError(err) - }) -} - -func (r *AssetRepositoryTestSuite) TestGetProbesWithFilter() { - r.insertProbes(r.T()) - - newTS := func(s string) time.Time { - r.T().Helper() - - ts, err := time.Parse(time.RFC3339, s) - r.Require().NoError(err) - return ts - } - keys := func(m map[string][]asset.Probe) []string { - kk := make([]string, 0, len(m)) - for k := range m { - kk = append(kk, k) - } - return kk - } - - cases := []struct { - name string - flt asset.ProbesFilter - expected map[string][]asset.Probe - }{ - { - name: "AssetURNs=c-demo-kafka", - flt: asset.ProbesFilter{AssetURNs: []string{"c-demo-kafka"}}, - expected: map[string][]asset.Probe{ - "c-demo-kafka": { - { - AssetURN: "c-demo-kafka", - Status: "SUCCESS", - Timestamp: newTS("2022-03-08T09:58:43Z"), - }, - { - AssetURN: "c-demo-kafka", - Status: "FAILURE", - Timestamp: newTS("2021-11-25T19:28:18Z"), - }, - { - AssetURN: "c-demo-kafka", - Status: "FAILURE", - StatusReason: "Expanded even-keeled data-warehouse", - Timestamp: newTS("2021-11-10T09:28:21Z"), - }, - }, - }, - }, - { - name: "NewerThan=2022-09-08", - flt: asset.ProbesFilter{NewerThan: newTS("2022-09-08T00:00:00Z")}, - expected: map[string][]asset.Probe{ - "f-john-test-001": { - { - AssetURN: "f-john-test-001", - Status: "CANCELLED", - Timestamp: newTS("2022-09-23T14:39:57Z"), - }, - }, - "ten-mock": { - { - AssetURN: "ten-mock", - Status: "CANCELLED", - StatusReason: "Synergized bottom-line forecast", - Timestamp: newTS("2022-09-11T07:40:11Z"), - }, - }, - "e-test-grant2": { - { - AssetURN: "e-test-grant2", - Status: "TERMINATED", - StatusReason: "Digitized asynchronous knowledge user", - Timestamp: newTS("2022-09-08T12:16:42Z"), - }, - }, - }, - }, - { - name: "OlderThan=2021-11-01", - flt: asset.ProbesFilter{OlderThan: newTS("2021-11-01T00:00:00Z")}, - expected: map[string][]asset.Probe{ - "i-undefined-dfgdgd-avi": { - { - AssetURN: "i-undefined-dfgdgd-avi", - Status: "CANCELLED", - StatusReason: "Re-contextualized secondary projection", - Timestamp: newTS("2021-10-17T19:14:51Z"), - }, - }, - "e-test-grant2": { - { - AssetURN: "e-test-grant2", - Status: "TERMINATED", - StatusReason: "Integrated attitude-oriented open system", - Timestamp: newTS("2021-10-31T05:58:13Z"), - }, - }, - }, - }, - { - name: "MaxRows=1", - flt: asset.ProbesFilter{MaxRows: 1}, - expected: map[string][]asset.Probe{ - "c-demo-kafka": { - { - AssetURN: "c-demo-kafka", - Status: "SUCCESS", - Timestamp: newTS("2022-03-08T09:58:43Z"), - }, - }, - "e-test-grant2": { - { - AssetURN: "e-test-grant2", - Status: "TERMINATED", - StatusReason: "Digitized asynchronous knowledge user", - Timestamp: newTS("2022-09-08T12:16:42Z"), - }, - }, - "eleven-mock": { - { - AssetURN: "eleven-mock", - Status: "FAILURE", - StatusReason: "Proactive zero administration attitude", - Timestamp: newTS("2022-02-21T22:52:06Z"), - }, - }, - "f-john-test-001": { - { - AssetURN: "f-john-test-001", - Status: "CANCELLED", - Timestamp: newTS("2022-09-23T14:39:57Z"), - }, - }, - "g-jane-kafka-1a": { - { - AssetURN: "g-jane-kafka-1a", - Status: "SUCCESS", - StatusReason: "Integrated 24/7 knowledge base", - Timestamp: newTS("2022-04-19T19:42:09Z"), - }, - }, - "h-test-new-kafka": { - { - AssetURN: "h-test-new-kafka", - Status: "SUCCESS", - StatusReason: "User-friendly systematic neural-net", - Timestamp: newTS("2022-08-14T03:04:44Z"), - }, - }, - "i-test-grant": { - { - AssetURN: "i-test-grant", - Status: "FAILURE", - StatusReason: "Ameliorated explicit customer loyalty", - Timestamp: newTS("2022-07-24T06:52:27Z"), - }, - }, - "i-undefined-dfgdgd-avi": { - { - AssetURN: "i-undefined-dfgdgd-avi", - Status: "TERMINATED", - StatusReason: "Networked analyzing framework", - Timestamp: newTS("2022-08-13T13:54:01Z"), - }, - }, - "j-xcvcx": { - { - AssetURN: "j-xcvcx", - Status: "FAILURE", - StatusReason: "Compatible impactful workforce", - Timestamp: newTS("2022-08-03T19:29:49Z"), - }, - }, - "nine-mock": { - { - AssetURN: "nine-mock", - Status: "CANCELLED", - StatusReason: "User-friendly tertiary matrix", - Timestamp: newTS("2022-08-14T14:20:20Z"), - }, - }, - "ten-mock": { - { - AssetURN: "ten-mock", - Status: "CANCELLED", - StatusReason: "Synergized bottom-line forecast", - Timestamp: newTS("2022-09-11T07:40:11Z"), - }, - }, - "twelfth-mock": { - { - AssetURN: "twelfth-mock", - Status: "TERMINATED", - StatusReason: "Enterprise-wide interactive Graphical User Interface", - Timestamp: newTS("2022-04-15T00:02:25Z"), - }, - }, - }, - }, - { - name: "AssetURNs=c-demo-kafka;NewerThan=2022-03-08", - flt: asset.ProbesFilter{AssetURNs: []string{"c-demo-kafka"}, NewerThan: newTS("2022-03-08T00:00:00Z")}, - expected: map[string][]asset.Probe{ - "c-demo-kafka": { - { - AssetURN: "c-demo-kafka", - Status: "SUCCESS", - Timestamp: newTS("2022-03-08T09:58:43Z"), - }, - }, - }, - }, - { - name: "AssetURNs=c-demo-kafka;MaxRows=1", - flt: asset.ProbesFilter{AssetURNs: []string{"c-demo-kafka"}, MaxRows: 1}, - expected: map[string][]asset.Probe{ - "c-demo-kafka": { - { - AssetURN: "c-demo-kafka", - Status: "SUCCESS", - Timestamp: newTS("2022-03-08T09:58:43Z"), - }, - }, - }, - }, - { - name: "AssetURNs=c-demo-kafka,e-test-grant2;MaxRows=1", - flt: asset.ProbesFilter{AssetURNs: []string{"c-demo-kafka", "e-test-grant2"}, MaxRows: 1}, - expected: map[string][]asset.Probe{ - "c-demo-kafka": { - { - AssetURN: "c-demo-kafka", - Status: "SUCCESS", - Timestamp: newTS("2022-03-08T09:58:43Z"), - }, - }, - "e-test-grant2": { - { - AssetURN: "e-test-grant2", - Status: "TERMINATED", - StatusReason: "Digitized asynchronous knowledge user", - Timestamp: newTS("2022-09-08T12:16:42Z"), - }, - }, - }, - }, - { - name: "NewerThan=2022-08-14;MaxRows=1", - flt: asset.ProbesFilter{NewerThan: newTS("2022-08-14T00:00:00Z"), MaxRows: 1}, - expected: map[string][]asset.Probe{ - "f-john-test-001": { - { - AssetURN: "f-john-test-001", - Status: "CANCELLED", - Timestamp: newTS("2022-09-23T14:39:57Z"), - }, - }, - "ten-mock": { - { - AssetURN: "ten-mock", - Status: "CANCELLED", - StatusReason: "Synergized bottom-line forecast", - Timestamp: newTS("2022-09-11T07:40:11Z"), - }, - }, - "e-test-grant2": { - { - AssetURN: "e-test-grant2", - Status: "TERMINATED", - StatusReason: "Digitized asynchronous knowledge user", - Timestamp: newTS("2022-09-08T12:16:42Z"), - }, - }, - "nine-mock": { - { - AssetURN: "nine-mock", - Status: "CANCELLED", - StatusReason: "User-friendly tertiary matrix", - Timestamp: newTS("2022-08-14T14:20:20Z"), - }, - }, - "h-test-new-kafka": { - { - AssetURN: "h-test-new-kafka", - Status: "SUCCESS", - StatusReason: "User-friendly systematic neural-net", - Timestamp: newTS("2022-08-14T03:04:44Z"), - }, - }, - }, - }, - { - name: "OlderThan=2021-11-08;MaxRows=1", - flt: asset.ProbesFilter{OlderThan: newTS("2021-11-08T00:00:00Z"), MaxRows: 1}, - expected: map[string][]asset.Probe{ - "i-undefined-dfgdgd-avi": { - { - AssetURN: "i-undefined-dfgdgd-avi", - Status: "SUCCESS", - StatusReason: "Persevering composite workforce", - Timestamp: newTS("2021-11-07T12:16:41Z"), - }, - }, - "e-test-grant2": { - { - AssetURN: "e-test-grant2", - Status: "TERMINATED", - StatusReason: "Digitized asynchronous knowledge user", - Timestamp: newTS("2022-09-08T12:16:42Z"), - }, - }, - }, - }, - { - name: "AssetURNs=c-demo-kafka,e-test-grant2,nine-mock;MaxRows=1;NewerThan=2022-08-14;OlderThan=2022-09-11", - flt: asset.ProbesFilter{ - AssetURNs: []string{"c-demo-kafka", "e-test-grant2", "nine-mock"}, - NewerThan: newTS("2022-08-14T00:00:00Z"), - OlderThan: newTS("2022-09-11T00:00:00Z"), - MaxRows: 1, - }, - expected: map[string][]asset.Probe{ - "e-test-grant2": { - { - AssetURN: "e-test-grant2", - Status: "TERMINATED", - StatusReason: "Digitized asynchronous knowledge user", - Timestamp: newTS("2022-09-08T12:16:42Z"), - }, - }, - "nine-mock": { - { - AssetURN: "nine-mock", - Status: "CANCELLED", - StatusReason: "User-friendly tertiary matrix", - Timestamp: newTS("2022-08-14T14:20:20Z"), - }, - }, - }, - }, - } - for _, tc := range cases { - r.Run(tc.name, func() { - actual, err := r.repository.GetProbesWithFilter(r.ctx, tc.flt) - r.NoError(err) - - r.ElementsMatch(keys(tc.expected), keys(actual), "Mismatch of URN keys in map") - for urn, expPrbs := range tc.expected { - actPrbs, ok := actual[urn] - if !ok || r.Lenf(actPrbs, len(expPrbs), "Mismatch in length of assets for URN '%s'", urn) { - continue - } - - for i := range actPrbs { - r.assertProbe(r.T(), expPrbs[i], actPrbs[i]) - } - } - }) - } -} - -func (r *AssetRepositoryTestSuite) insertProbes(t *testing.T) { - t.Helper() - - probesJSON, err := os.ReadFile("./testdata/mock-probes-data.json") - r.Require().NoError(err) - - var probes []asset.Probe - r.Require().NoError(json.Unmarshal(probesJSON, &probes)) - - for _, p := range probes { - r.Require().NoError(r.repository.AddProbe(r.ctx, r.ns, p.AssetURN, &p)) - } -} - -func (r *AssetRepositoryTestSuite) assertAsset(expectedAsset *asset.Asset, actualAsset *asset.Asset) bool { - // sanitize time to make the assets comparable - expectedAsset.CreatedAt = time.Time{} - expectedAsset.UpdatedAt = time.Time{} - expectedAsset.RefreshedAt = nil - expectedAsset.UpdatedBy.CreatedAt = time.Time{} - expectedAsset.UpdatedBy.UpdatedAt = time.Time{} - - actualAsset.CreatedAt = time.Time{} - actualAsset.UpdatedAt = time.Time{} - actualAsset.RefreshedAt = nil - actualAsset.UpdatedBy.CreatedAt = time.Time{} - actualAsset.UpdatedBy.UpdatedAt = time.Time{} - - return r.Equal(expectedAsset, actualAsset) -} - -func clearTimestamps(ast *asset.Asset) { - ast.UpdatedBy.CreatedAt = time.Time{} - ast.UpdatedBy.UpdatedAt = time.Time{} - ast.CreatedAt = time.Time{} - ast.UpdatedAt = time.Time{} - ast.RefreshedAt = nil -} - -func (r *AssetRepositoryTestSuite) assertProbe(t *testing.T, expected asset.Probe, actual asset.Probe) bool { - t.Helper() - - return r.Equal(expected.AssetURN, actual.AssetURN) && - r.Equal(expected.Status, actual.Status) && - r.Equal(expected.StatusReason, actual.StatusReason) && - r.Equal(expected.Metadata, actual.Metadata) && - r.Equal(expected.Timestamp, actual.Timestamp) -} - -func TestAssetRepository(t *testing.T) { - suite.Run(t, &AssetRepositoryTestSuite{}) -} - -func stripUserID(u user.User) user.User { - u.ID = "" - return u -} diff --git a/store/postgres/comment_model.go b/store/postgres/comment_model.go deleted file mode 100644 index 25b68de4..00000000 --- a/store/postgres/comment_model.go +++ /dev/null @@ -1,29 +0,0 @@ -package postgres - -import ( - "time" - - "github.com/raystack/compass/core/discussion" -) - -type CommentModel struct { - ID string `db:"id"` - DiscussionID string `db:"discussion_id"` - Body string `db:"body"` - Owner UserModel `db:"owner"` - UpdatedBy UserModel `db:"updated_by"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` -} - -func (cm CommentModel) toComment() discussion.Comment { - return discussion.Comment{ - ID: cm.ID, - DiscussionID: cm.DiscussionID, - Body: cm.Body, - Owner: cm.Owner.toUser(), - UpdatedBy: cm.UpdatedBy.toUser(), - CreatedAt: cm.CreatedAt, - UpdatedAt: cm.UpdatedAt, - } -} diff --git a/store/postgres/discussion_comment_repository.go b/store/postgres/discussion_comment_repository.go deleted file mode 100644 index 4f2b712e..00000000 --- a/store/postgres/discussion_comment_repository.go +++ /dev/null @@ -1,180 +0,0 @@ -package postgres - -import ( - "context" - "database/sql" - "errors" - "fmt" - "github.com/jmoiron/sqlx" - "github.com/raystack/compass/core/namespace" - "time" - - sq "github.com/Masterminds/squirrel" - "github.com/raystack/compass/core/discussion" -) - -// CreateComment adds a new comment to a specific discussion -func (r *DiscussionRepository) CreateComment(ctx context.Context, ns *namespace.Namespace, cmt *discussion.Comment) (string, error) { - var commentID string - query, args, err := sq.Insert("comments"). - Columns("discussion_id", - "body", - "owner", - "updated_by", - "namespace_id"). - Values(cmt.DiscussionID, cmt.Body, cmt.Owner.ID, cmt.Owner.ID, ns.ID). - Suffix("RETURNING \"id\""). - PlaceholderFormat(sq.Dollar). - ToSql() - if err != nil { - return "", fmt.Errorf("error building insert query: %w", err) - } - - err = r.client.QueryFn(ctx, func(conn *sqlx.Conn) error { - return conn.QueryRowxContext(ctx, query, args...).Scan(&commentID) - }) - if err != nil { - err = checkPostgresError(err) - if errors.Is(err, errForeignKeyViolation) { - return "", discussion.NotFoundError{DiscussionID: cmt.DiscussionID} - } - return "", fmt.Errorf("error running insert query: %w", err) - } - - if commentID == "" { - return "", fmt.Errorf("error comment ID is empty from DB") - } - - return commentID, nil -} - -// GetAllComments fetches all comments of a specific discussion -func (r *DiscussionRepository) GetAllComments(ctx context.Context, did string, flt discussion.Filter) ([]discussion.Comment, error) { - - builder := r.selectCommentsSQL() - builder = builder.Where(sq.Eq{"discussion_id": did}) - builder = r.buildSelectOrderQuery(builder, flt) - builder = r.buildSelectLimitQuery(builder, flt) - query, args, err := r.buildSQL(builder) - if err != nil { - return nil, fmt.Errorf("error building query: %w", err) - } - - var models []CommentModel - err = r.client.SelectContext(ctx, &models, query, args...) - if err != nil { - return nil, fmt.Errorf("error getting list of comments: %w", err) - } - - cmts := make([]discussion.Comment, 0, len(models)) - for _, m := range models { - cmts = append(cmts, m.toComment()) - } - return cmts, nil -} - -// Get fetchs a comment -func (r *DiscussionRepository) GetComment(ctx context.Context, cid string, did string) (discussion.Comment, error) { - - builder := r.selectCommentsSQL() - builder = builder.Where(sq.Eq{ - "c.id": cid, - "c.discussion_id": did, - }) - query, args, err := r.buildSQL(builder) - if err != nil { - return discussion.Comment{}, fmt.Errorf("error building query: %w", err) - } - - var model CommentModel - err = r.client.GetContext(ctx, &model, query, args...) - if errors.Is(err, sql.ErrNoRows) { - return discussion.Comment{}, discussion.NotFoundError{CommentID: cid, DiscussionID: did} - } - if err != nil { - return discussion.Comment{}, fmt.Errorf("error getting comment: %w", err) - } - - return model.toComment(), nil -} - -// Update updates a comment -func (r *DiscussionRepository) UpdateComment(ctx context.Context, cmt *discussion.Comment) error { - builder := sq.Update("comments"). - Set("body", cmt.Body). - Set("updated_by", cmt.UpdatedBy.ID). - Set("updated_at", time.Now()). - Where(sq.Eq{ - "id": cmt.ID, - "discussion_id": cmt.DiscussionID, - }) - query, args, err := r.buildSQL(builder) - if err != nil { - return fmt.Errorf("error building query: %w", err) - } - - res, err := r.client.ExecContext(ctx, query, args...) - if err != nil { - return fmt.Errorf("failed updating comment with id %s and discussion id %s: %w", cmt.ID, cmt.DiscussionID, err) - } - affectedRows, err := res.RowsAffected() - if err != nil { - return fmt.Errorf("error getting affected rows: %w", err) - } - if affectedRows == 0 { - return discussion.NotFoundError{CommentID: cmt.ID, DiscussionID: cmt.DiscussionID} - } - - return nil -} - -// Delete removes a comment -func (r *DiscussionRepository) DeleteComment(ctx context.Context, cid string, did string) error { - builder := sq.Delete("comments"). - Where(sq.Eq{ - "id": cid, - "discussion_id": did, - }) - query, args, err := r.buildSQL(builder) - if err != nil { - return fmt.Errorf("error building query: %w", err) - } - - res, err := r.client.ExecContext(ctx, query, args...) - if err != nil { - return fmt.Errorf("failed deleting comment with id %s and discussion id: %w", cid, err) - } - affectedRows, err := res.RowsAffected() - if err != nil { - return fmt.Errorf("error getting affected rows: %w", err) - } - if affectedRows == 0 { - return discussion.NotFoundError{CommentID: cid, DiscussionID: did} - } - - return nil -} - -func (r *DiscussionRepository) selectCommentsSQL() sq.SelectBuilder { - return sq.Select(` - c.id as id, - c.discussion_id as discussion_id, - c.body as body, - c.created_at as created_at, - c.updated_at as updated_at, - uo.id as "owner.id", - uo.uuid as "owner.uuid", - uo.email as "owner.email", - uo.provider as "owner.provider", - uo.created_at as "owner.created_at", - uo.updated_at as "owner.updated_at", - uu.uuid as "updated_by.uuid", - uu.email as "updated_by.email", - uu.provider as "updated_by.provider", - uu.created_at as "updated_by.created_at", - uu.updated_at as "updated_by.updated_at" - `). - From("comments c"). - Join("users uo ON c.owner = uo.id"). - Join("users uu ON c.updated_by = uu.id") -} diff --git a/store/postgres/discussion_comment_repository_test.go b/store/postgres/discussion_comment_repository_test.go deleted file mode 100644 index 34898d3d..00000000 --- a/store/postgres/discussion_comment_repository_test.go +++ /dev/null @@ -1,227 +0,0 @@ -package postgres_test - -import ( - "github.com/raystack/compass/core/discussion" -) - -func (r *DiscussionRepositoryTestSuite) TestCreateComment() { - r.Run("should create a new comment with full information", func() { - cmt := &discussion.Comment{ - DiscussionID: "55555", - Body: "This is a new comment", - Owner: r.users[len(r.users)-1], - } - id, err := r.repository.CreateComment(r.ctx, r.ns, cmt) - r.NoError(err) - r.NotEmpty(id) - }) - - r.Run("should return error when creating a new comment with empty body", func() { - cmt := &discussion.Comment{ - Body: " ", - Owner: r.users[len(r.users)-1], - } - id, err := r.repository.CreateComment(r.ctx, r.ns, cmt) - r.Error(err) - r.Empty(id) - }) - - r.Run("should return error when creating a new comment with empty owner", func() { - cmt := &discussion.Comment{ - Body: "This is Body", - } - id, err := r.repository.CreateComment(r.ctx, r.ns, cmt) - r.Error(err) - r.Empty(id) - }) - - r.Run("should return error not found when creating a new comment with unknown discussion id", func() { - cmt := &discussion.Comment{ - Body: "some body", - Owner: r.users[len(r.users)-1], - } - cmt.DiscussionID = "9278" - id, err := r.repository.CreateComment(r.ctx, r.ns, cmt) - r.ErrorAs(err, new(discussion.NotFoundError)) - r.Empty(id) - }) -} - -func (r *DiscussionRepositoryTestSuite) TestGetAllComments() { - r.Run("should return list of comments of a discussion if discussion id exists", func() { - discussionID := "11111" - cmts, err := r.repository.GetAllComments(r.ctx, discussionID, discussion.Filter{}) - r.NoError(err) - r.Len(cmts, 2) - for _, cmt := range cmts { - r.Equal(discussionID, cmt.DiscussionID) - } - }) - - r.Run("should return empty list of comments of a discussion if discussion id does not exist", func() { - discussionID := "90909" - cmts, err := r.repository.GetAllComments(r.ctx, discussionID, discussion.Filter{}) - r.NoError(err) - r.Empty(cmts) - }) - - r.Run("should return error if discussion id's type is wrong", func() { - discussionID := "abc" - cmts, err := r.repository.GetAllComments(r.ctx, discussionID, discussion.Filter{}) - r.Error(err) - r.Empty(cmts) - }) - - r.Run("should working fine with filter", func() { - testCases := []struct { - description string - filter discussion.Filter - resultLength int - validateResult func(r *DiscussionRepositoryTestSuite, results []discussion.Comment) - }{ - { - description: "should limit with size", - filter: discussion.Filter{ - Size: 1, - }, - resultLength: 1, - }, - { - description: "should move cursor with offset", - filter: discussion.Filter{ - Size: 5, - Offset: 2, - }, - resultLength: 1, - }, - { - description: "should sort descendingly with sort", - filter: discussion.Filter{ - SortBy: "updated_at", - SortDirection: "desc", - }, - resultLength: 3, - validateResult: func(r *DiscussionRepositoryTestSuite, results []discussion.Comment) { - r.Equal(results[0].ID, "55") - r.Equal(results[1].ID, "44") - r.Equal(results[2].ID, "33") - }, - }, - } - - for _, testCase := range testCases { - r.Run(testCase.description, func() { - discussionID := "22222" - dscs, err := r.repository.GetAllComments(r.ctx, discussionID, testCase.filter) - r.NoError(err) - r.Len(dscs, testCase.resultLength) - - if testCase.validateResult != nil { - testCase.validateResult(r, dscs) - } - }) - } - }) -} - -func (r *DiscussionRepositoryTestSuite) TestGetComment() { - discussionID := "11111" - r.Run("should return a comment if comment id exists", func() { - commentID := "11" - cmt, err := r.repository.GetComment(r.ctx, commentID, discussionID) - r.NoError(err) - r.Equal(commentID, cmt.ID) - r.Equal(discussionID, cmt.DiscussionID) - r.Equal("This is 1st comment of discussion 11111", cmt.Body) - }) - - r.Run("should return error not found if comment id does not exist", func() { - commentID := "9090" - cmt, err := r.repository.GetComment(r.ctx, commentID, discussionID) - r.ErrorAs(err, new(discussion.NotFoundError)) - r.Empty(cmt) - }) - - r.Run("should return error if commnet id's type is wrong", func() { - commentID := "abc" - cmt, err := r.repository.GetComment(r.ctx, commentID, discussionID) - r.Error(err) - r.Empty(cmt) - }) -} - -func (r *DiscussionRepositoryTestSuite) TestUpdateComment() { - r.Run("should successfully update a comment", func() { - cmt := &discussion.Comment{ - ID: "55", - DiscussionID: "22222", - Body: "Updated Body Comment", - UpdatedBy: r.users[1], - } - err := r.repository.UpdateComment(r.ctx, cmt) - r.NoError(err) - - newCmt, err := r.repository.GetComment(r.ctx, cmt.ID, cmt.DiscussionID) - r.NoError(err) - r.Equal(newCmt.Body, cmt.Body) - r.NotEqual(newCmt.UpdatedAt, cmt.UpdatedAt) - r.Equal(newCmt.UpdatedBy.UUID, cmt.UpdatedBy.UUID) - }) - - r.Run("should return error when updating a comment that does not exist", func() { - cmt := &discussion.Comment{ - ID: "9090", - DiscussionID: "22222", - Body: "Updated Body Comment", - UpdatedBy: r.users[len(r.users)-1], - } - err := r.repository.UpdateComment(r.ctx, cmt) - r.Error(err) - }) - - r.Run("should return error when updating a comment that does not belong to a discussion", func() { - cmt := &discussion.Comment{ - ID: "55", - DiscussionID: "9090", - Body: "Updated Body Comment", - UpdatedBy: r.users[len(r.users)-1], - } - err := r.repository.UpdateComment(r.ctx, cmt) - r.Error(err) - }) - - r.Run("should return error when updating a comment with empty updated_by", func() { - cmt := &discussion.Comment{ - Body: "This is Body", - } - err := r.repository.UpdateComment(r.ctx, cmt) - r.Error(err) - }) -} - -func (r *DiscussionRepositoryTestSuite) TestDeleteComment() { - r.Run("should successfully delete a comment", func() { - commentID := "55" - discussionID := "22222" - err := r.repository.DeleteComment(r.ctx, commentID, discussionID) - r.NoError(err) - - newCmt, err := r.repository.GetComment(r.ctx, commentID, discussionID) - r.ErrorAs(err, new(discussion.NotFoundError)) - r.Empty(newCmt) - }) - - r.Run("should return error when deleting a comment that does not exist", func() { - commentID := "9090" - discussionID := "22222" - err := r.repository.DeleteComment(r.ctx, commentID, discussionID) - r.Error(err) - }) - - r.Run("should return error when deleting a comment that does not belong to a discussion", func() { - commentID := "55" - discussionID := "9090" - err := r.repository.DeleteComment(r.ctx, commentID, discussionID) - r.Error(err) - }) -} diff --git a/store/postgres/discussion_model.go b/store/postgres/discussion_model.go deleted file mode 100644 index f13e64fb..00000000 --- a/store/postgres/discussion_model.go +++ /dev/null @@ -1,56 +0,0 @@ -package postgres - -import ( - "time" - - "github.com/lib/pq" - "github.com/raystack/compass/core/discussion" -) - -type DiscussionModel struct { - ID string `db:"id"` - NamespaceID string `db:"namespace_id"` - Title string `db:"title"` - Body string `db:"body"` - Type string `db:"type"` - State string `db:"state"` - Owner UserModel `db:"owner"` - Labels pq.StringArray `db:"labels"` - Assets pq.StringArray `db:"assets"` - Assignees pq.StringArray `db:"assignees"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` -} - -func (dm DiscussionModel) toDiscussion() discussion.Discussion { - return discussion.Discussion{ - ID: dm.ID, - Title: dm.Title, - Body: dm.Body, - Type: discussion.GetTypeEnum(dm.Type), - State: discussion.GetStateEnum(dm.State), - Labels: dm.Labels, - Assets: dm.Assets, - Assignees: dm.Assignees, - Owner: dm.Owner.toUser(), - CreatedAt: dm.CreatedAt, - UpdatedAt: dm.UpdatedAt, - } -} - -func newDiscussionModel(dc *discussion.Discussion) *DiscussionModel { - um := newUserModel(&dc.Owner) - return &DiscussionModel{ - ID: dc.ID, - Title: dc.Title, - Body: dc.Body, - Type: dc.Type.String(), - State: dc.State.String(), - Owner: um, - Labels: dc.Labels, - Assets: dc.Assets, - Assignees: dc.Assignees, - CreatedAt: dc.CreatedAt, - UpdatedAt: dc.UpdatedAt, - } -} diff --git a/store/postgres/discussion_repository.go b/store/postgres/discussion_repository.go deleted file mode 100644 index fd2864d5..00000000 --- a/store/postgres/discussion_repository.go +++ /dev/null @@ -1,296 +0,0 @@ -package postgres - -import ( - "context" - "database/sql" - "errors" - "fmt" - "github.com/jmoiron/sqlx" - "github.com/raystack/compass/core/namespace" - "strings" - - sq "github.com/Masterminds/squirrel" - "github.com/raystack/compass/core/discussion" -) - -// DiscussionRepository is a type that manages discussion operation to the primary database -type DiscussionRepository struct { - client *Client - defaultGetMaxSize int -} - -// GetAll fetchs all discussion data -func (r *DiscussionRepository) GetAll(ctx context.Context, flt discussion.Filter) ([]discussion.Discussion, error) { - - builder := r.selectSQL() - builder = r.buildSelectFilterQuery(builder, flt) - builder = r.buildSelectOrderQuery(builder, flt) - builder = r.buildSelectLimitQuery(builder, flt) - query, args, err := r.buildSQL(builder) - if err != nil { - return nil, fmt.Errorf("error building query: %w", err) - } - - dms := []DiscussionModel{} - err = r.client.SelectContext(ctx, &dms, query, args...) - if err != nil { - return nil, fmt.Errorf("error getting discussion list: %w", err) - } - - discussions := []discussion.Discussion{} - for _, dm := range dms { - discussions = append(discussions, dm.toDiscussion()) - } - - return discussions, nil -} - -// Create inserts a new discussion data -func (r *DiscussionRepository) Create(ctx context.Context, ns *namespace.Namespace, dsc *discussion.Discussion) (string, error) { - dm := newDiscussionModel(dsc) - var discussionID string - query, args, err := sq.Insert("discussions"). - Columns("title", - "body", - "state", - "type", - "owner", - "labels", - "assets", - "assignees", - "namespace_id"). - Values(dm.Title, dm.Body, discussion.StateOpen, dm.Type, dm.Owner.ID, dm.Labels, dm.Assets, dm.Assignees, ns.ID). - Suffix("RETURNING \"id\""). - PlaceholderFormat(sq.Dollar). - ToSql() - if err != nil { - return "", fmt.Errorf("error building insert query: %w", err) - } - - err = r.client.QueryFn(ctx, func(conn *sqlx.Conn) error { - return conn.QueryRowxContext(ctx, query, args...).Scan(&discussionID) - }) - if err != nil { - return "", fmt.Errorf("error running insert query: %w", err) - } - - if discussionID == "" { - return "", fmt.Errorf("error discussion ID is empty from DB") - } - - return discussionID, nil -} - -// Get returns a specific discussion by id -func (r *DiscussionRepository) Get(ctx context.Context, did string) (discussion.Discussion, error) { - builder := r.selectSQL() - builder = builder.Where("d.id = ?", did).Limit(1) - query, args, err := r.buildSQL(builder) - if err != nil { - return discussion.Discussion{}, fmt.Errorf("error building query: %w", err) - } - - var discussionModel DiscussionModel - err = r.client.GetContext(ctx, &discussionModel, query, args...) - if errors.Is(err, sql.ErrNoRows) { - return discussion.Discussion{}, discussion.NotFoundError{DiscussionID: did} - } - if err != nil { - return discussion.Discussion{}, fmt.Errorf("failed fetching discussion with id %s: %w", did, err) - } - - return discussionModel.toDiscussion(), nil -} - -// Patch will update a field in discussion -func (r *DiscussionRepository) Patch(ctx context.Context, dsc *discussion.Discussion) error { - if dsc.ID == "" { - return discussion.ErrInvalidID - } - - dm := newDiscussionModel(dsc) - builder := r.patchSQL(dm) - query, args, err := r.buildSQL(builder) - if err != nil { - return fmt.Errorf("error building query: %w", err) - } - - res, err := r.client.ExecContext(ctx, query, args...) - if err != nil { - return fmt.Errorf("failed updating discussion with id %s: %w", dm.ID, err) - } - affectedRows, err := res.RowsAffected() - if err != nil { - return fmt.Errorf("error getting affected rows: %w", err) - } - if affectedRows == 0 { - return discussion.NotFoundError{DiscussionID: dm.ID} - } - - return nil -} - -func (r *DiscussionRepository) patchSQL(dm *DiscussionModel) sq.UpdateBuilder { - builder := sq.Update("discussions") - - if len(strings.TrimSpace(dm.Title)) > 0 { - builder = builder.Set("title", dm.Title) - } - - if len(strings.TrimSpace(dm.Body)) > 0 { - builder = builder.Set("body", dm.Body) - } - - if len(strings.TrimSpace(dm.Type)) > 0 { - builder = builder.Set("type", dm.Type) - } - - if len(strings.TrimSpace(dm.State)) > 0 { - builder = builder.Set("state", dm.State) - } - - if dm.Labels != nil { - if len(dm.Labels) > 0 { - builder = builder.Set("labels", dm.Labels) - } else { - builder = builder.Set("labels", nil) - } - } - - if dm.Assets != nil { - if len(dm.Assets) > 0 { - builder = builder.Set("assets", dm.Assets) - } else { - builder = builder.Set("assets", nil) - } - } - - if dm.Assignees != nil { - if len(dm.Assignees) > 0 { - builder = builder.Set("assignees", dm.Assignees) - } else { - builder = builder.Set("assignees", nil) - } - } - - return builder.Where(sq.Eq{"id": dm.ID}) -} - -func (r *DiscussionRepository) selectSQL() sq.SelectBuilder { - return sq.Select(` - d.id as id, - d.title as title, - d.body as body, - d.state as state, - d.type as type, - d.labels as labels, - d.assets as assets, - d.assignees as assignees, - d.created_at as created_at, - d.updated_at as updated_at, - u.id as "owner.id", - u.uuid as "owner.uuid", - u.email as "owner.email", - u.provider as "owner.provider", - u.created_at as "owner.created_at", - u.updated_at as "owner.updated_at" - `). - From("discussions d"). - LeftJoin("users u ON d.owner = u.id") -} - -func (r *DiscussionRepository) buildSelectFilterQuery(builder sq.SelectBuilder, flt discussion.Filter) sq.SelectBuilder { - whereClauses := sq.And{} - if len(strings.TrimSpace(flt.Type)) > 0 && flt.Type != "all" { - whereClauses = append(whereClauses, sq.Expr("type = ?", flt.Type)) - } - - if len(strings.TrimSpace(flt.State)) > 0 && flt.State != "all" { - whereClauses = append(whereClauses, sq.Expr("state = ?", flt.State)) - } - - if len(flt.Labels) > 0 { - whereClauses = append(whereClauses, sq.Expr("labels @> ?", flt.Labels)) - } - - if flt.DisjointAssigneeOwner { - if len(strings.TrimSpace(flt.Owner)) > 0 && len(flt.Assignees) > 0 { - whereClauses = append(whereClauses, - sq.Or{ - sq.Expr("owner = ?", flt.Owner), - sq.Expr("assignees @> ?", flt.Assignees), - }) - } - } else { - if len(strings.TrimSpace(flt.Owner)) > 0 { - whereClauses = append(whereClauses, sq.Expr("owner = ?", flt.Owner)) - } - - if len(flt.Assignees) > 0 { - whereClauses = append(whereClauses, sq.Expr("assignees @> ?", flt.Assignees)) - } - } - - if len(flt.Assets) > 0 { - whereClauses = append(whereClauses, sq.Expr("assets @> ?", flt.Assets)) - } - - if len(whereClauses) > 0 { - return builder.Where(whereClauses) - } - - return builder -} - -func (r *DiscussionRepository) buildSelectOrderQuery(builder sq.SelectBuilder, flt discussion.Filter) sq.SelectBuilder { - if flt.SortBy != "" { - orderDirection := "DESC" - if flt.SortDirection != "" { - orderDirection = strings.ToUpper(flt.SortDirection) - } - return builder.OrderBy(flt.SortBy + " " + orderDirection) - } - - return builder -} - -func (r *DiscussionRepository) buildSelectLimitQuery(builder sq.SelectBuilder, flt discussion.Filter) sq.SelectBuilder { - limitSize := r.defaultGetMaxSize - if flt.Size > 0 { - limitSize = flt.Size - } - - return builder. - Limit(uint64(limitSize)). - Offset(uint64(flt.Offset)) -} - -func (r *DiscussionRepository) buildSQL(builder sq.Sqlizer) (query string, args []interface{}, err error) { - query, args, err = builder.ToSql() - if err != nil { - err = fmt.Errorf("error transforming to sql") - return - } - query, err = sq.Dollar.ReplacePlaceholders(query) - if err != nil { - err = fmt.Errorf("error replacing placeholders to dollar") - return - } - - return -} - -// NewDiscussionRepository initializes discussion repository clients -func NewDiscussionRepository(c *Client, defaultGetMaxSize int) (*DiscussionRepository, error) { - if c == nil { - return nil, errors.New("postgres client is nil") - } - if defaultGetMaxSize == 0 { - defaultGetMaxSize = DefaultMaxResultSize - } - - return &DiscussionRepository{ - client: c, - defaultGetMaxSize: defaultGetMaxSize, - }, nil -} diff --git a/store/postgres/discussion_repository_test.go b/store/postgres/discussion_repository_test.go deleted file mode 100644 index ee42edf5..00000000 --- a/store/postgres/discussion_repository_test.go +++ /dev/null @@ -1,436 +0,0 @@ -package postgres_test - -import ( - "context" - "fmt" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/middleware" - "testing" - - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/discussion" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/store/postgres" - "github.com/ory/dockertest/v3" - "github.com/stretchr/testify/suite" -) - -type DiscussionRepositoryTestSuite struct { - suite.Suite - ctx context.Context - client *postgres.Client - pool *dockertest.Pool - resource *dockertest.Resource - repository *postgres.DiscussionRepository - assetRepo *postgres.AssetRepository - userRepo *postgres.UserRepository - users []user.User - assets []asset.Asset - ns *namespace.Namespace -} - -func (r *DiscussionRepositoryTestSuite) SetupSuite() { - var err error - r.ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.DedicatedState, - Metadata: nil, - } - r.ctx = middleware.BuildContextWithNamespace(context.Background(), r.ns) - - r.client, r.pool, r.resource, err = newTestClient() - if err != nil { - r.T().Fatal(err) - } - - r.userRepo, err = postgres.NewUserRepository(r.client) - if err != nil { - r.T().Fatal(err) - } - - r.ctx = context.TODO() - r.assetRepo, err = postgres.NewAssetRepository(r.client, r.userRepo, defaultGetMaxSize, defaultProviderName) - if err != nil { - r.T().Fatal(err) - } - - r.repository, err = postgres.NewDiscussionRepository(r.client, defaultGetMaxSize) - if err != nil { - r.T().Fatal(err) - } - - r.users, err = createUsers(r.userRepo, r.ns, 5) - if err != nil { - r.T().Fatal(err) - } - - r.assets, err = createAssets(r.assetRepo, r.ns, r.users, asset.Type(asset.TypeTable.String())) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *DiscussionRepositoryTestSuite) TearDownSuite() { - // Clean tests - err := r.client.Close() - if err != nil { - r.T().Fatal(err) - } - err = purgeDocker(r.pool, r.resource) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *DiscussionRepositoryTestSuite) SetupTest() { - if err := r.bootstrap(); err != nil { - r.T().Fatal(err) - } -} - -func (r *DiscussionRepositoryTestSuite) TearDownTest() { - if err := r.cleanup(); err != nil { - r.T().Fatal(err) - } -} - -func (r *DiscussionRepositoryTestSuite) bootstrap() error { - queries := []string{ - fmt.Sprintf(`insert into discussions values (11111, 'Kafka Source', 'We need to figure out how to source the new kafka', 1, 2, '%s', array['kafka','topic','question'],null,array['59bf4219-433e-4e38-ad72-ebab70c7ee7a'])`, r.users[0].ID), - fmt.Sprintf(`insert into discussions values (22222, 'Missing data point on asset 1234-5678', 'Does anyone know why do we miss datapoint on asset 1234-5678', 'open', 'qanda', '%s', array['wondering','data','datapoint','question'],array['6663c3c7-62cf-41db-b0e1-4d443525f6d4'],array['59bf4219-433e-4e38-ad72-ebab70c7ee7a','%s'])`, r.users[1].ID, r.users[0].ID), - fmt.Sprintf(`insert into discussions values (33333, 'Improve data', 'How about cleaning the data more?', 'open', 'openended', '%s', array['data','enhancement'],array['44a368e7-73df-4520-8803-3979a97f1cc3','59bf4219-433e-4e38-ad72-ebab70c7ee7a','458e8fdd-bca3-45a8-a17c-c00b2541d671'],array['ef1f0896-785a-47a0-8c9f-9897cdcf3697'])`, r.users[2].ID), - fmt.Sprintf(`insert into discussions values (44444, 'Kafka Source (duplicated)', 'We need to figure out how to source the new kafka', 'closed', 'issues', '%s', array['kafka','topic'],null,array['ef1f0896-785a-47a0-8c9f-9897cdcf3697'])`, r.users[3].ID), - fmt.Sprintf(`insert into discussions values (55555, 'Answered Questions', 'This question is answered', 'closed', 'qanda', '%s', array['question','answered'],null,null)`, r.users[4].ID), - } - - queries = append(queries, []string{ - fmt.Sprintf(`insert into comments values (11, 11111, 'This is 1st comment of discussion 11111', '%s', '%s')`, r.users[0].ID, r.users[0].ID), - fmt.Sprintf(`insert into comments values (22, 11111, 'This is 2nd comment of discussion 11111', '%s', '%s')`, r.users[1].ID, r.users[1].ID), - fmt.Sprintf(`insert into comments values (33, 22222, 'This is 1st comment of discussion 22222', '%s', '%s')`, r.users[2].ID, r.users[2].ID), - fmt.Sprintf(`insert into comments values (44, 22222, 'This is 2nd comment of discussion 22222', '%s', '%s')`, r.users[3].ID, r.users[3].ID), - fmt.Sprintf(`insert into comments values (55, 22222, 'This is 3rd comment of discussion 22222', '%s', '%s')`, r.users[0].ID, r.users[0].ID), - }...) - return r.client.ExecQueries(r.ctx, queries) -} - -func (r *DiscussionRepositoryTestSuite) cleanup() error { - queries := []string{ - "TRUNCATE TABLE discussions CASCADE", - } - return r.client.ExecQueries(r.ctx, queries) -} - -func (r *DiscussionRepositoryTestSuite) TestCreate() { - r.Run("should create a new discussion with type open ended and default state", func() { - disc := &discussion.Discussion{ - Title: "A New Discussion", - Body: "This is body", - Type: discussion.TypeOpenEnded, - Labels: []string{"label1", "label2"}, - Assets: assetsToAssetIDs(r.assets), - Assignees: usersToUserIDs(r.users)[:2], - Owner: r.users[len(r.users)-1], - } - id, err := r.repository.Create(r.ctx, r.ns, disc) - r.NoError(err) - r.NotEmpty(id) - }) - - r.Run("should create a new discussion with empty asignee and assets", func() { - disc := &discussion.Discussion{ - Title: "A New Discussion", - Body: "This is body", - Type: discussion.TypeOpenEnded, - Labels: []string{"label1", "label2"}, - Owner: r.users[len(r.users)-1], - } - id, err := r.repository.Create(r.ctx, r.ns, disc) - r.NoError(err) - r.NotEmpty(id) - }) - - r.Run("should return error when creating a new discussion with empty owner", func() { - disc := &discussion.Discussion{ - Title: "A New Discussion", - Body: "This is body", - Type: discussion.TypeOpenEnded, - Labels: []string{"label1", "label2"}, - } - id, err := r.repository.Create(r.ctx, r.ns, disc) - r.Error(err) - r.Empty(id) - }) -} - -func (r *DiscussionRepositoryTestSuite) TestGetAll() { - r.Run("should return list of discussions if filter is valid", func() { - testCases := []struct { - description string - filter discussion.Filter - resultLength int - validateResult func(r *DiscussionRepositoryTestSuite, results []discussion.Discussion) - }{ - { - description: "should successfully fetch all discussions", - filter: discussion.Filter{}, - resultLength: 5, - }, - { - description: "should successfully fetch all discussions with all filters", - filter: discussion.Filter{Type: "all", State: "all"}, - resultLength: 5, - }, - { - description: "should successfully fetch all discussions with assignee user 0 or owner user 0", - filter: discussion.Filter{Assignees: []string{r.users[0].ID}, Owner: r.users[0].ID, DisjointAssigneeOwner: true}, - resultLength: 2, - }, - { - description: "should limit with size", - filter: discussion.Filter{ - Size: 1, - }, - resultLength: 1, - }, - { - description: "should get all q&a type", - filter: discussion.Filter{ - Type: discussion.TypeQAndA.String(), - }, - resultLength: 2, - }, - { - description: "should only get closed q&a type", - filter: discussion.Filter{ - Type: discussion.TypeQAndA.String(), - State: discussion.StateClosed.String(), - }, - resultLength: 1, - validateResult: func(r *DiscussionRepositoryTestSuite, results []discussion.Discussion) { - r.Equal(results[0].Title, "Answered Questions") - }, - }, - { - description: "should get all discussions with label `question` and `data`", - filter: discussion.Filter{ - Labels: []string{"question", "data"}, - }, - resultLength: 1, - validateResult: func(r *DiscussionRepositoryTestSuite, results []discussion.Discussion) { - r.Equal(results[0].ID, "22222") - }, - }, - { - description: "should get all discussions with a specific assignee", - filter: discussion.Filter{ - Assignees: []string{"ef1f0896-785a-47a0-8c9f-9897cdcf3697"}, - }, - resultLength: 2, - }, - { - description: "should get all discussions ascendingly sorted by created_at", - filter: discussion.Filter{ - SortBy: "created_at", - SortDirection: "asc", - }, - resultLength: 5, - validateResult: func(r *DiscussionRepositoryTestSuite, results []discussion.Discussion) { - r.Equal(results[0].ID, "11111") - r.Equal(results[1].ID, "22222") - r.Equal(results[2].ID, "33333") - r.Equal(results[3].ID, "44444") - r.Equal(results[4].ID, "55555") - }, - }, - { - description: "should get all discussions with a specific assetid", - filter: discussion.Filter{ - Assets: []string{"6663c3c7-62cf-41db-b0e1-4d443525f6d4"}, - }, - resultLength: 1, - validateResult: func(r *DiscussionRepositoryTestSuite, results []discussion.Discussion) { - r.Equal(results[0].ID, "22222") - }, - }, - { - description: "should get all discussions with a specific owner", - filter: discussion.Filter{ - Owner: r.users[4].ID, - }, - resultLength: 1, - validateResult: func(r *DiscussionRepositoryTestSuite, results []discussion.Discussion) { - r.Equal(results[0].Owner.ID, r.users[4].ID) - }, - }, - { - description: "should get all discussions with all filter populated", - filter: discussion.Filter{ - Type: discussion.TypeQAndA.String(), - State: discussion.StateOpen.String(), - Labels: []string{"wondering"}, - Assignees: []string{"59bf4219-433e-4e38-ad72-ebab70c7ee7a"}, - Assets: []string{"6663c3c7-62cf-41db-b0e1-4d443525f6d4"}, - Owner: r.users[1].ID, - }, - resultLength: 1, - validateResult: func(r *DiscussionRepositoryTestSuite, results []discussion.Discussion) { - r.Equal(results[0].Owner.ID, r.users[1].ID) - }, - }, - } - - for _, testCase := range testCases { - r.Run(testCase.description, func() { - dscs, err := r.repository.GetAll(r.ctx, testCase.filter) - r.NoError(err) - r.Len(dscs, testCase.resultLength) - - if testCase.validateResult != nil { - testCase.validateResult(r, dscs) - } - }) - } - }) -} - -func (r *DiscussionRepositoryTestSuite) TestGet() { - testCases := []struct { - description string - id string - validateResult func(r *DiscussionRepositoryTestSuite, result discussion.Discussion, err error) - }{ - { - description: "should successfully fetch all discussions", - id: "777", - validateResult: func(r *DiscussionRepositoryTestSuite, result discussion.Discussion, err error) { - r.ErrorAs(err, new(discussion.NotFoundError)) - r.Empty(result) - }, - }, - { - description: "should return error if id is not serial", - id: "some-id", - validateResult: func(r *DiscussionRepositoryTestSuite, result discussion.Discussion, err error) { - r.Error(err) - r.Empty(result) - }, - }, - { - description: "should return discussion with a specific id", - id: "11111", - validateResult: func(r *DiscussionRepositoryTestSuite, result discussion.Discussion, err error) { - r.NoError(err) - r.Equal(result.ID, "11111") - }, - }, - { - description: "should return not found if id not found", - id: "99999", - validateResult: func(r *DiscussionRepositoryTestSuite, result discussion.Discussion, err error) { - r.Error(discussion.NotFoundError{DiscussionID: "99999"}) - r.Empty(result) - }, - }, - } - - for _, testCase := range testCases { - r.Run(testCase.description, func() { - dsc, err := r.repository.Get(r.ctx, testCase.id) - testCase.validateResult(r, dsc, err) - }) - } - - r.Run("discussion with deleted owner information would return empty owner", func() { - queries := []string{ - `insert into discussions values (123, 'discussion with deleted user', 'discussion with deleted user', 1, 2, '59bf4219-433e-4e38-ad72-ebab70c7ee7a', array['kafka','topic','question'],null,array['59bf4219-433e-4e38-ad72-ebab70c7ee7a'])`, - } - err := r.client.ExecQueries(r.ctx, queries) - r.NoError(err) - dsc, err := r.repository.Get(r.ctx, "123") - r.NoError(err) - r.Empty(dsc.Owner) - }) -} - -func (r *DiscussionRepositoryTestSuite) TestPatch() { - testCases := []struct { - description string - disc *discussion.Discussion - err error - validateResult func(r *DiscussionRepositoryTestSuite, result discussion.Discussion) - }{ - { - description: "should successfully patch title and body", - disc: &discussion.Discussion{ID: "11111", Title: "patched title", Body: "patched body"}, - err: nil, - validateResult: func(r *DiscussionRepositoryTestSuite, result discussion.Discussion) { - r.Equal("patched title", result.Title) - r.Equal("patched body", result.Body) - }, - }, - { - description: "should successfully patch assignees", - disc: &discussion.Discussion{ID: "11111", Assignees: []string{"a", "b", "c"}}, - err: nil, - validateResult: func(r *DiscussionRepositoryTestSuite, result discussion.Discussion) { - r.Equal([]string{"a", "b", "c"}, result.Assignees) - }, - }, - { - description: "should successfully patch assets", - disc: &discussion.Discussion{ID: "11111", Assets: []string{"d", "e", "f"}}, - err: nil, - validateResult: func(r *DiscussionRepositoryTestSuite, result discussion.Discussion) { - r.Equal([]string{"d", "e", "f"}, result.Assets) - }, - }, - { - description: "should successfully patch assets empty", - disc: &discussion.Discussion{ID: "11111", Assets: []string{}}, - err: nil, - validateResult: func(r *DiscussionRepositoryTestSuite, result discussion.Discussion) { - r.Equal([]string(nil), result.Assets) - }, - }, - { - description: "should successfully patch labels empty", - disc: &discussion.Discussion{ID: "11111", Labels: []string{}}, - err: nil, - validateResult: func(r *DiscussionRepositoryTestSuite, result discussion.Discussion) { - r.Equal([]string(nil), result.Labels) - }, - }, - { - description: "should successfully patch assignees empty", - disc: &discussion.Discussion{ID: "11111", Assignees: []string{}}, - err: nil, - validateResult: func(r *DiscussionRepositoryTestSuite, result discussion.Discussion) { - r.Equal([]string(nil), result.Assignees) - }, - }, { - description: "should return error if discussion id does not exist", - disc: &discussion.Discussion{ID: "999", Assignees: []string{}}, - err: discussion.NotFoundError{DiscussionID: "999"}, - validateResult: func(r *DiscussionRepositoryTestSuite, result discussion.Discussion) { - r.Empty(result) - }, - }, - } - - for _, testCase := range testCases { - r.Run(testCase.description, func() { - err := r.repository.Patch(r.ctx, testCase.disc) - r.Equal(testCase.err, err) - - dsc, err := r.repository.Get(r.ctx, testCase.disc.ID) - r.Equal(err, testCase.err) - testCase.validateResult(r, dsc) - }) - } -} - -func TestDiscussionRepository(t *testing.T) { - suite.Run(t, &DiscussionRepositoryTestSuite{}) -} diff --git a/store/postgres/jsonmap.go b/store/postgres/jsonmap.go new file mode 100644 index 00000000..cdf02400 --- /dev/null +++ b/store/postgres/jsonmap.go @@ -0,0 +1,54 @@ +package postgres + +import ( + "database/sql/driver" + "encoding/json" + "errors" + "fmt" +) + +// JSONMap is a map[string]interface{} that implements sql.Scanner and driver.Valuer for JSONB columns. +type JSONMap map[string]interface{} + +func (m JSONMap) Value() (driver.Value, error) { + if m == nil { + return nil, nil + } + ba, err := m.MarshalJSON() + return string(ba), err +} + +func (m *JSONMap) Scan(value interface{}) error { + if value == nil { + *m = nil + return nil + } + var ba []byte + switch v := value.(type) { + case []byte: + ba = v + case string: + ba = []byte(v) + default: + return errors.New(fmt.Sprint("failed to unmarshal JSONB value:", value)) + } + t := map[string]interface{}{} + err := json.Unmarshal(ba, &t) + *m = JSONMap(t) + return err +} + +func (m JSONMap) MarshalJSON() ([]byte, error) { + if m == nil { + return []byte("null"), nil + } + t := (map[string]interface{})(m) + return json.Marshal(t) +} + +func (m *JSONMap) UnmarshalJSON(b []byte) error { + t := map[string]interface{}{} + err := json.Unmarshal(b, &t) + *m = JSONMap(t) + return err +} diff --git a/store/postgres/lineage_model.go b/store/postgres/lineage_model.go deleted file mode 100644 index 6a5d3460..00000000 --- a/store/postgres/lineage_model.go +++ /dev/null @@ -1,33 +0,0 @@ -package postgres - -import ( - "github.com/raystack/compass/core/asset" -) - -type LineageGraphModel []LineageEdgeModel - -func (gm LineageGraphModel) toGraph() asset.LineageGraph { - graph := asset.LineageGraph{} - for _, em := range gm { - graph = append(graph, em.toEdge()) - } - - return graph -} - -type LineageEdgeModel struct { - NamespaceID string `db:"namespace_id"` - Source string `db:"source"` - Target string `db:"target"` - Prop JSONMap `db:"prop"` -} - -func (m LineageEdgeModel) toEdge() asset.LineageEdge { - edge := asset.LineageEdge{ - Source: m.Source, - Target: m.Target, - Prop: m.Prop, - } - - return edge -} diff --git a/store/postgres/lineage_repository.go b/store/postgres/lineage_repository.go deleted file mode 100644 index c33dd6e6..00000000 --- a/store/postgres/lineage_repository.go +++ /dev/null @@ -1,384 +0,0 @@ -package postgres - -import ( - "context" - "errors" - "fmt" - "github.com/raystack/compass/core/namespace" - "strings" - - sq "github.com/Masterminds/squirrel" - "github.com/jmoiron/sqlx" - "github.com/raystack/compass/core/asset" -) - -type LineageRepository struct { - client *Client -} - -// NewLineageRepository initializes lineage repository -func NewLineageRepository(client *Client) (*LineageRepository, error) { - if client == nil { - return nil, errors.New("postgres client is nil") - } - return &LineageRepository{ - client: client, - }, nil -} - -// GetGraph returns a graph that contains list of relations of a given node -func (repo *LineageRepository) GetGraph(ctx context.Context, urn string, query asset.LineageQuery) (asset.LineageGraph, error) { - var graph asset.LineageGraph - - if query.Direction == "" || query.Direction == asset.LineageDirectionUpstream { - upstreams, err := repo.getUpstreamsGraph(ctx, urn, query.Level) - if err != nil { - return graph, fmt.Errorf("error fetching upstreams graph: %w", err) - } - graph = append(graph, upstreams...) - } - - if query.Direction == "" || query.Direction == asset.LineageDirectionDownstream { - downstreams, err := repo.getDownstreamsGraph(ctx, urn, query.Level) - if err != nil { - return graph, fmt.Errorf("error fetching upstreams graph: %w", err) - } - graph = append(graph, downstreams...) - } - - return graph, nil -} - -func (repo *LineageRepository) DeleteByURN(ctx context.Context, urn string) error { - - deleteQuery, _, err := sq.Delete("lineage_graph").Where( - fmt.Sprintf("source='%s' or target='%s'", urn, urn)).ToSql() - - if err != nil { - return fmt.Errorf("error building delete query when deleting asset with URN = %q: %w", urn, err) - } - - res, err := repo.client.ExecContext(ctx, deleteQuery) - if err != nil { - return fmt.Errorf("error deleting asset with URN = %q: %w", urn, err) - } - affectedRows, err := res.RowsAffected() - - if err != nil { - return fmt.Errorf("error getting affected rows: %w", err) - } - if affectedRows == 0 { - return asset.LineageNotFoundError{URN: urn} - } - return nil -} - -// DeleteByURNs removes lineage edges for multiple URNs -func (repo *LineageRepository) DeleteByURNs(ctx context.Context, urns []string) error { - if len(urns) == 0 { - return nil - } - - orClauses := make([]string, 0, len(urns)) - for _, urn := range urns { - orClauses = append(orClauses, fmt.Sprintf("source='%s' or target='%s'", urn, urn)) - } - whereClause := strings.Join(orClauses, " or ") - - deleteQuery, _, err := sq.Delete("lineage_graph").Where(whereClause).ToSql() - if err != nil { - return fmt.Errorf("error building delete query: %w", err) - } - - _, err = repo.client.ExecContext(ctx, deleteQuery) - if err != nil { - return fmt.Errorf("error deleting lineage by URNs: %w", err) - } - - return nil -} - -// Upsert insert or delete connections of a given node by comparing them with current state -func (repo *LineageRepository) Upsert(ctx context.Context, ns *namespace.Namespace, urn string, upstreams, downstreams []string) error { - currentGraph, err := repo.getDirectLineage(ctx, urn) - if err != nil { - return fmt.Errorf("error getting node's direct lineage: %w", err) - } - newGraph := repo.buildGraph(urn, upstreams, downstreams) - toInserts, toRemoves := repo.compareGraph(currentGraph, newGraph) - toRemoves = repo.filterSelfDeleteOnly(urn, toRemoves) - - return repo.client.RunWithinTx(ctx, func(tx *sqlx.Tx) error { - err := repo.insertGraph(ctx, tx, ns, toInserts) - if err != nil { - return fmt.Errorf("error inserting graph: %w", err) - } - - err = repo.removeGraph(ctx, tx, toRemoves) - if err != nil { - return fmt.Errorf("error removing graph: %w", err) - } - - return nil - }) -} - -func (repo *LineageRepository) buildGraph(urn string, upstreams, downstreams []string) (graph asset.LineageGraph) { - for _, us := range upstreams { - graph = append(graph, asset.LineageEdge{ - Source: us, - Target: urn, - Prop: map[string]interface{}{ - "root": urn, // this is to note which node is updating the relation - }, - }) - } - for _, ds := range downstreams { - graph = append(graph, asset.LineageEdge{ - Source: urn, - Target: ds, - Prop: map[string]interface{}{ - "root": urn, // this is to note which node is updating the relation - }, - }) - } - - return -} - -// filterSelfDeleteOnly filters edges that are not created by the given node -// it uses prop["root"] field to figure out which node (source or target) is latest updater of the edge, -// and only allow that node to delete the relation -func (repo *LineageRepository) filterSelfDeleteOnly(urn string, toRemoves asset.LineageGraph) (res asset.LineageGraph) { - for _, edge := range toRemoves { - rootURN, ok := edge.Prop["root"] - if ok && rootURN != urn { - continue - } - res = append(res, edge) - } - - return -} - -func (repo *LineageRepository) insertGraph(ctx context.Context, execer sqlx.ExecerContext, ns *namespace.Namespace, graph asset.LineageGraph) error { - if len(graph) == 0 { - return nil - } - - builder := sq.Insert("lineage_graph").Columns("source", "target", "prop", "namespace_id").PlaceholderFormat(sq.Dollar) - for _, edge := range graph { - builder = builder.Values(edge.Source, edge.Target, edge.Prop, ns.ID) - } - builder = builder.Suffix("ON CONFLICT DO NOTHING") - - sql, args, err := builder.ToSql() - if err != nil { - return fmt.Errorf("error building query: %w", err) - } - - _, err = execer.ExecContext(ctx, sql, args...) - if err != nil { - return fmt.Errorf("error executing insert query: %w", err) - } - - return nil -} - -func (repo *LineageRepository) removeGraph(ctx context.Context, execer sqlx.ExecerContext, graph asset.LineageGraph) error { - if len(graph) == 0 { - return nil - } - - builder := sq.Delete("lineage_graph").PlaceholderFormat(sq.Dollar) - conditions := sq.Or{} - for _, edge := range graph { - conditions = append(conditions, - sq.Eq{"source": edge.Source, "target": edge.Target}, - ) - } - builder = builder.Where(conditions) - - sql, args, err := builder.ToSql() - if err != nil { - return fmt.Errorf("error building query: %w", err) - } - _, err = execer.ExecContext(ctx, sql, args...) - if err != nil { - return fmt.Errorf("error executing query: %w", err) - } - - return nil -} - -func (repo *LineageRepository) compareGraph(current, new asset.LineageGraph) (toInserts, toRemoves asset.LineageGraph) { - if len(current) == 0 && len(new) == 0 { - return - } - - currMap := map[string]asset.LineageEdge{} - for _, c := range current { - key := c.Source + c.Target - currMap[key] = c - } - - for _, n := range new { - key := n.Source + n.Target - _, exists := currMap[key] - if exists { - // if exists, it means that both new and current have it. - // we remove it from the map, - // so that what's left in the map is the that only exists in current - // and have to be removed - delete(currMap, key) - } else { - toInserts = append(toInserts, n) - } - } - - for _, edge := range currMap { - toRemoves = append(toRemoves, edge) - } - - return -} - -func (repo *LineageRepository) getUpstreamsGraph(ctx context.Context, urn string, level int) (asset.LineageGraph, error) { - var graph asset.LineageGraph - - query, args, err := repo.buildUpstreamQuery(urn, level) - if err != nil { - return graph, fmt.Errorf("error building upstream query: %w", err) - } - - var gm LineageGraphModel - err = repo.client.SelectContext(ctx, &gm, query, args...) - if err != nil { - return graph, fmt.Errorf("error running upstream query: %w", err) - } - - graph = gm.toGraph() - - return graph, nil -} - -func (repo *LineageRepository) getDownstreamsGraph(ctx context.Context, urn string, level int) (asset.LineageGraph, error) { - var graph asset.LineageGraph - - query, args, err := repo.buildDownstreamQuery(urn, level) - if err != nil { - return graph, fmt.Errorf("error building downstream query: %w", err) - } - - var gm LineageGraphModel - err = repo.client.SelectContext(ctx, &gm, query, args...) - if err != nil { - return graph, fmt.Errorf("error running downstream query: %w", err) - } - - graph = gm.toGraph() - - return graph, nil -} - -func (repo *LineageRepository) buildUpstreamQuery(urn string, level int) (query string, args []interface{}, err error) { - alias := "search_graph" - nonRecursiveBuilder := sq. - Select("source", "target", "prop", "1 as depth", "ARRAY[target] as path"). - From("lineage_graph"). - Where("target = ?", urn) - recursiveBuilder := sq. - Select("lg.source", "lg.target", "lg.prop", "sg.depth + 1", "sg.path || lg.target"). - From(fmt.Sprintf("lineage_graph lg, %s sg", alias)). - Where("lg.target <> ALL(sg.path)"). - Where("lg.target = sg.source") - if level > 0 { - recursiveBuilder = recursiveBuilder.Where("sg.depth < ?", level) - } - - return repo.buildRecursiveQuery(alias, nonRecursiveBuilder, recursiveBuilder) -} - -func (repo *LineageRepository) buildDownstreamQuery(urn string, level int) (query string, args []interface{}, err error) { - alias := "search_graph" - nonRecursiveBuilder := sq. - Select("source", "target", "prop", "1 as depth", "ARRAY[source] as path"). - From("lineage_graph"). - Where("source = ?", urn) - recursiveBuilder := sq. - Select("lg.source", "lg.target", "lg.prop", "sg.depth + 1", "sg.path || lg.source"). - From(fmt.Sprintf("lineage_graph lg, %s sg", alias)). - Where("lg.source <> ALL(sg.path)"). - Where("lg.source = sg.target") - if level > 0 { - recursiveBuilder = recursiveBuilder.Where("sg.depth < ?", level) - } - - return repo.buildRecursiveQuery(alias, nonRecursiveBuilder, recursiveBuilder) -} - -func (repo *LineageRepository) buildRecursiveQuery(alias string, nonRecursiveBuilder, recursiveBuilder sq.SelectBuilder) (query string, args []interface{}, err error) { - - cteBuilder := recursiveCTEBuilder{ - alias: alias, - columns: []string{"source", "target", "prop", "depth", "path"}, - nonRecursiveBuilder: nonRecursiveBuilder, - recursiveBuilder: recursiveBuilder, - } - cteQuery, cteArgs, err := cteBuilder.toSql() - if err != nil { - err = fmt.Errorf("error building recursive cte: %w", err) - return - } - - query, args, err = sq. - Select("source", "target", "prop"). - From(alias). - Prefix(cteQuery). - PlaceholderFormat(sq.Dollar). - ToSql() - if err != nil { - err = fmt.Errorf("error building final recursive query: %w", err) - return - } - - args = append(cteArgs, args...) - return -} - -func (repo *LineageRepository) getDirectLineage(ctx context.Context, urn string) (graph asset.LineageGraph, err error) { - query := `SELECT * FROM lineage_graph WHERE (source = $1 OR target = $1)` - var gm LineageGraphModel - if err = repo.client.SelectContext(ctx, &gm, query, urn); err != nil { - err = fmt.Errorf("error running fetch direct nodes query: %w", err) - return - } - - graph = gm.toGraph() - - return -} - -type recursiveCTEBuilder struct { - alias string - columns []string - nonRecursiveBuilder sq.SelectBuilder - recursiveBuilder sq.SelectBuilder -} - -func (b *recursiveCTEBuilder) toSql() (query string, args []interface{}, err error) { - query, args, err = b.nonRecursiveBuilder. - Suffix("UNION ALL"). - SuffixExpr(b.recursiveBuilder). - PlaceholderFormat(sq.Dollar). - ToSql() - - cols := strings.Join(b.columns, ", ") - query = fmt.Sprintf(` - WITH RECURSIVE %s ( - %s - ) AS (%s)`, - b.alias, cols, query) - - return -} diff --git a/store/postgres/lineage_repository_test.go b/store/postgres/lineage_repository_test.go deleted file mode 100644 index 883460ca..00000000 --- a/store/postgres/lineage_repository_test.go +++ /dev/null @@ -1,196 +0,0 @@ -package postgres_test - -import ( - "context" - "fmt" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/middleware" - "testing" - - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/store/postgres" - "github.com/ory/dockertest/v3" - "github.com/stretchr/testify/suite" -) - -type LineageRepositoryTestSuite struct { - suite.Suite - ctx context.Context - client *postgres.Client - pool *dockertest.Pool - resource *dockertest.Resource - repository *postgres.LineageRepository - ns *namespace.Namespace -} - -func (r *LineageRepositoryTestSuite) SetupSuite() { - var err error - - r.client, r.pool, r.resource, err = newTestClient() - if err != nil { - r.T().Fatal(err) - } - - r.ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - r.ctx = middleware.BuildContextWithNamespace(context.Background(), r.ns) - - r.repository, err = postgres.NewLineageRepository(r.client) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *LineageRepositoryTestSuite) TearDownSuite() { - // Clean tests - err := r.client.Close() - if err != nil { - r.T().Fatal(err) - } - err = purgeDocker(r.pool, r.resource) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *LineageRepositoryTestSuite) TestGetGraph() { - rootNode := "test-get-graph-root-node" - - // populate root node - // Graph: - // - // table-50 metabase-tgg-51 - // > optimus-tgg-1 > rootNode > metabase-tgg-99 > - // table-51 metabase-tgg-52 - // - err := r.repository.Upsert(r.ctx, r.ns, rootNode, []string{"optimus-tgg-1"}, []string{"metabase-tgg-99"}) - r.Require().NoError(err) - // populate upstream's node - err = r.repository.Upsert(r.ctx, r.ns, "optimus-tgg-1", []string{"table-50", "table-51"}, nil) - r.Require().NoError(err) - // populate downstream's node - err = r.repository.Upsert(r.ctx, r.ns, "metabase-tgg-99", nil, []string{"metabase-tgg-51", "metabase-tgg-52"}) - r.Require().NoError(err) - - r.Run("should recursively fetch all graph", func() { - expected := asset.LineageGraph{ - {Source: "optimus-tgg-1", Target: rootNode}, - {Source: "table-50", Target: "optimus-tgg-1"}, - {Source: "table-51", Target: "optimus-tgg-1"}, - {Source: rootNode, Target: "metabase-tgg-99"}, - {Source: "metabase-tgg-99", Target: "metabase-tgg-51"}, - {Source: "metabase-tgg-99", Target: "metabase-tgg-52"}, - } - - graph, err := r.repository.GetGraph(r.ctx, rootNode, asset.LineageQuery{}) - r.Require().NoError(err) - r.compareGraphs(expected, graph) - }) - - r.Run("should fetch based on the level given in config if any", func() { - expected := asset.LineageGraph{ - {Source: "optimus-tgg-1", Target: rootNode}, - {Source: rootNode, Target: "metabase-tgg-99"}, - } - - graph, err := r.repository.GetGraph(r.ctx, rootNode, asset.LineageQuery{ - Level: 1, - }) - r.Require().NoError(err) - r.compareGraphs(expected, graph) - }) - - r.Run("should fetch based on the direction given in config if any", func() { - expected := asset.LineageGraph{ - {Source: rootNode, Target: "metabase-tgg-99"}, - {Source: "metabase-tgg-99", Target: "metabase-tgg-51"}, - {Source: "metabase-tgg-99", Target: "metabase-tgg-52"}, - } - - graph, err := r.repository.GetGraph(r.ctx, rootNode, asset.LineageQuery{ - Direction: asset.LineageDirectionDownstream, - }) - r.Require().NoError(err) - r.compareGraphs(expected, graph) - }) -} - -func (r *LineageRepositoryTestSuite) TestUpsert() { - r.Run("should insert all as graph if upstreams and downstreams are new", func() { - nodeURN := "table-1" - upstreams := []string{"job-1"} - downstreams := []string{"dashboard-1", "dashboard-2"} - err := r.repository.Upsert(r.ctx, r.ns, nodeURN, upstreams, downstreams) - r.NoError(err) - - graph, err := r.repository.GetGraph(r.ctx, nodeURN, asset.LineageQuery{}) - r.Require().NoError(err) - r.compareGraphs(asset.LineageGraph{ - {Source: "job-1", Target: nodeURN}, - {Source: nodeURN, Target: "dashboard-1"}, - {Source: nodeURN, Target: "dashboard-2"}, - }, graph) - }) - - r.Run("should insert or delete graph when updating existing graph", func() { - nodeURN := "update-table" - - // create initial - err := r.repository.Upsert(r.ctx, r.ns, nodeURN, []string{"job-99"}, []string{"dashboard-99"}) - r.NoError(err) - - // update - err = r.repository.Upsert(r.ctx, r.ns, nodeURN, []string{"job-99", "job-100"}, []string{"dashboard-93"}) - r.NoError(err) - - graph, err := r.repository.GetGraph(r.ctx, nodeURN, asset.LineageQuery{}) - r.Require().NoError(err) - r.compareGraphs(asset.LineageGraph{ - {Source: "job-99", Target: nodeURN}, - {Source: "job-100", Target: nodeURN}, - {Source: nodeURN, Target: "dashboard-93"}, - }, graph) - }) -} - -func (r *LineageRepositoryTestSuite) TestDeleteByURN() { - r.Run("should delete asset from lineage", func() { - nodeURN := "table-1" - - // create initial - err := r.repository.Upsert(r.ctx, r.ns, nodeURN, []string{"table-2"}, []string{"table-3"}) - r.NoError(err) - - err = r.repository.DeleteByURN(r.ctx, nodeURN) - r.NoError(err) - - graph, err := r.repository.GetGraph(r.ctx, nodeURN, asset.LineageQuery{}) - r.Require().NoError(err) - r.compareGraphs(asset.LineageGraph{}, graph) - }) - - r.Run("delete when URN has no lineage", func() { - nodeURN := "table-1" - err := r.repository.DeleteByURN(r.ctx, nodeURN) - r.Equal(asset.LineageNotFoundError{URN: nodeURN}.Error(), err.Error()) - }) -} - -func (r *LineageRepositoryTestSuite) compareGraphs(expected, actual asset.LineageGraph) { - expLen := len(expected) - r.Require().Len(actual, expLen) - - for i := 0; i < expLen; i++ { - r.Equal(expected[i].Source, actual[i].Source, fmt.Sprintf("different source on index %d", i)) - r.Equal(expected[i].Target, actual[i].Target, fmt.Sprintf("different target on index %d", i)) - } -} - -func TestLineageRepository(t *testing.T) { - suite.Run(t, &LineageRepositoryTestSuite{}) -} diff --git a/store/postgres/migrations/000001_create_tags_templates_fields_table.down.sql b/store/postgres/migrations/000001_create_tags_templates_fields_table.down.sql deleted file mode 100644 index d5c42068..00000000 --- a/store/postgres/migrations/000001_create_tags_templates_fields_table.down.sql +++ /dev/null @@ -1,9 +0,0 @@ -BEGIN; - -DROP TABLE IF EXISTS tags; - -DROP TABLE IF EXISTS tag_template_fields; - -DROP TABLE IF EXISTS tag_templates; - -COMMIT; \ No newline at end of file diff --git a/store/postgres/migrations/000001_create_tags_templates_fields_table.up.sql b/store/postgres/migrations/000001_create_tags_templates_fields_table.up.sql deleted file mode 100644 index c12351d2..00000000 --- a/store/postgres/migrations/000001_create_tags_templates_fields_table.up.sql +++ /dev/null @@ -1,38 +0,0 @@ -BEGIN; - -CREATE TABLE tag_templates ( - urn text PRIMARY KEY, - display_name text NOT NULL, - description text NOT NULL, - created_at timestamp DEFAULT NOW(), - updated_at timestamp DEFAULT NOW() -); - -CREATE TABLE tag_template_fields ( - id bigserial PRIMARY KEY, - urn text NOT NULL, - display_name text NOT NULL, - description text NOT NULL, - data_type text NOT NULL, - options text, - required boolean NOT NULL, - template_urn text NOT NULL REFERENCES tag_templates(urn) ON DELETE CASCADE, - created_at timestamp DEFAULT NOW(), - updated_at timestamp DEFAULT NOW() -); - -CREATE UNIQUE INDEX tag_template_fields_idx_urn_template_urn ON tag_template_fields(urn,template_urn); - -CREATE TABLE tags ( - id bigserial PRIMARY KEY, - value text NOT NULL, - record_urn text NOT NULL, - record_type text NOT NULL, - field_id bigint NOT NULL REFERENCES tag_template_fields(id) ON DELETE CASCADE, - created_at timestamp DEFAULT NOW(), - updated_at timestamp DEFAULT NOW() -); - -CREATE UNIQUE INDEX tags_idx_record_urn_record_type_field_id ON tags(record_urn,record_type,field_id); - -COMMIT; \ No newline at end of file diff --git a/store/postgres/migrations/000001_init_schema.down.sql b/store/postgres/migrations/000001_init_schema.down.sql new file mode 100644 index 00000000..7ed2b19c --- /dev/null +++ b/store/postgres/migrations/000001_init_schema.down.sql @@ -0,0 +1,6 @@ +DROP TABLE IF EXISTS stars CASCADE; +DROP TABLE IF EXISTS chunks CASCADE; +DROP TABLE IF EXISTS edges CASCADE; +DROP TABLE IF EXISTS entities CASCADE; +DROP TABLE IF EXISTS users CASCADE; +DROP TABLE IF EXISTS namespaces CASCADE; diff --git a/store/postgres/migrations/000001_init_schema.up.sql b/store/postgres/migrations/000001_init_schema.up.sql new file mode 100644 index 00000000..5af614c2 --- /dev/null +++ b/store/postgres/migrations/000001_init_schema.up.sql @@ -0,0 +1,154 @@ +-- Compass v2: Fresh schema +-- All search is Postgres-native: tsvector + pg_trgm + pgvector. + +CREATE EXTENSION IF NOT EXISTS vector; +CREATE EXTENSION IF NOT EXISTS pg_trgm; + +-- ============================================================ +-- Namespaces (multi-tenancy root) +-- ============================================================ + +CREATE TABLE namespaces ( + id uuid DEFAULT gen_random_uuid() PRIMARY KEY, + name text NOT NULL UNIQUE, + state text, + metadata jsonb, + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now(), + deleted_at timestamptz +); + +-- ============================================================ +-- Users +-- ============================================================ + +CREATE TABLE users ( + id uuid DEFAULT gen_random_uuid() PRIMARY KEY, + namespace_id uuid NOT NULL REFERENCES namespaces(id), + uuid text, + email text, + provider text, + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now() +); + +CREATE UNIQUE INDEX idx_users_uuid ON users(uuid) WHERE uuid IS NOT NULL AND uuid != ''; +CREATE UNIQUE INDEX idx_users_email ON users(email) WHERE email IS NOT NULL AND email != ''; +CREATE INDEX idx_users_namespace ON users(namespace_id); + +-- ============================================================ +-- Entities (core knowledge layer) +-- ============================================================ + +CREATE TABLE entities ( + id uuid DEFAULT gen_random_uuid() PRIMARY KEY, + namespace_id uuid NOT NULL REFERENCES namespaces(id), + urn text NOT NULL, + type text NOT NULL, + name text NOT NULL, + description text, + properties jsonb DEFAULT '{}', + source text, + valid_from timestamptz DEFAULT now(), + valid_to timestamptz, + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now(), + + search_vector tsvector GENERATED ALWAYS AS ( + setweight(to_tsvector('english', coalesce(urn, '')), 'A') || + setweight(to_tsvector('english', coalesce(name, '')), 'A') || + setweight(to_tsvector('english', coalesce(description, '')), 'B') || + setweight(to_tsvector('english', coalesce(source, '')), 'C') + ) STORED, + + UNIQUE (namespace_id, urn, valid_from) +); + +CREATE INDEX idx_entities_ns_urn ON entities(namespace_id, urn); +CREATE INDEX idx_entities_type ON entities(type); +CREATE INDEX idx_entities_current ON entities(valid_to) WHERE valid_to IS NULL; +CREATE INDEX idx_entities_properties ON entities USING GIN(properties); +CREATE INDEX idx_entities_source ON entities(source); +CREATE INDEX idx_entities_search ON entities USING GIN(search_vector); +CREATE INDEX idx_entities_name_trgm ON entities USING GIN(name gin_trgm_ops); +CREATE INDEX idx_entities_urn_trgm ON entities USING GIN(urn gin_trgm_ops); + +-- ============================================================ +-- Edges (typed, temporal relationships between entities) +-- ============================================================ + +CREATE TABLE edges ( + id uuid DEFAULT gen_random_uuid() PRIMARY KEY, + namespace_id uuid NOT NULL REFERENCES namespaces(id), + source_urn text NOT NULL, + target_urn text NOT NULL, + type text NOT NULL, + properties jsonb DEFAULT '{}', + valid_from timestamptz DEFAULT now(), + valid_to timestamptz, + source text, + created_at timestamptz DEFAULT now(), + + UNIQUE (namespace_id, source_urn, target_urn, type, valid_from) +); + +CREATE INDEX idx_edges_source_urn ON edges(namespace_id, source_urn); +CREATE INDEX idx_edges_target_urn ON edges(namespace_id, target_urn); +CREATE INDEX idx_edges_type ON edges(type); +CREATE INDEX idx_edges_current ON edges(valid_to) WHERE valid_to IS NULL; + +-- ============================================================ +-- Chunks (vector embeddings for semantic search) +-- ============================================================ + +CREATE TABLE chunks ( + id uuid DEFAULT gen_random_uuid() PRIMARY KEY, + namespace_id uuid NOT NULL REFERENCES namespaces(id), + entity_urn text NOT NULL, + content text NOT NULL, + context text, + embedding vector(1536) NOT NULL, + position int, + heading text, + token_count int, + created_at timestamptz DEFAULT now() +); + +CREATE INDEX chunks_embedding_idx ON chunks + USING hnsw (embedding vector_cosine_ops) + WITH (m = 16, ef_construction = 64); +CREATE INDEX idx_chunks_entity_urn ON chunks(entity_urn); +CREATE INDEX idx_chunks_namespace ON chunks(namespace_id); + +-- ============================================================ +-- Stars (users starring entities) +-- ============================================================ + +CREATE TABLE stars ( + id bigserial PRIMARY KEY, + namespace_id uuid NOT NULL REFERENCES namespaces(id), + user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE, + entity_id uuid NOT NULL REFERENCES entities(id) ON DELETE CASCADE, + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now() +); + +CREATE UNIQUE INDEX idx_stars_user_entity ON stars(user_id, entity_id); +CREATE INDEX idx_stars_entity ON stars(entity_id); +CREATE INDEX idx_stars_namespace ON stars(namespace_id); + +-- ============================================================ +-- Row Level Security (all tables) +-- ============================================================ + +ALTER TABLE users ENABLE ROW LEVEL SECURITY; +ALTER TABLE entities ENABLE ROW LEVEL SECURITY; +ALTER TABLE edges ENABLE ROW LEVEL SECURITY; +ALTER TABLE chunks ENABLE ROW LEVEL SECURITY; +ALTER TABLE stars ENABLE ROW LEVEL SECURITY; + +CREATE POLICY users_ns ON users USING (namespace_id = current_setting('app.current_tenant')::UUID); +CREATE POLICY entities_ns ON entities USING (namespace_id = current_setting('app.current_tenant')::UUID); +CREATE POLICY edges_ns ON edges USING (namespace_id = current_setting('app.current_tenant')::UUID); +CREATE POLICY chunks_ns ON chunks USING (namespace_id = current_setting('app.current_tenant')::UUID); +CREATE POLICY stars_ns ON stars USING (namespace_id = current_setting('app.current_tenant')::UUID); diff --git a/store/postgres/migrations/000002_create_users_table.down.sql b/store/postgres/migrations/000002_create_users_table.down.sql deleted file mode 100644 index 365a2107..00000000 --- a/store/postgres/migrations/000002_create_users_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE IF EXISTS users; \ No newline at end of file diff --git a/store/postgres/migrations/000002_create_users_table.up.sql b/store/postgres/migrations/000002_create_users_table.up.sql deleted file mode 100644 index 66a7ef6b..00000000 --- a/store/postgres/migrations/000002_create_users_table.up.sql +++ /dev/null @@ -1,11 +0,0 @@ -CREATE TABLE users ( - id uuid DEFAULT gen_random_uuid() PRIMARY KEY, - uuid text, - email text, - provider text, - created_at timestamp DEFAULT NOW(), - updated_at timestamp DEFAULT NOW() -); - -CREATE UNIQUE INDEX users_idx_uuid ON users(uuid); -CREATE UNIQUE INDEX users_idx_email ON users(email); \ No newline at end of file diff --git a/store/postgres/migrations/000003_create_assets_table.down.sql b/store/postgres/migrations/000003_create_assets_table.down.sql deleted file mode 100644 index deaab3f0..00000000 --- a/store/postgres/migrations/000003_create_assets_table.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE IF EXISTS asset_owners; -DROP TABLE IF EXISTS assets; diff --git a/store/postgres/migrations/000003_create_assets_table.up.sql b/store/postgres/migrations/000003_create_assets_table.up.sql deleted file mode 100644 index 341feec4..00000000 --- a/store/postgres/migrations/000003_create_assets_table.up.sql +++ /dev/null @@ -1,24 +0,0 @@ -CREATE TABLE assets ( - id uuid DEFAULT gen_random_uuid() PRIMARY KEY, - urn text NOT NULL, - type text NOT NULL, - service text NOT NULL, - name text NOT NULL, - description text, - data jsonb, - labels jsonb, - version text NOT NULL, - updated_by uuid NOT NULL, - created_at timestamp DEFAULT NOW(), - updated_at timestamp DEFAULT NOW() -); - -CREATE UNIQUE INDEX assets_idx_urn_type_service ON assets(urn,type,service); - -CREATE TABLE asset_owners ( - id bigserial PRIMARY KEY, - asset_id uuid NOT NULL REFERENCES assets(id) ON DELETE CASCADE, - user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE -); - -CREATE UNIQUE INDEX asset_owners_idx_asset_id_user_id ON asset_owners(asset_id,user_id); diff --git a/store/postgres/migrations/000004_create_stars_table.down.sql b/store/postgres/migrations/000004_create_stars_table.down.sql deleted file mode 100644 index d55fb890..00000000 --- a/store/postgres/migrations/000004_create_stars_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE IF EXISTS stars; \ No newline at end of file diff --git a/store/postgres/migrations/000004_create_stars_table.up.sql b/store/postgres/migrations/000004_create_stars_table.up.sql deleted file mode 100644 index fdb11cfa..00000000 --- a/store/postgres/migrations/000004_create_stars_table.up.sql +++ /dev/null @@ -1,10 +0,0 @@ -CREATE TABLE stars ( - id bigserial PRIMARY KEY, - user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE, - asset_id uuid NOT NULL REFERENCES assets(id) ON DELETE CASCADE, - created_at timestamp DEFAULT NOW(), - updated_at timestamp DEFAULT NOW() -); - -CREATE UNIQUE INDEX stars_idx_user_id_asset_id ON stars(user_id,asset_id); -CREATE INDEX stars_idx_asset_id ON stars(asset_id); diff --git a/store/postgres/migrations/000005_create_assets_versions_table.down.sql b/store/postgres/migrations/000005_create_assets_versions_table.down.sql deleted file mode 100644 index d9ae3a70..00000000 --- a/store/postgres/migrations/000005_create_assets_versions_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE IF EXISTS assets_versions; \ No newline at end of file diff --git a/store/postgres/migrations/000005_create_assets_versions_table.up.sql b/store/postgres/migrations/000005_create_assets_versions_table.up.sql deleted file mode 100644 index ed547974..00000000 --- a/store/postgres/migrations/000005_create_assets_versions_table.up.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE assets_versions ( - id bigserial PRIMARY KEY, - asset_id uuid NOT NULL REFERENCES assets(id) ON DELETE CASCADE, - urn text NOT NULL, - type text NOT NULL, - service text NOT NULL, - name text NOT NULL, - description text, - data jsonb, - labels jsonb, - version text NOT NULL, - updated_by uuid NOT NULL, - created_at timestamp, - updated_at timestamp, - owners jsonb, - changelog jsonb NOT NULL -); - -CREATE UNIQUE INDEX assets_versions_idx_asset_id_version ON assets_versions(asset_id,version); -CREATE UNIQUE INDEX assets_versions_idx_urn_type_service_version ON assets_versions(urn,type,service,version); \ No newline at end of file diff --git a/store/postgres/migrations/000006_create_lineage_graph_table.down.sql b/store/postgres/migrations/000006_create_lineage_graph_table.down.sql deleted file mode 100644 index 4750c1a1..00000000 --- a/store/postgres/migrations/000006_create_lineage_graph_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE IF EXISTS lineage_graph; diff --git a/store/postgres/migrations/000006_create_lineage_graph_table.up.sql b/store/postgres/migrations/000006_create_lineage_graph_table.up.sql deleted file mode 100644 index 25e32b35..00000000 --- a/store/postgres/migrations/000006_create_lineage_graph_table.up.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE lineage_graph ( - source text NOT NULL, - target text NOT NULL, - prop jsonb, - primary key (source, target) -); diff --git a/store/postgres/migrations/000007_create_discussions_table.down.sql b/store/postgres/migrations/000007_create_discussions_table.down.sql deleted file mode 100644 index ac098491..00000000 --- a/store/postgres/migrations/000007_create_discussions_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE IF EXISTS discussions; diff --git a/store/postgres/migrations/000007_create_discussions_table.up.sql b/store/postgres/migrations/000007_create_discussions_table.up.sql deleted file mode 100644 index a375473f..00000000 --- a/store/postgres/migrations/000007_create_discussions_table.up.sql +++ /dev/null @@ -1,19 +0,0 @@ -CREATE TABLE discussions ( - id bigserial PRIMARY KEY, - title text NOT NULL, - body text NOT NULL, - state text NOT NULL, - type text NOT NULL, - owner uuid NOT NULL, - labels text[], - assets text[], - assignees text[], - created_at timestamp DEFAULT NOW(), - updated_at timestamp DEFAULT NOW() -); - -CREATE INDEX discussions_idx_assets ON discussions USING GIN(assets); -CREATE INDEX discussions_idx_labels ON discussions USING GIN(labels); -CREATE INDEX discussions_idx_assignees ON discussions USING GIN(assignees); -CREATE INDEX discussions_idx_owner ON discussions(owner); -CREATE INDEX discussions_idx_type_state ON discussions(type,state); diff --git a/store/postgres/migrations/000008_create_comments_table.down.sql b/store/postgres/migrations/000008_create_comments_table.down.sql deleted file mode 100644 index df81169e..00000000 --- a/store/postgres/migrations/000008_create_comments_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE IF EXISTS comments; diff --git a/store/postgres/migrations/000008_create_comments_table.up.sql b/store/postgres/migrations/000008_create_comments_table.up.sql deleted file mode 100644 index fa4d206a..00000000 --- a/store/postgres/migrations/000008_create_comments_table.up.sql +++ /dev/null @@ -1,12 +0,0 @@ -CREATE TABLE comments ( - id bigserial PRIMARY KEY, - discussion_id bigint NOT NULL REFERENCES discussions(id) ON DELETE CASCADE, - body text NOT NULL, - owner uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE, - updated_by uuid NOT NULL, - created_at timestamp DEFAULT NOW(), - updated_at timestamp DEFAULT NOW() -); - -CREATE INDEX comments_idx_discussion_id ON comments(discussion_id); -CREATE INDEX comments_idx_owner ON comments(owner); diff --git a/store/postgres/migrations/000009_update_tags_templates_assetid.down.sql b/store/postgres/migrations/000009_update_tags_templates_assetid.down.sql deleted file mode 100644 index ead7d726..00000000 --- a/store/postgres/migrations/000009_update_tags_templates_assetid.down.sql +++ /dev/null @@ -1,12 +0,0 @@ -BEGIN; - -DROP INDEX IF EXISTS tags_idx_asset_id_field_id; - -ALTER TABLE tags -ADD COLUMN record_urn text NOT NULL, -ADD COLUMN record_type text NOT NULL, -DROP COLUMN asset_id; - -CREATE UNIQUE INDEX tags_idx_record_urn_record_type_field_id ON tags(record_urn,record_type,field_id); - -COMMIT; \ No newline at end of file diff --git a/store/postgres/migrations/000009_update_tags_templates_assetid.up.sql b/store/postgres/migrations/000009_update_tags_templates_assetid.up.sql deleted file mode 100644 index 5376c521..00000000 --- a/store/postgres/migrations/000009_update_tags_templates_assetid.up.sql +++ /dev/null @@ -1,12 +0,0 @@ -BEGIN; - -DROP INDEX IF EXISTS tags_idx_record_urn_record_type_field_id; - -ALTER TABLE tags -ADD COLUMN asset_id text NOT NULL, -DROP COLUMN record_urn, -DROP COLUMN record_type; - -CREATE UNIQUE INDEX tags_idx_asset_id_field_id ON tags(asset_id,field_id); - -COMMIT; \ No newline at end of file diff --git a/store/postgres/migrations/000010_drop_assets_idx_urn_type_service.down.sql b/store/postgres/migrations/000010_drop_assets_idx_urn_type_service.down.sql deleted file mode 100644 index cc5d8f29..00000000 --- a/store/postgres/migrations/000010_drop_assets_idx_urn_type_service.down.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS assets_idx_urn_type_service ON assets(urn,type,service); diff --git a/store/postgres/migrations/000010_drop_assets_idx_urn_type_service.up.sql b/store/postgres/migrations/000010_drop_assets_idx_urn_type_service.up.sql deleted file mode 100644 index 4f74eb5b..00000000 --- a/store/postgres/migrations/000010_drop_assets_idx_urn_type_service.up.sql +++ /dev/null @@ -1,4 +0,0 @@ --- By default, golang-migrate wraps multiple SQL statements in a transaction. --- Dropping index concurrently is not allowed in a transaction. So the drop --- statement needs to be the only statement in the migration. -DROP INDEX CONCURRENTLY IF EXISTS assets_idx_urn_type_service; diff --git a/store/postgres/migrations/000011_create_idx_assets_urn.down.sql b/store/postgres/migrations/000011_create_idx_assets_urn.down.sql deleted file mode 100644 index c06e8a3a..00000000 --- a/store/postgres/migrations/000011_create_idx_assets_urn.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP INDEX CONCURRENTLY IF EXISTS assets_idx_urn; diff --git a/store/postgres/migrations/000011_create_idx_assets_urn.up.sql b/store/postgres/migrations/000011_create_idx_assets_urn.up.sql deleted file mode 100644 index 2e6a817c..00000000 --- a/store/postgres/migrations/000011_create_idx_assets_urn.up.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS assets_idx_urn ON assets(urn); diff --git a/store/postgres/migrations/000012_create_asset_probes_table.down.sql b/store/postgres/migrations/000012_create_asset_probes_table.down.sql deleted file mode 100644 index 1ae833c5..00000000 --- a/store/postgres/migrations/000012_create_asset_probes_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE IF EXISTS asset_probes; diff --git a/store/postgres/migrations/000012_create_asset_probes_table.up.sql b/store/postgres/migrations/000012_create_asset_probes_table.up.sql deleted file mode 100644 index ee68c132..00000000 --- a/store/postgres/migrations/000012_create_asset_probes_table.up.sql +++ /dev/null @@ -1,9 +0,0 @@ -CREATE TABLE IF NOT EXISTS asset_probes ( - id uuid DEFAULT gen_random_uuid() PRIMARY KEY, - asset_urn text NOT NULL REFERENCES assets(urn) ON DELETE CASCADE ON UPDATE CASCADE, - status text NOT NULL, - status_reason text, - metadata jsonb, - timestamp timestamp DEFAULT NOW(), - created_at timestamp DEFAULT NOW() -); diff --git a/store/postgres/migrations/000013_alter_assets_table.down.sql b/store/postgres/migrations/000013_alter_assets_table.down.sql deleted file mode 100644 index 2b6ad57c..00000000 --- a/store/postgres/migrations/000013_alter_assets_table.down.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE assets DROP COLUMN IF EXISTS url; diff --git a/store/postgres/migrations/000013_alter_assets_table.up.sql b/store/postgres/migrations/000013_alter_assets_table.up.sql deleted file mode 100644 index cf561e1c..00000000 --- a/store/postgres/migrations/000013_alter_assets_table.up.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE assets ADD COLUMN IF NOT EXISTS url TEXT; diff --git a/store/postgres/migrations/000014_create_namespace_table_and_add_namespace_in_tables.down.sql b/store/postgres/migrations/000014_create_namespace_table_and_add_namespace_in_tables.down.sql deleted file mode 100644 index 039a2f1a..00000000 --- a/store/postgres/migrations/000014_create_namespace_table_and_add_namespace_in_tables.down.sql +++ /dev/null @@ -1,65 +0,0 @@ -BEGIN; - --- foreign key is a pain -ALTER TABLE asset_probes DROP CONSTRAINT IF EXISTS asset_probes_asset_urn_fkey; - -DROP INDEX IF EXISTS assets_idx_urn; -CREATE UNIQUE INDEX assets_idx_urn ON assets(urn); - -DROP INDEX IF EXISTS idx_assets_namespace_id; -ALTER TABLE assets DROP COLUMN IF EXISTS namespace_id; - -ALTER TABLE asset_probes ADD CONSTRAINT asset_probes_asset_urn_fkey FOREIGN KEY (asset_urn) - REFERENCES assets(urn) ON DELETE CASCADE ON UPDATE CASCADE; - -DROP INDEX IF EXISTS assets_versions_idx_urn_version; -CREATE UNIQUE INDEX IF NOT EXISTS assets_versions_idx_urn_type_service_version ON assets_versions(urn,type,service,version); - -DROP INDEX IF EXISTS users_idx_uuid; -CREATE UNIQUE INDEX users_idx_uuid ON users(uuid); - -DROP INDEX IF EXISTS users_idx_email; -CREATE UNIQUE INDEX users_idx_email ON users(email); - ----- - - -DROP INDEX IF EXISTS idx_assets_versions_namespace_id; -ALTER TABLE assets_versions DROP COLUMN IF EXISTS namespace_id; - -DROP INDEX IF EXISTS idx_asset_owners_namespace_id; -ALTER TABLE asset_owners DROP COLUMN IF EXISTS namespace_id; - -DROP INDEX IF EXISTS idx_asset_probes_namespace_id; -ALTER TABLE asset_probes DROP COLUMN IF EXISTS namespace_id; - -DROP INDEX IF EXISTS idx_tags_namespace_id; -ALTER TABLE tags DROP COLUMN IF EXISTS namespace_id; - -DROP INDEX IF EXISTS idx_tag_templates_namespace_id; -ALTER TABLE tag_templates DROP COLUMN IF EXISTS namespace_id; - -DROP INDEX IF EXISTS idx_tag_template_fields_namespace_id; -ALTER TABLE tag_template_fields DROP COLUMN IF EXISTS namespace_id; - -DROP INDEX IF EXISTS idx_users_namespace_id; -ALTER TABLE users DROP COLUMN IF EXISTS namespace_id; - -DROP INDEX IF EXISTS idx_stars_namespace_id; -ALTER TABLE stars DROP COLUMN IF EXISTS namespace_id; - -DROP INDEX IF EXISTS idx_lineage_graph_namespace_id; -ALTER TABLE lineage_graph DROP COLUMN IF EXISTS namespace_id; - -DROP INDEX IF EXISTS idx_discussions_namespace_id; -ALTER TABLE discussions DROP COLUMN IF EXISTS namespace_id; - -DROP INDEX IF EXISTS idx_comments_namespace_id; -ALTER TABLE comments DROP COLUMN IF EXISTS namespace_id; - ----- - -DROP TABLE IF EXISTS namespaces; - -COMMIT; - diff --git a/store/postgres/migrations/000014_create_namespace_table_and_add_namespace_in_tables.up.sql b/store/postgres/migrations/000014_create_namespace_table_and_add_namespace_in_tables.up.sql deleted file mode 100644 index b7d8406f..00000000 --- a/store/postgres/migrations/000014_create_namespace_table_and_add_namespace_in_tables.up.sql +++ /dev/null @@ -1,66 +0,0 @@ -BEGIN; - -CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -CREATE TABLE IF NOT EXISTS namespaces ( - id uuid DEFAULT gen_random_uuid() PRIMARY KEY, - name text UNIQUE NOT NULL, - state text, - metadata jsonb, - created_at timestamp DEFAULT NOW(), - updated_at timestamp DEFAULT NOW(), - deleted_at timestamp -); - -ALTER TABLE assets ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_assets_namespace_id ON assets(namespace_id); - -ALTER TABLE assets_versions ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_assets_versions_namespace_id ON assets_versions(namespace_id); - -ALTER TABLE asset_owners ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_asset_owners_namespace_id ON asset_owners(namespace_id); - -ALTER TABLE asset_probes ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_asset_probes_namespace_id ON asset_probes(namespace_id); - -ALTER TABLE tags ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_tags_namespace_id ON tags(namespace_id); - -ALTER TABLE tag_templates ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_tag_templates_namespace_id ON tag_templates(namespace_id); - -ALTER TABLE tag_template_fields ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_tag_template_fields_namespace_id ON tag_template_fields(namespace_id); - -ALTER TABLE users ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_users_namespace_id ON users(namespace_id); - -ALTER TABLE stars ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_stars_namespace_id ON stars(namespace_id); - -ALTER TABLE lineage_graph ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_lineage_graph_namespace_id ON lineage_graph(namespace_id); - -ALTER TABLE discussions ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_discussions_namespace_id ON discussions(namespace_id); - -ALTER TABLE comments ADD COLUMN IF NOT EXISTS namespace_id uuid NOT NULL DEFAULT uuid_nil(); -CREATE INDEX IF NOT EXISTS idx_comments_namespace_id ON comments(namespace_id); - --- include namespace in index -ALTER TABLE asset_probes DROP CONSTRAINT IF EXISTS asset_probes_asset_urn_fkey; -DROP INDEX IF EXISTS assets_idx_urn; -CREATE UNIQUE INDEX assets_idx_urn ON assets(namespace_id,urn); -ALTER TABLE asset_probes ADD CONSTRAINT asset_probes_asset_urn_fkey FOREIGN KEY (namespace_id, asset_urn) - REFERENCES assets(namespace_id, urn) ON DELETE CASCADE ON UPDATE CASCADE; - -DROP INDEX IF EXISTS assets_versions_idx_urn_type_service_version; -CREATE UNIQUE INDEX assets_versions_idx_urn_version ON assets_versions(namespace_id,urn,version); - -DROP INDEX IF EXISTS users_idx_uuid; -CREATE UNIQUE INDEX users_idx_uuid ON users(namespace_id,uuid); - -DROP INDEX IF EXISTS users_idx_email; -CREATE UNIQUE INDEX users_idx_email ON users(namespace_id,email); - -COMMIT; \ No newline at end of file diff --git a/store/postgres/migrations/000015_enable_row_level_security_all_tables.down.sql b/store/postgres/migrations/000015_enable_row_level_security_all_tables.down.sql deleted file mode 100644 index 92c5e6f0..00000000 --- a/store/postgres/migrations/000015_enable_row_level_security_all_tables.down.sql +++ /dev/null @@ -1,29 +0,0 @@ -BEGIN; - -DROP POLICY IF EXISTS assets_isolation_policy ON assets; -DROP POLICY IF EXISTS assets_versions_isolation_policy ON assets_versions; -DROP POLICY IF EXISTS asset_owners_isolation_policy ON asset_owners; -DROP POLICY IF EXISTS asset_probes_isolation_policy ON asset_probes; -DROP POLICY IF EXISTS tags_isolation_policy ON tags; -DROP POLICY IF EXISTS tag_templates_isolation_policy ON tag_templates; -DROP POLICY IF EXISTS tag_template_fields_isolation_policy ON tag_template_fields; -DROP POLICY IF EXISTS users_isolation_policy ON users; -DROP POLICY IF EXISTS stars_isolation_policy ON stars; -DROP POLICY IF EXISTS lineage_graph_isolation_policy ON lineage_graph; -DROP POLICY IF EXISTS discussions_isolation_policy ON discussions; -DROP POLICY IF EXISTS comments_isolation_policy ON comments; - -ALTER TABLE assets DISABLE ROW LEVEL SECURITY; -ALTER TABLE assets_versions DISABLE ROW LEVEL SECURITY; -ALTER TABLE asset_owners DISABLE ROW LEVEL SECURITY; -ALTER TABLE asset_probes DISABLE ROW LEVEL SECURITY; -ALTER TABLE tags DISABLE ROW LEVEL SECURITY; -ALTER TABLE tag_templates DISABLE ROW LEVEL SECURITY; -ALTER TABLE tag_template_fields DISABLE ROW LEVEL SECURITY; -ALTER TABLE users DISABLE ROW LEVEL SECURITY; -ALTER TABLE stars DISABLE ROW LEVEL SECURITY; -ALTER TABLE lineage_graph DISABLE ROW LEVEL SECURITY; -ALTER TABLE discussions DISABLE ROW LEVEL SECURITY; -ALTER TABLE comments DISABLE ROW LEVEL SECURITY; - -COMMIT; \ No newline at end of file diff --git a/store/postgres/migrations/000015_enable_row_level_security_all_tables.up.sql b/store/postgres/migrations/000015_enable_row_level_security_all_tables.up.sql deleted file mode 100644 index dcbfc54c..00000000 --- a/store/postgres/migrations/000015_enable_row_level_security_all_tables.up.sql +++ /dev/null @@ -1,52 +0,0 @@ -BEGIN; - -ALTER TABLE assets ENABLE ROW LEVEL SECURITY; -ALTER TABLE assets_versions ENABLE ROW LEVEL SECURITY; -ALTER TABLE asset_owners ENABLE ROW LEVEL SECURITY; -ALTER TABLE asset_probes ENABLE ROW LEVEL SECURITY; -ALTER TABLE tags ENABLE ROW LEVEL SECURITY; -ALTER TABLE tag_templates ENABLE ROW LEVEL SECURITY; -ALTER TABLE tag_template_fields ENABLE ROW LEVEL SECURITY; -ALTER TABLE users ENABLE ROW LEVEL SECURITY; -ALTER TABLE stars ENABLE ROW LEVEL SECURITY; -ALTER TABLE lineage_graph ENABLE ROW LEVEL SECURITY; -ALTER TABLE discussions ENABLE ROW LEVEL SECURITY; -ALTER TABLE comments ENABLE ROW LEVEL SECURITY; - -DROP POLICY IF EXISTS assets_isolation_policy ON assets; -CREATE POLICY assets_isolation_policy on assets USING (namespace_id = current_setting('app.current_tenant')::UUID); - -DROP POLICY IF EXISTS assets_versions_isolation_policy ON assets_versions; -CREATE POLICY assets_versions_isolation_policy on assets_versions USING (namespace_id = current_setting('app.current_tenant')::UUID); - -DROP POLICY IF EXISTS asset_owners_isolation_policy ON asset_owners; -CREATE POLICY asset_owners_isolation_policy on asset_owners USING (namespace_id = current_setting('app.current_tenant')::UUID); - -DROP POLICY IF EXISTS asset_probes_isolation_policy ON asset_probes; -CREATE POLICY asset_probes_isolation_policy on asset_probes USING (namespace_id = current_setting('app.current_tenant')::UUID); - -DROP POLICY IF EXISTS tags_isolation_policy ON tags; -CREATE POLICY tags_isolation_policy on tags USING (namespace_id = current_setting('app.current_tenant')::UUID); - -DROP POLICY IF EXISTS tag_templates_isolation_policy ON tag_templates; -CREATE POLICY tag_templates_isolation_policy on tag_templates USING (namespace_id = current_setting('app.current_tenant')::UUID); - -DROP POLICY IF EXISTS tag_template_fields_isolation_policy ON tag_template_fields; -CREATE POLICY tag_template_fields_isolation_policy on tag_template_fields USING (namespace_id = current_setting('app.current_tenant')::UUID); - -DROP POLICY IF EXISTS users_isolation_policy ON users; -CREATE POLICY users_isolation_policy on users USING (namespace_id = current_setting('app.current_tenant')::UUID); - -DROP POLICY IF EXISTS stars_isolation_policy ON stars; -CREATE POLICY stars_isolation_policy on stars USING (namespace_id = current_setting('app.current_tenant')::UUID); - -DROP POLICY IF EXISTS lineage_graph_isolation_policy ON lineage_graph; -CREATE POLICY lineage_graph_isolation_policy on lineage_graph USING (namespace_id = current_setting('app.current_tenant')::UUID); - -DROP POLICY IF EXISTS discussions_isolation_policy ON discussions; -CREATE POLICY discussions_isolation_policy on discussions USING (namespace_id = current_setting('app.current_tenant')::UUID); - -DROP POLICY IF EXISTS comments_isolation_policy ON comments; -CREATE POLICY comments_isolation_policy on comments USING (namespace_id = current_setting('app.current_tenant')::UUID); - -COMMIT; \ No newline at end of file diff --git a/store/postgres/migrations/000016_update_assets_versions.down.sql b/store/postgres/migrations/000016_update_assets_versions.down.sql deleted file mode 100644 index e69de29b..00000000 diff --git a/store/postgres/migrations/000016_update_assets_versions.up.sql b/store/postgres/migrations/000016_update_assets_versions.up.sql deleted file mode 100644 index c848c386..00000000 --- a/store/postgres/migrations/000016_update_assets_versions.up.sql +++ /dev/null @@ -1 +0,0 @@ -UPDATE assets_versions SET version = '0.1' WHERE version = ''; \ No newline at end of file diff --git a/store/postgres/migrations/000017_add_soft_deletion.down.sql b/store/postgres/migrations/000017_add_soft_deletion.down.sql deleted file mode 100644 index 54b6926f..00000000 --- a/store/postgres/migrations/000017_add_soft_deletion.down.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE assets DROP COLUMN IF EXISTS refreshed_at; -ALTER TABLE assets DROP COLUMN IF EXISTS is_deleted; -ALTER TABLE assets_versions DROP COLUMN IF EXISTS is_deleted; diff --git a/store/postgres/migrations/000017_add_soft_deletion.up.sql b/store/postgres/migrations/000017_add_soft_deletion.up.sql deleted file mode 100644 index 35aeef68..00000000 --- a/store/postgres/migrations/000017_add_soft_deletion.up.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE assets ADD COLUMN IF NOT EXISTS refreshed_at TIMESTAMP; -ALTER TABLE assets ADD COLUMN IF NOT EXISTS is_deleted BOOLEAN DEFAULT false; -ALTER TABLE assets_versions ADD COLUMN IF NOT EXISTS is_deleted BOOLEAN DEFAULT false; diff --git a/store/postgres/migrations/000018_index_asset_probes.down.sql b/store/postgres/migrations/000018_index_asset_probes.down.sql deleted file mode 100644 index f56f2696..00000000 --- a/store/postgres/migrations/000018_index_asset_probes.down.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP INDEX IF EXISTS idx_asset_probes_asset_urn; -DROP INDEX IF EXISTS idx_asset_probes_timestamp; diff --git a/store/postgres/migrations/000018_index_asset_probes.up.sql b/store/postgres/migrations/000018_index_asset_probes.up.sql deleted file mode 100644 index 381fc32e..00000000 --- a/store/postgres/migrations/000018_index_asset_probes.up.sql +++ /dev/null @@ -1,2 +0,0 @@ -CREATE INDEX IF NOT EXISTS idx_asset_probes_asset_urn ON asset_probes (asset_urn); -CREATE INDEX IF NOT EXISTS idx_asset_probes_timestamp ON asset_probes (timestamp); diff --git a/store/postgres/migrations/000019_create_entity_tables.down.sql b/store/postgres/migrations/000019_create_entity_tables.down.sql deleted file mode 100644 index bfe8b849..00000000 --- a/store/postgres/migrations/000019_create_entity_tables.down.sql +++ /dev/null @@ -1,3 +0,0 @@ -DROP TABLE IF EXISTS chunks CASCADE; -DROP TABLE IF EXISTS edges CASCADE; -DROP TABLE IF EXISTS entities CASCADE; diff --git a/store/postgres/migrations/000019_create_entity_tables.up.sql b/store/postgres/migrations/000019_create_entity_tables.up.sql deleted file mode 100644 index ae8243bf..00000000 --- a/store/postgres/migrations/000019_create_entity_tables.up.sql +++ /dev/null @@ -1,98 +0,0 @@ --- Entity Model v2: entities, edges, chunks (alongside existing assets tables) --- All search is Postgres-native: tsvector for keyword, pg_trgm for fuzzy, pgvector for semantic. --- No Elasticsearch dependency for the v2 entity system. - -CREATE EXTENSION IF NOT EXISTS vector; -CREATE EXTENSION IF NOT EXISTS pg_trgm; - --- Entities: the core knowledge layer -CREATE TABLE entities ( - id uuid DEFAULT gen_random_uuid() PRIMARY KEY, - namespace_id uuid NOT NULL REFERENCES namespaces(id), - urn text NOT NULL, - type text NOT NULL, - name text NOT NULL, - description text, - properties jsonb DEFAULT '{}', - source text, - valid_from timestamptz DEFAULT now(), - valid_to timestamptz, - created_at timestamptz DEFAULT now(), - updated_at timestamptz DEFAULT now(), - - -- Full-text search vector (auto-populated by trigger) - search_vector tsvector GENERATED ALWAYS AS ( - setweight(to_tsvector('english', coalesce(urn, '')), 'A') || - setweight(to_tsvector('english', coalesce(name, '')), 'A') || - setweight(to_tsvector('english', coalesce(description, '')), 'B') || - setweight(to_tsvector('english', coalesce(source, '')), 'C') - ) STORED, - - UNIQUE (namespace_id, urn, valid_from) -); - -CREATE INDEX idx_entities_ns_urn ON entities(namespace_id, urn); -CREATE INDEX idx_entities_type ON entities(type); -CREATE INDEX idx_entities_current ON entities(valid_to) WHERE valid_to IS NULL; -CREATE INDEX idx_entities_properties ON entities USING GIN(properties); -CREATE INDEX idx_entities_source ON entities(source); - --- Full-text search index (GIN on tsvector) -CREATE INDEX idx_entities_search ON entities USING GIN(search_vector); - --- Trigram indexes for fuzzy matching on name and URN -CREATE INDEX idx_entities_name_trgm ON entities USING GIN(name gin_trgm_ops); -CREATE INDEX idx_entities_urn_trgm ON entities USING GIN(urn gin_trgm_ops); - -ALTER TABLE entities ENABLE ROW LEVEL SECURITY; -CREATE POLICY entities_ns_policy ON entities - USING (namespace_id = current_setting('app.current_tenant')::UUID); - --- Edges: typed, temporal relationships between entities -CREATE TABLE edges ( - id uuid DEFAULT gen_random_uuid() PRIMARY KEY, - namespace_id uuid NOT NULL REFERENCES namespaces(id), - source_urn text NOT NULL, - target_urn text NOT NULL, - type text NOT NULL, - properties jsonb DEFAULT '{}', - valid_from timestamptz DEFAULT now(), - valid_to timestamptz, - source text, - created_at timestamptz DEFAULT now(), - - UNIQUE (namespace_id, source_urn, target_urn, type, valid_from) -); - -CREATE INDEX idx_edges_source_urn ON edges(namespace_id, source_urn); -CREATE INDEX idx_edges_target_urn ON edges(namespace_id, target_urn); -CREATE INDEX idx_edges_type ON edges(type); -CREATE INDEX idx_edges_current ON edges(valid_to) WHERE valid_to IS NULL; - -ALTER TABLE edges ENABLE ROW LEVEL SECURITY; -CREATE POLICY edges_ns_policy ON edges - USING (namespace_id = current_setting('app.current_tenant')::UUID); - --- Chunks: vector embeddings for semantic search -CREATE TABLE chunks ( - id uuid DEFAULT gen_random_uuid() PRIMARY KEY, - namespace_id uuid NOT NULL REFERENCES namespaces(id), - entity_urn text NOT NULL, - content text NOT NULL, - context text, - embedding vector(1536) NOT NULL, - position int, - heading text, - token_count int, - created_at timestamptz DEFAULT now() -); - -CREATE INDEX chunks_embedding_idx ON chunks - USING hnsw (embedding vector_cosine_ops) - WITH (m = 16, ef_construction = 64); -CREATE INDEX idx_chunks_entity_urn ON chunks(entity_urn); -CREATE INDEX idx_chunks_namespace ON chunks(namespace_id); - -ALTER TABLE chunks ENABLE ROW LEVEL SECURITY; -CREATE POLICY chunks_ns_policy ON chunks - USING (namespace_id = current_setting('app.current_tenant')::UUID); diff --git a/store/postgres/postgres_test.go b/store/postgres/postgres_test.go deleted file mode 100644 index 427be4b7..00000000 --- a/store/postgres/postgres_test.go +++ /dev/null @@ -1,207 +0,0 @@ -package postgres_test - -import ( - "context" - "fmt" - "github.com/raystack/compass/core/namespace" - "strconv" - "time" - - "github.com/google/uuid" - _ "github.com/jackc/pgx/v5/stdlib" - "github.com/raystack/compass/core/asset" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/store/postgres" -"github.com/ory/dockertest/v3" - "github.com/ory/dockertest/v3/docker" -) - -const ( - defaultProviderName = "shield" - defaultGetMaxSize = 7 -) - -var ( - pgConfig = postgres.Config{ - Host: "localhost", - User: "test_user", - Password: "test_pass", - Name: "test_db", - } -) - -func newTestClient() (*postgres.Client, *dockertest.Pool, *dockertest.Resource, error) { - - opts := &dockertest.RunOptions{ - Repository: "postgres", - Tag: "13", - Env: []string{ - "POSTGRES_PASSWORD=" + pgConfig.Password, - "POSTGRES_USER=" + pgConfig.User, - "POSTGRES_DB=" + pgConfig.Name, - }, - } - - // uses a sensible default on windows (tcp/http) and linux/osx (socket) - pool, err := dockertest.NewPool("") - if err != nil { - return nil, nil, nil, fmt.Errorf("could not create dockertest pool: %w", err) - } - - // pulls an image, creates a container based on it and runs it - resource, err := pool.RunWithOptions(opts, func(config *docker.HostConfig) { - // set AutoRemove to true so that stopped container goes away by itself - config.AutoRemove = true - config.RestartPolicy = docker.RestartPolicy{Name: "no"} - }) - if err != nil { - return nil, nil, nil, fmt.Errorf("could not start resource: %w", err) - } - - pgConfig.Port, err = strconv.Atoi(resource.GetPort("5432/tcp")) - if err != nil { - return nil, nil, nil, fmt.Errorf("cannot parse external port of container to int: %w", err) - } - - // Tell docker to hard kill the container in 120 seconds - if err := resource.Expire(120); err != nil { - return nil, nil, nil, err - } - - // exponential backoff-retry, because the application in the container might not be ready to accept connections yet - pool.MaxWait = 60 * time.Second - - var pgClient *postgres.Client - if err = pool.Retry(func() error { - pgClient, err = postgres.NewClient(pgConfig) - if err != nil { - return err - } - - if _, err = pgClient.ExecContext(context.Background(), ";"); err != nil { - return err - } - - return nil - }); err != nil { - return nil, nil, nil, fmt.Errorf("could not connect to docker: %w", err) - } - - err = setup(context.Background(), pgClient) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to setup and migrate DB: %w", err) - } - return pgClient, pool, resource, nil -} - -func purgeDocker(pool *dockertest.Pool, resource *dockertest.Resource) error { - if err := pool.Purge(resource); err != nil { - return fmt.Errorf("could not purge resource: %w", err) - } - return nil -} - -func setup(ctx context.Context, client *postgres.Client) (err error) { - var queries = []string{ - "DROP SCHEMA public CASCADE", - "CREATE SCHEMA public", - } - - err = client.ExecQueries(ctx, queries) - if err != nil { - return - } - - _, err = client.Migrate(pgConfig) - return -} - -// helper functions -func createUser(userRepo user.Repository, ns *namespace.Namespace, email string) (string, error) { - user := getUser(email) - id, err := userRepo.Create(context.Background(), ns, user) - if err != nil { - return "", err - } - return id, nil -} - -func createAsset(assetRepo asset.Repository, ns *namespace.Namespace, updaterID string, ownerEmail, assetURN, assetType string) (*asset.Asset, error) { - ast := getAsset(ownerEmail, assetURN, assetType) - ast.UpdatedBy.ID = updaterID - id, err := assetRepo.Upsert(context.Background(), ns, ast) - if err != nil { - return nil, err - } - ast.ID = id - return ast, nil -} - -func getAsset(ownerEmail, assetURN, assetType string) *asset.Asset { - return &asset.Asset{ - URN: assetURN, - Type: asset.Type(assetType), - Service: "bigquery", - Owners: []user.User{ - { - Email: ownerEmail, - }, - }, - UpdatedBy: user.User{ - Email: ownerEmail, - }, - } -} - -func getUser(email string) *user.User { - timestamp := time.Now().UTC() - return &user.User{ - UUID: uuid.NewString(), // uuid is autogenerated in DB - Email: email, - Provider: defaultProviderName, - CreatedAt: timestamp, - UpdatedAt: timestamp, - } -} - -func createUsers(userRepo user.Repository, ns *namespace.Namespace, num int) (users []user.User, err error) { - for i := 0; i < num; i++ { - email := fmt.Sprintf("user-test-%d@raystack.io", i+1) - user1 := user.User{UUID: uuid.NewString(), Email: email, Provider: defaultProviderName} - user1.ID, err = userRepo.Create(context.Background(), ns, &user1) - if err != nil { - return - } - users = append(users, user1) - } - return -} - -func createAssets(assetRepo asset.Repository, ns *namespace.Namespace, users []user.User, astType asset.Type) (asts []asset.Asset, err error) { - var count = 0 - for _, usr := range users { - var ast *asset.Asset - count += 1 - assetURN := fmt.Sprintf("asset-urn-%d", count) - ast, err = createAsset(assetRepo, ns, usr.ID, usr.Email, assetURN, astType.String()) - if err != nil { - return - } - asts = append(asts, *ast) - } - return -} - -func usersToUserIDs(users []user.User) (uids []string) { - for _, us := range users { - uids = append(uids, us.ID) - } - return -} - -func assetsToAssetIDs(assets []asset.Asset) (aids []string) { - for _, as := range assets { - aids = append(aids, as.ID) - } - return -} diff --git a/store/postgres/star_repository.go b/store/postgres/star_repository.go index e10d9f8f..64082d92 100644 --- a/store/postgres/star_repository.go +++ b/store/postgres/star_repository.go @@ -5,10 +5,10 @@ import ( "database/sql" "errors" "fmt" + "github.com/jmoiron/sqlx" + "github.com/raystack/compass/core/entity" "github.com/raystack/compass/core/namespace" - - "github.com/raystack/compass/core/asset" "github.com/raystack/compass/core/star" "github.com/raystack/compass/core/user" ) @@ -20,42 +20,34 @@ type StarClauses struct { SortDirectionKey string } -// StarRepository is a type that manages star operation to the primary database type StarRepository struct { client *Client } -// Create insert a new record in the stars table -func (r *StarRepository) Create(ctx context.Context, ns *namespace.Namespace, userID string, assetID string) (string, error) { +func (r *StarRepository) Create(ctx context.Context, ns *namespace.Namespace, userID string, entityID string) (string, error) { var starID string if userID == "" { return "", star.ErrEmptyUserID } - if assetID == "" { - return "", star.ErrEmptyAssetID + if entityID == "" { + return "", star.ErrEmptyEntityID } - if !isValidUUID(userID) { return "", star.InvalidError{UserID: userID} } - - if !isValidUUID(assetID) { - return "", star.InvalidError{AssetID: assetID} + if !isValidUUID(entityID) { + return "", star.InvalidError{EntityID: entityID} } + err := r.client.QueryFn(ctx, func(conn *sqlx.Conn) error { - return conn.QueryRowxContext(ctx, ` - INSERT INTO - stars - (user_id, asset_id, namespace_id) - VALUES - ($1, $2, $3) - RETURNING id - `, userID, assetID, ns.ID).Scan(&starID) + return conn.QueryRowxContext(ctx, + `INSERT INTO stars (user_id, entity_id, namespace_id) VALUES ($1, $2, $3) RETURNING id`, + userID, entityID, ns.ID).Scan(&starID) }) if err != nil { err = checkPostgresError(err) if errors.Is(err, errDuplicateKey) { - return "", star.DuplicateRecordError{UserID: userID, AssetID: assetID} + return "", star.DuplicateRecordError{UserID: userID, EntityID: entityID} } if errors.Is(err, errForeignKeyViolation) { return "", star.UserNotFoundError{UserID: userID} @@ -68,196 +60,123 @@ func (r *StarRepository) Create(ctx context.Context, ns *namespace.Namespace, us return starID, nil } -// GetStargazers fetch list of user IDs that star an asset -func (r *StarRepository) GetStargazers(ctx context.Context, flt star.Filter, assetID string) ([]user.User, error) { - if assetID == "" { - return nil, star.ErrEmptyAssetID +func (r *StarRepository) GetStargazers(ctx context.Context, flt star.Filter, entityID string) ([]user.User, error) { + if entityID == "" { + return nil, star.ErrEmptyEntityID } - - if !isValidUUID(assetID) { - return nil, star.InvalidError{AssetID: assetID} + if !isValidUUID(entityID) { + return nil, star.InvalidError{EntityID: entityID} } - starClausesValue := r.buildClausesValue(flt) + clauses := r.buildClausesValue(flt) var userModels UserModels if err := r.client.SelectContext(ctx, &userModels, ` - SELECT - DISTINCT ON (u.id) u.id, - u.uuid, - u.email, - u.provider, - u.created_at, - u.updated_at - FROM - stars s - JOIN - users u ON s.user_id = u.id - WHERE - s.asset_id = $1 - LIMIT $2 - OFFSET $3 - `, assetID, starClausesValue.Limit, starClausesValue.Offset); err != nil { - return nil, fmt.Errorf("failed fetching users of star: %w", err) + SELECT DISTINCT ON (u.id) u.id, u.uuid, u.email, u.provider, u.created_at, u.updated_at + FROM stars s + JOIN users u ON s.user_id = u.id + WHERE s.entity_id = $1 + LIMIT $2 OFFSET $3 + `, entityID, clauses.Limit, clauses.Offset); err != nil { + return nil, fmt.Errorf("failed fetching stargazers: %w", err) } - if len(userModels) == 0 { - return nil, star.NotFoundError{AssetID: assetID} + return nil, star.NotFoundError{EntityID: entityID} } - return userModels.toUsers(), nil } -// GetAllAssetsByUserID fetch list of assets starred by a user -func (r *StarRepository) GetAllAssetsByUserID(ctx context.Context, flt star.Filter, userID string) ([]asset.Asset, error) { +func (r *StarRepository) GetAllEntitiesByUserID(ctx context.Context, flt star.Filter, userID string) ([]entity.Entity, error) { if userID == "" { return nil, star.ErrEmptyUserID } - if !isValidUUID(userID) { return nil, star.InvalidError{UserID: userID} } - starClausesValue := r.buildClausesValue(flt) - - var assetModels []AssetModel - if err := r.client.SelectContext(ctx, &assetModels, fmt.Sprintf(` + clauses := r.buildClausesValue(flt) + var models []entityModel + if err := r.client.SelectContext(ctx, &models, fmt.Sprintf(` SELECT - a.id as id, - a.urn as urn, - a.type as type, - a.name as name, - a.service as service, - a.description as description, - a.data as data, - a.labels as labels, - a.version as version, - a.created_at as created_at, - a.updated_at as updated_at, - u.id as "updated_by.id", - u.uuid as "updated_by.uuid", - u.email as "updated_by.email", - u.provider as "updated_by.provider", - u.created_at as "updated_by.created_at", - u.updated_at as "updated_by.updated_at" - FROM - stars s - INNER JOIN - assets a ON s.asset_id = a.id - LEFT JOIN - users u ON a.updated_by = u.id - WHERE - s.user_id = $1 - ORDER BY - $2 %s - LIMIT - $3 - OFFSET - $4 - `, starClausesValue.SortDirectionKey), userID, starClausesValue.SortKey, starClausesValue.Limit, starClausesValue.Offset); err != nil { - return nil, fmt.Errorf("failed fetching stars by user: %w", err) - } - - if len(assetModels) == 0 { + a.id, a.namespace_id, a.urn, a.type, a.name, a.description, + a.properties, COALESCE(a.source, '') as source, + a.valid_from, a.valid_to, a.created_at, a.updated_at + FROM stars s + INNER JOIN entities a ON s.entity_id = a.id + WHERE s.user_id = $1 AND a.valid_to IS NULL + ORDER BY $2 %s + LIMIT $3 OFFSET $4 + `, clauses.SortDirectionKey), userID, clauses.SortKey, clauses.Limit, clauses.Offset); err != nil { + return nil, fmt.Errorf("failed fetching starred entities: %w", err) + } + if len(models) == 0 { return nil, star.NotFoundError{UserID: userID} } - assets := []asset.Asset{} - for _, am := range assetModels { - assets = append(assets, am.toAsset(nil)) + result := make([]entity.Entity, len(models)) + for i, m := range models { + result[i] = m.toEntity() } - return assets, nil + return result, nil } -// GetAssetByUserID fetch a specific starred asset by user id -func (r *StarRepository) GetAssetByUserID(ctx context.Context, userID string, assetID string) (asset.Asset, error) { +func (r *StarRepository) GetEntityByUserID(ctx context.Context, userID string, entityID string) (entity.Entity, error) { if userID == "" { - return asset.Asset{}, star.ErrEmptyUserID + return entity.Entity{}, star.ErrEmptyUserID } - if assetID == "" { - return asset.Asset{}, star.ErrEmptyAssetID + if entityID == "" { + return entity.Entity{}, star.ErrEmptyEntityID } - if !isValidUUID(userID) { - return asset.Asset{}, star.InvalidError{UserID: userID} + return entity.Entity{}, star.InvalidError{UserID: userID} } - if !isValidUUID(assetID) { - return asset.Asset{}, star.InvalidError{AssetID: assetID} + if !isValidUUID(entityID) { + return entity.Entity{}, star.InvalidError{EntityID: entityID} } - var assetModel AssetModel - err := r.client.GetContext(ctx, &assetModel, ` + var m entityModel + err := r.client.GetContext(ctx, &m, ` SELECT - a.id, - a.urn, - a.type, - a.service, - a.name, - a.description, - a.data, - a.labels, - a.version, - a.created_at, - a.updated_at, - u.id as "updated_by.id", - u.uuid as "updated_by.uuid", - u.email as "updated_by.email", - u.provider as "updated_by.provider", - u.created_at as "updated_by.created_at", - u.updated_at as "updated_by.updated_at" - FROM - stars s - INNER JOIN - assets a ON s.asset_id = a.id - LEFT JOIN - users u ON a.updated_by = u.id - WHERE - s.user_id = $1 AND s.asset_id = $2 + a.id, a.namespace_id, a.urn, a.type, a.name, a.description, + a.properties, COALESCE(a.source, '') as source, + a.valid_from, a.valid_to, a.created_at, a.updated_at + FROM stars s + INNER JOIN entities a ON s.entity_id = a.id + WHERE s.user_id = $1 AND s.entity_id = $2 AND a.valid_to IS NULL LIMIT 1 - `, userID, assetID) + `, userID, entityID) if errors.Is(err, sql.ErrNoRows) { - return asset.Asset{}, star.NotFoundError{AssetID: assetID, UserID: userID} + return entity.Entity{}, star.NotFoundError{EntityID: entityID, UserID: userID} } if err != nil { - return asset.Asset{}, fmt.Errorf("failed fetching star by user: %w", err) + return entity.Entity{}, fmt.Errorf("failed fetching starred entity: %w", err) } - - asset := assetModel.toAsset(nil) - return asset, nil + return m.toEntity(), nil } -// Delete will delete/unstar a starred asset for a user id -func (r *StarRepository) Delete(ctx context.Context, userID string, assetID string) error { +func (r *StarRepository) Delete(ctx context.Context, userID string, entityID string) error { if userID == "" { return star.ErrEmptyUserID } - if assetID == "" { - return star.ErrEmptyAssetID + if entityID == "" { + return star.ErrEmptyEntityID } - if !isValidUUID(userID) { return star.InvalidError{UserID: userID} } - if !isValidUUID(assetID) { - return star.InvalidError{AssetID: assetID} + if !isValidUUID(entityID) { + return star.InvalidError{EntityID: entityID} } - res, err := r.client.ExecContext(ctx, ` - DELETE FROM - stars - WHERE - user_id = $1 AND asset_id = $2 - `, userID, assetID) + res, err := r.client.ExecContext(ctx, `DELETE FROM stars WHERE user_id = $1 AND entity_id = $2`, userID, entityID) if err != nil { - return fmt.Errorf("failed to unstar an asset: %w", err) + return fmt.Errorf("failed to unstar entity: %w", err) } - rowsAffected, err := res.RowsAffected() if err != nil { - return fmt.Errorf("failed to get row affected unstarring an asset: %w", err) + return fmt.Errorf("failed to get rows affected: %w", err) } - if rowsAffected == 0 { - return star.NotFoundError{AssetID: assetID, UserID: userID} + return star.NotFoundError{EntityID: entityID, UserID: userID} } return nil } @@ -269,22 +188,18 @@ func (r *StarRepository) buildClausesValue(flt star.Filter) StarClauses { SortKey: columnNameCreatedAt, SortDirectionKey: sortDirectionDescending, } - if flt.Size > 0 { sCfg.Limit = flt.Size } - if flt.Offset < 1 { flt.Offset = 0 } - switch flt.Sort { case star.SortKeyCreated: sCfg.SortKey = columnNameCreatedAt case star.SortKeyUpdated: sCfg.SortKey = columnNameUpdatedAt } - switch flt.SortDirection { case star.SortDirectionKeyAscending: sCfg.SortDirectionKey = sortDirectionAscending @@ -294,12 +209,9 @@ func (r *StarRepository) buildClausesValue(flt star.Filter) StarClauses { return sCfg } -// NewStarRepository initializes star repository clients func NewStarRepository(c *Client) (*StarRepository, error) { if c == nil { return nil, errNilPostgresClient } - return &StarRepository{ - client: c, - }, nil + return &StarRepository{client: c}, nil } diff --git a/store/postgres/star_repository_test.go b/store/postgres/star_repository_test.go deleted file mode 100644 index 65dba837..00000000 --- a/store/postgres/star_repository_test.go +++ /dev/null @@ -1,466 +0,0 @@ -package postgres_test - -import ( - "context" - "fmt" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/middleware" - "testing" - - "github.com/google/uuid" - "github.com/raystack/compass/core/star" - "github.com/raystack/compass/store/postgres" - "github.com/ory/dockertest/v3" - "github.com/stretchr/testify/suite" -) - -type StarRepositoryTestSuite struct { - suite.Suite - ctx context.Context - client *postgres.Client - pool *dockertest.Pool - resource *dockertest.Resource - repository *postgres.StarRepository - userRepository *postgres.UserRepository - assetRepository *postgres.AssetRepository - ns *namespace.Namespace -} - -func (r *StarRepositoryTestSuite) SetupSuite() { - var err error - r.ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.SharedState, - Metadata: nil, - } - - r.client, r.pool, r.resource, err = newTestClient() - if err != nil { - r.T().Fatal(err) - } - - r.ctx = middleware.BuildContextWithNamespace(context.Background(), r.ns) - r.repository, err = postgres.NewStarRepository(r.client) - if err != nil { - r.T().Fatal(err) - } - r.userRepository, err = postgres.NewUserRepository(r.client) - if err != nil { - r.T().Fatal(err) - } - r.assetRepository, err = postgres.NewAssetRepository(r.client, r.userRepository, postgres.DefaultMaxResultSize, "") - if err != nil { - r.T().Fatal(err) - } -} - -func (r *StarRepositoryTestSuite) TearDownSuite() { - // Clean tests - err := r.client.Close() - if err != nil { - r.T().Fatal(err) - } - err = purgeDocker(r.pool, r.resource) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *StarRepositoryTestSuite) TestCreate() { - ownerEmail := "test-create@raystack.io" - - r.Run("return no error if succesfully create star", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - userID, err := createUser(r.userRepository, r.ns, "user@raystack.io") - r.NoError(err) - - createdAsset, err := createAsset(r.assetRepository, r.ns, userID, ownerEmail, "asset-urn-1", "table") - r.NoError(err) - - id, err := r.repository.Create(r.ctx, r.ns, userID, createdAsset.ID) - r.NoError(err) - r.NotEmpty(id) - }) - - r.Run("return ErrEmptyUserID if user id is empty", func() { - id, err := r.repository.Create(r.ctx, r.ns, "", "") - r.ErrorIs(err, star.ErrEmptyUserID) - r.Empty(id) - }) - - r.Run("return ErrEmptyAssetID error if asset id is empty", func() { - id, err := r.repository.Create(r.ctx, r.ns, "user-id", "") - r.ErrorIs(err, star.ErrEmptyAssetID) - r.Empty(id) - }) - - r.Run("return invalid error if user id is not uuid", func() { - id, err := r.repository.Create(r.ctx, r.ns, "user-id", "asset-id") - r.ErrorIs(err, star.InvalidError{UserID: "user-id"}) - r.Empty(id) - }) - - r.Run("return invalid error if asset id is not uuid", func() { - uid := uuid.NewString() - id, err := r.repository.Create(r.ctx, r.ns, uid, "asset-id") - r.ErrorIs(err, star.InvalidError{AssetID: "asset-id"}) - r.Empty(id) - }) - - r.Run("return ErrDuplicateRecord if starred asset is already exist", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - userID, err := createUser(r.userRepository, r.ns, "user@raystack.io") - r.NoError(err) - - createdAsset, err := createAsset(r.assetRepository, r.ns, userID, ownerEmail, "asset-urn-1", "table") - r.NoError(err) - - id, err := r.repository.Create(r.ctx, r.ns, userID, createdAsset.ID) - r.NoError(err) - r.NotEmpty(id) - - id, err = r.repository.Create(r.ctx, r.ns, userID, createdAsset.ID) - r.ErrorIs(err, star.DuplicateRecordError{UserID: userID, AssetID: createdAsset.ID}) - r.Empty(id) - }) - - r.Run("return error user not found if user does not exist", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - uid := uuid.NewString() - - createdAsset, err := createAsset(r.assetRepository, r.ns, uid, ownerEmail, "asset-urn-1", "table") - r.NoError(err) - - id, err := r.repository.Create(r.ctx, r.ns, uid, createdAsset.ID) - r.ErrorIs(err, star.UserNotFoundError{UserID: uid}) - r.Empty(id) - }) -} - -func (r *StarRepositoryTestSuite) TestGetStargazers() { - ownerEmail := "test-getstargazers@raystack.io" - - defaultCfg := star.Filter{} - r.Run("return ErrEmptyAssetID if asset id is empty", func() { - users, err := r.repository.GetStargazers(r.ctx, defaultCfg, "") - r.ErrorIs(err, star.ErrEmptyAssetID) - r.Empty(users) - }) - - r.Run("return invalid error if asset id is not uuid", func() { - users, err := r.repository.GetStargazers(r.ctx, defaultCfg, "asset-id") - r.ErrorIs(err, star.InvalidError{AssetID: "asset-id"}) - r.Empty(users) - }) - - r.Run("return not found error if starred asset not found in db", func() { - assetID := uuid.NewString() - users, err := r.repository.GetStargazers(r.ctx, defaultCfg, assetID) - r.ErrorIs(err, star.NotFoundError{AssetID: assetID}) - r.Empty(users) - }) - - r.Run("return list of users that star an asset if get users success", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - userID1, err := createUser(r.userRepository, r.ns, "user@raystack.io") - r.NoError(err) - - createdAsset1, err := createAsset(r.assetRepository, r.ns, userID1, ownerEmail, "asset-urn-1", "table") - r.NoError(err) - - id, err := r.repository.Create(r.ctx, r.ns, userID1, createdAsset1.ID) - r.NoError(err) - r.NotEmpty(id) - - userID2, err := createUser(r.userRepository, r.ns, "admin@raystack.io") - r.NoError(err) - - id, err = r.repository.Create(r.ctx, r.ns, userID2, createdAsset1.ID) - r.NoError(err) - r.NotEmpty(id) - - actualUsers, err := r.repository.GetStargazers(r.ctx, defaultCfg, createdAsset1.ID) - r.NoError(err) - - actualUserIDs := []string{} - for _, user := range actualUsers { - actualUserIDs = append(actualUserIDs, user.ID) - } - - r.Len(actualUserIDs, 2) - r.Contains(actualUserIDs, userID1) - r.Contains(actualUserIDs, userID2) - }) - - r.Run("return limited paginated list of users that star an asset if get users success", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - var assetID string - - for i := 1; i < 20; i++ { - userEmail := fmt.Sprintf("user%d@raystack.io", i) - userID, err := createUser(r.userRepository, r.ns, userEmail) - r.NoError(err) - createdAsset, err := createAsset(r.assetRepository, r.ns, userID, ownerEmail, "asset-urn-1", "table") - r.NoError(err) - - id, err := r.repository.Create(r.ctx, r.ns, userID, createdAsset.ID) - r.NoError(err) - r.NotEmpty(id) - - assetID = createdAsset.ID - } - - cfg := star.Filter{Size: 7} - actualUsers, err := r.repository.GetStargazers(r.ctx, cfg, assetID) - r.NoError(err) - - r.Len(actualUsers, 7) - }) -} - -func (r *StarRepositoryTestSuite) TestGetAllAssetsByUserID() { - ownerEmail := "test-getallbyuserid@raystack.io" - - defaultCfg := star.Filter{} - r.Run("return invalid error if user id is empty", func() { - assets, err := r.repository.GetAllAssetsByUserID(r.ctx, defaultCfg, "") - r.ErrorIs(err, star.ErrEmptyUserID) - r.Empty(assets) - }) - - r.Run("return invalid error if user id is not uuid", func() { - assets, err := r.repository.GetAllAssetsByUserID(r.ctx, defaultCfg, "user-id") - r.ErrorIs(err, star.InvalidError{UserID: "user-id"}) - r.Empty(assets) - }) - - r.Run("return not found error if starred asset not found in db", func() { - randomUserID := uuid.NewString() - assets, err := r.repository.GetAllAssetsByUserID(r.ctx, defaultCfg, randomUserID) - r.ErrorIs(err, star.NotFoundError{UserID: randomUserID}) - r.Empty(assets) - }) - - r.Run("return list of starred assets if get by user id success", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - userID1, err := createUser(r.userRepository, r.ns, "user@raystack.io") - r.NoError(err) - - createdAsset1, err := createAsset(r.assetRepository, r.ns, userID1, ownerEmail, "asset-urn-1", "table") - r.NoError(err) - id, err := r.repository.Create(r.ctx, r.ns, userID1, createdAsset1.ID) - r.NoError(err) - r.NotEmpty(id) - - createdAsset2, err := createAsset(r.assetRepository, r.ns, userID1, ownerEmail, "asset-urn-2", "table") - r.NoError(err) - id, err = r.repository.Create(r.ctx, r.ns, userID1, createdAsset2.ID) - r.NoError(err) - r.NotEmpty(id) - - createdAsset3, err := createAsset(r.assetRepository, r.ns, userID1, ownerEmail, "asset-urn-3", "table") - r.NoError(err) - id, err = r.repository.Create(r.ctx, r.ns, userID1, createdAsset3.ID) - r.NoError(err) - r.NotEmpty(id) - - actualAssets, err := r.repository.GetAllAssetsByUserID(r.ctx, defaultCfg, userID1) - r.NoError(err) - - assetIDs := []string{} - for _, asset := range actualAssets { - assetIDs = append(assetIDs, asset.ID) - } - - r.Len(actualAssets, 3) - r.Contains(assetIDs, createdAsset1.ID) - r.Contains(assetIDs, createdAsset2.ID) - r.Contains(assetIDs, createdAsset3.ID) - }) - - r.Run("return limited paginated list of starred assets if get by user id success", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - userID, err := createUser(r.userRepository, r.ns, "user@raystack.io") - r.NoError(err) - - for i := 1; i < 20; i++ { - starURN := fmt.Sprintf("asset-urn-%d", i) - createdAsset, err := createAsset(r.assetRepository, r.ns, userID, ownerEmail, starURN, "table") - r.NoError(err) - id, err := r.repository.Create(r.ctx, r.ns, userID, createdAsset.ID) - r.NoError(err) - r.NotEmpty(id) - } - - cfg := star.Filter{Size: 7} - actualAssets, err := r.repository.GetAllAssetsByUserID(r.ctx, cfg, userID) - r.NoError(err) - r.NoError(err) - - r.Len(actualAssets, 7) - }) -} - -func (r *StarRepositoryTestSuite) TestGetAssetByUserID() { - ownerEmail := "test-getbyuserid@raystack.io" - - r.Run("return ErrEmptyUserID if user id is empty", func() { - ast, err := r.repository.GetAssetByUserID(r.ctx, "", "") - r.ErrorIs(err, star.ErrEmptyUserID) - r.Empty(ast) - }) - - r.Run("return ErrEmptyAssetID if asset id is empty", func() { - ast, err := r.repository.GetAssetByUserID(r.ctx, "user-id", "") - r.ErrorIs(err, star.ErrEmptyAssetID) - r.Empty(ast) - }) - - r.Run("return invalid error if user id is not uuid", func() { - ast, err := r.repository.GetAssetByUserID(r.ctx, "user-id", "asset-id") - r.ErrorIs(err, star.InvalidError{UserID: "user-id"}) - r.Empty(ast) - }) - - r.Run("return invalid error if asset id is not uuid", func() { - uid := uuid.NewString() - ast, err := r.repository.GetAssetByUserID(r.ctx, uid, "asset-id") - r.ErrorIs(err, star.InvalidError{AssetID: "asset-id"}) - r.Empty(ast) - }) - - r.Run("return not found error if starred asset not found in db", func() { - randomUserID := uuid.NewString() - assetID := uuid.NewString() - ast, err := r.repository.GetAssetByUserID(r.ctx, randomUserID, assetID) - r.ErrorIs(err, star.NotFoundError{AssetID: assetID, UserID: randomUserID}) - r.Empty(ast) - }) - - r.Run("return the starred assets if get user starred asset success", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - userID1, err := createUser(r.userRepository, r.ns, "user@raystack.io") - r.NoError(err) - - createdAsset1, err := createAsset(r.assetRepository, r.ns, userID1, ownerEmail, "asset-urn-1", "table") - r.NoError(err) - id, err := r.repository.Create(r.ctx, r.ns, userID1, createdAsset1.ID) - r.NoError(err) - r.NotEmpty(id) - - createdAsset2, err := createAsset(r.assetRepository, r.ns, userID1, ownerEmail, "asset-urn-2", "table") - r.NoError(err) - id, err = r.repository.Create(r.ctx, r.ns, userID1, createdAsset2.ID) - r.NoError(err) - r.NotEmpty(id) - - createdAsset3, err := createAsset(r.assetRepository, r.ns, userID1, ownerEmail, "asset-urn-3", "table") - r.NoError(err) - id, err = r.repository.Create(r.ctx, r.ns, userID1, createdAsset3.ID) - r.NoError(err) - r.NotEmpty(id) - - actualAsset, err := r.repository.GetAssetByUserID(r.ctx, userID1, createdAsset2.ID) - r.NoError(err) - - r.Equal(createdAsset2.ID, actualAsset.ID) - }) -} - -func (r *StarRepositoryTestSuite) TestDelete() { - ownerEmail := "test-delete@raystack.io" - - r.Run("return invalid error if user id is empty", func() { - err := r.repository.Delete(r.ctx, "", "") - r.ErrorIs(err, star.ErrEmptyUserID) - }) - - r.Run("return invalid error if asset id is empty", func() { - err := r.repository.Delete(r.ctx, "user-id", "") - r.ErrorIs(err, star.ErrEmptyAssetID) - }) - - r.Run("return invalid error if user id is not uuid", func() { - err := r.repository.Delete(r.ctx, "user-id", "asset-id") - r.ErrorIs(err, star.InvalidError{UserID: "user-id"}) - }) - - r.Run("return invalid error if asset id is not uuid", func() { - uid := uuid.NewString() - err := r.repository.Delete(r.ctx, uid, "asset-id") - r.ErrorIs(err, star.InvalidError{AssetID: "asset-id"}) - }) - - r.Run("return not found error if starred asset not found in db", func() { - randomUserID := uuid.NewString() - assetID := uuid.NewString() - err := r.repository.Delete(r.ctx, randomUserID, assetID) - r.ErrorIs(err, star.NotFoundError{AssetID: assetID, UserID: randomUserID}) - }) - - r.Run("return nil if successfully unstar an asset", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - userID1, err := createUser(r.userRepository, r.ns, "user@raystack.io") - r.NoError(err) - - createdAsset1, err := createAsset(r.assetRepository, r.ns, userID1, ownerEmail, "asset-urn-1", "table") - r.NoError(err) - id, err := r.repository.Create(r.ctx, r.ns, userID1, createdAsset1.ID) - r.NoError(err) - r.NotEmpty(id) - - createdAsset2, err := createAsset(r.assetRepository, r.ns, userID1, ownerEmail, "asset-urn-2", "table") - r.NoError(err) - id, err = r.repository.Create(r.ctx, r.ns, userID1, createdAsset2.ID) - r.NoError(err) - r.NotEmpty(id) - - createdAsset3, err := createAsset(r.assetRepository, r.ns, userID1, ownerEmail, "asset-urn-3", "table") - r.NoError(err) - id, err = r.repository.Create(r.ctx, r.ns, userID1, createdAsset3.ID) - r.NoError(err) - r.NotEmpty(id) - - actualAssets, err := r.repository.GetAllAssetsByUserID(r.ctx, star.Filter{}, userID1) - r.NoError(err) - - r.Len(actualAssets, 3) - - err = r.repository.Delete(r.ctx, userID1, createdAsset3.ID) - r.NoError(err) - - actualAssets, err = r.repository.GetAllAssetsByUserID(r.ctx, star.Filter{}, userID1) - r.NoError(err) - - assetIDs := []string{} - for _, asset := range actualAssets { - assetIDs = append(assetIDs, asset.ID) - } - - r.Len(actualAssets, 2) - r.Contains(assetIDs, createdAsset1.ID) - r.Contains(assetIDs, createdAsset2.ID) - - }) -} - -func TestStarRepository(t *testing.T) { - suite.Run(t, &StarRepositoryTestSuite{}) -} diff --git a/store/postgres/tag_model.go b/store/postgres/tag_model.go deleted file mode 100644 index d9982dad..00000000 --- a/store/postgres/tag_model.go +++ /dev/null @@ -1,310 +0,0 @@ -package postgres - -import ( - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "strings" - "time" - - "github.com/raystack/compass/core/tag" -) - -// TagModel is a model for tag value in database table -type TagModel struct { - ID uint `db:"id"` - NamespaceID string `db:"namespace_id"` - Value string `db:"value"` - AssetID string `db:"asset_id"` - FieldID uint `db:"field_id"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` - Field TagTemplateFieldModel `db:"-"` -} - -type TagModels []TagModel - -func (ts TagModels) buildMapByTemplateURN() map[string][]TagModel { - tagsByTemplateURN := make(map[string][]TagModel) - for _, t := range ts { - key := t.Field.TemplateURN - if tagsByTemplateURN[key] == nil { - tagsByTemplateURN[key] = []TagModel{} - } - tagsByTemplateURN[key] = append(tagsByTemplateURN[key], t) - } - return tagsByTemplateURN -} - -func (ts TagModels) toTags(assetID string, templates TagTemplateModels) []tag.Tag { - templateByURN := templates.buildMapByURN() - tagsByTemplateURN := ts.buildMapByTemplateURN() - - output := []tag.Tag{} - for templateURN, tagModels := range tagsByTemplateURN { - var listOfTagValue []tag.TagValue - templateModel := templateByURN[templateURN] - for _, t := range tagModels { - var options []string - if t.Field.Options != nil { - options = strings.Split(*t.Field.Options, ",") - } - parsedValue, _ := tag.ParseTagValue(templateModel.URN, t.FieldID, t.Field.DataType, t.Value, options) - listOfTagValue = append(listOfTagValue, tag.TagValue{ - FieldID: t.FieldID, - FieldValue: parsedValue, - FieldURN: t.Field.URN, - FieldDisplayName: t.Field.DisplayName, - FieldDescription: t.Field.Description, - FieldDataType: t.Field.DataType, - FieldOptions: options, - FieldRequired: t.Field.Required, - CreatedAt: t.CreatedAt, - UpdatedAt: t.UpdatedAt, - }) - } - output = append(output, tag.Tag{ - AssetID: assetID, - TemplateURN: templateModel.URN, - TagValues: listOfTagValue, - TemplateDisplayName: templateModel.DisplayName, - TemplateDescription: templateModel.Description, - }) - } - return output -} - -// TagTemplateModel is a model for template database table -type TagTemplateModel struct { - URN string `db:"urn"` - DisplayName string `db:"display_name"` - Description string `db:"description"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` - Fields TagTemplateFieldModels `db:"-"` - NamespaceID uuid.UUID `db:"namespace_id"` -} - -func (tmp *TagTemplateModel) toTemplate() tag.Template { - return tag.Template{ - URN: tmp.URN, - DisplayName: tmp.DisplayName, - Description: tmp.Description, - Fields: tmp.Fields.toDomainFields(), - CreatedAt: tmp.CreatedAt, - UpdatedAt: tmp.UpdatedAt, - } -} - -func newTemplateModel(ns *namespace.Namespace, template *tag.Template) *TagTemplateModel { - fieldModels := newSliceOfFieldModel(ns, template.Fields) - - return &TagTemplateModel{ - URN: template.URN, - DisplayName: template.DisplayName, - Description: template.Description, - Fields: fieldModels, - } -} - -type TagTemplateModels []TagTemplateModel - -func (tmps TagTemplateModels) buildMapByURN() map[string]TagTemplateModel { - templateByURN := make(map[string]TagTemplateModel) - for _, t := range tmps { - templateByURN[t.URN] = t - } - return templateByURN -} - -// TagTemplateFieldModel is a model for field tag in database table -type TagTemplateFieldModel struct { - ID uint `db:"id"` - URN string `db:"urn"` - DisplayName string `db:"display_name"` - Description string `db:"description"` - DataType string `db:"data_type"` - Options *string `db:"options"` - Required bool `db:"required"` - TemplateURN string `db:"template_urn"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` - Template TagTemplateModel `db:"-"` - NamespaceID uuid.UUID `db:"namespace_id"` -} - -type TagTemplateFieldModels []TagTemplateFieldModel - -func (fs *TagTemplateFieldModels) isIDExist(id uint) bool { - for _, field := range *fs { - if field.ID == id { - return true - } - } - return false -} - -func (fs *TagTemplateFieldModels) toDomainFields() []tag.Field { - output := make([]tag.Field, len(*fs)) - for i, field := range *fs { - var options []string - if field.Options != nil { - options = strings.Split(*field.Options, fieldOptionSeparator) - } - output[i] = tag.Field{ - ID: field.ID, - URN: field.URN, - DisplayName: field.DisplayName, - Description: field.Description, - DataType: field.DataType, - Options: options, - Required: field.Required, - CreatedAt: field.CreatedAt, - UpdatedAt: field.UpdatedAt, - } - } - return output -} - -func newSliceOfFieldModel(ns *namespace.Namespace, listOfDomainField []tag.Field) TagTemplateFieldModels { - newFields := TagTemplateFieldModels{} - for _, field := range listOfDomainField { - var options *string - if len(field.Options) > 0 { - joinedOptions := strings.Join(field.Options, fieldOptionSeparator) - options = &joinedOptions - } - newFields = append(newFields, TagTemplateFieldModel{ - ID: field.ID, - URN: field.URN, - DisplayName: field.DisplayName, - Description: field.Description, - DataType: field.DataType, - Options: options, - Required: field.Required, - NamespaceID: ns.ID, - }) - } - return newFields -} - -// TagJoinTemplateFieldModel is a placeholder for joined template and field -type TagJoinTemplateFieldModel struct { - Template TagTemplateModel `db:"tag_templates"` - Field TagTemplateFieldModel `db:"tag_template_fields"` -} - -// TagJoinTemplateFieldModels is a slice of placeholder for joined template and field -type TagJoinTemplateFieldModels []TagJoinTemplateFieldModel - -func (tfs TagJoinTemplateFieldModels) toTemplateModels() (templates []TagTemplateModel) { - templateMap := make(map[string]TagTemplateModel) - - for _, tf := range tfs { - if _, ok := templateMap[tf.Template.URN]; !ok { - templateMap[tf.Template.URN] = tf.Template - } - templatePtr := templateMap[tf.Template.URN] - // check existing field - if !templatePtr.Fields.isIDExist(tf.Field.ID) { - templatePtr.Fields = append(templatePtr.Fields, tf.Field) - templateMap[tf.Template.URN] = templatePtr - } - } - - for _, t := range templateMap { - templates = append(templates, t) - } - - return -} - -func (tfs TagJoinTemplateFieldModels) toTemplates() (templates []tag.Template) { - templatesMap := map[string]TagTemplateModel{} - for _, tf := range tfs { - // build template - if _, ok := templatesMap[tf.Template.URN]; !ok { - templatesMap[tf.Template.URN] = tf.Template - } - - templatePtr := templatesMap[tf.Template.URN] - // check existing field - if !templatePtr.Fields.isIDExist(tf.Field.ID) { - templatePtr.Fields = append(templatePtr.Fields, tf.Field) - templatesMap[tf.Template.URN] = templatePtr - } - } - - for _, template := range templatesMap { - listOfDomainField := []tag.Field{} - for _, field := range template.Fields { - var options []string - if field.Options != nil { - options = strings.Split(*field.Options, ",") - } - listOfDomainField = append(listOfDomainField, tag.Field{ - ID: field.ID, - URN: field.URN, - DisplayName: field.DisplayName, - Description: field.Description, - DataType: field.DataType, - Required: field.Required, - Options: options, - CreatedAt: field.CreatedAt, - UpdatedAt: field.UpdatedAt, - }) - } - - templates = append(templates, tag.Template{ - URN: template.URN, - DisplayName: template.DisplayName, - Description: template.Description, - Fields: listOfDomainField, - CreatedAt: template.CreatedAt, - UpdatedAt: template.UpdatedAt, - }) - } - return -} - -// TemplateField is a placeholder for joined template, tag, and field -type TagJoinTemplateTagFieldModel struct { - Template TagTemplateModel `db:"tag_templates"` - Tag TagModel `db:"tags"` - Field TagTemplateFieldModel `db:"tag_template_fields"` -} - -// TagJoinTemplateTagFieldModels is a slice of placeholder for joined template, tag, and field -type TagJoinTemplateTagFieldModels []TagJoinTemplateTagFieldModel - -func (ttfs TagJoinTemplateTagFieldModels) toTemplateAndTagModels() (templates TagTemplateModels, tags TagModels) { - tmpltsMap := make(map[string]TagTemplateModel) // template urn as key - tagsMap := make(map[uint]TagModel) - - for _, ttf := range ttfs { - // build template - if _, ok := tmpltsMap[ttf.Template.URN]; !ok { - tmpltsMap[ttf.Template.URN] = ttf.Template - } - - templatePtr := tmpltsMap[ttf.Template.URN] - // check existing field - if !templatePtr.Fields.isIDExist(ttf.Field.ID) { - templatePtr.Fields = append(templatePtr.Fields, ttf.Field) - tmpltsMap[ttf.Template.URN] = templatePtr - } - - if _, ok := tagsMap[ttf.Tag.ID]; !ok { - ttf.Tag.Field = ttf.Field - tagsMap[ttf.Tag.ID] = ttf.Tag - } - } - - for _, tmp := range tmpltsMap { - templates = append(templates, tmp) - } - - for _, tg := range tagsMap { - tags = append(tags, tg) - } - return -} diff --git a/store/postgres/tag_model_test.go b/store/postgres/tag_model_test.go deleted file mode 100644 index adfc39de..00000000 --- a/store/postgres/tag_model_test.go +++ /dev/null @@ -1,360 +0,0 @@ -package postgres - -import ( - "github.com/raystack/compass/core/namespace" - "sort" - "testing" - - "github.com/google/uuid" - "github.com/raystack/compass/core/tag" - "github.com/stretchr/testify/assert" -) - -func TestTagModel(t *testing.T) { - assetID := uuid.NewString() - - templates := getTemplateModels() - tags := getTagModels() - - t.Run("successfully build map of tags model by template URN", func(t *testing.T) { - expectedTagsMap := map[string][]TagModel{ - "governance_policy": {tags[0], tags[1]}, - } - tagsMap := tags.buildMapByTemplateURN() - - assert.EqualValues(t, expectedTagsMap, tagsMap) - - }) - t.Run("successfully build tags from tags model", func(t *testing.T) { - - expectedTagDomains := []tag.Tag{ - { - AssetID: assetID, - TemplateURN: "governance_policy", - TagValues: []tag.TagValue{ - { - FieldID: 1, - FieldValue: "Public", - FieldURN: "classification", - FieldDisplayName: "classification", - FieldDescription: "The classification of this asset", - FieldDataType: "enumerated", - FieldOptions: []string{"Public", "Restricted"}, - FieldRequired: true, - }, { - FieldID: 2, - FieldValue: "dexter@raystack.io", - FieldURN: "admin_email", - FieldDisplayName: "Admin Email", - FieldDescription: "Email of the admin of the asset.", - FieldDataType: "string", - FieldRequired: true, - }}, - TemplateDisplayName: "Governance Policy", - TemplateDescription: "Template that is mandatory to be used.", - }} - - actualTagDomains := tags.toTags(assetID, templates) - - assert.EqualValues(t, expectedTagDomains, actualTagDomains) - }) -} - -func TestTemplateModel(t *testing.T) { - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - templates := getTemplateModels() - - t.Run("successfully convert template model to template", func(t *testing.T) { - expectedTemplate := tag.Template{ - URN: "governance_policy", - DisplayName: "Governance Policy", - Description: "Template that is mandatory to be used.", - Fields: []tag.Field{ - { - ID: 1, - URN: "classification", - DisplayName: "classification", - Description: "The classification of this asset", - DataType: "enumerated", - Options: []string{"Public", "Restricted"}, - Required: true, - }, - { - ID: 2, - URN: "admin_email", - DisplayName: "Admin Email", - Description: "Email of the admin of the asset.", - DataType: "string", - Required: true, - }, - }, - } - actualTemplate := templates[0].toTemplate() - - assert.EqualValues(t, expectedTemplate, actualTemplate) - }) - - t.Run("successfully build from template model from template", func(t *testing.T) { - - template := getTemplate() - option := "Public,Restricted" - expectedTemplateModel := &TagTemplateModel{ - URN: "governance_policy", - DisplayName: "Governance Policy", - Description: "Template that is mandatory to be used.", - Fields: TagTemplateFieldModels{ - { - ID: 1, - URN: "classification", - DisplayName: "classification", - Description: "The classification of this asset", - DataType: "enumerated", - Options: &option, - Required: true, - NamespaceID: ns.ID, - }, - { - ID: 0x2, - URN: "admin_email", - DisplayName: "Admin Email", - Description: "Email of the admin of the asset.", - DataType: "string", - Required: true, - NamespaceID: ns.ID, - }, - }, - } - - templateModel := newTemplateModel(ns, template) - - assert.EqualValues(t, expectedTemplateModel, templateModel) - }) -} - -func TestFieldModels(t *testing.T) { - fieldModels := getFieldModels() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - t.Run("successfully convert fields model to fields", func(t *testing.T) { - expectedDomainFields := []tag.Field{ - { - ID: 1, - URN: "classification", - DisplayName: "classification", - Description: "The classification of this asset", - DataType: "enumerated", - Options: []string{"Public", "Restricted"}, - Required: true, - }, - { - ID: 2, - URN: "admin_email", - DisplayName: "Admin Email", - Description: "Email of the admin of the asset.", - DataType: "string", - Required: true, - }, - } - actualDomainFields := fieldModels.toDomainFields() - - assert.EqualValues(t, expectedDomainFields, actualDomainFields) - }) - - t.Run("successfully build fields model from fields", func(t *testing.T) { - domainFields := fieldModels.toDomainFields() - option := "Public,Restricted" - expectedFieldModels := TagTemplateFieldModels{ - { - ID: 1, - URN: "classification", - DisplayName: "classification", - Description: "The classification of this asset", - DataType: "enumerated", - Options: &option, - Required: true, - NamespaceID: ns.ID, - }, - { - ID: 2, - URN: "admin_email", - DisplayName: "Admin Email", - Description: "Email of the admin of the asset.", - DataType: "string", - Required: true, - NamespaceID: ns.ID, - }, - } - - actualFieldModels := newSliceOfFieldModel(ns, domainFields) - - assert.EqualValues(t, expectedFieldModels, actualFieldModels) - }) - - t.Run("return true if ID exist in slice of fields model", func(t *testing.T) { - assert.True(t, fieldModels.isIDExist(1)) - }) - t.Run("return false if ID exist in slice of field model", func(t *testing.T) { - assert.False(t, fieldModels.isIDExist(100)) - }) -} - -func TestTemplateFields(t *testing.T) { - tfs := getTemplateFieldModels() - templateModels := getTemplateModels() - templates := getTemplate() - t.Run("successfully build template models", func(t *testing.T) { - - actualTemplateModels := tfs.toTemplateModels() - - assert.EqualValues(t, templateModels[0], actualTemplateModels[0]) - }) - t.Run("successfully build templates", func(t *testing.T) { - actualTemplates := tfs.toTemplates() - - assert.EqualValues(t, *templates, actualTemplates[0]) - }) -} - -func TestTemplateTagFields(t *testing.T) { - ttfs := getTemplateTagFieldModels() - t.Run("successfully build templates model and tags model", func(t *testing.T) { - - expectedTemplateModels := getTemplateModels() - expectedTagModels := getTagModels() - actualTemplateModels, actualTagModels := ttfs.toTemplateAndTagModels() - assert.EqualValues(t, expectedTemplateModels[0], actualTemplateModels[0]) - - sort.Slice(actualTagModels[:], func(i, j int) bool { - return actualTagModels[i].ID < actualTagModels[j].ID - }) - sort.Slice(expectedTagModels[:], func(i, j int) bool { - return expectedTagModels[i].ID < expectedTagModels[j].ID - }) - assert.EqualValues(t, expectedTagModels[0], actualTagModels[0]) - }) -} - -func getFieldModels() TagTemplateFieldModels { - option := "Public,Restricted" - return TagTemplateFieldModels{ - { - ID: 1, - URN: "classification", - DisplayName: "classification", - Description: "The classification of this asset", - DataType: "enumerated", - Options: &option, - Required: true, - TemplateURN: "governance_policy", - }, - { - ID: 2, - URN: "admin_email", - DisplayName: "Admin Email", - Description: "Email of the admin of the asset.", - DataType: "string", - Options: nil, - Required: true, - TemplateURN: "governance_policy", - }, - } -} - -func getTemplate() *tag.Template { - return &tag.Template{ - URN: "governance_policy", - DisplayName: "Governance Policy", - Description: "Template that is mandatory to be used.", - Fields: []tag.Field{ - { - ID: 1, - URN: "classification", - DisplayName: "classification", - Description: "The classification of this asset", - DataType: "enumerated", - Required: true, - Options: []string{"Public", "Restricted"}, - }, - { - ID: 2, - URN: "admin_email", - DisplayName: "Admin Email", - Description: "Email of the admin of the asset.", - DataType: "string", - Required: true, - }, - }, - } -} - -func getTemplateModels() TagTemplateModels { - fields := getFieldModels() - return TagTemplateModels{ - { - URN: "governance_policy", - DisplayName: "Governance Policy", - Description: "Template that is mandatory to be used.", - Fields: fields, - }, - } -} - -func getTagModels() TagModels { - fields := getFieldModels() - return TagModels{ - { - ID: 1, - Value: "Public", - AssetID: "an-asset-id", - FieldID: 1, - Field: fields[0], - }, - { - ID: 2, - Value: "dexter@raystack.io", - AssetID: "an-asset-id", - FieldID: 2, - Field: fields[1], - }, - } -} - -func getTemplateFieldModels() TagJoinTemplateFieldModels { - templates := getTemplateModels() - return TagJoinTemplateFieldModels{ - { - Template: templates[0], - Field: templates[0].Fields[0], - }, - { - Template: templates[0], - Field: templates[0].Fields[1], - }, - } -} - -func getTemplateTagFieldModels() TagJoinTemplateTagFieldModels { - templates := getTemplateModels() - tags := getTagModels() - return TagJoinTemplateTagFieldModels{ - { - Template: templates[0], - Tag: tags[0], - Field: templates[0].Fields[0], - }, - { - Template: templates[0], - Tag: tags[1], - Field: templates[0].Fields[1], - }, - } -} diff --git a/store/postgres/tag_repository.go b/store/postgres/tag_repository.go deleted file mode 100644 index 0eb4ddab..00000000 --- a/store/postgres/tag_repository.go +++ /dev/null @@ -1,315 +0,0 @@ -package postgres - -import ( - "context" - "errors" - "fmt" - "github.com/raystack/compass/core/namespace" - "time" - - "github.com/jmoiron/sqlx" - "github.com/raystack/compass/core/tag" -) - -var ( - errNilTag = errors.New("tag is nil") - errEmptyAssetID = errors.New("asset id should not be empty") -) - -// TagRepository is a type that manages tag operation ot the primary database -type TagRepository struct { - client *Client -} - -// Create inserts tag to database -func (r *TagRepository) Create(ctx context.Context, ns *namespace.Namespace, domainTag *tag.Tag) error { - if domainTag == nil { - return errNilTag - } - - templateFieldModels, err := r.readTemplatesByURNFromDB(ctx, domainTag.TemplateURN) - if err != nil { - return err - } - - if len(templateFieldModels) < 1 { - return tag.TemplateNotFoundError{URN: domainTag.TemplateURN} - } - - templates := templateFieldModels.toTemplates() - - var insertedModelTags []TagModel - if err := r.client.RunWithinTx(ctx, func(tx *sqlx.Tx) error { - timestamp := time.Now().UTC() - - for _, tv := range domainTag.TagValues { - var insertedTagValue TagModel - if tv.FieldValue == nil { - continue - } - tagToInsert := &TagModel{ - AssetID: domainTag.AssetID, - FieldID: tv.FieldID, - Value: fmt.Sprintf("%v", tv.FieldValue), - CreatedAt: timestamp, - UpdatedAt: timestamp, - } - - if err := tx.QueryRowxContext(ctx, ` - INSERT INTO tags - (value, asset_id, field_id, created_at, updated_at, namespace_id) - VALUES - ($1, $2, $3, $4, $5, $6) - RETURNING *`, - tagToInsert.Value, tagToInsert.AssetID, tagToInsert.FieldID, - tagToInsert.CreatedAt, tagToInsert.UpdatedAt, ns.ID). - StructScan(&insertedTagValue); err != nil { - if err := checkPostgresError(err); errors.Is(err, errDuplicateKey) { - return tag.DuplicateError{ - AssetID: tagToInsert.AssetID, - TemplateURN: domainTag.TemplateURN, - } - } - return fmt.Errorf("failed to insert a domain tag: %w", err) - } - - insertedModelTags = append(insertedModelTags, insertedTagValue) - } - return nil - }); err != nil { - return err - } - - return r.complementTag(domainTag, templates[0], insertedModelTags) -} - -// Read reads tags grouped by its template -func (r *TagRepository) Read(ctx context.Context, filter tag.Tag) ([]tag.Tag, error) { - - if filter.AssetID == "" { - return nil, errEmptyAssetID - } - - sqlQuery := ` - SELECT - t.urn as "tag_templates.urn", t.display_name as "tag_templates.display_name", t.description as "tag_templates.description", - t.created_at as "tag_templates.created_at", t.updated_at as "tag_templates.updated_at", - tg.id as "tags.id", tg.value as "tags.value", tg.asset_id as "tags.asset_id", - tg.field_id as "tags.field_id", tg.created_at as "tags.created_at", tg.updated_at as "tags.updated_at", - f.id as "tag_template_fields.id", f.urn as "tag_template_fields.urn", f.display_name as "tag_template_fields.display_name", f.description as "tag_template_fields.description", - f.data_type as "tag_template_fields.data_type", f.options as "tag_template_fields.options", f.required as "tag_template_fields.required", f.template_urn as "tag_template_fields.template_urn", - f.created_at as "tag_template_fields.created_at", f.updated_at as "tag_template_fields.updated_at" - FROM - tag_templates t - JOIN - tag_template_fields f ON f.template_urn = t.urn - JOIN - tags tg ON f.id = tg.field_id - WHERE - tg.asset_id = $1` - sqlArgs := []interface{}{filter.AssetID} - - if filter.TemplateURN != "" { - // filter by asset and template - sqlQuery += " AND t.urn = $2" - sqlArgs = append(sqlArgs, filter.TemplateURN) - } - - var templateTagFields TagJoinTemplateTagFieldModels - if err := r.client.SelectContext(ctx, &templateTagFields, sqlQuery, sqlArgs...); err != nil { - return nil, fmt.Errorf("failed reading domain tag: %w", err) - } - - // (nil, not found error) if no asset id and template urn = "" - // (empty, nil) if no asset id and template urn != "" - if len(templateTagFields) == 0 && filter.TemplateURN != "" { - return nil, tag.NotFoundError{ - AssetID: filter.AssetID, - Template: filter.TemplateURN, - } - } - - templates, tags := templateTagFields.toTemplateAndTagModels() - - return tags.toTags(filter.AssetID, templates), nil -} - -// Update updates tags in the database -func (r *TagRepository) Update(ctx context.Context, domainTag *tag.Tag) error { - if domainTag == nil { - return errNilTag - } - - templateFieldModels, err := r.readTemplatesByURNFromDB(ctx, domainTag.TemplateURN) - if err != nil { - return err - } - if len(templateFieldModels) < 1 { - return tag.TemplateNotFoundError{URN: domainTag.TemplateURN} - } - - templates := templateFieldModels.toTemplates() - - var updatedModelTags []TagModel - if err := r.client.RunWithinTx(ctx, func(tx *sqlx.Tx) error { - timestamp := time.Now().UTC() - - for _, value := range domainTag.TagValues { - if value.FieldValue == nil || value.FieldValue == "" { - continue - } - valueStr := fmt.Sprintf("%v", value.FieldValue) - tagModel := &TagModel{ - Value: valueStr, - AssetID: domainTag.AssetID, - FieldID: value.FieldID, - CreatedAt: timestamp, - UpdatedAt: timestamp, - } - - var updatedModelTag TagModel - if err := tx.QueryRowxContext(ctx, ` - INSERT INTO - tags - (value, asset_id, field_id, created_at, updated_at) - VALUES - ($1, $2, $3, $4, $5) - ON CONFLICT - (asset_id, field_id) - DO UPDATE SET - (value, asset_id, field_id, created_at, updated_at) = - ($1, $2, $3, $4, $5) - RETURNING *`, - tagModel.Value, tagModel.AssetID, tagModel.FieldID, tagModel.CreatedAt, tagModel.UpdatedAt). - StructScan(&updatedModelTag); err != nil { - return err - } - updatedModelTags = append(updatedModelTags, updatedModelTag) - } - return nil - }); err != nil { - return fmt.Errorf("failed to update a domain tag: %w", err) - } - - return r.complementTag(domainTag, templates[0], updatedModelTags) -} - -// Delete deletes tags from database -func (r *TagRepository) Delete(ctx context.Context, domainTag tag.Tag) error { - if domainTag.AssetID == "" { - return errEmptyAssetID - } - deletedModelTags := []TagModel{} - fieldIDMap := map[uint]bool{} - if domainTag.TemplateURN != "" { - assetTemplatesFields, err := r.readTemplatesByURNFromDB(ctx, domainTag.TemplateURN) - if err != nil { - return err - } - if len(assetTemplatesFields) < 1 { - return tag.TemplateNotFoundError{URN: domainTag.TemplateURN} - } - for _, tf := range assetTemplatesFields { - fieldIDMap[tf.Field.ID] = true - deletedModelTags = append(deletedModelTags, TagModel{ - AssetID: domainTag.AssetID, - FieldID: tf.Field.ID, - }) - } - } else { - deletedModelTags = append(deletedModelTags, TagModel{ - AssetID: domainTag.AssetID, - }) - } - - return r.client.RunWithinTx(ctx, func(tx *sqlx.Tx) error { - for _, tagModel := range deletedModelTags { - sqlQuery := "DELETE FROM tags WHERE tags.asset_id = $1" - sqlArgs := []interface{}{tagModel.AssetID} - - if tagModel.FieldID != 0 { - sqlQuery += " AND tags.field_id = $2" - sqlArgs = append(sqlArgs, tagModel.FieldID) - } - - res, err := tx.ExecContext(ctx, sqlQuery, sqlArgs...) - if err != nil { - return fmt.Errorf("failed to delete a tag: %w", err) - } - rowsAffected, err := res.RowsAffected() - if err != nil { - return fmt.Errorf("failed to get row affected of deleting tag: %w", err) - } - - if rowsAffected == 0 { - return tag.NotFoundError{AssetID: tagModel.AssetID, Template: domainTag.TemplateURN} - } - } - return nil - }) -} - -func (r *TagRepository) complementTag(domainTag *tag.Tag, template tag.Template, tagModels []TagModel) error { - tagByFieldID := make(map[uint]TagModel) - for _, t := range tagModels { - tagByFieldID[t.FieldID] = t - } - var listOfTagValue []tag.TagValue - for _, field := range template.Fields { - t := tagByFieldID[field.ID] - parsedValue, _ := tag.ParseTagValue(domainTag.TemplateURN, field.ID, field.DataType, t.Value, field.Options) - listOfTagValue = append(listOfTagValue, tag.TagValue{ - FieldID: field.ID, - FieldValue: parsedValue, - FieldURN: field.URN, - FieldDisplayName: field.DisplayName, - FieldDescription: field.Description, - FieldDataType: field.DataType, - FieldOptions: field.Options, - FieldRequired: field.Required, - CreatedAt: t.CreatedAt, - UpdatedAt: t.UpdatedAt, - }) - } - domainTag.TemplateURN = template.URN - domainTag.TemplateDescription = template.Description - domainTag.TemplateDisplayName = template.DisplayName - domainTag.TagValues = listOfTagValue - return nil -} - -func (r *TagRepository) readTemplatesByURNFromDB(ctx context.Context, templateURN string) (TagJoinTemplateFieldModels, error) { - var templateFields TagJoinTemplateFieldModels - // return empty with nil error if not found - if err := r.client.SelectContext(ctx, &templateFields, ` - SELECT - t.urn as "tag_templates.urn", t.display_name as "tag_templates.display_name", t.description as "tag_templates.description", - t.created_at as "tag_templates.created_at", t.updated_at as "tag_templates.updated_at", - f.id as "tag_template_fields.id", f.urn as "tag_template_fields.urn", f.display_name as "tag_template_fields.display_name", f.description as "tag_template_fields.description", - f.data_type as "tag_template_fields.data_type", f.options as "tag_template_fields.options", f.required as "tag_template_fields.required", f.template_urn as "tag_template_fields.template_urn", - f.created_at as "tag_template_fields.created_at", f.updated_at as "tag_template_fields.updated_at" - FROM - tag_templates t - JOIN - tag_template_fields f - ON - f.template_urn = t.urn - WHERE - t.urn = $1`, templateURN); err != nil { - return nil, fmt.Errorf("tag_templates: failed to read from DB %w", err) - } - - return templateFields, nil -} - -// NewTagRepository initializes tag repository -// all methods in tag repository uses passed by reference -// which will mutate the reference variable in method's argument -func NewTagRepository(client *Client) (*TagRepository, error) { - if client == nil { - return nil, errNilPostgresClient - } - return &TagRepository{ - client: client, - }, nil -} diff --git a/store/postgres/tag_repository_test.go b/store/postgres/tag_repository_test.go deleted file mode 100644 index b512aa98..00000000 --- a/store/postgres/tag_repository_test.go +++ /dev/null @@ -1,471 +0,0 @@ -package postgres_test - -import ( - "context" - "fmt" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/middleware" - "sort" - "testing" - - "github.com/google/uuid" - "github.com/raystack/compass/core/tag" - "github.com/raystack/compass/store/postgres" - "github.com/ory/dockertest/v3" - "github.com/stretchr/testify/suite" -) - -var domainAssetID = uuid.NewString() - -type TagRepositoryTestSuite struct { - suite.Suite - ctx context.Context - client *postgres.Client - repository *postgres.TagRepository - templateRepository *postgres.TagTemplateRepository - pool *dockertest.Pool - resource *dockertest.Resource - ns *namespace.Namespace -} - -func (r *TagRepositoryTestSuite) SetupSuite() { - var err error - - r.client, r.pool, r.resource, err = newTestClient() - if err != nil { - r.T().Fatal(err) - } - r.ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - r.ctx = middleware.BuildContextWithNamespace(context.Background(), r.ns) - r.repository, err = postgres.NewTagRepository(r.client) - if err != nil { - r.T().Fatal(err) - } - r.templateRepository, err = postgres.NewTagTemplateRepository(r.client) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *TagRepositoryTestSuite) TearDownSuite() { - // Clean tests - err := r.client.Close() - if err != nil { - r.T().Fatal(err) - } - err = purgeDocker(r.pool, r.resource) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *TagRepositoryTestSuite) TestNewRepository() { - r.Run("should return repository and nil if postgres client is not nil", func() { - pgClient := &postgres.Client{} - - actualTagRepository, err := postgres.NewTagRepository(pgClient) - - r.NotNil(actualTagRepository) - r.Nil(err) - }) -} - -func (r *TagRepositoryTestSuite) TestCreate() { - r.Run("should return error if tag is nil", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - var domainTag *tag.Tag = nil - - expectedErrorMsg := "tag is nil" - - actualError := r.repository.Create(r.ctx, r.ns, domainTag) - - r.EqualError(actualError, expectedErrorMsg) - }) - - r.Run("should return error if template is not found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - domain := getDomainTag() - - err = r.repository.Create(r.ctx, r.ns, &domain) - - r.EqualError(err, tag.TemplateNotFoundError{URN: domain.TemplateURN}.Error()) - }) - - r.Run("should return nil and create tag if no error found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - domainTemplate := getTemplate() - err = r.templateRepository.Create(r.ctx, r.ns, domainTemplate) - r.NoError(err) - domainTag := getDomainTag() - - err = r.repository.Create(r.ctx, r.ns, &domainTag) - r.NoError(err) - - tags, err := r.repository.Read(r.ctx, domainTag) - r.NoError(err) - - r.Equal(domainTag.AssetID, tags[0].AssetID) - r.Equal(domainTag.TemplateDescription, tags[0].TemplateDescription) - r.Equal(domainTag.TemplateDisplayName, tags[0].TemplateDisplayName) - r.Equal(domainTag.TemplateURN, tags[0].TemplateURN) - r.NotEmpty(domainTag.TagValues) - r.NotEmpty(tags[0].TagValues) - - expectedTagValues := domainTag.TagValues - actualTagValues := tags[0].TagValues - - sort.Slice(expectedTagValues[:], func(i, j int) bool { - return expectedTagValues[i].FieldID < expectedTagValues[j].FieldID - }) - sort.Slice(actualTagValues[:], func(i, j int) bool { - return actualTagValues[i].FieldID < actualTagValues[j].FieldID - }) - r.EqualValues(expectedTagValues, actualTagValues) - }) - - r.Run("should return nil and update tag if no error found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - domainTemplate := getTemplate() - err = r.templateRepository.Create(r.ctx, r.ns, domainTemplate) - r.NoError(err) - domainTag := getDomainTag() - - err = r.repository.Create(r.ctx, r.ns, &domainTag) - r.NoError(err) - - for _, value := range domainTag.TagValues { - r.NotZero(value.CreatedAt) - } - }) -} - -func (r *TagRepositoryTestSuite) TestRead() { - r.Run("should return error if asset id is empty", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - paramDomainTag := tag.Tag{ - AssetID: "", - } - - expectedErrorMsg := "asset id should not be empty" - - actualTag, actualError := r.repository.Read(r.ctx, paramDomainTag) - - r.Nil(actualTag) - r.EqualError(actualError, expectedErrorMsg) - }) - - r.Run("should return empty and nil if no tags found for the specified asset", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - paramDomainTag := tag.Tag{ - AssetID: uuid.NewString(), - } - - actualTag, actualError := r.repository.Read(r.ctx, paramDomainTag) - r.NoError(actualError) - r.Empty(actualTag) - }) - - r.Run("should return tags if found for the specified asset", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - domainTemplate := getTemplate() - err = r.templateRepository.Create(r.ctx, r.ns, domainTemplate) - r.Require().NoError(err) - - domainTag := getDomainTag() - err = r.repository.Create(r.ctx, r.ns, &domainTag) - r.Require().NoError(err) - - tags, err := r.repository.Read(r.ctx, tag.Tag{ - AssetID: domainTag.AssetID, - }) - - r.NoError(err) - r.NotEmpty(tags) - r.Len(tags[0].TagValues, 2) - }) - - r.Run("should return nil and not found error if no tags found for the specified asset id and template", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - var assetID = uuid.NewString() - var templateURN = "governance_policy" - - domainTemplate := getTemplate() - err = r.templateRepository.Create(r.ctx, r.ns, domainTemplate) - r.NoError(err) - - paramDomainTag := tag.Tag{ - AssetID: assetID, - TemplateURN: templateURN, - } - - expectedErrorMsg := fmt.Sprintf("could not find tag with asset id: \"%s\", template: \"%s\"", - assetID, templateURN, - ) - - actualTag, actualError := r.repository.Read(r.ctx, paramDomainTag) - r.ErrorAs(actualError, new(tag.NotFoundError)) - r.EqualError(actualError, expectedErrorMsg) - r.Nil(actualTag) - }) - - r.Run("should return maximum of one tag for the specified asset id and template", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - var assetID = domainAssetID - var templateURN = "governance_policy" - - domainTemplate := getTemplate() - err = r.templateRepository.Create(r.ctx, r.ns, domainTemplate) - r.NoError(err) - domainTag := getDomainTag() - - if err := r.repository.Create(r.ctx, r.ns, &domainTag); err != nil { - panic(err) - } - paramDomainTag := tag.Tag{ - AssetID: assetID, - TemplateURN: templateURN, - } - - expectedLength := 1 - - actualTag, actualError := r.repository.Read(r.ctx, paramDomainTag) - - r.Len(actualTag, expectedLength) - r.NoError(actualError) - }) -} - -func (r *TagRepositoryTestSuite) TestUpdate() { - r.Run("should return error if tag is nil", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - var domainTag *tag.Tag = nil - - expectedErrorMsg := "tag is nil" - - actualError := r.repository.Update(r.ctx, domainTag) - - r.EqualError(actualError, expectedErrorMsg) - }) - - r.Run("should return error if template is not found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - t := getDomainTag() - - err = r.repository.Update(r.ctx, &t) - r.EqualError(err, tag.TemplateNotFoundError{URN: t.TemplateURN}.Error()) - }) - - r.Run("should return nil and update tag if no error found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - domainTemplate := getTemplate() - err = r.templateRepository.Create(r.ctx, r.ns, domainTemplate) - r.Require().NoError(err) - - domainTag := getDomainTag() - err = r.repository.Create(r.ctx, r.ns, &domainTag) - r.Require().NoError(err) - - domainTag.TagValues[0].FieldValue = "Restricted" - actualError := r.repository.Update(r.ctx, &domainTag) - r.Require().NoError(actualError) - - updatedTags, err := r.repository.Read(r.ctx, domainTag) - r.NoError(err) - - for _, updatedTag := range updatedTags { - for idx, value := range updatedTag.TagValues { - r.NoError(err) - r.EqualValues(value.UpdatedAt, domainTag.TagValues[idx].UpdatedAt) - } - } - }) - - r.Run("should return nil and update tag if no error found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - domainTemplate := getTemplate() - err = r.templateRepository.Create(r.ctx, r.ns, domainTemplate) - r.NoError(err) - domainTag := getDomainTag() - - if err := r.repository.Create(r.ctx, r.ns, &domainTag); err != nil { - panic(err) - } - domainTag.TagValues = domainTag.TagValues[:1] - - actualError := r.repository.Update(r.ctx, &domainTag) - - r.NoError(actualError) - r.Len(domainTag.TagValues, 2) - }) -} - -func (r *TagRepositoryTestSuite) TestDelete() { - r.Run("should return error if asset id is empty", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - paramDomainTag := tag.Tag{ - AssetID: "", - } - - expectedErrorMsg := "asset id should not be empty" - - actualError := r.repository.Delete(r.ctx, paramDomainTag) - - r.EqualError(actualError, expectedErrorMsg) - }) - - r.Run("should delete tags related to the asset id and return no error if the asset id has one", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - domainTemplate := getTemplate() - err = r.templateRepository.Create(r.ctx, r.ns, domainTemplate) - r.NoError(err) - - domainTag := getDomainTag() - - if err := r.repository.Create(r.ctx, r.ns, &domainTag); err != nil { - r.T().Fatal(err) - } - - paramDomainTag := tag.Tag{ - AssetID: domainTag.AssetID, - } - - actualError := r.repository.Delete(r.ctx, paramDomainTag) - r.NoError(actualError) - - foundTags, err := r.repository.Read(r.ctx, tag.Tag{ - AssetID: paramDomainTag.AssetID, - }) - if err != nil { - r.T().Fatal(err) - } - - r.Empty(foundTags) - }) - - r.Run("should return error if template is not found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - var assetID = uuid.NewString() - var templateURN = "random-urn" - paramDomainTag := tag.Tag{ - AssetID: assetID, - TemplateURN: templateURN, - } - - err = r.repository.Delete(r.ctx, paramDomainTag) - r.ErrorIs(err, tag.TemplateNotFoundError{URN: templateURN}) - }) - - r.Run("should delete only the tag for asset id and template and return error if asset id has none", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - var assetID = uuid.NewString() - domainTemplate := getTemplate() - err = r.templateRepository.Create(r.ctx, r.ns, domainTemplate) - r.NoError(err) - - paramDomainTag := tag.Tag{ - AssetID: assetID, - TemplateURN: domainTemplate.URN, - } - - actualError := r.repository.Delete(r.ctx, paramDomainTag) - r.Error(actualError) - }) -} - -func getTemplate() *tag.Template { - return &tag.Template{ - URN: "governance_policy", - DisplayName: "Governance Policy", - Description: "Template that is mandatory to be used.", - Fields: []tag.Field{ - { - ID: 1, - URN: "classification", - DisplayName: "classification", - Description: "The classification of this asset", - DataType: "enumerated", - Required: true, - Options: []string{"Public", "Restricted"}, - }, - { - ID: 2, - URN: "admin_email", - DisplayName: "Admin Email", - Description: "Email of the admin of the asset.", - DataType: "string", - Required: true, - }, - }, - } -} - -func getDomainTag() tag.Tag { - return tag.Tag{ - AssetID: domainAssetID, - TemplateURN: "governance_policy", - TemplateDisplayName: "Governance Policy", - TemplateDescription: "Template that is mandatory to be used.", - TagValues: []tag.TagValue{ - { - FieldID: 1, - FieldValue: "Public", - FieldURN: "classification", - FieldDisplayName: "classification", - FieldDescription: "The classification of this asset", - FieldDataType: "enumerated", - FieldRequired: true, - FieldOptions: []string{"Public", "Restricted"}, - }, - { - FieldID: 2, - FieldValue: "dexter@raystack.io", - FieldURN: "admin_email", - FieldDisplayName: "Admin Email", - FieldDescription: "Email of the admin of the asset.", - FieldDataType: "string", - FieldRequired: true, - }, - }, - } -} - -func TestTagRepository(t *testing.T) { - suite.Run(t, &TagRepositoryTestSuite{}) -} diff --git a/store/postgres/tag_template_repository.go b/store/postgres/tag_template_repository.go deleted file mode 100644 index df1e919a..00000000 --- a/store/postgres/tag_template_repository.go +++ /dev/null @@ -1,321 +0,0 @@ -package postgres - -import ( - "context" - "database/sql" - "errors" - "fmt" - "github.com/raystack/compass/core/namespace" - "time" - - "github.com/jmoiron/sqlx" - "github.com/raystack/compass/core/tag" -) - -const ( - fieldOptionSeparator = "," -) - -var ( - errNilTemplate = errors.New("template is nil") -) - -// TagTemplateRepository is a type that manages template operation to the primary database -type TagTemplateRepository struct { - client *Client -} - -// Create inserts template to database -func (r *TagTemplateRepository) Create(ctx context.Context, ns *namespace.Namespace, templateDomain *tag.Template) error { - if templateDomain == nil { - return errNilTemplate - } - - templateModel := newTemplateModel(ns, templateDomain) - - timestamp := time.Now().UTC() - templateModel.CreatedAt = timestamp - templateModel.UpdatedAt = timestamp - - if err := r.client.RunWithinTx(ctx, func(tx *sqlx.Tx) error { - insertedTemplate := *templateModel - if err := insertTemplateToDBTx(ctx, tx, ns, &insertedTemplate); err != nil { - return err - } - - for _, field := range templateModel.Fields { - field.CreatedAt = templateModel.CreatedAt - field.UpdatedAt = templateModel.UpdatedAt - field.TemplateURN = templateModel.URN - - if err := insertFieldToDBTx(ctx, tx, &field); err != nil { - return err - } - - insertedTemplate.Fields = append(insertedTemplate.Fields, field) - } - *templateModel = insertedTemplate - return nil - }); err != nil { - return fmt.Errorf("failed to insert template: %w", err) - } - - *templateDomain = templateModel.toTemplate() - return nil -} - -// Read reads template from database by URN -func (r *TagTemplateRepository) Read(ctx context.Context, templateURN string) ([]tag.Template, error) { - templates := []tag.Template{} - var templatesFieldModels TagJoinTemplateFieldModels - - // return empty with nil error if not found - templatesFieldModels, err := r.readTemplatesByURNFromDB(ctx, templateURN) - if err != nil { - return nil, err - } - - templateModels := templatesFieldModels.toTemplateModels() - - for _, template := range templateModels { - templateDomain := template.toTemplate() - templates = append(templates, templateDomain) - } - return templates, nil -} - -// Read reads all template from database -func (r *TagTemplateRepository) ReadAll(ctx context.Context) ([]tag.Template, error) { - templates := []tag.Template{} - var templatesFieldModels TagJoinTemplateFieldModels - // return empty with nil error if not found - templatesFieldModels, err := r.readAllTemplatesFromDB(ctx) - if err != nil { - return nil, err - } - - templateModels := templatesFieldModels.toTemplateModels() - - for _, template := range templateModels { - templateDomain := template.toTemplate() - templates = append(templates, templateDomain) - } - return templates, nil -} - -// Update updates template into database -func (r *TagTemplateRepository) Update(ctx context.Context, ns *namespace.Namespace, targetURN string, templateDomain *tag.Template) error { - if templateDomain == nil { - return errNilTemplate - } - - templateModel := newTemplateModel(ns, templateDomain) - updatedTemplateModel := *templateModel - if err := r.client.RunWithinTx(ctx, func(tx *sqlx.Tx) error { - timestamp := time.Now().UTC() - - updatedTemplateModel.UpdatedAt = timestamp - if err := updateTemplateToDBTx(ctx, tx, targetURN, &updatedTemplateModel); err != nil { - return fmt.Errorf("failed to update a field: %w", err) - } - - for _, field := range templateModel.Fields { - field.TemplateURN = templateModel.URN - field.UpdatedAt = timestamp - - if field.ID == 0 { - field.CreatedAt = timestamp - field.TemplateURN = templateModel.URN - - if err := insertFieldToDBTx(ctx, tx, &field); err != nil { - return fmt.Errorf("failed to insert a field: %w", err) - } - - updatedTemplateModel.Fields = append(updatedTemplateModel.Fields, field) - continue - } - - if err := updateFieldToDBTx(ctx, tx, &field); err != nil { - return fmt.Errorf("failed to update a field: %w", err) - } - updatedTemplateModel.Fields = append(updatedTemplateModel.Fields, field) - } - - *templateModel = updatedTemplateModel - return nil - }); err != nil { - return fmt.Errorf("failed to update template: %w", err) - } - - *templateDomain = updatedTemplateModel.toTemplate() - - return nil -} - -// Delete deletes template and its fields from database -func (r *TagTemplateRepository) Delete(ctx context.Context, templateURN string) error { - res, err := r.client.ExecContext(ctx, ` - DELETE FROM - tag_templates - WHERE - urn = $1`, templateURN) - if err != nil { - return fmt.Errorf("failed to delete template with urn: %w", err) - } - - tmpRowsAffected, err := res.RowsAffected() - if err != nil { - return fmt.Errorf("failed to get row affected in deleting template: %w", err) - } - - if tmpRowsAffected == 0 { - return tag.TemplateNotFoundError{URN: templateURN} - } - return nil -} - -func insertTemplateToDBTx(ctx context.Context, tx *sqlx.Tx, ns *namespace.Namespace, templateModel *TagTemplateModel) error { - var insertedTemplate TagTemplateModel - if err := tx.QueryRowxContext(ctx, ` - INSERT INTO - tag_templates - (urn,display_name,description,created_at,updated_at,namespace_id) - VALUES - ($1,$2,$3,$4,$5,$6) - RETURNING * - `, - templateModel.URN, templateModel.DisplayName, templateModel.Description, - templateModel.CreatedAt, templateModel.UpdatedAt, ns.ID). - StructScan(&insertedTemplate); err != nil { - return fmt.Errorf("failed to insert a template: %w", err) - } - - *templateModel = insertedTemplate - return nil -} - -func insertFieldToDBTx(ctx context.Context, tx *sqlx.Tx, field *TagTemplateFieldModel) error { - var insertedField TagTemplateFieldModel - if err := tx.QueryRowxContext(ctx, ` - INSERT INTO - tag_template_fields - (urn, display_name, description, data_type, options, required, template_urn, created_at, updated_at, namespace_id) - VALUES - ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) - RETURNING * - `, - field.URN, field.DisplayName, field.Description, field.DataType, field.Options, field.Required, field.TemplateURN, - field.CreatedAt, field.UpdatedAt, field.NamespaceID). - StructScan(&insertedField); err != nil { - return fmt.Errorf("failed to insert a field: %w", err) - } - *field = insertedField - return nil -} - -func (r *TagTemplateRepository) readAllTemplatesFromDB(ctx context.Context) (TagJoinTemplateFieldModels, error) { - var templateFields TagJoinTemplateFieldModels - // return empty with nil error if not found - if err := r.client.SelectContext(ctx, &templateFields, ` - SELECT - t.urn as "tag_templates.urn", t.display_name as "tag_templates.display_name", t.description as "tag_templates.description", - t.created_at as "tag_templates.created_at", t.updated_at as "tag_templates.updated_at", - f.id as "tag_template_fields.id", f.urn as "tag_template_fields.urn", f.display_name as "tag_template_fields.display_name", f.description as "tag_template_fields.description", - f.data_type as "tag_template_fields.data_type", f.options as "tag_template_fields.options", f.required as "tag_template_fields.required", f.template_urn as "tag_template_fields.template_urn", - f.created_at as "tag_template_fields.created_at", f.updated_at as "tag_template_fields.updated_at" - FROM - tag_templates t - JOIN - tag_template_fields f - ON - f.template_urn = t.urn`); err != nil { - return nil, fmt.Errorf("tag_templates: failed to read all from DB %w", err) - } - - return templateFields, nil -} - -func (r *TagTemplateRepository) readTemplatesByURNFromDB(ctx context.Context, templateURN string) (TagJoinTemplateFieldModels, error) { - var templateFields TagJoinTemplateFieldModels - // return empty with nil error if not found - if err := r.client.SelectContext(ctx, &templateFields, ` - SELECT - t.urn as "tag_templates.urn", t.display_name as "tag_templates.display_name", t.description as "tag_templates.description", - t.created_at as "tag_templates.created_at", t.updated_at as "tag_templates.updated_at", - f.id as "tag_template_fields.id", f.urn as "tag_template_fields.urn", f.display_name as "tag_template_fields.display_name", f.description as "tag_template_fields.description", - f.data_type as "tag_template_fields.data_type", f.options as "tag_template_fields.options", f.required as "tag_template_fields.required", f.template_urn as "tag_template_fields.template_urn", - f.created_at as "tag_template_fields.created_at", f.updated_at as "tag_template_fields.updated_at" - FROM - tag_templates t - JOIN - tag_template_fields f - ON - f.template_urn = t.urn - WHERE - t.urn = $1`, templateURN); err != nil { - return nil, fmt.Errorf("tag_templates: failed to read from DB %w", err) - } - - return templateFields, nil -} - -func updateTemplateToDBTx(ctx context.Context, tx *sqlx.Tx, targetTemplateURN string, templateModel *TagTemplateModel) error { - var updatedTemplate TagTemplateModel - if err := tx.QueryRowxContext(ctx, ` - UPDATE - tag_templates - SET - urn = $1, display_name = $2, description = $3, updated_at = $4 - WHERE - urn = $5 - RETURNING *`, - templateModel.URN, templateModel.DisplayName, templateModel.Description, templateModel.UpdatedAt, targetTemplateURN). - StructScan(&updatedTemplate); err != nil { - // scan returns sql.ErrNoRows if no rows - if errors.Is(err, sql.ErrNoRows) { - return tag.TemplateNotFoundError{URN: templateModel.URN} - } - return fmt.Errorf("failed building update template sql: %w", err) - } - - *templateModel = updatedTemplate - return nil -} - -func updateFieldToDBTx(ctx context.Context, tx *sqlx.Tx, field *TagTemplateFieldModel) error { - var updatedField TagTemplateFieldModel - - if err := tx.QueryRowxContext(ctx, ` - UPDATE - tag_template_fields - SET - urn = $1, display_name = $2, description = $3, data_type = $4, options = $5, - required = $6, template_urn = $7, updated_at = $8 - WHERE - id = $9 AND template_urn = $7 - RETURNING *`, - field.URN, field.DisplayName, field.Description, field.DataType, field.Options, field.Required, - field.TemplateURN, field.UpdatedAt, field.ID). - StructScan(&updatedField); err != nil { - return fmt.Errorf("failed updating fields: %w", err) - } - - if updatedField.ID == 0 { - return errors.New("field not found when updating fields") - } - - *field = updatedField - return nil -} - -// NewTagTemplateRepository initializes template repository clients -// all methods in template repository uses passed by reference -// which will mutate the reference variable in method's argument -func NewTagTemplateRepository(c *Client) (*TagTemplateRepository, error) { - if c == nil { - return nil, errNilPostgresClient - } - return &TagTemplateRepository{ - client: c, - }, nil -} diff --git a/store/postgres/tag_template_repository_test.go b/store/postgres/tag_template_repository_test.go deleted file mode 100644 index aa140f13..00000000 --- a/store/postgres/tag_template_repository_test.go +++ /dev/null @@ -1,432 +0,0 @@ -package postgres_test - -import ( - "context" - "encoding/json" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/middleware" - "testing" - "time" - - "github.com/raystack/compass/core/tag" - "github.com/raystack/compass/store/postgres" - "github.com/ory/dockertest/v3" - "github.com/stretchr/testify/suite" -) - -type TagTemplateRepositoryTestSuite struct { - suite.Suite - ctx context.Context - client *postgres.Client - repository *postgres.TagTemplateRepository - pool *dockertest.Pool - resource *dockertest.Resource - ns *namespace.Namespace -} - -func (r *TagTemplateRepositoryTestSuite) SetupSuite() { - var err error - - r.client, r.pool, r.resource, err = newTestClient() - if err != nil { - r.T().Fatal(err) - } - r.ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "tenant", - State: namespace.SharedState, - Metadata: nil, - } - r.ctx = middleware.BuildContextWithNamespace(context.Background(), r.ns) - r.repository, err = postgres.NewTagTemplateRepository(r.client) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *TagTemplateRepositoryTestSuite) TearDownSuite() { - // Clean tests - err := r.client.Close() - if err != nil { - r.T().Fatal(err) - } - err = purgeDocker(r.pool, r.resource) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *TagTemplateRepositoryTestSuite) TestNewRepository() { - r.Run("should return repository and nil if postgres client is not nil", func() { - pgClient := &postgres.Client{} - - actualRepository, err := postgres.NewTagTemplateRepository(pgClient) - r.NotNil(actualRepository) - r.Nil(err) - }) -} - -func (r *TagTemplateRepositoryTestSuite) TestCreate() { - - r.Run("should return error if template is nil", func() { - var template *tag.Template = nil - - expectedErrorMsg := "template is nil" - - actualError := r.repository.Create(r.ctx, r.ns, template) - - r.EqualError(actualError, expectedErrorMsg) - }) - - r.Run("should return nil and insert new record if no error found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - - actualError := r.repository.Create(r.ctx, r.ns, &template) - r.NoError(actualError) - - var actualRecord tag.Template - templates, err := r.repository.Read(r.ctx, template.URN) - r.NoError(err) - - actualRecord = templates[0] - r.Equal(template.URN, actualRecord.URN) - r.Equal(template.DisplayName, actualRecord.DisplayName) - r.Equal(template.Description, actualRecord.Description) - r.Equal(len(template.Fields), len(actualRecord.Fields)) - r.Equal(template.Fields[0].DisplayName, actualRecord.Fields[0].DisplayName) - r.Equal(template.Fields[0].URN, actualRecord.Fields[0].URN) - }) - - r.Run("should return nil and update template", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - originalTemplate := r.getTemplate() - referenceTemplate := r.getTemplate() - - actualError := r.repository.Create(r.ctx, r.ns, &originalTemplate) - r.NoError(actualError) - - r.Equal(referenceTemplate.URN, originalTemplate.URN) - r.NotEqual(referenceTemplate.CreatedAt, originalTemplate.CreatedAt) - r.NotEqual(referenceTemplate.UpdatedAt, originalTemplate.UpdatedAt) - r.Equal(referenceTemplate.Fields[0].ID, originalTemplate.Fields[0].ID) - r.Equal(referenceTemplate.Fields[0].URN, originalTemplate.Fields[0].URN) - r.NotEqual(referenceTemplate.Fields[0].CreatedAt, originalTemplate.Fields[0].CreatedAt) - r.NotEqual(referenceTemplate.Fields[0].UpdatedAt, originalTemplate.Fields[0].UpdatedAt) - }) - - r.Run("should return error if encountered uncovered error", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - - if err := r.repository.Create(r.ctx, r.ns, &template); err != nil { - r.Error(err) - } - actualError := r.repository.Create(r.ctx, r.ns, &template) - - r.Error(actualError) - }) -} - -func (r *TagTemplateRepositoryTestSuite) TestRead() { - r.Run("should return empty and no error if no record found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - template := r.getTemplate() - - actualTemplate, actualError := r.repository.Read(r.ctx, template.URN) - - r.Empty(actualTemplate) - r.NoError(actualError) - }) - - r.Run("should return templates and nil if found any", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - if err := r.repository.Create(r.ctx, r.ns, &template); err != nil { - panic(err) - } - now := time.Now() - - expectedTemplate := []tag.Template{template} - r.updateTimeForTemplate(&expectedTemplate[0], now) - - actualTemplate, actualError := r.repository.Read(r.ctx, template.URN) - r.updateTimeForTemplate(&actualTemplate[0], now) - - r.EqualValues(expectedTemplate, actualTemplate) - r.NoError(actualError) - }) - r.Run("should return template with multiple fields if exist", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - - template.DisplayName = "Random Display" - template.Fields[0].DisplayName = "Another Random Display" - template.Fields = append(template.Fields, tag.Field{ - URN: "new_field", - DisplayName: "New Field", - Description: "This field is a new addition.", - DataType: "string", - }) - - err = r.repository.Create(r.ctx, r.ns, &template) - r.NoError(err) - - templates, err := r.repository.Read(r.ctx, template.URN) - - r.NoError(err) - r.Len(templates[0].Fields, 2) - r.Equal(template.DisplayName, templates[0].DisplayName) - r.Equal(template.UpdatedAt, templates[0].UpdatedAt) - }) -} - -func (r *TagTemplateRepositoryTestSuite) TestReadAll() { - r.Run("should return empty and no error if no record found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - actualTemplate, actualError := r.repository.ReadAll(r.ctx) - - r.Empty(actualTemplate) - r.NoError(actualError) - }) - - r.Run("should return templates and nil if found any", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - if err := r.repository.Create(r.ctx, r.ns, &template); err != nil { - panic(err) - } - now := time.Now() - - expectedTemplate := []tag.Template{template} - r.updateTimeForTemplate(&expectedTemplate[0], now) - - actualTemplate, actualError := r.repository.ReadAll(r.ctx) - r.updateTimeForTemplate(&actualTemplate[0], now) - - r.EqualValues(expectedTemplate, actualTemplate) - r.NoError(actualError) - }) - r.Run("should return template with multiple fields if exist", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - - template.DisplayName = "Random Display" - template.Fields[0].DisplayName = "Another Random Display" - template.Fields = append(template.Fields, tag.Field{ - URN: "new_field", - DisplayName: "New Field", - Description: "This field is a new addition.", - DataType: "string", - }) - - err = r.repository.Create(r.ctx, r.ns, &template) - r.NoError(err) - - templates, err := r.repository.ReadAll(r.ctx) - - r.NoError(err) - r.Len(templates[0].Fields, 2) - r.Equal(template.DisplayName, templates[0].DisplayName) - r.Equal(template.UpdatedAt, templates[0].UpdatedAt) - }) -} - -func (r *TagTemplateRepositoryTestSuite) TestUpdate() { - r.Run("should return error if template is nil", func() { - var template *tag.Template = nil - - expectedErrorMsg := "template is nil" - - actualError := r.repository.Update(r.ctx, r.ns, "", template) - - r.EqualError(actualError, expectedErrorMsg) - }) - - r.Run("should return error if record not found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - - actualError := r.repository.Update(r.ctx, r.ns, template.URN, &template) - - r.Error(actualError) - }) - - r.Run("should return nil and updated template if update is success", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - err = r.repository.Create(r.ctx, r.ns, &template) - r.NoError(err) - - template.DisplayName = "Random Display" - template.Fields[0].DisplayName = "Another Random Display" - template.Fields = append(template.Fields, tag.Field{ - URN: "new_field", - DisplayName: "New Field", - Description: "This field is a new addition.", - DataType: "string", - }) - - actualError := r.repository.Update(r.ctx, r.ns, template.URN, &template) - r.NoError(actualError) - - templates, err := r.repository.Read(r.ctx, template.URN) - r.NoError(err) - - recordModelTemplate := templates[0] - r.Len(recordModelTemplate.Fields, 2) - r.Equal(template.DisplayName, recordModelTemplate.DisplayName) - r.True(template.UpdatedAt.Equal(recordModelTemplate.UpdatedAt)) - - expectedFields, err := json.Marshal(recordModelTemplate.Fields) - r.NoError(err) - - actualFields, err := json.Marshal(template.Fields) - r.NoError(err) - - r.JSONEq(string(expectedFields), string(actualFields)) - }) - - r.Run("should return error if trying to update with conflicting existing template", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template1 := r.getTemplate() - template1.URN = "hello1" - if err := r.repository.Create(r.ctx, r.ns, &template1); err != nil { - panic(err) - } - template2 := r.getTemplate() - template2.URN = "hello2" - if err := r.repository.Create(r.ctx, r.ns, &template2); err != nil { - panic(err) - } - targetURN := template2.URN - template2.URN = "hello1" - - actualError := r.repository.Update(r.ctx, r.ns, targetURN, &template2) - - r.Error(actualError) - }) - - r.Run("should return error if trying to update with unrelated field", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - if err := r.repository.Create(r.ctx, r.ns, &template); err != nil { - panic(err) - } - template.Fields[0].ID = 2 - - actualError := r.repository.Update(r.ctx, r.ns, template.URN, &template) - - r.Error(actualError) - }) - - r.Run("should return error if trying to update with duplicated field", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - template.Fields = append(template.Fields, tag.Field{ - URN: "second_field", - DisplayName: "Second Field", - Description: "Random description for the second field.", - DataType: "string", - Required: false, - }) - - if err := r.repository.Create(r.ctx, r.ns, &template); err != nil { - panic(err) - } - - template.Fields[1].URN = template.Fields[0].URN - - actualError := r.repository.Update(r.ctx, r.ns, template.URN, &template) - - r.Error(actualError) - }) -} - -func (r *TagTemplateRepositoryTestSuite) TestDelete() { - r.Run("should return error if record not found", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - - err = r.repository.Delete(r.ctx, template.URN) - r.EqualError(err, "could not find template \"governance_policy\"") - }) - - r.Run("should return nil if record is deleted", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - template := r.getTemplate() - if err := r.repository.Create(r.ctx, r.ns, &template); err != nil { - panic(err) - } - - actualError := r.repository.Delete(r.ctx, template.URN) - r.NoError(actualError) - - templates, err := r.repository.Read(r.ctx, template.URN) - r.NoError(err) - r.Empty(templates) - }) -} - -func (r *TagTemplateRepositoryTestSuite) getTemplate() tag.Template { - return tag.Template{ - URN: "governance_policy", - DisplayName: "Governance Policy", - Description: "Template that is mandatory to be used.", - Fields: []tag.Field{ - { - ID: 1, - URN: "team_owner", - DisplayName: "Team Owner", - Description: "Owner of the resource.", - DataType: "enumerated", - Required: true, - Options: []string{"PIC", "Escalated"}, - }, - }, - } -} - -func (r *TagTemplateRepositoryTestSuite) updateTimeForTemplate(template *tag.Template, t time.Time) { - template.CreatedAt = t - template.UpdatedAt = t - for i := 0; i < len(template.Fields); i++ { - template.Fields[i].CreatedAt = t - template.Fields[i].UpdatedAt = t - } -} - -func TestTagTemplateRepository(t *testing.T) { - suite.Run(t, &TagTemplateRepositoryTestSuite{}) -} diff --git a/test/asset_test.go b/test/asset_test.go deleted file mode 100644 index e1ab1771..00000000 --- a/test/asset_test.go +++ /dev/null @@ -1,289 +0,0 @@ -//go:build e2e -// +build e2e - -package test - -import ( - "context" - "fmt" - "strings" - "testing" - - "github.com/google/uuid" - "github.com/raystack/compass/core/asset" - "github.com/stretchr/testify/suite" -) - -type AssetEndToEndTestSuite struct { - suite.Suite - ctx context.Context - client *Client -} - -func (r *AssetEndToEndTestSuite) SetupSuite() { - r.client = NewClient() -} - -func (r *AssetEndToEndTestSuite) TestAllNormalFlow() { - // create 5 assets, get all, get 1, get 1 asset version, patch 1 asset 2 times, get 1 asset version, get asset version v0.3 - assetIDs := []string{} - for i := 0; i < 5; i++ { - uniqueAssetURN := strings.ReplaceAll(uuid.NewString()+r.T().Name(), "/", "-") - uniqueName := strings.ReplaceAll(r.T().Name()+" "+fmt.Sprintf("%d", (i+1)), "/", "-") - ast := generateAsset(uniqueAssetURN, uniqueName) - id, err := r.client.PatchAsset(ast) - if err != nil { - r.T().Fatal(err) - } - assetIDs = append(assetIDs, id) - } - - // Get all assets - retreivedAssets, err := r.client.GetAllAssets() - if err != nil { - r.T().Fatal(err) - } - r.Len(retreivedAssets, 5) - - // GetAsset - sampleAsset, err := r.client.GetAnAsset(assetIDs[0]) - if err != nil { - r.T().Fatal(err) - } - r.Equal(sampleAsset.Version, "0.1") - // PatchAsset - descriptionV2 := "new description v0.2" - descriptionV3 := "new description v0.3" - sampleAsset.Description = descriptionV2 - id, err := r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(id, sampleAsset.ID) - - sampleAsset.Description = descriptionV3 - id, err = r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(id, sampleAsset.ID) - - // Get All Versions - assetVersions, err := r.client.GetAssetVersions(sampleAsset.ID) - if err != nil { - r.T().Fatal(err) - } - r.Len(assetVersions, 3) - - // Get Latest Version - sampleAsset, err = r.client.GetAnAsset(sampleAsset.ID) - if err != nil { - r.T().Fatal(err) - } - r.Equal(sampleAsset.Version, "0.3") - - // Get a specific Version - sampleAsset, err = r.client.GetAssetWithVersion(sampleAsset.ID, "0.3") - if err != nil { - r.T().Fatal(err) - } - r.Equal(sampleAsset.Description, descriptionV3) - r.Equal(sampleAsset.Version, "0.3") - -} - -func (r *AssetEndToEndTestSuite) TestPatchAssetsAllFields() { - uniqueAssetURN := strings.ReplaceAll(uuid.NewString()+r.T().Name(), "/", "-") - uniqueName := strings.ReplaceAll(r.T().Name(), "/", "-") - ast := generateAsset(uniqueAssetURN, uniqueName) - assetID, err := r.client.PatchAsset(ast) - if err != nil { - r.T().Fatal(err) - } - - // GetAsset - sampleAsset, err := r.client.GetAnAsset(assetID) - if err != nil { - r.T().Fatal(err) - } - r.Equal("0.1", sampleAsset.Version) - - // v0.2 PatchAsset field name - sampleAsset.Name = "new name" - id, err := r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(sampleAsset.ID, id) - - retrievedAsset, err := r.client.GetAnAsset(assetID) - if err != nil { - r.T().Fatal(err) - } - r.Equal("0.2", retrievedAsset.Version) - r.Equal("new name", retrievedAsset.Name) - - // v0.3 PatchAsset field data update data type - sampleAsset.Data["key1"] = 987 - id, err = r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(sampleAsset.ID, id) - - retrievedAsset, err = r.client.GetAnAsset(assetID) - if err != nil { - r.T().Fatal(err) - } - r.Equal("0.3", retrievedAsset.Version) - r.Equal(float64(987), retrievedAsset.Data["key1"]) - - // v0.4 PatchAsset field data update nested data type - sampleAsset.Data["key3"].(map[string]interface{})["key31"] = 987 - id, err = r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(id, sampleAsset.ID) - - retrievedAsset, err = r.client.GetAnAsset(assetID) - if err != nil { - r.T().Fatal(err) - } - r.Equal("0.4", retrievedAsset.Version) - r.Equal(float64(987), retrievedAsset.Data["key3"].(map[string]interface{})["key31"]) - - // v0.5 PatchAsset field data add new bool entry - sampleAsset.Data["key4"] = true - id, err = r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(sampleAsset.ID, id) - - retrievedAsset, err = r.client.GetAnAsset(assetID) - if err != nil { - r.T().Fatal(err) - } - r.Equal("0.5", retrievedAsset.Version) - r.Equal(true, retrievedAsset.Data["key4"]) - - // v0.6 PatchAsset field data remove entry - sampleAsset.Data["key2"] = nil - id, err = r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(sampleAsset.ID, id) - - retrievedAsset, err = r.client.GetAnAsset(assetID) - if err != nil { - r.T().Fatal(err) - } - r.Equal("0.6", retrievedAsset.Version) - r.Equal(nil, retrievedAsset.Data["key2"]) - - // v0.7 PatchAsset field data add new nested bool entry - sampleAsset.Data["key3"].(map[string]interface{})["key34"] = true - id, err = r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(sampleAsset.ID, id) - - retrievedAsset, err = r.client.GetAnAsset(assetID) - if err != nil { - r.T().Fatal(err) - } - r.Equal("0.7", retrievedAsset.Version) - r.Equal(true, retrievedAsset.Data["key3"].(map[string]interface{})["key34"]) - - // v0.8 PatchAsset field data remove entry - sampleAsset.Data["key3"].(map[string]interface{})["key32"] = nil - id, err = r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(sampleAsset.ID, id) - - retrievedAsset, err = r.client.GetAnAsset(assetID) - if err != nil { - r.T().Fatal(err) - } - r.Equal("0.8", retrievedAsset.Version) - r.Equal(nil, sampleAsset.Data["key3"].(map[string]interface{})["key32"]) - - // v0.9 PatchAsset field label update value - sampleAsset.Labels["label1"] = "new label 1" - id, err = r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(sampleAsset.ID, id) - - retrievedAsset, err = r.client.GetAnAsset(assetID) - if err != nil { - r.T().Fatal(err) - } - r.Equal("0.9", retrievedAsset.Version) - r.Equal("new label 1", retrievedAsset.Labels["label1"]) - - // v0.10 PatchAsset field label add new entry - sampleAsset.Labels["label4"] = "new label 4" - id, err = r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(sampleAsset.ID, id) - - retrievedAsset, err = r.client.GetAnAsset(assetID) - if err != nil { - r.T().Fatal(err) - } - r.Equal("0.10", retrievedAsset.Version) - r.Equal("new label 4", retrievedAsset.Labels["label4"]) - - // v0.11 PatchAsset field label remove entry - delete(sampleAsset.Labels, "label2") - id, err = r.client.PatchAsset(sampleAsset) - if err != nil { - r.T().Fatal(err) - } - r.Equal(id, sampleAsset.ID) - - retrievedAsset, err = r.client.GetAnAsset(assetID) - if err != nil { - r.T().Fatal(err) - } - r.Equal("0.11", retrievedAsset.Version) - _, ok := retrievedAsset.Labels["label2"] - r.False(ok) - -} - -func generateAsset(urn, name string) asset.Asset { - return asset.Asset{ - URN: urn, - Type: "table", - Service: "postgres", - Name: name, - Description: "description about " + name, - Data: map[string]interface{}{ - "key1": "value1", - "key2": 123, - "key3": map[string]interface{}{ - "key31": "value31", - "key32": 123, - }, - }, - Labels: map[string]string{ - "label1": "valuelabel1", - "label2": "valuelabel2", - "label3": "valuelabel3", - }, - } -} - -func TestAssetEndToEnd(t *testing.T) { - suite.Run(t, &AssetEndToEndTestSuite{}) -} diff --git a/test/helper_test.go b/test/helper_test.go deleted file mode 100644 index 178996a9..00000000 --- a/test/helper_test.go +++ /dev/null @@ -1,156 +0,0 @@ -//go:build e2e -// +build e2e - -package test - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - - "github.com/raystack/compass/core/asset" -) - -var ( - SERVER_HOST = "http://localhost:8080" - IDENTITY_HEADER_KEY_UUID = "Compass-User-UUID" - IDENTITY_HEADER_KEY_EMAIL = "Compass-User-Email" -) - -// Client is the http client implementation -type Client struct { - client *http.Client - host string - headers map[string]string -} - -func NewClient() *Client { - client := Client{ - client: &http.Client{}, - host: SERVER_HOST, - } - - return &client -} - -func (c *Client) PatchAsset(ast asset.Asset) (string, error) { - path := "/v1beta1/assets" - url := c.host + path - type requestStruct struct { - Asset asset.Asset `json:"asset"` - } - type responseStruct struct { - ID string - } - - var responsePayload responseStruct - requestPayload := requestStruct{ - Asset: ast, - } - err := c.makeRequest(http.MethodPatch, url, &requestPayload, &responsePayload) - if err != nil { - return "", err - } - - return responsePayload.ID, nil -} - -func (c *Client) GetAllAssets() ([]asset.Asset, error) { - path := "/v1beta1/assets?size=5" - url := c.host + path - type responseStruct struct { - Data []asset.Asset - } - - var responsePayload responseStruct - err := c.makeRequest(http.MethodGet, url, nil, &responsePayload) - if err != nil { - return nil, err - } - return responsePayload.Data, nil -} - -func (c *Client) GetAnAsset(id string) (asset.Asset, error) { - path := "/v1beta1/assets/" + id - url := c.host + path - type responseStruct struct { - Data asset.Asset `json:"data"` - } - - var responsePayload responseStruct - err := c.makeRequest(http.MethodGet, url, nil, &responsePayload) - if err != nil { - return asset.Asset{}, err - } - return responsePayload.Data, nil -} - -func (c *Client) GetAssetVersions(id string) ([]asset.Asset, error) { - path := "/v1beta1/assets/" + id + "/versions" - url := c.host + path - type responseStruct struct { - Data []asset.Asset `json:"data"` - } - - var responsePayload responseStruct - err := c.makeRequest(http.MethodGet, url, nil, &responsePayload) - if err != nil { - return nil, err - } - return responsePayload.Data, nil -} - -func (c *Client) GetAssetWithVersion(id, version string) (asset.Asset, error) { - path := "/v1beta1/assets/" + id + "/versions/" + version - url := c.host + path - type responseStruct struct { - Data asset.Asset `json:"data"` - } - - var responsePayload responseStruct - err := c.makeRequest(http.MethodGet, url, nil, &responsePayload) - if err != nil { - return asset.Asset{}, err - } - return responsePayload.Data, nil -} - -func (c *Client) makeRequest(method, url string, payload interface{}, data interface{}) (err error) { - jsonBytes, err := json.Marshal(payload) - if err != nil { - return fmt.Errorf("failed to encode the payload JSON: %w", err) - } - - req, err := http.NewRequest(method, url, bytes.NewBuffer(jsonBytes)) - if err != nil { - return fmt.Errorf("failed to create request: %w", err) - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json") - req.Header.Set(IDENTITY_HEADER_KEY_UUID, "compassendtoendtest@raystack.io") - req.Header.Set(IDENTITY_HEADER_KEY_EMAIL, "compassendtoendtest@raystack.io") - - for key, value := range c.headers { - req.Header.Set(key, value) - } - - res, err := c.client.Do(req) - if err != nil { - return fmt.Errorf("failed to generate response") - } - - bytes, err := ioutil.ReadAll(res.Body) - if err != nil { - return fmt.Errorf("failed to read response body") - } - if res.StatusCode >= 300 { - return fmt.Errorf("getting %d status code, body: %s", res.StatusCode, string(bytes)) - } - - if err = json.Unmarshal(bytes, &data); err != nil { - return fmt.Errorf("failed to parse: %s, err: %w", string(bytes), err) - } - return -} From 376ff9f9a3df4eeb1c164f72e3ce6f8f457b1164 Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 29 Mar 2026 02:06:45 -0500 Subject: [PATCH 04/10] refactor: cleanup stale deps, fix namespace service, add entity tests - go mod tidy: removed unused ES and other stale dependencies - Namespace service: nil-safe DiscoveryRepository (ES removed) - Deleted stale integration tests (postgres, user, namespace repo tests that depended on deleted test infrastructure) - Fixed last 2 "asset" string references in star errors and CLI - Added entity unit tests (11 tests): - Type validation (open type system) - Entity.IsCurrent temporal check - Reciprocal Rank Fusion (empty, single, multi-list) - Service: Upsert, GetByURN, Delete, GetAll, GetTypes, Search --- cli/root.go | 2 +- core/entity/entity_test.go | 46 ++++ core/entity/search_test.go | 53 ++++ core/entity/service_test.go | 178 ++++++++++++ core/namespace/service.go | 6 +- core/star/errors.go | 2 +- go.mod | 15 +- go.sum | 18 -- store/postgres/namespace_repository_test.go | 197 -------------- store/postgres/user_model_test.go | 59 ---- store/postgres/user_repository_test.go | 285 -------------------- 11 files changed, 286 insertions(+), 575 deletions(-) create mode 100644 core/entity/entity_test.go create mode 100644 core/entity/search_test.go create mode 100644 core/entity/service_test.go delete mode 100644 store/postgres/namespace_repository_test.go delete mode 100644 store/postgres/user_model_test.go delete mode 100644 store/postgres/user_repository_test.go diff --git a/cli/root.go b/cli/root.go index b16227fb..27d208fc 100644 --- a/cli/root.go +++ b/cli/root.go @@ -16,7 +16,7 @@ var ( SilenceErrors: true, SilenceUsage: true, Example: heredoc.Doc(` - $ compass asset + $ compass entity $ compass search $ compass server `), diff --git a/core/entity/entity_test.go b/core/entity/entity_test.go new file mode 100644 index 00000000..041f9e17 --- /dev/null +++ b/core/entity/entity_test.go @@ -0,0 +1,46 @@ +package entity + +import ( + "testing" + "time" +) + +func TestType_IsValid(t *testing.T) { + tests := []struct { + name string + typ Type + want bool + }{ + {"empty string is invalid", "", false}, + {"table is valid", TypeTable, true}, + {"custom type is valid", Type("satellite"), true}, + {"any non-empty string is valid", Type("anything"), true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.typ.IsValid(); got != tt.want { + t.Errorf("Type.IsValid() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestType_String(t *testing.T) { + if got := TypeTable.String(); got != "table" { + t.Errorf("Type.String() = %q, want %q", got, "table") + } +} + +func TestEntity_IsCurrent(t *testing.T) { + now := time.Now() + + current := Entity{ValidTo: nil} + if !current.IsCurrent() { + t.Error("entity with nil ValidTo should be current") + } + + expired := Entity{ValidTo: &now} + if expired.IsCurrent() { + t.Error("entity with non-nil ValidTo should not be current") + } +} diff --git a/core/entity/search_test.go b/core/entity/search_test.go new file mode 100644 index 00000000..ab3528d2 --- /dev/null +++ b/core/entity/search_test.go @@ -0,0 +1,53 @@ +package entity + +import ( + "testing" +) + +func TestReciprocalRankFusion(t *testing.T) { + list1 := []SearchResult{ + {URN: "a", Name: "Alpha"}, + {URN: "b", Name: "Beta"}, + {URN: "c", Name: "Charlie"}, + } + list2 := []SearchResult{ + {URN: "b", Name: "Beta"}, + {URN: "d", Name: "Delta"}, + {URN: "a", Name: "Alpha"}, + } + + fused := reciprocalRankFusion(list1, list2) + + if len(fused) != 4 { + t.Fatalf("expected 4 results, got %d", len(fused)) + } + + // "a" and "b" appear in both lists, should be ranked higher + // "b" is rank 2 in list1 and rank 1 in list2 → strong + // "a" is rank 1 in list1 and rank 3 in list2 → strong + topTwo := map[string]bool{fused[0].URN: true, fused[1].URN: true} + if !topTwo["a"] || !topTwo["b"] { + t.Errorf("expected a and b in top 2, got %s and %s", fused[0].URN, fused[1].URN) + } +} + +func TestReciprocalRankFusion_EmptyLists(t *testing.T) { + fused := reciprocalRankFusion(nil, nil) + if len(fused) != 0 { + t.Fatalf("expected 0 results, got %d", len(fused)) + } +} + +func TestReciprocalRankFusion_SingleList(t *testing.T) { + list := []SearchResult{ + {URN: "a"}, + {URN: "b"}, + } + fused := reciprocalRankFusion(list) + if len(fused) != 2 { + t.Fatalf("expected 2 results, got %d", len(fused)) + } + if fused[0].URN != "a" { + t.Errorf("expected first result to be 'a', got %q", fused[0].URN) + } +} diff --git a/core/entity/service_test.go b/core/entity/service_test.go new file mode 100644 index 00000000..78f7570c --- /dev/null +++ b/core/entity/service_test.go @@ -0,0 +1,178 @@ +package entity + +import ( + "context" + "database/sql" + "testing" + "time" + + "github.com/raystack/compass/core/namespace" +) + +// mockRepo is a simple in-memory entity repository for testing. +type mockRepo struct { + entities map[string]Entity +} + +func newMockRepo() *mockRepo { + return &mockRepo{entities: make(map[string]Entity)} +} + +func (m *mockRepo) Upsert(_ context.Context, _ *namespace.Namespace, ent *Entity) (string, error) { + id := ent.URN + ent.ID = id + ent.CreatedAt = time.Now() + ent.UpdatedAt = time.Now() + m.entities[id] = *ent + return id, nil +} + +func (m *mockRepo) GetByURN(_ context.Context, _ *namespace.Namespace, urn string) (Entity, error) { + if e, ok := m.entities[urn]; ok { + return e, nil + } + return Entity{}, sql.ErrNoRows +} + +func (m *mockRepo) GetByID(_ context.Context, id string) (Entity, error) { + for _, e := range m.entities { + if e.ID == id { + return e, nil + } + } + return Entity{}, sql.ErrNoRows +} + +func (m *mockRepo) GetAll(_ context.Context, _ *namespace.Namespace, _ Filter) ([]Entity, error) { + var result []Entity + for _, e := range m.entities { + result = append(result, e) + } + return result, nil +} + +func (m *mockRepo) GetCount(_ context.Context, _ *namespace.Namespace, _ Filter) (int, error) { + return len(m.entities), nil +} + +func (m *mockRepo) GetTypes(_ context.Context, _ *namespace.Namespace) (map[Type]int, error) { + types := make(map[Type]int) + for _, e := range m.entities { + types[e.Type]++ + } + return types, nil +} + +func (m *mockRepo) Delete(_ context.Context, _ *namespace.Namespace, urn string) error { + if _, ok := m.entities[urn]; !ok { + return sql.ErrNoRows + } + delete(m.entities, urn) + return nil +} + +func TestService_UpsertAndGet(t *testing.T) { + repo := newMockRepo() + svc := NewService(repo, nil, nil) + ctx := context.Background() + ns := namespace.DefaultNamespace + + ent := &Entity{ + URN: "urn:table:test", + Type: TypeTable, + Name: "test_table", + Source: "bigquery", + } + + id, err := svc.Upsert(ctx, ns, ent) + if err != nil { + t.Fatalf("Upsert failed: %v", err) + } + if id == "" { + t.Fatal("expected non-empty ID") + } + + got, err := svc.GetByURN(ctx, ns, "urn:table:test") + if err != nil { + t.Fatalf("GetByURN failed: %v", err) + } + if got.Name != "test_table" { + t.Errorf("expected name 'test_table', got %q", got.Name) + } + if got.Source != "bigquery" { + t.Errorf("expected source 'bigquery', got %q", got.Source) + } +} + +func TestService_Delete(t *testing.T) { + repo := newMockRepo() + svc := NewService(repo, nil, nil) + ctx := context.Background() + ns := namespace.DefaultNamespace + + svc.Upsert(ctx, ns, &Entity{URN: "urn:x", Type: TypeJob, Name: "x"}) + + err := svc.Delete(ctx, ns, "urn:x") + if err != nil { + t.Fatalf("Delete failed: %v", err) + } + + _, err = svc.GetByURN(ctx, ns, "urn:x") + if err == nil { + t.Error("expected error after delete, got nil") + } +} + +func TestService_GetAll(t *testing.T) { + repo := newMockRepo() + svc := NewService(repo, nil, nil) + ctx := context.Background() + ns := namespace.DefaultNamespace + + svc.Upsert(ctx, ns, &Entity{URN: "urn:a", Type: TypeTable, Name: "a"}) + svc.Upsert(ctx, ns, &Entity{URN: "urn:b", Type: TypeJob, Name: "b"}) + + entities, count, err := svc.GetAll(ctx, ns, Filter{}) + if err != nil { + t.Fatalf("GetAll failed: %v", err) + } + if count != 2 { + t.Errorf("expected count 2, got %d", count) + } + if len(entities) != 2 { + t.Errorf("expected 2 entities, got %d", len(entities)) + } +} + +func TestService_GetTypes(t *testing.T) { + repo := newMockRepo() + svc := NewService(repo, nil, nil) + ctx := context.Background() + ns := namespace.DefaultNamespace + + svc.Upsert(ctx, ns, &Entity{URN: "urn:a", Type: TypeTable, Name: "a"}) + svc.Upsert(ctx, ns, &Entity{URN: "urn:b", Type: TypeTable, Name: "b"}) + svc.Upsert(ctx, ns, &Entity{URN: "urn:c", Type: TypeJob, Name: "c"}) + + types, err := svc.GetTypes(ctx, ns) + if err != nil { + t.Fatalf("GetTypes failed: %v", err) + } + if types[TypeTable] != 2 { + t.Errorf("expected 2 tables, got %d", types[TypeTable]) + } + if types[TypeJob] != 1 { + t.Errorf("expected 1 job, got %d", types[TypeJob]) + } +} + +func TestService_Search_NilRepos(t *testing.T) { + svc := NewService(newMockRepo(), nil, nil) + results, err := svc.Search(context.Background(), SearchConfig{Text: "test"}) + if err != nil { + t.Fatalf("Search with nil repos should not error: %v", err) + } + if results != nil { + t.Errorf("expected nil results, got %v", results) + } +} diff --git a/core/namespace/service.go b/core/namespace/service.go index f352e6cf..d6c7d73e 100644 --- a/core/namespace/service.go +++ b/core/namespace/service.go @@ -26,8 +26,10 @@ func (s Service) Create(ctx context.Context, namespace *Namespace) (string, erro if err != nil { return "", err } - if err := s.discoveryRepo.CreateNamespace(ctx, namespace); err != nil { - return "", err + if s.discoveryRepo != nil { + if err := s.discoveryRepo.CreateNamespace(ctx, namespace); err != nil { + return "", err + } } return id, nil } diff --git a/core/star/errors.go b/core/star/errors.go index 851c9a3e..923f89bb 100644 --- a/core/star/errors.go +++ b/core/star/errors.go @@ -52,7 +52,7 @@ type InvalidError struct { func (e InvalidError) Error() string { fields := []string{"invalid"} if e.EntityID != "" { - fields = append(fields, fmt.Sprintf("asset id \"%s\"", e.EntityID)) + fields = append(fields, fmt.Sprintf("entity id \"%s\"", e.EntityID)) } if e.UserID != "" { fields = append(fields, fmt.Sprintf("user id \"%s\"", e.UserID)) diff --git a/go.mod b/go.mod index 8ff15abe..846b12a2 100644 --- a/go.mod +++ b/go.mod @@ -12,25 +12,17 @@ require ( connectrpc.com/otelconnect v0.7.1 connectrpc.com/validate v0.6.0 github.com/MakeNowJust/heredoc v1.0.0 - github.com/Masterminds/semver/v3 v3.4.0 github.com/Masterminds/squirrel v1.5.4 - github.com/elastic/go-elasticsearch/v8 v8.17.1 - github.com/go-playground/locales v0.14.1 - github.com/go-playground/universal-translator v0.18.1 github.com/go-playground/validator/v10 v10.30.1 github.com/golang-migrate/migrate/v4 v4.19.1 - github.com/golang-module/carbon/v2 v2.6.9 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6 github.com/jackc/pgx/v5 v5.9.1 github.com/jmoiron/sqlx v1.4.0 github.com/lestrrat-go/jwx/v2 v2.1.6 - github.com/lib/pq v1.12.0 github.com/mark3labs/mcp-go v0.46.0 github.com/ory/dockertest/v3 v3.12.0 - github.com/peterbourgon/mergemap v0.0.1 - github.com/r3labs/diff/v3 v3.0.2 github.com/raystack/salt v0.7.0 github.com/rs/cors v1.11.1 github.com/spf13/cobra v1.10.2 @@ -127,12 +119,12 @@ require ( github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/dromara/carbon/v2 v2.6.9 // indirect - github.com/elastic/elastic-transport-go/v8 v8.6.1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.12 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator v9.31.0+incompatible // indirect github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/google/cel-go v0.26.1 // indirect @@ -140,6 +132,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/lib/pq v1.12.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/sys/user v0.3.0 // indirect @@ -151,8 +144,6 @@ require ( github.com/spf13/viper v1.19.0 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect - github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect diff --git a/go.sum b/go.sum index aa4a3369..1bd1e8f9 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= -github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= -github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= @@ -89,12 +87,6 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dromara/carbon/v2 v2.6.9 h1:kx4D7qqLmNkKRLYo/2n1owtu/A1hfPs4WTGYC2tUFFA= -github.com/dromara/carbon/v2 v2.6.9/go.mod h1:7GXqCUplwN1s1b4whGk2zX4+g4CMCoDIZzmjlyt0vLY= -github.com/elastic/elastic-transport-go/v8 v8.6.1 h1:h2jQRqH6eLGiBSN4eZbQnJLtL4bC5b4lfVFRjw2R4e4= -github.com/elastic/elastic-transport-go/v8 v8.6.1/go.mod h1:YLHer5cj0csTzNFXoNQ8qhtGY1GTvSqPnKWKaqQE3Hk= -github.com/elastic/go-elasticsearch/v8 v8.17.1 h1:bOXChDoCMB4TIwwGqKd031U8OXssmWLT3UrAr9EGs3Q= -github.com/elastic/go-elasticsearch/v8 v8.17.1/go.mod h1:MVJCtL+gJJ7x5jFeUmA20O7rvipX8GcQmo5iBcmaJn4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= @@ -131,8 +123,6 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA= github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE= -github.com/golang-module/carbon/v2 v2.6.9 h1:GtDPA0O5qaszAPs51whhpimtt3FEEeM90gRBuyWR1W4= -github.com/golang-module/carbon/v2 v2.6.9/go.mod h1:2JsYhwO7UPnUr+1hfsELAP9qjgIWzNuEz89tA1v4sY0= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ= @@ -257,16 +247,12 @@ github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCy github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= -github.com/peterbourgon/mergemap v0.0.1 h1:5/brtSACv34REV0xoYjPQ8JXZnx3nurGt6WInLRwqX4= -github.com/peterbourgon/mergemap v0.0.1/go.mod h1:jQyRpOpE/KbvPc0VKXjAqctYglwUO5W6zAcGcFfbvlo= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/r3labs/diff/v3 v3.0.2 h1:yVuxAY1V6MeM4+HNur92xkS39kB/N+cFi2hMkY06BbA= -github.com/r3labs/diff/v3 v3.0.2/go.mod h1:Cy542hv0BAEmhDYWtGxXRQ4kqRsVIcEjG9gChUlTmkw= github.com/raystack/salt v0.7.0 h1:5w9U0qYLwMIgz0dEecmHnv6LZRFuC/UMnthtRawHrV8= github.com/raystack/salt v0.7.0/go.mod h1:3f9NBwwtuniW5xOsyQ3ntcugFVTFDDZBqHw6rX6+8w4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -322,10 +308,6 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= -github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= -github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= -github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= diff --git a/store/postgres/namespace_repository_test.go b/store/postgres/namespace_repository_test.go deleted file mode 100644 index 7af68f26..00000000 --- a/store/postgres/namespace_repository_test.go +++ /dev/null @@ -1,197 +0,0 @@ -package postgres_test - -import ( - "context" - "github.com/google/uuid" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/store/postgres" - "github.com/ory/dockertest/v3" - "github.com/stretchr/testify/suite" - "testing" -) - -type NamespaceRepositoryTestSuite struct { - suite.Suite - ctx context.Context - client *postgres.Client - pool *dockertest.Pool - resource *dockertest.Resource - repository *postgres.NamespaceRepository - ns *namespace.Namespace -} - -func (r *NamespaceRepositoryTestSuite) SetupSuite() { - var err error - r.ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.SharedState, - Metadata: nil, - } - - r.client, r.pool, r.resource, err = newTestClient() - if err != nil { - r.T().Fatal(err) - } - - r.ctx = context.TODO() - r.repository = postgres.NewNamespaceRepository(r.client) -} - -func (r *NamespaceRepositoryTestSuite) TearDownSuite() { - // Clean tests - err := r.client.Close() - if err != nil { - r.T().Fatal(err) - } - err = purgeDocker(r.pool, r.resource) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *NamespaceRepositoryTestSuite) SetupTest() { -} - -func (r *NamespaceRepositoryTestSuite) TearDownTest() { -} - -func (r *NamespaceRepositoryTestSuite) cleanup() error { - queries := []string{ - "TRUNCATE TABLE namespaces CASCADE", - } - return r.client.ExecQueries(r.ctx, queries) -} - -func (r *NamespaceRepositoryTestSuite) TestCreate() { - r.Run("should fail to create a new namespace if name is empty", func() { - _ = r.cleanup() - _, err := r.repository.Create(r.ctx, &namespace.Namespace{ - State: namespace.SharedState, - Metadata: nil, - }) - r.Error(err) - }) - - r.Run("should create a new namespace successfully", func() { - _ = r.cleanup() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.SharedState, - Metadata: map[string]interface{}{ - "hello": "world", - }, - } - id, err := r.repository.Create(r.ctx, ns) - r.NoError(err) - r.Equal(ns.ID.String(), id) - fetched, err := r.repository.GetByName(r.ctx, ns.Name) - r.NoError(err) - r.EqualValues(ns, fetched) - }) - - r.Run("should fail to insert duplicate namespace", func() { - _ = r.cleanup() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.SharedState, - Metadata: map[string]interface{}{ - "hello": "world", - }, - } - _, err := r.repository.Create(r.ctx, ns) - r.NoError(err) - _, err = r.repository.Create(r.ctx, ns) - r.Error(err) - }) -} - -func (r *NamespaceRepositoryTestSuite) TestList() { - r.Run("should return list of namespaces", func() { - _ = r.cleanup() - ns1 := &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.SharedState, - Metadata: map[string]interface{}{ - "hello": "world", - }, - } - ns2 := &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella-2", - State: namespace.SharedState, - Metadata: map[string]interface{}{ - "hello": "world-2", - }, - } - _, err := r.repository.Create(r.ctx, ns1) - r.NoError(err) - _, err = r.repository.Create(r.ctx, ns2) - r.NoError(err) - - nss, err := r.repository.List(r.ctx) - r.NoError(err) - r.Contains(nss, ns1) - r.Contains(nss, ns2) - }) -} - -func (r *NamespaceRepositoryTestSuite) TestGetByID() { - r.Run("should fetch namespace by id successfully", func() { - _ = r.cleanup() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.SharedState, - Metadata: map[string]interface{}{ - "hello": "world", - }, - } - id, err := r.repository.Create(r.ctx, ns) - r.NoError(err) - r.Equal(ns.ID.String(), id) - fetched, err := r.repository.GetByID(r.ctx, ns.ID) - r.NoError(err) - r.EqualValues(ns, fetched) - }) -} - -func (r *NamespaceRepositoryTestSuite) TestUpdate() { - r.Run("should update an existing namespace successfully", func() { - _ = r.cleanup() - ns := &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.SharedState, - Metadata: map[string]interface{}{ - "hello": "world", - }, - } - id, err := r.repository.Create(r.ctx, ns) - r.NoError(err) - r.Equal(ns.ID.String(), id) - - nsUpdated := &namespace.Namespace{ - ID: ns.ID, - Name: ns.Name, - State: namespace.SharedState, - Metadata: map[string]interface{}{ - "hello": "xworldx", - "bye": "world", - }, - } - err = r.repository.Update(r.ctx, nsUpdated) - r.NoError(err) - - fetched, err := r.repository.GetByID(r.ctx, nsUpdated.ID) - r.NoError(err) - r.EqualValues(nsUpdated, fetched) - }) -} - -func TestNamespaceRepository(t *testing.T) { - suite.Run(t, &NamespaceRepositoryTestSuite{}) -} diff --git a/store/postgres/user_model_test.go b/store/postgres/user_model_test.go deleted file mode 100644 index 6a1da202..00000000 --- a/store/postgres/user_model_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package postgres - -import ( - "database/sql" - "testing" - "time" - - "github.com/google/uuid" - "github.com/raystack/compass/core/user" - "github.com/stretchr/testify/assert" -) - -func TestUserModel(t *testing.T) { - - t.Run("should return user domain entitiy", func(t *testing.T) { - someUUID := uuid.NewString() - timestamp := time.Now().UTC() - um := UserModel{ - ID: sql.NullString{String: "12", Valid: true}, - UUID: sql.NullString{String: someUUID, Valid: true}, - Email: sql.NullString{String: "user@raystack.io", Valid: true}, - Provider: sql.NullString{String: "compass", Valid: true}, - CreatedAt: sql.NullTime{Time: timestamp, Valid: true}, - UpdatedAt: sql.NullTime{Time: timestamp, Valid: true}, - } - - ud := um.toUser() - - assert.Equal(t, um.ID.String, ud.ID) - assert.Equal(t, um.UUID.String, ud.UUID) - assert.Equal(t, um.Email.String, ud.Email) - assert.Equal(t, um.Provider.String, ud.Provider) - assert.True(t, um.CreatedAt.Time.Equal(ud.CreatedAt)) - assert.True(t, um.UpdatedAt.Time.Equal(ud.UpdatedAt)) - }) - - t.Run("should properly create user model from user", func(t *testing.T) { - someUUID := uuid.NewString() - timestamp := time.Now().UTC() - - ud := &user.User{ - ID: "12", - UUID: someUUID, - Email: "user@raystack.io", - Provider: "compass", - CreatedAt: timestamp, - UpdatedAt: timestamp, - } - - um := newUserModel(ud) - - assert.Equal(t, um.ID.String, ud.ID) - assert.Equal(t, um.UUID.String, ud.UUID) - assert.Equal(t, um.Email.String, ud.Email) - assert.Equal(t, um.Provider.String, ud.Provider) - assert.True(t, um.CreatedAt.Time.Equal(ud.CreatedAt)) - assert.True(t, um.UpdatedAt.Time.Equal(ud.UpdatedAt)) - }) -} diff --git a/store/postgres/user_repository_test.go b/store/postgres/user_repository_test.go deleted file mode 100644 index 65383460..00000000 --- a/store/postgres/user_repository_test.go +++ /dev/null @@ -1,285 +0,0 @@ -package postgres_test - -import ( - "context" - "fmt" - "github.com/raystack/compass/core/namespace" - "github.com/raystack/compass/internal/middleware" - "testing" - - "github.com/google/uuid" - "github.com/jmoiron/sqlx" - "github.com/raystack/compass/core/user" - "github.com/raystack/compass/store/postgres" - "github.com/ory/dockertest/v3" - "github.com/stretchr/testify/suite" -) - -type UserRepositoryTestSuite struct { - suite.Suite - ctx context.Context - client *postgres.Client - pool *dockertest.Pool - resource *dockertest.Resource - repository *postgres.UserRepository - ns *namespace.Namespace -} - -func (r *UserRepositoryTestSuite) SetupSuite() { - var err error - - r.client, r.pool, r.resource, err = newTestClient() - if err != nil { - r.T().Fatal(err) - } - r.ns = &namespace.Namespace{ - ID: uuid.New(), - Name: "umbrella", - State: namespace.SharedState, - Metadata: nil, - } - r.ctx = middleware.BuildContextWithNamespace(context.Background(), r.ns) - r.repository, err = postgres.NewUserRepository(r.client) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *UserRepositoryTestSuite) TearDownSuite() { - // Clean tests - err := r.client.Close() - if err != nil { - r.T().Fatal(err) - } - err = purgeDocker(r.pool, r.resource) - if err != nil { - r.T().Fatal(err) - } -} - -func (r *UserRepositoryTestSuite) insertEmail(email string) error { - query := fmt.Sprintf("insert into users (email) values ('%s')", email) - if err := r.client.ExecQueries(context.Background(), []string{ - query, - }); err != nil { - return err - } - return nil -} - -func (r *UserRepositoryTestSuite) TestCreate() { - r.Run("return no error if succesfully create user", func() { - user := getUser("user@raystack.io") - id, err := r.repository.Create(r.ctx, r.ns, user) - r.NotEmpty(id) - r.NoError(err) - }) - - r.Run("return ErrNoUserInformation if user is nil", func() { - id, err := r.repository.Create(r.ctx, r.ns, nil) - r.ErrorIs(err, user.ErrNoUserInformation) - r.Empty(id) - }) - - r.Run("return ErrDuplicateRecord if user is already exist", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - ud := getUser("user@raystack.io") - id, err := r.repository.Create(r.ctx, r.ns, ud) - r.NoError(err) - r.NotEmpty(id) - - id, err = r.repository.Create(r.ctx, r.ns, ud) - r.ErrorAs(err, new(user.DuplicateRecordError)) - r.Empty(id) - }) -} - -func (r *UserRepositoryTestSuite) TestCreateWithTx() { - validUserWithoutUUID := &user.User{ - Email: "userWithTx@raystack.io", - Provider: "compass", - } - validUserWithoutEmail := &user.User{ - UUID: "a-uuid", - Provider: "compass", - } - r.Run("return no error if succesfully create user without uuid", func() { - var id string - err := r.client.RunWithinTx(r.ctx, func(tx *sqlx.Tx) error { - var err error - id, err = r.repository.CreateWithTx(r.ctx, tx, r.ns, validUserWithoutUUID) - return err - }) - r.NotEmpty(id) - r.NoError(err) - }) - - r.Run("return no error if succesfully create user without email", func() { - var id string - err := r.client.RunWithinTx(r.ctx, func(tx *sqlx.Tx) error { - var err error - id, err = r.repository.CreateWithTx(r.ctx, tx, r.ns, validUserWithoutEmail) - return err - }) - r.NotEmpty(id) - r.NoError(err) - }) - - r.Run("return ErrNilUser if user is nil", func() { - var id string - err := r.client.RunWithinTx(r.ctx, func(tx *sqlx.Tx) error { - var err error - id, err = r.repository.CreateWithTx(r.ctx, tx, r.ns, nil) - return err - }) - r.ErrorIs(err, user.ErrNoUserInformation) - r.Empty(id) - }) - - r.Run("return ErrDuplicateRecord if user is already exist", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - id, err := r.repository.Create(r.ctx, r.ns, validUserWithoutUUID) - r.NoError(err) - r.NotEmpty(id) - - err = r.client.RunWithinTx(r.ctx, func(tx *sqlx.Tx) error { - var err error - id, err = r.repository.CreateWithTx(r.ctx, tx, r.ns, validUserWithoutUUID) - return err - }) - r.ErrorAs(err, new(user.DuplicateRecordError)) - r.Empty(id) - }) -} - -func (r *UserRepositoryTestSuite) TestGetBy() { - r.Run("by email", func() { - r.Run("return empty string and ErrNotFound if email not found in DB", func() { - usr, err := r.repository.GetByEmail(r.ctx, "random") - r.ErrorAs(err, new(user.NotFoundError)) - r.Empty(usr) - }) - - r.Run("return non empty user if email found in DB", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - user := getUser("use-getbyemail@raystack.io") - id, err := r.repository.Create(r.ctx, r.ns, user) - r.NoError(err) - r.NotEmpty(id) - - usr, err := r.repository.GetByEmail(r.ctx, user.Email) - r.NoError(err) - r.NotEmpty(usr) - }) - }) - - r.Run("by uuid", func() { - r.Run("return empty string and ErrNotFound if uuid not found in DB", func() { - usr, err := r.repository.GetByUUID(r.ctx, "random") - r.ErrorAs(err, new(user.NotFoundError)) - r.Empty(usr) - }) - - r.Run("return non empty user if email found in DB", func() { - err := setup(r.ctx, r.client) - r.NoError(err) - - user := getUser("use-getbyuuid@raystack.io") - id, err := r.repository.Create(r.ctx, r.ns, user) - r.NoError(err) - r.NotEmpty(id) - - usr, err := r.repository.GetByUUID(r.ctx, user.UUID) - r.NoError(err) - r.NotEmpty(usr) - }) - }) - -} - -func (r *UserRepositoryTestSuite) TestUpsertByEmail() { - r.Run("return ErrNoUserInformation if user is nil", func() { - id, err := r.repository.UpsertByEmail(r.ctx, r.ns, nil) - r.ErrorIs(err, user.ErrNoUserInformation) - r.Empty(id) - }) - - r.Run("return ErrDuplicateRecord if record already exist", func() { - usr := &user.User{UUID: uuid.NewString(), Email: "dummy@raystack.io"} - - err := r.insertEmail(usr.Email) - r.NoError(err) - - usr.UUID = uuid.NewString() - id, err := r.repository.UpsertByEmail(r.ctx, r.ns, usr) - r.NoError(err) - r.NotEmpty(id) - - id, err = r.repository.UpsertByEmail(r.ctx, r.ns, usr) - r.ErrorIs(err, user.DuplicateRecordError{UUID: usr.UUID, Email: usr.Email}) - r.Empty(id) - }) - - r.Run("new row is inserted with uuid and email if user not exist", func() { - usr := &user.User{UUID: uuid.NewString(), Email: "user-upsert-1@raystack.io"} - id, err := r.repository.UpsertByEmail(r.ctx, r.ns, usr) - r.NoError(err) - r.NotEmpty(id) - - gotUser, err := r.repository.GetByUUID(r.ctx, usr.UUID) - r.NoError(err) - r.Equal(gotUser.UUID, usr.UUID) - r.Equal(gotUser.Email, usr.Email) - }) - - r.Run("new row is inserted with uuid only if user not exist", func() { - usr := &user.User{UUID: uuid.NewString()} - id, err := r.repository.UpsertByEmail(r.ctx, r.ns, usr) - r.NoError(err) - r.NotEmpty(id) - - gotUser, err := r.repository.GetByUUID(r.ctx, usr.UUID) - r.NoError(err) - r.Equal(gotUser.UUID, usr.UUID) - r.Equal(gotUser.Email, usr.Email) - }) - - r.Run("upserting existing row with empty uuid is upserted with uuid and email", func() { - usr := &user.User{Email: "user-upsert-2@raystack.io"} - - err := r.insertEmail(usr.Email) - r.NoError(err) - - usr.UUID = uuid.NewString() - id, err := r.repository.UpsertByEmail(r.ctx, r.ns, usr) - r.NoError(err) - r.NotEmpty(id) - - gotUser, err := r.repository.GetByUUID(r.ctx, usr.UUID) - r.NoError(err) - r.Equal(gotUser.UUID, usr.UUID) - r.Equal(gotUser.Email, usr.Email) - }) - - r.Run("upserting existing row with non empty uuid would return error", func() { - usr := &user.User{UUID: uuid.NewString(), Email: "user-upsert-3@raystack.io"} - - id, err := r.repository.Create(r.ctx, r.ns, usr) - r.NoError(err) - r.NotEmpty(id) - - id, err = r.repository.UpsertByEmail(r.ctx, r.ns, usr) - r.Error(err) - r.Empty(id) - }) -} - -func TestUserRepository(t *testing.T) { - suite.Run(t, &UserRepositoryTestSuite{}) -} From 371f30a920a270da9215ac09860cdbc8b5a2c184 Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 29 Mar 2026 02:10:20 -0500 Subject: [PATCH 05/10] chore: remove ES dependency, stale docs, configs, mocks, CI - Removed elasticsearch from docker-compose.yaml (Postgres-only) - Removed elasticsearch from config.yaml and config.example.yaml - Removed elasticsearch service from .github/workflows/test.yml - Deleted stale guide docs (ingestion, querying, starring, telemetry) - Deleted stale handler mocks (no tests import them) - Removed empty test/ directory - Updated Postgres to v16 in docker-compose - go mod tidy (cleaned unused indirect deps) --- .github/workflows/test.yml | 16 - docker-compose.yaml | 20 +- docs/docs/guides/ingestion.md | 445 ---------------------------- docs/docs/guides/querying.md | 315 -------------------- docs/docs/guides/starring.md | 51 ---- docs/docs/guides/telemetry.md | 19 -- go.mod | 23 -- go.sum | 59 ---- handler/mocks/namespace_service.go | 301 ------------------- handler/mocks/user_service.go | 94 ------ internal/config/config.example.yaml | 7 +- 11 files changed, 2 insertions(+), 1348 deletions(-) delete mode 100644 docs/docs/guides/ingestion.md delete mode 100644 docs/docs/guides/querying.md delete mode 100644 docs/docs/guides/starring.md delete mode 100644 docs/docs/guides/telemetry.md delete mode 100644 handler/mocks/namespace_service.go delete mode 100644 handler/mocks/user_service.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 219d443a..f155b2be 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,22 +18,6 @@ concurrency: jobs: test: runs-on: ubuntu-latest - services: - elasticsearch: - image: elasticsearch:8.17.1 - ports: - - 9200:9200 - env: - discovery.type: single-node - xpack.security.enabled: "false" - ES_JAVA_OPTS: "-Xms128m -Xmx128m" - options: >- - --health-cmd "curl -f http://localhost:9200/_cluster/health" - --health-interval 10s - --health-timeout 5s - --health-retries 10 - env: - ES_TEST_SERVER_URL: "http://localhost:9200" steps: - uses: actions/checkout@v6 - uses: actions/setup-go@v6 diff --git a/docker-compose.yaml b/docker-compose.yaml index 8ee67e65..fbc3457f 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,29 +1,11 @@ services: - es: - image: docker.elastic.co/elasticsearch/elasticsearch:8.17.1 - ports: - - 9200:9200 - environment: - discovery.type: single-node - xpack.security.enabled: "false" - ES_JAVA_OPTS: "-Xms256m -Xmx256m" - networks: - - storage - volumes: - - ./temp/esdata:/usr/share/elasticsearch/data - postgres: - image: postgres:13 + image: postgres:16 ports: - 5433:5432 environment: POSTGRES_USER: compass POSTGRES_PASSWORD: compass_password POSTGRES_DB: compass - networks: - - storage volumes: - ./temp/pgdata:/var/lib/postgresql/data - -networks: - storage: diff --git a/docs/docs/guides/ingestion.md b/docs/docs/guides/ingestion.md deleted file mode 100644 index 127c3c2f..00000000 --- a/docs/docs/guides/ingestion.md +++ /dev/null @@ -1,445 +0,0 @@ -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; - -# Ingesting metadata - -This document showcases compass usage, from producing data, to using APIs for specific use-cases. This guide is geared towards adminstrators, more than users. It is meant to give the administrators an introduction of different configuration options available, and how they affect the behaviour of the application. - -## Prerequisites - -This guide assumes that you have a local instance of compass running and listening on `localhost:8080`. See [Installation](installation.md) guide for information on how to run Compass. - -## Adding Data - -Let’s say that you have a hypothetical tool called Piccolo and you have several deployments of this tool on your platform. Before we can push data for Piccolo deployments to Compass, you need to recognize the type of Piccolo, whether it is a kind of `table`, `topic`, `dashboard`, or `job`. One can ingest metadata to compass with the Upsert Patch API. The API contract is available [here](https://github.com/raystack/compass/blob/main/third_party/OpenAPI/compass.swagger.json). - -If there is an existing asset, Upsert Patch API will check each field whether there is an update in the field of the existing asset. With this behaviour, it is possible to send partial updated field to update a certain field only as long as the `urn`, `type`, and `service` match with the existing asset. If there is any field changed, a new version of the asset will be created. If the asset does not exist, upsert patch API will create a new asset. Apart from asset details, we also could send upstreams and downstreams of lineage edges of the asset in the body. - -Let's say `piccolo` tool is a kind of `table`, we can start pushing data for it. Let's add 3 metadata of `picollo`. - - - - -```bash -$ curl --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "asset": { - "urn": "picollo:deployment-01", - "type": "table", - "name": "deployment-01", - "service": "picollo", - "description": "this is the one", - "data": {}, - "owners": [ - { - "email": "john.doe@email.com" - } - ] - } -}' -``` - - - - -```bash -$ curl --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "asset": { - "urn": "picollo:deployment-02", - "type": "table", - "name": "deployment-02", - "service": "picollo", - "description": "this came second", - "data": {}, - "owners": [ - { - "email": "kami@email.com" - } - ] - } -}' -``` - - - - -```bash -$ curl --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "asset": { - "urn": "picollo:deployment-03", - "type": "table", - "name": "deployment-03", - "service": "picollo", - "description": "the last one", - "data": {}, - "owners": [ - { - "email": "kami@email.com" - } - ] - } -}' -``` - - - - -## Searching - -#### We can search for required text in the following ways: - -1. Using **`compass search `** CLI command -2. Calling to **`GET /v1beta1/search`** API with `text` to be searched as query parameter - -Now we're ready to start searching. Let's run a search for the term **'one'** from the assets we ingested earlier. - - - - -```bash -$ compass search one -``` - - - - -```bash -$ curl 'http://localhost:8080/v1beta1/search?text\=one' \ ---header 'Compass-User-UUID:raystack@email.com' | jq -``` - - - - -The output is the following: - -```json -{ - "data": [ - { - "urn": "picollo:deployment-01", - "type": "table", - "name": "deployment-01", - "service": "picollo", - "description": "this is the one", - "data": {}, - "owners": [ - { - "email": "john.doe@email.com" - } - ], - "labels": {} - }, - { - "urn": "picollo:deployment-03", - "type": "table", - "name": "deployment-03", - "service": "picollo", - "description": "the last one", - "data": {}, - "owners": [ - { - "email": "kami@email.com" - } - ], - "labels": {} - } - ] -} -``` - -The search is run against ALL fields of the records. It can be further restricted by specifying a filter criteria, could be exact match with `filter` and fuzzy match with `query`. For instance, if you wish to restrict the search to piccolo deployments that belong to `kami` (fuzzy), you can run: - -#### We can search with custom queries in the following ways: - -1. Using **`compass search --query=field_key1:val1`** CLI command -2. Calling to **`GET /v1beta1/search`** API with `text` and `query[field_key1]=val1` as query parameters - - - - -```bash -$ compass search one --query=owners:kami -``` - - - - -```bash -$ curl 'http://localhost:8080/v1beta1/search?text=one&query[owners]=kami' \ ---header 'Compass-User-UUID:raystack@email.com' | jq -``` - - - - -The output is the following: - -```json -{ - "data": [ - { - "urn": "picollo:deployment-03", - "type": "table", - "name": "deployment-03", - "service": "picollo", - "description": "the last one", - "data": {}, - "owners": [ - { - "email": "kami@email.com" - } - ], - "labels": {} - } - ] -} -``` - -## Lineage - -Now that we have configured the `piccolo` type and learnt how to use the search API to search it's assets, let's configure lineage for it. - -To begin with, let's start over adding picolo metadata with its lineage information and add another metadata with service name `sensu` and type `topic` and add some records for it. - -### Adding `picollo` Metadata - - - - -```bash -$ curl --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "asset": { - "urn": "picollo:deployment-01", - "type": "table", - "name": "deployment-01", - "service": "picollo", - "description": "this is the one", - "data": {}, - "owners": [ - { - "email": "john.doe@email.com" - } - ] - }, - "upstreams": [ - { - "urn": "sensu:deployment-01", - "type": "topic", - "service": "sensu" - } - ], - "downstreams": [ - { - "urn": "gohan:deployment-01", - "type": "table", - "service": "gohan" - } - ] -}' -``` - - - - -```bash -$ curl --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "asset": { - "urn": "picollo:deployment-02", - "type": "table", - "name": "deployment-02", - "service": "picollo", - "description": "this came second", - "data": {}, - "owners": [ - { - "email": "kami@email.com" - } - ] - }, - "upstreams": [ - { - "urn": "sensu:deployment-02", - "type": "topic", - "service": "sensu" - } - ], - "downstreams": [ - { - "urn": "gohan:deployment-02", - "type": "table", - "service": "gohan" - } - ] -}' -``` - - - - -```bash -$ curl --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "asset": { - "urn": "picollo:deployment-03", - "type": "table", - "name": "deployment-03", - "service": "picollo", - "description": "the last one", - "data": {}, - "owners": [ - { - "email": "kami@email.com" - } - ] - }, - "upstreams": [ - { - "urn": "sensu:deployment-03", - "type": "topic", - "service": "sensu" - } - ], - "downstreams": [ - { - "urn": "gohan:deployment-03", - "type": "table", - "service": "gohan" - } - ] -}' -``` - - - - -### Adding `sensu` Metadata - -`sensu` is the data store that `piccolo` instances read from. In order to have a lineage, we need to have the metadata urn of `sensu` in Compass. - -For instance, if you look at the `upstreams` and `downstreams` fields when we are ingesting `piccolo` metadata, you'll see that they are urn's of `sensu` instances. This means we can define the relationship between `piccolo` and `sensu` resources by declaring this relationship in `piccolo`'s definition. - - - -```bash -$ curl --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "asset": { - "urn": "sensu:deployment-01", - "type": "topic", - "name": "deployment-01", - "service": "sensu", - "description": "primary sensu dataset", - "data": {} - }, - "upstreams": [], - "downstreams": [] -}' -``` - - - - -```bash -$ curl --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "asset": { - "urn": "sensu:deployment-02", - "type": "topic", - "name": "deployment-02", - "service": "sensu", - "description": "secondary sensu dataset", - "data": {} - }, - "upstreams": [], - "downstreams": [] -}' -``` - - - - -```bash -$ curl --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Compass-User-UUID:raystack@email.com' \ ---data-raw '{ - "asset": { - "urn": "sensu:deployment-03", - "type": "topic", - "name": "deployment-03", - "service": "sensu", - "description": "tertiary sensu dataset", - "data": {} - }, - "upstreams": [], - "downstreams": [] -}' -``` - - - - -**Note:** it is sufficient \(and preferred\) that one declare it's relationship to another. Both need not do this. - -### Querying Lineage - -#### We can search for lineage in the following ways: - -1. Using **`compass lineage `** CLI command -2. Calling to **`GET /v1beta1/lineage/:urn`** API with `urn` to be searched as the path parameter - - - - -```bash -$ compass lineage picollo:deployment-01 -``` - - - - -```bash -curl 'http://localhost:8080/v1beta1/lineage/picollo%3Adeployment-01' \ ---header 'Compass-User-UUID:raystack@email.com' -``` - - - - -The output is the following: - -```json -{ - "data": [ - { - "source": "sensu:deployment-01", - "target": "picollo:deployment-01", - "prop": { - "root": "picollo:deployment-01" - } - }, - { - "source": "picollo:deployment-01", - "target": "gohan:deployment-01", - "prop": { - "root": "picollo:deployment-01" - } - } - ], - "node_attrs": {} -} -``` - -The response represents a graph that consists of edges in its graph. diff --git a/docs/docs/guides/querying.md b/docs/docs/guides/querying.md deleted file mode 100644 index 298dc592..00000000 --- a/docs/docs/guides/querying.md +++ /dev/null @@ -1,315 +0,0 @@ -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; - -# Querying metadata - -## Prerequisites - -This guide assumes that you have a local instance of compass running and listening on `localhost:8080`. See [Installation](installation.md) guide for information on how to run Compass. - -## Using the Search API - -#### We can search for required text in the following ways: - -1. Using **`compass search `** CLI command -2. Calling to **`GET /v1beta1/search`** API with `text` to be searched as query parameter - -The API contract is available [here](https://github.com/raystack/compass/blob/main/third_party/OpenAPI/compass.swagger.json). - -To demonstrate how to use compass, we’re going to query it for resources that contain the word ‘booking’. - - - - -```bash -$ compass search booking -``` - - - - -```bash -$ curl 'http://localhost:8080/v1beta1/search?text=booking' \ ---header 'Compass-User-UUID:raystack@email.com' -``` - - - - -This will return a list of search results. Here’s a sample response: - -```bash -{ - "data": [ - { - "id": "00c06ef7-badb-4236-9d9e-889697cbda46", - "urn": "kafka::g-godata-id-playground/ g-godata-id-seg-enriched-booking-dagger", - "type": "topic", - "service": "kafka", - "name": "g-godata-id-seg-enriched-booking-dagger", - "description": "", - "labels": { - "flink_name": "g-godata-id-playground", - "sink_type": "kafka" - } - }, - { - "id": "9e69c08a-c3c2-4e04-957f-c8010c1e6515", - "urn": "kafka::g-godata-id-playground/ g-godata-id-booking-bach-test-dagger", - "type": "topic", - "service": "kafka", - "name": "g-godata-id-booking-bach-test-dagger", - "description": "", - "labels": { - "flink_name": "g-godata-id-playground", - "sink_type": "kafka" - } - }, - { - "id": "ff597a0f-8062-4370-a54c-fd6f6c12d2a0", - "urn": "kafka::g-godata-id-playground/ g-godata-id-booking-bach-test-3-dagger", - "type": "topic", - "service": "kafka", - "title": "g-godata-id-booking-bach-test-3-dagger", - "description": "", - "labels": { - "flink_name": "g-godata-id-playground", - "sink_type": "kafka" - } - } - ] -} -``` - -Compass decouple identifier from external system with the one that is being used internally. ID is the internally auto-generated unique identifier. URN is the external identifier of the asset, while Name is the human friendly name for it. See the complete API spec to learn more about what the rest of the fields mean. - -### Filter - -Compass search supports restricting search results via filter by passing it in query params. Filter query params format is **`filter[{field_key}]={value}`** where **`field_key`** is the field name that we want to restrict and **`value`** is what value that should be matched. Filter can also support nested field by chaining key **`field_key`** with **`.`** \(dot\) such as **`filter[{field_key}.{nested_field_key}]={value}`**. - -#### We can filter our search in the following ways: - -1. Using **`compass search --filter=field_key1:val1`** CLI command -2. Calling to **`GET /v1beta1/search`** API with **`text`** and **`filter[field_key1]=val1`** as query parameters - -For instance, to restrict search results to the ‘id’ landscape for ‘raystack’ organisation, run: - - - - -```bash -$ compass search booking --filter=labels.landscape=id,labels.entity=raystack -``` - - - - -```bash -$ curl 'http://localhost:8080/v1beta1/search?text=booking&filter[labels.landscape]=id&filter[labels.entity]=raystack' \ ---header 'Compass-User-UUID:raystack@email.com' -``` - - - - -Under the hood, filter's work by checking whether the matching document's contain the filter key and checking if their values match. Filters can be specified multiple times to specify a set of filter criteria. For example, to search for ‘booking’ in both ‘vn’ and ‘th’ landscape, run: - - - - -```bash -$ compass search booking --filter=labels.landscape=vn,labels.landscape=th -``` - - - - -```bash -$ curl 'http://localhost:8080/v1beta1/search?text=booking&filter[labels.landscape]=vn&filter[labels.landscape]=th' \ ---header 'Compass-User-UUID:raystack@email.com' -``` - - - - -### Query - -Apart from filters, Compass search API also supports fuzzy restriction in its query params. The difference of filter and query are, filter is for exact match on a specific field in asset while query is for fuzzy match. - -#### We can search with custom queries in the following ways: - -1. Using **`compass search --query=field_key1:val1`** CLI command -2. Calling to **`GET /v1beta1/search`** API with **`text`** and **`query[field_key1]=val1`** as query parameters - -Query format is not different with filter `query[{field_key}]={value}` where `field_key` is the field name that we want to query and `value` is what value that should be fuzzy matched. Query could also support nested field by chaining key `field_key` with `.` \(dot\) such as `query[{field_key}.{nested_field_key}]={value}`. For instance, to search results that has a name `kafka` and belongs to the team `data_engineering`, run: - - - - -```bash -$ compass search booking --query=name:kafka,labels.team=data_eng -``` - - - - -```bash -$ curl 'http://localhost:8080/v1beta1/search?text=booking&query[name]=kafka&query[labels.team]=data_eng' \ ---header 'Compass-User-UUID:raystack@email.com' -``` - - - - -### Ranking Results - -Compass allows user to rank the results based on a numeric field in the asset. It supports nested field by using the `.` \(dot\) to point to the nested field. For instance, to rank the search results based on `usage_count` in `data` field, run: - - - - -```bash -$ compass search booking --rankby=data.usage_count -``` - - - - -```bash -$ curl 'http://localhost:8080/v1beta1/search?text=booking&rankby=data.usage_count' \ ---header 'Compass-User-UUID:raystack@email.com' -``` - - - - -### Size - -You can also specify the number of maximum results you want compass to return using the **`size`** parameter - - - - -```bash -$ compass search booking --size=5 -``` - - - - -```bash -$ curl 'http://localhost:8080/v1beta1/search?text=booking&size=5' \ ---header 'Compass-User-UUID:raystack@email.com' -``` - - - - -## Using the Suggest API - -The Suggest API gives a number of suggestion based on asset's name. There are 5 suggestions by default return by this API. - -The API contract is available [here](https://github.com/raystack/compass/blob/main/third_party/OpenAPI/compass.swagger.json). - -Example of searching assets suggestion that has a name ‘booking’. - -```bash -$ curl 'http://localhost:8080/v1beta1/search/suggest?text=booking' \ ---header 'Compass-User-UUID:raystack@email.com' -``` - -This will return a list of suggestions. Here’s a sample response: - -```bash -{ - "data": [ - "booking-daily-test-962ZFY", - "booking-daily-test-c7OUZv", - "booking-weekly-test-fmDeUf", - "booking-daily-test-jkQS2b", - "booking-daily-test-m6Oe9M" - ] -} -``` - -## Using the Get Assets API - -The Get Assets API returns assets from Compass' main storage (PostgreSQL) while the Search API returns assets from Elasticsearch. The Get Assets API has several options (filters, size, offset, etc...) in its query params. - -| Query Params | Description | -| --------------------------------------------------- | ------------------------------ | -| `types=topic,table` | filter by types | -| `services=kafka,postgres` | filter by services | -| `data[dataset]=booking&data[project]=p-godata-id` | filter by field in asset.data | -| `q=internal&q_fields=name,urn,description,services` | querying by field | -| `sort=created_at` | sort by certain fields | -| `direction=desc` | sorting direction (asc / desc) | - -The API contract is available [here](https://github.com/raystack/compass/blob/main/third_party/OpenAPI/compass.swagger.json). - -## Using the Lineage API - -The Lineage API allows the clients to query the data flow relationship between different assets managed by Compass. - -See the swagger definition of [Lineage API](https://github.com/raystack/compass/blob/main/third_party/OpenAPI/compass.swagger.json)) for more information. - -Lineage API returns a list of directed edges. For each edge, there are `source` and `target` fields that represent nodes to indicate the direction of the edge. Each edge could have an optional property in the `props` field. - -#### We can search for lineage in the following ways: - -1. Using **`compass lineage `** CLI command -2. Calling to **`GET /v1beta1/lineage/:urn`** API with `urn` to be searched as the path parameter - - - - -```bash -$ compass lineage data-project:datalake.events -``` - - - - -```bash -$ curl 'http://localhost:8080/v1beta1/lineage/data-project%3Adatalake.events' \ ---header 'Compass-User-UUID:raystack@email.com' -``` - - - - -```json -{ - "data": [ - { - "source": { - "urn": "data-project:datalake.events", - "type": "table", - "service": "bigquery" - }, - "target": { - "urn": "events-transform-dwh", - "type": "csv", - "service": "s3" - }, - "props": {} - }, - { - "source": { - "urn": "events-ingestion", - "type": "topic", - "service": "beast" - }, - "target": { - "urn": "data-project:datalake.events", - "type": "table", - "service": "bigquery" - }, - "props": {} - } - ] -} -``` - -The lineage is fetched from the perspective of an asset. The response shows it has a list of upstreams and downstreams assets of the requested asset. -Notice that in the URL, we are using `urn` instead of `id`. The reason is because we use `urn` as a main identifier in our lineage storage. We don't use `id` to store the lineage as a main identifier, because `id` is internally auto generated and in lineage, there might be some assets that we don't store in our Compass' storage yet. diff --git a/docs/docs/guides/starring.md b/docs/docs/guides/starring.md deleted file mode 100644 index 0a79fd67..00000000 --- a/docs/docs/guides/starring.md +++ /dev/null @@ -1,51 +0,0 @@ -# Starring - -Compass allows a user to stars an asset. This bookmarking functionality is introduced to increase the speed of a user to get information. - -To star and asset, we can use the User Starring API. Assuming we already have `asset_id` that we want to star. - -```bash -$ curl --request PUT 'http://localhost:8080/v1beta1/me/starred/00c06ef7-badb-4236-9d9e-889697cbda46' \ ---header 'Compass-User-UUID:raystack@email.com' -``` - -To get the list of my starred assets. - -```bash -$ curl --request PUT 'http://localhost:8080/v1beta1/me/starred' \ ---header 'Compass-User-UUID:raystack@email.com' - -{ - "data": [ - { - "id": "00c06ef7-badb-4236-9d9e-889697cbda46", - "urn": "kafka::g-godata-id-playground/ g-godata-id-seg-enriched-booking-dagger", - "type": "topic", - "service": "kafka", - "name": "g-godata-id-seg-enriched-booking-dagger", - "description": "", - "labels": { - "flink_name": "g-godata-id-playground", - "sink_type": "kafka" - } - } - ] -} -``` - -There is also an API to see which users star an asset (stargazers) in the Asset API. - -```bash -$ curl 'http://localhost:8080/v1beta1/assets/00c06ef7-badb-4236-9d9e-889697cbda46/stargazers' \ ---header 'Compass-User-UUID:raystack@email.com' - -{ - "data": [ - { - "id": "1111-2222-3333", - "email": "raystack@email.com", - "provider": "shield" - } - ] -} -``` diff --git a/docs/docs/guides/telemetry.md b/docs/docs/guides/telemetry.md deleted file mode 100644 index 5f46ec27..00000000 --- a/docs/docs/guides/telemetry.md +++ /dev/null @@ -1,19 +0,0 @@ -# Telemetry - -Compass uses [OpenTelemetry](https://opentelemetry.io/) to collect traces and metrics and export them via OTLP gRPC to a collector. - -## OpenTelemetry - -By default OpenTelemetry is not enabled. To enable it, set these configurations: - -``` -TELEMETRY_OPENTELEMETRY_ENABLED=true -TELEMETRY_OPENTELEMETRY_COLLECTORADDR=localhost:4317 -TELEMETRY_SERVICENAME=compass -``` - -You can optionally configure trace sampling probability: - -``` -TELEMETRY_OPENTELEMETRY_TRACESAMPLEPROBABILITY=0.1 -``` diff --git a/go.mod b/go.mod index 846b12a2..d882784a 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,6 @@ require ( github.com/jmoiron/sqlx v1.4.0 github.com/lestrrat-go/jwx/v2 v2.1.6 github.com/mark3labs/mcp-go v0.46.0 - github.com/ory/dockertest/v3 v3.12.0 github.com/raystack/salt v0.7.0 github.com/rs/cors v1.11.1 github.com/spf13/cobra v1.10.2 @@ -39,28 +38,18 @@ require ( ) require ( - github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect - github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/chroma v0.8.2 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/briandowns/spinner v1.18.0 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/charmbracelet/glamour v0.3.0 // indirect github.com/cli/safeexec v1.0.0 // indirect - github.com/containerd/continuity v0.4.5 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dlclark/regexp2 v1.9.0 // indirect - github.com/docker/cli v27.4.1+incompatible // indirect - github.com/docker/docker v28.3.3+incompatible // indirect - github.com/docker/go-connections v0.5.0 // indirect - github.com/docker/go-units v0.5.0 // indirect github.com/fatih/color v1.15.0 // indirect github.com/goccy/go-json v0.10.3 // indirect - github.com/gogo/protobuf v1.3.2 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/hashicorp/go-version v1.3.0 // indirect @@ -84,26 +73,18 @@ require ( github.com/mcuadros/go-defaults v1.2.0 // indirect github.com/microcosm-cc/bluemonday v1.0.6 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect - github.com/moby/term v0.5.0 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0 // indirect - github.com/opencontainers/runc v1.2.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/progressbar/v3 v3.8.5 // indirect github.com/segmentio/asm v1.2.0 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/yuin/goldmark v1.4.13 // indirect github.com/yuin/goldmark-emoji v1.0.1 // indirect golang.org/x/sys v0.41.0 // indirect @@ -115,7 +96,6 @@ require ( require ( buf.build/go/protovalidate v1.0.0 // indirect cel.dev/expr v0.25.1 // indirect - dario.cat/mergo v1.0.0 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -126,7 +106,6 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator v9.31.0+incompatible // indirect - github.com/go-viper/mapstructure/v2 v2.1.0 // indirect github.com/google/cel-go v0.26.1 // indirect github.com/google/jsonschema-go v0.4.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect @@ -134,8 +113,6 @@ require ( github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/lib/pq v1.12.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/sys/user v0.3.0 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect diff --git a/go.sum b/go.sum index 1bd1e8f9..f1146d2b 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,6 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= connectrpc.com/validate v0.6.0 h1:DcrgDKt2ZScrUs/d/mh9itD2yeEa0UbBBa+i0mwzx+4= connectrpc.com/validate v0.6.0/go.mod h1:ihrpI+8gVbLH1fvVWJL1I3j0CfWnF8P/90LsmluRiZs= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= @@ -26,8 +24,6 @@ github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8 github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg= @@ -44,8 +40,6 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/briandowns/spinner v1.18.0 h1:SJs0maNOs4FqhBwiJ3Gr7Z1D39/rukIVGQvpNZVHVcM= github.com/briandowns/spinner v1.18.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -54,16 +48,12 @@ github.com/charmbracelet/glamour v0.3.0 h1:3H+ZrKlSg8s+WU6V7eF2eRVYt8lCueffbi7r2 github.com/charmbracelet/glamour v0.3.0/go.mod h1:TzF0koPZhqq0YVBNL100cPHznAAjVj7fksX2RInwjGw= github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI= github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= -github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= -github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -79,8 +69,6 @@ github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5 github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.9.0 h1:pTK/l/3qYIKaRXuHnEnIf7Y5NxfRPfpb7dis6/gdlVI= github.com/dlclark/regexp2 v1.9.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI= -github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -115,8 +103,6 @@ github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy0 github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= -github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= -github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -160,8 +146,6 @@ github.com/jeremywohl/flatten v1.0.1/go.mod h1:4AmD/VxjWcI5SRB0n6szE2A6s2fsNHDLO github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -222,8 +206,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= -github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -241,10 +223,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/opencontainers/runc v1.2.3 h1:fxE7amCzfZflJO2lHXf4y/y8M1BoAqp+FVmG19oYB80= -github.com/opencontainers/runc v1.2.3/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM= -github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw= -github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -274,8 +252,6 @@ github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= @@ -308,16 +284,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.3/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= @@ -354,44 +322,27 @@ go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU= golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= @@ -400,19 +351,11 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0= @@ -438,5 +381,3 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= -gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= diff --git a/handler/mocks/namespace_service.go b/handler/mocks/namespace_service.go deleted file mode 100644 index c2a27a75..00000000 --- a/handler/mocks/namespace_service.go +++ /dev/null @@ -1,301 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - mock "github.com/stretchr/testify/mock" - - namespace "github.com/raystack/compass/core/namespace" - - uuid "github.com/google/uuid" -) - -// NamespaceService is an autogenerated mock type for the NamespaceService type -type NamespaceService struct { - mock.Mock -} - -type NamespaceService_Expecter struct { - mock *mock.Mock -} - -func (_m *NamespaceService) EXPECT() *NamespaceService_Expecter { - return &NamespaceService_Expecter{mock: &_m.Mock} -} - -// Create provides a mock function with given fields: ctx, ns -func (_m *NamespaceService) Create(ctx context.Context, ns *namespace.Namespace) (string, error) { - ret := _m.Called(ctx, ns) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace) (string, error)); ok { - return rf(ctx, ns) - } - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace) string); ok { - r0 = rf(ctx, ns) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(context.Context, *namespace.Namespace) error); ok { - r1 = rf(ctx, ns) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NamespaceService_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' -type NamespaceService_Create_Call struct { - *mock.Call -} - -// Create is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -func (_e *NamespaceService_Expecter) Create(ctx interface{}, ns interface{}) *NamespaceService_Create_Call { - return &NamespaceService_Create_Call{Call: _e.mock.On("Create", ctx, ns)} -} - -func (_c *NamespaceService_Create_Call) Run(run func(ctx context.Context, ns *namespace.Namespace)) *NamespaceService_Create_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace)) - }) - return _c -} - -func (_c *NamespaceService_Create_Call) Return(_a0 string, _a1 error) *NamespaceService_Create_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *NamespaceService_Create_Call) RunAndReturn(run func(context.Context, *namespace.Namespace) (string, error)) *NamespaceService_Create_Call { - _c.Call.Return(run) - return _c -} - -// GetByID provides a mock function with given fields: ctx, id -func (_m *NamespaceService) GetByID(ctx context.Context, id uuid.UUID) (*namespace.Namespace, error) { - ret := _m.Called(ctx, id) - - var r0 *namespace.Namespace - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) (*namespace.Namespace, error)); ok { - return rf(ctx, id) - } - if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) *namespace.Namespace); ok { - r0 = rf(ctx, id) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*namespace.Namespace) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, uuid.UUID) error); ok { - r1 = rf(ctx, id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NamespaceService_GetByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByID' -type NamespaceService_GetByID_Call struct { - *mock.Call -} - -// GetByID is a helper method to define mock.On call -// - ctx context.Context -// - id uuid.UUID -func (_e *NamespaceService_Expecter) GetByID(ctx interface{}, id interface{}) *NamespaceService_GetByID_Call { - return &NamespaceService_GetByID_Call{Call: _e.mock.On("GetByID", ctx, id)} -} - -func (_c *NamespaceService_GetByID_Call) Run(run func(ctx context.Context, id uuid.UUID)) *NamespaceService_GetByID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(uuid.UUID)) - }) - return _c -} - -func (_c *NamespaceService_GetByID_Call) Return(_a0 *namespace.Namespace, _a1 error) *NamespaceService_GetByID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *NamespaceService_GetByID_Call) RunAndReturn(run func(context.Context, uuid.UUID) (*namespace.Namespace, error)) *NamespaceService_GetByID_Call { - _c.Call.Return(run) - return _c -} - -// GetByName provides a mock function with given fields: ctx, name -func (_m *NamespaceService) GetByName(ctx context.Context, name string) (*namespace.Namespace, error) { - ret := _m.Called(ctx, name) - - var r0 *namespace.Namespace - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (*namespace.Namespace, error)); ok { - return rf(ctx, name) - } - if rf, ok := ret.Get(0).(func(context.Context, string) *namespace.Namespace); ok { - r0 = rf(ctx, name) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*namespace.Namespace) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, name) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NamespaceService_GetByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByName' -type NamespaceService_GetByName_Call struct { - *mock.Call -} - -// GetByName is a helper method to define mock.On call -// - ctx context.Context -// - name string -func (_e *NamespaceService_Expecter) GetByName(ctx interface{}, name interface{}) *NamespaceService_GetByName_Call { - return &NamespaceService_GetByName_Call{Call: _e.mock.On("GetByName", ctx, name)} -} - -func (_c *NamespaceService_GetByName_Call) Run(run func(ctx context.Context, name string)) *NamespaceService_GetByName_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *NamespaceService_GetByName_Call) Return(_a0 *namespace.Namespace, _a1 error) *NamespaceService_GetByName_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *NamespaceService_GetByName_Call) RunAndReturn(run func(context.Context, string) (*namespace.Namespace, error)) *NamespaceService_GetByName_Call { - _c.Call.Return(run) - return _c -} - -// List provides a mock function with given fields: ctx -func (_m *NamespaceService) List(ctx context.Context) ([]*namespace.Namespace, error) { - ret := _m.Called(ctx) - - var r0 []*namespace.Namespace - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) ([]*namespace.Namespace, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) []*namespace.Namespace); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*namespace.Namespace) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NamespaceService_List_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'List' -type NamespaceService_List_Call struct { - *mock.Call -} - -// List is a helper method to define mock.On call -// - ctx context.Context -func (_e *NamespaceService_Expecter) List(ctx interface{}) *NamespaceService_List_Call { - return &NamespaceService_List_Call{Call: _e.mock.On("List", ctx)} -} - -func (_c *NamespaceService_List_Call) Run(run func(ctx context.Context)) *NamespaceService_List_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *NamespaceService_List_Call) Return(_a0 []*namespace.Namespace, _a1 error) *NamespaceService_List_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *NamespaceService_List_Call) RunAndReturn(run func(context.Context) ([]*namespace.Namespace, error)) *NamespaceService_List_Call { - _c.Call.Return(run) - return _c -} - -// Update provides a mock function with given fields: ctx, ns -func (_m *NamespaceService) Update(ctx context.Context, ns *namespace.Namespace) error { - ret := _m.Called(ctx, ns) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace) error); ok { - r0 = rf(ctx, ns) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// NamespaceService_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' -type NamespaceService_Update_Call struct { - *mock.Call -} - -// Update is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -func (_e *NamespaceService_Expecter) Update(ctx interface{}, ns interface{}) *NamespaceService_Update_Call { - return &NamespaceService_Update_Call{Call: _e.mock.On("Update", ctx, ns)} -} - -func (_c *NamespaceService_Update_Call) Run(run func(ctx context.Context, ns *namespace.Namespace)) *NamespaceService_Update_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace)) - }) - return _c -} - -func (_c *NamespaceService_Update_Call) Return(_a0 error) *NamespaceService_Update_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *NamespaceService_Update_Call) RunAndReturn(run func(context.Context, *namespace.Namespace) error) *NamespaceService_Update_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTNewNamespaceService interface { - mock.TestingT - Cleanup(func()) -} - -// NewNamespaceService creates a new instance of NamespaceService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewNamespaceService(t mockConstructorTestingTNewNamespaceService) *NamespaceService { - mock := &NamespaceService{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/handler/mocks/user_service.go b/handler/mocks/user_service.go deleted file mode 100644 index 655c97cb..00000000 --- a/handler/mocks/user_service.go +++ /dev/null @@ -1,94 +0,0 @@ -// Code generated by mockery v2.20.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - mock "github.com/stretchr/testify/mock" - - namespace "github.com/raystack/compass/core/namespace" -) - -// UserService is an autogenerated mock type for the UserService type -type UserService struct { - mock.Mock -} - -type UserService_Expecter struct { - mock *mock.Mock -} - -func (_m *UserService) EXPECT() *UserService_Expecter { - return &UserService_Expecter{mock: &_m.Mock} -} - -// ValidateUser provides a mock function with given fields: ctx, ns, uuid, email -func (_m *UserService) ValidateUser(ctx context.Context, ns *namespace.Namespace, uuid string, email string) (string, error) { - ret := _m.Called(ctx, ns, uuid, email) - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string, string) (string, error)); ok { - return rf(ctx, ns, uuid, email) - } - if rf, ok := ret.Get(0).(func(context.Context, *namespace.Namespace, string, string) string); ok { - r0 = rf(ctx, ns, uuid, email) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(context.Context, *namespace.Namespace, string, string) error); ok { - r1 = rf(ctx, ns, uuid, email) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// UserService_ValidateUser_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ValidateUser' -type UserService_ValidateUser_Call struct { - *mock.Call -} - -// ValidateUser is a helper method to define mock.On call -// - ctx context.Context -// - ns *namespace.Namespace -// - uuid string -// - email string -func (_e *UserService_Expecter) ValidateUser(ctx interface{}, ns interface{}, uuid interface{}, email interface{}) *UserService_ValidateUser_Call { - return &UserService_ValidateUser_Call{Call: _e.mock.On("ValidateUser", ctx, ns, uuid, email)} -} - -func (_c *UserService_ValidateUser_Call) Run(run func(ctx context.Context, ns *namespace.Namespace, uuid string, email string)) *UserService_ValidateUser_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*namespace.Namespace), args[2].(string), args[3].(string)) - }) - return _c -} - -func (_c *UserService_ValidateUser_Call) Return(_a0 string, _a1 error) *UserService_ValidateUser_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *UserService_ValidateUser_Call) RunAndReturn(run func(context.Context, *namespace.Namespace, string, string) (string, error)) *UserService_ValidateUser_Call { - _c.Call.Return(run) - return _c -} - -type mockConstructorTestingTNewUserService interface { - mock.TestingT - Cleanup(func()) -} - -// NewUserService creates a new instance of UserService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewUserService(t mockConstructorTestingTNewUserService) *UserService { - mock := &UserService{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/internal/config/config.example.yaml b/internal/config/config.example.yaml index aa31a780..9cc3e2bc 100644 --- a/internal/config/config.example.yaml +++ b/internal/config/config.example.yaml @@ -1,8 +1,5 @@ log_level: info -elasticsearch: - brokers: http://localhost:9200 - db: host: localhost port: 5432 @@ -18,11 +15,9 @@ service: headerkey_uuid: Compass-User-UUID headerkey_email: Compass-User-Email provider_default_name: shield - # namespace_claim_key is used to get the namespace from the jwt token, if not set default is "namespace_id" - # used for multi-tenancy namespace_claim_key: project_id client: host: localhost:8080 - serverheaderkey_uuid: Compass-User-UUID # if omitted, will use value on service.identity.headerkey_uuid + serverheaderkey_uuid: Compass-User-UUID serverheadervalue_uuid: raystack@email.com From 7a0843731305966804bc677b1d3717282ff2283e Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 29 Mar 2026 02:16:25 -0500 Subject: [PATCH 06/10] build: update PROTON_COMMIT to eefb04d (merged entity proto) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7e6c3b87..d6ca9a7b 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ COMMIT := $(shell git rev-parse --short HEAD) TAG := "$(shell git rev-list --tags --max-count=1)" VERSION := "$(shell git describe --tags ${TAG})-next" BUILD_DIR=dist -PROTON_COMMIT := "b9ed2ad" +PROTON_COMMIT := "eefb04d" .PHONY: all build clean test tidy vet proto setup format generate lint install From 677ede5ef48199d50057af0f3193f9f1ab1c6fc6 Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 29 Mar 2026 02:24:40 -0500 Subject: [PATCH 07/10] chore: gitignore docs/_drafts --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e79a4f01..c74ab78b 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ vendor/ compass.yaml temp/ .mcp.json +docs/_drafts/ From 5e532b0c6cb5cbd81ca98cf1681b961b9602bff1 Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 29 Mar 2026 08:33:54 -0500 Subject: [PATCH 08/10] fix: resolve all lint issues --- cli/root.go | 1 - cli/utils.go | 45 ++++--------------------------------- core/entity/service.go | 4 +--- core/entity/service_test.go | 12 +++++----- handler/handler.go | 4 ---- 5 files changed, 11 insertions(+), 55 deletions(-) diff --git a/cli/root.go b/cli/root.go index 27d208fc..f61d4339 100644 --- a/cli/root.go +++ b/cli/root.go @@ -32,7 +32,6 @@ var ( }, } - namespaceID string ) func New(cliConfig *config.Config) *cobra.Command { diff --git a/cli/utils.go b/cli/utils.go index 1f86f618..456169c0 100644 --- a/cli/utils.go +++ b/cli/utils.go @@ -2,49 +2,12 @@ package cli import ( "encoding/json" - "errors" - "fmt" - "os" - "path/filepath" - "strings" - - "google.golang.org/protobuf/encoding/protojson" - "google.golang.org/protobuf/reflect/protoreflect" ) -func parseFile(filePath string, v protoreflect.ProtoMessage) error { - b, err := os.ReadFile(filePath) +func prettyPrint(v interface{}) string { + b, err := json.MarshalIndent(v, "", " ") if err != nil { - return err - } - - switch filepath.Ext(filePath) { - case ".json": - if err := protojson.Unmarshal(b, v); err != nil { - return fmt.Errorf("invalid json: %w", err) - } - case ".yaml", ".yml": - if err := protojson.Unmarshal(b, v); err != nil { - return fmt.Errorf("invalid yaml: %w", err) - } - default: - return errors.New("unsupported file type") - } - - return nil -} - -func prettyPrint(i interface{}) string { - s, _ := json.MarshalIndent(i, "", "\t") - return string(s) -} - -func makeMapFromString(commaSepStr string) map[string]string { - m := make(map[string]string) - keyValArray := strings.Split(commaSepStr, ",") - for _, s := range keyValArray { - arr := strings.Split(s, ":") - m[arr[0]] = arr[1] + return "" } - return m + return string(b) } diff --git a/core/entity/service.go b/core/entity/service.go index cd33f78e..b0770cd3 100644 --- a/core/entity/service.go +++ b/core/entity/service.go @@ -112,9 +112,7 @@ func (s *Service) GetContext(ctx context.Context, ns *namespace.Namespace, urn s cg := &ContextGraph{Entity: ent} if s.edges != nil { - if depth <= 0 { - depth = 2 - } + _ = depth // TODO: use depth for multi-hop traversal outgoing, _ := s.edges.GetBySource(ctx, ns, urn, EdgeFilter{Current: true}) incoming, _ := s.edges.GetByTarget(ctx, ns, urn, EdgeFilter{Current: true}) cg.Edges = append(outgoing, incoming...) diff --git a/core/entity/service_test.go b/core/entity/service_test.go index 78f7570c..92d3e1f3 100644 --- a/core/entity/service_test.go +++ b/core/entity/service_test.go @@ -110,7 +110,7 @@ func TestService_Delete(t *testing.T) { ctx := context.Background() ns := namespace.DefaultNamespace - svc.Upsert(ctx, ns, &Entity{URN: "urn:x", Type: TypeJob, Name: "x"}) + _, _ = svc.Upsert(ctx, ns, &Entity{URN: "urn:x", Type: TypeJob, Name: "x"}) err := svc.Delete(ctx, ns, "urn:x") if err != nil { @@ -129,8 +129,8 @@ func TestService_GetAll(t *testing.T) { ctx := context.Background() ns := namespace.DefaultNamespace - svc.Upsert(ctx, ns, &Entity{URN: "urn:a", Type: TypeTable, Name: "a"}) - svc.Upsert(ctx, ns, &Entity{URN: "urn:b", Type: TypeJob, Name: "b"}) + _, _ = svc.Upsert(ctx, ns, &Entity{URN: "urn:a", Type: TypeTable, Name: "a"}) + _, _ = svc.Upsert(ctx, ns, &Entity{URN: "urn:b", Type: TypeJob, Name: "b"}) entities, count, err := svc.GetAll(ctx, ns, Filter{}) if err != nil { @@ -150,9 +150,9 @@ func TestService_GetTypes(t *testing.T) { ctx := context.Background() ns := namespace.DefaultNamespace - svc.Upsert(ctx, ns, &Entity{URN: "urn:a", Type: TypeTable, Name: "a"}) - svc.Upsert(ctx, ns, &Entity{URN: "urn:b", Type: TypeTable, Name: "b"}) - svc.Upsert(ctx, ns, &Entity{URN: "urn:c", Type: TypeJob, Name: "c"}) + _, _ = svc.Upsert(ctx, ns, &Entity{URN: "urn:a", Type: TypeTable, Name: "a"}) + _, _ = svc.Upsert(ctx, ns, &Entity{URN: "urn:b", Type: TypeTable, Name: "b"}) + _, _ = svc.Upsert(ctx, ns, &Entity{URN: "urn:c", Type: TypeJob, Name: "c"}) types, err := svc.GetTypes(ctx, ns) if err != nil { diff --git a/handler/handler.go b/handler/handler.go index c43e9afd..394ca044 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -69,7 +69,3 @@ func internalServerError(ctx context.Context, msg string, err error) error { ref, )) } - -func bodyParserErrorMsg(err error) string { - return fmt.Sprintf("error parsing request body: %v", err) -} From 5366c97437fb144c7078d25934edf45f62a68466 Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 29 Mar 2026 14:06:56 -0500 Subject: [PATCH 09/10] fix: remove stale docs and fix sidebars.js --- docs/docs/concepts/asset.mdx | 150 ------------------- docs/docs/concepts/type.md | 15 -- docs/docs/concepts/user.md | 14 -- docs/docs/tour/1-my-first-asset.md | 118 --------------- docs/docs/tour/2-querying-assets.mdx | 208 --------------------------- docs/docs/tour/3-asset-lineage.mdx | 132 ----------------- docs/docs/tour/introduction.md | 49 ------- docs/sidebars.js | 26 +--- 8 files changed, 1 insertion(+), 711 deletions(-) delete mode 100644 docs/docs/concepts/asset.mdx delete mode 100644 docs/docs/concepts/type.md delete mode 100644 docs/docs/concepts/user.md delete mode 100644 docs/docs/tour/1-my-first-asset.md delete mode 100644 docs/docs/tour/2-querying-assets.mdx delete mode 100644 docs/docs/tour/3-asset-lineage.mdx delete mode 100644 docs/docs/tour/introduction.md diff --git a/docs/docs/concepts/asset.mdx b/docs/docs/concepts/asset.mdx deleted file mode 100644 index 88005506..00000000 --- a/docs/docs/concepts/asset.mdx +++ /dev/null @@ -1,150 +0,0 @@ -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; - -# Asset - -In Compass, we call every metadata that you input as an Asset. All your tables, dashboards, topics, jobs are an example of assets. - - - - -| Field | Required | Type | Description | -| ----------- | -------- | ------ | ------------------------------------------------------------------------------- | -| id | false | string | compass' auto-generated uuid | -| urn | true | string | external identifier of the metadata | -| type | true | string | type of metadata, only supports `table`, `job`, `topic`,`dashboard` | -| service | true | string | application name where the metadata was coming from e.g. `bigquery`, `postgres` | -| name | true | string | name of the metadata | -| description | false | string | description of the metadata | -| data | false | json | dynamic data | -| labels | false | json | labels of metadata, written in key-value string | -| owners | false | []json | array of json, where each json contains `email` field | - - - - -```json -{ - - "urn": "topic/order-log", - "type": "topic", - "service": "kafka", - "description": "desc", - "data": { - "some_data1": { - "random_data": 123, - "nested_data": { - "boolean_data": true - } - }, - "some_data1": "value" - } - "labels": { - "labelkey1": "labelvalue1", - "labelkey2": "labelvalue2" - }, - "users": [ - { - "email": "user@raystack.io" - } - ] -} -``` - - - - -Every asset that is pushed SHOULD have the required fields: `urn`, `type`, `service`, `name`. The value of these fields MUST be string, if present. - -Asset ingestion API (`/v1beta1/assets`) is using HTTP PATCH method. The behavioud would be similar with how PATCH works. It is possible to patch one field only in an asset by sending the updated field to the ingestion API. This also works for the data in dynamic `data` field. The combination of `urn`, `type`, `service` will be the identifier to patch an asset. -In case the `urn` does not exist, the asset ingestion PATCH API \(/v1beta1/assets\) will create a new asset. - -## Lineage - -Lineage is the origin or history of an asset. It represents a series of transformation of one or many assets. - -Each asset can have downstream/s and upstream/s. An asset without a single downstream, tells us that it is the end of the lineage, while an asset without a single upstream means that it is a start of a lineage. - -This is how a lineage is currently being represented - -```text -[ - { - "source": { - "urn": "topic/order-log", - "type": "topic", - "service": "kafka" - }, - "target": { - "urn": "bqtable/order_monthly", - "type": "table", - "service": "bigquery" - }, - "props": nil - }, - { - "source": { - "urn": "topic/order-log", - "type": "topic", - "service": "kafka" - }, - "target": { - "urn": "bqtable/order_daily", - "type": "table", - "service": "bigquery" - }, - "props": nil - }, -] -``` - -## Asset Versioning - -Compass versions each updated asset ingested via Upsert Patch API. The base version of an asset is `v0.1`. The base version will be given to the newly created asset. If there is any changes in the asset schema, a new version will be created. -Up until now, Compass always bump up the minor version if an asset get updated. The version history of an asset could also be fetched via [/v1beta1/assets/{id}/versions](https://github.com/raystack/compass/blob/main/third_party/OpenAPI/compass.swagger.json) API. -Not only storing the versions of an asset, Compass also stores the changelog between each version. Compass use [r3labs/diff](https://github.com/r3labs/diff) to get the diff between newly ingested asset and the existing asset. - -For instance, there is an asset with urn `kafka:booking-log-kafka` - -```text -{ - "id": "f2bb4e02-12b6-4c9f-aa9d-7d56aaaeb51e", - "urn": "kafka:booking-log-kafka", - "type": "topic", - "service": "kafka", - "data": {}, - "labels": { - "environment": "integration" - }, - "version": "0.1" -} -``` - -If there is an update to the `environment` in the asset labels, here is the asset version history stored in Compass: - -```text -{ - "id": "f2bb4e02-12b6-4c9f-aa9d-7d56aaaeb51e", - "urn": "kafka:booking-log-kafka", - "type": "topic", - "service": "kafka", - "data": {}, - "labels": { - "environment": "production" - }, - "version": "0.2" - "changelog": [ - { - "type": "update", - "path": ["labels","environment"], - "from": "integration", - "to": "production - } - ] -} -``` - -## Tagging an Asset - -Compass allows user to tag a specific asset. To tag a new asset, one needs to create a template of the tag. Tag's template defines a set of fields' tag that are applicable to tag each field in an asset. -Once a template is created, each field in an asset is possible to be tagged by calling `/v1beta1/tags` API. More detail about [Tagging](../guides/tagging.md). diff --git a/docs/docs/concepts/type.md b/docs/docs/concepts/type.md deleted file mode 100644 index 567b7ff2..00000000 --- a/docs/docs/concepts/type.md +++ /dev/null @@ -1,15 +0,0 @@ -# Type - -Each Asset will have a `Type` to represent the kind of metadata it represents. It is currently pre-defined by Compass, so no arbitrary types will be supported. - -Compass currently supports the following types: -1. `table` -2. `job` -3. `dashboard` -4. `topic` -5. `feature_table` -6. `model` (under development) -7. `application` (under development) - -Type will be extremely useful for categorizing your assets and it will be really helpful during discovery. -Check [this section on querying assets](../guides/querying#using-the-get-assets-api) on how to leverage `type` for your discovery. diff --git a/docs/docs/concepts/user.md b/docs/docs/concepts/user.md deleted file mode 100644 index 5dbab2b4..00000000 --- a/docs/docs/concepts/user.md +++ /dev/null @@ -1,14 +0,0 @@ -# User -The current version of Compass does not have user management. Compass expects there is an external instance that manages user. Compass consumes user information from the configurable identity uuid header in every API call. The default name of the header is `Compass-User-UUID`. -Compass does not make any assumption of what kind of identity format that is being used. The `uuid` indicates that it could be in any form (e.g. email, UUIDv4, etc) as long as it is universally unique. -The current behaviour is, Compass will add a new user if the user information consumed from the header does not exist in Compass' database. - -## Phantom User -In Compass ingestion API, Compass allows asset to mentioned who is its own owners. During the ingestion, if the `email` field in the list of `owners` field in the asset is not empty, Compass will create a new `'Phantom User'` with the email but with empty UUID. -A `'Phantom User'` is a user that is written in the storage but with empty UUID. The `'Phantom User'` cannot do any user-related interaction (e.g. Starring, Discussion) in Compass. - -## Linking User -There is another configurable optional email header that Compass expect. The default name is `Compass-User-Email`. In case there is already an existing `'Phantom User'`, if there is a request coming to Compass with completed user information in its header (uuid header and email header are not empty), Compass will register the UUID to the existing `'Phantom User'` and the `'Phantom User'` becomes a normal user. By doing so, assets ownership of that new user will immediately reflected. - -## User Provider -Since Compass expects that there is an external instance that manages user, it is possible for Compass to consume user information from multiple external instances. Compass distinguishes the source of user by marking it in the `provider` field. The default `provider` field value can be configured via config. \ No newline at end of file diff --git a/docs/docs/tour/1-my-first-asset.md b/docs/docs/tour/1-my-first-asset.md deleted file mode 100644 index 7d594248..00000000 --- a/docs/docs/tour/1-my-first-asset.md +++ /dev/null @@ -1,118 +0,0 @@ -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; - -# 1. My First Asset - -### Pre-Requisites - -1. [Setting up server](../configuration.md#server-setup) -2. [Setting up the CLI](../configuration.md#client-initialisation) (if you want to use the CLI client) - -## 1.1 Introduction - -In Compass, we call every metadata that you input as an [Asset](../concepts/asset). All your tables, dashboards, topics, jobs are an example of assets. - -In this section, we will help you to build your first Asset and hopefully it will give your clear idea about what an Asset is in Compass. - -## 1.2 Hello, ~~World~~ Asset! - -Let's imagine we have a `postgres` instance that we keep referring to as our `main-postgres`. Inside it there is a database called `my-database` that has plenty of tables. One of the tables is named `orders`, and below is how you represent that `table` as a Compass' Asset. - -```json -{ - "urn": "main-postgres:my-database.orders", - "type": "table", - "service": "postgres", - "name": "orders", - "data": { - "database": "my-database", - "namespace": "main-postgres" - } -} -``` - -- **urn** is a unique name you assign to an asset. You need to make sure you don't have a duplicate urns across all of your assets because Compass treats `urn` as an identifier of your asset. For this example, we use the following format to make sure our urn is unique, `{NAMESPACE}:{DB_NAME}.{TABLE_NAME}`. - -- **type** is your Asset's type. The value for type has to be recognizable by Compass. More info about Asset's Type can be found [here](../concepts/type). - -- **service** can be seen as the source of your asset. `service` can be anything, in this case since our `orders` table resides in `postgres`, we can just put `postgres` as the service. - -- **name** is the name of your asset, it does not have to be unique. We don't need to worry to get mixed up if there are other tables with the same name, `urn` will be the main identifier for your asset, that is why we need to make it unique across all of your assets. - -- **data** can hold your asset's extra details if there is any. In the example, we use it to store information of the **database name** and the **alias/namespace** that we use when referring the postgres instance. - -## 1.3 Sending your first asset to Compass -Assets can be created ingested in Compass using the following ways: - -1. Using `compass asset edit` CLI command -2. Calling to `PATCH /v1beta1/assets` API - -Let's send this into Compass so that it would be discoverable. - - - - -```bash -$ compass asset edit --body= -``` - -```json -{ - "asset": { - "urn": "main-postgres:my-database.orders", - "type": "table", - "service": "postgres", - "name": "orders", - "data": { - "database": "my-database", - "namespace": "main-postgres" - } - } -} -``` - - - -```bash -curl --location --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Content-Type: application/json' \ ---header 'Compass-User-UUID: john.doe@example.com' \ ---data-raw '{ - "asset": { - "urn": "main-postgres:my-database.orders", - "type": "table", - "service": "postgres", - "name": "orders", - "data": { - "database": "my-database", - "namespace": "main-postgres" - } - } -}' -``` - - - - -There are a few things to notice here: -1. The HTTP method used is `PATCH`. This is because Compass does not have a dedicated `Create` API, it uses a single API to `Patch / Create` an asset instead. So when updating or patching your asset, you can use the same API. Similarly we use `compass asset edit` for upserting via the Compass CLI tool - -2. Compass requires `Compass-User-UUID` header to be in the request. More information about the identity header can be found [here](../concepts/user). To simplify this tour, let's just use `john.doe@example.com`. For CLI, these configurations are to be done in the config file discussed [here](../configuration.md#required-headermetadata-in-api) - -3. When sending our asset to Compass, we need to put our asset object inside an `asset` field as shown in the example above - -4. For using the CLI tool, create a .json file using the example configurations shown above and provide the path to it here. - -On a success insertion, your will receive below response: - -```json -{ "id": "cebeb793-8933-434c-b38f-beb6dbad91a5" } -``` - -**id** is an identifier of your asset. Unlike `urn` which is provided by you, `id` is auto generated by Compass if there was no asset found with the given URN. - -## Conclusion - -Now that you have successfully ingested your asset to Compass, we can now search and find it via Compass. - -In the next section, we will see how Compass can help you in searching and discovering your assets. diff --git a/docs/docs/tour/2-querying-assets.mdx b/docs/docs/tour/2-querying-assets.mdx deleted file mode 100644 index 1f1811c0..00000000 --- a/docs/docs/tour/2-querying-assets.mdx +++ /dev/null @@ -1,208 +0,0 @@ -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -# 2. Querying your Assets - -In this section, we will learn how we can find and search our assets using the following approaches: -- [Using URN or ID](#21-using-asset-urn-or-id) -- [Using Search API](#23-using-search-api) - -## 2.1 Using Asset URN or ID - -Using the Asset URN or ID returned from when [you are uploading your asset](./1-my-first-asset.md#13-sending-your-first-asset-to-compass), you can easily find your asset like below - - - - -```bash -$ compass asset view main-postgres:my-database.orders -``` - - - - -```bash -curl 'http://localhost:8080/v1beta1/assets/main-postgres:my-database.orders' \ ---header 'Content-Type: application/json' \ ---header 'Compass-User-UUID: john.doe@example.com' -``` - - - - -Response from the above query -```json -{ - "data": { - "id": "cebeb793-8933-434c-b38f-beb6dbad91a5", - "urn": "main-postgres:my-database.orders", - "type": "table", - "service": "postgres", - "name": "orders", - "description": "", - "data": { - "database": "my-database", - "namespace": "main-postgres" - }, - "labels": null, - "owners": [], - "version": "0.2", - "updated_by": { - "uuid": "john.doe@example.com" - }, - "changelog": [], - "created_at": "2021-03-22T22:45:11.160593Z", - "updated_at": "2021-03-22T22:45:11.160593Z" - } -} -``` - -## 2.2 Adding more assets - -Before we try other APIs let's first add **5 additional assets** to Compass. - - - - -```bash -curl --location --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Content-Type: application/json' \ ---header 'Compass-User-UUID: john.doe@example.com' \ ---data-raw '{ - "asset": { - "urn": "main-postgres:my-database.products", - "type": "table", - "service": "postgres", - "name": "products", - "data": { - "database": "my-database", - "namespace": "main-postgres" - } - } -} -' -``` - - - - -```bash -curl --location --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Content-Type: application/json' \ ---header 'Compass-User-UUID: john.doe@example.com' \ ---data-raw '{ - "asset": { - "urn": "main-postgres:temp-database.invoices", - "type": "table", - "service": "postgres", - "name": "invoices", - "data": { - "database": "temp-database", - "namespace": "main-postgres" - } - } -} -' -``` - - - - -```bash -curl --location --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Content-Type: application/json' \ ---header 'Compass-User-UUID: john.doe@example.com' \ ---data-raw '{ - "asset": { - "urn": "userdb:identity.users", - "type": "table", - "service": "mysql", - "name": "users", - "data": { - "database": "identity", - "namespace": "userdb" - } - } -} -' -``` - - - - -```bash -curl --location --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Content-Type: application/json' \ ---header 'Compass-User-UUID: john.doe@example.com' \ ---data-raw '{ - "asset": { - "urn": "mymetabase:collections/123", - "type": "dashboard", - "service": "metabase", - "name": "My Profit Dashboard", - "data": { - "collection_id": 123, - "charts": [ - "Income Chart", - "Outcome Chart" - ] - } - } -} -' -``` - - - - -## 2.3 Using Search API - -Search API is the preferred way when browsing through your assets in Compass. Let's see how powerful Compass is for discovering your assets. - -Now that we have added more assets to Compass [here](#22-adding-more-assets), let's try to search for our newly added `products` table. To use Search API, we just need to provide a query/text/term. - -Let's search for our `products` table using a typo query `"podcts"`. - - - - -```bash -$ compass search "podcts" -``` - - - - -```bash -curl 'http://localhost:8080/v1beta1/search?text=podcts' \ ---header 'Compass-User-UUID: john.doe@example.com' -``` - - - - -Search results: -```json -{ - "data": [ - { - "id": "7c0759f4-feec-4b5e-bf26-bf0d0b1236b1", - "urn": "main-postgres:my-database.products", - "type": "table", - "service": "postgres", - "name": "products", - "description": "" - } - ] -} -``` - -Compass Search API supports fuzzy search, so even when you give `"podcts"`, it will still be able to fetch your `products` table. - -## Conclusion - -Search API is a really powerful discovery tool that you can leverage when storing your assets. It has lots of feature like `fuzzy search` which we just saw, you can also easily filter through asset's type, service and much more. - -Up to this point, you have learnt how to create assets, inserting assets and querying them. Using these features, you can start leveraging Compass to be your Metadata Discovery Service. - -Next we will see how you can use Compass to build a Lineage between your assets. diff --git a/docs/docs/tour/3-asset-lineage.mdx b/docs/docs/tour/3-asset-lineage.mdx deleted file mode 100644 index 0637f8bf..00000000 --- a/docs/docs/tour/3-asset-lineage.mdx +++ /dev/null @@ -1,132 +0,0 @@ -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; - -# 3. Asset Lineage - -## 3.1 Inserting lineage -To have a lineage, we need at least two assets to be linked with each other. -Compass only needs one of the assets to define the lineage. - -Let's create a new dashboard asset (tableau) that uses data from the `main-postgres:my-database.orders` table asset that we created earlier in [first section](./1-my-first-asset.md#13-sending-your-first-asset-to-compass). -And while creating the asset, we can also define its lineage in the same request. - - - - -```bash -$ compass asset edit --body= -``` -Example asset.json configuration for creating the `upstream` lineage (denoting the source of the asset data) -```json -{ - "asset": { - "urn": "tableau:my-dashboard.daily-orders", - "type": "dashboard", - "service": "tableau", - "name": "Daily Orders Dashboard", - "description": "This is a dashboard showing daily orders" - }, - "upstreams": [ - { - "urn": "main-postgres:my-database.orders" - } - ] -} -``` - - - - -```bash -curl --location --request PATCH 'http://localhost:8080/v1beta1/assets' \ ---header 'Content-Type: application/json' \ ---header 'Compass-User-UUID: john.doe@example.com' \ ---data-raw '{ - "asset": { - "urn": "tableau:my-dashboard.daily-orders", - "type": "dashboard", - "service": "tableau", - "name": "Daily Orders Dashboard", - "description": "This is a dashboard showing daily orders" - }, - "upstreams": [ - { - "urn": "main-postgres:my-database.orders" - } - ] -}' -``` - - - - -We use `upstreams` and `downstreams` field to define lineage. -From the example above `main-postgres:my-database.orders` is the source of the dashboard, so we put it inside `upstreams` field. - -And just like that we created a lineage :) - -## Querying Lineage - -Once lineage is defined, we can easily fetch them using a single asset URN to be the center of the lineage like below - - - - -```bash -$ compass lineage tableau:my-dashboard.daily-orders -``` - - - - -```bash -curl 'http://localhost:8080/v1beta1/lineage/tableau:my-dashboard.daily-orders' \ ---header 'Compass-User-UUID: john.doe@example.com' -``` - - - - -And you will get this as the response - -```json -{ - "data": [ - { - "source": "main-postgres:my-database.orders", - "target": "tableau:my-dashboard.daily-orders", - "prop": { - "root": "tableau:my-dashboard.daily-orders" - } - } - ] -} -``` - -You can also get the lineage using the URN `main-postgres:my-database.orders`, even when you have only defined `upstreams` on `tableau:my-dashboard.daily-orders`. - - - - -```bash -$ compass lineage main-postgres:my-database.orders -``` - - - - -```bash -curl 'http://localhost:8080/v1beta1/lineage/main-postgres:my-database.orders' \ ---header 'Compass-User-UUID: john.doe@example.com' -``` - - - - -## Conclusion - -This is merely a simple example of how Compass can help you manage and build your Data Lineage. -You just need to dump all of your assets along with its `upstreams` and `downstreams` as shown above and Compass will take care of the rest. - -And that's it, we have just covered all the basics of Compass and how you can use it to manage and maintain your metadata. -Aside from features introduced in this tour, Compass also has additional features such as Asset starring and discussion, you can check those in the [Guides section](../guides/starring). diff --git a/docs/docs/tour/introduction.md b/docs/docs/tour/introduction.md deleted file mode 100644 index 823ac385..00000000 --- a/docs/docs/tour/introduction.md +++ /dev/null @@ -1,49 +0,0 @@ -# Introduction - -This tour introduces you to Compass. Along the way you will learn how to ingest assets in Compass database, list, search and manage asset lineage. -### Prerequisites - -This tour requires you to have a Compass CLI tool installed on your local machine. -You can run `compass` to verify the installation. Please follow [installation](../installation) and [configuration](../configuration) guides if you do not have it installed already. - -Compass CLI and clients talks to Compass server to publish and fetch assets, search and lineage. Please make sure you also have a Compass server running. You can also run server locally with `compass server start` command. For more details check deployment guide. - -### Help - -At any time you can run the following commands. - -``` -# See the help for a command -$ compass --help -``` - -The list of all available commands are as follows: - -```text -Core commands - asset Manage assets - discussion Manage discussions - lineage observe the lineage of metadata - search query the metadata available - -Other commands - completion Generate shell completion scripts - config Manage server and client configurations - help Help about any command - server Manage server - version Print version information - -Help topics - environment List of supported environment variables - reference Comprehensive reference of all commands -``` - -Help command can also be run on any sub command with syntax `compass --help` Here is an example for the same. - -``` -$ compass asset --help -``` - -### Background for this tutorial - -Let's imagine we have a postgres instance running with a database called `my-database` that has plenty of tables. One of the tables is named `orders`. We will ingest this asset, list and search the metadata from Compass. If you don't know what an asset is, don't worry we have got you covered in the [next page](./1-my-first-asset.md#12-hello-world-asset). We will also be defining certain rules to inserting and quering lineage between tables `dailyorders` and `orders` in this example guide. \ No newline at end of file diff --git a/docs/sidebars.js b/docs/sidebars.js index 6c888869..9ee7749c 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -3,35 +3,11 @@ module.exports = { 'introduction', 'installation', 'configuration', - { - type: 'category', - label: 'Tour', - items: [ - "tour/introduction", - "tour/my-first-asset", - "tour/querying-assets", - "tour/asset-lineage" - ] - }, - { - type: "category", - label: "Guides", - items: [ - "guides/ingestion", - "guides/querying", - "guides/starring", - "guides/tagging", - "guides/discussion", - ], - }, { type: "category", label: "Concepts", items: [ "concepts/overview", - "concepts/asset", - "concepts/type", - "concepts/user", "concepts/architecture", "concepts/internals", ], @@ -55,4 +31,4 @@ module.exports = { }, 'roadmap', ], -}; \ No newline at end of file +}; From e4988b2747a5cc96dcbc96c8ae293cca1c6b08b2 Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 29 Mar 2026 14:12:14 -0500 Subject: [PATCH 10/10] fix: resolve broken doc links and update concepts overview --- docs/docs/concepts/overview.mdx | 58 ++++++++++++++-------------- docs/docs/configuration.md | 4 +- docs/docs/introduction.md | 2 +- docs/docs/reference/configuration.md | 6 +-- 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/docs/docs/concepts/overview.mdx b/docs/docs/concepts/overview.mdx index e93fea08..c81eaeb4 100644 --- a/docs/docs/concepts/overview.mdx +++ b/docs/docs/concepts/overview.mdx @@ -1,30 +1,32 @@ # Overview -Compass has three major concept when it comes to data ingestion: Asset, Type, and Service. - -Asset is the main model that represents a metadata of a specific service with a specific type. - -Type defines a ‘type’ of an asset and it is pre-defined. Compass currently supports the following types: -1. `table` -2. `job` -3. `dashboard` -4. `topic` -5. `feature_table` -6. `model` (under development) -7. `application` (under development) - -Service defines the application or source that maintains or generates the asset. Examples would be `biquery`, `postgres`, etc. - -Some features that compass has: -* [Discovery](../tour/2-querying-assets.mdx) -* [Lineage](../tour/3-asset-lineage.mdx) -* [Asset Tagging](./asset#tagging-an-asset) -* [User](./user.md) -* [Discussion](../guides/discussion.md) -* [Starring](../guides/starring.md) - -## Discussion -Compass supports discussion feature. User could drop comments in each discussion. Currently, there are three types of discussions `issues`, `open ended`, and `question and answer`. Depending on the type, the discussion could have multiple possible states. In the current version, all types only have two states: `open` and `closed`. A newly created discussion will always be assign an `open` state. More detail about [Discussion](../guides/discussion.md). - -## Starring -Compass allows a user to stars an asset. This bookmarking functionality is introduced to increase the speed of a user to get information. There is also an API to see which users star an asset (stargazers). More detail about [Starring](../guides/starring.md). +Compass is an organizational context engine that builds a temporal entity graph of your systems and serves it to AI agents via MCP. + +## Core Concepts + +**Entity** is the core domain object — anything worth naming in your organization's knowledge graph: a table, service, pipeline, satellite, person, decision, etc. Entities have an open type system — any non-empty string is a valid type. + +**Edge** is a typed, directed, temporal relationship between two entities. Lineage, ownership, and other relationships are all modeled as edges. + +**Chunk** is a text fragment with a vector embedding for semantic search. Chunks are derived from entities — they're an indexing mechanism, not knowledge. + +## Features + +- **Entity Graph**: Temporal entities with typed edges and properties (JSONB) +- **Search**: Keyword (tsvector), semantic (pgvector), and hybrid (RRF fusion) +- **Context Assembly**: `get_context` builds a subgraph around any entity +- **Impact Analysis**: `impact` traces downstream blast radius +- **MCP Tools**: AI agents query the graph via MCP protocol +- **Stars**: Users can star entities for quick access + +## Architecture + +All search is Postgres-native — no Elasticsearch dependency: + +| Mode | Engine | Purpose | +|---|---|---| +| Keyword | tsvector + pg_trgm | Exact matches, fuzzy/typo tolerance | +| Semantic | pgvector cosine | Conceptual/natural language | +| Hybrid | Both + RRF fusion | Best of both | + +Schema: `namespaces` → `users` → `entities` → `edges` → `chunks` → `stars` diff --git a/docs/docs/configuration.md b/docs/docs/configuration.md index 1d6d5f7d..2a44b50b 100644 --- a/docs/docs/configuration.md +++ b/docs/docs/configuration.md @@ -269,9 +269,9 @@ client: #### Required Header/Metadata in API -Compass has a concept of [User](./concepts/user.md). In the current version, all APIs in Compass require an identity header in the request. The header key is configurable but the default name is `Compass-User-UUID`. +Compass has a concept of User. In the current version, all APIs in Compass require an identity header in the request. The header key is configurable but the default name is `Compass-User-UUID`. -Compass APIs also expect an additional optional e-mail header. This is also configurable and the default name is `Compass-User-Email`. The purpose of having this optional e-mail header is described in the [User](./concepts/user.md) section. +Compass APIs also expect an additional optional e-mail header. This is also configurable and the default name is `Compass-User-Email`. The purpose of having this optional e-mail header is described in the API reference. If everything goes ok, you should see something like this: diff --git a/docs/docs/introduction.md b/docs/docs/introduction.md index 6b8771d0..8c97c7cf 100644 --- a/docs/docs/introduction.md +++ b/docs/docs/introduction.md @@ -44,7 +44,7 @@ You can use the Compass command line interface to issue commands and to perform ### HTTPS API You can get hands on asset searching, listing, tagging, starring and much more by using the Compass HTTPS API, which lets you issue HTTPS requests directly to the service. When you use the HTTPS API, you must include the user information from the configurable identity uuid in the request header. -For more information, see the [User Management](./concepts/user.md) and [API reference](./reference/api.md) pages. +For more information, see the [API reference](./reference/api.md) page. ## Where to go from here diff --git a/docs/docs/reference/configuration.md b/docs/docs/reference/configuration.md index c4f24dbc..e73847bd 100644 --- a/docs/docs/reference/configuration.md +++ b/docs/docs/reference/configuration.md @@ -60,15 +60,15 @@ Compass's required variables to start using it. ### `IDENTITY_UUID_HEADER` * Example value: `Compass-User-UUID` * Type: `required` -* Header key to accept Compass User UUID. See [User](../concepts/user.md) for more information about the usage. +* Header key to accept Compass User UUID. See the API reference for more information. ### `IDENTITY_EMAIL_HEADER` * Example value: `Compass-User-Email` * Type: `optional` -* Header key to accept Compass User Email. See [User](../concepts/user.md) for more information about the usage. +* Header key to accept Compass User Email. See the API reference for more information. ### `IDENTITY_PROVIDER_DEFAULT_NAME` * Example value: `shield` * Type: `optional` -* Default value of user provider. See [User](../concepts/user.md) for more information about the usage. +* Default value of user provider. See the API reference for more information. ## Telemetry