mirror of
https://github.com/lloeki/rebel.git
synced 2025-12-06 10:04:39 +01:00
Going public
This commit is contained in:
commit
77c44a0b2d
7 changed files with 331 additions and 0 deletions
7
Gemfile
Normal file
7
Gemfile
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
|
gemspec
|
||||||
|
|
||||||
|
gem 'rubocop'
|
||||||
|
gem 'minitest'
|
||||||
|
gem 'pry'
|
||||||
41
Gemfile.lock
Normal file
41
Gemfile.lock
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
PATH
|
||||||
|
remote: .
|
||||||
|
specs:
|
||||||
|
rebel (0.1.0)
|
||||||
|
|
||||||
|
GEM
|
||||||
|
remote: https://rubygems.org/
|
||||||
|
specs:
|
||||||
|
ast (2.3.0)
|
||||||
|
coderay (1.1.1)
|
||||||
|
method_source (0.8.2)
|
||||||
|
minitest (5.10.1)
|
||||||
|
parser (2.4.0.0)
|
||||||
|
ast (~> 2.2)
|
||||||
|
powerpack (0.1.1)
|
||||||
|
pry (0.10.4)
|
||||||
|
coderay (~> 1.1.0)
|
||||||
|
method_source (~> 0.8.1)
|
||||||
|
slop (~> 3.4)
|
||||||
|
rainbow (2.2.1)
|
||||||
|
rubocop (0.47.1)
|
||||||
|
parser (>= 2.3.3.1, < 3.0)
|
||||||
|
powerpack (~> 0.1)
|
||||||
|
rainbow (>= 1.99.1, < 3.0)
|
||||||
|
ruby-progressbar (~> 1.7)
|
||||||
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||||
|
ruby-progressbar (1.8.1)
|
||||||
|
slop (3.6.0)
|
||||||
|
unicode-display_width (1.1.3)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
ruby
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
minitest
|
||||||
|
pry
|
||||||
|
rebel!
|
||||||
|
rubocop
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
1.14.5
|
||||||
19
LICENSE
Normal file
19
LICENSE
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2016 Loic Nageleisen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
37
README.md
Normal file
37
README.md
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Rebel - Ruby-flavored SQL
|
||||||
|
|
||||||
|
SQL-flavored Ruby.
|
||||||
|
|
||||||
|
```
|
||||||
|
You've been fighting yet another abstraction...
|
||||||
|
Aren't you fed up with object-relation magic?
|
||||||
|
But wait, here comes a humongous migration.
|
||||||
|
Is ActiveRecord making you sick?
|
||||||
|
To hell with that monstrous ARel expression!
|
||||||
|
Tell the truth, you were just wishing
|
||||||
|
That it was as simple as a here-string.
|
||||||
|
But could it keep some Ruby notation
|
||||||
|
Instead of silly interpolations?
|
||||||
|
Stop the menace, time for a revolution!
|
||||||
|
|
||||||
|
Rebel!
|
||||||
|
|
||||||
|
No magic
|
||||||
|
No bullshit
|
||||||
|
No layers
|
||||||
|
No wrappers
|
||||||
|
No smarty-pants
|
||||||
|
No weird stance
|
||||||
|
No sexy
|
||||||
|
No AST
|
||||||
|
No lazy loading
|
||||||
|
No crazy mapping
|
||||||
|
No pretense
|
||||||
|
No nonsense
|
||||||
|
|
||||||
|
What you write is what you get: readable and obvious
|
||||||
|
What you write is what you meant: tasty and delicious
|
||||||
|
|
||||||
|
Wait, it doesn't execute!?
|
||||||
|
Just use your fave client gem, isn't that cute?
|
||||||
|
```
|
||||||
3
lib/rebel.rb
Normal file
3
lib/rebel.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module Rebel; end
|
||||||
|
|
||||||
|
require 'rebel/sql'
|
||||||
213
lib/rebel/sql.rb
Normal file
213
lib/rebel/sql.rb
Normal file
|
|
@ -0,0 +1,213 @@
|
||||||
|
module Rebel::SQL
|
||||||
|
attr_reader :conn
|
||||||
|
|
||||||
|
def exec(query)
|
||||||
|
conn.exec(query)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_table(table_name, desc)
|
||||||
|
exec(SQL.create_table(table_name, desc))
|
||||||
|
end
|
||||||
|
|
||||||
|
def select(*fields, from: nil, where: nil, inner: nil, left: nil, right: nil)
|
||||||
|
exec(SQL.select(*fields,
|
||||||
|
from: from,
|
||||||
|
where: where,
|
||||||
|
inner: inner,
|
||||||
|
left: left,
|
||||||
|
right: right))
|
||||||
|
end
|
||||||
|
|
||||||
|
def insert_into(table_name, *rows)
|
||||||
|
exec(SQL.insert_into(table_name, *rows))
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(table_name, set: nil, where: nil, inner: nil, left: nil, right: nil)
|
||||||
|
exec(SQL.update(table_name, set: set, where: where, inner: inner, left: left, right: right))
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_from(table_name, where: nil, inner: nil, left: nil, right: nil)
|
||||||
|
exec(SQL.delete_from(table_name, where: where, inner: inner, left: left, right: right))
|
||||||
|
end
|
||||||
|
|
||||||
|
def truncate(table_name)
|
||||||
|
exec(SQL.truncate(table_name))
|
||||||
|
end
|
||||||
|
|
||||||
|
def count(*n)
|
||||||
|
SQL.count(*n)
|
||||||
|
end
|
||||||
|
|
||||||
|
def join(table, on: nil)
|
||||||
|
SQL.join(table, on: on)
|
||||||
|
end
|
||||||
|
|
||||||
|
def outer_join(table, on: nil)
|
||||||
|
SQL.outer_join(table, on: on)
|
||||||
|
end
|
||||||
|
|
||||||
|
class Raw < String
|
||||||
|
def as(n)
|
||||||
|
Raw.new(self + " AS #{SQL.name(n)}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def as?(n)
|
||||||
|
n ? as(n) : self
|
||||||
|
end
|
||||||
|
|
||||||
|
def on(clause)
|
||||||
|
Raw.new(self + " ON #{SQL.and_clause(clause)}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def on?(clause)
|
||||||
|
clause ? on(clause) : self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def raw(str)
|
||||||
|
Raw.new(str)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_table(table_name, desc)
|
||||||
|
<<-SQL
|
||||||
|
CREATE TABLE #{SQL.name(table_name)} (
|
||||||
|
#{SQL.list(desc.map { |k, v| "#{SQL.name(k)} #{v}" })}
|
||||||
|
);
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
|
def select(*fields, from: nil, where: nil, inner: nil, left: nil, right: nil)
|
||||||
|
<<-SQL
|
||||||
|
SELECT #{names(*fields)} FROM #{name(from)}
|
||||||
|
#{SQL.inner?(inner)}
|
||||||
|
#{SQL.left?(left)}
|
||||||
|
#{SQL.right?(right)}
|
||||||
|
#{SQL.where?(where)};
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
|
def insert_into(table_name, *rows)
|
||||||
|
<<-SQL
|
||||||
|
INSERT INTO #{SQL.name(table_name)} (#{SQL.names(*rows.first.keys)})
|
||||||
|
VALUES #{SQL.list(rows.map { |r| "(#{SQL.values(*r.values)})" })};
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(table_name, set: nil, where: nil, inner: nil, left: nil, right: nil)
|
||||||
|
fail ArgumentError if set.nil?
|
||||||
|
|
||||||
|
<<-SQL
|
||||||
|
UPDATE #{SQL.name(table_name)}
|
||||||
|
SET #{SQL.assign_clause(set)}
|
||||||
|
#{SQL.inner?(inner)}
|
||||||
|
#{SQL.left?(left)}
|
||||||
|
#{SQL.right?(right)}
|
||||||
|
#{SQL.where?(where)};
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_from(table_name, where: nil, inner: nil, left: nil, right: nil)
|
||||||
|
<<-SQL
|
||||||
|
DELETE FROM #{SQL.name(table_name)}
|
||||||
|
#{SQL.inner?(inner)}
|
||||||
|
#{SQL.left?(left)}
|
||||||
|
#{SQL.right?(right)}
|
||||||
|
#{SQL.where?(where)};
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
|
def truncate(table_name)
|
||||||
|
<<-SQL
|
||||||
|
TRUNCATE #{SQL.name(table_name)};
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
def count(*n)
|
||||||
|
raw("COUNT(#{names(*n)})")
|
||||||
|
end
|
||||||
|
|
||||||
|
def join(table, on: nil)
|
||||||
|
raw("JOIN #{name(table)}").on?(on)
|
||||||
|
end
|
||||||
|
|
||||||
|
def outer_join(table, on: nil)
|
||||||
|
raw("OUTER JOIN #{name(table)}").on?(on)
|
||||||
|
end
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
def name(name)
|
||||||
|
return name if name.is_a?(Raw)
|
||||||
|
return raw('*') if name == '*'
|
||||||
|
|
||||||
|
name.to_s.split('.').map { |e| "\"#{e}\"" }.join('.')
|
||||||
|
end
|
||||||
|
|
||||||
|
def names(*names)
|
||||||
|
list(names.map { |k| name(k) })
|
||||||
|
end
|
||||||
|
|
||||||
|
def list(*items)
|
||||||
|
items.join(', ')
|
||||||
|
end
|
||||||
|
|
||||||
|
def value(v)
|
||||||
|
case v
|
||||||
|
when Raw then v
|
||||||
|
when String then raw "'#{v.tr("'", "''")}'"
|
||||||
|
when Fixnum then raw v.to_s
|
||||||
|
when nil then raw 'NULL'
|
||||||
|
else fail NotImplementedError, v.inspect
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def values(*values)
|
||||||
|
list(values.map { |v| value(v) })
|
||||||
|
end
|
||||||
|
|
||||||
|
def name_or_value(item)
|
||||||
|
item.is_a?(Symbol) ? name(item) : value(item)
|
||||||
|
end
|
||||||
|
|
||||||
|
def equal(l, r)
|
||||||
|
"#{name_or_value(l)} = #{name_or_value(r)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_clause(clause)
|
||||||
|
list(clause.map { |k, v| equal(k, v) })
|
||||||
|
end
|
||||||
|
|
||||||
|
def and_clause(clause)
|
||||||
|
return clause if clause.is_a?(Raw) || clause.is_a?(String)
|
||||||
|
|
||||||
|
clause.map do |e|
|
||||||
|
case e
|
||||||
|
when Array then "#{name(e[0])} = #{name_or_value(e[1])}"
|
||||||
|
when Raw, String then e
|
||||||
|
else fail NotImplementedError, e.class
|
||||||
|
end
|
||||||
|
end.join(' AND ')
|
||||||
|
end
|
||||||
|
|
||||||
|
def where?(clause)
|
||||||
|
return "WHERE #{clause}" if clause.is_a?(Raw) || clause.is_a?(String)
|
||||||
|
|
||||||
|
(clause && clause.any?) ? "WHERE #{SQL.and_clause(clause)}" : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def inner?(join)
|
||||||
|
join ? "INNER #{join}" : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def left?(join)
|
||||||
|
join ? "LEFT #{join}" : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def right?(join)
|
||||||
|
join ? "RIGHT #{join}" : nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
11
rebel.gemspec
Normal file
11
rebel.gemspec
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
Gem::Specification.new do |s|
|
||||||
|
s.name = 'rebel'
|
||||||
|
s.version = '0.1.0'
|
||||||
|
s.licenses = ['MIT']
|
||||||
|
s.summary = "Fight against the Object tyranny"
|
||||||
|
s.description = "Write SQL queries in Ruby, or is it the other way around?"
|
||||||
|
s.authors = ["Loic Nageleisen"]
|
||||||
|
s.email = 'loic.nageleisen@gmail.com'
|
||||||
|
s.files = ["lib/**/*.rb"]
|
||||||
|
s.homepage = 'https://github.com/lloeki/rebel.git'
|
||||||
|
end
|
||||||
Loading…
Add table
Add a link
Reference in a new issue