package store import ( "context" "errors" "time" ) // ItemReader is the read-path contract every projax UI handler, the // internal/aggregate fan-out engine, and the MCP read tools depend on. // Pure projax-shaped structs in/out; the slice-B mBrian-backed // implementation translates mBrian nodes/edges into the same shape // without leaking mBrian types to consumers. // // Phase 6 Slice B prep — see docs/plans/slice-b-adapter-contract.md. // The existing *Store already satisfies this interface (the compile-time // assertion below pins that). Slice B impl ships a second satisfier // (MBrianReader) once m/mBrian#73's migration completes and hands the // uuid map over. type ItemReader interface { // --- item lookups --- ListAll(ctx context.Context) ([]*Item, error) GetByID(ctx context.Context, id string) (*Item, error) GetByPath(ctx context.Context, path string) (*Item, error) GetByPathOrSlug(ctx context.Context, key string) (*Item, error) Roots(ctx context.Context) ([]*Item, error) MaiOrphans(ctx context.Context) ([]*Item, error) ListByFilters(ctx context.Context, f SearchFilters) ([]*Item, error) Search(ctx context.Context, q string, limit int) ([]*Item, error) ItemsCreatedInRange(ctx context.Context, from, to time.Time) ([]*Item, error) AllTags(ctx context.Context) ([]string, error) // --- link lookups --- LinksByType(ctx context.Context, itemID, refType string) ([]*ItemLink, error) LinksByRefType(ctx context.Context, refType string) ([]*ItemLink, error) DatedLinks(ctx context.Context, itemID string) ([]*ItemLink, error) DatedLinksRange(ctx context.Context, from, to time.Time) ([]*ItemLinkWithItem, error) RecentDocuments(ctx context.Context, since time.Time, limit int) ([]*ItemLinkWithItem, error) } // Compile-time assertion that the existing pgx-backed *Store satisfies // ItemReader. Drops in cleanly because every method in the interface is // already part of *Store's public surface. If a future refactor removes // or reshapes one of these methods on *Store, the compiler points at // this line first. var _ ItemReader = (*Store)(nil) // errNotImplementedSliceB is the placeholder return from every method on // the slice-B-prep stub. Slice B's impl replaces each return with the // real mBrian-backed body. var errNotImplementedSliceB = errors.New("not implemented: Phase 6 Slice B (mBrian-backed reader) — waits on m/mBrian#73 migration") // MBrianReader is the slice-B implementation target. Every method body // returns errNotImplementedSliceB during prep; slice B's coder fills // each in once the migration completes and the uuid map lands. The type // holds no mBrian client today — the client decision (MCP-over-stdio / // direct pgxpool against mbrian.* / in-process submodule) is the first // thing slice B's impl chooses, then this struct grows the // corresponding field. // // Per-method comments name the §3 gaps in the contract doc each method // will need to resolve at impl time. type MBrianReader struct { // Reserved for slice-B's mBrian client. Empty struct today so the // compile-time assertion below stays meaningful. } // Compile-time assertion that MBrianReader satisfies ItemReader. Keeps // the stubs in lockstep with the interface as slice B grows methods. var _ ItemReader = (*MBrianReader)(nil) // --- item lookups --- // ListAll: §2.1 — edge-walk for Item.Paths + Item.ParentIDs per item; // §2.2 — metadata-unpack across all returned items; §3 — Item.Source // constant. func (*MBrianReader) ListAll(ctx context.Context) ([]*Item, error) { return nil, errNotImplementedSliceB } // GetByID: §2.2 metadata-unpack. func (*MBrianReader) GetByID(ctx context.Context, id string) (*Item, error) { return nil, errNotImplementedSliceB } // GetByPath: §2.1 — walks child_of edges from path's root segment to // resolve a leaf node. Per-request cache reduces N+1. func (*MBrianReader) GetByPath(ctx context.Context, path string) (*Item, error) { return nil, errNotImplementedSliceB } // GetByPathOrSlug: GetByPath, fall back to slug lookup. func (*MBrianReader) GetByPathOrSlug(ctx context.Context, key string) (*Item, error) { return nil, errNotImplementedSliceB } // Roots: §2.1 — "no outbound child_of edge" predicate. func (*MBrianReader) Roots(ctx context.Context) ([]*Item, error) { return nil, errNotImplementedSliceB } // MaiOrphans: §2.1 — Roots ∩ metadata.projax.management ⊇ {'mai'}. func (*MBrianReader) MaiOrphans(ctx context.Context) ([]*Item, error) { return nil, errNotImplementedSliceB } // ListByFilters: structured search; status/management/has-link/paths-prefix // dimensions map to metadata.projax.* predicates + edge existence checks. func (*MBrianReader) ListByFilters(ctx context.Context, f SearchFilters) ([]*Item, error) { return nil, errNotImplementedSliceB } // Search: mBrian already has trigram + FTS on title + content_md // (idx_nodes_fts). Adapter narrows to projax-managed nodes. func (*MBrianReader) Search(ctx context.Context, q string, limit int) ([]*Item, error) { return nil, errNotImplementedSliceB } // ItemsCreatedInRange: direct over nodes.created_at, scoped to // metadata.projax_origin IS NOT NULL (or whatever projax-managed marker // the migration settles on). func (*MBrianReader) ItemsCreatedInRange(ctx context.Context, from, to time.Time) ([]*Item, error) { return nil, errNotImplementedSliceB } // AllTags: §3 — union over metadata.projax.tags[]. Full-scan at m's // scale; tag-graph deferred to Phase 7 (m's Q8). func (*MBrianReader) AllTags(ctx context.Context) ([]string, error) { return nil, errNotImplementedSliceB } // --- link lookups --- // LinksByType: §2.3 — WHERE source_id=$1 AND rel='projax-'||$2. func (*MBrianReader) LinksByType(ctx context.Context, itemID, refType string) ([]*ItemLink, error) { return nil, errNotImplementedSliceB } // LinksByRefType: §2.3 — WHERE rel='projax-'||$1. func (*MBrianReader) LinksByRefType(ctx context.Context, refType string) ([]*ItemLink, error) { return nil, errNotImplementedSliceB } // DatedLinks: §2.3 — one item's edges with metadata ? 'event_date'. func (*MBrianReader) DatedLinks(ctx context.Context, itemID string) ([]*ItemLink, error) { return nil, errNotImplementedSliceB } // DatedLinksRange: §2.3 — metadata->>'event_date' BETWEEN $1 AND $2, // joined with source node for the ItemLinkWithItem shape. func (*MBrianReader) DatedLinksRange(ctx context.Context, from, to time.Time) ([]*ItemLinkWithItem, error) { return nil, errNotImplementedSliceB } // RecentDocuments: dated links since $1 ORDER BY event_date DESC LIMIT $2. func (*MBrianReader) RecentDocuments(ctx context.Context, since time.Time, limit int) ([]*ItemLinkWithItem, error) { return nil, errNotImplementedSliceB }