El uso de stored procedures está muy difundido entre los administradores de bases de datos como una forma de encapsular la lógica de datos de las aplicaciones. La comunidad de desarrolladores web, sin embargo, nunca los adoptó plenamente porque siempre ha tenido dudas acerca de su portabilidad y mantenibilidad, además de una antipatía generalizada por SQL.
De todos modos, la alternativa que se utiliza actualmente, la dupla abstracción de base de datos-ORM, también tiene sus propios problemas: baja performance, subutilización de las funciones avanzadas de bases de datos, y sintaxis de queries ad-hoc que terminan siendo más complicadas que el propio SQL.
La creciente popularidad de las bases de datos NoSQL pone de manifiesto que los desarrolladores web contemporáneos están de nuevo dispuestos a considerar librerías de bases de datos específicas del vendedor para el desarrollo de aplicaciones. Entonces veamos qué es lo que tiene para ofrecernos un vendedor en particular: PostgreSQL.
En esta charla voy a demostrar que crear una API basada en una mezcla de objetos Ruby sencillos y stored procedures de Postgres puede ser una opción muy convincente como sustituto de ORM.
5. 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
6. Stored Procedures
programación "real" con SQL
Wednesday, November 9, 11
17. No hagan eso por favor
Wednesday, November 9, 11
18. Squirm
github.com/bvision/squirm
Wednesday, November 9, 11
19. Squirm
• Azúcar sintáctico para la gema "pg"
• Connection pool básico
• Stored procedures como procs o lambdas
Wednesday, November 9, 11
20. 1 Squirm.connect host: "localhost"
2 Squirm.transaction do
3 Squirm.exec "SELECT ..." do |result|
4 result.to_a
5 end
6 Squirm.rollback
7 end
Wednesday, November 9, 11
21. 1 Squirm do
2 connect host: "localhost"
3 transaction do
4 exec "SELECT ..." do |result|
5 result.to_a
6 end
7 rollback
8 end
9 end
Wednesday, November 9, 11
22. 1 Squirm do
2 exec "CREATE FUNCTION ..."
3 proc = procedure "greeting"
4 proc.call "Juan"
5 #=> "¡hola Juan!"
6 end
Wednesday, November 9, 11
23. 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.new
11 foo.bar("hello")
Wednesday, November 9, 11
24. GET followers/ids
GET friends/ids
GET lists/all
GET favorites
GET statuses/home_timeline
GET statuses/mentions
GET statuses/user_timeline
GET direct_messages
Wednesday, November 9, 11
26. Squirm Model
github.com/bvision/squirm_model
Wednesday, November 9, 11
27. Squirm Model
• Generador de tablas, procedures
• SQL "scaffolding"
• Active Model
Wednesday, November 9, 11
28. $ 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" TEXT
7 );
Wednesday, November 9, 11
29. $ 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_time
Wednesday, November 9, 11
30. $ 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
31. 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_json
10 redirect_to @person
Wednesday, November 9, 11
32. 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 :name
10 end
Wednesday, November 9, 11
33. 1 class PersonTest < Test::Unit::TestCase
2 def test_create
3 assert Person.create(Person.sample)
4 end
5 end
Wednesday, November 9, 11
34. 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.delete
11 end
Wednesday, November 9, 11
35. Benchmarks
ROFLSCALE
0 7.5 15 22.5 30
Squirm Model ActiveRecord
Wednesday, November 9, 11
36. ¿Por qué no usar un
ORM?
Wednesday, November 9, 11
37. Usen los ORM
• Active Record
• DataMapper
• Sequel
• otros
Wednesday, November 9, 11
38. Pero conozcan
sus defectos
Wednesday, November 9, 11
39. 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
40. table = Product.arel_table
Product.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