arel 0.1.0

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.
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