I'm using Arels
for creating query. In this query, I use generate_series
function. Here is my code:
def generate_series
Arel::Nodes::NamedFunction.new('GENERATE_SERIES', [start_date, end_day, '1 day'])
end
def start_date
Arel::Nodes::SqlLiteral.new(<<-SQL
CASE WHEN DATE_PART('hour', NOW() AT TIME ZONE 'ICT') < #{Time.now - 3days} THEN (CURRENT_DATE - INTERVAL '14 days') ELSE (CURRENT_DATE - INTERVAL '13 days') END
SQL
)
end
def end_date
Arel::Nodes::SqlLiteral.new(<<-SQL
CASE WHEN DATE_PART('hour', NOW() AT TIME ZONE 'ICT') < #{Time.now} THEN (CURRENT_DATE - INTERVAL '1 day') ELSE CURRENT_DATE END
SQL
)
end
When I try to test by generate_series.to_sql
. I meet exception:
Arel::Visitors::UnsupportedVisitError: Unsupported argument type: String. Construct an Arel node instead.
I try to shorter my code for testing:
def generate_series
Arel::Nodes::NamedFunction.new('GENERATE_SERIES', ['19/11/2012', '20/11/2012', '1 day'])
end
The problem is same. Please tell me how can I fix this problem.
Arel is a domain-specific-language allowing to express your queries in relational algebra. In past versions of Rails it was rather common to have to resort to Arel in order to accomplish some rather frequently requested functionalities, though nowadays Rails 6's Active Record already covers most of these use cases.
The #activerecord is what binds the model in our ruby application with its respective database table. The Active record object comes with a set of methods to help us query database records so theres no need to use raw SQL. For comparation purposes will present the translation of our activerecord queries to sql queries.
In older versions of rails, you should use the ActiveRecord::Base#scope class method to create such reusable queries. You are able to attain the same functionality by simply defining class methods: After defining the queries in such fashion, you are able to chain these high level abstractions together.
The Active record object comes with a set of methods to help us query database records so theres no need to use raw SQL. For comparation purposes will present the translation of our activerecord queries to sql queries.
You can use Arel::Nodes.build_quoted
to quote literals:
def generate_series
Arel::Nodes::NamedFunction.new('GENERATE_SERIES',
[start_date, end_date, Arel::Nodes.build_quoted('1 day')]
)
end
The advantage of this is that you don't have to remember to include and manually escape quotes like you do with Arel::Nodes::SqlLiteral
.
Your last parameter should be an Arel::Nodes
. So you should wrap 1 day
into an Arel::Nodes:SqlLiteral
. Here is updated code:
def generate_series
Arel::Nodes::NamedFunction.new('GENERATE_SERIES',
[start_date, end_date, Arel::Nodes::SqlLiteral.new('\'1 day\'')]
)
end
Noted that you must also wrap 1 day
inside (single) quotes, i.e: '1 day'
. Because if you don't do this, the generated query will be:
GENERATE_SERIES(start, stop, 1 day)
But true query should be:
GENERATE_SERIES(start, stop, '1 day')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With