Forked from lloeki/arel_composition_without_activerecord.rb
Created
October 10, 2016 19:32
-
-
Save matt-morris/598c2d43a24d6e2257334d3c348bf089 to your computer and use it in GitHub Desktop.
Arel composition (without ActiveRecord)
This file contains 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
# rebuttal of http://www.try-alf.org/blog/2013-10-21-relations-as-first-class-citizen | |
require 'arel' | |
require 'sqlite3' | |
require 'pry' | |
def suppliers | |
@suppliers ||= Arel::Table.new(:suppliers) | |
end | |
def cities | |
@cities ||= Arel::Table.new(:cities) | |
end | |
def suppliers_in(city) | |
suppliers.project(suppliers[:sid], suppliers[:name], suppliers[:city]) | |
.where(suppliers[:city].eq city) | |
end | |
def with_country(operand) | |
operand.join(cities).project(cities[:country]) | |
end | |
# with_country(suppliers_in('Paris')).to_sql | |
# => "SELECT `suppliers`.`sid`, `suppliers`.`name`, `suppliers`.`city`, `cities`.`country` FROM `suppliers` INNER JOIN `cities` WHERE `suppliers`.`city` = \"Paris\"" | |
# minimal hack of a sqlite adapter | |
Column = Struct.new(:name, :default, :cast_type, :sql_type, :null) | |
module SchemaCache | |
def schema_cache | |
self | |
end | |
def table_exists?(name) | |
tables.include?(name) | |
end | |
def tables | |
@tables ||= execute(<<-SQL).flatten | |
SELECT name FROM sqlite_master | |
WHERE type = 'table' AND NOT name = 'sqlite_sequence' | |
SQL | |
end | |
def columns(table_name) | |
schema = execute(<<-SQL) | |
PRAGMA table_info(#{table_name}) | |
SQL | |
@columns ||= schema.map do |_, name, type, not_null, default, _| | |
Column.new(name, default == 'null' ? nil : default, String, type, not_null == 0) | |
end | |
end | |
def columns_hash | |
@columns_hash ||= Hash.new do |h, table_name| | |
h[table_name] = Hash[columns(table_name).map { |col| | |
[col.name, col] | |
}] | |
end | |
end | |
end | |
module Quotes | |
def quote_table_name(name) | |
"`#{name}`" | |
end | |
def quote_column_name(name) | |
"`#{name}`" | |
end | |
def quote(value, column) | |
"\"#{value}\"" | |
end | |
end | |
module Visitable | |
def visitor | |
@visitor ||= Arel::Visitors::SQLite.new(self) | |
end | |
end | |
$connection = SQLite3::Database.new(':memory:') | |
$connection.extend SchemaCache | |
$connection.extend Quotes | |
$connection.extend Visitable | |
$connection.execute(<<-SQL) | |
CREATE TABLE suppliers | |
(sid int, name varchar(255), status int, city varchar(255)) | |
SQL | |
$connection.execute(<<-SQL) | |
CREATE TABLE cities | |
(city varchar(255), country varchar(255)) | |
SQL | |
Arel::Table.engine = Class.new do | |
def connection | |
$connection | |
end | |
end.new | |
binding.pry |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment