oedipus 0.0.1.pre1 → 0.0.1.pre2

Sign up to get free protection for your applications and to get access to all the features.
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