Commit MetaInfo

Revisionabd1baacad8c9f850dd33151d523f63919cca149 (tree)
Time2023-12-14 23:55:05
AuthorErik <erikgronwal@user...>
CommiterErik

Log Message

Regular updates

Change Summary

Incremental Difference

--- a/_data/content.yml
+++ b/_data/content.yml
@@ -12,8 +12,8 @@ sheet:
1212 suffix: cheatsheet
1313
1414 social_list:
15- default_description: "Ridiculous collection of web development cheatsheets"
16- description: "The ultimate cheatsheet for TITLE."
15+ default_description: 'Ridiculous collection of web development cheatsheets'
16+ description: 'The ultimate cheatsheet for TITLE.'
1717 facebook_share: Share on Facebook
1818 twitter_share: Share on Twitter
1919
@@ -33,7 +33,7 @@ search_form:
3333
3434 comments_area:
3535 suffix: for this cheatsheet.
36- link: "Write yours!"
36+ link: 'Write yours!'
3737
3838 not_found:
3939 title: Not found
@@ -41,10 +41,11 @@ not_found:
4141 home: Back to home
4242
4343 announcement:
44- id: 2017-10-26-twitter
44+ # id: 2017-10-26-twitter
45+ id: 2023-12-14
4546 title: |
46- New: We're on Twitter ♥️
47+ We're on Twitter ♥️
4748 body: |
48- Follow [@devhints](https://twitter.com/devhints) on Twitter for daily "today I learned" snippets!
49+ Follow [@devhints](https://twitter.com/devhints) on X/Twitter for daily "today I learned" snippets.
4950
50- [![](https://img.shields.io/twitter/follow/devhints.svg?style=social&label=@devhints)](https://twitter.com/devhints)
51+ Also: I've started a new blog with some insights on web devlopment. Have a look! [**ricostacruz.com/posts**](https://ricostacruz.com/posts?utm_source=devhints)
--- a/_includes/about-the-site.html
+++ b/_includes/about-the-site.html
@@ -5,7 +5,7 @@
55 Suggestions and corrections? <a href='https://github.com/rstacruz/cheatsheets/issues/907'>Send them in</a>.
66 <i class='fleuron'></i>
77 I'm <a href="http://ricostacruz.com">Rico Sta. Cruz</a>.
8- Check out my <a href="http://ricostacruz.com/til">Today I learned blog</a> for more.
8+ Check out my <a href="http://ricostacruz.com/posts">Today I learned blog</a> for more.
99 </p>
1010
1111 {% if page.url != '/index.html' %}
--- a/bash.md
+++ b/bash.md
@@ -14,11 +14,12 @@ keywords:
1414 - Command substitution
1515 ---
1616
17-Getting started
18----------------
17+## Getting started
18+
1919 {: .-three-column}
2020
2121 ### Introduction
22+
2223 {: .-intro}
2324
2425 This is a quick reference to getting started with Bash scripting.
@@ -44,6 +45,7 @@ echo $name # see below
4445 echo "$name"
4546 echo "${name}!"
4647 ```
48+
4749 Generally quote your variables unless they contain wildcards to expand or command fragments.
4850
4951 ```bash
@@ -78,6 +80,7 @@ git commit || echo "Commit failed"
7880 ```
7981
8082 ### Functions
83+
8184 {: id='functions-example'}
8285
8386 ```bash
@@ -91,6 +94,7 @@ echo "You are $(get_name)"
9194 See: [Functions](#functions)
9295
9396 ### Conditionals
97+
9498 {: id='conditionals-example'}
9599
96100 ```bash
@@ -118,17 +122,17 @@ See: [Unofficial bash strict mode](http://redsymbol.net/articles/unofficial-bash
118122 echo {A,B}.js
119123 ```
120124
121-| Expression | Description |
122-| ---------- | ------------------- |
123-| `{A,B}` | Same as `A B` |
124-| `{A,B}.js` | Same as `A.js B.js` |
125-| `{1..5}` | Same as `1 2 3 4 5` |
125+| Expression | Description |
126+| ---------------------- | --------------------- |
127+| `{A,B}` | Same as `A B` |
128+| `{A,B}.js` | Same as `A.js B.js` |
129+| `{1..5}` | Same as `1 2 3 4 5` |
130+| <code>&lcub;{1..3},{7..9}}</code> | Same as `1 2 3 7 8 9` |
126131
127132 See: [Brace expansion](https://web.archive.org/web/20230207192110/https://wiki.bash-hackers.org/syntax/expansion/brace)
128133
134+## Parameter expansions
129135
130-Parameter expansions
131---------------------
132136 {: .-three-column}
133137
134138 ### Basics
@@ -247,8 +251,8 @@ echo "${str^^}" #=> "HELLO WORLD!" (all uppercase)
247251
248252 Omitting the `:` removes the (non)nullity checks, e.g. `${foo-val}` expands to `val` if unset otherwise `$foo`.
249253
250-Loops
251------
254+## Loops
255+
252256 {: .-three-column}
253257
254258 ### Basic for loop
@@ -299,8 +303,8 @@ while true; do
299303 done
300304 ```
301305
302-Functions
303----------
306+## Functions
307+
304308 {: .-three-column}
305309
306310 ### Defining functions
@@ -353,21 +357,21 @@ fi
353357
354358 ### Arguments
355359
356-| Expression | Description |
357-| --- | --- |
358-| `$#` | Number of arguments |
359-| `$*` | All positional arguments (as a single word) |
360-| `$@` | All positional arguments (as separate strings) |
361-| `$1` | First argument |
362-| `$_` | Last argument of the previous command |
360+| Expression | Description |
361+| ---------- | ---------------------------------------------- |
362+| `$#` | Number of arguments |
363+| `$*` | All positional arguments (as a single word) |
364+| `$@` | All positional arguments (as separate strings) |
365+| `$1` | First argument |
366+| `$_` | Last argument of the previous command |
363367
364368 **Note**: `$@` and `$*` must be quoted in order to perform as described.
365369 Otherwise, they do exactly the same thing (arguments as separate strings).
366370
367371 See [Special parameters](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars#special_parameters_and_shell_variables).
368372
369-Conditionals
370-------------
373+## Conditionals
374+
371375 {: .-three-column}
372376
373377 ### Conditions
@@ -375,7 +379,7 @@ Conditionals
375379 Note that `[[` is actually a command/program that returns either `0` (true) or `1` (false). Any program that obeys the same logic (like all base utils, such as `grep(1)` or `ping(1)`) can be used as condition, see examples.
376380
377381 | Condition | Description |
378-| --- | --- |
382+| ------------------------ | --------------------- |
379383 | `[[ -z STRING ]]` | Empty string |
380384 | `[[ -n STRING ]]` | Not empty string |
381385 | `[[ STRING == STRING ]]` | Equal |
@@ -405,7 +409,7 @@ Note that `[[` is actually a command/program that returns either `0` (true) or `
405409 ### File conditions
406410
407411 | Condition | Description |
408-| --- | --- |
412+| ----------------------- | ----------------------- |
409413 | `[[ -e FILE ]]` | Exists |
410414 | `[[ -r FILE ]]` | Readable |
411415 | `[[ -h FILE ]]` | Symlink |
@@ -461,8 +465,7 @@ if [[ -e "file.txt" ]]; then
461465 fi
462466 ```
463467
464-Arrays
465-------
468+## Arrays
466469
467470 ### Defining arrays
468471
@@ -509,8 +512,8 @@ for i in "${arrayName[@]}"; do
509512 done
510513 ```
511514
512-Dictionaries
513-------------
515+## Dictionaries
516+
514517 {: .-three-column}
515518
516519 ### Defining
@@ -556,8 +559,7 @@ for key in "${!sounds[@]}"; do
556559 done
557560 ```
558561
559-Options
560--------
562+## Options
561563
562564 ### Options
563565
@@ -581,8 +583,7 @@ shopt -s globstar # Allow ** for recursive matches ('lib/**/*.rb' => 'lib/a/b
581583 Set `GLOBIGNORE` as a colon-separated list of patterns to be removed from glob
582584 matches.
583585
584-History
585--------
586+## History
586587
587588 ### Commands
588589
@@ -625,9 +626,7 @@ History
625626
626627 `!!` can be replaced with any valid expansion i.e. `!cat`, `!-2`, `!42`, etc.
627628
628-
629-Miscellaneous
630--------------
629+## Miscellaneous
631630
632631 ### Numeric calculations
633632
@@ -640,7 +639,7 @@ $(($RANDOM%200)) # Random number 0..199
640639 ```
641640
642641 ```bash
643-declare -i count # Declare as type integer
642+declare -i count # Declare as type integer
644643 count+=1 # Increment
645644 ```
646645
@@ -732,18 +731,18 @@ printf '%i+%i=%i\n' 1 2 3 4 5 9
732731
733732 ### Transform strings
734733
735-| Command option | Description |
736-| ------------------ | --------------------------------------------------- |
737-| `-c` | Operations apply to characters not in the given set |
738-| `-d` | Delete characters |
739-| `-s` | Replaces repeated characters with single occurrence |
740-| `-t` | Truncates |
741-| `[:upper:]` | All upper case letters |
742-| `[:lower:]` | All lower case letters |
743-| `[:digit:]` | All digits |
744-| `[:space:]` | All whitespace |
745-| `[:alpha:]` | All letters |
746-| `[:alnum:]` | All letters and digits |
734+| Command option | Description |
735+| -------------- | --------------------------------------------------- |
736+| `-c` | Operations apply to characters not in the given set |
737+| `-d` | Delete characters |
738+| `-s` | Replaces repeated characters with single occurrence |
739+| `-t` | Truncates |
740+| `[:upper:]` | All upper case letters |
741+| `[:lower:]` | All lower case letters |
742+| `[:digit:]` | All digits |
743+| `[:space:]` | All whitespace |
744+| `[:alpha:]` | All letters |
745+| `[:alnum:]` | All letters and digits |
747746
748747 #### Example
749748
@@ -838,10 +837,11 @@ fi
838837 ```
839838
840839 ## Also see
840+
841841 {: .-one-column}
842842
843-* [Bash-hackers wiki](https://web.archive.org/web/20230406205817/https://wiki.bash-hackers.org/) _(bash-hackers.org)_
844-* [Shell vars](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars) _(bash-hackers.org)_
845-* [Learn bash in y minutes](https://learnxinyminutes.com/docs/bash/) _(learnxinyminutes.com)_
846-* [Bash Guide](http://mywiki.wooledge.org/BashGuide) _(mywiki.wooledge.org)_
847-* [ShellCheck](https://www.shellcheck.net/) _(shellcheck.net)_
843+- [Bash-hackers wiki](https://web.archive.org/web/20230406205817/https://wiki.bash-hackers.org/) _(bash-hackers.org)_
844+- [Shell vars](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars) _(bash-hackers.org)_
845+- [Learn bash in y minutes](https://learnxinyminutes.com/docs/bash/) _(learnxinyminutes.com)_
846+- [Bash Guide](http://mywiki.wooledge.org/BashGuide) _(mywiki.wooledge.org)_
847+- [ShellCheck](https://www.shellcheck.net/) _(shellcheck.net)_
--- a/pry.md
+++ b/pry.md
@@ -95,7 +95,7 @@ Also consider [pry-rails](https://rubygems.org/gems/pry-rails).
9595
9696 > ls -i # Instance vars
9797
98- > ls -G xx # Grey by regex
98+ > ls -G xx # Grep by regex
9999
100100 ## Shell integration
101101
--- a/sequel.md
+++ b/sequel.md
@@ -5,6 +5,7 @@ layout: 2017/sheet
55 ---
66
77 ### About
8+
89 {: .-intro}
910
1011 Sequel is a database toolkit for Ruby.
@@ -13,382 +14,460 @@ Sequel is a database toolkit for Ruby.
1314
1415 ### Open a database
1516
16- require 'rubygems'
17- require 'sequel'
17+```
18+require 'rubygems'
19+require 'sequel'
1820
19- DB = Sequel.sqlite('my_blog.db')
20- DB = Sequel.connect('postgres://user:password@localhost/my_db')
21- DB = Sequel.postgres('my_db', :user => 'user', :password => 'password', :host => 'localhost')
22- DB = Sequel.ado('mydb')
21+DB = Sequel.sqlite('my_blog.db')
22+DB = Sequel.connect('postgres://user:password@localhost/my_db')
23+DB = Sequel.postgres('my_db', :user => 'user', :password => 'password', :host => 'localhost')
24+DB = Sequel.ado('mydb')
25+```
2326
2427 ### Open an SQLite memory database
2528
2629 Without a filename argument, the sqlite adapter will setup a new sqlite database in memory.
2730
28- DB = Sequel.sqlite
31+```
32+DB = Sequel.sqlite
33+```
2934
3035 ### Logging SQL statements
3136
32- require 'logger'
33- DB = Sequel.sqlite '', :loggers => [Logger.new($stdout)]
34- # or
35- DB.loggers << Logger.new(...)
37+```
38+require 'logger'
39+DB = Sequel.sqlite '', :loggers => [Logger.new($stdout)]
40+# or
41+DB.loggers << Logger.new(...)
42+```
3643
3744 ### Using raw SQL
3845
39- DB.run "CREATE TABLE users (name VARCHAR(255) NOT NULL, age INT(3) NOT NULL)"
40- dataset = DB["SELECT age FROM users WHERE name = ?", name]
41- dataset.map(:age)
42- DB.fetch("SELECT name FROM users") do |row|
43- p row[:name]
44- end
46+```
47+DB.run "CREATE TABLE users (name VARCHAR(255) NOT NULL, age INT(3) NOT NULL)"
48+dataset = DB["SELECT age FROM users WHERE name = ?", name]
49+dataset.map(:age)
50+DB.fetch("SELECT name FROM users") do |row|
51+ p row[:name]
52+end
53+```
4554
4655 ### Create a dataset
4756
48- dataset = DB[:items]
49- dataset = DB.from(:items)
57+```
58+dataset = DB[:items]
59+dataset = DB.from(:items)
60+```
5061
5162 ### Most dataset methods are chainable
5263
53- dataset = DB[:managers].where(:salary => 5000..10000).order(:name, :department)
64+```
65+dataset = DB[:managers].where(:salary => 5000..10000).order(:name, :department)
66+```
5467
5568 ### Insert rows
5669
57- dataset.insert(:name => 'Sharon', :grade => 50)
70+```
71+dataset.insert(:name => 'Sharon', :grade => 50)
72+```
5873
5974 ### Retrieve rows
6075
61- dataset.each{|r| p r}
62- dataset.all # => [{...}, {...}, ...]
63- dataset.first # => {...}
76+```
77+dataset.each{|r| p r}
78+dataset.all # => [{...}, {...}, ...]
79+dataset.first # => {...}
80+```
6481
6582 ### Update/Delete rows
6683
67- dataset.filter(~:active).delete
68- dataset.filter('price < ?', 100).update(:active => true)
84+```
85+dataset.filter(~:active).delete
86+dataset.filter('price < ?', 100).update(:active => true)
87+```
6988
7089 ### Datasets are Enumerable
7190
72- dataset.map{|r| r[:name]}
73- dataset.map(:name) # same as above
91+```
92+dataset.map{|r| r[:name]}
93+dataset.map(:name) # same as above
7494
75- dataset.inject(0){|sum, r| sum + r[:value]}
76- dataset.sum(:value) # same as above
95+dataset.inject(0){|sum, r| sum + r[:value]}
96+dataset.sum(:value) # same as above
97+```
7798
7899 ### Filtering (see also doc/dataset_filtering.rdoc)
79100
80101 #### Equality
81102
82- dataset.filter(:name => 'abc')
83- dataset.filter('name = ?', 'abc')
103+```
104+dataset.filter(:name => 'abc')
105+dataset.filter('name = ?', 'abc')
106+```
84107
85108 #### Inequality
86109
87- dataset.filter{value > 100}
88- dataset.exclude{value <= 100}
110+```
111+dataset.filter{value > 100}
112+dataset.exclude{value <= 100}
113+```
89114
90115 #### Inclusion
91116
92- dataset.filter(:value => 50..100)
93- dataset.where{(value >= 50) & (value <= 100)}
117+```
118+dataset.filter(:value => 50..100)
119+dataset.where{(value >= 50) & (value <= 100)}
94120
95- dataset.where('value IN ?', [50,75,100])
96- dataset.where(:value=>[50,75,100])
121+dataset.where('value IN ?', [50,75,100])
122+dataset.where(:value=>[50,75,100])
97123
98- dataset.where(:id=>other_dataset.select(:other_id))
124+dataset.where(:id=>other_dataset.select(:other_id))
125+```
99126
100127 #### Subselects as scalar values
101128
102- dataset.where('price > (SELECT avg(price) + 100 FROM table)')
103- dataset.filter{price > dataset.select(avg(price) + 100)}
129+```
130+dataset.where('price > (SELECT avg(price) + 100 FROM table)')
131+dataset.filter{price > dataset.select(avg(price) + 100)}
132+```
104133
105134 #### LIKE/Regexp
106135
107- DB[:items].filter(:name.like('AL%'))
108- DB[:items].filter(:name => /^AL/)
136+```
137+DB[:items].filter(:name.like('AL%'))
138+DB[:items].filter(:name => /^AL/)
139+```
109140
110141 #### AND/OR/NOT
111142
112- DB[:items].filter{(x > 5) & (y > 10)}.sql
113- # SELECT * FROM items WHERE ((x > 5) AND (y > 10))
143+```
144+DB[:items].filter{(x > 5) & (y > 10)}.sql
145+# SELECT * FROM items WHERE ((x > 5) AND (y > 10))
114146
115- DB[:items].filter({:x => 1, :y => 2}.sql_or & ~{:z => 3}).sql
116- # SELECT * FROM items WHERE (((x = 1) OR (y = 2)) AND (z != 3))
147+DB[:items].filter({:x => 1, :y => 2}.sql_or & ~{:z => 3}).sql
148+# SELECT * FROM items WHERE (((x = 1) OR (y = 2)) AND (z != 3))
149+```
117150
118151 #### Mathematical operators
119152
120- DB[:items].filter((:x + :y) > :z).sql
121- # SELECT * FROM items WHERE ((x + y) > z)
153+```
154+DB[:items].filter((:x + :y) > :z).sql
155+# SELECT * FROM items WHERE ((x + y) > z)
122156
123- DB[:items].filter{price - 100 < avg(price)}.sql
124- # SELECT * FROM items WHERE ((price - 100) < avg(price))
157+DB[:items].filter{price - 100 < avg(price)}.sql
158+# SELECT * FROM items WHERE ((price - 100) < avg(price))
159+```
125160
126161 ### Ordering
127162
128- dataset.order(:kind)
129- dataset.reverse_order(:kind)
130- dataset.order(:kind.desc, :name)
163+```
164+dataset.order(:kind)
165+dataset.reverse_order(:kind)
166+dataset.order(:kind.desc, :name)
167+```
131168
132169 ### Limit/Offset
133170
134- dataset.limit(30) # LIMIT 30
135- dataset.limit(30, 10) # LIMIT 30 OFFSET 10
171+```
172+dataset.limit(30) # LIMIT 30
173+dataset.limit(30, 10) # LIMIT 30 OFFSET 10
174+```
136175
137176 ### Joins
138177
139- DB[:items].left_outer_join(:categories, :id => :category_id).sql
140- # SELECT * FROM items LEFT OUTER JOIN categories ON categories.id = items.category_id
178+```
179+DB[:items].left_outer_join(:categories, :id => :category_id).sql
180+# SELECT * FROM items LEFT OUTER JOIN categories ON categories.id = items.category_id
181+
182+DB[:items].join(:categories, :id => :category_id).join(:groups, :id => :items__group_id)
183+# SELECT * FROM items INNER JOIN categories ON categories.id = items.category_id INNER JOIN groups ON groups.id = items.group_id
184+```
141185
142- DB[:items].join(:categories, :id => :category_id).join(:groups, :id => :items__group_id)
143- # SELECT * FROM items INNER JOIN categories ON categories.id = items.category_id INNER JOIN groups ON groups.id = items.group_id
144-
145186 ### Aggregate functions methods
146187
147- dataset.count #=> record count
148- dataset.max(:price)
149- dataset.min(:price)
150- dataset.avg(:price)
151- dataset.sum(:stock)
188+```
189+dataset.count #=> record count
190+dataset.max(:price)
191+dataset.min(:price)
192+dataset.avg(:price)
193+dataset.sum(:stock)
152194
153- dataset.group_and_count(:category)
154- dataset.group(:category).select(:category, :AVG.sql_function(:price))
195+dataset.group_and_count(:category)
196+dataset.group(:category).select(:category, :AVG.sql_function(:price))
197+```
155198
156199 ### SQL Functions / Literals
157200
158- dataset.update(:updated_at => :NOW.sql_function)
159- dataset.update(:updated_at => 'NOW()'.lit)
201+```
202+dataset.update(:updated_at => :NOW.sql_function)
203+dataset.update(:updated_at => 'NOW()'.lit)
160204
161- dataset.update(:updated_at => "DateValue('1/1/2001')".lit)
162- dataset.update(:updated_at => :DateValue.sql_function('1/1/2001'))
205+dataset.update(:updated_at => "DateValue('1/1/2001')".lit)
206+dataset.update(:updated_at => :DateValue.sql_function('1/1/2001'))
207+```
163208
164209 ### Schema Manipulation
165210
166- DB.create_table :items do
167- primary_key :id
168- String :name, :unique => true, :null => false
169- TrueClass :active, :default => true
170- foreign_key :category_id, :categories
171- DateTime :created_at
172-
173- index :created_at
174- end
211+```
212+DB.create_table :items do
213+ primary_key :id
214+ String :name, :unique => true, :null => false
215+ TrueClass :active, :default => true
216+ foreign_key :category_id, :categories
217+ DateTime :created_at
175218
176- DB.drop_table :items
219+ index :created_at
220+end
177221
178- DB.create_table :test do
179- String :zipcode
180- enum :system, :elements => ['mac', 'linux', 'windows']
181- end
222+DB.drop_table :items
223+
224+DB.create_table :test do
225+ String :zipcode
226+ enum :system, :elements => ['mac', 'linux', 'windows']
227+end
228+```
182229
183230 ### Aliasing
184231
185- DB[:items].select(:name.as(:item_name))
186- DB[:items].select(:name___item_name)
187- DB[:items___items_table].select(:items_table__name___item_name)
188- # SELECT items_table.name AS item_name FROM items AS items_table
232+```
233+DB[:items].select(:name.as(:item_name))
234+DB[:items].select(:name___item_name)
235+DB[:items___items_table].select(:items_table__name___item_name)
236+# SELECT items_table.name AS item_name FROM items AS items_table
237+```
189238
190239 ### Transactions
191240
192- DB.transaction do
193- dataset.insert(:first_name => 'Inigo', :last_name => 'Montoya')
194- dataset.insert(:first_name => 'Farm', :last_name => 'Boy')
195- end # Either both are inserted or neither are inserted
241+```
242+DB.transaction do
243+ dataset.insert(:first_name => 'Inigo', :last_name => 'Montoya')
244+ dataset.insert(:first_name => 'Farm', :last_name => 'Boy')
245+end # Either both are inserted or neither are inserted
246+```
196247
197248 Database#transaction is re-entrant:
198249
199- DB.transaction do # BEGIN issued only here
200- DB.transaction
201- dataset << {:first_name => 'Inigo', :last_name => 'Montoya'}
202- end
203- end # COMMIT issued only here
250+```
251+DB.transaction do # BEGIN issued only here
252+ DB.transaction
253+ dataset << {:first_name => 'Inigo', :last_name => 'Montoya'}
254+ end
255+end # COMMIT issued only here
256+```
204257
205258 Transactions are aborted if an error is raised:
206259
207- DB.transaction do
208- raise "some error occurred"
209- end # ROLLBACK issued and the error is re-raised
260+```
261+DB.transaction do
262+ raise "some error occurred"
263+end # ROLLBACK issued and the error is re-raised
264+```
210265
211266 Transactions can also be aborted by raising Sequel::Rollback:
212267
213- DB.transaction do
214- raise(Sequel::Rollback) if something_bad_happened
215- end # ROLLBACK issued and no error raised
268+```
269+DB.transaction do
270+ raise(Sequel::Rollback) if something_bad_happened
271+end # ROLLBACK issued and no error raised
272+```
216273
217274 Savepoints can be used if the database supports it:
218275
219- DB.transaction do
220- dataset << {:first_name => 'Farm', :last_name => 'Boy'} # Inserted
221- DB.transaction(:savepoint=>true) # This savepoint is rolled back
222- dataset << {:first_name => 'Inigo', :last_name => 'Montoya'} # Not inserted
223- raise(Sequel::Rollback) if something_bad_happened
224- end
225- dataset << {:first_name => 'Prince', :last_name => 'Humperdink'} # Inserted
226- end
276+```
277+DB.transaction do
278+ dataset << {:first_name => 'Farm', :last_name => 'Boy'} # Inserted
279+ DB.transaction(:savepoint=>true) # This savepoint is rolled back
280+ dataset << {:first_name => 'Inigo', :last_name => 'Montoya'} # Not inserted
281+ raise(Sequel::Rollback) if something_bad_happened
282+ end
283+ dataset << {:first_name => 'Prince', :last_name => 'Humperdink'} # Inserted
284+end
285+```
227286
228287 ### Miscellaneous:
229288
230- dataset.sql # "SELECT * FROM items"
231- dataset.delete_sql # "DELETE FROM items"
232- dataset.where(:name => 'sequel').exists # "EXISTS ( SELECT * FROM items WHERE name = 'sequel' )"
233- dataset.columns #=> array of columns in the result set, does a SELECT
234- DB.schema(:items) => [[:id, {:type=>:integer, ...}], [:name, {:type=>:string, ...}], ...]
289+```
290+dataset.sql # "SELECT * FROM items"
291+dataset.delete_sql # "DELETE FROM items"
292+dataset.where(:name => 'sequel').exists # "EXISTS ( SELECT * FROM items WHERE name = 'sequel' )"
293+dataset.columns #=> array of columns in the result set, does a SELECT
294+DB.schema(:items) => [[:id, {:type=>:integer, ...}], [:name, {:type=>:string, ...}], ...]
295+```
235296
236-----------------------------------------------------------------------------------------------------------------------------------------------------------------
297+---
237298
238299 ### Documents
239300
240- http://sequel.rubyforge.org/rdoc/files/doc/association_basics_rdoc.html
241- http://sequel.rubyforge.org/rdoc/classes/Sequel/Schema/Generator.html
242- http://sequel.rubyforge.org/rdoc/files/doc/validations_rdoc.html
243- http://sequel.rubyforge.org/rdoc/classes/Sequel/Model.html
301+```
302+http://sequel.rubyforge.org/rdoc/files/doc/association_basics_rdoc.html
303+http://sequel.rubyforge.org/rdoc/classes/Sequel/Schema/Generator.html
304+http://sequel.rubyforge.org/rdoc/files/doc/validations_rdoc.html
305+http://sequel.rubyforge.org/rdoc/classes/Sequel/Model.html
306+```
244307
245308 ### Alter table
246309
247- database.alter_table :deals do
248- add_column :name, String
249- drop_column :column_name
250- rename_column :from, :to
310+```
311+database.alter_table :deals do
312+ add_column :name, String
313+ drop_column :column_name
314+ rename_column :from, :to
251315
252- add_constraint :valid_name, :name.like('A%')
253- drop_constraint :constraint
316+ add_constraint :valid_name, :name.like('A%')
317+ drop_constraint :constraint
254318
255- add_full_text_index :body
256- add_spacial_index [columns]
319+ add_full_text_index :body
320+ add_spacial_index [columns]
257321
258- add_index :price
259- drop_index :index
322+ add_index :price
323+ drop_index :index
260324
261- add_foreign_key :artist_id, :table
262- add_primary_key :id
263- add_unique_constraint [columns]
264- set_column_allow_null :foo, false
265- set_column_default :title, ''
325+ add_foreign_key :artist_id, :table
326+ add_primary_key :id
327+ add_unique_constraint [columns]
328+ set_column_allow_null :foo, false
329+ set_column_default :title, ''
266330
267- set_column_type :price, 'char(10)'
268- end
331+ set_column_type :price, 'char(10)'
332+end
333+```
269334
270335 ### Model associations
271336
272- class Deal < Sequel::Model
337+```
338+class Deal < Sequel::Model
273339
274- # Us (left) <=> Them (right)
275- many_to_many :images,
276- left_id: :deal_id,
277- right_id: :image_id,
278- join_table: :image_links
340+ # Us (left) <=> Them (right)
341+ many_to_many :images,
342+ left_key: :deal_id,
343+ right_key: :image_id,
344+ join_table: :image_links
279345
280- one_to_many :files,
281- key: :deal_id,
282- class: :DataFile,
346+ one_to_many :files,
347+ key: :deal_id,
348+ class: :DataFile,
283349
284- many_to_one :parent, class: self
285- one_to_many :children, key: :parent_id, class: self
350+ many_to_one :parent, class: self
351+ one_to_many :children, key: :parent_id, class: self
286352
287- one_to_many :gold_albums, class: :Album do |ds|
288- ds.filter { copies_sold > 50000 }
289- end
353+ one_to_many :gold_albums, class: :Album do |ds|
354+ ds.filter { copies_sold > 50000 }
355+ end
356+```
290357
291358 Provided by many_to_many
292359
293- Deal[1].images
294- Deal[1].add_image
295- Deal[1].remove_image
296- Deal[1].remove_all_images
360+```
361+Deal[1].images
362+Deal[1].add_image
363+Deal[1].remove_image
364+Deal[1].remove_all_images
365+```
297366
298367 ### Validations
299368
300- def validate
301- super
302- errors.add(:name, 'cannot be empty') if !name || name.empty?
303-
304- validates_presence [:title, :site]
305- validates_unique :name
306- validates_format /\Ahttps?:\/\//, :website, :message=>'is not a valid URL'
307- validates_includes %w(a b c), :type
308- validates_integer :rating
309- validates_numeric :number
310- validates_type String, [:title, :description]
311-
312- validates_integer :rating if new?
313-
314- # options: :message =>, :allow_nil =>, :allow_blank =>,
315- # :allow_missing =>,
316-
317- validates_exact_length 17, :isbn
318- validates_min_length 3, :name
319- validates_max_length 100, :name
320- validates_length_range 3..100, :name
321-
322- # Setter override
323- def filename=(name)
324- @values[:filename] = name
325- end
326- end
369+```
370+def validate
371+ super
372+ errors.add(:name, 'cannot be empty') if !name || name.empty?
373+
374+ validates_presence [:title, :site]
375+ validates_unique :name
376+ validates_format /\Ahttps?:\/\//, :website, :message=>'is not a valid URL'
377+ validates_includes %w(a b c), :type
378+ validates_integer :rating
379+ validates_numeric :number
380+ validates_type String, [:title, :description]
381+
382+ validates_integer :rating if new?
383+
384+ # options: :message =>, :allow_nil =>, :allow_blank =>,
385+ # :allow_missing =>,
386+
387+ validates_exact_length 17, :isbn
388+ validates_min_length 3, :name
389+ validates_max_length 100, :name
390+ validates_length_range 3..100, :name
391+
392+ # Setter override
393+ def filename=(name)
394+ @values[:filename] = name
327395 end
396+ end
397+end
328398
329- deal.errors
399+deal.errors
400+```
330401
331402 ### Model stuff
332403
333- deal = Deal[1]
334- deal.changed_columns
335- deal.destroy # Calls hooks
336- deal.delete # No hooks
337- deal.exists?
338- deal.new?
339- deal.hash # Only uniques
340- deal.keys #=> [:id, :name]
341- deal.modified!
342- deal.modified?
343-
344- deal.lock!
404+```
405+deal = Deal[1]
406+deal.changed_columns
407+deal.destroy # Calls hooks
408+deal.delete # No hooks
409+deal.exists?
410+deal.new?
411+deal.hash # Only uniques
412+deal.keys #=> [:id, :name]
413+deal.modified!
414+deal.modified?
415+
416+deal.lock!
417+```
345418
346419 ### Callbacks
347420
348- before_create
349- after_create
421+```
422+before_create
423+after_create
350424
351- before_validation
352- after_validation
353- before_save
354- before_update
355- UPDATE QUERY
356- after_update
357- after_save
425+before_validation
426+after_validation
427+before_save
428+before_update
429+UPDATE QUERY
430+after_update
431+after_save
358432
359- before_destroy
360- DELETE QUERY
361- after_destroy
433+before_destroy
434+DELETE QUERY
435+after_destroy
436+```
362437
363438 ### Schema
364439
365- class Deal < Sequel::Model
366- set_schema do
367- primary_key :id
368- primary_key [:id, :title]
369- String :name, primary_key: true
370-
371- String :title
372- Numeric :price
373- DateTime :expires
374-
375- unique :whatever
376- check(:price) { num > 0 }
377-
378- foreign_key :artist_id
379- String :artist_name, key: :id
380-
381- index :title
382- index [:artist_id, :name]
383- full_text_index :title
384-
385- # String, Integer, Fixnum, Bignum, Float, Numeric, BigDecimal,
386- # Date, DateTime, Time, File, TrueClass, FalseClass
387- end
388- end
440+```
441+class Deal < Sequel::Model
442+ set_schema do
443+ primary_key :id
444+ primary_key [:id, :title]
445+ String :name, primary_key: true
446+
447+ String :title
448+ Numeric :price
449+ DateTime :expires
450+
451+ unique :whatever
452+ check(:price) { num > 0 }
453+
454+ foreign_key :artist_id
455+ String :artist_name, key: :id
456+
457+ index :title
458+ index [:artist_id, :name]
459+ full_text_index :title
460+
461+ # String, Integer, Fixnum, Bignum, Float, Numeric, BigDecimal,
462+ # Date, DateTime, Time, File, TrueClass, FalseClass
463+ end
464+end
465+```
389466
390467 ### Unrestrict primary key
391468
392- Category.create id: 'travel' # error
393- Category.unrestrict_primary_key
394- Category.create id: 'travel' # ok
469+```
470+Category.create id: 'travel' # error
471+Category.unrestrict_primary_key
472+Category.create id: 'travel' # ok
473+```
--- a/typescript.md
+++ b/typescript.md
@@ -244,7 +244,7 @@ type Point = { x: number; y: number };
244244 type P = keyof Point; // x | y
245245 ```
246246
247-## Conditinal Types
247+## Conditional Types
248248
249249 ```ts
250250 // SomeType extends OtherType ? TrueType : FalseType;
Show on old repository browser