feat(relation): add Relation decorator for declarative table links - #8
Merged
Conversation
Adds a property decorator that records relation metadata (target table thunk, optional target field, one-to-many flag) without enforcing any database constraint. Consumed by introspection tooling to expose links between tables. Claude-Session: https://claude.ai/code/session_01HnTc4Zvaayya2HqKGEVwTP
Member
Author
|
@greptile review |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🔗 Linked issue
N/A
❓ Type of change
📚 Description
Adds a
Relationproperty decorator that declares a link from a field to another table as declarative metadata only — database implementations do not enforce it (no foreign key constraint, no referential validation). Introspection tooling consumes it to expose the links between tables, e.g. to render schema diagrams or navigate related records.src/relation.tswithRelationdecorator,RelationOptions(tothunk for forward references, optionaltoField,manyflag) andRelationStaticMetadata.src/index.tsand exposed as a./relationsubpath inpackage.json.docs/2.table-definitions.md.Test plan:
pnpm run test— 96 tests pass, including the 5 newRelationtests.📝 Checklist
https://claude.ai/code/session_01HnTc4Zvaayya2HqKGEVwTP
Greptile Summary
This PR adds a
Relationproperty decorator that attaches declarative link metadata from a field to a target table class. The implementation follows the existingMakePropertyDecorator/getMetadatapattern used throughout the codebase forField,Index, and other decorators.src/relation.tsexportsRelationOptions,RelationStaticMetadata, and theRelationdecorator, which stores relation options keyed by property name on the class'sRelationStaticMetadatainstance.src/index.tsand given its own./relationsubpath export inpackage.json, consistent with the existing./model,./schema, etc. subpath pattern.Confidence Score: 5/5
This PR is safe to merge — it adds purely additive, declarative metadata with no enforcement logic and no changes to existing behavior.
The new Relation decorator is a thin wrapper over the existing MakePropertyDecorator / getMetadata infrastructure, storing options in a new metadata class. No existing code paths are modified, and the implementation is structurally identical to Field, Index, and other decorators in the codebase. Tests cover the key scenarios — storage, options round-tripping, forward references, and class isolation.
No files require special attention.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Dev as Developer participant Decorator as @Relation decorator participant MakePD as MakePropertyDecorator participant GetMeta as getMetadata() participant Meta as RelationStaticMetadata participant Tool as Introspection Tooling Dev->>Decorator: "@Relation({ to: () => Post, toField: "id", many: false })" Decorator->>MakePD: wraps callback MakePD->>GetMeta: getMetadata(target.constructor, RelationStaticMetadata) GetMeta-->>Meta: create or reuse instance (stored via Reflect) MakePD->>Meta: "metadata.relations["fieldName"] = options" Note over Meta: relations: { postId: { to, toField, many } } Tool->>GetMeta: getMetadata(CommentClass, RelationStaticMetadata) GetMeta-->>Meta: return stored instance Tool->>Meta: read relations Record Tool-->>Dev: schema diagram / navigation links%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant Dev as Developer participant Decorator as @Relation decorator participant MakePD as MakePropertyDecorator participant GetMeta as getMetadata() participant Meta as RelationStaticMetadata participant Tool as Introspection Tooling Dev->>Decorator: "@Relation({ to: () => Post, toField: "id", many: false })" Decorator->>MakePD: wraps callback MakePD->>GetMeta: getMetadata(target.constructor, RelationStaticMetadata) GetMeta-->>Meta: create or reuse instance (stored via Reflect) MakePD->>Meta: "metadata.relations["fieldName"] = options" Note over Meta: relations: { postId: { to, toField, many } } Tool->>GetMeta: getMetadata(CommentClass, RelationStaticMetadata) GetMeta-->>Meta: return stored instance Tool->>Meta: read relations Record Tool-->>Dev: schema diagram / navigation linksReviews (2): Last reviewed commit: "address greptile review feedback (greplo..." | Re-trigger Greptile