From abd1baacad8c9f850dd33151d523f63919cca149 Mon Sep 17 00:00:00 2001 From: Erik Date: Thu, 14 Dec 2023 23:55:05 +0900 Subject: [PATCH] Regular updates --- _data/content.yml | 15 +- _includes/about-the-site.html | 2 +- bash.md | 106 ++++---- pry.md | 2 +- sequel.md | 553 ++++++++++++++++++++++++------------------ typescript.md | 2 +- 6 files changed, 380 insertions(+), 300 deletions(-) diff --git a/_data/content.yml b/_data/content.yml index cb946f2..ca7df3e 100644 --- a/_data/content.yml +++ b/_data/content.yml @@ -12,8 +12,8 @@ sheet: suffix: cheatsheet social_list: - default_description: "Ridiculous collection of web development cheatsheets" - description: "The ultimate cheatsheet for TITLE." + default_description: 'Ridiculous collection of web development cheatsheets' + description: 'The ultimate cheatsheet for TITLE.' facebook_share: Share on Facebook twitter_share: Share on Twitter @@ -33,7 +33,7 @@ search_form: comments_area: suffix: for this cheatsheet. - link: "Write yours!" + link: 'Write yours!' not_found: title: Not found @@ -41,10 +41,11 @@ not_found: home: Back to home announcement: - id: 2017-10-26-twitter + # id: 2017-10-26-twitter + id: 2023-12-14 title: | - New: We're on Twitter ♥️ + We're on Twitter ♥️ body: | - Follow [@devhints](https://twitter.com/devhints) on Twitter for daily "today I learned" snippets! + Follow [@devhints](https://twitter.com/devhints) on X/Twitter for daily "today I learned" snippets. - [![](https://img.shields.io/twitter/follow/devhints.svg?style=social&label=@devhints)](https://twitter.com/devhints) + 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) diff --git a/_includes/about-the-site.html b/_includes/about-the-site.html index de4f487..afdbbb2 100644 --- a/_includes/about-the-site.html +++ b/_includes/about-the-site.html @@ -5,7 +5,7 @@ Suggestions and corrections? Send them in. I'm Rico Sta. Cruz. - Check out my Today I learned blog for more. + Check out my Today I learned blog for more.

{% if page.url != '/index.html' %} diff --git a/bash.md b/bash.md index c079175..b131cf2 100644 --- a/bash.md +++ b/bash.md @@ -14,11 +14,12 @@ keywords: - Command substitution --- -Getting started ---------------- +## Getting started + {: .-three-column} ### Introduction + {: .-intro} This is a quick reference to getting started with Bash scripting. @@ -44,6 +45,7 @@ echo $name # see below echo "$name" echo "${name}!" ``` + Generally quote your variables unless they contain wildcards to expand or command fragments. ```bash @@ -78,6 +80,7 @@ git commit || echo "Commit failed" ``` ### Functions + {: id='functions-example'} ```bash @@ -91,6 +94,7 @@ echo "You are $(get_name)" See: [Functions](#functions) ### Conditionals + {: id='conditionals-example'} ```bash @@ -118,17 +122,17 @@ See: [Unofficial bash strict mode](http://redsymbol.net/articles/unofficial-bash echo {A,B}.js ``` -| Expression | Description | -| ---------- | ------------------- | -| `{A,B}` | Same as `A B` | -| `{A,B}.js` | Same as `A.js B.js` | -| `{1..5}` | Same as `1 2 3 4 5` | +| Expression | Description | +| ---------------------- | --------------------- | +| `{A,B}` | Same as `A B` | +| `{A,B}.js` | Same as `A.js B.js` | +| `{1..5}` | Same as `1 2 3 4 5` | +| {{1..3},{7..9}} | Same as `1 2 3 7 8 9` | See: [Brace expansion](https://web.archive.org/web/20230207192110/https://wiki.bash-hackers.org/syntax/expansion/brace) +## Parameter expansions -Parameter expansions --------------------- {: .-three-column} ### Basics @@ -247,8 +251,8 @@ echo "${str^^}" #=> "HELLO WORLD!" (all uppercase) Omitting the `:` removes the (non)nullity checks, e.g. `${foo-val}` expands to `val` if unset otherwise `$foo`. -Loops ------ +## Loops + {: .-three-column} ### Basic for loop @@ -299,8 +303,8 @@ while true; do done ``` -Functions ---------- +## Functions + {: .-three-column} ### Defining functions @@ -353,21 +357,21 @@ fi ### Arguments -| Expression | Description | -| --- | --- | -| `$#` | Number of arguments | -| `$*` | All positional arguments (as a single word) | -| `$@` | All positional arguments (as separate strings) | -| `$1` | First argument | -| `$_` | Last argument of the previous command | +| Expression | Description | +| ---------- | ---------------------------------------------- | +| `$#` | Number of arguments | +| `$*` | All positional arguments (as a single word) | +| `$@` | All positional arguments (as separate strings) | +| `$1` | First argument | +| `$_` | Last argument of the previous command | **Note**: `$@` and `$*` must be quoted in order to perform as described. Otherwise, they do exactly the same thing (arguments as separate strings). See [Special parameters](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars#special_parameters_and_shell_variables). -Conditionals ------------- +## Conditionals + {: .-three-column} ### Conditions @@ -375,7 +379,7 @@ Conditionals 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. | Condition | Description | -| --- | --- | +| ------------------------ | --------------------- | | `[[ -z STRING ]]` | Empty string | | `[[ -n STRING ]]` | Not empty string | | `[[ STRING == STRING ]]` | Equal | @@ -405,7 +409,7 @@ Note that `[[` is actually a command/program that returns either `0` (true) or ` ### File conditions | Condition | Description | -| --- | --- | +| ----------------------- | ----------------------- | | `[[ -e FILE ]]` | Exists | | `[[ -r FILE ]]` | Readable | | `[[ -h FILE ]]` | Symlink | @@ -461,8 +465,7 @@ if [[ -e "file.txt" ]]; then fi ``` -Arrays ------- +## Arrays ### Defining arrays @@ -509,8 +512,8 @@ for i in "${arrayName[@]}"; do done ``` -Dictionaries ------------- +## Dictionaries + {: .-three-column} ### Defining @@ -556,8 +559,7 @@ for key in "${!sounds[@]}"; do done ``` -Options -------- +## Options ### Options @@ -581,8 +583,7 @@ shopt -s globstar # Allow ** for recursive matches ('lib/**/*.rb' => 'lib/a/b Set `GLOBIGNORE` as a colon-separated list of patterns to be removed from glob matches. -History -------- +## History ### Commands @@ -625,9 +626,7 @@ History `!!` can be replaced with any valid expansion i.e. `!cat`, `!-2`, `!42`, etc. - -Miscellaneous -------------- +## Miscellaneous ### Numeric calculations @@ -640,7 +639,7 @@ $(($RANDOM%200)) # Random number 0..199 ``` ```bash -declare -i count # Declare as type integer +declare -i count # Declare as type integer count+=1 # Increment ``` @@ -732,18 +731,18 @@ printf '%i+%i=%i\n' 1 2 3 4 5 9 ### Transform strings -| Command option | Description | -| ------------------ | --------------------------------------------------- | -| `-c` | Operations apply to characters not in the given set | -| `-d` | Delete characters | -| `-s` | Replaces repeated characters with single occurrence | -| `-t` | Truncates | -| `[:upper:]` | All upper case letters | -| `[:lower:]` | All lower case letters | -| `[:digit:]` | All digits | -| `[:space:]` | All whitespace | -| `[:alpha:]` | All letters | -| `[:alnum:]` | All letters and digits | +| Command option | Description | +| -------------- | --------------------------------------------------- | +| `-c` | Operations apply to characters not in the given set | +| `-d` | Delete characters | +| `-s` | Replaces repeated characters with single occurrence | +| `-t` | Truncates | +| `[:upper:]` | All upper case letters | +| `[:lower:]` | All lower case letters | +| `[:digit:]` | All digits | +| `[:space:]` | All whitespace | +| `[:alpha:]` | All letters | +| `[:alnum:]` | All letters and digits | #### Example @@ -838,10 +837,11 @@ fi ``` ## Also see + {: .-one-column} -* [Bash-hackers wiki](https://web.archive.org/web/20230406205817/https://wiki.bash-hackers.org/) _(bash-hackers.org)_ -* [Shell vars](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars) _(bash-hackers.org)_ -* [Learn bash in y minutes](https://learnxinyminutes.com/docs/bash/) _(learnxinyminutes.com)_ -* [Bash Guide](http://mywiki.wooledge.org/BashGuide) _(mywiki.wooledge.org)_ -* [ShellCheck](https://www.shellcheck.net/) _(shellcheck.net)_ +- [Bash-hackers wiki](https://web.archive.org/web/20230406205817/https://wiki.bash-hackers.org/) _(bash-hackers.org)_ +- [Shell vars](https://web.archive.org/web/20230318164746/https://wiki.bash-hackers.org/syntax/shellvars) _(bash-hackers.org)_ +- [Learn bash in y minutes](https://learnxinyminutes.com/docs/bash/) _(learnxinyminutes.com)_ +- [Bash Guide](http://mywiki.wooledge.org/BashGuide) _(mywiki.wooledge.org)_ +- [ShellCheck](https://www.shellcheck.net/) _(shellcheck.net)_ diff --git a/pry.md b/pry.md index fcb0a3c..8e77b1a 100644 --- a/pry.md +++ b/pry.md @@ -95,7 +95,7 @@ Also consider [pry-rails](https://rubygems.org/gems/pry-rails). > ls -i # Instance vars - > ls -G xx # Grey by regex + > ls -G xx # Grep by regex ## Shell integration diff --git a/sequel.md b/sequel.md index c57b600..a15750d 100644 --- a/sequel.md +++ b/sequel.md @@ -5,6 +5,7 @@ layout: 2017/sheet --- ### About + {: .-intro} Sequel is a database toolkit for Ruby. @@ -13,382 +14,460 @@ Sequel is a database toolkit for Ruby. ### Open a database - require 'rubygems' - require 'sequel' +``` +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 => 'user', :password => 'password', :host => 'localhost') - DB = Sequel.ado('mydb') +DB = Sequel.sqlite('my_blog.db') +DB = Sequel.connect('postgres://user:password@localhost/my_db') +DB = Sequel.postgres('my_db', :user => 'user', :password => 'password', :host => 'localhost') +DB = Sequel.ado('mydb') +``` ### Open an SQLite memory database Without a filename argument, the sqlite adapter will setup a new sqlite database in memory. - DB = Sequel.sqlite +``` +DB = Sequel.sqlite +``` ### Logging SQL statements - require 'logger' - DB = Sequel.sqlite '', :loggers => [Logger.new($stdout)] - # or - DB.loggers << Logger.new(...) +``` +require 'logger' +DB = Sequel.sqlite '', :loggers => [Logger.new($stdout)] +# or +DB.loggers << Logger.new(...) +``` ### Using raw SQL - DB.run "CREATE TABLE users (name VARCHAR(255) NOT NULL, age INT(3) NOT NULL)" - dataset = DB["SELECT age FROM users WHERE name = ?", name] - dataset.map(:age) - DB.fetch("SELECT name FROM users") do |row| - p row[:name] - end +``` +DB.run "CREATE TABLE users (name VARCHAR(255) NOT NULL, age INT(3) NOT NULL)" +dataset = DB["SELECT age FROM users WHERE name = ?", name] +dataset.map(:age) +DB.fetch("SELECT name FROM users") do |row| + p row[:name] +end +``` ### Create a dataset - dataset = DB[:items] - dataset = DB.from(:items) +``` +dataset = DB[:items] +dataset = DB.from(:items) +``` ### Most dataset methods are chainable - dataset = DB[:managers].where(:salary => 5000..10000).order(:name, :department) +``` +dataset = DB[:managers].where(:salary => 5000..10000).order(:name, :department) +``` ### Insert rows - dataset.insert(:name => 'Sharon', :grade => 50) +``` +dataset.insert(:name => 'Sharon', :grade => 50) +``` ### Retrieve rows - dataset.each{|r| p r} - dataset.all # => [{...}, {...}, ...] - dataset.first # => {...} +``` +dataset.each{|r| p r} +dataset.all # => [{...}, {...}, ...] +dataset.first # => {...} +``` ### Update/Delete rows - dataset.filter(~:active).delete - dataset.filter('price < ?', 100).update(:active => true) +``` +dataset.filter(~:active).delete +dataset.filter('price < ?', 100).update(:active => true) +``` ### Datasets are Enumerable - dataset.map{|r| r[:name]} - dataset.map(:name) # same as above +``` +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 +dataset.inject(0){|sum, r| sum + r[:value]} +dataset.sum(:value) # same as above +``` ### Filtering (see also doc/dataset_filtering.rdoc) #### Equality - dataset.filter(:name => 'abc') - dataset.filter('name = ?', 'abc') +``` +dataset.filter(:name => 'abc') +dataset.filter('name = ?', 'abc') +``` #### Inequality - dataset.filter{value > 100} - dataset.exclude{value <= 100} +``` +dataset.filter{value > 100} +dataset.exclude{value <= 100} +``` #### Inclusion - dataset.filter(:value => 50..100) - dataset.where{(value >= 50) & (value <= 100)} +``` +dataset.filter(:value => 50..100) +dataset.where{(value >= 50) & (value <= 100)} - dataset.where('value IN ?', [50,75,100]) - dataset.where(:value=>[50,75,100]) +dataset.where('value IN ?', [50,75,100]) +dataset.where(:value=>[50,75,100]) - dataset.where(:id=>other_dataset.select(:other_id)) +dataset.where(:id=>other_dataset.select(:other_id)) +``` #### Subselects as scalar values - dataset.where('price > (SELECT avg(price) + 100 FROM table)') - dataset.filter{price > dataset.select(avg(price) + 100)} +``` +dataset.where('price > (SELECT avg(price) + 100 FROM table)') +dataset.filter{price > dataset.select(avg(price) + 100)} +``` #### LIKE/Regexp - DB[:items].filter(:name.like('AL%')) - DB[:items].filter(:name => /^AL/) +``` +DB[:items].filter(:name.like('AL%')) +DB[:items].filter(:name => /^AL/) +``` #### AND/OR/NOT - DB[:items].filter{(x > 5) & (y > 10)}.sql - # SELECT * FROM items WHERE ((x > 5) AND (y > 10)) +``` +DB[:items].filter{(x > 5) & (y > 10)}.sql +# SELECT * FROM items WHERE ((x > 5) AND (y > 10)) - DB[:items].filter({:x => 1, :y => 2}.sql_or & ~{:z => 3}).sql - # SELECT * FROM items WHERE (((x = 1) OR (y = 2)) AND (z != 3)) +DB[:items].filter({:x => 1, :y => 2}.sql_or & ~{:z => 3}).sql +# SELECT * FROM items WHERE (((x = 1) OR (y = 2)) AND (z != 3)) +``` #### Mathematical operators - DB[:items].filter((:x + :y) > :z).sql - # SELECT * FROM items WHERE ((x + y) > z) +``` +DB[:items].filter((:x + :y) > :z).sql +# SELECT * FROM items WHERE ((x + y) > z) - DB[:items].filter{price - 100 < avg(price)}.sql - # SELECT * FROM items WHERE ((price - 100) < avg(price)) +DB[:items].filter{price - 100 < avg(price)}.sql +# SELECT * FROM items WHERE ((price - 100) < avg(price)) +``` ### Ordering - dataset.order(:kind) - dataset.reverse_order(:kind) - dataset.order(:kind.desc, :name) +``` +dataset.order(:kind) +dataset.reverse_order(:kind) +dataset.order(:kind.desc, :name) +``` ### Limit/Offset - dataset.limit(30) # LIMIT 30 - dataset.limit(30, 10) # LIMIT 30 OFFSET 10 +``` +dataset.limit(30) # LIMIT 30 +dataset.limit(30, 10) # LIMIT 30 OFFSET 10 +``` ### Joins - DB[:items].left_outer_join(:categories, :id => :category_id).sql - # SELECT * FROM items LEFT OUTER JOIN categories ON categories.id = items.category_id +``` +DB[:items].left_outer_join(:categories, :id => :category_id).sql +# SELECT * FROM items LEFT OUTER JOIN categories ON categories.id = items.category_id + +DB[:items].join(:categories, :id => :category_id).join(:groups, :id => :items__group_id) +# SELECT * FROM items INNER JOIN categories ON categories.id = items.category_id INNER JOIN groups ON groups.id = items.group_id +``` - DB[:items].join(:categories, :id => :category_id).join(:groups, :id => :items__group_id) - # SELECT * FROM items INNER JOIN categories ON categories.id = items.category_id INNER JOIN groups ON groups.id = items.group_id - ### Aggregate functions methods - dataset.count #=> record count - dataset.max(:price) - dataset.min(:price) - dataset.avg(:price) - dataset.sum(:stock) +``` +dataset.count #=> 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)) +dataset.group_and_count(:category) +dataset.group(:category).select(:category, :AVG.sql_function(:price)) +``` ### SQL Functions / Literals - dataset.update(:updated_at => :NOW.sql_function) - dataset.update(:updated_at => 'NOW()'.lit) +``` +dataset.update(:updated_at => :NOW.sql_function) +dataset.update(:updated_at => 'NOW()'.lit) - dataset.update(:updated_at => "DateValue('1/1/2001')".lit) - dataset.update(:updated_at => :DateValue.sql_function('1/1/2001')) +dataset.update(:updated_at => "DateValue('1/1/2001')".lit) +dataset.update(:updated_at => :DateValue.sql_function('1/1/2001')) +``` ### Schema Manipulation - DB.create_table :items do - primary_key :id - String :name, :unique => true, :null => false - TrueClass :active, :default => true - foreign_key :category_id, :categories - DateTime :created_at - - index :created_at - end +``` +DB.create_table :items do + primary_key :id + String :name, :unique => true, :null => false + TrueClass :active, :default => true + foreign_key :category_id, :categories + DateTime :created_at - DB.drop_table :items + index :created_at +end - DB.create_table :test do - String :zipcode - enum :system, :elements => ['mac', 'linux', 'windows'] - end +DB.drop_table :items + +DB.create_table :test do + String :zipcode + enum :system, :elements => ['mac', 'linux', 'windows'] +end +``` ### Aliasing - 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 +``` +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 +``` ### Transactions - DB.transaction do - dataset.insert(:first_name => 'Inigo', :last_name => 'Montoya') - dataset.insert(:first_name => 'Farm', :last_name => 'Boy') - end # Either both are inserted or neither are inserted +``` +DB.transaction do + dataset.insert(:first_name => 'Inigo', :last_name => 'Montoya') + dataset.insert(:first_name => 'Farm', :last_name => 'Boy') +end # Either both are inserted or neither are inserted +``` Database#transaction is re-entrant: - DB.transaction do # BEGIN issued only here - DB.transaction - dataset << {:first_name => 'Inigo', :last_name => 'Montoya'} - end - end # COMMIT issued only here +``` +DB.transaction do # BEGIN issued only here + DB.transaction + dataset << {:first_name => 'Inigo', :last_name => 'Montoya'} + end +end # COMMIT issued only here +``` Transactions are aborted if an error is raised: - DB.transaction do - raise "some error occurred" - end # ROLLBACK issued and the error is re-raised +``` +DB.transaction do + raise "some error occurred" +end # ROLLBACK issued and the error is re-raised +``` Transactions can also be aborted by raising Sequel::Rollback: - DB.transaction do - raise(Sequel::Rollback) if something_bad_happened - end # ROLLBACK issued and no error raised +``` +DB.transaction do + raise(Sequel::Rollback) if something_bad_happened +end # ROLLBACK issued and no error raised +``` Savepoints can be used if the database supports it: - DB.transaction do - dataset << {:first_name => 'Farm', :last_name => 'Boy'} # Inserted - DB.transaction(:savepoint=>true) # This savepoint is rolled back - dataset << {:first_name => 'Inigo', :last_name => 'Montoya'} # Not inserted - raise(Sequel::Rollback) if something_bad_happened - end - dataset << {:first_name => 'Prince', :last_name => 'Humperdink'} # Inserted - end +``` +DB.transaction do + dataset << {:first_name => 'Farm', :last_name => 'Boy'} # Inserted + DB.transaction(:savepoint=>true) # This savepoint is rolled back + dataset << {:first_name => 'Inigo', :last_name => 'Montoya'} # Not inserted + raise(Sequel::Rollback) if something_bad_happened + end + dataset << {:first_name => 'Prince', :last_name => 'Humperdink'} # Inserted +end +``` ### Miscellaneous: - dataset.sql # "SELECT * FROM items" - dataset.delete_sql # "DELETE FROM items" - dataset.where(:name => 'sequel').exists # "EXISTS ( SELECT * FROM items WHERE name = 'sequel' )" - dataset.columns #=> array of columns in the result set, does a SELECT - DB.schema(:items) => [[:id, {:type=>:integer, ...}], [:name, {:type=>:string, ...}], ...] +``` +dataset.sql # "SELECT * FROM items" +dataset.delete_sql # "DELETE FROM items" +dataset.where(:name => 'sequel').exists # "EXISTS ( SELECT * FROM items WHERE name = 'sequel' )" +dataset.columns #=> array of columns in the result set, does a SELECT +DB.schema(:items) => [[:id, {:type=>:integer, ...}], [:name, {:type=>:string, ...}], ...] +``` ----------------------------------------------------------------------------------------------------------------------------------------------------------------- +--- ### Documents - 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 +``` +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 +``` ### Alter table - database.alter_table :deals do - add_column :name, String - drop_column :column_name - rename_column :from, :to +``` +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_constraint :valid_name, :name.like('A%') + drop_constraint :constraint - add_full_text_index :body - add_spacial_index [columns] + add_full_text_index :body + add_spacial_index [columns] - add_index :price - drop_index :index + 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, '' + 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 + set_column_type :price, 'char(10)' +end +``` ### Model associations - class Deal < Sequel::Model +``` +class Deal < Sequel::Model - # Us (left) <=> Them (right) - many_to_many :images, - left_id: :deal_id, - right_id: :image_id, - join_table: :image_links + # Us (left) <=> Them (right) + many_to_many :images, + left_key: :deal_id, + right_key: :image_id, + join_table: :image_links - one_to_many :files, - key: :deal_id, - class: :DataFile, + one_to_many :files, + key: :deal_id, + class: :DataFile, - many_to_one :parent, class: self - one_to_many :children, key: :parent_id, class: self + 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 > 50000 } - end + one_to_many :gold_albums, class: :Album do |ds| + ds.filter { copies_sold > 50000 } + end +``` Provided by many_to_many - Deal[1].images - Deal[1].add_image - Deal[1].remove_image - Deal[1].remove_all_images +``` +Deal[1].images +Deal[1].add_image +Deal[1].remove_image +Deal[1].remove_all_images +``` ### Validations - 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=>'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 =>, :allow_nil =>, :allow_blank =>, - # :allow_missing =>, - - 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 +``` +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=>'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 =>, :allow_nil =>, :allow_blank =>, + # :allow_missing =>, + + 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 +deal.errors +``` ### Model stuff - deal = Deal[1] - deal.changed_columns - deal.destroy # Calls hooks - deal.delete # No hooks - deal.exists? - deal.new? - deal.hash # Only uniques - deal.keys #=> [:id, :name] - deal.modified! - deal.modified? - - deal.lock! +``` +deal = Deal[1] +deal.changed_columns +deal.destroy # Calls hooks +deal.delete # No hooks +deal.exists? +deal.new? +deal.hash # Only uniques +deal.keys #=> [:id, :name] +deal.modified! +deal.modified? + +deal.lock! +``` ### Callbacks - before_create - after_create +``` +before_create +after_create - before_validation - after_validation - before_save - before_update - UPDATE QUERY - after_update - after_save +before_validation +after_validation +before_save +before_update +UPDATE QUERY +after_update +after_save - before_destroy - DELETE QUERY - after_destroy +before_destroy +DELETE QUERY +after_destroy +``` ### Schema - class Deal < 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 > 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 +``` +class Deal < 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 > 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 +``` ### Unrestrict primary key - Category.create id: 'travel' # error - Category.unrestrict_primary_key - Category.create id: 'travel' # ok +``` +Category.create id: 'travel' # error +Category.unrestrict_primary_key +Category.create id: 'travel' # ok +``` diff --git a/typescript.md b/typescript.md index d9cd501..7a4e6e7 100644 --- a/typescript.md +++ b/typescript.md @@ -244,7 +244,7 @@ type Point = { x: number; y: number }; type P = keyof Point; // x | y ``` -## Conditinal Types +## Conditional Types ```ts // SomeType extends OtherType ? TrueType : FalseType; -- 2.11.0