oedipus 0.0.1.pre1 → 0.0.1.pre2

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 (48) hide show
  1. data/.gitignore +2 -0
  2. data/README.md +235 -44
  3. data/Rakefile +25 -0
  4. data/ext/oedipus/extconf.rb +72 -0
  5. data/ext/oedipus/oedipus.c +239 -0
  6. data/ext/oedipus/oedipus.h +50 -0
  7. data/lib/oedipus/comparison/between.rb +26 -0
  8. data/lib/oedipus/comparison/equal.rb +21 -0
  9. data/lib/oedipus/comparison/gt.rb +21 -0
  10. data/lib/oedipus/comparison/gte.rb +21 -0
  11. data/lib/oedipus/comparison/in.rb +21 -0
  12. data/lib/oedipus/comparison/lt.rb +21 -0
  13. data/lib/oedipus/comparison/lte.rb +21 -0
  14. data/lib/oedipus/comparison/not.rb +25 -0
  15. data/lib/oedipus/comparison/not_equal.rb +21 -0
  16. data/lib/oedipus/comparison/not_in.rb +21 -0
  17. data/lib/oedipus/comparison/outside.rb +26 -0
  18. data/lib/oedipus/comparison/shortcuts.rb +144 -0
  19. data/lib/oedipus/comparison.rb +88 -0
  20. data/lib/oedipus/connection.rb +91 -13
  21. data/lib/oedipus/connection_error.rb +14 -0
  22. data/lib/oedipus/index.rb +189 -46
  23. data/lib/oedipus/query_builder.rb +97 -4
  24. data/lib/oedipus/version.rb +1 -1
  25. data/lib/oedipus.rb +24 -7
  26. data/oedipus.gemspec +4 -5
  27. data/spec/integration/connection_spec.rb +58 -0
  28. data/spec/integration/index_spec.rb +353 -0
  29. data/spec/spec_helper.rb +2 -23
  30. data/spec/support/test_harness.rb +30 -9
  31. data/spec/unit/comparison/between_spec.rb +36 -0
  32. data/spec/unit/comparison/equal_spec.rb +22 -0
  33. data/spec/unit/comparison/gt_spec.rb +22 -0
  34. data/spec/unit/comparison/gte_spec.rb +22 -0
  35. data/spec/unit/comparison/in_spec.rb +22 -0
  36. data/spec/unit/comparison/lt_spec.rb +22 -0
  37. data/spec/unit/comparison/lte_spec.rb +22 -0
  38. data/spec/unit/comparison/not_equal_spec.rb +22 -0
  39. data/spec/unit/comparison/not_in_spec.rb +22 -0
  40. data/spec/unit/comparison/not_spec.rb +37 -0
  41. data/spec/unit/comparison/outside_spec.rb +36 -0
  42. data/spec/unit/comparison/shortcuts_spec.rb +125 -0
  43. data/spec/unit/comparison_spec.rb +109 -0
  44. data/spec/unit/query_builder_spec.rb +150 -0
  45. metadata +68 -19
  46. data/lib/oedipus/mysql/client.rb +0 -136
  47. data/spec/unit/connection_spec.rb +0 -36
  48. data/spec/unit/index_spec.rb +0 -85
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Oedipus Sphinx 2 Search.
5
+ # Copyright © 2012 Chris Corbyn.
6
+ #
7
+ # See LICENSE file for details.
8
+ ##
9
+
10
+ require "spec_helper"
11
+
12
+ describe Oedipus::Comparison::Outside do
13
+ context "with an inclusive range" do
14
+ let(:comparison) { Oedipus::Comparison::Outside.new(42..100) }
15
+
16
+ it "draws as NOT BETWEEN x AND y" do
17
+ comparison.to_s.should == "NOT BETWEEN 42 AND 100"
18
+ end
19
+
20
+ it "inverses as BETWEEN x AND y" do
21
+ comparison.inverse.to_s.should == "BETWEEN 42 AND 100"
22
+ end
23
+ end
24
+
25
+ context "with an exclusive range" do
26
+ let(:comparison) { Oedipus::Comparison::Outside.new(42...100) }
27
+
28
+ it "draws as NOT BETWEEN x AND y-1" do
29
+ comparison.to_s.should == "NOT BETWEEN 42 AND 99"
30
+ end
31
+
32
+ it "inverses as BETWEEN x AND y-1" do
33
+ comparison.inverse.to_s.should == "BETWEEN 42 AND 99"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,125 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Oedipus Sphinx 2 Search.
5
+ # Copyright © 2012 Chris Corbyn.
6
+ #
7
+ # See LICENSE file for details.
8
+ ##
9
+
10
+ require "spec_helper"
11
+
12
+ describe Oedipus::Comparison::Shortcuts do
13
+ let(:s) { Object.new.tap { |o| o.extend subject } }
14
+
15
+ describe "#eq" do
16
+ it "returns the = comparison for v" do
17
+ s.eq(7).should == Oedipus::Comparison::Equal.new(7)
18
+ end
19
+ end
20
+
21
+ describe "#neq" do
22
+ it "returns the != comparison for v" do
23
+ s.neq(7).should == Oedipus::Comparison::NotEqual.new(7)
24
+ end
25
+ end
26
+
27
+
28
+ describe "#not" do
29
+ it "returns the NOT comparison for v" do
30
+ s.not(7).should == Oedipus::Comparison::Not.new(7)
31
+ end
32
+ end
33
+
34
+ describe "#gt" do
35
+ it "returns the > comparison for v" do
36
+ s.gt(7).should == Oedipus::Comparison::GT.new(7)
37
+ end
38
+ end
39
+
40
+ describe "#lt" do
41
+ it "returns the < comparison for v" do
42
+ s.lt(7).should == Oedipus::Comparison::LT.new(7)
43
+ end
44
+ end
45
+
46
+ describe "#gte" do
47
+ it "returns the >= comparison for v" do
48
+ s.gte(7).should == Oedipus::Comparison::GTE.new(7)
49
+ end
50
+ end
51
+
52
+ describe "#lte" do
53
+ it "returns the <= comparison for v" do
54
+ s.lte(7).should == Oedipus::Comparison::LTE.new(7)
55
+ end
56
+ end
57
+
58
+ describe "#between" do
59
+ context "with a range" do
60
+ it "returns the BETWEEN comparison for v" do
61
+ s.between(7..11).should == Oedipus::Comparison::Between.new(7..11)
62
+ end
63
+ end
64
+
65
+ context "with two bounds" do
66
+ it "returns the BETWEEN comparison for x and y" do
67
+ s.between(7, 11).should == Oedipus::Comparison::Between.new(7..11)
68
+ end
69
+ end
70
+ end
71
+
72
+ describe "#outside" do
73
+ context "with a range" do
74
+ it "returns the NOT BETWEEN comparison for v" do
75
+ s.outside(7..11).should == Oedipus::Comparison::Outside.new(7..11)
76
+ end
77
+ end
78
+
79
+ context "with two bounds" do
80
+ it "returns the NOT BETWEEN comparison for x and y" do
81
+ s.outside(7, 11).should == Oedipus::Comparison::Outside.new(7..11)
82
+ end
83
+ end
84
+ end
85
+
86
+ describe "#in" do
87
+ context "with an array" do
88
+ it "returns the IN comparison for v" do
89
+ s.in([1, 2, 3]).should == Oedipus::Comparison::In.new([1, 2, 3])
90
+ end
91
+ end
92
+
93
+ context "with a range" do
94
+ it "returns the IN comparison for v" do
95
+ s.in(1..3).should == Oedipus::Comparison::In.new([1, 2, 3])
96
+ end
97
+ end
98
+
99
+ context "with a variable arguments" do
100
+ it "returns the IN comparison for x, y, z" do
101
+ s.in(1, 2, 3).should == Oedipus::Comparison::In.new([1, 2, 3])
102
+ end
103
+ end
104
+ end
105
+
106
+ describe "#not_in" do
107
+ context "with an array" do
108
+ it "returns the NOT IN comparison for v" do
109
+ s.not_in([1, 2, 3]).should == Oedipus::Comparison::NotIn.new([1, 2, 3])
110
+ end
111
+ end
112
+
113
+ context "with a range" do
114
+ it "returns the NOT IN comparison for v" do
115
+ s.not_in(1..3).should == Oedipus::Comparison::NotIn.new([1, 2, 3])
116
+ end
117
+ end
118
+
119
+ context "with a variable arguments" do
120
+ it "returns the NOT IN comparison for x, y, z" do
121
+ s.not_in(1, 2, 3).should == Oedipus::Comparison::NotIn.new([1, 2, 3])
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,109 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Oedipus Sphinx 2 Search.
5
+ # Copyright © 2012 Chris Corbyn.
6
+ #
7
+ # See LICENSE file for details.
8
+ ##
9
+
10
+ require "spec_helper"
11
+
12
+ describe Oedipus::Comparison do
13
+ subject { Oedipus::Comparison }
14
+
15
+ describe "#of" do
16
+ context "with a comparison" do
17
+ it "returns the comparison" do
18
+ subject.of(
19
+ Oedipus::Comparison::Equal.new(7)
20
+ ).should == Oedipus::Comparison::Equal.new(7)
21
+ end
22
+ end
23
+
24
+ context "with a Fixnum" do
25
+ it "returns an Equal comparison" do
26
+ subject.of(7).should == Oedipus::Comparison::Equal.new(7)
27
+ end
28
+ end
29
+
30
+ context "with a Float" do
31
+ it "returns an Equal comparison" do
32
+ subject.of(7.2).should == Oedipus::Comparison::Equal.new(7.2)
33
+ end
34
+ end
35
+
36
+ context "with a BigDecimal" do
37
+ it "returns an Equal comparison" do
38
+ subject.of(BigDecimal("7.2")).should == Oedipus::Comparison::Equal.new(7.2)
39
+ end
40
+ end
41
+
42
+ context "with a Rational" do
43
+ it "returns an Equal comparison" do
44
+ subject.of(Rational("1/3")).should == Oedipus::Comparison::Equal.new(Rational("1/3").to_f)
45
+ end
46
+ end
47
+
48
+ context "with a String" do
49
+ it "returns an Equal comparison" do
50
+ subject.of("test").should == Oedipus::Comparison::Equal.new("test")
51
+ end
52
+ end
53
+
54
+ context "with a Symbol" do
55
+ it "returns an Equal comparison" do
56
+ subject.of(:test).should == Oedipus::Comparison::Equal.new(:test)
57
+ end
58
+ end
59
+
60
+ context "with a range" do
61
+ context "starting at -Infinity" do
62
+ context "inclusive" do
63
+ it "returns a LTE comparison" do
64
+ subject.of(-Float::INFINITY..10).should == Oedipus::Comparison::LTE.new(10)
65
+ end
66
+ end
67
+
68
+ context "exclusive" do
69
+ it "returns a LT comparison" do
70
+ subject.of(-Float::INFINITY...10).should == Oedipus::Comparison::LT.new(10)
71
+ end
72
+ end
73
+ end
74
+
75
+ context "ending at -Infinity" do
76
+ context "inclusive" do
77
+ it "returns a GTE comparison" do
78
+ subject.of(10..Float::INFINITY).should == Oedipus::Comparison::GTE.new(10)
79
+ end
80
+ end
81
+
82
+ context "exclusive" do
83
+ it "returns a GT comparison" do
84
+ subject.of(10...Float::INFINITY).should == Oedipus::Comparison::GT.new(10)
85
+ end
86
+ end
87
+ end
88
+
89
+ context "of real numbers" do
90
+ it "returns a BETWEEN comparison" do
91
+ subject.of(10..20).should == Oedipus::Comparison::Between.new(10..20)
92
+ end
93
+ end
94
+ end
95
+
96
+ context "with an array" do
97
+ it "returns an IN comparison" do
98
+ subject.of([1, 2, 3]).should == Oedipus::Comparison::In.new([1, 2, 3])
99
+ end
100
+ end
101
+
102
+ context "with an Enumerable type" do
103
+ it "returns an IN comparison" do
104
+ require 'set'
105
+ subject.of(Set[1, 2, 3]).should == Oedipus::Comparison::In.new([1, 2, 3])
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,150 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # Oedipus Sphinx 2 Search.
5
+ # Copyright © 2012 Chris Corbyn.
6
+ #
7
+ # See LICENSE file for details.
8
+ ##
9
+
10
+ require "spec_helper"
11
+
12
+ describe Oedipus::QueryBuilder do
13
+ let(:builder) { Oedipus::QueryBuilder.new(:posts) }
14
+
15
+ describe "#select" do
16
+ context "with a fulltext search" do
17
+ it "uses MATCH()" do
18
+ builder.select("dogs AND cats", {}).should =~ /SELECT .* FROM posts WHERE MATCH\('dogs AND cats'\)/
19
+ end
20
+ end
21
+
22
+ context "without conditions" do
23
+ it "does not add a where clause" do
24
+ builder.select("", {}).should_not =~ /WHERE/
25
+ end
26
+ end
27
+
28
+ context "with equal attribute filters" do
29
+ it "uses the '=' operator" do
30
+ builder.select("dogs", author_id: 7).should =~ /SELECT .* FROM posts WHERE .* author_id = 7/
31
+ end
32
+ end
33
+
34
+ context "with not equal attribute filters" do
35
+ it "uses the '!=' operator" do
36
+ builder.select("dogs", author_id: Oedipus.not(7)).should =~ /SELECT .* FROM posts WHERE .* author_id != 7/
37
+ end
38
+ end
39
+
40
+ context "with inclusive range-filtered attribute filters" do
41
+ it "uses the BETWEEN operator" do
42
+ builder.select("cats", views: 10..20).should =~ /SELECT .* FROM posts WHERE .* views BETWEEN 10 AND 20/
43
+ end
44
+ end
45
+
46
+ context "with exclusive range-filtered attribute filters" do
47
+ it "uses the BETWEEN operator" do
48
+ builder.select("cats", views: 10...20).should =~ /SELECT .* FROM posts WHERE .* views BETWEEN 10 AND 19/
49
+ end
50
+ end
51
+
52
+ context "with a greater than or equal comparison" do
53
+ it "uses the >= operator" do
54
+ builder.select("cats", views: 50..(1/0.0)).should =~ /SELECT .* FROM posts WHERE .* views >= 50/
55
+ end
56
+ end
57
+
58
+ context "with a greater than comparison" do
59
+ it "uses the > operator" do
60
+ builder.select("cats", views: 50...(1/0.0)).should =~ /SELECT .* FROM posts WHERE .* views > 50/
61
+ end
62
+ end
63
+
64
+ context "with a less than or equal comparison" do
65
+ it "uses the <= operator" do
66
+ builder.select("cats", views: -(1/0.0)..50).should =~ /SELECT .* FROM posts WHERE .* views <= 50/
67
+ end
68
+ end
69
+
70
+ context "with a less than comparison" do
71
+ it "uses the < operator" do
72
+ builder.select("cats", views: -(1/0.0)...50).should =~ /SELECT .* FROM posts WHERE .* views < 50/
73
+ end
74
+ end
75
+
76
+ context "with a negated range comparison" do
77
+ it "uses the NOT BETWEEN operator" do
78
+ builder.select("cats", views: Oedipus.not(50..100)).should =~ /SELECT .* FROM posts WHERE .* views NOT BETWEEN 50 AND 100/
79
+ end
80
+ end
81
+
82
+ context "with an attributed filtered by collection" do
83
+ it "uses the IN operator" do
84
+ builder.select("cats", author_id: [7, 11]).should =~ /SELECT .* FROM posts WHERE .* author_id IN \(7, 11\)/
85
+ end
86
+ end
87
+
88
+ context "with an attributed filtered by negated collection" do
89
+ it "uses the NOT IN operator" do
90
+ builder.select("cats", author_id: Oedipus.not([7, 11])).should =~ /SELECT .* FROM posts WHERE .* author_id NOT IN \(7, 11\)/
91
+ end
92
+ end
93
+
94
+ context "with a limit" do
95
+ it "applies a LIMIT with an offset of 0" do
96
+ builder.select("dogs", limit: 50).should =~ /SELECT .* FROM posts WHERE .* LIMIT 0, 50/
97
+ end
98
+
99
+ it "is not considered an attribute" do
100
+ builder.select("dogs", limit: 50).should_not =~ /limit = 50/
101
+ end
102
+ end
103
+
104
+ context "with an offset" do
105
+ it "applies a LIMIT with an offset" do
106
+ builder.select("dogs", limit: 50, offset: 200).should =~ /SELECT .* FROM posts WHERE .* LIMIT 200, 50/
107
+ end
108
+
109
+ it "is not considered an attribute" do
110
+ builder.select("dogs", limit: 50, offset: 200).should_not =~ /offset = 200/
111
+ end
112
+ end
113
+
114
+ context "with an order clause" do
115
+ it "applies an ORDER BY" do
116
+ builder.select("cats", order: {views: :desc}).should =~ /SELECT .* FROM posts WHERE .* ORDER BY views DESC/
117
+ end
118
+
119
+ it "defaults to ASC" do
120
+ builder.select("cats", order: :views).should =~ /SELECT .* FROM posts WHERE .* ORDER BY views ASC/
121
+ end
122
+
123
+ it "supports multiple orders" do
124
+ builder.select("cats", order: {views: :asc, author_id: :desc}).should =~ /SELECT .* FROM posts WHERE .* ORDER BY views ASC, author_id DESC/
125
+ end
126
+ end
127
+ end
128
+
129
+ describe "#insert" do
130
+ it "includes the ID and the attributes" do
131
+ builder.insert(3, title: "example", views: 9).should == "INSERT INTO posts (id, title, views) VALUES (3, 'example', 9)"
132
+ end
133
+ end
134
+
135
+ describe "#update" do
136
+ it "includes the ID in the WHERE clause" do
137
+ builder.update(3, title: "example", views: 9).should =~ /UPDATE posts SET .* WHERE id = 3/
138
+ end
139
+
140
+ it "includes the changed attributes" do
141
+ builder.update(3, title: "example", views: 9).should =~ /UPDATE posts SET title = 'example', views = 9/
142
+ end
143
+ end
144
+
145
+ describe "#replace" do
146
+ it "includes the ID and the attributes" do
147
+ builder.replace(3, title: "example", views: 9).should == "REPLACE INTO posts (id, title, views) VALUES (3, 'example', 9)"
148
+ end
149
+ end
150
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oedipus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.pre1
4
+ version: 0.0.1.pre2
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-30 00:00:00.000000000 Z
12
+ date: 2012-04-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: ruby-mysql
16
- requirement: &20332040 !ruby/object:Gem::Requirement
15
+ name: rspec
16
+ requirement: &22480320 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
21
  version: '0'
22
- type: :runtime
22
+ type: :development
23
23
  prerelease: false
24
- version_requirements: *20332040
24
+ version_requirements: *22480320
25
25
  - !ruby/object:Gem::Dependency
26
- name: rspec
27
- requirement: &20331620 !ruby/object:Gem::Requirement
26
+ name: rake-compiler
27
+ requirement: &22479900 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,16 +32,16 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *20331620
36
- description: ! "Oedipus brings full support for Sphinx 2 to Ruby:\n\n * real-time
37
- indexes\n * faceted search\n * multi-queries\n * full attribute support\n
38
- \ * optional model-style interaction\n\n It works with 'stable' versions
39
- of Sphinx 2 (>= 2.0.2). All\n features are implemented entirely through the SphinxQL
40
- interface."
35
+ version_requirements: *22479900
36
+ description: ! "Oedipus brings full support for Sphinx 2 to Ruby:\n\n * real-time
37
+ indexes\n * faceted search\n * multi-queries\n * full attribute support\n *
38
+ optional model-style interaction\n\nIt works with 'stable' versions of Sphinx 2
39
+ (>= 2.0.2). All\nfeatures are implemented entirely through the SphinxQL interface.\n"
41
40
  email:
42
41
  - chris@w3style.co.uk
43
42
  executables: []
44
- extensions: []
43
+ extensions:
44
+ - ext/oedipus/extconf.rb
45
45
  extra_rdoc_files: []
46
46
  files:
47
47
  - .gitignore
@@ -50,18 +50,48 @@ files:
50
50
  - LICENSE
51
51
  - README.md
52
52
  - Rakefile
53
+ - ext/oedipus/extconf.rb
54
+ - ext/oedipus/oedipus.c
55
+ - ext/oedipus/oedipus.h
53
56
  - lib/oedipus.rb
57
+ - lib/oedipus/comparison.rb
58
+ - lib/oedipus/comparison/between.rb
59
+ - lib/oedipus/comparison/equal.rb
60
+ - lib/oedipus/comparison/gt.rb
61
+ - lib/oedipus/comparison/gte.rb
62
+ - lib/oedipus/comparison/in.rb
63
+ - lib/oedipus/comparison/lt.rb
64
+ - lib/oedipus/comparison/lte.rb
65
+ - lib/oedipus/comparison/not.rb
66
+ - lib/oedipus/comparison/not_equal.rb
67
+ - lib/oedipus/comparison/not_in.rb
68
+ - lib/oedipus/comparison/outside.rb
69
+ - lib/oedipus/comparison/shortcuts.rb
54
70
  - lib/oedipus/connection.rb
71
+ - lib/oedipus/connection_error.rb
55
72
  - lib/oedipus/index.rb
56
- - lib/oedipus/mysql/client.rb
57
73
  - lib/oedipus/query_builder.rb
58
74
  - lib/oedipus/version.rb
59
75
  - oedipus.gemspec
60
76
  - spec/data/.gitkeep
77
+ - spec/integration/connection_spec.rb
78
+ - spec/integration/index_spec.rb
61
79
  - spec/spec_helper.rb
62
80
  - spec/support/test_harness.rb
63
- - spec/unit/connection_spec.rb
64
- - spec/unit/index_spec.rb
81
+ - spec/unit/comparison/between_spec.rb
82
+ - spec/unit/comparison/equal_spec.rb
83
+ - spec/unit/comparison/gt_spec.rb
84
+ - spec/unit/comparison/gte_spec.rb
85
+ - spec/unit/comparison/in_spec.rb
86
+ - spec/unit/comparison/lt_spec.rb
87
+ - spec/unit/comparison/lte_spec.rb
88
+ - spec/unit/comparison/not_equal_spec.rb
89
+ - spec/unit/comparison/not_in_spec.rb
90
+ - spec/unit/comparison/not_spec.rb
91
+ - spec/unit/comparison/outside_spec.rb
92
+ - spec/unit/comparison/shortcuts_spec.rb
93
+ - spec/unit/comparison_spec.rb
94
+ - spec/unit/query_builder_spec.rb
65
95
  homepage: https://github.com/d11wtq/oedipus
66
96
  licenses: []
67
97
  post_install_message:
@@ -86,4 +116,23 @@ rubygems_version: 1.8.11
86
116
  signing_key:
87
117
  specification_version: 3
88
118
  summary: Sphinx 2 Search Client for Ruby
89
- test_files: []
119
+ test_files:
120
+ - spec/data/.gitkeep
121
+ - spec/integration/connection_spec.rb
122
+ - spec/integration/index_spec.rb
123
+ - spec/spec_helper.rb
124
+ - spec/support/test_harness.rb
125
+ - spec/unit/comparison/between_spec.rb
126
+ - spec/unit/comparison/equal_spec.rb
127
+ - spec/unit/comparison/gt_spec.rb
128
+ - spec/unit/comparison/gte_spec.rb
129
+ - spec/unit/comparison/in_spec.rb
130
+ - spec/unit/comparison/lt_spec.rb
131
+ - spec/unit/comparison/lte_spec.rb
132
+ - spec/unit/comparison/not_equal_spec.rb
133
+ - spec/unit/comparison/not_in_spec.rb
134
+ - spec/unit/comparison/not_spec.rb
135
+ - spec/unit/comparison/outside_spec.rb
136
+ - spec/unit/comparison/shortcuts_spec.rb
137
+ - spec/unit/comparison_spec.rb
138
+ - spec/unit/query_builder_spec.rb
@@ -1,136 +0,0 @@
1
- # encoding: utf-8
2
-
3
- ##
4
- # Oedipus Sphinx 2 Search.
5
- # Copyright © 2012 Chris Corbyn.
6
- #
7
- # See LICENSE file for details.
8
- ##
9
-
10
- require "socket"
11
- require "net/protocol"
12
-
13
- module Oedipus
14
- module Mysql
15
- # Limited subset of MySQL protocol for communication with SphinxQL.
16
- #
17
- # This needs to exist since other ruby MySQL clients do not provide the relevant features.
18
- class Client
19
- # Connect to the SphinxQL server.
20
- #
21
- # @param [Hash]
22
- # a Hash containing :host and :port
23
- def initialize(options)
24
- @sock = TCPSocket.new(options[:host], options[:port])
25
- @seq = 0
26
- perform_handshake
27
- end
28
-
29
- def execute(sql)
30
- p send_packet(query_packet(sql))
31
- end
32
-
33
- private
34
-
35
- def perform_handshake
36
- auth_pkt = clnt_authentication_packet(serv_initialization_packet)
37
- raise "Some sort of error" unless send_packet(auth_pkt)[:type] == :ok
38
- end
39
-
40
- def incr_seq(seq)
41
- raise ProtocolError, "Invalid packet sequence value #{seq} != #{@seq}" unless seq == @seq
42
- @seq = (seq + 1) % 256
43
- end
44
-
45
- def recv_packet
46
- a, b, seq = @sock.read(4).unpack("CvC")
47
- incr_seq(seq)
48
- @sock.read(a | (b << 8))
49
- end
50
-
51
- def send_packet(pkt)
52
- while chunk = pkt.read(2**24 - 1)
53
- @sock.write([chunk.length % 256, chunk.length / 256, @seq, chunk].pack("CvCZ*"))
54
- incr_seq(@seq)
55
- end
56
-
57
- serv_result_packet
58
- end
59
-
60
- def serv_result_packet
61
- pkt = recv_packet
62
- case pkt[0]
63
- when "\x00" then ok_packet(pkt)
64
- else raise ProtocolError, "Unknown packet type #{pkt[0]}"
65
- end
66
- end
67
-
68
- def scan_lcb(str)
69
- case v = str.slice!(0)
70
- when "\xFB" then nil
71
- when "\xFC" then str.slice!(0, 2).unpack("v").first
72
- when "\xFD"
73
- a, b = str.slice!(0, 3).unpack("Cv")
74
- a | (b << 8)
75
- when "\xFE"
76
- a, b = str.slice!(0, 8).unpack("VV")
77
- a | (b << 32)
78
- else v.ord
79
- end
80
- end
81
-
82
- def ok_packet(str)
83
- Hash[
84
- [
85
- :field_count,
86
- :affected_rows,
87
- :insert_id,
88
- :serv_stat,
89
- :warning_count,
90
- :message
91
- ].zip([scan_lcb(str), scan_lcb(str), scan_lcb(str)] + str.unpack("vva*"))
92
- ].tap { |pkt| pkt[:type] = :ok }
93
- end
94
-
95
- def serv_initialization_packet
96
- Hash[
97
- [
98
- :prot_ver,
99
- :serv_ver,
100
- :thread_id,
101
- :scramble_buf_a,
102
- :filler_a,
103
- :serv_cap_a,
104
- :serv_enc,
105
- :serv_stat,
106
- :serv_cap_b,
107
- :scramble_len,
108
- :filler_b,
109
- :scramble_buf_b
110
- ].zip(recv_packet.unpack("CZ*Va8CvCvvCa10Z*"))
111
- ].tap do |pkt|
112
- raise ProtocolError, "Unsupported MySQL protocol version #{pkt[:prot_ver]}" unless pkt[:prot_ver] == 0x0A
113
- end
114
- end
115
-
116
- def clnt_authentication_packet(init_pkt)
117
- StringIO.new [
118
- 197120, # clnt_cap (prot 4.1, multi-stmt, multi-rs)
119
- 1024**3, # max pkt size
120
- 0, # charset not used
121
- '', # filler 23 bytes
122
- '', # username not used
123
- '', # scramble buf (no password)
124
- '' # dbname not used
125
- ].pack("VVCa23Z*A*Z*")
126
- end
127
-
128
- def query_packet(sql)
129
- StringIO.new [
130
- 0x03, # COM_QUERY type
131
- sql
132
- ].pack("Ca*")
133
- end
134
- end
135
- end
136
- end