rails_db_views 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ff2f855836b239c4af2dae529189588761c22ff3
4
- data.tar.gz: 027d2f0e0f45ddb654d5ba70f4613219aa581eba
3
+ metadata.gz: 377a7268197020fe62a087261f12cd94ead05b30
4
+ data.tar.gz: 90090417d3607056ba577fa159f6b29366ca870b
5
5
  SHA512:
6
- metadata.gz: c1289482ced1e66da617ad275fd184e68fd2050aaa1ed0f53288066931e35418a6424ab4e7b09fc2bef98e598a90c382bb3d7311ff5107344061ed80b31d7bcd
7
- data.tar.gz: 871085dcaac1dc9663bdc6c4b4ce983f9e9d9be8363c41f0cfeced6ca70023334598d09c9481efbca3aaa722411d7412fe6cefe23653e225a7d388e3b4e76f7e
6
+ metadata.gz: a1f7de8e87be5f0de472bcc4a19d11934b69bee78520ed7704c0b33c686e7d942af8755c66a644757c076b073d1e77490aab5f945f219f61046b6efc3ddef446
7
+ data.tar.gz: 13c1b6a148618a475a9185fcaaba6b41e7905de85eaa0d4a45b7c373fa169b679b51748fe7a319361a6ec3fb860ec8bde007dc6dcbcfd03aedbecf8ed1d5b8cc
@@ -48,6 +48,10 @@ class RailsDbViews::DatabaseSymbol
48
48
  status == Status::UNLOADED
49
49
  end
50
50
 
51
+ def uncommented_sql_content
52
+ sql_content.split("\n").reject{|x| x=~ COMMENTS }.join("\n")
53
+ end
54
+
51
55
  def create!
52
56
  return if marked_as_deleted? || loaded?
53
57
 
@@ -82,8 +86,8 @@ class RailsDbViews::DatabaseSymbol
82
86
 
83
87
  begin
84
88
  ActiveRecord::Base.connection.execute(drop_sql)
85
- #rescue ActiveRecord::ActiveRecordError => e #Probably because the symbol doesn't exists yet.
86
- # handle_error_on_drop
89
+ rescue ActiveRecord::ActiveRecordError => e #Probably because the symbol doesn't exists yet.
90
+ handle_error_on_drop
87
91
  end
88
92
 
89
93
  self.status = Status::LOADED
@@ -107,6 +111,11 @@ protected
107
111
  SHARP_CHAR_DIRECTIVE_START = /^#[ \t]*!/
108
112
  DIRECTIVE_START = /#{TWO_DASH_DIRECTIVE_START}|#{SHARP_CHAR_DIRECTIVE_START}/
109
113
 
114
+ #It's not very safe in case we start a line into a string with the characters -- or #.
115
+ COMMENTS_TWO_DASH = /^--.*$/
116
+ COMMENTS_SHARP = /^#.*$/
117
+ COMMENTS = /#{COMMENTS_TWO_DASH}|#{COMMENTS_SHARP}/
118
+
110
119
  def circular_reference_error
111
120
  raise CircularReferenceError, "Circular file reference! (file: #{path})"
112
121
  end
@@ -1,7 +1,7 @@
1
1
  class RailsDbViews::Function < RailsDbViews::DatabaseSymbol
2
2
  def create_sql
3
3
  puts "CREATE OR REPLACE FUNCTION #{name}..."
4
- "CREATE OR REPLACE FUNCTION #{name} #{sql_content}"
4
+ "CREATE OR REPLACE FUNCTION #{name} #{uncommented_sql_content}"
5
5
  end
6
6
 
7
7
  def drop_sql
@@ -1,3 +1,3 @@
1
1
  module RailsDbViews
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  class RailsDbViews::View < RailsDbViews::DatabaseSymbol
2
2
  def create_sql
3
3
  puts "CREATE VIEW #{name}..."
4
- "CREATE VIEW #{name} AS #{sql_content}"
4
+ "CREATE VIEW #{name} AS #{uncommented_sql_content}"
5
5
  end
6
6
 
7
7
  def drop_sql
@@ -0,0 +1,2 @@
1
+ class Chat < ActiveRecord::Base
2
+ end
@@ -0,0 +1,6 @@
1
+ class Message < ActiveRecord::Base
2
+ #receiver_name, receiver_id, sender_name, sender_id, content, updated_at, created_at
3
+ belongs_to :receiver, class_name: "User"
4
+ belongs_to :sender, class_name: "Sender"
5
+
6
+ end
@@ -0,0 +1,18 @@
1
+ class User < ActiveRecord::Base
2
+ validates :name, presence: true, uniqueness: true
3
+
4
+
5
+ has_many :sended_messages, class_name: "UserMessage", foreign_key: :from
6
+ has_many :received_messages, class_name: "UserMessage", foreign_key: :to
7
+
8
+ has_many :messages
9
+
10
+ def message! user, content
11
+ UserMessage.create! from: self, to: user, content: content
12
+ end
13
+
14
+ # Return all chats of this guy!
15
+ def chats
16
+ Chat.where("'{?}' && ids", self.id)
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ class UserMessage < ActiveRecord::Base
2
+ belongs_to :from, class_name: "User"
3
+ belongs_to :to, class_name: "User"
4
+ end
5
+
6
+
@@ -5,7 +5,7 @@
5
5
  # gem 'sqlite3'
6
6
  development:
7
7
  adapter: postgresql
8
- database: rails_db_views
8
+ database: rails_db_views_development
9
9
  pool: 5
10
10
  timeout: 5000
11
11
 
@@ -13,13 +13,7 @@ development:
13
13
  # re-generated from your development database when you run "rake".
14
14
  # Do not set this db to the same as development or production.
15
15
  test:
16
- adapter: sqlite3
17
- database: db/test.sqlite3
18
- pool: 5
19
- timeout: 5000
20
-
21
- production:
22
- adapter: sqlite3
23
- database: db/production.sqlite3
16
+ adapter: postgresql
17
+ database: rails_db_views_test
24
18
  pool: 5
25
19
  timeout: 5000
@@ -0,0 +1,10 @@
1
+ (x int[]) RETURNS int[] AS $$
2
+ BEGIN
3
+ -- Note to myself: selection in array start at 1, not at zero !
4
+ IF x[1]::int > x[2]::int THEN
5
+ RETURN ARRAY[x[2], x[1]];
6
+ ELSE
7
+ RETURN x;
8
+ END IF;
9
+ END;
10
+ $$ LANGUAGE plpgsql;
@@ -0,0 +1,18 @@
1
+ class CreateTestTables < ActiveRecord::Migration
2
+ def change
3
+ create_table :users do |t|
4
+ t.string :name, index: true
5
+
6
+ t.timestamps null: false
7
+ end
8
+
9
+ create_table :user_messages do |t|
10
+ t.integer :from_id, index: true
11
+ t.integer :to_id, index: true
12
+
13
+ t.text :content
14
+
15
+ t.timestamps null: false
16
+ end
17
+ end
18
+ end
@@ -11,9 +11,28 @@
11
11
  #
12
12
  # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(version: 0) do
14
+ ActiveRecord::Schema.define(version: 20160208084226) do
15
15
 
16
16
  # These are extensions that must be enabled in order to support this database
17
17
  enable_extension "plpgsql"
18
18
 
19
+ create_table "user_messages", force: :cascade do |t|
20
+ t.integer "from_id"
21
+ t.integer "to_id"
22
+ t.text "content"
23
+ t.datetime "created_at", null: false
24
+ t.datetime "updated_at", null: false
25
+ end
26
+
27
+ add_index "user_messages", ["from_id"], name: "index_user_messages_on_from_id", using: :btree
28
+ add_index "user_messages", ["to_id"], name: "index_user_messages_on_to_id", using: :btree
29
+
30
+ create_table "users", force: :cascade do |t|
31
+ t.string "name"
32
+ t.datetime "created_at", null: false
33
+ t.datetime "updated_at", null: false
34
+ end
35
+
36
+ add_index "users", ["name"], name: "index_users_on_name", using: :btree
37
+
19
38
  end
Binary file
@@ -0,0 +1,6 @@
1
+ # This is the request for virtual chat object.
2
+ # !require messages
3
+ SELECT tuple_sort(ARRAY[sender_id, receiver_id]) AS ids,
4
+ MIN(created_at) as created_at, MAX(updated_at) as updated_at, COUNT(*) as number_of_messages
5
+ FROM messages
6
+ GROUP BY tuple_sort(ARRAY[sender_id, receiver_id])
@@ -0,0 +1,20 @@
1
+ -- Sample virtual model to test the gem.
2
+ -- output:
3
+ -- receiver_name, receiver_id, sender_name, sender_id, content, updated_at, created_at
4
+ SELECT DISTINCT _.receiver_name, _.receiver_id, _.sender_name, _.sender_id, _.content, _.updated_at, _.created_at
5
+ FROM
6
+ (SELECT u2.name as receiver_name, u2.id as receiver_id,
7
+ u1.name as sender_name, u1.id as sender_id,
8
+ um.content as content, um.updated_at as updated_at, um.created_at as created_at
9
+ FROM users u1
10
+ INNER JOIN user_messages um ON ( u1.id = um.from_id )
11
+ INNER JOIN users u2 ON (u2.id = um.to_id)
12
+ UNION
13
+ SELECT u1.name as receiver_name, u1.id as receiver_id,
14
+ u2.name as sender_name, u2.id as sender_id,
15
+ um.content as content, um.updated_at as updated_at, um.created_at as created_at
16
+ FROM users u1
17
+ INNER JOIN user_messages um ON ( u1.id = um.to_id )
18
+ INNER JOIN users u2 ON ( u2.id = um.from_id )
19
+ ORDER BY created_at ASC
20
+ ) AS _
@@ -0,0 +1,30 @@
1
+ # I've no idea of what I'm doing... haha.
2
+ # No, really, I don't know what's the best way to test
3
+ # this gem since it's launched during rake process and not during
4
+ # application time.
5
+ task :test do
6
+ begin
7
+ Rake::Task["db:drop"].invoke
8
+ rescue
9
+ # Case the database is not created, we ignore this error
10
+ end
11
+ # But if the database can't be created, we don't ignore.
12
+ Rake::Task["db:create"].invoke
13
+ Rake::Task["db:migrate"].invoke
14
+
15
+ # Launch RoR
16
+ Rake::Task["environment"].invoke
17
+
18
+ #Create some models
19
+ jack = User.create! name: "Jack"
20
+ cindy = User.create! name: "Cindy"
21
+ henry = User.create! name: "Henry"
22
+
23
+ jack.message! cindy, "Hey, how are you?"
24
+ cindy.message! jack, "I'm fine, and you?"
25
+ henry.message! cindy, "Me too, I want to chat with you babe!"
26
+
27
+ puts henry.chats.inspect
28
+ puts cindy.chats.inspect
29
+ puts jack.chats.inspect
30
+ end
@@ -482,3 +482,244 @@ $$ LANGUAGE plpgsql;
482
482
   (12.4ms) CREATE VIEW required AS SELECT 1 as id
483
483
   (12.6ms) CREATE VIEW hello_world AS --!require required
484
484
  SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
485
+  (2.3ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
486
+ BEGIN
487
+ RETURN x + y;
488
+ END;
489
+ $$ LANGUAGE plpgsql;
490
+  (7.2ms) DROP VIEW hello_world
491
+  (6.7ms) DROP VIEW required
492
+ ActiveRecord::SchemaMigration Load (0.7ms) SELECT "schema_migrations".* FROM "schema_migrations"
493
+  (13.2ms) CREATE VIEW required AS SELECT 1 as id
494
+  (7.1ms) CREATE VIEW hello_world AS --!require required
495
+ SELECT 'HelloWorld' WHERE ( SELECT id FROM required ) IN (1)
496
+ ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
497
+  (2.0ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
498
+ BEGIN
499
+ RETURN x + y;
500
+ END;
501
+ $$ LANGUAGE plpgsql;
502
+  (6.1ms) CREATE OR REPLACE FUNCTION tuple_sort (x int[]) RETURNS int[] AS $$
503
+ BEGIN
504
+ IF x[0] > x[1] THEN
505
+ RETURN ARRAY[x[1], x[0]];
506
+ ELSE
507
+ RETURN x;
508
+ END IF;
509
+ END;
510
+ $$ LANGUAGE plpgsql;
511
+  (0.4ms) DROP VIEW chats
512
+ PG::UndefinedTable: ERROR: view "chats" does not exist
513
+ : DROP VIEW chats
514
+  (0.2ms) DROP VIEW messages
515
+ PG::UndefinedTable: ERROR: view "messages" does not exist
516
+ : DROP VIEW messages
517
+  (7.3ms) CREATE TABLE "schema_migrations" ("version" character varying NOT NULL) 
518
+  (0.9ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
519
+ ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
520
+ Migrating to CreateTestTables (20160208084226)
521
+  (0.1ms) BEGIN
522
+  (3.7ms) CREATE TABLE "users" ("id" serial primary key, "name" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
523
+  (0.8ms) CREATE INDEX "index_users_on_name" ON "users" ("name")
524
+  (2.4ms) CREATE TABLE "user_messages" ("id" serial primary key, "from_id" integer, "to_id" integer, "content" text, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
525
+  (0.7ms) CREATE INDEX "index_user_messages_on_from_id" ON "user_messages" ("from_id")
526
+  (0.8ms) CREATE INDEX "index_user_messages_on_to_id" ON "user_messages" ("to_id")
527
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160208084226"]]
528
+  (0.5ms) COMMIT
529
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
530
+  (1.8ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
531
+ FROM pg_constraint c
532
+ JOIN pg_class t1 ON c.conrelid = t1.oid
533
+ JOIN pg_class t2 ON c.confrelid = t2.oid
534
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
535
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
536
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
537
+ WHERE c.contype = 'f'
538
+ AND t1.relname = 'user_messages'
539
+ AND t3.nspname = ANY (current_schemas(false))
540
+ ORDER BY c.conname
541
+ 
542
+  (1.5ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
543
+ FROM pg_constraint c
544
+ JOIN pg_class t1 ON c.conrelid = t1.oid
545
+ JOIN pg_class t2 ON c.confrelid = t2.oid
546
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
547
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
548
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
549
+ WHERE c.contype = 'f'
550
+ AND t1.relname = 'users'
551
+ AND t3.nspname = ANY (current_schemas(false))
552
+ ORDER BY c.conname
553
+
554
+  (10.5ms) CREATE VIEW messages AS SELECT DISTINCT _.receiver_name, _.receiver_id, _.sender_name, _.sender_id, _.content, _.updated_at, _.created_at
555
+ FROM
556
+ (SELECT u2.name as receiver_name, u2.id as receiver_id,
557
+ u1.name as sender_name, u1.id as sender_id,
558
+ um.content as content, um.updated_at as updated_at, um.created_at as created_at
559
+ FROM users u1
560
+ INNER JOIN user_messages um ON ( u1.id = um.from_id )
561
+ INNER JOIN users u2 ON (u2.id = um.to_id)
562
+ UNION
563
+ SELECT u1.name as receiver_name, u1.id as receiver_id,
564
+ u2.name as sender_name, u2.id as sender_id,
565
+ um.content as content, um.updated_at as updated_at, um.created_at as created_at
566
+ FROM users u1
567
+ INNER JOIN user_messages um ON ( u1.id = um.to_id )
568
+ INNER JOIN users u2 ON ( u2.id = um.from_id )
569
+ ORDER BY created_at ASC
570
+ ) AS _
571
+  (7.1ms) CREATE VIEW chats AS SELECT tuple_sort(ARRAY[sender_id, receiver_id]) AS ids,
572
+ MIN(created_at) as created_at, MAX(updated_at) as updated_at, COUNT(*) as number_of_messages
573
+ FROM messages
574
+ GROUP BY tuple_sort(ARRAY[sender_id, receiver_id])
575
+  (1.5ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
576
+ BEGIN
577
+ RETURN x + y;
578
+ END;
579
+ $$ LANGUAGE plpgsql;
580
+  (0.7ms) CREATE OR REPLACE FUNCTION tuple_sort (x int[]) RETURNS int[] AS $$
581
+ BEGIN
582
+ IF x[0] > x[1] THEN
583
+ RETURN ARRAY[x[1], x[0]];
584
+ ELSE
585
+ RETURN x;
586
+ END IF;
587
+ END;
588
+ $$ LANGUAGE plpgsql;
589
+  (1.6ms) DROP VIEW chats
590
+  (0.8ms) DROP VIEW messages
591
+ ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
592
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
593
+  (1.9ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
594
+ FROM pg_constraint c
595
+ JOIN pg_class t1 ON c.conrelid = t1.oid
596
+ JOIN pg_class t2 ON c.confrelid = t2.oid
597
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
598
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
599
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
600
+ WHERE c.contype = 'f'
601
+ AND t1.relname = 'user_messages'
602
+ AND t3.nspname = ANY (current_schemas(false))
603
+ ORDER BY c.conname
604
+ 
605
+  (1.4ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
606
+ FROM pg_constraint c
607
+ JOIN pg_class t1 ON c.conrelid = t1.oid
608
+ JOIN pg_class t2 ON c.confrelid = t2.oid
609
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
610
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
611
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
612
+ WHERE c.contype = 'f'
613
+ AND t1.relname = 'users'
614
+ AND t3.nspname = ANY (current_schemas(false))
615
+ ORDER BY c.conname
616
+
617
+  (8.5ms) CREATE VIEW messages AS SELECT DISTINCT _.receiver_name, _.receiver_id, _.sender_name, _.sender_id, _.content, _.updated_at, _.created_at
618
+ FROM
619
+ (SELECT u2.name as receiver_name, u2.id as receiver_id,
620
+ u1.name as sender_name, u1.id as sender_id,
621
+ um.content as content, um.updated_at as updated_at, um.created_at as created_at
622
+ FROM users u1
623
+ INNER JOIN user_messages um ON ( u1.id = um.from_id )
624
+ INNER JOIN users u2 ON (u2.id = um.to_id)
625
+ UNION
626
+ SELECT u1.name as receiver_name, u1.id as receiver_id,
627
+ u2.name as sender_name, u2.id as sender_id,
628
+ um.content as content, um.updated_at as updated_at, um.created_at as created_at
629
+ FROM users u1
630
+ INNER JOIN user_messages um ON ( u1.id = um.to_id )
631
+ INNER JOIN users u2 ON ( u2.id = um.from_id )
632
+ ORDER BY created_at ASC
633
+ ) AS _
634
+  (7.6ms) CREATE VIEW chats AS SELECT tuple_sort(ARRAY[sender_id, receiver_id]) AS ids,
635
+ MIN(created_at) as created_at, MAX(updated_at) as updated_at, COUNT(*) as number_of_messages
636
+ FROM messages
637
+ GROUP BY tuple_sort(ARRAY[sender_id, receiver_id])
638
+  (0.1ms) SELECT 1;
639
+  (0.3ms) SELECT 1;
640
+  (0.3ms) SELECT 2;
641
+  (0.2ms) SELECT 2;
642
+  (0.3ms) SELECT 2
643
+  (8.3ms) SELECT tuple_sort(ARRAY[1,3])
644
+  (0.9ms) SELECT tuple_sort(ARRAY[3,1])
645
+  (0.9ms) SELECT tuple_sort(ARRAY[3,1])
646
+  (2.4ms) CREATE OR REPLACE FUNCTION add (x integer, y integer) RETURNS integer AS $$
647
+ BEGIN
648
+ RETURN x + y;
649
+ END;
650
+ $$ LANGUAGE plpgsql;
651
+  (0.6ms) CREATE OR REPLACE FUNCTION tuple_sort (x int[]) RETURNS int[] AS $$
652
+ BEGIN
653
+ IF x[0]::int > x[1]::int THEN
654
+ RETURN ARRAY[x[1], x[0]];
655
+ ELSE
656
+ RETURN x;
657
+ END IF;
658
+ END;
659
+ $$ LANGUAGE plpgsql;
660
+  (0.3ms) DROP VIEW chats
661
+ PG::UndefinedTable: ERROR: view "chats" does not exist
662
+ : DROP VIEW chats
663
+  (0.2ms) DROP VIEW messages
664
+ PG::UndefinedTable: ERROR: view "messages" does not exist
665
+ : DROP VIEW messages
666
+  (2.3ms) CREATE TABLE "schema_migrations" ("version" character varying NOT NULL) 
667
+  (1.2ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
668
+ ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
669
+ Migrating to CreateTestTables (20160208084226)
670
+  (0.1ms) BEGIN
671
+  (5.8ms) CREATE TABLE "users" ("id" serial primary key, "name" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
672
+  (0.6ms) CREATE INDEX "index_users_on_name" ON "users" ("name")
673
+  (2.2ms) CREATE TABLE "user_messages" ("id" serial primary key, "from_id" integer, "to_id" integer, "content" text, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
674
+  (0.6ms) CREATE INDEX "index_user_messages_on_from_id" ON "user_messages" ("from_id")
675
+  (0.6ms) CREATE INDEX "index_user_messages_on_to_id" ON "user_messages" ("to_id")
676
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160208084226"]]
677
+  (0.5ms) COMMIT
678
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
679
+  (2.0ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
680
+ FROM pg_constraint c
681
+ JOIN pg_class t1 ON c.conrelid = t1.oid
682
+ JOIN pg_class t2 ON c.confrelid = t2.oid
683
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
684
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
685
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
686
+ WHERE c.contype = 'f'
687
+ AND t1.relname = 'user_messages'
688
+ AND t3.nspname = ANY (current_schemas(false))
689
+ ORDER BY c.conname
690
+ 
691
+  (1.5ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
692
+ FROM pg_constraint c
693
+ JOIN pg_class t1 ON c.conrelid = t1.oid
694
+ JOIN pg_class t2 ON c.confrelid = t2.oid
695
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
696
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
697
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
698
+ WHERE c.contype = 'f'
699
+ AND t1.relname = 'users'
700
+ AND t3.nspname = ANY (current_schemas(false))
701
+ ORDER BY c.conname
702
+
703
+  (7.7ms) CREATE VIEW messages AS SELECT DISTINCT _.receiver_name, _.receiver_id, _.sender_name, _.sender_id, _.content, _.updated_at, _.created_at
704
+ FROM
705
+ (SELECT u2.name as receiver_name, u2.id as receiver_id,
706
+ u1.name as sender_name, u1.id as sender_id,
707
+ um.content as content, um.updated_at as updated_at, um.created_at as created_at
708
+ FROM users u1
709
+ INNER JOIN user_messages um ON ( u1.id = um.from_id )
710
+ INNER JOIN users u2 ON (u2.id = um.to_id)
711
+ UNION
712
+ SELECT u1.name as receiver_name, u1.id as receiver_id,
713
+ u2.name as sender_name, u2.id as sender_id,
714
+ um.content as content, um.updated_at as updated_at, um.created_at as created_at
715
+ FROM users u1
716
+ INNER JOIN user_messages um ON ( u1.id = um.to_id )
717
+ INNER JOIN users u2 ON ( u2.id = um.from_id )
718
+ ORDER BY created_at ASC
719
+ ) AS _
720
+  (7.7ms) CREATE VIEW chats AS SELECT tuple_sort(ARRAY[sender_id, receiver_id]) AS ids,
721
+ MIN(created_at) as created_at, MAX(updated_at) as updated_at, COUNT(*) as number_of_messages
722
+ FROM messages
723
+ GROUP BY tuple_sort(ARRAY[sender_id, receiver_id])
724
+  (1.0ms) SELECT tuple_sort(ARRAY[3,1])
725
+  (2.1ms) SELECT tuple_sort(ARRAY[1,3])