Norman Clarke
Business Vision Ruby Labs@compay
Volver al futuro con SQL y stored procedures
Wednesday, November 9, 11
Wednesday, November 9, 11
Wednesday, November 9, 11
Wednesday, November 9, 11
Lo que les espera...
• Características, ventajas y desventajas de stored procedures
• Una librería experimental basada en stored procedures
• Stored procedures vs. ORM
Wednesday, November 9, 11
Stored Proceduresprogramación "real" con SQL
Wednesday, November 9, 11
postgres=# select greeting();
greeting ------------- hello world!
(1 row)
Wednesday, November 9, 11
1 CREATE FUNCTION greeting()2 RETURNS TEXT AS $$3 BEGIN4 RETURN 'hello world!';5 END;6 $$ LANGUAGE 'plpgsql';
Wednesday, November 9, 11
declarebegin select ... if ... then update ... else while ... loop ... end loop; end if; return ...;end;
Wednesday, November 9, 11
¿Cuántas funciones?Postgres: 2333
Lua: 135
Wednesday, November 9, 11
Ventajas
Wednesday, November 9, 11
Cacheo automáticode consultas
Wednesday, November 9, 11
Menos coordinación entre la BD y Ruby
O Java, Python, Perl, PHP, etc.
Wednesday, November 9, 11
Encapsulación del esquema
Stored Procedures
Esquema Ruby
Wednesday, November 9, 11
Toda la lógica de negocios en SQL
Wednesday, November 9, 11
Wednesday, November 9, 11
No hagan eso por favor
Wednesday, November 9, 11
Squirm
github.com/bvision/squirm
Wednesday, November 9, 11
Squirm
• Azúcar sintáctico para la gema "pg"
• Connection pool básico
• Stored procedures como procs o lambdas
Wednesday, November 9, 11
1 Squirm.connect host: "localhost"2 Squirm.transaction do3 Squirm.exec "SELECT ..." do |result|4 result.to_a5 end6 Squirm.rollback7 end
Wednesday, November 9, 11
1 Squirm do2 connect host: "localhost"3 transaction do4 exec "SELECT ..." do |result|5 result.to_a6 end7 rollback8 end9 end
Wednesday, November 9, 11
1 Squirm do2 exec "CREATE FUNCTION ..."3 proc = procedure "greeting"4 proc.call "Juan"5 #=> "¡hola Juan!"6 end
Wednesday, November 9, 11
1 class Foo 2 3 @@bar = Procedure.load "bar" 4 5 def bar(*args) 6 @@bar.call(*args) 7 end 8 end 9 10 foo = Foo.new11 foo.bar("hello")
Wednesday, November 9, 11
GET followers/idsGET friends/idsGET lists/allGET favorites GET statuses/home_timelineGET statuses/mentionsGET statuses/user_timelineGET direct_messages
Wednesday, November 9, 11
SELECT followers.ids()SELECT friends.ids()SELECT lists.all()SELECT favorites() SELECT statuses.home_timeline()SELECT statuses.mentions()SELECT statuses.user_timeline()SELECT direct_messages()
Wednesday, November 9, 11
Squirm Model
github.com/bvision/squirm_model
Wednesday, November 9, 11
Squirm Model
• Generador de tablas, procedures
• SQL "scaffolding"
• Active Model
Wednesday, November 9, 11
$ squirm table person id email birth_date access_time bio
1 CREATE TABLE "person" (2 "id" SERIAL NOT NULL PRIMARY KEY,3 "email" VARCHAR(64) NOT NULL UNIQUE,4 "birth_date" DATE,5 "access_time" TIMESTAMP WITH TIME ZONE,6 "bio" TEXT7 );
Wednesday, November 9, 11
$ squirm table person id created_at
1 CREATE TABLE "person" ( 2 "id" SERIAL NOT NULL PRIMARY KEY, 3 "created_at" TIMESTAMP WITH TIME ZONE NOT NULL 4 ); 5 6 CREATE OR REPLACE FUNCTION "update_person_created_at_timestamp"() 7 RETURNS TRIGGER AS $$ 8 BEGIN 9 NEW.created_at = NOW();10 RETURN NEW;11 END;12 $$ LANGUAGE 'plpgsql';13 14 CREATE TRIGGER "update_person_created_at_timestamp"15 BEFORE INSERT ON "person"16 FOR EACH ROW EXECUTE PROCEDURE "update_person_created_at_timestamp"();
Wednesday, November 9, 11
$ squirm table person id email --api
CREATE TABLE "person" ...CREATE SCHEMA "person" ...CREATE FUNCTION "person.get" ...CREATE FUNCTION "person.create" ...CREATE FUNCTION "person.update" ...CREATE FUNCTION "person.delete" ...
Wednesday, November 9, 11
1 class Person 2 extend Squirm::Model ... 3 validates_presence_of :name 4 end 5 6 Person.create(...) 7 @person = Person.find(1) 8 @person.valid? 9 @person.to_json10 redirect_to @person
Wednesday, November 9, 11
1 class Person 2 extend Squirm::Model 3 4 sample do |s| 5 s.id = 1 6 s.name = "Juan Fulano" 7 end 8 9 validates_presence_of :name10 end
Wednesday, November 9, 11
1 class PersonTest < Test::Unit::TestCase2 def test_create3 assert Person.create(Person.sample)4 end5 end
Wednesday, November 9, 11
1 Squirm do 2 connect host: "localhost" 3 4 exec Person.to_ddl 5 6 Person.finalize 7 8 p = Person.create name: "John" 9 p.update name: "Johnny"10 p.delete11 end
Wednesday, November 9, 11
ROFLSCALE
0 7.5 15 22.5 30
Squirm Model ActiveRecord
Benchmarks
Wednesday, November 9, 11
¿Por qué no usar un ORM?
Wednesday, November 9, 11
Usen los ORM
• Active Record
• DataMapper
• Sequel
• otros
Wednesday, November 9, 11
Pero conozcan sus defectos
Wednesday, November 9, 11
Exhibition.all( :run_time.gt => 2, :run_time.lt => 5)
run_time > 1 AND run_time < 5
...you might be wondering how we can specify conditions beyond equality without resorting to SQL. Well, thanks to some clever additions to the Symbol class, it’s easy!
Wednesday, November 9, 11
table = Product.arel_tableProduct.where( table[:price].eq(2.99). or(table[:name].matches("%foo"))).to_sql
#=> "WHERE price = 2.99 OR name LIKE '%foo'"
railscasts.com/episodes/215-advanced-queries-in-rails-3
Wednesday, November 9, 11
SQL (mal) generado
Wednesday, November 9, 11
La abstracción dificulta el uso de features
avanzados
Wednesday, November 9, 11
Los stored procedures ofrecen una alternativa
interesante
Wednesday, November 9, 11
"Pensemos diferente"
Wednesday, November 9, 11
Nihil sub sole novum
Wednesday, November 9, 11
Postgres y MySQL están muy desaprovechados
Wednesday, November 9, 11
No usemos abstracciones innecesarias
Wednesday, November 9, 11
¡Gracias!
Wednesday, November 9, 11
Wednesday, November 9, 11
Obelisco: flickr.com/photos/budgetplaces/4173902613/Matz: flickr.com/photos/rrrodrigo/2394122680/
Gracias, fotógrafos
Wednesday, November 9, 11