cheatsheets/_output/sequel.html

413 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title></title>
<link href="style.css" rel="stylesheet" />
</head>
<body>
<h1>Sequel</h1>
<h1>Cheat Sheet </h1>
<h2>Open a database</h2>
<pre>
require 'rubygems'
require 'sequel'
DB = Sequel.sqlite('my_blog.db')
DB = Sequel.connect('postgres://user:password@localhost/my_db')
DB = Sequel.postgres('my_db', :user =&gt; 'user', :password =&gt; 'password', :host =&gt; 'localhost')
DB = Sequel.ado('mydb')
</pre>
<h2>Open an SQLite memory database</h2>
<p>
Without a filename argument, the sqlite adapter will setup a new sqlite
database in memory.
</p>
<pre>
DB = Sequel.sqlite
</pre>
<h2>Logging SQL statements</h2>
<pre>
require 'logger'
DB = Sequel.sqlite '', :loggers =&gt; [Logger.new($stdout)]
# or
DB.loggers &lt;&lt; Logger.new(...)
</pre>
<h2>Using raw SQL</h2>
<pre>
DB.run &quot;CREATE TABLE users (name VARCHAR(255) NOT NULL, age INT(3) NOT NULL)&quot;
dataset = DB[&quot;SELECT age FROM users WHERE name = ?&quot;, name]
dataset.map(:age)
DB.fetch(&quot;SELECT name FROM users&quot;) do |row|
p row[:name]
end
</pre>
<h2>Create a dataset</h2>
<pre>
dataset = DB[:items]
dataset = DB.from(:items)
</pre>
<h2>Most dataset methods are chainable</h2>
<pre>
dataset = DB[:managers].where(:salary =&gt; 5000..10000).order(:name, :department)
</pre>
<h2>Insert rows</h2>
<pre>
dataset.insert(:name =&gt; 'Sharon', :grade =&gt; 50)
</pre>
<h2>Retrieve rows</h2>
<pre>
dataset.each{|r| p r}
dataset.all # =&gt; [{...}, {...}, ...]
dataset.first # =&gt; {...}
</pre>
<h2>Update/Delete rows</h2>
<pre>
dataset.filter(~:active).delete
dataset.filter('price &lt; ?', 100).update(:active =&gt; true)
</pre>
<h2>Datasets are Enumerable</h2>
<pre>
dataset.map{|r| r[:name]}
dataset.map(:name) # same as above
dataset.inject(0){|sum, r| sum + r[:value]}
dataset.sum(:value) # same as above
</pre>
<h2>Filtering (see also doc/dataset_filtering.rdoc)</h2>
<h3>Equality</h3>
<pre>
dataset.filter(:name =&gt; 'abc')
dataset.filter('name = ?', 'abc')
</pre>
<h3>Inequality</h3>
<pre>
dataset.filter{value &gt; 100}
dataset.exclude{value &lt;= 100}
</pre>
<h3>Inclusion</h3>
<pre>
dataset.filter(:value =&gt; 50..100)
dataset.where{(value &gt;= 50) &amp; (value &lt;= 100)}
dataset.where('value IN ?', [50,75,100])
dataset.where(:value=&gt;[50,75,100])
dataset.where(:id=&gt;other_dataset.select(:other_id))
</pre>
<h3>Subselects as scalar values</h3>
<pre>
dataset.where('price &gt; (SELECT avg(price) + 100 FROM table)')
dataset.filter{price &gt; dataset.select(avg(price) + 100)}
</pre>
<h3>LIKE/Regexp</h3>
<pre>
DB[:items].filter(:name.like('AL%'))
DB[:items].filter(:name =&gt; /^AL/)
</pre>
<h3>AND/OR/NOT</h3>
<pre>
DB[:items].filter{(x &gt; 5) &amp; (y &gt; 10)}.sql
# SELECT * FROM items WHERE ((x &gt; 5) AND (y &gt; 10))
DB[:items].filter({:x =&gt; 1, :y =&gt; 2}.sql_or &amp; ~{:z =&gt; 3}).sql
# SELECT * FROM items WHERE (((x = 1) OR (y = 2)) AND (z != 3))
</pre>
<h3>Mathematical operators</h3>
<pre>
DB[:items].filter((:x + :y) &gt; :z).sql
# SELECT * FROM items WHERE ((x + y) &gt; z)
DB[:items].filter{price - 100 &lt; avg(price)}.sql
# SELECT * FROM items WHERE ((price - 100) &lt; avg(price))
</pre>
<h2>Ordering</h2>
<pre>
dataset.order(:kind)
dataset.reverse_order(:kind)
dataset.order(:kind.desc, :name)
</pre>
<h2>Limit/Offset</h2>
<pre>
dataset.limit(30) # LIMIT 30
dataset.limit(30, 10) # LIMIT 30 OFFSET 10
</pre>
<h2>Joins</h2>
<pre>
DB[:items].left_outer_join(:categories, :id =&gt; :category_id).sql
# SELECT * FROM items LEFT OUTER JOIN categories ON categories.id = items.category_id
DB[:items].join(:categories, :id =&gt; :category_id).join(:groups, :id =&gt; :items__group_id)
# SELECT * FROM items INNER JOIN categories ON categories.id = items.category_id INNER JOIN groups ON groups.id = items.group_id
</pre>
<p>
</p>
<h2>Aggregate functions methods</h2>
<pre>
dataset.count #=&gt; record count
dataset.max(:price)
dataset.min(:price)
dataset.avg(:price)
dataset.sum(:stock)
dataset.group_and_count(:category)
dataset.group(:category).select(:category, :AVG.sql_function(:price))
</pre>
<h2>SQL Functions / Literals</h2>
<pre>
dataset.update(:updated_at =&gt; :NOW.sql_function)
dataset.update(:updated_at =&gt; 'NOW()'.lit)
dataset.update(:updated_at =&gt; &quot;DateValue('1/1/2001')&quot;.lit)
dataset.update(:updated_at =&gt; :DateValue.sql_function('1/1/2001'))
</pre>
<h2>Schema Manipulation</h2>
<pre>
DB.create_table :items do
primary_key :id
String :name, :unique =&gt; true, :null =&gt; false
TrueClass :active, :default =&gt; true
foreign_key :category_id, :categories
DateTime :created_at
index :created_at
end
DB.drop_table :items
DB.create_table :test do
String :zipcode
enum :system, :elements =&gt; ['mac', 'linux', 'windows']
end
</pre>
<h2>Aliasing</h2>
<pre>
DB[:items].select(:name.as(:item_name))
DB[:items].select(:name___item_name)
DB[:items___items_table].select(:items_table__name___item_name)
# SELECT items_table.name AS item_name FROM items AS items_table
</pre>
<h2>Transactions</h2>
<pre>
DB.transaction do
dataset.insert(:first_name =&gt; 'Inigo', :last_name =&gt; 'Montoya')
dataset.insert(:first_name =&gt; 'Farm', :last_name =&gt; 'Boy')
end # Either both are inserted or neither are inserted
</pre>
<p>
Database#transaction is re-entrant:
</p>
<pre>
DB.transaction do # BEGIN issued only here
DB.transaction
dataset &lt;&lt; {:first_name =&gt; 'Inigo', :last_name =&gt; 'Montoya'}
end
end # COMMIT issued only here
</pre>
<p>
Transactions are aborted if an error is raised:
</p>
<pre>
DB.transaction do
raise &quot;some error occurred&quot;
end # ROLLBACK issued and the error is re-raised
</pre>
<p>
Transactions can also be aborted by raising Sequel::Rollback:
</p>
<pre>
DB.transaction do
raise(Sequel::Rollback) if something_bad_happened
end # ROLLBACK issued and no error raised
</pre>
<p>
Savepoints can be used if the database supports it:
</p>
<pre>
DB.transaction do
dataset &lt;&lt; {:first_name =&gt; 'Farm', :last_name =&gt; 'Boy'} # Inserted
DB.transaction(:savepoint=&gt;true) # This savepoint is rolled back
dataset &lt;&lt; {:first_name =&gt; 'Inigo', :last_name =&gt; 'Montoya'} # Not inserted
raise(Sequel::Rollback) if something_bad_happened
end
dataset &lt;&lt; {:first_name =&gt; 'Prince', :last_name =&gt; 'Humperdink'} # Inserted
end
</pre>
<h2>Miscellaneous:</h2>
<pre>
dataset.sql # &quot;SELECT * FROM items&quot;
dataset.delete_sql # &quot;DELETE FROM items&quot;
dataset.where(:name =&gt; 'sequel').exists # &quot;EXISTS ( SELECT * FROM items WHERE name = 'sequel' )&quot;
dataset.columns #=&gt; array of columns in the result set, does a SELECT
DB.schema(:items) =&gt; [[:id, {:type=&gt;:integer, ...}], [:name, {:type=&gt;:string, ...}], ...]
</pre>
<hr style="height: 10px"></hr><h2>Documents</h2>
<pre>
http://sequel.rubyforge.org/rdoc/files/doc/association_basics_rdoc.html
http://sequel.rubyforge.org/rdoc/classes/Sequel/Schema/Generator.html
http://sequel.rubyforge.org/rdoc/files/doc/validations_rdoc.html
http://sequel.rubyforge.org/rdoc/classes/Sequel/Model.html
</pre>
<h2>Alter table</h2>
<pre>
database.alter_table :deals do
add_column :name, String
drop_column :column_name
rename_column :from, :to
add_constraint :valid_name, :name.like('A%')
drop_constraint :constraint
add_full_text_index :body
add_spacial_index [columns]
add_index :price
drop_index :index
add_foreign_key :artist_id, :table
add_primary_key :id
add_unique_constraint [columns]
set_column_allow_null :foo, false
set_column_default :title, ''
set_column_type :price, 'char(10)'
end
</pre>
<h2>Model associations</h2>
<pre>
class Deal &lt; Sequel::Model
# Us (left) &lt;=&gt; Them (right)
many_to_many :images,
left_id: :deal_id,
right_id: :image_id,
join_table: :image_links
one_to_many :files,
key: :deal_id,
class: :DataFile,
many_to_one :parent, class: self
one_to_many :children, key: :parent_id, class: self
one_to_many :gold_albums, class: :Album do |ds|
ds.filter { copies_sold &gt; 50000 }
end
</pre>
<p>
Provided by many_to_many
</p>
<pre>
Deal[1].images
Deal[1].add_image
Deal[1].remove_image
Deal[1].remove_all_images
</pre>
<h2>Validations</h2>
<pre>
def validate
super
errors.add(:name, 'cannot be empty') if !name || name.empty?
validates_presence [:title, :site]
validates_unique :name
validates_format /\Ahttps?:\/\//, :website, :message=&gt;'is not a valid URL'
validates_includes %w(a b c), :type
validates_integer :rating
validates_numeric :number
validates_type String, [:title, :description]
validates_integer :rating if new?
# options: :message =&gt;, :allow_nil =&gt;, :allow_blank =&gt;,
# :allow_missing =&gt;,
validates_exact_length 17, :isbn
validates_min_length 3, :name
validates_max_length 100, :name
validates_length_range 3..100, :name
# Setter override
def filename=(name)
@values[:filename] = name
end
end
end
deal.errors
</pre>
<h2>Model stuff</h2>
<pre>
deal = Deal[1]
deal.changed_columns
deal.destory # Calls hooks
deal.delete # No hooks
deal.exists?
deal.new?
deal.hash # Only uniques
deal.keys #=&gt; [:id, :name]
deal.modified!
deal.modified?
deal.lock!
</pre>
<h2>Callbacks</h2>
<pre>
before_create
after_create
before_validation
after_validation
before_save
before_update
UPDATE QUERY
after_update
after_save
before_destroy
DELETE QUERY
after_destroy
</pre>
<h2>Schema</h2>
<pre>
class Deal &lt; Sequel::Model
set_schema do
primary_key :id
primary_key [:id, :title]
String :name, primary_key: true
String :title
Numeric :price
DateTime :expires
unique :whatever
check(:price) { num &gt; 0 }
foreign_key :artist_id
String :artist_name, key: :id
index :title
index [:artist_id, :name]
full_text_index :title
# String, Integer, Fixnum, Bignum, Float, Numeric, BigDecimal,
# Date, DateTime, Time, File, TrueClass, FalseClass
end
end
</pre>
<h2>Unrestrict primary key</h2>
<pre>
Category.create id: 'travel' # error
Category.unrestrict_primary_key
Category.create id: 'travel' # ok
</pre>
<script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.4/jquery.min.js'></script>
<script src="http://cachedcommons.org/cache/prettify/1.0.0/javascripts/prettify-min.js"></script>
<script>$("pre").addClass("prettyprint");</script>
<script>prettyPrint();</script>
</body>
</html>