Class: Serviced::Query

Inherits:
Object
  • Object
show all
Includes:
Typed
Defined in:
lib/serviced/query.rb

Overview

Base class for query objects: a named home for a complex read.

A query has the same typed, immutable inputs as a Service (see Typed), but instead of a Result it returns whatever #call returns, usually an ActiveRecord::Relation. Returning a relation keeps the result composable: callers can still paginate, add includes, or chain more scopes. A service then consumes the query and wraps its result in a Result.

class EnrolledPatientsQuery < Serviced::Query
attribute :clinic
attribute :program_external_id, :string
attribute :sort_direction, :string, default: "asc"

validates :sort_direction, inclusion: { in: %w[asc desc] }

def call
  clinic.patients
        .where("enrolled_in(?)", program_external_id)
        .order("enrolled_at #{sort_direction}")
end
end

relation = EnrolledPatientsQuery.call(clinic:, program_external_id: "cardio")
relation.page(params[:page]) # still a relation

Invalid inputs raise InvalidQuery (a query has no failure channel, so bad input is treated as a programming error).

The SQL helpers (#quote, #count_of, ...) require ActiveRecord at runtime.

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Typed

#initialize

Class Method Details

.call(attributes = {}) ⇒ Object

Builds the query, validates it, and runs #call.

Parameters:

  • attributes (Hash) (defaults to: {})

    input values; unknown keys are ignored

Returns:

  • (Object)

    whatever #call returns (typically an ActiveRecord::Relation)

Raises:



41
42
43
44
45
46
# File 'lib/serviced/query.rb', line 41

def call(attributes = {})
  query = new(attributes)
  raise InvalidQuery, query.errors if query.invalid?

  query.call
end

Instance Method Details

#callActiveRecord::Relation, Object

The query body. Subclasses must implement it and return a relation (to stay composable) or a materialized value.

Returns:

  • (ActiveRecord::Relation, Object)

Raises:

  • (NotImplementedError)


52
53
54
# File 'lib/serviced/query.rb', line 52

def call
  raise NotImplementedError, "#{self.class} must implement #call"
end