Class: LinearToonMcp::Resolvers::Base
- Inherits:
-
Object
- Object
- LinearToonMcp::Resolvers::Base
- Defined in:
- lib/linear_toon_mcp/resolvers/base.rb
Overview
Base class for entity resolvers. Subclasses declare their lookup attributes and any required parent scope. UUIDs always pass through unchanged regardless of the declared attributes.
Defaults derive from the class name:
WorkflowState.connection_name # => "workflowStates"
WorkflowState.filter_type_name # => "WorkflowStateFilter"
WorkflowState.entity_label # => "State"
Override any default via Base.connection, Base.filter_type, or Base.label.
Direct Known Subclasses
Cycle, Initiative, IssueLabel, Project, ProjectMilestone, ProjectStatus, Team, User, WorkflowState
Constant Summary collapse
- ATTRIBUTES =
Lookup attribute catalog: value predicate paired with GraphQL filter builder.
{ name: { matches: ->(_v) { true }, filter: ->(v) { {name: {eqIgnoreCase: v}} } }, email: { matches: ->(v) { v.include?("@") }, filter: ->(v) { {email: {eq: v}} } }, number: { matches: ->(v) { v.match?(NUMERIC_RE) }, filter: ->(v) { {number: {eq: v.to_i}} } }, slug: { matches: ->(_v) { true }, filter: ->(v) { {slugId: {eqIgnoreCase: v}} } }, key: { matches: ->(v) { v.match?(/\A[A-Z]+\z/) }, filter: ->(v) { {key: {eq: v}} } }, type: { matches: ->(v) { v.match?(/\A[a-z]+\z/) }, filter: ->(v) { {type: {eq: v}} } } }.freeze
Class Attribute Summary collapse
-
.scope_config ⇒ Object
readonly
Returns the value of attribute scope_config.
Class Method Summary collapse
-
.attributes ⇒ Object
Returns the attributes declared via Base.lookup_by.
-
.call(value:, **scope) ⇒ String
Resolves
valueto a UUID using LinearToonMcp.client. -
.call_many(values:, **scope) ⇒ Array<String>
Resolves each value via Base.call, forwarding scope.
-
.connection(name) ⇒ Object
Overrides the derived GraphQL connection name.
-
.connection_name ⇒ Object
Returns the GraphQL connection name.
-
.entity_label ⇒ Object
Returns the not-found label — the trailing CamelCase word of Base.entity_name.
-
.entity_name ⇒ Object
Returns the entity name.
-
.filter_type(name) ⇒ Object
Overrides the derived GraphQL filter type name.
-
.filter_type_name ⇒ Object
Returns the GraphQL filter input type name.
-
.label(name) ⇒ Object
Overrides the derived not-found label.
-
.lookup_by(*attrs) ⇒ Object
Declares lookup attributes for this resolver, in priority order.
-
.query ⇒ Object
Returns the memoized GraphQL query.
-
.scoped_by(key, optional: false, workspace_fallback: false) ⇒ Object
Declares a parent-scoping kwarg expected by Base.call.
Instance Method Summary collapse
-
#initialize(**scope) ⇒ Base
constructor
A new instance of Base.
-
#resolve(value) ⇒ Object
Resolves
valueto a UUID.
Constructor Details
#initialize(**scope) ⇒ Base
Returns a new instance of Base.
158 159 160 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 158 def initialize(**scope) @scope = scope end |
Class Attribute Details
.scope_config ⇒ Object (readonly)
Returns the value of attribute scope_config.
95 96 97 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 95 def scope_config @scope_config end |
Class Method Details
.attributes ⇒ Object
Returns the attributes declared via lookup_by.
91 92 93 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 91 def attributes @attributes || [] end |
.call(value:, **scope) ⇒ String
Resolves value to a UUID using LinearToonMcp.client.
Team.call(value: "Engineering")
WorkflowState.call(value: "Done", team_id: tid)
144 145 146 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 144 def call(value:, **scope) new(**scope).resolve(value) end |
.call_many(values:, **scope) ⇒ Array<String>
Resolves each value via call, forwarding scope.
IssueLabel.call_many(values: ["bug", "p1"], team_id: tid)
153 154 155 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 153 def call_many(values:, **scope) values.map { |v| call(value: v, **scope) } end |
.connection(name) ⇒ Object
Overrides the derived GraphQL connection name.
76 77 78 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 76 def connection(name) @connection = name.to_s end |
.connection_name ⇒ Object
Returns the GraphQL connection name.
WorkflowState.connection_name # => "workflowStates"
100 101 102 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 100 def connection_name @connection ||= "#{entity_name[0].downcase}#{entity_name[1..]}s" end |
.entity_label ⇒ Object
Returns the not-found label — the trailing CamelCase word of entity_name.
WorkflowState.entity_label # => "State"
115 116 117 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 115 def entity_label @label ||= entity_name.scan(/[A-Z][a-z]+/).last || entity_name end |
.entity_name ⇒ Object
Returns the entity name.
WorkflowState.entity_name # => "WorkflowState"
122 123 124 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 122 def entity_name @entity_name ||= name.split("::").last end |
.filter_type(name) ⇒ Object
Overrides the derived GraphQL filter type name.
81 82 83 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 81 def filter_type(name) @filter_type = name.to_s end |
.filter_type_name ⇒ Object
Returns the GraphQL filter input type name.
WorkflowState.filter_type_name # => "WorkflowStateFilter"
107 108 109 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 107 def filter_type_name @filter_type ||= "#{entity_name}Filter" end |
.label(name) ⇒ Object
Overrides the derived not-found label.
86 87 88 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 86 def label(name) @label = name.to_s end |
.lookup_by(*attrs) ⇒ Object
53 54 55 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 53 def lookup_by(*attrs) @attributes = attrs.freeze end |
.query ⇒ Object
Returns the memoized GraphQL query.
127 128 129 130 131 132 133 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 127 def query @query ||= <<~GRAPHQL query($filter: #{filter_type_name}) { #{connection_name}(filter: $filter, first: 1) { nodes { id } } } GRAPHQL end |
.scoped_by(key, optional: false, workspace_fallback: false) ⇒ Object
71 72 73 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 71 def scoped_by(key, optional: false, workspace_fallback: false) @scope_config = {key: key, optional: optional, workspace_fallback: workspace_fallback}.freeze end |
Instance Method Details
#resolve(value) ⇒ Object
Resolves value to a UUID. UUIDs pass through unchanged; otherwise each lookup_by attribute is tried in declared order and the first GraphQL lookup that returns a node wins.
167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/linear_toon_mcp/resolvers/base.rb', line 167 def resolve(value) return value if value.match?(UUID_RE) self.class.attributes.each do |attr| definition = ATTRIBUTES.fetch(attr) { raise Error, "Unknown attribute: #{attr.inspect}" } next unless definition[:matches].call(value) id = lookup(definition[:filter].call(value).merge(scope_filter)) return id if id end raise Error, (value) end |