Slide 1

Slide 1 text

Validations! Caching! Logic! Use your database for…

Slide 2

Slide 2 text

vote = Vote.where( user_id: current_user.id, link_id: params[:id] ).first_or_create

Slide 3

Slide 3 text

INSERT INTO votes (user_id, link_id) VALUES (1, 2) ON CONFLICT DO NOTHING; Simple upsert

Slide 4

Slide 4 text

INSERT INTO profiles (user_id, name, age) VALUES (27, "Arjan", 32) ON CONFLICT ON CONSTRAINT profiles_users_fk ON UPDATE SET name = EXCLUDED.name, age = EXCLUDED.age; Upsert with update

Slide 5

Slide 5 text

class User < ActiveRecord::Base default_scope -> { where(deleted_at: nil) } scope :account_managers, -> { where(role: 'account_manager') } end

Slide 6

Slide 6 text

CREATE VIEW account_managers AS SELECT * FROM users WHERE role = 'account_manager' AND deleted_at IS NULL WITH CASCADED CHECK OPTION; class AccountManager < ActiveRecord::Base end Views

Slide 7

Slide 7 text

CREATE MATERIALIZED VIEW invoices AS SELECT number, SUM(lines.amount) FROM offers LEFT JOIN lines ON lines.offer_id = offers.id GROUP BY number; Materialized views

Slide 8

Slide 8 text

CREATE FUNCTION refresh_invoices() RETURNS trigger AS $$ BEGIN REFRESH MATERIALIZED VIEW invoices; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trigger_refresh_invoices AFTER TRUNCATE OR INSERT OR UPDATE OR DELETE ON offers FOR EACH STATEMENT EXECUTE PROCEDURE refresh_invoices(); Refreshing materialised views

Slide 9

Slide 9 text

CREATE TRIGGER soft_delete_user BEFORE DELETE ON users FOR EACH ROW EXECUTE PROCEDURE soft_delete(); CREATE FUNCTION soft_delete() RETURNS trigger AS $$ DECLARE command text := ' SET deleted_at = current_timestamp WHERE id = $1'; BEGIN EXECUTE 'UPDATE ' || TG_TABLE_NAME || command USING OLD.id; RETURN NULL; END; $$ LANGUAGE plpgsql; Triggers per row

Slide 10

Slide 10 text

class User < ActiveRecord::Base validates :email, presence: true, length: { maximum: 250 } end

Slide 11

Slide 11 text

ALTER TABLE users ADD CONSTRAINT email_presence CHECK (char_length(email) > 0); Constraints

Slide 12

Slide 12 text

ALTER TABLE users ADD CONSTRAINT age_numericality CHECK (age >= 18); Constraints

Slide 13

Slide 13 text

ALTER TABLE users ADD CONSTRAINT approved_role CHECK (role IN ("public", "admin")); Constraints

Slide 14

Slide 14 text

ALTER TABLE users ADD CONSTRAINT email_format CHECK (email ~* '\A([^@\s]+)@((?:[-a- z0-9]+\.)+[a-z]{2,})\Z'); Constraints

Slide 15

Slide 15 text

create_table :articles do |t| t.string :title t.text :body t.string :tags, array: true t.jsonb :props, default: '{}' end Complex datatypes

Slide 16

Slide 16 text

Use it today* • Data validation • Decouple storage from usage • Referential integrity • Simplify complex queries • Cache expensive queries • Data audit trail • Optimistic locking • Counter cache • Updated/created timestamps • Multi-table constraints • Schema-less data • Multiple-table inheritance

Slide 17

Slide 17 text

your database is
 probably not
 an implementation detail
 of your application

Slide 18

Slide 18 text

No content