Skip to content

Builder

Georgy Yuriev edited this page May 15, 2018 · 6 revisions

Builder can be useful when you want to collect and use some complex data.

How does it work?

Let's imagine we don't use any ORM in a project and want to use pure SQL queries to control all processes. For this we can use a builder (DONT USE THIS CODE IN PRODUCTION! THIS IS JUST EXAMPLE TO UNDERSTAND HOW YOU CAN USE BUILDER).

First, create a new builder:

rails g builder sql

It will create app/builders/sql_builder.rb file.

Let's imagine we need only two operations with database: select and insert. We will not update or delete data. Here is the code:

# app/builders/sql_builder.rb
class SqlBuilder < Methodist::Builder
  OPERATIONS = [SELECT_OPERATION INSERT]

  field :operation, ->(val) { val.present? && OPERATIONS.include?(val) }
  field :source, -> (val) { val.present? } 
  field :columns
  field :where
  field :values
  field :order
  field :limit

  def result_query
    raise 'Invalid data in the builder' unless valid?
    send("#{operation.downcase}_query")
  end

  private

  def select_query
    str_query = "SELECT"
    str_query += if columns ? " #{columns}" : " *" 
    str_query += " FROM #{source}"
    str_query += " WHERE #{where}" if where
    str_query += " ORDER BY #{order}" if order
    str_query += " LIMIT(#{limit})" if order
    str_query
  end
  
  def insert_query
    str_query = "INSERT INTO"
    str_query += " (#{*columns})"
    str_query += " VALUES (#{*values})"
  end
 def 
end

In the #field method we define the field attribute. You can list all builder attributes with instance_of_builder.attributes. The second argument in the #field is a proc with validation. When procs return true for all attriubutes then #valid? also returns true.

Now we can use our builder:

query = SqlBuilder.new
query.operation = 'SELECT'
query.source = 'cars'
query.where = 'color = red'
query.order = 'created_at ASC'
query.limit = '2'

query.result_query # => "SELECT * FROM cars WHERE color = red ORDER BY created_at ASC LIMIT(2)"
query.columns = ["id", "producer", "color", "created_at"]
query.result_query # => "SELECT id, producer, color, created FROM cars WHERE color = red ORDER BY created_at ASC LIMIT(2)
query.valid? #=> true
query.operation = 'FailedOperation'
query.valid? #=> false

Clone this wiki locally