arel 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. data/.gitignore +6 -0
  2. data/README.markdown +184 -0
  3. data/Rakefile +60 -0
  4. data/VERSION +1 -0
  5. data/arel.gemspec +233 -0
  6. data/doc/CONVENTIONS +17 -0
  7. data/doc/TODO +118 -0
  8. data/lib/arel.rb +10 -0
  9. data/lib/arel/algebra.rb +4 -0
  10. data/lib/arel/algebra/extensions.rb +4 -0
  11. data/lib/arel/algebra/extensions/class.rb +32 -0
  12. data/lib/arel/algebra/extensions/hash.rb +11 -0
  13. data/lib/arel/algebra/extensions/object.rb +17 -0
  14. data/lib/arel/algebra/extensions/symbol.rb +9 -0
  15. data/lib/arel/algebra/predicates.rb +41 -0
  16. data/lib/arel/algebra/primitives.rb +5 -0
  17. data/lib/arel/algebra/primitives/attribute.rb +150 -0
  18. data/lib/arel/algebra/primitives/expression.rb +43 -0
  19. data/lib/arel/algebra/primitives/ordering.rb +23 -0
  20. data/lib/arel/algebra/primitives/value.rb +14 -0
  21. data/lib/arel/algebra/relations.rb +14 -0
  22. data/lib/arel/algebra/relations/operations/alias.rb +7 -0
  23. data/lib/arel/algebra/relations/operations/group.rb +12 -0
  24. data/lib/arel/algebra/relations/operations/join.rb +64 -0
  25. data/lib/arel/algebra/relations/operations/order.rb +18 -0
  26. data/lib/arel/algebra/relations/operations/project.rb +20 -0
  27. data/lib/arel/algebra/relations/operations/skip.rb +6 -0
  28. data/lib/arel/algebra/relations/operations/take.rb +10 -0
  29. data/lib/arel/algebra/relations/operations/where.rb +16 -0
  30. data/lib/arel/algebra/relations/relation.rb +136 -0
  31. data/lib/arel/algebra/relations/row.rb +26 -0
  32. data/lib/arel/algebra/relations/utilities/compound.rb +30 -0
  33. data/lib/arel/algebra/relations/utilities/externalization.rb +24 -0
  34. data/lib/arel/algebra/relations/utilities/nil.rb +7 -0
  35. data/lib/arel/algebra/relations/writes.rb +36 -0
  36. data/lib/arel/engines.rb +2 -0
  37. data/lib/arel/engines/memory.rb +4 -0
  38. data/lib/arel/engines/memory/engine.rb +16 -0
  39. data/lib/arel/engines/memory/predicates.rb +35 -0
  40. data/lib/arel/engines/memory/primitives.rb +27 -0
  41. data/lib/arel/engines/memory/relations.rb +5 -0
  42. data/lib/arel/engines/memory/relations/array.rb +25 -0
  43. data/lib/arel/engines/memory/relations/compound.rb +9 -0
  44. data/lib/arel/engines/memory/relations/operations.rb +61 -0
  45. data/lib/arel/engines/memory/relations/writes.rb +7 -0
  46. data/lib/arel/engines/sql.rb +7 -0
  47. data/lib/arel/engines/sql/christener.rb +13 -0
  48. data/lib/arel/engines/sql/engine.rb +37 -0
  49. data/lib/arel/engines/sql/extensions.rb +4 -0
  50. data/lib/arel/engines/sql/extensions/array.rb +16 -0
  51. data/lib/arel/engines/sql/extensions/nil_class.rb +11 -0
  52. data/lib/arel/engines/sql/extensions/object.rb +15 -0
  53. data/lib/arel/engines/sql/extensions/range.rb +15 -0
  54. data/lib/arel/engines/sql/formatters.rb +113 -0
  55. data/lib/arel/engines/sql/predicates.rb +51 -0
  56. data/lib/arel/engines/sql/primitives.rb +85 -0
  57. data/lib/arel/engines/sql/relations.rb +9 -0
  58. data/lib/arel/engines/sql/relations/operations/alias.rb +5 -0
  59. data/lib/arel/engines/sql/relations/operations/join.rb +33 -0
  60. data/lib/arel/engines/sql/relations/relation.rb +50 -0
  61. data/lib/arel/engines/sql/relations/table.rb +52 -0
  62. data/lib/arel/engines/sql/relations/utilities/compound.rb +10 -0
  63. data/lib/arel/engines/sql/relations/utilities/externalization.rb +14 -0
  64. data/lib/arel/engines/sql/relations/utilities/nil.rb +6 -0
  65. data/lib/arel/engines/sql/relations/utilities/recursion.rb +13 -0
  66. data/lib/arel/engines/sql/relations/writes.rb +39 -0
  67. data/lib/arel/session.rb +48 -0
  68. data/spec/arel/algebra/unit/predicates/binary_spec.rb +33 -0
  69. data/spec/arel/algebra/unit/predicates/equality_spec.rb +27 -0
  70. data/spec/arel/algebra/unit/predicates/in_spec.rb +10 -0
  71. data/spec/arel/algebra/unit/primitives/attribute_spec.rb +183 -0
  72. data/spec/arel/algebra/unit/primitives/expression_spec.rb +45 -0
  73. data/spec/arel/algebra/unit/primitives/value_spec.rb +15 -0
  74. data/spec/arel/algebra/unit/relations/alias_spec.rb +16 -0
  75. data/spec/arel/algebra/unit/relations/delete_spec.rb +9 -0
  76. data/spec/arel/algebra/unit/relations/group_spec.rb +10 -0
  77. data/spec/arel/algebra/unit/relations/insert_spec.rb +9 -0
  78. data/spec/arel/algebra/unit/relations/join_spec.rb +26 -0
  79. data/spec/arel/algebra/unit/relations/order_spec.rb +21 -0
  80. data/spec/arel/algebra/unit/relations/project_spec.rb +34 -0
  81. data/spec/arel/algebra/unit/relations/relation_spec.rb +188 -0
  82. data/spec/arel/algebra/unit/relations/skip_spec.rb +10 -0
  83. data/spec/arel/algebra/unit/relations/table_spec.rb +39 -0
  84. data/spec/arel/algebra/unit/relations/take_spec.rb +10 -0
  85. data/spec/arel/algebra/unit/relations/update_spec.rb +9 -0
  86. data/spec/arel/algebra/unit/relations/where_spec.rb +18 -0
  87. data/spec/arel/algebra/unit/session/session_spec.rb +84 -0
  88. data/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb +48 -0
  89. data/spec/arel/engines/memory/unit/relations/array_spec.rb +32 -0
  90. data/spec/arel/engines/memory/unit/relations/insert_spec.rb +28 -0
  91. data/spec/arel/engines/memory/unit/relations/join_spec.rb +31 -0
  92. data/spec/arel/engines/memory/unit/relations/order_spec.rb +27 -0
  93. data/spec/arel/engines/memory/unit/relations/project_spec.rb +27 -0
  94. data/spec/arel/engines/memory/unit/relations/skip_spec.rb +26 -0
  95. data/spec/arel/engines/memory/unit/relations/take_spec.rb +26 -0
  96. data/spec/arel/engines/memory/unit/relations/where_spec.rb +39 -0
  97. data/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb +209 -0
  98. data/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb +167 -0
  99. data/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb +107 -0
  100. data/spec/arel/engines/sql/unit/engine_spec.rb +45 -0
  101. data/spec/arel/engines/sql/unit/predicates/binary_spec.rb +117 -0
  102. data/spec/arel/engines/sql/unit/predicates/equality_spec.rb +46 -0
  103. data/spec/arel/engines/sql/unit/predicates/in_spec.rb +86 -0
  104. data/spec/arel/engines/sql/unit/predicates/predicates_spec.rb +65 -0
  105. data/spec/arel/engines/sql/unit/primitives/attribute_spec.rb +32 -0
  106. data/spec/arel/engines/sql/unit/primitives/expression_spec.rb +24 -0
  107. data/spec/arel/engines/sql/unit/primitives/literal_spec.rb +23 -0
  108. data/spec/arel/engines/sql/unit/primitives/value_spec.rb +29 -0
  109. data/spec/arel/engines/sql/unit/relations/alias_spec.rb +43 -0
  110. data/spec/arel/engines/sql/unit/relations/delete_spec.rb +63 -0
  111. data/spec/arel/engines/sql/unit/relations/group_spec.rb +56 -0
  112. data/spec/arel/engines/sql/unit/relations/insert_spec.rb +107 -0
  113. data/spec/arel/engines/sql/unit/relations/join_spec.rb +57 -0
  114. data/spec/arel/engines/sql/unit/relations/order_spec.rb +113 -0
  115. data/spec/arel/engines/sql/unit/relations/project_spec.rb +110 -0
  116. data/spec/arel/engines/sql/unit/relations/skip_spec.rb +32 -0
  117. data/spec/arel/engines/sql/unit/relations/table_spec.rb +69 -0
  118. data/spec/arel/engines/sql/unit/relations/take_spec.rb +32 -0
  119. data/spec/arel/engines/sql/unit/relations/update_spec.rb +151 -0
  120. data/spec/arel/engines/sql/unit/relations/where_spec.rb +56 -0
  121. data/spec/connections/mysql_connection.rb +16 -0
  122. data/spec/connections/postgresql_connection.rb +15 -0
  123. data/spec/connections/sqlite3_connection.rb +25 -0
  124. data/spec/doubles/hash.rb +23 -0
  125. data/spec/matchers/be_like.rb +24 -0
  126. data/spec/matchers/disambiguate_attributes.rb +28 -0
  127. data/spec/matchers/hash_the_same_as.rb +26 -0
  128. data/spec/schemas/mysql_schema.rb +18 -0
  129. data/spec/schemas/postgresql_schema.rb +18 -0
  130. data/spec/schemas/sqlite3_schema.rb +18 -0
  131. data/spec/spec_helper.rb +47 -0
  132. metadata +250 -0
@@ -0,0 +1,110 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Project do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ @attribute = @relation[:id]
8
+ end
9
+
10
+ describe '#to_sql' do
11
+ describe 'when given an attribute' do
12
+ it "manufactures sql with a limited select clause" do
13
+ sql = Project.new(@relation, @attribute).to_sql
14
+
15
+ adapter_is :mysql do
16
+ sql.should be_like(%Q{
17
+ SELECT `users`.`id`
18
+ FROM `users`
19
+ })
20
+ end
21
+
22
+ adapter_is_not :mysql do
23
+ sql.should be_like(%Q{
24
+ SELECT "users"."id"
25
+ FROM "users"
26
+ })
27
+ end
28
+ end
29
+ end
30
+
31
+ describe 'when given a relation' do
32
+ before do
33
+ @scalar_relation = Project.new(@relation, @relation[:name])
34
+ end
35
+
36
+ it "manufactures sql with scalar selects" do
37
+ sql = Project.new(@relation, @scalar_relation).to_sql
38
+
39
+ adapter_is :mysql do
40
+ sql.should be_like(%Q{
41
+ SELECT (SELECT `users`.`name` FROM `users`) AS `users` FROM `users`
42
+ })
43
+ end
44
+
45
+ adapter_is_not :mysql do
46
+ sql.should be_like(%Q{
47
+ SELECT (SELECT "users"."name" FROM "users") AS "users" FROM "users"
48
+ })
49
+ end
50
+ end
51
+ end
52
+
53
+ describe 'when given a string' do
54
+ it "passes the string through to the select clause" do
55
+ sql = Project.new(@relation, 'asdf').to_sql
56
+
57
+ adapter_is :mysql do
58
+ sql.should be_like(%Q{
59
+ SELECT asdf FROM `users`
60
+ })
61
+ end
62
+
63
+ adapter_is_not :mysql do
64
+ sql.should be_like(%Q{
65
+ SELECT asdf FROM "users"
66
+ })
67
+ end
68
+ end
69
+ end
70
+
71
+ describe 'when given an expression' do
72
+ it 'manufactures sql with expressions' do
73
+ sql = @relation.project(@attribute.count).to_sql
74
+
75
+ adapter_is :mysql do
76
+ sql.should be_like(%Q{
77
+ SELECT COUNT(`users`.`id`) AS count_id
78
+ FROM `users`
79
+ })
80
+ end
81
+
82
+ adapter_is_not :mysql do
83
+ sql.should be_like(%Q{
84
+ SELECT COUNT("users"."id") AS count_id
85
+ FROM "users"
86
+ })
87
+ end
88
+ end
89
+
90
+ it 'manufactures sql with distinct expressions' do
91
+ sql = @relation.project(@attribute.count(true)).to_sql
92
+
93
+ adapter_is :mysql do
94
+ sql.should be_like(%Q{
95
+ SELECT COUNT(DISTINCT `users`.`id`) AS count_id
96
+ FROM `users`
97
+ })
98
+ end
99
+
100
+ adapter_is_not :mysql do
101
+ sql.should be_like(%Q{
102
+ SELECT COUNT(DISTINCT "users"."id") AS count_id
103
+ FROM "users"
104
+ })
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,32 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Skip do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ @skipped = 4
8
+ end
9
+
10
+ describe '#to_sql' do
11
+ it "manufactures sql with limit and offset" do
12
+ sql = Skip.new(@relation, @skipped).to_sql
13
+
14
+ adapter_is :mysql do
15
+ sql.should be_like(%Q{
16
+ SELECT `users`.`id`, `users`.`name`
17
+ FROM `users`
18
+ OFFSET 4
19
+ })
20
+ end
21
+
22
+ adapter_is_not :mysql do
23
+ sql.should be_like(%Q{
24
+ SELECT "users"."id", "users"."name"
25
+ FROM "users"
26
+ OFFSET 4
27
+ })
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,69 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Table do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ end
8
+
9
+ describe '#to_sql' do
10
+ it "manufactures a simple select query" do
11
+ sql = @relation.to_sql
12
+
13
+ adapter_is :mysql do
14
+ sql.should be_like(%Q{
15
+ SELECT `users`.`id`, `users`.`name`
16
+ FROM `users`
17
+ })
18
+ end
19
+
20
+ adapter_is_not :mysql do
21
+ sql.should be_like(%Q{
22
+ SELECT "users"."id", "users"."name"
23
+ FROM "users"
24
+ })
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '#column_for' do
30
+ it "returns the column corresponding to the attribute" do
31
+ @relation.column_for(@relation[:id]).should == @relation.columns.detect { |c| c.name == 'id' }
32
+ end
33
+ end
34
+
35
+ describe '#attributes' do
36
+ it 'manufactures attributes corresponding to columns in the table' do
37
+ @relation.attributes.should == [
38
+ Attribute.new(@relation, :id),
39
+ Attribute.new(@relation, :name)
40
+ ]
41
+ end
42
+
43
+ describe '#reset' do
44
+ it "reloads columns from the database" do
45
+ lambda { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes }
46
+ lambda { @relation.reset }.should change { @relation.attributes }
47
+ end
48
+ end
49
+ end
50
+
51
+ describe 'hashing' do
52
+ it "implements hash equality" do
53
+ Table.new(:users).should hash_the_same_as(Table.new(:users))
54
+ Table.new(:users).should_not hash_the_same_as(Table.new(:photos))
55
+ end
56
+ end
57
+
58
+ describe '#engine' do
59
+ it "defaults to global engine" do
60
+ Table.engine = engine = Sql::Engine.new
61
+ Table.new(:users).engine.should == engine
62
+ end
63
+
64
+ it "can be specified" do
65
+ Table.new(:users, engine = Sql::Engine.new).engine.should == engine
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,32 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Take do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ @taken = 4
8
+ end
9
+
10
+ describe '#to_sql' do
11
+ it "manufactures sql with limit and offset" do
12
+ sql = Take.new(@relation, @taken).to_sql
13
+
14
+ adapter_is :mysql do
15
+ sql.should be_like(%Q{
16
+ SELECT `users`.`id`, `users`.`name`
17
+ FROM `users`
18
+ LIMIT 4
19
+ })
20
+ end
21
+
22
+ adapter_is_not :mysql do
23
+ sql.should be_like(%Q{
24
+ SELECT "users"."id", "users"."name"
25
+ FROM "users"
26
+ LIMIT 4
27
+ })
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,151 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Update do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ end
8
+
9
+ describe '#to_sql' do
10
+ it "manufactures sql updating attributes when given multiple attributes" do
11
+ sql = Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql
12
+
13
+ adapter_is :mysql do
14
+ sql.should be_like(%Q{
15
+ UPDATE `users`
16
+ SET `id` = 1, `name` = 'nick'
17
+ })
18
+ end
19
+
20
+ adapter_is :sqlite3 do
21
+ sql.should be_like(%Q{
22
+ UPDATE "users"
23
+ SET "id" = 1, "name" = 'nick'
24
+ })
25
+ end
26
+
27
+ adapter_is :postgresql do
28
+ sql.should be_like(%Q{
29
+ UPDATE "users"
30
+ SET "id" = 1, "name" = E'nick'
31
+ })
32
+ end
33
+ end
34
+
35
+ it "manufactures sql updating attributes when given a ranged relation" do
36
+ sql = Update.new(@relation.take(1), @relation[:name] => "nick").to_sql
37
+
38
+ adapter_is :mysql do
39
+ sql.should be_like(%Q{
40
+ UPDATE `users`
41
+ SET `name` = 'nick'
42
+ LIMIT 1
43
+ })
44
+ end
45
+
46
+ adapter_is :sqlite3 do
47
+ sql.should be_like(%Q{
48
+ UPDATE "users"
49
+ SET "name" = 'nick'
50
+ LIMIT 1
51
+ })
52
+ end
53
+
54
+ adapter_is :postgresql do
55
+ sql.should be_like(%Q{
56
+ UPDATE "users"
57
+ SET "name" = E'nick'
58
+ LIMIT 1
59
+ })
60
+ end
61
+ end
62
+
63
+ describe 'when given values whose types correspond to the types of the attributes' do
64
+ before do
65
+ @update = Update.new(@relation, @relation[:name] => "nick")
66
+ end
67
+
68
+ it 'manufactures sql updating attributes' do
69
+ adapter_is :mysql do
70
+ @update.to_sql.should be_like(%Q{
71
+ UPDATE `users`
72
+ SET `name` = 'nick'
73
+ })
74
+ end
75
+
76
+ adapter_is :sqlite3 do
77
+ @update.to_sql.should be_like(%Q{
78
+ UPDATE "users"
79
+ SET "name" = 'nick'
80
+ })
81
+ end
82
+
83
+ adapter_is :postgresql do
84
+ @update.to_sql.should be_like(%Q{
85
+ UPDATE "users"
86
+ SET "name" = E'nick'
87
+ })
88
+ end
89
+ end
90
+ end
91
+
92
+ describe 'when given values whose types differ from from the types of the attributes' do
93
+ before do
94
+ @update = Update.new(@relation, @relation[:id] => '1-asdf')
95
+ end
96
+
97
+ it 'manufactures sql updating attributes' do
98
+ adapter_is :mysql do
99
+ @update.to_sql.should be_like(%Q{
100
+ UPDATE `users`
101
+ SET `id` = 1
102
+ })
103
+ end
104
+
105
+ adapter_is_not :mysql do
106
+ @update.to_sql.should be_like(%Q{
107
+ UPDATE "users"
108
+ SET "id" = 1
109
+ })
110
+ end
111
+ end
112
+ end
113
+
114
+ describe 'when the relation is a where' do
115
+ before do
116
+ @update = Update.new(
117
+ @relation.where(@relation[:id].eq(1)),
118
+ @relation[:name] => "nick"
119
+ )
120
+ end
121
+
122
+ it 'manufactures sql updating a where relation' do
123
+ adapter_is :mysql do
124
+ @update.to_sql.should be_like(%Q{
125
+ UPDATE `users`
126
+ SET `name` = 'nick'
127
+ WHERE `users`.`id` = 1
128
+ })
129
+ end
130
+
131
+ adapter_is :sqlite3 do
132
+ @update.to_sql.should be_like(%Q{
133
+ UPDATE "users"
134
+ SET "name" = 'nick'
135
+ WHERE "users"."id" = 1
136
+ })
137
+ end
138
+
139
+ adapter_is :postgresql do
140
+ @update.to_sql.should be_like(%Q{
141
+ UPDATE "users"
142
+ SET "name" = E'nick'
143
+ WHERE "users"."id" = 1
144
+ })
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ end
151
+ end
@@ -0,0 +1,56 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Where do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ @predicate = @relation[:id].eq(1)
8
+ end
9
+
10
+ describe '#to_sql' do
11
+ describe 'when given a predicate' do
12
+ it "manufactures sql with where clause conditions" do
13
+ sql = Where.new(@relation, @predicate).to_sql
14
+
15
+ adapter_is :mysql do
16
+ sql.should be_like(%Q{
17
+ SELECT `users`.`id`, `users`.`name`
18
+ FROM `users`
19
+ WHERE `users`.`id` = 1
20
+ })
21
+ end
22
+
23
+ adapter_is_not :mysql do
24
+ sql.should be_like(%Q{
25
+ SELECT "users"."id", "users"."name"
26
+ FROM "users"
27
+ WHERE "users"."id" = 1
28
+ })
29
+ end
30
+ end
31
+ end
32
+
33
+ describe 'when given a string' do
34
+ it "passes the string through to the where clause" do
35
+ sql = Where.new(@relation, 'asdf').to_sql
36
+
37
+ adapter_is :mysql do
38
+ sql.should be_like(%Q{
39
+ SELECT `users`.`id`, `users`.`name`
40
+ FROM `users`
41
+ WHERE asdf
42
+ })
43
+ end
44
+
45
+ adapter_is_not :mysql do
46
+ sql.should be_like(%Q{
47
+ SELECT "users"."id", "users"."name"
48
+ FROM "users"
49
+ WHERE asdf
50
+ })
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end