intermine 0.98.11 → 0.99.00
Sign up to get free protection for your applications and to get access to all the features.
- data/TODO +3 -0
- data/lib/intermine/lists.rb +20 -8
- data/lib/intermine/model.rb +87 -0
- data/lib/intermine/query.rb +40 -1
- data/lib/intermine/results.rb +26 -11
- data/lib/intermine/version.rb +3 -1
- data/test/live_test.rb +25 -14
- metadata +8 -9
data/lib/intermine/lists.rb
CHANGED
@@ -675,13 +675,10 @@ module InterMine::Lists
|
|
675
675
|
def make_list_names(objs)
|
676
676
|
current_names = list_names
|
677
677
|
return objs.map do |x|
|
678
|
-
case
|
679
|
-
when List
|
680
|
-
|
681
|
-
when
|
682
|
-
create_list(x).name
|
683
|
-
when current_names.include?(x.to_s)
|
684
|
-
x.to_s
|
678
|
+
case
|
679
|
+
when x.is_a?(List) then x.name
|
680
|
+
when x.respond_to?(:list_upload_uri) then create_list(x).name
|
681
|
+
when current_names.include?(x.to_s) then x.to_s
|
685
682
|
else
|
686
683
|
raise ArgumentError, "#{x} is not a list you can access"
|
687
684
|
end
|
@@ -711,15 +708,17 @@ module InterMine::Lists
|
|
711
708
|
else
|
712
709
|
begin
|
713
710
|
container = JSON.parse(response.body)
|
714
|
-
|
711
|
+
err = container["error"]
|
715
712
|
rescue
|
716
713
|
response.error!
|
717
714
|
end
|
715
|
+
raise ServiceError, container["error"]
|
718
716
|
end
|
719
717
|
end
|
720
718
|
|
721
719
|
# Routine for creating a list from a PathQuery::Query
|
722
720
|
def create_list_from_query(query, tags=[], name=nil, description=nil)
|
721
|
+
query = get_listable_query(query)
|
723
722
|
uri = query.list_upload_uri
|
724
723
|
list_params = {
|
725
724
|
"listName" => name,
|
@@ -731,6 +730,19 @@ module InterMine::Lists
|
|
731
730
|
return Net::HTTP.post_form(URI.parse(uri), params)
|
732
731
|
end
|
733
732
|
|
733
|
+
def get_listable_query(query)
|
734
|
+
clone = query.clone()
|
735
|
+
views = clone.views
|
736
|
+
selected_classes = views.map {|x| x.prefix}.uniq {|p| p.to_s}
|
737
|
+
if selected_classes.size == 1
|
738
|
+
return clone.select(selected_classes.first.append("id"))
|
739
|
+
elsif selected_classes.size == 0
|
740
|
+
return clone.select("#{clone.root.name}.id")
|
741
|
+
end
|
742
|
+
# Bound to fail, but let the service provide the message.
|
743
|
+
return clone
|
744
|
+
end
|
745
|
+
|
734
746
|
# Routine for creating a List in a webservice from a list of Ids.
|
735
747
|
def create_list_from_ids(ids, type, tags=[], name=nil, description=nil)
|
736
748
|
if @service.model.get_cd(type).nil?
|
data/lib/intermine/model.rb
CHANGED
@@ -402,6 +402,46 @@ module Metadata
|
|
402
402
|
return q
|
403
403
|
end
|
404
404
|
|
405
|
+
# call-seq:
|
406
|
+
# find(*attributes) => Enumerable[InterMineObject]
|
407
|
+
#
|
408
|
+
# Get the items in the database matching the identifiers.
|
409
|
+
#
|
410
|
+
# zen = model.table("Gene").find("zen")
|
411
|
+
# puts zen.length, zen.organism.name
|
412
|
+
#
|
413
|
+
# find may retrun multiple results:
|
414
|
+
#
|
415
|
+
# genes = model.table("Gene").find("zen", "eve", "r", "h")
|
416
|
+
#
|
417
|
+
# The search mechanism used is a "lookup" constraint, so extra-values
|
418
|
+
# may be provided to distinguish search terms by passing key-value pairs:
|
419
|
+
#
|
420
|
+
# starting_with_c = model.table("Gene").find("c*" => "D. melanogaster")
|
421
|
+
#
|
422
|
+
def find(*attrs)
|
423
|
+
q = new_query
|
424
|
+
q.select("*")
|
425
|
+
attrs.each do |attr|
|
426
|
+
if attr.is_a? Hash
|
427
|
+
attr.each do |term, extra|
|
428
|
+
q.or(@root, "LOOKUP", term, extra)
|
429
|
+
end
|
430
|
+
else
|
431
|
+
q.or(@root, "LOOKUP", attr)
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
c = q.count()
|
436
|
+
if c < 1
|
437
|
+
raise ItemNotFoundError
|
438
|
+
elsif c == 1
|
439
|
+
return q.results.first
|
440
|
+
else
|
441
|
+
return q.results
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
405
445
|
# call-seq:
|
406
446
|
# where(*constraints) => PathQuery::Query
|
407
447
|
#
|
@@ -749,11 +789,55 @@ module Metadata
|
|
749
789
|
end
|
750
790
|
end
|
751
791
|
|
792
|
+
# call-seq:
|
793
|
+
# end => ClassDescriptor | ReferenceDescriptor | AttributeDescriptor
|
794
|
+
#
|
795
|
+
# Return the last element of this path
|
796
|
+
#
|
797
|
+
def end
|
798
|
+
return @elements.last
|
799
|
+
end
|
800
|
+
|
801
|
+
# call-seq:
|
802
|
+
# prefix => Path
|
803
|
+
#
|
804
|
+
# Return the Path one above this.
|
805
|
+
def prefix
|
806
|
+
if @elements.size == 1
|
807
|
+
raise PathException, "Root paths do not have a prefix"
|
808
|
+
end
|
809
|
+
new_str = @elements[0, @elements.size - 1].map {|x| x.name}.join(".")
|
810
|
+
return Path.new(new_str, @model, @subclasses)
|
811
|
+
end
|
812
|
+
|
813
|
+
# call-seq:
|
814
|
+
# append(part, ...) => Path
|
815
|
+
#
|
816
|
+
# Return a new path by adding elements to this path.
|
817
|
+
#
|
818
|
+
def append(*parts)
|
819
|
+
new_str = self.to_s + "." + parts.join(".")
|
820
|
+
return Path.new(new_str, @model, @subclasses)
|
821
|
+
end
|
822
|
+
|
752
823
|
# Two paths can be said to be equal when they stringify to the same representation.
|
753
824
|
def ==(other)
|
754
825
|
return self.to_s == other.to_s
|
755
826
|
end
|
756
827
|
|
828
|
+
# Two paths are identical when they have the same everything.
|
829
|
+
def eql?(other)
|
830
|
+
begin
|
831
|
+
return (self == other) && @model.eql?(other.model) && @subclasses.eql?(other.subclasses)
|
832
|
+
rescue
|
833
|
+
return false
|
834
|
+
end
|
835
|
+
end
|
836
|
+
|
837
|
+
def hash
|
838
|
+
return 17 * @model.hash * 11 * @subclasses.hash * 3 * to_s.hash
|
839
|
+
end
|
840
|
+
|
757
841
|
# Get the number of elements in the path
|
758
842
|
def length
|
759
843
|
return @elements.length
|
@@ -880,6 +964,9 @@ module Metadata
|
|
880
964
|
end
|
881
965
|
end
|
882
966
|
end
|
967
|
+
|
968
|
+
class ItemNotFoundError < RuntimeError
|
969
|
+
end
|
883
970
|
end
|
884
971
|
end
|
885
972
|
|
data/lib/intermine/query.rb
CHANGED
@@ -762,6 +762,32 @@ module InterMine::PathQuery
|
|
762
762
|
@constraints << con
|
763
763
|
return con
|
764
764
|
end
|
765
|
+
|
766
|
+
def or(*parameters)
|
767
|
+
logic = @logic
|
768
|
+
new_con = add_constraint(*parameters)
|
769
|
+
|
770
|
+
if logic
|
771
|
+
set_logic(LogicGroup.new(logic, "OR", new_con))
|
772
|
+
elsif @constraints.size > 1
|
773
|
+
set_logic(@constraints.map {|c| c.code }.join(" or "))
|
774
|
+
end
|
775
|
+
|
776
|
+
return self
|
777
|
+
end
|
778
|
+
|
779
|
+
def and(*parameters)
|
780
|
+
logic = @logic
|
781
|
+
new_con = add_constraint(*parameters)
|
782
|
+
|
783
|
+
if logic
|
784
|
+
set_logic(LogicGroup.new(logic, "AND", new_con))
|
785
|
+
elsif @constraints.size > 1
|
786
|
+
set_logic(@constraints.map {|c| c.code }.join(" and "))
|
787
|
+
end
|
788
|
+
|
789
|
+
return self
|
790
|
+
end
|
765
791
|
|
766
792
|
# Returns a Path object constructed from the given path-string,
|
767
793
|
# taking the current state of the query into account (its data-model
|
@@ -826,7 +852,7 @@ module InterMine::PathQuery
|
|
826
852
|
end
|
827
853
|
parameters[:values] = subv.to_a
|
828
854
|
elsif subv.is_a?(Lists::List)
|
829
|
-
if subk == "="
|
855
|
+
if subk == "=" or subk == "<" or subk == "<="
|
830
856
|
parameters[:op] = "IN"
|
831
857
|
elsif subk == "!="
|
832
858
|
parameters[:op] = "NOT IN"
|
@@ -834,6 +860,19 @@ module InterMine::PathQuery
|
|
834
860
|
parameters[:op] = normalised_k
|
835
861
|
end
|
836
862
|
parameters[:value] = subv.name
|
863
|
+
elsif subv.is_a? Query
|
864
|
+
if subk == "=" or subk == "<" or subk == "<="
|
865
|
+
parameters[:op] = "IN"
|
866
|
+
elsif subk == "!="
|
867
|
+
parameters[:op] = "NOT IN"
|
868
|
+
else
|
869
|
+
parameters[:op] = normalised_k
|
870
|
+
end
|
871
|
+
s = subv.service
|
872
|
+
l = s.create_list(subv)
|
873
|
+
|
874
|
+
parameters[:value] = l.name
|
875
|
+
|
837
876
|
else
|
838
877
|
parameters[:op] = normalised_k
|
839
878
|
parameters[:value] = subv
|
data/lib/intermine/results.rb
CHANGED
@@ -85,12 +85,12 @@ module InterMine::Results
|
|
85
85
|
def [](arg, length=nil)
|
86
86
|
unless length.nil?
|
87
87
|
raise ArgumentError, "when providing a length, the first argument must be an Integer" unless arg.is_a? Integer
|
88
|
-
return @results[arg, length].map {|x| x
|
88
|
+
return @results[arg, length].map {|x| value_of(x)}
|
89
89
|
end
|
90
90
|
|
91
91
|
case arg
|
92
92
|
when Range
|
93
|
-
return @results[arg].map {|x| x
|
93
|
+
return @results[arg].map {|x| value_of(x)}
|
94
94
|
when Integer
|
95
95
|
idx = arg
|
96
96
|
else
|
@@ -103,17 +103,17 @@ module InterMine::Results
|
|
103
103
|
|
104
104
|
raise IndexError, "Argument out of range" if cell.nil?
|
105
105
|
|
106
|
-
return cell
|
106
|
+
return value_of(cell)
|
107
107
|
end
|
108
108
|
|
109
109
|
# Returns the first value in this row
|
110
110
|
def first
|
111
|
-
return @results[0]
|
111
|
+
return value_of(@results[0])
|
112
112
|
end
|
113
113
|
|
114
114
|
# Returns the last value in this row
|
115
115
|
def last
|
116
|
-
return @results.last
|
116
|
+
return value_of(@results.last)
|
117
117
|
end
|
118
118
|
|
119
119
|
# Iterate over the values in this row in the
|
@@ -134,9 +134,11 @@ module InterMine::Results
|
|
134
134
|
def each(&block)
|
135
135
|
if block
|
136
136
|
if block.arity == 1
|
137
|
-
@results.each {|x| block.call(x
|
137
|
+
@results.each {|x| block.call(value_of(x))}
|
138
138
|
else block.arity == 2
|
139
|
-
(0 ... @results.size).to_a.each {|i|
|
139
|
+
(0 ... @results.size).to_a.each {|i|
|
140
|
+
block.call(@columns[i], value_of(@results[i]))
|
141
|
+
}
|
140
142
|
end
|
141
143
|
end
|
142
144
|
return self
|
@@ -154,7 +156,7 @@ module InterMine::Results
|
|
154
156
|
|
155
157
|
# Return an Array version of the row.
|
156
158
|
def to_a
|
157
|
-
return @results.map {|x| x
|
159
|
+
return @results.map {|x| value_of(x)}
|
158
160
|
end
|
159
161
|
|
160
162
|
# Return a Hash version of the row. All keys in this
|
@@ -185,11 +187,15 @@ module InterMine::Results
|
|
185
187
|
# CSV or TSV file. The optional separator argument will be used to delimit
|
186
188
|
# columns
|
187
189
|
def to_csv(sep="\t")
|
188
|
-
return @results.map {|x| x
|
190
|
+
return @results.map {|x| value_of(x).inspect}.join(sep)
|
189
191
|
end
|
190
192
|
|
191
193
|
private
|
192
194
|
|
195
|
+
def value_of(cell)
|
196
|
+
return cell["value"]
|
197
|
+
end
|
198
|
+
|
193
199
|
# Return the index for a string or symbol key.
|
194
200
|
def index_for(key)
|
195
201
|
if @indexes.nil?
|
@@ -209,6 +215,13 @@ module InterMine::Results
|
|
209
215
|
end
|
210
216
|
end
|
211
217
|
|
218
|
+
class NewResultRow < ResultsRow
|
219
|
+
|
220
|
+
def value_of(cell)
|
221
|
+
return cell
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
212
225
|
# The class responsible for retrieving results and processing them
|
213
226
|
#
|
214
227
|
# query.each_row do |row|
|
@@ -250,11 +263,13 @@ module InterMine::Results
|
|
250
263
|
|
251
264
|
# Iterate over the result set one ResultsRow at a time
|
252
265
|
def each_row
|
266
|
+
cls = @query.service.version >= 8 ? NewResultRow : ResultsRow
|
267
|
+
format = @query.service.version >= 8 ? "json" : "jsonrows"
|
253
268
|
processor = lambda {|line|
|
254
269
|
x = line.chomp.chomp(",")
|
255
|
-
x.empty? ? nil :
|
270
|
+
x.empty? ? nil : cls.new(x, @query.views)
|
256
271
|
}
|
257
|
-
read_result_set(params(
|
272
|
+
read_result_set(params(format), processor) {|x|
|
258
273
|
yield x
|
259
274
|
}
|
260
275
|
end
|
data/lib/intermine/version.rb
CHANGED
@@ -12,5 +12,7 @@ module Intermine
|
|
12
12
|
# 0.98.10 - Added status property to lists
|
13
13
|
# 0.98.09 - Major changes to results - now with thorough-going Enumerable support
|
14
14
|
# 0.98.08 - Added column summary support
|
15
|
-
|
15
|
+
# 0.99.00 - Added coercion from query to lists in "IN/NOT IN" constraints
|
16
|
+
# - Added support for "json" format (performance) improvement
|
17
|
+
VERSION = "0.99.00"
|
16
18
|
end
|
data/test/live_test.rb
CHANGED
@@ -6,7 +6,7 @@ require "intermine/service"
|
|
6
6
|
class LiveDemoTest < Test::Unit::TestCase
|
7
7
|
|
8
8
|
def setup
|
9
|
-
@service = Service.new("
|
9
|
+
@service = Service.new("localhost/intermine-test", "test-user-token")
|
10
10
|
@temp_lists = []
|
11
11
|
end
|
12
12
|
|
@@ -48,42 +48,42 @@ class LiveDemoTest < Test::Unit::TestCase
|
|
48
48
|
def testListEnumerability
|
49
49
|
list = @service.list("My-Favourite-Employees")
|
50
50
|
names = list.map {|emp| emp.name }
|
51
|
-
exp = ["
|
51
|
+
exp = ["David Brent", "Neil Godwin", "Bernd Stromberg", "Timo Becker"]
|
52
52
|
assert_equal(exp, names)
|
53
53
|
|
54
|
-
old = list.select {|emp| emp.age >
|
54
|
+
old = list.select {|emp| emp.age > 42}
|
55
55
|
assert_equal(1, old.size)
|
56
|
-
assert_equal("
|
56
|
+
assert_equal("Neil Godwin", old.first.name)
|
57
57
|
|
58
58
|
sum = list.reduce(0) {|m, i| m + i.age}
|
59
|
-
assert_equal(
|
59
|
+
assert_equal(159, sum)
|
60
60
|
end
|
61
61
|
|
62
62
|
def testLazyReferenceFetching
|
63
63
|
list = @service.list("My-Favourite-Employees")
|
64
64
|
|
65
65
|
deps = list.map {|emp| emp.department.name }
|
66
|
-
exp = ["
|
67
|
-
"
|
66
|
+
exp = ["Sales", "Human Resources",
|
67
|
+
"Schadensregulierung M-Z", "Schadensregulierung"]
|
68
68
|
assert_equal(exp, deps)
|
69
69
|
|
70
70
|
comps = list.map {|emp| emp.department.company.name }
|
71
|
-
exp = [
|
72
|
-
"
|
71
|
+
exp = [ "Wernham-Hogg","Wernham-Hogg",
|
72
|
+
"Capitol Versicherung AG", "Capitol Versicherung AG"]
|
73
73
|
assert_equal(exp, comps)
|
74
74
|
end
|
75
75
|
|
76
76
|
def testLazyCollectionFetching
|
77
77
|
list = @service.list("My-Favourite-Employees")
|
78
78
|
emps = list.map {|manager| manager.department.employees.map {|employee| employee.age} }
|
79
|
-
exp = [[
|
80
|
-
|
81
|
-
|
82
|
-
|
79
|
+
exp = [[34, 36, 41, 55, 61, 61],
|
80
|
+
[44, 49, 62],
|
81
|
+
[30, 37, 45, 46, 58, 64],
|
82
|
+
[36, 37, 39, 49, 57, 59]]
|
83
83
|
assert_equal(exp, emps)
|
84
84
|
|
85
85
|
sum = list.reduce(0) {|m, manager| m + manager.department.employees.reduce(0) {|n, emp| n + emp.age}}
|
86
|
-
assert_equal(
|
86
|
+
assert_equal(1000, sum)
|
87
87
|
end
|
88
88
|
|
89
89
|
def testListCreation
|
@@ -130,4 +130,15 @@ class LiveDemoTest < Test::Unit::TestCase
|
|
130
130
|
assert_equal(tags.sort, new_list.tags.sort)
|
131
131
|
end
|
132
132
|
|
133
|
+
def testCoercingQueriesToLists
|
134
|
+
q1 = @service.query("Bank")
|
135
|
+
q2 = @service.query("Bank").where("corporateCustomers.id" => {'!=' => nil})
|
136
|
+
|
137
|
+
assert_equal(2, @service.query("Bank").where("Bank" => {:not_in => q2}).count)
|
138
|
+
|
139
|
+
l = @service.subtract([q1], [q2])
|
140
|
+
@temp_lists << l
|
141
|
+
assert_equal(2, l.size)
|
142
|
+
end
|
143
|
+
|
133
144
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: intermine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 403
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 99
|
9
|
+
- 0
|
10
|
+
version: 0.99.00
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Alex Kalderimis
|
@@ -15,8 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
19
|
-
default_executable:
|
18
|
+
date: 2011-12-12 00:00:00 Z
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
21
|
name: json
|
@@ -149,9 +148,9 @@ files:
|
|
149
148
|
- LICENCE
|
150
149
|
- Rakefile
|
151
150
|
- README.rdoc
|
151
|
+
- TODO
|
152
152
|
- Gemfile
|
153
153
|
- contact_header.rdoc
|
154
|
-
has_rdoc: true
|
155
154
|
homepage: http://www.intermine.org
|
156
155
|
licenses:
|
157
156
|
- LGPL
|
@@ -185,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
184
|
requirements: []
|
186
185
|
|
187
186
|
rubyforge_project: intermine
|
188
|
-
rubygems_version: 1.
|
187
|
+
rubygems_version: 1.7.2
|
189
188
|
signing_key:
|
190
189
|
specification_version: 3
|
191
190
|
summary: Webservice Client Library for InterMine Data-Warehouses
|