voruby 1.0.1
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.
- data/LICENSE +339 -0
- data/REQUIREMENTS +4 -0
- data/Rakefile.rb +296 -0
- data/lib/voruby/adql/adql.rb +2735 -0
- data/lib/voruby/adql/ext.rb +15 -0
- data/lib/voruby/adql/loader.rb +5 -0
- data/lib/voruby/adql/operations.rb +54 -0
- data/lib/voruby/adql/parser.rb +160 -0
- data/lib/voruby/adql/transforms.rb +573 -0
- data/lib/voruby/ext.rb +17 -0
- data/lib/voruby/loader.rb +4 -0
- data/lib/voruby/misc/propertyfile.rb +36 -0
- data/lib/voruby/plastic/applications.rb +174 -0
- data/lib/voruby/plastic/constants.rb +30 -0
- data/lib/voruby/plastic/loader.rb +10 -0
- data/lib/voruby/plastic/plastic.rb +1 -0
- data/lib/voruby/resources/conesearch/conesearch.rb +9 -0
- data/lib/voruby/resources/conesearch/conesearch_v0_2.rb +55 -0
- data/lib/voruby/resources/conesearch/conesearch_v0_3.rb +50 -0
- data/lib/voruby/resources/conesearch/conesearch_v1_0.rb +72 -0
- data/lib/voruby/resources/conesearch/loader.rb +4 -0
- data/lib/voruby/resources/loader.rb +50 -0
- data/lib/voruby/resources/nodes.rb +190 -0
- data/lib/voruby/resources/openskynode/loader.rb +4 -0
- data/lib/voruby/resources/openskynode/openskynode.rb +9 -0
- data/lib/voruby/resources/openskynode/openskynode_v0_1.rb +54 -0
- data/lib/voruby/resources/sia/loader.rb +5 -0
- data/lib/voruby/resources/sia/sia.rb +9 -0
- data/lib/voruby/resources/sia/sia_v0_6.rb +90 -0
- data/lib/voruby/resources/sia/sia_v0_7.rb +89 -0
- data/lib/voruby/resources/sia/sia_v1_0.rb +122 -0
- data/lib/voruby/resources/stsci.rb +59 -0
- data/lib/voruby/resources/vodataservice/coverage_v0_2.rb +195 -0
- data/lib/voruby/resources/vodataservice/coverage_v0_3.rb +158 -0
- data/lib/voruby/resources/vodataservice/loader.rb +5 -0
- data/lib/voruby/resources/vodataservice/vodataservice.rb +9 -0
- data/lib/voruby/resources/vodataservice/vodataservice_v0_4.rb +189 -0
- data/lib/voruby/resources/vodataservice/vodataservice_v0_5.rb +163 -0
- data/lib/voruby/resources/vodataservice/vodataservice_v1_0.rb +221 -0
- data/lib/voruby/resources/voregistry/loader.rb +4 -0
- data/lib/voruby/resources/voregistry/voregistry.rb +9 -0
- data/lib/voruby/resources/voregistry/voregistry_v0_2.rb +40 -0
- data/lib/voruby/resources/voregistry/voregistry_v0_3.rb +30 -0
- data/lib/voruby/resources/voregistry/voregistry_v1_0.rb +86 -0
- data/lib/voruby/resources/voresource/loader.rb +17 -0
- data/lib/voruby/resources/voresource/voresource.rb +9 -0
- data/lib/voruby/resources/voresource/voresource_v0_10.rb +322 -0
- data/lib/voruby/resources/voresource/voresource_v0_9.rb +405 -0
- data/lib/voruby/resources/voresource/voresource_v1_0.rb +230 -0
- data/lib/voruby/services/ext.rb +11 -0
- data/lib/voruby/services/gestalt/footprint.rb +95 -0
- data/lib/voruby/services/gestalt/wcs_fixer.rb +105 -0
- data/lib/voruby/services/gestalt/wesix.rb +155 -0
- data/lib/voruby/services/loader.rb +7 -0
- data/lib/voruby/services/registry/registry.rb +53 -0
- data/lib/voruby/services/resolver/resolver.rb +35 -0
- data/lib/voruby/sesame/loader.rb +6 -0
- data/lib/voruby/sesame/sesame_v1_0.rb +64 -0
- data/lib/voruby/simple/loader.rb +6 -0
- data/lib/voruby/simple/parameters.rb +196 -0
- data/lib/voruby/simple/sap.rb +446 -0
- data/lib/voruby/spacetime/loader.rb +3 -0
- data/lib/voruby/spacetime/spacetime.rb +607 -0
- data/lib/voruby/stc/coords_v1_20.rb +900 -0
- data/lib/voruby/stc/loader.rb +55 -0
- data/lib/voruby/stc/region_v1_20.rb +274 -0
- data/lib/voruby/stc/stc_v1_20.rb +1196 -0
- data/lib/voruby/util.rb +27 -0
- data/lib/voruby/voevent/loader.rb +7 -0
- data/lib/voruby/voevent/voevent_v1_0.rb +213 -0
- data/lib/voruby/voevent/voevent_v1_1.rb +196 -0
- data/lib/voruby/votables/chandra.rb +410 -0
- data/lib/voruby/votables/cnoc.rb +393 -0
- data/lib/voruby/votables/data.rb +179 -0
- data/lib/voruby/votables/galex.rb +390 -0
- data/lib/voruby/votables/hst.rb +391 -0
- data/lib/voruby/votables/int.rb +391 -0
- data/lib/voruby/votables/libxml_parser.rb +411 -0
- data/lib/voruby/votables/libxml_votable.rb +67 -0
- data/lib/voruby/votables/loader.rb +10 -0
- data/lib/voruby/votables/meta.rb +763 -0
- data/lib/voruby/votables/misc.rb +51 -0
- data/lib/voruby/votables/nsa.rb +393 -0
- data/lib/voruby/votables/nsar3.rb +410 -0
- data/lib/voruby/votables/rexml_parser.rb +408 -0
- data/lib/voruby/votables/rexml_votable.rb +67 -0
- data/lib/voruby/votables/sdss.rb +393 -0
- data/lib/voruby/votables/transforms.rb +388 -0
- data/lib/voruby/votables/tree.rb +45 -0
- data/lib/voruby/votables/types.rb +391 -0
- data/lib/voruby/votables/votable.rb +630 -0
- data/lib/voruby/votables/xmm.rb +394 -0
- data/test/adql/test1.adql +49 -0
- data/test/adql/test2.adql +51 -0
- data/test/adql/test3.adql +81 -0
- data/test/adql/test4.adql +53 -0
- data/test/adql/test5.adql +55 -0
- data/test/adql/test6.adql +18 -0
- data/test/adql/test7.adql +48 -0
- data/test/adql/unittest.rb +1672 -0
- data/test/plastic/test.rb +44 -0
- data/test/plastic/test.vot +5385 -0
- data/test/plastic/unittest.rb +66 -0
- data/test/resources/conesearch/conesearch_v0_3.xml +31 -0
- data/test/resources/conesearch/conesearch_v1_0.xml +86 -0
- data/test/resources/conesearch/unittest_v0_3.rb +22 -0
- data/test/resources/conesearch/unittest_v1_0.rb +24 -0
- data/test/resources/openskynode/open_sky_node_v0_1.xml +32 -0
- data/test/resources/openskynode/unittest_v0_1.rb +31 -0
- data/test/resources/sia/simple_image_access_v0_7.xml +36 -0
- data/test/resources/sia/simple_image_access_v1_0.xml +122 -0
- data/test/resources/sia/unittest_v0_7.rb +24 -0
- data/test/resources/sia/unittest_v1_0.rb +29 -0
- data/test/resources/stsci.xml +336 -0
- data/test/resources/unittest_stsci.rb +25 -0
- data/test/resources/vodataservice/catalog_service_resource_v1_0.xml +128 -0
- data/test/resources/vodataservice/data_collection_resource_v0_5.xml +54 -0
- data/test/resources/vodataservice/data_collection_resource_v1_0.xml +117 -0
- data/test/resources/vodataservice/data_service_resource_v1_0.xml +115 -0
- data/test/resources/vodataservice/sky_service_resource_v0_10.xml +45 -0
- data/test/resources/vodataservice/table_service_resource_v1_0.xml +122 -0
- data/test/resources/vodataservice/tabular_sky_service_resource_v0_10.xml +60 -0
- data/test/resources/vodataservice/unittest_v0_5.rb +126 -0
- data/test/resources/vodataservice/unittest_v1_0.rb +151 -0
- data/test/resources/voregistry/authority_resource_v0_3.xml +20 -0
- data/test/resources/voregistry/authority_resource_v1_0.xml +82 -0
- data/test/resources/voregistry/registry_service_v0_3.xml +20 -0
- data/test/resources/voregistry/registry_service_v1_0.xml +107 -0
- data/test/resources/voregistry/unittest_v0_3.rb +31 -0
- data/test/resources/voregistry/unittest_v1_0.rb +34 -0
- data/test/resources/voresource/organisation_resource_v1_0.xml +90 -0
- data/test/resources/voresource/resource_organisation_v0_10.xml +22 -0
- data/test/resources/voresource/resource_service_v0_10.xml +19 -0
- data/test/resources/voresource/resource_v0_10.xml +19 -0
- data/test/resources/voresource/resource_v1_0.xml +79 -0
- data/test/resources/voresource/service_resource_v1_0.xml +91 -0
- data/test/resources/voresource/unittest_v0_10.rb +61 -0
- data/test/resources/voresource/unittest_v0_9.rb +4 -0
- data/test/resources/voresource/unittest_v1_0.rb +190 -0
- data/test/services/gestalt/unittest.rb +74 -0
- data/test/services/registry/unittest.rb +34 -0
- data/test/services/resolver/unittest.rb +38 -0
- data/test/simple/unittest.rb +46 -0
- data/test/spacetime/unittest.rb +39 -0
- data/test/stc/catalog_entry_location_v1_20.xml +112 -0
- data/test/stc/obs_data_location_v1_20.xml +108 -0
- data/test/stc/search_location_v1_20.xml +54 -0
- data/test/stc/stc_resource_profile_v1_20.xml +60 -0
- data/test/stc/unittest_v1_20.rb +620 -0
- data/test/voevent/unittest_v1_0.rb +79 -0
- data/test/voevent/unittest_v1_1.rb +70 -0
- data/test/voevent/voevent_v1_0.xml +96 -0
- data/test/voevent/voevent_v1_1.xml +76 -0
- data/test/votables/test.vot +366 -0
- data/test/votables/unittest.rb +54 -0
- metadata +256 -0
@@ -0,0 +1,2735 @@
|
|
1
|
+
require 'voruby/adql/loader'
|
2
|
+
|
3
|
+
# A set of classes designed to read and manipulate ADQL[http://www.ivoa.net/Documents/latest/ADQL.html].
|
4
|
+
module VORuby
|
5
|
+
|
6
|
+
module ADQL
|
7
|
+
# Acts as glue between xsi:types and their corresponding
|
8
|
+
# domain objects in the * hierarchy.
|
9
|
+
class ObjectBuilder
|
10
|
+
def self.classes
|
11
|
+
{:allSelectionItemType => AllSelectionItem,
|
12
|
+
:columnReferenceType => ColumnReference,
|
13
|
+
:tableType => ArchiveTable,
|
14
|
+
:atomType => Atom,
|
15
|
+
:stringType => StringType,
|
16
|
+
:realType => RealType,
|
17
|
+
:integerType => IntegerType,
|
18
|
+
:binaryExprType => BinaryExpr,
|
19
|
+
:unaryExprType => UnaryExpr,
|
20
|
+
:closedExprType => ClosedExpr,
|
21
|
+
:trigonometricFunctionType => TrigonometricFunction,
|
22
|
+
:trigonometricFunctionNameType => TrigonometricFunctionName,
|
23
|
+
:mathFunctionType => MathFunction,
|
24
|
+
:mathFunctionNameType => MathFunctionName,
|
25
|
+
:aggregateFunctionType => AggregateFunction,
|
26
|
+
:aggregateFunctionNameType => AggregateFunctionName,
|
27
|
+
:userDefinedFunctionType => UserDefinedFunction,
|
28
|
+
:aliasSelectionItemType => AliasSelectionItem,
|
29
|
+
:likePredType => LikePred,
|
30
|
+
:notLikePredType => NotLikePred,
|
31
|
+
:closedSearchType => ClosedSearch,
|
32
|
+
:intersectionSearchType => IntersectionSearch,
|
33
|
+
:unionSearchType => UnionSearch,
|
34
|
+
:comparisonPredType => ComparisonPred,
|
35
|
+
:betweenPredType => BetweenPred,
|
36
|
+
:notBetweenPredType => NotBetweenPred,
|
37
|
+
:includeTableType => IncludeTable,
|
38
|
+
:dropTableType => DropTable,
|
39
|
+
:xMatchType => XMatch,
|
40
|
+
:xMatchTableAliasType => XMatchTableAlias,
|
41
|
+
:comparisonType => Comparison,
|
42
|
+
:regionSearchType => RegionSearch,
|
43
|
+
:inverseSearchType => InverseSearch,
|
44
|
+
:inclusionSetType => InclusionSet,
|
45
|
+
:inclusiveSearchType => InclusiveSearch,
|
46
|
+
:exclusiveSearchType => ExclusiveSearch,
|
47
|
+
:subQuerySetType => SubQuerySet,
|
48
|
+
:joinTableType => JoinTable,
|
49
|
+
:constantListSetType => ConstantListSet,
|
50
|
+
:orderType => Order,
|
51
|
+
:circleType => Circle,
|
52
|
+
:boxType => Box,
|
53
|
+
:archiveTableType => ArchiveTable}
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get the domain class associated with a particular xsi:type.
|
57
|
+
def self.get_class_for(type)
|
58
|
+
klass = self.classes()[type.to_sym] || self.classes()[type]
|
59
|
+
raise "Unable to find type #{type}" if !klass
|
60
|
+
return klass
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# The abstract base type for any of items to be selected in a query.
|
65
|
+
class SelectionItem
|
66
|
+
def self.from_xml(node)
|
67
|
+
#type_s = node.elements['xsi:type']
|
68
|
+
type_s = node.find_attribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
|
69
|
+
return ObjectBuilder.get_class_for(type_s).from_xml(node)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# The base type for a scalar expression.
|
74
|
+
class ScalarExpression < SelectionItem
|
75
|
+
attr_reader :value
|
76
|
+
|
77
|
+
def initialize(val)
|
78
|
+
self.value = val
|
79
|
+
end
|
80
|
+
|
81
|
+
def is_scalar?(v)
|
82
|
+
if v.is_a?(String) or v.is_a?(Integer) or v.is_a?(Float)
|
83
|
+
return true
|
84
|
+
else
|
85
|
+
return false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def value=(v)
|
90
|
+
if self.is_scalar?(v)
|
91
|
+
@value = v
|
92
|
+
else
|
93
|
+
raise "Scalar expression must contain scalar values"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_s
|
98
|
+
"{value=#{self.value}}"
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.from_xml(node)
|
102
|
+
#type_s = node.attributes['xsi:type']
|
103
|
+
type_s = node.find_attribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
|
104
|
+
return ObjectBuilder.get_class_for(type_s).from_xml(node)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Represents an expression inside a bracket.
|
109
|
+
class ClosedExpr < ScalarExpression
|
110
|
+
attr_reader :value
|
111
|
+
|
112
|
+
def initialize(val)
|
113
|
+
self.value = val
|
114
|
+
end
|
115
|
+
|
116
|
+
def value=(v)
|
117
|
+
VOTables::VOTable::Misc::TypeCheck.new(v, ScalarExpression).check()
|
118
|
+
@value = v
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.from_xml(node)
|
122
|
+
expr_node = REXML::XPath.first(node, 'Arg')
|
123
|
+
expr = ScalarExpression.from_xml(expr_node)
|
124
|
+
return ClosedExpr.new(expr)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Used for expressing operations like A+B.
|
129
|
+
class BinaryOperator
|
130
|
+
attr_reader :operator
|
131
|
+
|
132
|
+
@@operators = ['+', '-', '*', '/']
|
133
|
+
|
134
|
+
def initialize(operator, op_list=nil)
|
135
|
+
@op_list = op_list || @@operators
|
136
|
+
self.operator = operator
|
137
|
+
end
|
138
|
+
|
139
|
+
def operator=(o)
|
140
|
+
if @op_list.include?(o)
|
141
|
+
@operator = o
|
142
|
+
else
|
143
|
+
raise "Binary operator is not valid. Use one of: " +
|
144
|
+
@op_list.join(', ')
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_s
|
149
|
+
"{operator=#{self.operator}}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Represents a binary expression such as a+b.
|
154
|
+
class BinaryExpr < ScalarExpression
|
155
|
+
attr_reader :oper, :arg1, :arg2
|
156
|
+
|
157
|
+
def initialize(arg1, oper, arg2)
|
158
|
+
super("#{arg1} #{oper} #{arg2}")
|
159
|
+
|
160
|
+
self.arg1 = arg1
|
161
|
+
self.arg2 = arg2
|
162
|
+
self.oper = oper
|
163
|
+
end
|
164
|
+
|
165
|
+
def arg1=(a)
|
166
|
+
begin
|
167
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, ScalarExpression).check()
|
168
|
+
rescue VOTables::VOTable::Misc::TypeException
|
169
|
+
@arg1 = ScalarExpression.new(a)
|
170
|
+
else
|
171
|
+
@arg1 = a
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def arg2=(a)
|
176
|
+
begin
|
177
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, ScalarExpression).check()
|
178
|
+
rescue VOTables::VOTable::Misc::TypeException
|
179
|
+
@arg2 = ScalarExpression.new(a)
|
180
|
+
else
|
181
|
+
@arg2 = a
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def oper=(o)
|
186
|
+
begin
|
187
|
+
VOTables::VOTable::Misc::TypeCheck.new(o, BinaryOperator).check()
|
188
|
+
rescue VOTables::VOTable::Misc::TypeException
|
189
|
+
@oper = BinaryOperator.new(o)
|
190
|
+
else
|
191
|
+
@oper = o
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def to_s
|
196
|
+
"{arg1=#{self.arg1},oper=#{self.oper},arg2=#{self.arg2}}"
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.from_xml(node)
|
200
|
+
oper = BinaryOperator.new(node.attributes['Oper'])
|
201
|
+
arg1_node, arg2_node = node.elements.to_a('Arg')
|
202
|
+
arg1 = ScalarExpression.from_xml(arg1_node)
|
203
|
+
arg2 = ScalarExpression.from_xml(arg2_node)
|
204
|
+
return BinaryExpr.new(arg1, oper, arg2)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Operators for expressing a single element operation.
|
209
|
+
class UnaryOperator
|
210
|
+
attr_reader :operator
|
211
|
+
|
212
|
+
@@operators = ['+', '-']
|
213
|
+
|
214
|
+
def initialize(operator, op_list=nil)
|
215
|
+
@op_list = op_list || @@operators
|
216
|
+
self.operator = operator
|
217
|
+
end
|
218
|
+
|
219
|
+
def operator=(o)
|
220
|
+
if @op_list.include?(o)
|
221
|
+
@operator = o
|
222
|
+
else
|
223
|
+
raise "Unary operator is not valid. Use one of: " +
|
224
|
+
@op_list.join(', ')
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def to_s
|
229
|
+
"{operator=#{self.operator}}"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Represents an unary expression such as -(a.ra)
|
234
|
+
class UnaryExpr < ScalarExpression
|
235
|
+
attr_reader :arg, :oper
|
236
|
+
|
237
|
+
def initialize(oper, arg)
|
238
|
+
super("#{oper}#{arg}")
|
239
|
+
|
240
|
+
self.arg = arg
|
241
|
+
self.oper = oper
|
242
|
+
end
|
243
|
+
|
244
|
+
def arg=(a)
|
245
|
+
begin
|
246
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, ScalarExpression).check()
|
247
|
+
rescue VOTables::VOTable::Misc::TypeException
|
248
|
+
@arg = ScalarExpression.new(a)
|
249
|
+
else
|
250
|
+
@arg = a
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def oper=(o)
|
255
|
+
begin
|
256
|
+
VOTables::VOTable::Misc::TypeCheck.new(o, UnaryOperator).check()
|
257
|
+
rescue VOTables::VOTable::Misc::TypeException
|
258
|
+
@oper = UnaryOperator.new(o)
|
259
|
+
else
|
260
|
+
@oper = o
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def to_s
|
265
|
+
"{arg=#{self.oper},oper=#{self.arg}}"
|
266
|
+
end
|
267
|
+
|
268
|
+
def self.from_xml(node)
|
269
|
+
oper = UnaryOperator.new(node.attributes['Oper'])
|
270
|
+
arg_node = REXML::XPath.first(node, 'Arg')
|
271
|
+
arg = ScalarExpression.from_xml(arg_node)
|
272
|
+
return UnaryExpr.new(oper, arg)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# Represents a column.
|
277
|
+
class ColumnReference < ScalarExpression
|
278
|
+
attr_accessor :table, :name, :xpath_name
|
279
|
+
|
280
|
+
def initialize(table, name, xpath_name=nil)
|
281
|
+
super("#{table}.#{name} #{xpath_name || ''}")
|
282
|
+
|
283
|
+
self.table = table
|
284
|
+
self.name = name
|
285
|
+
self.xpath_name = xpath_name
|
286
|
+
end
|
287
|
+
|
288
|
+
def to_s
|
289
|
+
self.value
|
290
|
+
end
|
291
|
+
|
292
|
+
def self.from_xml(el)
|
293
|
+
table = el.attributes['Table']
|
294
|
+
name = el.attributes['Name']
|
295
|
+
xpath = el.attributes['xpathName']
|
296
|
+
cr = ColumnReference.new(table, name, xpath)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# Encapsulates basic literals such as Strings, Integers and Real numbers.
|
301
|
+
class Atom < ScalarExpression
|
302
|
+
attr_reader :literal
|
303
|
+
attr_accessor :unit
|
304
|
+
|
305
|
+
def initialize(literal, unit=nil)
|
306
|
+
super("#{literal}#{unit || ''}")
|
307
|
+
|
308
|
+
self.literal = literal
|
309
|
+
self.unit = unit
|
310
|
+
end
|
311
|
+
|
312
|
+
def literal=(l)
|
313
|
+
begin
|
314
|
+
VOTables::VOTable::Misc::TypeCheck.new(l, LiteralType).check()
|
315
|
+
rescue VOTables::VOTable::Misc::TypeException
|
316
|
+
if l.is_a?(Float)
|
317
|
+
@literal = RealType.new(l)
|
318
|
+
elsif l.is_a?(Integer)
|
319
|
+
@literal = IntegerType.new(l)
|
320
|
+
elsif l.is_a?(String)
|
321
|
+
@literal = StringType.new(l)
|
322
|
+
else
|
323
|
+
raise "Literal is not a real, integer or string"
|
324
|
+
end
|
325
|
+
else
|
326
|
+
@literal = l
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def to_s
|
331
|
+
"{literal=#{self.literal},unit=#{self.unit}}"
|
332
|
+
end
|
333
|
+
|
334
|
+
def self.from_xml(node)
|
335
|
+
literal_node = REXML::XPath.first(node, 'Literal')
|
336
|
+
literal = LiteralType.from_xml(literal_node)
|
337
|
+
return Atom.new(literal)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
# The base type for all literals.
|
342
|
+
class LiteralType
|
343
|
+
def to_s
|
344
|
+
"{value=#{self.value}}"
|
345
|
+
end
|
346
|
+
|
347
|
+
def self.from_xml(node)
|
348
|
+
#type_s = node.attributes['xsi:type']
|
349
|
+
type_s = node.find_attribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
|
350
|
+
literal = ObjectBuilder.get_class_for(type_s).from_xml(node)
|
351
|
+
return literal
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
# The base type for all numbers.
|
356
|
+
class NumberType < LiteralType
|
357
|
+
def self.from_xml(node)
|
358
|
+
#type_s = node.attributes['xsi:type']
|
359
|
+
type_s = node.find_attribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
|
360
|
+
number = ObjectBuilder.get_class_for(type_s).from_xml(node)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
# Represents a real number.
|
365
|
+
class RealType < NumberType
|
366
|
+
attr_reader :value
|
367
|
+
|
368
|
+
def initialize(value)
|
369
|
+
self.value = value
|
370
|
+
end
|
371
|
+
|
372
|
+
def value=(v)
|
373
|
+
begin
|
374
|
+
VOTables::VOTable::Misc::TypeCheck.new(v, Float).check()
|
375
|
+
rescue VOTables::VOTable::Misc::TypeException
|
376
|
+
if v.is_a?(Integer)
|
377
|
+
@value = v.to_f
|
378
|
+
else
|
379
|
+
raise VOTables::VOTable::Misc::TypeException
|
380
|
+
end
|
381
|
+
else
|
382
|
+
@value = v
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
def self.from_xml(node)
|
387
|
+
return RealType.new(node.attributes['Value'].to_f)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
# Represents an integer.
|
392
|
+
class IntegerType < NumberType
|
393
|
+
attr_reader :value
|
394
|
+
|
395
|
+
def initialize(value)
|
396
|
+
self.value = value
|
397
|
+
end
|
398
|
+
|
399
|
+
def value=(v)
|
400
|
+
VOTables::VOTable::Misc::TypeCheck.new(v, Integer).check()
|
401
|
+
@value = v
|
402
|
+
end
|
403
|
+
|
404
|
+
def self.from_xml(node)
|
405
|
+
return IntegerType.new(node.attributes['Value'].to_i)
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
# Represents a string literal.
|
410
|
+
class StringType < LiteralType
|
411
|
+
attr_reader :value
|
412
|
+
|
413
|
+
def initialize(value)
|
414
|
+
self.value = value
|
415
|
+
end
|
416
|
+
|
417
|
+
def value=(v)
|
418
|
+
VOTables::VOTable::Misc::TypeCheck.new(v, String).check()
|
419
|
+
@value = v
|
420
|
+
end
|
421
|
+
|
422
|
+
def self.from_xml(node)
|
423
|
+
return StringType.new(node.attributes['Value'])
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
# The base type for a function.
|
428
|
+
class FunctionType < ScalarExpression
|
429
|
+
def to_s
|
430
|
+
"{name=#{self.name}}"
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
# Option of selecting all or distinct elements in a query.
|
435
|
+
class SelectionOption
|
436
|
+
attr_reader :option
|
437
|
+
|
438
|
+
def initialize(option)
|
439
|
+
self.option = option
|
440
|
+
end
|
441
|
+
|
442
|
+
def option=(o)
|
443
|
+
begin
|
444
|
+
VOTables::VOTable::Misc::TypeCheck.new(o, AllOrDistinct).check()
|
445
|
+
rescue VOTables::VOTable::Misc::TypeException
|
446
|
+
@option = AllOrDistinct.new(o)
|
447
|
+
else
|
448
|
+
@option = o
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
def content
|
453
|
+
self.option.option
|
454
|
+
end
|
455
|
+
|
456
|
+
def to_s
|
457
|
+
"{option=#{self.option}}"
|
458
|
+
end
|
459
|
+
|
460
|
+
def self.from_xml(node)
|
461
|
+
option = AllOrDistinct.new(node.attributes['Option'])
|
462
|
+
return SelectionOption.new(option)
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
# Enumeration for All and Distinct options.
|
467
|
+
class AllOrDistinct
|
468
|
+
attr_reader :option, :option_list
|
469
|
+
|
470
|
+
@@options = ['ALL', 'DISTINCT']
|
471
|
+
|
472
|
+
def initialize(option, option_list=nil)
|
473
|
+
@option_list = option_list || @@options
|
474
|
+
self.option = option
|
475
|
+
end
|
476
|
+
|
477
|
+
def option=(o)
|
478
|
+
if @option_list.include?(o)
|
479
|
+
@option = o
|
480
|
+
else
|
481
|
+
raise "Option is not valid. Use one of: " +
|
482
|
+
@option_list.join(', ')
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
def to_s
|
487
|
+
"{option=#{self.option}}"
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
# Represents a trigonometric function.
|
492
|
+
class TrigonometricFunction < FunctionType
|
493
|
+
attr_reader :name, :arg, :allow
|
494
|
+
|
495
|
+
def initialize(name, arg, allow=nil)
|
496
|
+
self.name = name
|
497
|
+
self.arg = arg
|
498
|
+
self.allow = allow
|
499
|
+
end
|
500
|
+
|
501
|
+
def name=(n)
|
502
|
+
begin
|
503
|
+
VOTables::VOTable::Misc::TypeCheck.new(n, TrigonometricFunctionName).check()
|
504
|
+
rescue VOTables::VOTable::Misc::TypeException
|
505
|
+
@name = TrigonometricFunctionName.new(n)
|
506
|
+
else
|
507
|
+
@name = n
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
def arg=(a)
|
512
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, SelectionItem).check()
|
513
|
+
@arg = a
|
514
|
+
end
|
515
|
+
|
516
|
+
def allow=(a)
|
517
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, SelectionOption).check()
|
518
|
+
@allow = a
|
519
|
+
end
|
520
|
+
|
521
|
+
def to_s
|
522
|
+
"{name=#{self.name},allow=#{self.allow},arg=#{self.arg}}"
|
523
|
+
end
|
524
|
+
|
525
|
+
def self.from_xml(node)
|
526
|
+
name = TrigonometricFunctionName.from_xml(node)
|
527
|
+
arg_node = REXML::XPath.first(node, 'Arg')
|
528
|
+
arg = Arg.from_xml(arg_node)
|
529
|
+
allow_node = REXML::XPath.first(node, 'Allow')
|
530
|
+
allow = nil
|
531
|
+
if allow_node
|
532
|
+
allow = Allow.from_xml(allow_node)
|
533
|
+
end
|
534
|
+
return TrigonometricFunction.new(name, arg, allow)
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
# Enumeration of allowed trigonometric functions.
|
539
|
+
class TrigonometricFunctionName
|
540
|
+
attr_reader :value, :values_list
|
541
|
+
|
542
|
+
@@values = ['SIN', 'COS', 'TAN', 'COT', 'ASIN', 'ACOS', 'ATAN', 'ATAN2']
|
543
|
+
|
544
|
+
def initialize(value, values_list=nil)
|
545
|
+
@values_list = values_list || @@values
|
546
|
+
self.value = value
|
547
|
+
end
|
548
|
+
|
549
|
+
def value=(v)
|
550
|
+
if @values_list.include?(v)
|
551
|
+
@value = v
|
552
|
+
else
|
553
|
+
raise "Value is not valid. Use one of: " +
|
554
|
+
@values_list.join(', ')
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
def to_s
|
559
|
+
"{value=#{self.value}}"
|
560
|
+
end
|
561
|
+
|
562
|
+
def self.from_xml(node)
|
563
|
+
return TrigonometricFunctionName.new(node.attributes['Name'])
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
# Represents a math function.
|
568
|
+
class MathFunction < FunctionType
|
569
|
+
attr_reader :name, :arg, :allow
|
570
|
+
|
571
|
+
def initialize(name, arg, allow=nil)
|
572
|
+
self.name = name
|
573
|
+
self.arg = arg
|
574
|
+
self.allow = allow
|
575
|
+
end
|
576
|
+
|
577
|
+
def name=(n)
|
578
|
+
begin
|
579
|
+
VOTables::VOTable::Misc::TypeCheck.new(n, MathFunctionName).check()
|
580
|
+
rescue VOTables::VOTable::Misc::TypeException
|
581
|
+
@name = MathFunctionName.new(n)
|
582
|
+
else
|
583
|
+
@name = n
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
def arg=(a)
|
588
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, SelectionItem).check()
|
589
|
+
@arg = a
|
590
|
+
end
|
591
|
+
|
592
|
+
def allow=(a)
|
593
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, SelectionOption).check()
|
594
|
+
@allow = a
|
595
|
+
end
|
596
|
+
|
597
|
+
def self.from_xml(node)
|
598
|
+
name = MathFunctionName.from_xml(node)
|
599
|
+
arg_node = REXML::XPath.first(node, 'Arg')
|
600
|
+
arg = Arg.from_xml(arg_node)
|
601
|
+
allow_node = REXML::XPath.first(node, 'Allow')
|
602
|
+
allow = nil
|
603
|
+
if allow_node
|
604
|
+
allow = Allow.from_xml(allow_node)
|
605
|
+
end
|
606
|
+
return MathFunction.new(name, arg, allow)
|
607
|
+
end
|
608
|
+
|
609
|
+
def to_s
|
610
|
+
"{name=#{self.name},arg=#{self.arg},allow=#{self.allow}}"
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
# Enumeration of allowed math functions.
|
615
|
+
class MathFunctionName
|
616
|
+
attr_reader :value, :values_list
|
617
|
+
|
618
|
+
@@values = ['ABS', 'CEILING', 'DEGREES', 'EXP', 'FLOOR', 'LOG',
|
619
|
+
'PI', 'POWER', 'RADIANS', 'SQRT', 'SQUARE', 'LOG10',
|
620
|
+
'RAND', 'ROUND', 'TRUNCATE']
|
621
|
+
|
622
|
+
def initialize(value, values_list=nil)
|
623
|
+
@values_list = values_list || @@values
|
624
|
+
self.value = value
|
625
|
+
end
|
626
|
+
|
627
|
+
def value=(v)
|
628
|
+
if @values_list.include?(v)
|
629
|
+
@value = v
|
630
|
+
else
|
631
|
+
raise "Value is not valid. Use one of: " +
|
632
|
+
@values_list.join(', ')
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
def to_s
|
637
|
+
"{value=#{self.value}}"
|
638
|
+
end
|
639
|
+
|
640
|
+
def self.from_xml(node)
|
641
|
+
return MathFunctionName.new(node.attributes['Name'])
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
# Represents an aggregate function.
|
646
|
+
class AggregateFunction < FunctionType
|
647
|
+
attr_reader :name, :arg, :allow
|
648
|
+
|
649
|
+
def initialize(name, arg, allow=nil)
|
650
|
+
self.name = name
|
651
|
+
self.arg = arg
|
652
|
+
self.allow = allow
|
653
|
+
end
|
654
|
+
|
655
|
+
def name=(n)
|
656
|
+
begin
|
657
|
+
VOTables::VOTable::Misc::TypeCheck.new(n, AggregateFunctionName).check()
|
658
|
+
rescue VOTables::VOTable::Misc::TypeException
|
659
|
+
@name = AggregateFunctionName.new(n)
|
660
|
+
else
|
661
|
+
@name = n
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
def arg=(a)
|
666
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, SelectionItem).check()
|
667
|
+
@arg = a
|
668
|
+
end
|
669
|
+
|
670
|
+
def allow=(a)
|
671
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, SelectionOption).check()
|
672
|
+
@allow = a
|
673
|
+
end
|
674
|
+
|
675
|
+
def to_s
|
676
|
+
"{name=#{self.name},arg=#{self.arg},allow=#{self.allow}}"
|
677
|
+
end
|
678
|
+
|
679
|
+
def self.from_xml(node)
|
680
|
+
name = AggregateFunctionName.from_xml(node)
|
681
|
+
arg_node = REXML::XPath.first(node, 'Arg')
|
682
|
+
arg = Arg.from_xml(arg_node)
|
683
|
+
allow_node = REXML::XPath.first(node, 'Allow')
|
684
|
+
allow = nil
|
685
|
+
if allow_node
|
686
|
+
allow = Allow.from_xml(allow_node)
|
687
|
+
end
|
688
|
+
return AggregateFunction.new(name, arg, allow)
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
# Enumeration of allowed aggregate functions.
|
693
|
+
class AggregateFunctionName
|
694
|
+
attr_reader :value, :values_list
|
695
|
+
|
696
|
+
@@values = ['AVG', 'MIN', 'MAX', 'SUM', 'COUNT']
|
697
|
+
|
698
|
+
def initialize(value, values_list=nil)
|
699
|
+
@values_list = values_list || @@values
|
700
|
+
self.value = value
|
701
|
+
end
|
702
|
+
|
703
|
+
def value=(v)
|
704
|
+
if @values_list.include?(v)
|
705
|
+
@value = v
|
706
|
+
else
|
707
|
+
raise "Value is not valid. Use one of: " +
|
708
|
+
@values_list.join(', ')
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
def to_s
|
713
|
+
"{value=#{self.value}}"
|
714
|
+
end
|
715
|
+
|
716
|
+
def self.from_xml(node)
|
717
|
+
return AggregateFunctionName.new(node.attributes['Name'])
|
718
|
+
end
|
719
|
+
end
|
720
|
+
|
721
|
+
# Used to select an expression as a new alias column.
|
722
|
+
class AliasSelectionItem < SelectionItem
|
723
|
+
attr_reader :expression
|
724
|
+
attr_accessor :as
|
725
|
+
|
726
|
+
def initialize(expression, as=nil)
|
727
|
+
self.expression = expression
|
728
|
+
self.as = as
|
729
|
+
end
|
730
|
+
|
731
|
+
def expression=(e)
|
732
|
+
begin
|
733
|
+
VOTables::VOTable::Misc::TypeCheck.new(e, ScalarExpression).check()
|
734
|
+
rescue VOTables::VOTable::Misc::TypeException
|
735
|
+
@expression = ScalarExpression.new(e)
|
736
|
+
else
|
737
|
+
@expression = e
|
738
|
+
end
|
739
|
+
end
|
740
|
+
|
741
|
+
def to_s
|
742
|
+
"{expression=#{self.expression},as=#{self.as}}"
|
743
|
+
end
|
744
|
+
|
745
|
+
def self.from_xml(node)
|
746
|
+
as = node.attributes['As']
|
747
|
+
expr_node = REXML::XPath.first(node, 'Expression')
|
748
|
+
expr = ScalarExpression.from_xml(expr_node)
|
749
|
+
return AliasSelectionItem.new(expr, as)
|
750
|
+
end
|
751
|
+
end
|
752
|
+
|
753
|
+
# Represent all columns as in Select * query.
|
754
|
+
class AllSelectionItem < SelectionItem
|
755
|
+
@@value = '*'
|
756
|
+
|
757
|
+
def initialize;end
|
758
|
+
|
759
|
+
def self.value
|
760
|
+
return @@value
|
761
|
+
end
|
762
|
+
|
763
|
+
def to_s
|
764
|
+
"{expression=#{self.value}}"
|
765
|
+
end
|
766
|
+
|
767
|
+
def self.from_xml(node)
|
768
|
+
return AllSelectionItem.new()
|
769
|
+
end
|
770
|
+
end
|
771
|
+
|
772
|
+
# The comparison operators such as Less-than or More-than, etc.
|
773
|
+
class Comparison
|
774
|
+
attr_reader :value, :values_list
|
775
|
+
|
776
|
+
@@values = ['=', '<>', '>', '>=', '<', '<=']
|
777
|
+
|
778
|
+
def initialize(value, values_list=nil)
|
779
|
+
@values_list = values_list || @@values
|
780
|
+
self.value = value
|
781
|
+
end
|
782
|
+
|
783
|
+
def value=(v)
|
784
|
+
if @values_list.include?(v)
|
785
|
+
@value = v
|
786
|
+
else
|
787
|
+
raise "Value is not valid. Use one of: " +
|
788
|
+
@values_list.join(', ')
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
792
|
+
def to_s
|
793
|
+
"{value=#{self.value}}"
|
794
|
+
end
|
795
|
+
|
796
|
+
def self.from_xml(node)
|
797
|
+
return Comparison.new(node.attributes['Comparison'])
|
798
|
+
end
|
799
|
+
end
|
800
|
+
|
801
|
+
# The base type for all tables used in the From clause of the query.
|
802
|
+
class FromTable
|
803
|
+
def self.from_xml(node)
|
804
|
+
type_s = node.find_attribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
|
805
|
+
table = ObjectBuilder.get_class_for(type_s).from_xml(node)
|
806
|
+
end
|
807
|
+
end
|
808
|
+
|
809
|
+
# Same as a TableType with an additional archive name.
|
810
|
+
class ArchiveTable < FromTable
|
811
|
+
attr_accessor :archive, :name, :alias_name
|
812
|
+
|
813
|
+
def initialize(archive, name, alias_name=nil)
|
814
|
+
self.archive = archive
|
815
|
+
self.name = name
|
816
|
+
self.alias_name = alias_name
|
817
|
+
end
|
818
|
+
|
819
|
+
def to_s
|
820
|
+
"{archive=#{self.archive},name=#{self.name},alias=#{self.alias_name}}"
|
821
|
+
end
|
822
|
+
|
823
|
+
def self.from_xml(node)
|
824
|
+
archive = node.attributes['Archive'] or raise "No ArchiveTable attribute 'Archive'"
|
825
|
+
#name = CGI::escapeHTML(node.attributes['Name']) or raise "No ArchiveTable attribute 'Name'"
|
826
|
+
name = node.attributes['Name'] or raise "No ArchiveTable attribute 'Name'"
|
827
|
+
alias_name = node.attributes['Alias']
|
828
|
+
|
829
|
+
at = ArchiveTable.new(archive, name, alias_name)
|
830
|
+
end
|
831
|
+
end
|
832
|
+
|
833
|
+
# Represents a table with its name and its alias name.
|
834
|
+
class Table < FromTable
|
835
|
+
attr_accessor :name, :alias_name, :xpath_name
|
836
|
+
|
837
|
+
def initialize(name, alias_name=nil, xpath_name=nil)
|
838
|
+
self.name = name
|
839
|
+
self.alias_name = alias_name
|
840
|
+
self.xpath_name = xpath_name
|
841
|
+
end
|
842
|
+
|
843
|
+
def to_s
|
844
|
+
"{name=#{self.name},alias=#{self.alias_name},xpath=#{self.xpath_name}}"
|
845
|
+
end
|
846
|
+
|
847
|
+
def self.from_xml(node)
|
848
|
+
type_s = node.find_attribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
|
849
|
+
table = ObjectBuilder.get_class_for(type_s).from_xml(node)
|
850
|
+
end
|
851
|
+
end
|
852
|
+
|
853
|
+
# The base type for all table inclusion or drop types used in a cross match expression.
|
854
|
+
class XMatchTableAlias
|
855
|
+
def to_s
|
856
|
+
"{name=#{self.name}}"
|
857
|
+
end
|
858
|
+
|
859
|
+
def self.from_xml(node)
|
860
|
+
#type_s = node.attributes['xsi:type']
|
861
|
+
type_s = node.find_attribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
|
862
|
+
xtable = ObjectBuilder.get_class_for(type_s).from_xml(node)
|
863
|
+
end
|
864
|
+
end
|
865
|
+
|
866
|
+
# Used for adding a table for the Xmatch operation.
|
867
|
+
class IncludeTable < XMatchTableAlias
|
868
|
+
attr_accessor :name
|
869
|
+
|
870
|
+
def initialize(name)
|
871
|
+
self.name = name
|
872
|
+
end
|
873
|
+
|
874
|
+
def self.from_xml(node)
|
875
|
+
name = node.attributes['Name']
|
876
|
+
return IncludeTable.new(name)
|
877
|
+
end
|
878
|
+
end
|
879
|
+
|
880
|
+
# Used for avoiding a table in Xmatch.
|
881
|
+
class DropTable < XMatchTableAlias
|
882
|
+
attr_accessor :name
|
883
|
+
|
884
|
+
def initialize(name)
|
885
|
+
self.name = name
|
886
|
+
end
|
887
|
+
|
888
|
+
def self.from_xml(node)
|
889
|
+
name = node.attributes['Name']
|
890
|
+
return DropTable.new(name)
|
891
|
+
end
|
892
|
+
end
|
893
|
+
|
894
|
+
# The base type for searches in Where and Having clauses of the query.
|
895
|
+
class Search
|
896
|
+
def self.from_xml(node)
|
897
|
+
type_s = node.find_attribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
|
898
|
+
search = ObjectBuilder.get_class_for(type_s).from_xml(node)
|
899
|
+
end
|
900
|
+
end
|
901
|
+
|
902
|
+
# Represents expressions like a AND b.
|
903
|
+
class IntersectionSearch < Search
|
904
|
+
attr_reader :cond1, :cond2
|
905
|
+
|
906
|
+
def initialize(cond1, cond2)
|
907
|
+
self.cond1 = cond1
|
908
|
+
self.cond2 = cond2
|
909
|
+
end
|
910
|
+
|
911
|
+
def cond1=(cond)
|
912
|
+
VOTables::VOTable::Misc::TypeCheck.new(cond, Search).check()
|
913
|
+
@cond1 = cond
|
914
|
+
end
|
915
|
+
|
916
|
+
def cond2=(cond)
|
917
|
+
VOTables::VOTable::Misc::TypeCheck.new(cond, Search).check()
|
918
|
+
@cond2 = cond
|
919
|
+
end
|
920
|
+
|
921
|
+
def to_s
|
922
|
+
"{cond1=#{self.cond1},cond2=#{self.cond2}}"
|
923
|
+
end
|
924
|
+
|
925
|
+
def self.from_xml(node)
|
926
|
+
cond1_node, cond2_node = node.elements.to_a('Condition')
|
927
|
+
cond1 = Search.from_xml(cond1_node)
|
928
|
+
cond2 = Search.from_xml(cond2_node)
|
929
|
+
return IntersectionSearch.new(cond1, cond2)
|
930
|
+
end
|
931
|
+
|
932
|
+
# This method finds a condition given its attributes and it returns it
|
933
|
+
def find_condition(type, attributes)
|
934
|
+
condition = self.cond1.find_condition(type, attributes)
|
935
|
+
if condition == nil
|
936
|
+
condition = self.cond2.find_condition(type, attributes)
|
937
|
+
end
|
938
|
+
|
939
|
+
return condition
|
940
|
+
end
|
941
|
+
|
942
|
+
# This method removes a condition. -1 means that the condition must
|
943
|
+
# be removed. 1 means that the condition given its attributes wasn't
|
944
|
+
# found, so that the process must continue.
|
945
|
+
def remove_condition(type, attributes)
|
946
|
+
cond1 = self.cond1.remove_condition(type, attributes)
|
947
|
+
if cond1 == -1
|
948
|
+
return self.cond2
|
949
|
+
elsif cond1 == 1
|
950
|
+
cond2 = self.cond2.remove_condition(type, attributes)
|
951
|
+
if cond2 == -1
|
952
|
+
return self.cond1
|
953
|
+
elsif cond2 == 1
|
954
|
+
return 1
|
955
|
+
end
|
956
|
+
else
|
957
|
+
self.cond1 = cond1
|
958
|
+
return self
|
959
|
+
end
|
960
|
+
end
|
961
|
+
|
962
|
+
# This method modifies a condition given its old attributes,
|
963
|
+
# replacing the old attributes with the new attributes.
|
964
|
+
def modify_condition(type, attributes_old, attributes_new)
|
965
|
+
cond1 = self.cond1.modify_condition(type, attributes_old, attributes_new)
|
966
|
+
if cond1 != nil
|
967
|
+
self.cond1 = cond1
|
968
|
+
else
|
969
|
+
cond2 = self.cond2.modify_condition(type, attributes_old, attributes_new)
|
970
|
+
if cond2 != nil
|
971
|
+
self.cond2 = cond2
|
972
|
+
else
|
973
|
+
return nil
|
974
|
+
end
|
975
|
+
end
|
976
|
+
|
977
|
+
return self
|
978
|
+
end
|
979
|
+
|
980
|
+
# This method replaces a condition for a new condition. -1 means that
|
981
|
+
# the condition must be replaced for the new condition. 1 means that
|
982
|
+
# the process must continue.
|
983
|
+
def replace_condition(type, attributes, new_condition)
|
984
|
+
cond1 = self.cond1.replace_condition(type, attributes, new_condition)
|
985
|
+
if cond1 == -1
|
986
|
+
self.cond1 = new_condition
|
987
|
+
return self
|
988
|
+
elsif cond1 == 1
|
989
|
+
cond2 = self.cond2.replace_condition(type, attributes, new_condition)
|
990
|
+
if cond2 == -1
|
991
|
+
self.cond2 = new_condition
|
992
|
+
return self
|
993
|
+
elsif cond2 == 1
|
994
|
+
return 1
|
995
|
+
end
|
996
|
+
else
|
997
|
+
return self
|
998
|
+
end
|
999
|
+
end
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
# Represents expressions like A Or B.
|
1003
|
+
class UnionSearch < Search
|
1004
|
+
attr_reader :cond1, :cond2
|
1005
|
+
|
1006
|
+
def initialize(cond1, cond2)
|
1007
|
+
self.cond1 = cond1
|
1008
|
+
self.cond2 = cond2
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
def cond1=(cond)
|
1012
|
+
VOTables::VOTable::Misc::TypeCheck.new(cond, Search).check()
|
1013
|
+
@cond1 = cond
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
def cond2=(cond)
|
1017
|
+
VOTables::VOTable::Misc::TypeCheck.new(cond, Search).check()
|
1018
|
+
@cond2 = cond
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
def to_s
|
1022
|
+
"{cond1=#{self.cond1},cond2=#{self.cond2}}"
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
def self.from_xml(node)
|
1026
|
+
cond1_node, cond2_node = node.elements.to_a('Condition')
|
1027
|
+
cond1 = Search.from_xml(cond1_node)
|
1028
|
+
cond2 = Search.from_xml(cond2_node)
|
1029
|
+
return UnionSearch.new(cond1, cond2)
|
1030
|
+
end
|
1031
|
+
|
1032
|
+
# This method finds a condition given its attributes and it returns it
|
1033
|
+
def find_condition(type, attributes)
|
1034
|
+
condition = self.cond1.find_condition(type, attributes)
|
1035
|
+
if condition == nil
|
1036
|
+
condition = self.cond2.find_condition(type, attributes)
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
return condition
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
# This method removes a condition. -1 means that the condition must
|
1043
|
+
# be removed. 1 means that the condition given its attributes wasn't
|
1044
|
+
# found, so that the process must continue.
|
1045
|
+
def remove_condition(type, attributes)
|
1046
|
+
cond1 = self.cond1.remove_condition(type, attributes)
|
1047
|
+
if cond1 == -1
|
1048
|
+
return self.cond2
|
1049
|
+
elsif cond1 == 1
|
1050
|
+
cond2 = self.cond2.remove_condition(type, attributes)
|
1051
|
+
if cond2 == -1
|
1052
|
+
return self.cond1
|
1053
|
+
elsif cond2 == 1
|
1054
|
+
return 1
|
1055
|
+
end
|
1056
|
+
else
|
1057
|
+
self.cond1 = cond1
|
1058
|
+
return self
|
1059
|
+
end
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
# This method modifies a condition given its old attributes,
|
1063
|
+
# replacing the old attributes with the new attributes.
|
1064
|
+
def modify_condition(type, attributes_old, attributes_new)
|
1065
|
+
cond1 = self.cond1.modify_condition(type, attributes_old, attributes_new)
|
1066
|
+
if cond1 != nil
|
1067
|
+
self.cond1 = cond1
|
1068
|
+
else
|
1069
|
+
cond2 = self.cond2.modify_condition(type, attributes_old, attributes_new)
|
1070
|
+
if cond2 != nil
|
1071
|
+
self.cond2 = cond2
|
1072
|
+
else
|
1073
|
+
return nil
|
1074
|
+
end
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
return self
|
1078
|
+
end
|
1079
|
+
|
1080
|
+
# This method replaces a condition for a new condition. -1 means that
|
1081
|
+
# the condition must be replaced for the new condition. 1 means that
|
1082
|
+
# the process must continue
|
1083
|
+
def replace_condition(type, attributes, new_condition)
|
1084
|
+
cond1 = self.cond1.replace_condition(type, attributes, new_condition)
|
1085
|
+
if cond1 == -1
|
1086
|
+
self.cond1 = new_condition
|
1087
|
+
return self
|
1088
|
+
elsif cond1 == 1
|
1089
|
+
cond2 = self.cond2.replace_condition(type, attributes, new_condition)
|
1090
|
+
if cond2 == -1
|
1091
|
+
self.cond2 = new_condition
|
1092
|
+
return self
|
1093
|
+
elsif cond2 == 1
|
1094
|
+
return 1
|
1095
|
+
end
|
1096
|
+
else
|
1097
|
+
return self
|
1098
|
+
end
|
1099
|
+
end
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
# A cross match expression.
|
1103
|
+
class XMatch < Search
|
1104
|
+
attr_reader :tables, :nature, :sigma
|
1105
|
+
|
1106
|
+
def initialize(tables, nature, sigma)
|
1107
|
+
self.tables = tables
|
1108
|
+
self.nature = nature
|
1109
|
+
self.sigma = sigma
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
def tables=(ts)
|
1113
|
+
raise "Specify at least two tables" if !ts or ts.length < 2
|
1114
|
+
|
1115
|
+
ts.each do |t|
|
1116
|
+
VOTables::VOTable::Misc::TypeCheck.new(t, XMatchTableAlias)
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
@tables = ts
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
def nature=(n)
|
1123
|
+
begin
|
1124
|
+
VOTables::VOTable::Misc::TypeCheck.new(n, Comparison).check()
|
1125
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1126
|
+
@nature = Comparison.new(n)
|
1127
|
+
else
|
1128
|
+
@nature = n
|
1129
|
+
end
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
def sigma=(s)
|
1133
|
+
begin
|
1134
|
+
VOTables::VOTable::Misc::TypeCheck.new(s, NumberType).check()
|
1135
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1136
|
+
if s.is_a?(Float)
|
1137
|
+
@sigma = RealType.new(s)
|
1138
|
+
elsif s.is_a?(Integer)
|
1139
|
+
@sigma = IntegerType.new(s)
|
1140
|
+
else
|
1141
|
+
raise "Sigma must be a float or integer"
|
1142
|
+
end
|
1143
|
+
else
|
1144
|
+
@sigma = s
|
1145
|
+
end
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
def to_s
|
1149
|
+
tables = self.tables.collect{|x| x.to_s}.join('|')
|
1150
|
+
"{tables=#{tables},nature=#{self.nature},sigma=#{self.sigma}}"
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
def self.from_xml(node)
|
1154
|
+
tables = []
|
1155
|
+
node.elements.each('Table') do |tbl_node|
|
1156
|
+
table = XMatchTableAlias.from_xml(tbl_node)
|
1157
|
+
tables.push(table)
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
nature_node = REXML::XPath.first(node, 'Nature')
|
1161
|
+
nature = Nature.from_xml(nature_node)
|
1162
|
+
|
1163
|
+
sigma_node = REXML::XPath.first(node, 'Sigma')
|
1164
|
+
sigma = Sigma.from_xml(sigma_node)
|
1165
|
+
|
1166
|
+
return XMatch.new(tables, nature, sigma)
|
1167
|
+
end
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
# The Like expression of a query.
|
1171
|
+
class LikePred < Search
|
1172
|
+
attr_reader :arg, :pattern
|
1173
|
+
|
1174
|
+
def initialize(arg, pattern)
|
1175
|
+
self.arg = arg
|
1176
|
+
self.pattern = pattern
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
def arg=(a)
|
1180
|
+
begin
|
1181
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, ScalarExpression).check()
|
1182
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1183
|
+
@arg = ScalarExpression.new(a)
|
1184
|
+
else
|
1185
|
+
@arg = a
|
1186
|
+
end
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
def pattern=(p)
|
1190
|
+
begin
|
1191
|
+
VOTables::VOTable::Misc::TypeCheck.new(p, Atom).check()
|
1192
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1193
|
+
@pattern = Atom.new(p)
|
1194
|
+
else
|
1195
|
+
@pattern = p
|
1196
|
+
end
|
1197
|
+
end
|
1198
|
+
|
1199
|
+
def to_s
|
1200
|
+
"{arg=#{self.arg},pattern=#{self.pattern}}"
|
1201
|
+
end
|
1202
|
+
|
1203
|
+
def self.from_xml(node)
|
1204
|
+
arg_node = REXML::XPath.first(node, 'Arg')
|
1205
|
+
arg = Arg.from_xml(arg_node)
|
1206
|
+
pattern_node = REXML::XPath.first(node, 'Pattern')
|
1207
|
+
pattern = Pattern.from_xml(pattern_node)
|
1208
|
+
|
1209
|
+
return LikePred.new(arg, pattern)
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
def self.create_new_object(attributes)
|
1213
|
+
arg = ColumnReference.new(attributes['table'], attributes['name'], nil)
|
1214
|
+
pattern = StringType.new(attributes['pattern'])
|
1215
|
+
return LikePred.new(arg, pattern)
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
def match_attributtes(attributes)
|
1219
|
+
return true if self.arg.table == attributes['table'] and
|
1220
|
+
self.arg.name == attributes['name'] and
|
1221
|
+
self.pattern.literal.value == attributes['pattern']
|
1222
|
+
return false
|
1223
|
+
end
|
1224
|
+
|
1225
|
+
# This method finds a condition given its attributes and it returns it
|
1226
|
+
def find_condition(type, attributes)
|
1227
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1228
|
+
return self if self.match_attributtes(attributes)
|
1229
|
+
return nil
|
1230
|
+
end
|
1231
|
+
return nil
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
# This method removes a condition. -1 means that the condition must
|
1235
|
+
# be removed. 1 means that the condition given its attributes wasn't
|
1236
|
+
# found, so that the process must continue.
|
1237
|
+
def remove_condition(type, attributes)
|
1238
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1239
|
+
return -1 if self.match_attributtes(attributes)
|
1240
|
+
return 1
|
1241
|
+
end
|
1242
|
+
return 1
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
# This method modifies a condition given its old attributes,
|
1246
|
+
# replacing the old attributes with the new attributes.
|
1247
|
+
def modify_condition(type, attributes_old, attributes_new)
|
1248
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1249
|
+
if self.match_attributtes(attributes_old)
|
1250
|
+
return LikePred.create_new_object(attributes_new)
|
1251
|
+
else
|
1252
|
+
return nil
|
1253
|
+
end
|
1254
|
+
end
|
1255
|
+
return nil
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
# This method replaces a condition given its attributes.
|
1259
|
+
# Returns -1 if the object must be replaced, or returns 1 if
|
1260
|
+
# isn't the object that must be replaced, so the process must continue
|
1261
|
+
def replace_condition(type, attributes, new_condition)
|
1262
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1263
|
+
return -1 if self.match_attributtes(attributes)
|
1264
|
+
return 1
|
1265
|
+
end
|
1266
|
+
return 1
|
1267
|
+
end
|
1268
|
+
end
|
1269
|
+
|
1270
|
+
# The Not Like expression of a query.
|
1271
|
+
class NotLikePred < LikePred
|
1272
|
+
def self.from_xml(node)
|
1273
|
+
arg_node = REXML::XPath.first(node, 'Arg')
|
1274
|
+
arg = Arg.from_xml(arg_node)
|
1275
|
+
pattern_node = REXML::XPath.first(node, 'Pattern')
|
1276
|
+
pattern = Pattern.from_xml(pattern_node)
|
1277
|
+
return NotLikePred.new(arg, pattern)
|
1278
|
+
end
|
1279
|
+
end
|
1280
|
+
|
1281
|
+
# Represents SQL NOT IN expression.
|
1282
|
+
class ExclusiveSearch < Search
|
1283
|
+
attr_reader :expression, :set
|
1284
|
+
|
1285
|
+
def initialize(expression, set)
|
1286
|
+
self.expression = expression
|
1287
|
+
self.set = set
|
1288
|
+
end
|
1289
|
+
|
1290
|
+
def expression=(e)
|
1291
|
+
begin
|
1292
|
+
VOTables::VOTable::Misc::TypeCheck.new(e, ScalarExpression).check()
|
1293
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1294
|
+
@expression = ScalarExpression.new(e)
|
1295
|
+
else
|
1296
|
+
@expression = e
|
1297
|
+
end
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
def set=(s)
|
1301
|
+
VOTables::VOTable::Misc::TypeCheck.new(s, InclusionSet).check()
|
1302
|
+
@set = s
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
def to_s
|
1306
|
+
"{expression=#{self.expression},set=#{self.set}}"
|
1307
|
+
end
|
1308
|
+
|
1309
|
+
def self.from_xml(node)
|
1310
|
+
expr_node = REXML::XPath.first(node, 'Expression')
|
1311
|
+
expr = Expression.from_xml(expr_node)
|
1312
|
+
set_node = REXML::XPath.first(node, 'Set')
|
1313
|
+
set = Set.from_xml(set_node)
|
1314
|
+
return ExclusiveSearch.new(expr, set)
|
1315
|
+
end
|
1316
|
+
end
|
1317
|
+
|
1318
|
+
# The base type for selection set in a SQL IN expression.
|
1319
|
+
class InclusionSet
|
1320
|
+
def self.from_xml(node)
|
1321
|
+
#type_s = node.attributes['xsi:type']
|
1322
|
+
type_s = node.find_attribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
|
1323
|
+
return ObjectBuilder.get_class_for(type_s).from_xml(node)
|
1324
|
+
end
|
1325
|
+
end
|
1326
|
+
|
1327
|
+
# Represents the subquery in a SQL IN expression.
|
1328
|
+
class SubQuerySet < InclusionSet
|
1329
|
+
attr_reader :selection
|
1330
|
+
|
1331
|
+
def initialize(selection)
|
1332
|
+
self.selection = selection
|
1333
|
+
end
|
1334
|
+
|
1335
|
+
def selection=(s)
|
1336
|
+
VOTables::VOTable::Misc::TypeCheck.new(s, Select).check()
|
1337
|
+
@selection = s
|
1338
|
+
end
|
1339
|
+
|
1340
|
+
def to_s
|
1341
|
+
"{selection=#{self.selection}}"
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
def self.from_xml(node)
|
1345
|
+
select_node = REXML::XPath.first(node, 'Select')
|
1346
|
+
select = Select.from_xml(select_node)
|
1347
|
+
return SubQuerySet.new(select)
|
1348
|
+
end
|
1349
|
+
end
|
1350
|
+
|
1351
|
+
# Represents expressions like (A).
|
1352
|
+
class ClosedSearch < Search
|
1353
|
+
attr_reader :condition
|
1354
|
+
|
1355
|
+
def initialize(condition)
|
1356
|
+
self.condition = condition
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
def condition=(c)
|
1360
|
+
VOTables::VOTable::Misc::TypeCheck.new(c, Search).check()
|
1361
|
+
@condition = c
|
1362
|
+
end
|
1363
|
+
|
1364
|
+
def to_s
|
1365
|
+
"{condition=#{self.condition}}"
|
1366
|
+
end
|
1367
|
+
|
1368
|
+
def self.from_xml(node)
|
1369
|
+
cond_node = REXML::XPath.first(node, 'Condition')
|
1370
|
+
cond = Condition.from_xml(cond_node)
|
1371
|
+
return ClosedSearch.new(cond)
|
1372
|
+
end
|
1373
|
+
end
|
1374
|
+
|
1375
|
+
# Represents the Comparison of two expressions.
|
1376
|
+
class ComparisonPred < Search
|
1377
|
+
attr_reader :arg1, :arg2, :comparison
|
1378
|
+
|
1379
|
+
def initialize(arg1, comparison, arg2)
|
1380
|
+
self.arg1 = arg1
|
1381
|
+
self.comparison = comparison
|
1382
|
+
self.arg2 = arg2
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
def arg1=(a)
|
1386
|
+
begin
|
1387
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, ScalarExpression).check()
|
1388
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1389
|
+
@arg1 = ScalarExpression.new(a)
|
1390
|
+
else
|
1391
|
+
@arg1 = a
|
1392
|
+
end
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
def arg2=(a)
|
1396
|
+
begin
|
1397
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, ScalarExpression).check()
|
1398
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1399
|
+
@arg2 = ScalarExpression.new(a)
|
1400
|
+
else
|
1401
|
+
@arg2 = a
|
1402
|
+
end
|
1403
|
+
end
|
1404
|
+
|
1405
|
+
def comparison=(c)
|
1406
|
+
begin
|
1407
|
+
VOTables::VOTable::Misc::TypeCheck.new(c, Comparison).check()
|
1408
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1409
|
+
@comparison = Comparison.new(c)
|
1410
|
+
else
|
1411
|
+
@comparison = c
|
1412
|
+
end
|
1413
|
+
end
|
1414
|
+
|
1415
|
+
def to_s
|
1416
|
+
"{arg1=#{self.arg1},comparison=#{self.comparison},arg2=#{self.arg2}}"
|
1417
|
+
end
|
1418
|
+
|
1419
|
+
def self.from_xml(node)
|
1420
|
+
comparison_s = node.attributes['Comparison']
|
1421
|
+
arg1_node, arg2_node = node.elements.to_a('Arg')
|
1422
|
+
arg1 = Arg.from_xml(arg1_node)
|
1423
|
+
arg2 = Arg.from_xml(arg2_node)
|
1424
|
+
|
1425
|
+
return ComparisonPred.new(arg1, comparison_s, arg2)
|
1426
|
+
end
|
1427
|
+
|
1428
|
+
def self.create_new_object(attributes)
|
1429
|
+
arg1 = ColumnReference.new(attributes['table'], attributes['name'], nil)
|
1430
|
+
|
1431
|
+
arg2 = nil
|
1432
|
+
if attributes['value'].is_a?(Float)
|
1433
|
+
arg2 = Atom.new(RealType.new(attributes['value']))
|
1434
|
+
elsif attributes['value'].is_a?(Integer)
|
1435
|
+
arg2 = Atom.new(IntegerType.new(attributes['value']))
|
1436
|
+
elsif attributes['value'].is_a?(String)
|
1437
|
+
arg2 = Atom.new(StringType.new(attributes['value']))
|
1438
|
+
else
|
1439
|
+
raise "value is not a real, integer or string"
|
1440
|
+
end
|
1441
|
+
|
1442
|
+
return ComparisonPred.new(arg1, attributes['comparison'], arg2)
|
1443
|
+
end
|
1444
|
+
|
1445
|
+
def match_attributtes(attributes)
|
1446
|
+
return true if self.arg1.table == attributes['table'] and
|
1447
|
+
self.arg1.name == attributes['name'] and
|
1448
|
+
self.comparison.value == attributes['comparison'] and
|
1449
|
+
self.arg2.literal.value == attributes['value']
|
1450
|
+
return false
|
1451
|
+
end
|
1452
|
+
|
1453
|
+
# This method finds a condition given its attributes and it returns it
|
1454
|
+
def find_condition(type, attributes)
|
1455
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1456
|
+
return self if self.match_attributtes(attributes)
|
1457
|
+
return nil
|
1458
|
+
end
|
1459
|
+
return nil
|
1460
|
+
end
|
1461
|
+
|
1462
|
+
# This method removes a condition. -1 means that the condition must
|
1463
|
+
# be removed. 1 means that the condition given its attributes wasn't
|
1464
|
+
# found, so that the process must continue.
|
1465
|
+
def remove_condition(type, attributes)
|
1466
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1467
|
+
return -1 if self.match_attributtes(attributes)
|
1468
|
+
return 1
|
1469
|
+
end
|
1470
|
+
return 1
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
# This method modifies a condition given its old attributes,
|
1474
|
+
# replacing the old attributes with the new attributes.
|
1475
|
+
def modify_condition(type, attributes_old, attributes_new)
|
1476
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1477
|
+
if self.match_attributtes(attributes_old)
|
1478
|
+
return ComparisonPred.create_new_object(attributes_new)
|
1479
|
+
else
|
1480
|
+
return nil
|
1481
|
+
end
|
1482
|
+
end
|
1483
|
+
return nil
|
1484
|
+
end
|
1485
|
+
|
1486
|
+
# This method replaces a condition given its attributes.
|
1487
|
+
# Returns -1 if the object must be replaced, or returns 1 if
|
1488
|
+
# isn't the object that must be replaced, so the process must continue
|
1489
|
+
def replace_condition(type, attributes, new_condition)
|
1490
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1491
|
+
return -1 if self.match_attributtes(attributes)
|
1492
|
+
return 1
|
1493
|
+
end
|
1494
|
+
return 1
|
1495
|
+
end
|
1496
|
+
end
|
1497
|
+
|
1498
|
+
# Represents the Between expression of a query.
|
1499
|
+
class BetweenPred < Search
|
1500
|
+
attr_reader :arg1, :arg2, :arg3
|
1501
|
+
|
1502
|
+
def initialize(arg1, arg2, arg3)
|
1503
|
+
self.arg1 = arg1
|
1504
|
+
self.arg2 = arg2
|
1505
|
+
self.arg3 = arg3
|
1506
|
+
end
|
1507
|
+
|
1508
|
+
def arg1=(a)
|
1509
|
+
begin
|
1510
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, ScalarExpression).check()
|
1511
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1512
|
+
@arg1 = ScalarExpression.new(a)
|
1513
|
+
else
|
1514
|
+
@arg1 = a
|
1515
|
+
end
|
1516
|
+
end
|
1517
|
+
|
1518
|
+
def arg2=(a)
|
1519
|
+
begin
|
1520
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, ScalarExpression).check()
|
1521
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1522
|
+
@arg2 = ScalarExpression.new(a)
|
1523
|
+
else
|
1524
|
+
@arg2 = a
|
1525
|
+
end
|
1526
|
+
end
|
1527
|
+
|
1528
|
+
def arg3=(a)
|
1529
|
+
begin
|
1530
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, ScalarExpression).check()
|
1531
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1532
|
+
@arg3 = ScalarExpression.new(a)
|
1533
|
+
else
|
1534
|
+
@arg3 = a
|
1535
|
+
end
|
1536
|
+
end
|
1537
|
+
|
1538
|
+
def to_s
|
1539
|
+
"{arg1=#{self.arg1},arg2=#{self.arg2},arg3=#{self.arg3}}"
|
1540
|
+
end
|
1541
|
+
|
1542
|
+
def self.from_xml(node)
|
1543
|
+
arg1_node, arg2_node, arg3_node = node.elements.to_a('Arg')
|
1544
|
+
arg1 = Arg.from_xml(arg1_node)
|
1545
|
+
arg2 = Arg.from_xml(arg2_node)
|
1546
|
+
arg3 = Arg.from_xml(arg3_node)
|
1547
|
+
|
1548
|
+
return BetweenPred.new(arg1, arg2, arg3)
|
1549
|
+
end
|
1550
|
+
|
1551
|
+
def self.create_new_object(attributes)
|
1552
|
+
arg1 = ColumnReference.new(attributes['table'], attributes['name'], nil)
|
1553
|
+
|
1554
|
+
arg2 = nil
|
1555
|
+
arg3 = nil
|
1556
|
+
if attributes['value_min'].is_a?(Float) and attributes['value_max'].is_a?(Float)
|
1557
|
+
arg2 = Atom.new(RealType.new(attributes['value_min']))
|
1558
|
+
arg3 = Atom.new(RealType.new(attributes['value_max']))
|
1559
|
+
elsif attributes['value_min'].is_a?(Integer) and attributes['value_max'].is_a?(Integer)
|
1560
|
+
arg2 = Atom.new(IntegerType.new(attributes['value_min']))
|
1561
|
+
arg3 = Atom.new(IntegerType.new(attributes['value_max']))
|
1562
|
+
else
|
1563
|
+
raise "value is not a real or integer"
|
1564
|
+
end
|
1565
|
+
|
1566
|
+
return BetweenPred.new(arg1, arg2, arg3)
|
1567
|
+
end
|
1568
|
+
|
1569
|
+
def match_attributtes(attributes)
|
1570
|
+
return true if self.arg1.table == attributes['table'] and
|
1571
|
+
self.arg1.name == attributes['name'] and
|
1572
|
+
self.arg2.literal.value == attributes['value_min'] and
|
1573
|
+
self.arg3.literal.value == attributes['value_max']
|
1574
|
+
return false
|
1575
|
+
end
|
1576
|
+
|
1577
|
+
# This method finds a condition given its attributes and it returns it
|
1578
|
+
def find_condition(type, attributes)
|
1579
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1580
|
+
return self if self.match_attributtes(attributes)
|
1581
|
+
return nil
|
1582
|
+
end
|
1583
|
+
return nil
|
1584
|
+
end
|
1585
|
+
|
1586
|
+
# This method removes a condition. -1 means that the condition must
|
1587
|
+
# be removed. 1 means that the condition given its attributes wasn't
|
1588
|
+
# found, so that the process must continue.
|
1589
|
+
def remove_condition(type, attributes)
|
1590
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1591
|
+
return -1 if self.match_attributtes(attributes)
|
1592
|
+
return 1
|
1593
|
+
end
|
1594
|
+
return 1
|
1595
|
+
end
|
1596
|
+
|
1597
|
+
# This method modifies a condition given its old attributes,
|
1598
|
+
# replacing the old attributes with the new attributes.
|
1599
|
+
def modify_condition(type, attributes_old, attributes_new)
|
1600
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1601
|
+
if self.match_attributtes(attributes_old)
|
1602
|
+
return BetweenPred.create_new_object(attributes_new)
|
1603
|
+
else
|
1604
|
+
return nil
|
1605
|
+
end
|
1606
|
+
end
|
1607
|
+
return nil
|
1608
|
+
end
|
1609
|
+
|
1610
|
+
# This method replaces a condition given its attributes.
|
1611
|
+
# Returns -1 if the object must be replaced, or returns 1 if
|
1612
|
+
# isn't the object that must be replaced, so the process must continue
|
1613
|
+
def replace_condition(type, attributes, new_condition)
|
1614
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1615
|
+
return -1 if self.match_attributtes(attributes)
|
1616
|
+
return 1
|
1617
|
+
end
|
1618
|
+
return 1
|
1619
|
+
end
|
1620
|
+
end
|
1621
|
+
|
1622
|
+
# Represents expressions like Not A.
|
1623
|
+
class NotBetweenPred < BetweenPred
|
1624
|
+
def self.from_xml(node)
|
1625
|
+
arg1_node, arg2_node, arg3_node = node.elements.to_a('Arg')
|
1626
|
+
arg1 = Arg.from_xml(arg1_node)
|
1627
|
+
arg2 = Arg.from_xml(arg2_node)
|
1628
|
+
arg3 = Arg.from_xml(arg3_node)
|
1629
|
+
return NotBetweenPred.new(arg1, arg2, arg3)
|
1630
|
+
end
|
1631
|
+
end
|
1632
|
+
|
1633
|
+
# Abstract Shape type. Shape definitions; Allsky, Circle, Polygon,
|
1634
|
+
# Box, and Sector are derived from Shape; Ellipse is derived from
|
1635
|
+
# Circle; Polygon includes also Vertex and SmallCircle
|
1636
|
+
class Shape
|
1637
|
+
def self.from_xml(node)
|
1638
|
+
type_s = node.find_attribute('type', 'http://www.w3.org/2001/XMLSchema-instance')
|
1639
|
+
type_s = type_s.slice(type_s.index(':')+1, type_s.length)
|
1640
|
+
return ObjectBuilder.get_class_for(type_s).from_xml(node)
|
1641
|
+
end
|
1642
|
+
end
|
1643
|
+
|
1644
|
+
# Circle shape. The circle is defined by a center and a radius
|
1645
|
+
class Circle < Shape
|
1646
|
+
attr_reader :ra, :dec, :radius, :system, :shape
|
1647
|
+
|
1648
|
+
def initialize(ra, dec, radius, system='J2000')
|
1649
|
+
self.ra = ra
|
1650
|
+
self.dec = dec
|
1651
|
+
self.radius = radius
|
1652
|
+
self.system = system
|
1653
|
+
self.shape = 'CIRCLE'
|
1654
|
+
end
|
1655
|
+
|
1656
|
+
def ra=(ra)
|
1657
|
+
begin
|
1658
|
+
VOTables::VOTable::Misc::TypeCheck.new(ra, RealType).check()
|
1659
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1660
|
+
@ra = RealType.new(ra)
|
1661
|
+
else
|
1662
|
+
@ra = ra
|
1663
|
+
end
|
1664
|
+
end
|
1665
|
+
|
1666
|
+
def dec=(dec)
|
1667
|
+
begin
|
1668
|
+
VOTables::VOTable::Misc::TypeCheck.new(dec, RealType).check()
|
1669
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1670
|
+
@dec = RealType.new(dec)
|
1671
|
+
else
|
1672
|
+
@dec = dec
|
1673
|
+
end
|
1674
|
+
end
|
1675
|
+
|
1676
|
+
def radius=(radius)
|
1677
|
+
begin
|
1678
|
+
VOTables::VOTable::Misc::TypeCheck.new(radius, RealType).check()
|
1679
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1680
|
+
@radius = RealType.new(radius)
|
1681
|
+
else
|
1682
|
+
@radius = radius
|
1683
|
+
end
|
1684
|
+
end
|
1685
|
+
|
1686
|
+
def system=(sys)
|
1687
|
+
begin
|
1688
|
+
VOTables::VOTable::Misc::TypeCheck.new(sys, StringType).check()
|
1689
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1690
|
+
@system = StringType.new(sys)
|
1691
|
+
else
|
1692
|
+
@system = sys
|
1693
|
+
end
|
1694
|
+
end
|
1695
|
+
|
1696
|
+
def shape=(sh)
|
1697
|
+
begin
|
1698
|
+
VOTables::VOTable::Misc::TypeCheck.new(sh, StringType).check()
|
1699
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1700
|
+
@shape = StringType.new(sh)
|
1701
|
+
else
|
1702
|
+
@shape = sh
|
1703
|
+
end
|
1704
|
+
end
|
1705
|
+
|
1706
|
+
def to_s
|
1707
|
+
"{shape=#{self.shape},system=#{self.system},ra=#{self.ra},dec=#{self.dec},radius=#{self.radius}}"
|
1708
|
+
end
|
1709
|
+
|
1710
|
+
def self.from_xml(node)
|
1711
|
+
unit = node.attributes['unit'] || 'deg'
|
1712
|
+
|
1713
|
+
center = REXML::XPath.first(node, 'reg:Center', {'reg' => 'http://www.ivoa.net/xml/STC/STCregion/v1.10'}).text
|
1714
|
+
ra_s, dec_s = center.split(/\s+/)
|
1715
|
+
ra = RealType.new(ra_s.to_f)
|
1716
|
+
dec = RealType.new(dec_s.to_f)
|
1717
|
+
|
1718
|
+
radius_s = REXML::XPath.first(node, 'reg:Radius', {'reg' => 'http://www.ivoa.net/xml/STC/STCregion/v1.10'}).text
|
1719
|
+
radius = RealType.new(radius_s.to_f)
|
1720
|
+
|
1721
|
+
return Circle.new(ra, dec, radius)
|
1722
|
+
end
|
1723
|
+
|
1724
|
+
def self.create_new_object(attributes)
|
1725
|
+
ra = RealType.new(attributes['ra'])
|
1726
|
+
dec = RealType.new(attributes['dec'])
|
1727
|
+
radius = RealType.new(attributes['radius'])
|
1728
|
+
|
1729
|
+
return Circle.new(ra, dec, radius)
|
1730
|
+
end
|
1731
|
+
|
1732
|
+
def match_attributtes(attributes)
|
1733
|
+
return true if self.ra.value == attributes['ra'] and
|
1734
|
+
self.dec.value == attributes['dec'] and
|
1735
|
+
self.radius.value == attributes['radius']
|
1736
|
+
return false
|
1737
|
+
end
|
1738
|
+
end
|
1739
|
+
|
1740
|
+
# Box shape. The box is defined by a center and a size
|
1741
|
+
class Box < Shape
|
1742
|
+
attr_reader :ra, :dec, :dra, :ddec, :system, :shape
|
1743
|
+
|
1744
|
+
def initialize(ra, dec, dra, ddec, system='J2000')
|
1745
|
+
self.ra = ra
|
1746
|
+
self.dec = dec
|
1747
|
+
self.dra = dra#deltha RA
|
1748
|
+
self.ddec = ddec#deltha DEC
|
1749
|
+
self.system = system
|
1750
|
+
self.shape = 'BOX'
|
1751
|
+
end
|
1752
|
+
|
1753
|
+
def ra=(ra)
|
1754
|
+
begin
|
1755
|
+
VOTables::VOTable::Misc::TypeCheck.new(ra, RealType).check()
|
1756
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1757
|
+
@ra = RealType.new(ra)
|
1758
|
+
else
|
1759
|
+
@ra = ra
|
1760
|
+
end
|
1761
|
+
end
|
1762
|
+
|
1763
|
+
def dec=(dec)
|
1764
|
+
begin
|
1765
|
+
VOTables::VOTable::Misc::TypeCheck.new(dec, RealType).check()
|
1766
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1767
|
+
@dec = RealType.new(dec)
|
1768
|
+
else
|
1769
|
+
@dec = dec
|
1770
|
+
end
|
1771
|
+
end
|
1772
|
+
|
1773
|
+
def dra=(dra)
|
1774
|
+
begin
|
1775
|
+
VOTables::VOTable::Misc::TypeCheck.new(dra, RealType).check()
|
1776
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1777
|
+
@dra = RealType.new(dra)
|
1778
|
+
else
|
1779
|
+
@dra = dra
|
1780
|
+
end
|
1781
|
+
end
|
1782
|
+
|
1783
|
+
def ddec=(ddec)
|
1784
|
+
begin
|
1785
|
+
VOTables::VOTable::Misc::TypeCheck.new(ddec, RealType).check()
|
1786
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1787
|
+
@ddec = RealType.new(ddec)
|
1788
|
+
else
|
1789
|
+
@ddec = ddec
|
1790
|
+
end
|
1791
|
+
end
|
1792
|
+
|
1793
|
+
def system=(sys)
|
1794
|
+
begin
|
1795
|
+
VOTables::VOTable::Misc::TypeCheck.new(sys, StringType).check()
|
1796
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1797
|
+
@system = StringType.new(sys)
|
1798
|
+
else
|
1799
|
+
@system = sys
|
1800
|
+
end
|
1801
|
+
end
|
1802
|
+
|
1803
|
+
def shape=(sh)
|
1804
|
+
begin
|
1805
|
+
VOTables::VOTable::Misc::TypeCheck.new(sh, StringType).check()
|
1806
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1807
|
+
@shape = StringType.new(sh)
|
1808
|
+
else
|
1809
|
+
@shape = sh
|
1810
|
+
end
|
1811
|
+
end
|
1812
|
+
|
1813
|
+
def to_s
|
1814
|
+
"{shape=#{self.shape},system=#{self.system},ra=#{self.ra}," +
|
1815
|
+
"dec=#{self.dec},dra=#{self.dra},ddec=#{self.ddec}}"
|
1816
|
+
end
|
1817
|
+
|
1818
|
+
def self.from_xml(node)
|
1819
|
+
unit = node.attributes['unit'] || 'deg'
|
1820
|
+
|
1821
|
+
center = REXML::XPath.first(node, 'reg:Center').text
|
1822
|
+
ra_s, dec_s = center.split(/\s+/)
|
1823
|
+
ra = RealType.new(ra_s.to_f)
|
1824
|
+
dec = RealType.new(dec_s.to_f)
|
1825
|
+
|
1826
|
+
size = REXML::XPath.first(node, 'reg:Size').text
|
1827
|
+
dra_s, ddec_s = size.split(/\s+/)
|
1828
|
+
dra = RealType.new(dra_s.to_f)
|
1829
|
+
ddec = RealType.new(ddec_s.to_f)
|
1830
|
+
|
1831
|
+
return Box.new(ra, dec, dra, ddec)
|
1832
|
+
end
|
1833
|
+
|
1834
|
+
def self.create_new_object(attributes)
|
1835
|
+
ra = RealType.new(attributes['ra'])
|
1836
|
+
dec = RealType.new(attributes['dec'])
|
1837
|
+
dra = RealType.new(attributes['dra'])
|
1838
|
+
ddec = RealType.new(attributes['ddec'])
|
1839
|
+
|
1840
|
+
return Box.new(ra, dec, dra, ddec)
|
1841
|
+
end
|
1842
|
+
|
1843
|
+
def match_attributtes(attributes)
|
1844
|
+
return true if self.ra.value == attributes['ra'] and
|
1845
|
+
self.dec.value == attributes['dec'] and
|
1846
|
+
self.dra.value == attributes['dra'] and
|
1847
|
+
self.ddec.value == attributes['ddec']
|
1848
|
+
return false
|
1849
|
+
end
|
1850
|
+
end
|
1851
|
+
|
1852
|
+
# Represents the Regions such as circle in Where clause.
|
1853
|
+
class RegionSearch < Search
|
1854
|
+
attr_reader :shape, :intersection
|
1855
|
+
|
1856
|
+
def initialize(shape, intersection='overlaps')
|
1857
|
+
self.shape = shape
|
1858
|
+
self.intersection = intersection
|
1859
|
+
end
|
1860
|
+
|
1861
|
+
def shape=(s)
|
1862
|
+
VOTables::VOTable::Misc::TypeCheck.new(s, Shape).check()
|
1863
|
+
@shape = s
|
1864
|
+
end
|
1865
|
+
|
1866
|
+
def intersection=(i)
|
1867
|
+
begin
|
1868
|
+
VOTables::VOTable::Misc::TypeCheck.new(i, StringType).check()
|
1869
|
+
rescue VOTables::VOTable::Misc::TypeException
|
1870
|
+
@intersection = StringType.new(i)
|
1871
|
+
else
|
1872
|
+
@intersection = i
|
1873
|
+
end
|
1874
|
+
end
|
1875
|
+
|
1876
|
+
def to_s
|
1877
|
+
"{region={intersection=#{self.intersection},shape=#{self.shape}}}"
|
1878
|
+
end
|
1879
|
+
|
1880
|
+
def self.from_xml(node)
|
1881
|
+
inter = node.attributes['intersection'].to_s
|
1882
|
+
region_node = REXML::XPath.first(node, 'Region')
|
1883
|
+
sh = Shape.from_xml(region_node)
|
1884
|
+
return RegionSearch.new(sh, inter)
|
1885
|
+
end
|
1886
|
+
|
1887
|
+
def self.create_new_object(attributes)
|
1888
|
+
sh = ObjectBuilder.get_class_for(attributes['shape_type']).create_new_object(attributes)
|
1889
|
+
return RegionSearch.new(sh, attributes['intersection'].to_s)
|
1890
|
+
end
|
1891
|
+
|
1892
|
+
def match_attributtes(attributes)
|
1893
|
+
return self.shape.match_attributtes(attributes)
|
1894
|
+
end
|
1895
|
+
|
1896
|
+
# This method finds a condition given its attributes and it returns it
|
1897
|
+
def find_condition(type, attributes)
|
1898
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1899
|
+
return self if self.match_attributtes(attributes)
|
1900
|
+
return nil
|
1901
|
+
end
|
1902
|
+
return nil
|
1903
|
+
end
|
1904
|
+
|
1905
|
+
# This method removes a condition. -1 means that the condition must
|
1906
|
+
# be removed. 1 means that the condition given its attributes wasn't
|
1907
|
+
# found, so that the process must continue.
|
1908
|
+
def remove_condition(type, attributes)
|
1909
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1910
|
+
return -1 if self.match_attributtes(attributes)
|
1911
|
+
return 1
|
1912
|
+
end
|
1913
|
+
return 1
|
1914
|
+
end
|
1915
|
+
|
1916
|
+
# This method modifies a condition given its old attributes,
|
1917
|
+
# replacing the old attributes with the new attributes.
|
1918
|
+
def modify_condition(type, attributes_old, attributes_new)
|
1919
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1920
|
+
if self.match_attributtes(attributes_old)
|
1921
|
+
return RegionSearch.create_new_object(attributes_new)
|
1922
|
+
else
|
1923
|
+
return nil
|
1924
|
+
end
|
1925
|
+
end
|
1926
|
+
return nil
|
1927
|
+
end
|
1928
|
+
|
1929
|
+
# This method replaces a condition given its attributes.
|
1930
|
+
# Returns -1 if the object must be replaced, or returns 1 if
|
1931
|
+
# isn't the object that must be replaced, so the process must continue
|
1932
|
+
def replace_condition(type, attributes, new_condition)
|
1933
|
+
if ObjectBuilder.get_class_for(type).to_s() == self.class.to_s()
|
1934
|
+
return -1 if self.match_attributtes(attributes)
|
1935
|
+
return 1
|
1936
|
+
end
|
1937
|
+
return 1
|
1938
|
+
end
|
1939
|
+
end
|
1940
|
+
|
1941
|
+
# Represents expressions like Not A.
|
1942
|
+
class InverseSearch < Search
|
1943
|
+
attr_reader :condition
|
1944
|
+
|
1945
|
+
def initialize(condition)
|
1946
|
+
self.condition = condition
|
1947
|
+
end
|
1948
|
+
|
1949
|
+
def condition=(c)
|
1950
|
+
VOTables::VOTable::Misc::TypeCheck.new(c, Search).check()
|
1951
|
+
@condition = c
|
1952
|
+
end
|
1953
|
+
|
1954
|
+
def to_s
|
1955
|
+
"{condition=#{self.condition}}"
|
1956
|
+
end
|
1957
|
+
|
1958
|
+
def self.from_xml(node)
|
1959
|
+
cond_node = REXML::XPath.first(node, 'Condition')
|
1960
|
+
cond = Condition.from_xml(cond_node)
|
1961
|
+
return InverseSearch.new(cond)
|
1962
|
+
end
|
1963
|
+
end
|
1964
|
+
|
1965
|
+
# Represents the Having expression part of a query.
|
1966
|
+
class Having
|
1967
|
+
attr_reader :condition
|
1968
|
+
|
1969
|
+
def initialize(condition)
|
1970
|
+
self.condition = condition
|
1971
|
+
end
|
1972
|
+
|
1973
|
+
def condition=(c)
|
1974
|
+
VOTables::VOTable::Misc::TypeCheck.new(c, Search).check()
|
1975
|
+
@condition = c
|
1976
|
+
end
|
1977
|
+
|
1978
|
+
def to_s
|
1979
|
+
"{condition=#{self.condition}}"
|
1980
|
+
end
|
1981
|
+
|
1982
|
+
def self.from_xml(node)
|
1983
|
+
cond_node = REXML::XPath.first(node, 'Condition')
|
1984
|
+
cond = Condition.from_xml(cond_node)
|
1985
|
+
return Having.new(cond)
|
1986
|
+
end
|
1987
|
+
end
|
1988
|
+
|
1989
|
+
# Represents the Group By expression part of a query.
|
1990
|
+
class GroupBy
|
1991
|
+
attr_reader :columns
|
1992
|
+
|
1993
|
+
def initialize(columns)
|
1994
|
+
self.columns = columns
|
1995
|
+
end
|
1996
|
+
|
1997
|
+
def columns=(c)
|
1998
|
+
raise "Provide at least one condition" if c.size < 1
|
1999
|
+
|
2000
|
+
@columns = []
|
2001
|
+
c.each do |col|
|
2002
|
+
VOTables::VOTable::Misc::TypeCheck.new(col, ColumnReference).check()
|
2003
|
+
@columns.push(col)
|
2004
|
+
end
|
2005
|
+
end
|
2006
|
+
|
2007
|
+
def to_s
|
2008
|
+
cols = self.columns.collect{|x| x.to_s}.join('|')
|
2009
|
+
"{columns=#{cols}}"
|
2010
|
+
end
|
2011
|
+
|
2012
|
+
def self.from_xml(node)
|
2013
|
+
columns = []
|
2014
|
+
node.elements.each('Column') do |col_node|
|
2015
|
+
col = Column.from_xml(col_node)
|
2016
|
+
columns.push(col)
|
2017
|
+
end
|
2018
|
+
|
2019
|
+
return GroupBy.new(columns)
|
2020
|
+
end
|
2021
|
+
end
|
2022
|
+
|
2023
|
+
# Represents the Where part of the query.
|
2024
|
+
class Where
|
2025
|
+
attr_reader :condition
|
2026
|
+
|
2027
|
+
def initialize(condition)
|
2028
|
+
self.condition = condition
|
2029
|
+
end
|
2030
|
+
|
2031
|
+
def condition=(c)
|
2032
|
+
VOTables::VOTable::Misc::TypeCheck.new(c, Search).check()
|
2033
|
+
@condition = c
|
2034
|
+
end
|
2035
|
+
|
2036
|
+
def to_s
|
2037
|
+
"{condition=#{self.condition}}"
|
2038
|
+
end
|
2039
|
+
|
2040
|
+
def self.from_xml(node)
|
2041
|
+
cond_node = REXML::XPath.first(node, 'Condition')
|
2042
|
+
cond = Condition.from_xml(cond_node)
|
2043
|
+
return Where.new(cond)
|
2044
|
+
end
|
2045
|
+
|
2046
|
+
# This method finds a condition given its attributes and it returns it
|
2047
|
+
def find_condition(type, attributes)
|
2048
|
+
return self.condition.find_condition(type, attributes)
|
2049
|
+
end
|
2050
|
+
|
2051
|
+
# This method removes a condition. -1 means that the condition must
|
2052
|
+
# be removed. 1 means that the condition given its attributes wasn't
|
2053
|
+
# found. The other case is that the condition was changed in another
|
2054
|
+
# place, for example could have been removed in the intersectionSearchType
|
2055
|
+
# called.
|
2056
|
+
def remove_condition(type, attributes)
|
2057
|
+
condition = self.condition.remove_condition(type, attributes)
|
2058
|
+
if condition == -1
|
2059
|
+
self.condition = nil
|
2060
|
+
elsif condition != 1
|
2061
|
+
self.condition = condition
|
2062
|
+
end
|
2063
|
+
end
|
2064
|
+
|
2065
|
+
# This method modify a condition given its old attributtes,
|
2066
|
+
# replacing the old attributes with the new attributes.
|
2067
|
+
def modify_condition(type, attributes_old, attributes_new)
|
2068
|
+
self.condition = self.condition.modify_condition(type, attributes_old, attributes_new)
|
2069
|
+
end
|
2070
|
+
|
2071
|
+
# This method replaces a condition for a new condition. -1 means that
|
2072
|
+
# the condition must be replaced. 1 means that the old condition in
|
2073
|
+
# this case wasn't found so that the old condition won't be replaced.
|
2074
|
+
# The other case is that the condition was changed in another place,
|
2075
|
+
# for example could have been replaced in the intersectionSearchType
|
2076
|
+
# called.
|
2077
|
+
def replace_condition(type, attributes, new_condition)
|
2078
|
+
condition = self.condition.replace_condition(type, attributes, new_condition)
|
2079
|
+
if condition == -1
|
2080
|
+
self.condition = new_condition
|
2081
|
+
elsif condition != 1
|
2082
|
+
self.condition = condition
|
2083
|
+
end
|
2084
|
+
end
|
2085
|
+
end
|
2086
|
+
|
2087
|
+
# Represents the From part of the query.
|
2088
|
+
class From
|
2089
|
+
attr_reader :tables
|
2090
|
+
|
2091
|
+
def initialize(tables)
|
2092
|
+
self.tables = tables
|
2093
|
+
end
|
2094
|
+
|
2095
|
+
def tables=(ts)
|
2096
|
+
raise "Specify at least one table" if ts.size < 1
|
2097
|
+
|
2098
|
+
@tables = []
|
2099
|
+
ts.each do |t|
|
2100
|
+
VOTables::VOTable::Misc::TypeCheck.new(t, FromTable).check()
|
2101
|
+
@tables.push(t)
|
2102
|
+
end
|
2103
|
+
end
|
2104
|
+
|
2105
|
+
def to_s
|
2106
|
+
tables = self.tables.collect{|x| x.to_s}.join('|')
|
2107
|
+
"{tables=#{tables}}"
|
2108
|
+
end
|
2109
|
+
|
2110
|
+
def self.from_xml(node)
|
2111
|
+
table_list = []
|
2112
|
+
node.elements.each("Table") do |tbl_node|
|
2113
|
+
table = Table.from_xml(tbl_node)
|
2114
|
+
table_list.push(table)
|
2115
|
+
end
|
2116
|
+
|
2117
|
+
return From.new(table_list)
|
2118
|
+
end
|
2119
|
+
end
|
2120
|
+
|
2121
|
+
# List of items to be selected in the Query.
|
2122
|
+
class SelectionList
|
2123
|
+
attr_reader :items
|
2124
|
+
|
2125
|
+
def initialize(items)
|
2126
|
+
self.items = items
|
2127
|
+
end
|
2128
|
+
|
2129
|
+
def items=(is)
|
2130
|
+
raise "Specify at least one item" if is.size < 1
|
2131
|
+
|
2132
|
+
@items = []
|
2133
|
+
is.each do |i|
|
2134
|
+
VOTables::VOTable::Misc::TypeCheck.new(i, SelectionItem).check()
|
2135
|
+
@items.push(i)
|
2136
|
+
end
|
2137
|
+
end
|
2138
|
+
|
2139
|
+
def to_s
|
2140
|
+
items = self.items.collect{|x| x.to_s}.join('|')
|
2141
|
+
return "{items=#{items}}"
|
2142
|
+
end
|
2143
|
+
|
2144
|
+
def self.from_xml(node)
|
2145
|
+
item_list = []
|
2146
|
+
node.elements.each('Item') do |item_node|
|
2147
|
+
item_list.push(Item.from_xml(item_node))
|
2148
|
+
end
|
2149
|
+
|
2150
|
+
return SelectionList.new(item_list)
|
2151
|
+
end
|
2152
|
+
|
2153
|
+
def add(attributes)
|
2154
|
+
new_item = nil
|
2155
|
+
if attributes['name'] == AllSelectionItem.value
|
2156
|
+
new_item = AllSelectionItem.new()
|
2157
|
+
else
|
2158
|
+
new_item = ColumnReference.new(attributes['table'],
|
2159
|
+
attributes['name'], attributes['xpath_name'])
|
2160
|
+
end
|
2161
|
+
self.items.push(new_item) if new_item and find(attributes) == nil
|
2162
|
+
end
|
2163
|
+
|
2164
|
+
def remove(attributes)
|
2165
|
+
remove_item = find(attributes)
|
2166
|
+
self.items.delete(remove_item) if remove_item != nil
|
2167
|
+
end
|
2168
|
+
|
2169
|
+
def find(attributes)
|
2170
|
+
self.items().each do |item|
|
2171
|
+
if !item.is_a?(AllSelectionItem)
|
2172
|
+
return item if item.name() == attributes['name'] and item.table() == attributes['table']
|
2173
|
+
elsif item.is_a?(AllSelectionItem)
|
2174
|
+
return item if AllSelectionItem.value == attributes['name']
|
2175
|
+
end
|
2176
|
+
end
|
2177
|
+
return nil
|
2178
|
+
end
|
2179
|
+
|
2180
|
+
def is_empty
|
2181
|
+
self.items().empty?
|
2182
|
+
end
|
2183
|
+
end
|
2184
|
+
|
2185
|
+
# Represents the TOP part of a query.
|
2186
|
+
class SelectionLimit
|
2187
|
+
attr_reader :top
|
2188
|
+
|
2189
|
+
def initialize(top)
|
2190
|
+
self.top = top
|
2191
|
+
end
|
2192
|
+
|
2193
|
+
def top=(t)
|
2194
|
+
raise "Provide an integer > 0" if t < 1 or !t.is_a?(Integer)
|
2195
|
+
@top = t
|
2196
|
+
end
|
2197
|
+
|
2198
|
+
def to_s
|
2199
|
+
"{top=#{self.top}}"
|
2200
|
+
end
|
2201
|
+
|
2202
|
+
def self.from_xml(node)
|
2203
|
+
top = node.attributes['Top'].to_i
|
2204
|
+
return SelectionLimit.new(top)
|
2205
|
+
end
|
2206
|
+
end
|
2207
|
+
|
2208
|
+
# Represents the SQL INTO expression.
|
2209
|
+
class Into
|
2210
|
+
attr_accessor :table_name
|
2211
|
+
|
2212
|
+
def initialize(name)
|
2213
|
+
self.table_name = name
|
2214
|
+
end
|
2215
|
+
|
2216
|
+
def to_s
|
2217
|
+
"{table_name=#{self.table_name}}"
|
2218
|
+
end
|
2219
|
+
|
2220
|
+
def self.from_xml(node)
|
2221
|
+
table_name_node = REXML::XPath.first(node, 'TableName')
|
2222
|
+
table_name = TableName.from_xml(table_name_node)
|
2223
|
+
return Into.new(table_name)
|
2224
|
+
end
|
2225
|
+
end
|
2226
|
+
|
2227
|
+
# Ascending or Descending order of an Order by term.
|
2228
|
+
class OrderDirection
|
2229
|
+
attr_reader :value
|
2230
|
+
|
2231
|
+
@@options = ['ASC', 'DESC']
|
2232
|
+
|
2233
|
+
def initialize(value, options_list=nil)
|
2234
|
+
@options_list = options_list || @@options
|
2235
|
+
self.value = value
|
2236
|
+
end
|
2237
|
+
|
2238
|
+
def value=(v)
|
2239
|
+
if @options_list.include?(v)
|
2240
|
+
@value = v
|
2241
|
+
else
|
2242
|
+
raise "Value is not valid. Use one of: " +
|
2243
|
+
@options_list.join(', ')
|
2244
|
+
end
|
2245
|
+
end
|
2246
|
+
|
2247
|
+
def to_s
|
2248
|
+
"{value=#{self.value}}"
|
2249
|
+
end
|
2250
|
+
end
|
2251
|
+
|
2252
|
+
# Option for setting the direction for Order By.
|
2253
|
+
class OrderOption
|
2254
|
+
attr_reader :direction
|
2255
|
+
|
2256
|
+
def initialize(direction)
|
2257
|
+
self.direction = direction
|
2258
|
+
end
|
2259
|
+
|
2260
|
+
def direction=(d)
|
2261
|
+
begin
|
2262
|
+
VOTables::VOTable::Misc::TypeCheck.new(d, OrderDirection).check()
|
2263
|
+
rescue VOTables::VOTable::Misc::TypeException
|
2264
|
+
@direction = OrderDirection.new(d)
|
2265
|
+
else
|
2266
|
+
@direction = d
|
2267
|
+
end
|
2268
|
+
end
|
2269
|
+
|
2270
|
+
def to_s
|
2271
|
+
"{direction=#{self.direction}}"
|
2272
|
+
end
|
2273
|
+
|
2274
|
+
def self.from_xml(node)
|
2275
|
+
return OrderOption.new(node.attributes['Direction'])
|
2276
|
+
end
|
2277
|
+
end
|
2278
|
+
|
2279
|
+
# Represents the ORDER BY part of a query.
|
2280
|
+
class Order
|
2281
|
+
attr_reader :expression, :order
|
2282
|
+
|
2283
|
+
def initialize(expression, order=nil)
|
2284
|
+
self.expression = expression
|
2285
|
+
self.order = order
|
2286
|
+
end
|
2287
|
+
|
2288
|
+
def expression=(e)
|
2289
|
+
VOTables::VOTable::Misc::TypeCheck.new(e, ScalarExpression).check()
|
2290
|
+
@expression = e
|
2291
|
+
end
|
2292
|
+
|
2293
|
+
def order=(o)
|
2294
|
+
begin
|
2295
|
+
VOTables::VOTable::Misc::TypeCheck.new(o, OrderOption).check()
|
2296
|
+
rescue VOTables::VOTable::Misc::TypeException
|
2297
|
+
@order = OrderOption.new(o)
|
2298
|
+
else
|
2299
|
+
@order = o
|
2300
|
+
end
|
2301
|
+
end
|
2302
|
+
|
2303
|
+
def to_s
|
2304
|
+
"{expression=#{self.expression},order=#{self.order}}"
|
2305
|
+
end
|
2306
|
+
|
2307
|
+
def self.from_xml(node)
|
2308
|
+
expr_node = REXML::XPath.first(node, 'Expression')
|
2309
|
+
expr = Expression.from_xml(expr_node)
|
2310
|
+
order_option_node = REXML::XPath.first(node, 'Order')
|
2311
|
+
order_option = OrderOption.from_xml(order_option_node)
|
2312
|
+
return Order.new(expr, order_option)
|
2313
|
+
end
|
2314
|
+
end
|
2315
|
+
|
2316
|
+
# List of expressions in which order the results should be provided.
|
2317
|
+
class OrderExpression
|
2318
|
+
attr_reader :items
|
2319
|
+
|
2320
|
+
def initialize(items)
|
2321
|
+
self.items = items
|
2322
|
+
end
|
2323
|
+
|
2324
|
+
def items=(is)
|
2325
|
+
raise "Specify at least one item" if is.size < 1
|
2326
|
+
|
2327
|
+
@items = []
|
2328
|
+
is.each do |i|
|
2329
|
+
VOTables::VOTable::Misc::TypeCheck.new(i, Order).check()
|
2330
|
+
@items.push(i)
|
2331
|
+
end
|
2332
|
+
end
|
2333
|
+
|
2334
|
+
def to_s
|
2335
|
+
items = self.items.collect{|x| x.to_s}.join('|')
|
2336
|
+
"{items=#{items}}"
|
2337
|
+
end
|
2338
|
+
|
2339
|
+
def self.from_xml(node)
|
2340
|
+
items = []
|
2341
|
+
node.elements.each('Item') do |item_node|
|
2342
|
+
item = Item.from_xml(item_node)
|
2343
|
+
items.push(item)
|
2344
|
+
end
|
2345
|
+
|
2346
|
+
return OrderExpression.new(items)
|
2347
|
+
end
|
2348
|
+
end
|
2349
|
+
|
2350
|
+
# Represents a list of constants provided for a SQL IN expression.
|
2351
|
+
class ConstantListSet < InclusionSet
|
2352
|
+
attr_reader :items
|
2353
|
+
|
2354
|
+
def initialize(items)
|
2355
|
+
self.items = items
|
2356
|
+
end
|
2357
|
+
|
2358
|
+
def items=(is)
|
2359
|
+
raise "Specify at least one item" if is.size < 1
|
2360
|
+
|
2361
|
+
@items = []
|
2362
|
+
is.each do |i|
|
2363
|
+
begin
|
2364
|
+
VOTables::VOTable::Misc::TypeCheck.new(i, LiteralType).check()
|
2365
|
+
rescue VOTables::VOTable::Misc::TypeException
|
2366
|
+
if i.is_a?(String)
|
2367
|
+
@items.push(StringType.new(i))
|
2368
|
+
elsif i.is_a?(Integer)
|
2369
|
+
@items.push(IntegerType.new(i))
|
2370
|
+
elsif i.is_a?(Float)
|
2371
|
+
@items.push(RealType.new(i))
|
2372
|
+
else
|
2373
|
+
raise "Item must be of type LiteralType"
|
2374
|
+
end
|
2375
|
+
else
|
2376
|
+
@items.push(i)
|
2377
|
+
end
|
2378
|
+
end
|
2379
|
+
end
|
2380
|
+
|
2381
|
+
def to_s
|
2382
|
+
items = self.items.collect{|x| x.to_s}.join('|')
|
2383
|
+
"{items=#{items}}"
|
2384
|
+
end
|
2385
|
+
|
2386
|
+
def self.from_xml(node)
|
2387
|
+
item_list = []
|
2388
|
+
node.elements.each('Item') do |item_node|
|
2389
|
+
item = Item.from_xml(item_node)
|
2390
|
+
item_list.push(Item.from_xml(item_node))
|
2391
|
+
end
|
2392
|
+
|
2393
|
+
return ConstantListSet.new(item_list)
|
2394
|
+
end
|
2395
|
+
end
|
2396
|
+
|
2397
|
+
# Represents SQL IN expression.
|
2398
|
+
class InclusiveSearch < Search
|
2399
|
+
attr_reader :expression, :set
|
2400
|
+
|
2401
|
+
def initialize(expression, set)
|
2402
|
+
self.expression = expression
|
2403
|
+
self.set = set
|
2404
|
+
end
|
2405
|
+
|
2406
|
+
def expression=(e)
|
2407
|
+
VOTables::VOTable::Misc::TypeCheck.new(e, ScalarExpression).check()
|
2408
|
+
@expression = e
|
2409
|
+
end
|
2410
|
+
|
2411
|
+
def set=(s)
|
2412
|
+
VOTables::VOTable::Misc::TypeCheck.new(s, InclusionSet).check()
|
2413
|
+
@set = s
|
2414
|
+
end
|
2415
|
+
|
2416
|
+
def to_s
|
2417
|
+
"{expression=#{self.expression},set=#{self.set}}"
|
2418
|
+
end
|
2419
|
+
|
2420
|
+
def self.from_xml(node)
|
2421
|
+
expr_node = REXML::XPath.first(node, 'Expression')
|
2422
|
+
expr = Expression.from_xml(expr_node)
|
2423
|
+
set_node = REXML::XPath.first(node, 'Set')
|
2424
|
+
set = Set.from_xml(set_node)
|
2425
|
+
return InclusiveSearch.new(expr, set)
|
2426
|
+
end
|
2427
|
+
end
|
2428
|
+
|
2429
|
+
# The SELECT part of a query.
|
2430
|
+
class Select
|
2431
|
+
attr_reader :allow, :restrict, :selection_list, :in_to, :from,
|
2432
|
+
:where, :group_by, :having, :order_by
|
2433
|
+
attr_accessor :start_comment, :end_comment
|
2434
|
+
|
2435
|
+
def initialize(selection_list, allow=nil, restrict=nil, in_to=nil,
|
2436
|
+
from=nil, where=nil, group_by=nil, having=nil, order_by=nil,
|
2437
|
+
start_comment=nil, end_comment=nil)
|
2438
|
+
self.selection_list = selection_list
|
2439
|
+
self.allow = allow
|
2440
|
+
self.restrict = restrict
|
2441
|
+
self.in_to = in_to
|
2442
|
+
self.from = from
|
2443
|
+
self.where = where
|
2444
|
+
self.group_by = group_by
|
2445
|
+
self.having = having
|
2446
|
+
self.order_by = order_by
|
2447
|
+
self.start_comment = start_comment
|
2448
|
+
self.end_comment = end_comment
|
2449
|
+
end
|
2450
|
+
|
2451
|
+
def selection_list=(sl)
|
2452
|
+
VOTables::VOTable::Misc::TypeCheck.new(sl, SelectionList).check()
|
2453
|
+
@selection_list = sl
|
2454
|
+
end
|
2455
|
+
|
2456
|
+
def allow=(a)
|
2457
|
+
begin
|
2458
|
+
VOTables::VOTable::Misc::TypeCheck.new(a, SelectionOption).check()
|
2459
|
+
rescue VOTables::VOTable::Misc::TypeException
|
2460
|
+
@allow = SelectionOption.new(a)
|
2461
|
+
else
|
2462
|
+
@allow = a
|
2463
|
+
end
|
2464
|
+
end
|
2465
|
+
|
2466
|
+
def restrict=(r)
|
2467
|
+
begin
|
2468
|
+
VOTables::VOTable::Misc::TypeCheck.new(r, SelectionLimit).check()
|
2469
|
+
rescue VOTables::VOTable::Misc::TypeException
|
2470
|
+
@restrict = SelectionLimit.new(r)
|
2471
|
+
else
|
2472
|
+
@restrict = r
|
2473
|
+
end
|
2474
|
+
end
|
2475
|
+
|
2476
|
+
def in_to=(it)
|
2477
|
+
begin
|
2478
|
+
VOTables::VOTable::Misc::TypeCheck.new(it, Into).check()
|
2479
|
+
rescue VOTables::VOTable::Misc::TypeException
|
2480
|
+
@in_to = Into.new(it)
|
2481
|
+
else
|
2482
|
+
@in_to = it
|
2483
|
+
end
|
2484
|
+
end
|
2485
|
+
|
2486
|
+
def from=(f)
|
2487
|
+
VOTables::VOTable::Misc::TypeCheck.new(f, From).check()
|
2488
|
+
@from = f
|
2489
|
+
end
|
2490
|
+
|
2491
|
+
def where=(w)
|
2492
|
+
VOTables::VOTable::Misc::TypeCheck.new(w, Where).check()
|
2493
|
+
@where = w
|
2494
|
+
end
|
2495
|
+
|
2496
|
+
def group_by=(gb)
|
2497
|
+
VOTables::VOTable::Misc::TypeCheck.new(gb, GroupBy).check()
|
2498
|
+
@group_by = gb
|
2499
|
+
end
|
2500
|
+
|
2501
|
+
def having=(h)
|
2502
|
+
VOTables::VOTable::Misc::TypeCheck.new(h, Having).check()
|
2503
|
+
@having = h
|
2504
|
+
end
|
2505
|
+
|
2506
|
+
def order_by=(ob)
|
2507
|
+
VOTables::VOTable::Misc::TypeCheck.new(ob, OrderExpression).check()
|
2508
|
+
@order_by = ob
|
2509
|
+
end
|
2510
|
+
|
2511
|
+
def to_s
|
2512
|
+
"{allow=#{self.allow},restrict=#{self.restrict},selection_list=#{self.selection_list}," +
|
2513
|
+
"in_to=#{self.in_to},from=#{self.from},where=#{self.where},group_by=#{self.group_by}," +
|
2514
|
+
"having=#{self.having},order_by=#{self.order_by},start_comment=#{self.start_comment}," +
|
2515
|
+
"end_comment=#{self.end_comment}}"
|
2516
|
+
end
|
2517
|
+
|
2518
|
+
def to_file(file_path)
|
2519
|
+
file = File.new(file_path, 'w')
|
2520
|
+
file.syswrite(self.to_adqlx)
|
2521
|
+
file.close()
|
2522
|
+
end
|
2523
|
+
|
2524
|
+
def self.from_xml(node)
|
2525
|
+
# SelectionList
|
2526
|
+
sl_node = REXML::XPath.first(node, 'SelectionList') or raise "No SelectionList element"
|
2527
|
+
selection_list = SelectionList.from_xml(sl_node)
|
2528
|
+
|
2529
|
+
# Allow
|
2530
|
+
allow_node = REXML::XPath.first(node, 'Allow')
|
2531
|
+
allow = nil
|
2532
|
+
allow = Allow.from_xml(allow_node) if allow_node
|
2533
|
+
|
2534
|
+
# Restrict
|
2535
|
+
restrict_node = REXML::XPath.first(node, 'Restrict')
|
2536
|
+
restrict = nil
|
2537
|
+
restrict = Restrict.from_xml(restrict_node) if restrict_node
|
2538
|
+
|
2539
|
+
# InTo
|
2540
|
+
into_node = REXML::XPath.first(node, 'InTo')
|
2541
|
+
into = nil
|
2542
|
+
into = InTo.from_xml(into_node) if into_node
|
2543
|
+
|
2544
|
+
# From
|
2545
|
+
from_node = REXML::XPath.first(node, 'From')
|
2546
|
+
from = nil
|
2547
|
+
from = From.from_xml(from_node) if from_node
|
2548
|
+
|
2549
|
+
# Where
|
2550
|
+
where_node = REXML::XPath.first(node, 'Where')
|
2551
|
+
where = nil
|
2552
|
+
where = Where.from_xml(where_node) if where_node
|
2553
|
+
|
2554
|
+
# GroupBy
|
2555
|
+
groupby_node = REXML::XPath.first(node, 'GroupBy')
|
2556
|
+
groupby = nil
|
2557
|
+
groupby = GroupBy.from_xml(groupby_node) if groupby_node
|
2558
|
+
|
2559
|
+
# Having
|
2560
|
+
having_node = REXML::XPath.first(node, 'Having')
|
2561
|
+
having = nil
|
2562
|
+
having = Having.from_xml(having_node) if having_node
|
2563
|
+
|
2564
|
+
# OrderBy
|
2565
|
+
orderby_node = REXML::XPath.first(node, 'OrderBy')
|
2566
|
+
orderby = nil
|
2567
|
+
orderby = OrderBy.from_xml(orderby_node) if orderby_node
|
2568
|
+
|
2569
|
+
# StartComment
|
2570
|
+
start_comment_node = REXML::XPath.first(node, 'StartComment')
|
2571
|
+
start_comment = nil
|
2572
|
+
start_comment = StartComment.from_xml(start_comment_node) if start_comment_node
|
2573
|
+
|
2574
|
+
# EndComment
|
2575
|
+
end_comment_node = REXML::XPath.first(node, 'EndComment')
|
2576
|
+
end_comment = nil
|
2577
|
+
end_comment = EndComment.from_xml(end_comment_node) if end_comment_node
|
2578
|
+
|
2579
|
+
return Select.new(selection_list, allow, restrict, into,
|
2580
|
+
from, where, groupby, having, orderby,
|
2581
|
+
start_comment, end_comment)
|
2582
|
+
end
|
2583
|
+
end
|
2584
|
+
|
2585
|
+
# Represents user defined function expressions.
|
2586
|
+
class UserDefinedFunction < ScalarExpression
|
2587
|
+
attr_accessor :name
|
2588
|
+
attr_reader :params
|
2589
|
+
|
2590
|
+
def initialize(name, params=nil)
|
2591
|
+
self.name = name
|
2592
|
+
self.params = params
|
2593
|
+
end
|
2594
|
+
|
2595
|
+
def params=(ps)
|
2596
|
+
if ps
|
2597
|
+
raise "Provide at least 1 parameter" if ps.size < 1
|
2598
|
+
|
2599
|
+
@params = []
|
2600
|
+
ps.each do |p|
|
2601
|
+
VOTables::VOTable::Misc::TypeCheck.new(p, ScalarExpression)
|
2602
|
+
@params.push(p)
|
2603
|
+
end
|
2604
|
+
end
|
2605
|
+
end
|
2606
|
+
|
2607
|
+
def to_s
|
2608
|
+
params = self.params.collect{|x| x.to_s}.join('|')
|
2609
|
+
"{name=#{self.name},params=#{params}}"
|
2610
|
+
end
|
2611
|
+
|
2612
|
+
def self.from_xml(node)
|
2613
|
+
name = REXML::XPath.first(node, 'Name').text
|
2614
|
+
params = []
|
2615
|
+
node.elements.each('Params') do |param_node|
|
2616
|
+
params.push(ScalarExpression.from_xml(param_node))
|
2617
|
+
end
|
2618
|
+
params = nil if params.size < 1
|
2619
|
+
return UserDefinedFunction.new(name, params)
|
2620
|
+
end
|
2621
|
+
end
|
2622
|
+
|
2623
|
+
# Denotes the type of a Join operation.
|
2624
|
+
class JointTableQualifier
|
2625
|
+
attr_reader :value
|
2626
|
+
|
2627
|
+
@@joins = ['LEFT_OUTER', 'RIGHT_OUTER', 'FULL_OUTER',
|
2628
|
+
'INNER', 'CROSS']
|
2629
|
+
|
2630
|
+
def initialize(value, join_list=nil)
|
2631
|
+
@join_list = join_list || @@joins
|
2632
|
+
self.value = value
|
2633
|
+
end
|
2634
|
+
|
2635
|
+
def value=(v)
|
2636
|
+
if @join_list.include?(v)
|
2637
|
+
@value = v
|
2638
|
+
else
|
2639
|
+
raise "Join type is not valid. Use one of: " +
|
2640
|
+
@join_list.join(', ')
|
2641
|
+
end
|
2642
|
+
end
|
2643
|
+
|
2644
|
+
def to_s
|
2645
|
+
"{value=#{self.value}}"
|
2646
|
+
end
|
2647
|
+
|
2648
|
+
def self.from_xml(node)
|
2649
|
+
return JointTableQualifier.new(node.text)
|
2650
|
+
end
|
2651
|
+
end
|
2652
|
+
|
2653
|
+
# Represents SQL JOIN expression.
|
2654
|
+
class JoinTable < FromTable
|
2655
|
+
attr_reader :qualifier, :tables, :condition
|
2656
|
+
|
2657
|
+
def initialize(qualifier, tables, condition)
|
2658
|
+
self.qualifier = qualifier
|
2659
|
+
self.tables = tables
|
2660
|
+
self.condition = condition
|
2661
|
+
end
|
2662
|
+
|
2663
|
+
def qualifier=(q)
|
2664
|
+
begin
|
2665
|
+
VOTables::VOTable::Misc::TypeCheck.new(q, JointTableQualifier).check()
|
2666
|
+
rescue VOTables::VOTable::Misc::TypeException
|
2667
|
+
@qualifier = JointTableQualifier.new(q)
|
2668
|
+
else
|
2669
|
+
@qualifier = q
|
2670
|
+
end
|
2671
|
+
end
|
2672
|
+
|
2673
|
+
def tables=(ts)
|
2674
|
+
VOTables::VOTable::Misc::TypeCheck.new(ts, ArrayOfFromTable).check()
|
2675
|
+
@tables = ts
|
2676
|
+
end
|
2677
|
+
|
2678
|
+
def condition=(c)
|
2679
|
+
VOTables::VOTable::Misc::TypeCheck.new(c, ComparisonPred).check()
|
2680
|
+
@condition = c
|
2681
|
+
end
|
2682
|
+
|
2683
|
+
def to_s
|
2684
|
+
"{qualifier=#{self.qualifier},tables=#{self.tables},condition=#{self.condition}}"
|
2685
|
+
end
|
2686
|
+
|
2687
|
+
def self.from_xml(node)
|
2688
|
+
qual_node = REXML::XPath.first(node, 'Qualifier')
|
2689
|
+
qual = Qualifier.from_xml(qual_node)
|
2690
|
+
tables_node = REXML::XPath.first(node, 'Tables')
|
2691
|
+
tables = Tables.from_xml(tables_node)
|
2692
|
+
cond_node = REXML::XPath.first(node, 'Condition')
|
2693
|
+
cond = Condition.from_xml(cond_node)
|
2694
|
+
return JoinTable.new(qual, tables, cond)
|
2695
|
+
end
|
2696
|
+
end
|
2697
|
+
|
2698
|
+
# Represents an array of tables in the from expression.def expression.
|
2699
|
+
class ArrayOfFromTable
|
2700
|
+
attr_reader :from_tables
|
2701
|
+
|
2702
|
+
def initialize(tables)
|
2703
|
+
self.from_tables = tables
|
2704
|
+
end
|
2705
|
+
|
2706
|
+
def from_tables=(fts)
|
2707
|
+
raise "Provide at least one table" if fts.size < 1
|
2708
|
+
|
2709
|
+
@from_tables = []
|
2710
|
+
if fts
|
2711
|
+
fts.each do |ft|
|
2712
|
+
VOTables::VOTable::Misc::TypeCheck.new(ft, FromTable)
|
2713
|
+
@from_tables.push(ft)
|
2714
|
+
end
|
2715
|
+
end
|
2716
|
+
end
|
2717
|
+
|
2718
|
+
def to_s
|
2719
|
+
tables = self.from_tables.collect{|x| x.to_s}.join('|')
|
2720
|
+
"{from_tables=#{tables}}"
|
2721
|
+
end
|
2722
|
+
|
2723
|
+
def self.from_xml(node)
|
2724
|
+
from_tables = []
|
2725
|
+
node.elements.to_a('Table').each do |ftbl|
|
2726
|
+
from_tables.push(FromTable.from_xml(ftbl))
|
2727
|
+
end
|
2728
|
+
|
2729
|
+
return ArrayOfFromTable.new(from_tables)
|
2730
|
+
end
|
2731
|
+
end
|
2732
|
+
|
2733
|
+
end
|
2734
|
+
|
2735
|
+
end
|