ginjo-rfm 1.4.4 → 2.0.pre31
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/CHANGELOG.md +107 -0
- data/README.md +378 -133
- data/lib/rfm.rb +51 -19
- data/lib/rfm/VERSION +1 -1
- data/lib/rfm/base.rb +416 -0
- data/lib/rfm/database.rb +14 -9
- data/lib/rfm/layout.rb +148 -96
- data/lib/rfm/metadata/field.rb +5 -5
- data/lib/rfm/metadata/field_control.rb +52 -51
- data/lib/rfm/metadata/script.rb +7 -5
- data/lib/rfm/record.rb +71 -56
- data/lib/rfm/resultset.rb +45 -26
- data/lib/rfm/server.rb +21 -17
- data/lib/rfm/utilities/complex_query.rb +64 -0
- data/lib/rfm/utilities/config.rb +115 -0
- data/lib/rfm/utilities/core_ext.rb +90 -0
- data/lib/rfm/utilities/factory.rb +100 -17
- data/lib/rfm/utilities/xml_parser.rb +94 -0
- data/lib/rfm/version.rb +1 -1
- data/lib/rfm/xml_mini/hpricot.rb +133 -0
- metadata +87 -30
data/lib/rfm/metadata/script.rb
CHANGED
@@ -9,12 +9,14 @@ module Rfm
|
|
9
9
|
#
|
10
10
|
# If you want to _run_ a script, see the Layout object instead.
|
11
11
|
class Script
|
12
|
-
def initialize(name,
|
12
|
+
def initialize(name, db_obj)
|
13
13
|
@name = name
|
14
|
-
|
14
|
+
self.db = db_obj
|
15
15
|
end
|
16
16
|
|
17
|
+
meta_attr_accessor :db
|
17
18
|
attr_reader :name
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
19
|
+
end # Script
|
20
|
+
|
21
|
+
end # Metadata
|
22
|
+
end # Rfm
|
data/lib/rfm/record.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Rfm
|
2
|
-
|
3
2
|
# The Record object represents a single FileMaker record. You typically get them from ResultSet objects.
|
4
3
|
# For example, you might use a Layout object to find some records:
|
5
4
|
#
|
@@ -69,7 +68,14 @@ module Rfm
|
|
69
68
|
# }
|
70
69
|
#
|
71
70
|
# This code iterates through the rows of the _Orders_ portal.
|
72
|
-
#
|
71
|
+
#
|
72
|
+
# As a convenience, you can call a specific portal as a method on your record, if the table occurrence name does
|
73
|
+
# not have any characters that are prohibited in ruby method names, just as you can call a field with a method:
|
74
|
+
#
|
75
|
+
# myRecord.orders.each {|portal_row|
|
76
|
+
# puts portal_row["Order Number"]
|
77
|
+
# }
|
78
|
+
#
|
73
79
|
# =Field Types and Ruby Types
|
74
80
|
#
|
75
81
|
# RFM automatically converts data from FileMaker into a Ruby object with the most reasonable type possible. The
|
@@ -100,41 +106,51 @@ module Rfm
|
|
100
106
|
# copy of the same record
|
101
107
|
class Record < Rfm::CaseInsensitiveHash
|
102
108
|
|
109
|
+
attr_accessor :layout, :resultset
|
103
110
|
attr_reader :record_id, :mod_id, :portals
|
111
|
+
def_delegators :resultset, :field_meta
|
112
|
+
def_delegators :layout, :db, :database, :server
|
104
113
|
|
105
|
-
def initialize(record,
|
106
|
-
@record_id = record['record-id']
|
107
|
-
@mod_id = record['mod-id']
|
108
|
-
@mods = {}
|
109
|
-
@layout = layout
|
110
|
-
@portals ||= Rfm::CaseInsensitiveHash.new
|
114
|
+
def initialize(record, resultset_obj, field_meta, layout_obj, portal=nil)
|
111
115
|
|
112
|
-
|
113
|
-
|
114
|
-
record
|
116
|
+
@layout = layout_obj
|
117
|
+
@resultset = resultset_obj
|
118
|
+
@record_id = record['record-id']
|
119
|
+
@mod_id = record['mod-id']
|
120
|
+
@mods = {}
|
121
|
+
@portals ||= Rfm::CaseInsensitiveHash.new
|
122
|
+
|
123
|
+
relatedsets = !portal && resultset_obj.instance_variable_get(:@include_portals) ? record['relatedset'].rfm_force_array : []
|
124
|
+
|
125
|
+
record['field'].rfm_force_array.each do |field|
|
126
|
+
next unless field
|
115
127
|
field_name = field['name']
|
116
128
|
field_name.gsub!(Regexp.new(portal + '::'), '') if portal
|
117
129
|
datum = []
|
118
130
|
|
119
|
-
field
|
120
|
-
|
121
|
-
|
131
|
+
data = field['data']; data = data.is_a?(Hash) ? [data] : data
|
132
|
+
data.each do |x|
|
133
|
+
next unless field_meta[field_name]
|
134
|
+
datum.push(field_meta[field_name].coerce(x['__content__'], resultset_obj))
|
135
|
+
end if data
|
122
136
|
|
123
137
|
if datum.length == 1
|
124
|
-
|
138
|
+
rfm_super[field_name] = datum[0]
|
125
139
|
elsif datum.length == 0
|
126
|
-
|
140
|
+
rfm_super[field_name] = nil
|
127
141
|
else
|
128
|
-
|
142
|
+
rfm_super[field_name] = datum
|
129
143
|
end
|
130
144
|
end
|
131
145
|
|
132
146
|
unless relatedsets.empty?
|
133
147
|
relatedsets.each do |relatedset|
|
148
|
+
next if relatedset.blank?
|
134
149
|
tablename, records = relatedset['table'], []
|
135
150
|
|
136
|
-
relatedset
|
137
|
-
|
151
|
+
relatedset['record'].rfm_force_array.each do |record|
|
152
|
+
next unless record
|
153
|
+
records << self.class.new(record, resultset_obj, resultset_obj.portal_meta[tablename], layout_obj, tablename)
|
138
154
|
end
|
139
155
|
|
140
156
|
@portals[tablename] = records
|
@@ -144,9 +160,9 @@ module Rfm
|
|
144
160
|
@loaded = true
|
145
161
|
end
|
146
162
|
|
147
|
-
def self.build_records(records,
|
163
|
+
def self.build_records(records, resultset_obj, field_meta, layout_obj, portal=nil)
|
148
164
|
records.each do |record|
|
149
|
-
|
165
|
+
resultset_obj << self.new(record, resultset_obj, field_meta, layout_obj, portal)
|
150
166
|
end
|
151
167
|
end
|
152
168
|
|
@@ -164,16 +180,15 @@ module Rfm
|
|
164
180
|
# to optimize on your end. Just save, and if you've changed the record it will be saved. If not, no
|
165
181
|
# server hit is incurred.
|
166
182
|
def save
|
167
|
-
self.merge!(
|
183
|
+
self.merge!(layout.edit(self.record_id, @mods)[0]) if @mods.size > 0
|
168
184
|
@mods.clear
|
169
185
|
end
|
170
|
-
|
171
186
|
|
172
187
|
# Like Record::save, except it fails (and raises an error) if the underlying record in FileMaker was
|
173
188
|
# modified after the record was fetched but before it was saved. In other words, prevents you from
|
174
189
|
# accidentally overwriting changes someone else made to the record.
|
175
190
|
def save_if_not_modified
|
176
|
-
self.merge!(
|
191
|
+
self.merge!(layout.edit(@record_id, @mods, {:modification_id => @mod_id})[0]) if @mods.size > 0
|
177
192
|
@mods.clear
|
178
193
|
end
|
179
194
|
|
@@ -190,43 +205,43 @@ module Rfm
|
|
190
205
|
#
|
191
206
|
# When you do, the change is noted, but *the data is not updated in FileMaker*. You must call
|
192
207
|
# Record::save or Record::save_if_not_modified to actually save the data.
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
@mods[name] = value
|
199
|
-
self.merge! @mods
|
200
|
-
end
|
201
|
-
|
202
|
-
alias :_old_hash_reader :[]
|
203
|
-
def [](value)
|
204
|
-
read_attribute(value)
|
205
|
-
end
|
208
|
+
def [](key)
|
209
|
+
return fetch(key.to_s.downcase)
|
210
|
+
rescue IndexError
|
211
|
+
raise Rfm::ParameterError, "#{key} does not exists as a field in the current Filemaker layout." unless key.to_s == '' #unless (!layout or self.key?(key_string))
|
212
|
+
end
|
206
213
|
|
207
214
|
def respond_to?(symbol, include_private = false)
|
208
215
|
return true if self.include?(symbol.to_s)
|
209
216
|
super
|
210
217
|
end
|
218
|
+
|
219
|
+
|
220
|
+
def []=(key, value)
|
221
|
+
key_string = key.to_s.downcase
|
222
|
+
return super unless @loaded # is this needed?
|
223
|
+
raise Rfm::ParameterError, "You attempted to modify a field that does not exist in the current Filemaker layout." unless self.key?(key_string)
|
224
|
+
@mods[key_string] = value
|
225
|
+
super(key, value)
|
226
|
+
end
|
227
|
+
|
228
|
+
def field_names
|
229
|
+
resultset.field_names rescue layout.field_names
|
230
|
+
end
|
211
231
|
|
212
|
-
private
|
213
232
|
|
214
|
-
|
215
|
-
key_string = key.to_s.downcase
|
216
|
-
raise NoMethodError,
|
217
|
-
"#{key_string} does not exists as a field in the current Filemaker layout." unless (!@layout or self.key?(key_string)) #!self.keys.grep(/#{key_string}/i).empty?
|
218
|
-
self._old_hash_reader(key).to_s.empty? ? nil : self._old_hash_reader(key) if self._old_hash_reader(key)
|
219
|
-
end
|
233
|
+
private
|
220
234
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
end
|
235
|
+
def method_missing (symbol, *attrs, &block)
|
236
|
+
method = symbol.to_s
|
237
|
+
return self[method] if self.key?(method)
|
238
|
+
return @portals[method] if @portals and @portals.key?(method)
|
239
|
+
|
240
|
+
if method =~ /(=)$/
|
241
|
+
return self[$`] = attrs.first if self.key?($`)
|
242
|
+
end
|
243
|
+
super
|
244
|
+
end
|
245
|
+
|
246
|
+
end # Record
|
247
|
+
end # Rfm
|
data/lib/rfm/resultset.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
# Author:: Geoff Coffey (mailto:gwcoffey@gmail.com)
|
6
6
|
# Copyright:: Copyright (c) 2007 Six Fried Rice, LLC and Mufaddal Khumri
|
7
7
|
# License:: See MIT-LICENSE for details
|
8
|
-
|
8
|
+
|
9
9
|
require 'bigdecimal'
|
10
10
|
require 'rfm/record'
|
11
11
|
|
@@ -40,7 +40,8 @@ module Rfm
|
|
40
40
|
attr_reader :layout, :server
|
41
41
|
attr_reader :field_meta, :portal_meta
|
42
42
|
attr_reader :date_format, :time_format, :timestamp_format
|
43
|
-
attr_reader :total_count, :foundset_count
|
43
|
+
attr_reader :total_count, :foundset_count, :table
|
44
|
+
def_delegators :layout, :db, :database
|
44
45
|
|
45
46
|
# Initializes a new ResultSet object. You will probably never do this your self (instead, use the Layout
|
46
47
|
# object to get various ResultSet obejects).
|
@@ -64,62 +65,80 @@ module Rfm
|
|
64
65
|
# layout contains portals, you can find out what fields they contain here. Again, if it's the data you're
|
65
66
|
# after, you want to look at the Record object.
|
66
67
|
|
67
|
-
def initialize(
|
68
|
-
@layout =
|
69
|
-
@server =
|
68
|
+
def initialize(server_obj, xml_response, layout_obj, portals=nil)
|
69
|
+
@layout = layout_obj
|
70
|
+
@server = server_obj
|
70
71
|
@field_meta ||= Rfm::CaseInsensitiveHash.new
|
71
72
|
@portal_meta ||= Rfm::CaseInsensitiveHash.new
|
72
73
|
@include_portals = portals
|
73
74
|
|
74
|
-
doc =
|
75
|
+
doc = XmlParser.new(xml_response, :namespace=>false, :parser=>server.state[:parser])
|
75
76
|
|
76
|
-
error = doc
|
77
|
+
error = doc['fmresultset']['error']['code'].to_i
|
77
78
|
check_for_errors(error, server.state[:raise_on_401])
|
78
79
|
|
79
|
-
datasource = doc
|
80
|
-
meta = doc
|
81
|
-
resultset = doc
|
82
|
-
|
83
|
-
@date_format = convert_date_time_format(datasource.attribute('date-format').value)
|
84
|
-
@time_format = convert_date_time_format(datasource.attribute('time-format').value)
|
85
|
-
@timestamp_format = convert_date_time_format(datasource.attribute('timestamp-format').value)
|
80
|
+
datasource = doc['fmresultset']['datasource']
|
81
|
+
meta = doc['fmresultset']['metadata']
|
82
|
+
resultset = doc['fmresultset']['resultset']
|
86
83
|
|
87
|
-
@
|
88
|
-
@
|
84
|
+
@date_format = convert_date_time_format(datasource['date-format'].to_s)
|
85
|
+
@time_format = convert_date_time_format(datasource['time-format'].to_s)
|
86
|
+
@timestamp_format = convert_date_time_format(datasource['timestamp-format'].to_s)
|
89
87
|
|
88
|
+
@foundset_count = resultset['count'].to_s.to_i
|
89
|
+
@total_count = datasource['total-count'].to_s.to_i
|
90
|
+
@table = datasource['table']
|
91
|
+
|
92
|
+
(layout.table = @table) if layout and layout.table_no_load.blank?
|
93
|
+
|
90
94
|
parse_fields(meta)
|
91
|
-
parse_portals(meta) if @include_portals
|
92
95
|
|
93
|
-
|
96
|
+
# This will always load portal meta, even if :include_portals was not specified.
|
97
|
+
# See Record for control of portal data loading.
|
98
|
+
parse_portals(meta)
|
94
99
|
|
100
|
+
return if resultset['record'].nil?
|
101
|
+
Rfm::Record.build_records(resultset['record'].rfm_force_array, self, @field_meta, @layout)
|
95
102
|
end
|
103
|
+
|
104
|
+
def field_names
|
105
|
+
field_meta.collect{|k,v| v.name}
|
106
|
+
end
|
107
|
+
|
108
|
+
def portal_names
|
109
|
+
portal_meta.keys
|
110
|
+
end
|
111
|
+
|
96
112
|
|
97
113
|
private
|
98
|
-
def remove_namespace(xml)
|
99
|
-
xml.gsub('xmlns="http://www.filemaker.com/xml/fmresultset" version="1.0"', '')
|
100
|
-
end
|
101
114
|
|
102
115
|
def check_for_errors(code, raise_401)
|
103
116
|
raise Rfm::Error.getError(code) if code != 0 && (code != 401 || raise_401)
|
104
117
|
end
|
105
118
|
|
106
119
|
def parse_fields(meta)
|
107
|
-
|
120
|
+
return if meta['field-definition'].blank?
|
121
|
+
|
122
|
+
meta['field-definition'].rfm_force_array.each do |field|
|
108
123
|
@field_meta[field['name']] = Rfm::Metadata::Field.new(field)
|
109
124
|
end
|
125
|
+
(layout.field_names = field_names) if layout and layout.field_names_no_load.blank?
|
110
126
|
end
|
111
127
|
|
112
128
|
def parse_portals(meta)
|
113
|
-
|
114
|
-
|
129
|
+
return if meta['relatedset-definition'].blank?
|
130
|
+
meta['relatedset-definition'].rfm_force_array.each do |relatedset|
|
131
|
+
next if relatedset.blank?
|
132
|
+
table, fields = relatedset['table'], {}
|
115
133
|
|
116
|
-
relatedset
|
117
|
-
name = field
|
134
|
+
relatedset['field-definition'].rfm_force_array.each do |field|
|
135
|
+
name = field['name'].to_s.gsub(Regexp.new(table + '::'), '')
|
118
136
|
fields[name] = Rfm::Metadata::Field.new(field)
|
119
137
|
end
|
120
138
|
|
121
139
|
@portal_meta[table] = fields
|
122
140
|
end
|
141
|
+
(layout.portal_meta = @portal_meta) if layout and layout.portal_meta_no_load.blank?
|
123
142
|
end
|
124
143
|
|
125
144
|
def convert_date_time_format(fm_format)
|
data/lib/rfm/server.rb
CHANGED
@@ -107,13 +107,13 @@ module Rfm
|
|
107
107
|
# * *name* is the name of this database
|
108
108
|
# * *state* is a hash of all server options used to initialize this server
|
109
109
|
class Server
|
110
|
-
|
110
|
+
|
111
111
|
# To create a Server object, you typically need at least a host name:
|
112
112
|
#
|
113
113
|
# myServer = Rfm::Server.new({:host => 'my.host.com'})
|
114
114
|
#
|
115
|
-
# Several other options are supported
|
116
|
-
#
|
115
|
+
# ===Several other options are supported
|
116
|
+
#
|
117
117
|
# * *host* the hostname of the Web Publishing Engine (WPE) server (defaults to 'localhost')
|
118
118
|
#
|
119
119
|
# * *port* the port number the WPE is listening no (defaults to 80 unless *ssl* +true+ which sets it to 443)
|
@@ -138,13 +138,13 @@ module Rfm
|
|
138
138
|
# ignores FileMaker's 401 error (no records found) and returns an empty record set instead; if you
|
139
139
|
# prefer a raised error when a find produces no errors, set this option to +true+
|
140
140
|
#
|
141
|
-
# ===SSL Options (SSL AND CERTIFICATE VERIFICATION ARE ON BY DEFAULT)
|
142
|
-
#
|
141
|
+
# ===SSL Options (SSL AND CERTIFICATE VERIFICATION ARE ON BY DEFAULT)
|
142
|
+
#
|
143
143
|
# * *ssl* +false+ if you want to turn SSL (HTTPS) off when connecting to connect to FileMaker (default is +true+)
|
144
144
|
#
|
145
|
-
# If you are using SSL and want to verify the certificate use the following options:
|
145
|
+
# If you are using SSL and want to verify the certificate, use the following options:
|
146
146
|
#
|
147
|
-
# * *root_cert* +
|
147
|
+
# * *root_cert* +true+ is the default. If you do not want to verify your SSL session, set this to +false+.
|
148
148
|
# You will want to turn this off if you are using a self signed certificate and do not have a certificate authority cert file.
|
149
149
|
# If you choose this option you will need to provide a cert *root_cert_name* and *root_cert_path* (if not in root directory).
|
150
150
|
#
|
@@ -154,8 +154,8 @@ module Rfm
|
|
154
154
|
#
|
155
155
|
# * *root_cert_path* path to cert file. (defaults to '/' if no path given)
|
156
156
|
#
|
157
|
-
# ===Configuration Examples
|
158
|
-
#
|
157
|
+
# ===Configuration Examples
|
158
|
+
#
|
159
159
|
# Example to turn off SSL:
|
160
160
|
#
|
161
161
|
# myServer = Rfm::Server.new({
|
@@ -192,8 +192,9 @@ module Rfm
|
|
192
192
|
# :root_cert_name => 'example.pem'
|
193
193
|
# :root_cert_path => '/usr/cert_file/'
|
194
194
|
# })
|
195
|
-
|
196
195
|
def initialize(options)
|
196
|
+
raise Rfm::Error::RfmError.new(0, "New instance of Rfm::Server has no host name.") if options[:host].to_s == ''
|
197
|
+
|
197
198
|
@state = {
|
198
199
|
:host => 'localhost',
|
199
200
|
:port => 80,
|
@@ -205,17 +206,18 @@ module Rfm
|
|
205
206
|
:password => '',
|
206
207
|
:log_actions => false,
|
207
208
|
:log_responses => false,
|
209
|
+
:log_parser => false,
|
208
210
|
:warn_on_redirect => true,
|
209
211
|
:raise_on_401 => false,
|
210
212
|
:timeout => 60
|
211
213
|
}.merge(options)
|
212
214
|
|
213
215
|
@state.freeze
|
214
|
-
|
216
|
+
|
215
217
|
@host_name = @state[:host]
|
216
218
|
@scheme = @state[:ssl] ? "https" : "http"
|
217
219
|
@port = @state[:ssl] && options[:port].nil? ? 443 : @state[:port]
|
218
|
-
|
220
|
+
|
219
221
|
@db = Rfm::Factory::DbFactory.new(self)
|
220
222
|
end
|
221
223
|
|
@@ -231,11 +233,13 @@ module Rfm
|
|
231
233
|
# get no error at this point if the database you access doesn't exist. Instead, you'll
|
232
234
|
# receive an error when you actually try to perform some action on a layout from this
|
233
235
|
# database.
|
234
|
-
|
235
|
-
|
236
|
-
|
236
|
+
# def [](dbname, acnt=nil, pass=nil)
|
237
|
+
# self.db[dbname, acnt, pass]
|
238
|
+
# end
|
239
|
+
def_delegator :db, :[]
|
237
240
|
|
238
241
|
attr_reader :db, :host_name, :port, :scheme, :state
|
242
|
+
alias_method :databases, :db
|
239
243
|
|
240
244
|
# Performs a raw FileMaker action. You will generally not call this method directly, but it
|
241
245
|
# is exposed in case you need to do something "under the hood."
|
@@ -272,12 +276,12 @@ module Rfm
|
|
272
276
|
def load_layout(layout)
|
273
277
|
post = {'-db' => layout.db.name, '-lay' => layout.name, '-view' => ''}
|
274
278
|
resp = http_fetch(@host_name, @port, "/fmi/xml/FMPXMLLAYOUT.xml", layout.db.account_name, layout.db.password, post)
|
275
|
-
remove_namespace(resp.body)
|
279
|
+
#remove_namespace(resp.body)
|
276
280
|
end
|
277
281
|
|
278
282
|
# Removes namespace from fmpxmllayout, so xpath will work
|
279
283
|
def remove_namespace(xml)
|
280
|
-
xml.gsub(
|
284
|
+
xml.gsub(/xmlns=\"[^\"]*\"/, '')
|
281
285
|
end
|
282
286
|
|
283
287
|
private
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Rfm
|
2
|
+
|
3
|
+
module ComplexQuery # @private :nodoc:
|
4
|
+
# Methods for Rfm::Layout to build complex queries
|
5
|
+
# Perform RFM find using complex boolean logic (multiple value options for a single field)
|
6
|
+
# Mimics creation of multiple find requests for "or" logic
|
7
|
+
# Use: rlayout_object.query({'fieldOne'=>['val1','val2','val3'], 'fieldTwo'=>'someValue', ...})
|
8
|
+
def query(hash_or_recid, options = {})
|
9
|
+
if hash_or_recid.kind_of? Hash
|
10
|
+
get_records('-findquery', assemble_query(hash_or_recid), options)
|
11
|
+
else
|
12
|
+
get_records('-find', {'-recid' => hash_or_recid.to_s}, options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Build ruby params to send to -query action via RFM
|
17
|
+
def assemble_query(query_hash)
|
18
|
+
key_values, query_map = build_key_values(query_hash)
|
19
|
+
key_values.merge("-query"=>query_translate(array_mix(query_map)))
|
20
|
+
end
|
21
|
+
|
22
|
+
# Build key-value definitions and query map '-q1...'
|
23
|
+
def build_key_values(qh)
|
24
|
+
key_values = {}
|
25
|
+
query_map = []
|
26
|
+
counter = 0
|
27
|
+
qh.each_with_index do |ha,i|
|
28
|
+
ha[1] = ha[1].to_a
|
29
|
+
query_tag = []
|
30
|
+
ha[1].each do |v|
|
31
|
+
key_values["-q#{counter}"] = ha[0]
|
32
|
+
key_values["-q#{counter}.value"] = v
|
33
|
+
query_tag << "q#{counter}"
|
34
|
+
counter += 1
|
35
|
+
end
|
36
|
+
query_map << query_tag
|
37
|
+
end
|
38
|
+
return key_values, query_map
|
39
|
+
end
|
40
|
+
|
41
|
+
# Build query request logic for FMP requests '-query...'
|
42
|
+
def array_mix(ary, line=[], rslt=[])
|
43
|
+
ary[0].to_a.each_with_index do |v,i|
|
44
|
+
array_mix(ary[1,ary.size], (line + [v]), rslt)
|
45
|
+
rslt << (line + [v]) if ary.size == 1
|
46
|
+
end
|
47
|
+
return rslt
|
48
|
+
end
|
49
|
+
|
50
|
+
# Translate query request logic to string
|
51
|
+
def query_translate(mixed_ary)
|
52
|
+
rslt = ""
|
53
|
+
sub = mixed_ary.collect {|a| "(#{a.join(',')})"}
|
54
|
+
sub.join(";")
|
55
|
+
end
|
56
|
+
|
57
|
+
end # ComplexQuery
|
58
|
+
|
59
|
+
# class Layout
|
60
|
+
# require 'rfm/layout'
|
61
|
+
# include ComplexQuery
|
62
|
+
# end
|
63
|
+
|
64
|
+
end # Rfm
|