ginjo-rfm 3.0.9 → 3.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/CHANGELOG.md +61 -40
- data/README.md +8 -8
- data/lib/rfm.rb +66 -67
- data/lib/rfm/VERSION +1 -1
- data/lib/rfm/base.rb +237 -241
- data/lib/rfm/database.rb +38 -24
- data/lib/rfm/error.rb +25 -25
- data/lib/rfm/layout.rb +217 -195
- data/lib/rfm/metadata/datum.rb +37 -37
- data/lib/rfm/metadata/field.rb +42 -39
- data/lib/rfm/metadata/field_control.rb +72 -72
- data/lib/rfm/metadata/layout_meta.rb +32 -32
- data/lib/rfm/metadata/resultset_meta.rb +74 -74
- data/lib/rfm/metadata/script.rb +3 -3
- data/lib/rfm/metadata/value_list_item.rb +30 -30
- data/lib/rfm/record.rb +80 -77
- data/lib/rfm/resultset.rb +63 -65
- data/lib/rfm/server.rb +31 -23
- data/lib/rfm/utilities/case_insensitive_hash.rb +4 -1
- data/lib/rfm/utilities/compound_query.rb +100 -101
- data/lib/rfm/utilities/config.rb +228 -218
- data/lib/rfm/utilities/connection.rb +65 -57
- data/lib/rfm/utilities/core_ext.rb +114 -119
- data/lib/rfm/utilities/factory.rb +122 -126
- data/lib/rfm/utilities/sax_parser.rb +1058 -1046
- data/lib/rfm/utilities/scope.rb +64 -0
- data/lib/rfm/version.rb +23 -7
- metadata +40 -39
data/lib/rfm/database.rb
CHANGED
@@ -58,8 +58,8 @@ module Rfm
|
|
58
58
|
# * *name* is the name of this database
|
59
59
|
# * *state* is a hash of all server options used to initialize this server
|
60
60
|
class Database
|
61
|
-
|
62
|
-
|
61
|
+
include Config
|
62
|
+
|
63
63
|
# Initialize a database object. You never really need to do this. Instead, just do this:
|
64
64
|
#
|
65
65
|
# myServer = Rfm::Server.new(...)
|
@@ -67,12 +67,12 @@ module Rfm
|
|
67
67
|
#
|
68
68
|
# This sample code gets a database object representing the Customers database on the FileMaker server.
|
69
69
|
def initialize(*args) #name, server_obj, acnt=nil, pass=nil
|
70
|
-
|
70
|
+
config(*args)
|
71
71
|
raise Rfm::Error::RfmError.new(0, "New instance of Rfm::Database has no name. Attempted name '#{state[:database]}'.") if state[:database].to_s == ''
|
72
72
|
@layouts = Rfm::Factory::LayoutFactory.new(server, self)
|
73
73
|
@scripts = Rfm::Factory::ScriptFactory.new(server, self)
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
meta_attr_accessor :server
|
77
77
|
attr_reader :layouts, :scripts
|
78
78
|
# Not sure if these writers are ever used
|
@@ -80,25 +80,39 @@ module Rfm
|
|
80
80
|
# Legacy methods
|
81
81
|
alias_method :layout, :layouts
|
82
82
|
alias_method :script, :scripts
|
83
|
-
|
84
|
-
def name
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
def
|
89
|
-
|
83
|
+
|
84
|
+
def name
|
85
|
+
state[:database].to_s
|
86
|
+
end
|
87
|
+
|
88
|
+
def account_name
|
89
|
+
state[:account_name]
|
90
|
+
end
|
91
|
+
|
92
|
+
def account_name=(x)
|
93
|
+
config :account_name=>x
|
94
|
+
end
|
95
|
+
|
96
|
+
def password
|
97
|
+
state[:password]
|
98
|
+
end
|
99
|
+
|
100
|
+
def password=(x)
|
101
|
+
config :password=>x
|
102
|
+
end
|
103
|
+
|
90
104
|
def config(*args)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
105
|
+
super(:capture_strings_with=>[:database, :account_name, :password])
|
106
|
+
super(*args) do |params|
|
107
|
+
(self.server = params[:objects][0]) if params && params[:objects] && params[:objects][0] && params[:objects][0].is_a?(Rfm::Server)
|
108
|
+
end
|
95
109
|
end
|
96
|
-
|
110
|
+
|
97
111
|
alias_method :server_orig, :server
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
112
|
+
def server
|
113
|
+
server_orig || (self.server = Rfm::Server.new(state[:host], state[:account_name], state[:password], self))
|
114
|
+
end
|
115
|
+
|
102
116
|
|
103
117
|
# Access the Layout object representing a layout in this database. For example:
|
104
118
|
#
|
@@ -111,10 +125,10 @@ module Rfm
|
|
111
125
|
# returned is created on the fly and assumed to refer to a valid layout, but you will
|
112
126
|
# get no error at this point if the layout you specify doesn't exist. Instead, you'll
|
113
127
|
# receive an error when you actually try to perform some action it.
|
114
|
-
|
115
|
-
|
116
|
-
|
128
|
+
# def [](layout_name)
|
129
|
+
# self.layout[layout_name]
|
130
|
+
# end
|
117
131
|
def_delegators :layouts, :[], :modelize, :models # modelize & models acquired from Rfm::Base
|
118
132
|
|
119
133
|
end
|
120
|
-
end
|
134
|
+
end
|
data/lib/rfm/error.rb
CHANGED
@@ -1,38 +1,38 @@
|
|
1
1
|
module Rfm
|
2
|
-
|
2
|
+
|
3
3
|
# Error is the base for the error hierarchy representing errors returned by Filemaker.
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# One could raise a FileMakerError by doing:
|
6
6
|
# raise Rfm::Error.getError(102)
|
7
7
|
#
|
8
8
|
# It also takes an optional argument to give a more discriptive error message:
|
9
9
|
# err = Rfm::Error.getError(102, 'add description with more detail here')
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# The above code would return a FieldMissing instance. Your could use this instance to raise that appropriate
|
12
12
|
# exception:
|
13
|
-
#
|
14
|
-
# raise err
|
15
|
-
#
|
13
|
+
#
|
14
|
+
# raise err
|
15
|
+
#
|
16
16
|
# You could access the specific error code by accessing:
|
17
|
-
#
|
17
|
+
#
|
18
18
|
# err.code
|
19
19
|
module Error
|
20
|
-
|
20
|
+
|
21
21
|
class RfmError < StandardError #:nodoc:
|
22
22
|
attr_reader :code
|
23
|
-
|
23
|
+
|
24
24
|
def initialize(code, message=nil)
|
25
25
|
@code = code
|
26
26
|
super(message)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
class UnknownError < RfmError
|
30
|
+
class UnknownError < RfmError
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
class SystemError < RfmError
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
class MissingError < RfmError
|
37
37
|
end
|
38
38
|
|
@@ -42,10 +42,10 @@ module Rfm
|
|
42
42
|
class FieldMissingError < MissingError #:nodoc:
|
43
43
|
end
|
44
44
|
|
45
|
-
class ScriptMissingError < MissingError #:nodoc:
|
45
|
+
class ScriptMissingError < MissingError #:nodoc:
|
46
46
|
end
|
47
47
|
|
48
|
-
class LayoutMissingError < MissingError #:nodoc:
|
48
|
+
class LayoutMissingError < MissingError #:nodoc:
|
49
49
|
end
|
50
50
|
|
51
51
|
class TableMissingError < MissingError #:nodoc:
|
@@ -82,7 +82,7 @@ module Rfm
|
|
82
82
|
end
|
83
83
|
|
84
84
|
class ValidationError < RfmError #:nodoc:
|
85
|
-
end
|
85
|
+
end
|
86
86
|
|
87
87
|
class DateValidationError < ValidationError #:nodoc:
|
88
88
|
end
|
@@ -90,7 +90,7 @@ module Rfm
|
|
90
90
|
class TimeValidationError < ValidationError #:nodoc:
|
91
91
|
end
|
92
92
|
|
93
|
-
class NumberValidationError < ValidationError #:nodoc:
|
93
|
+
class NumberValidationError < ValidationError #:nodoc:
|
94
94
|
end
|
95
95
|
|
96
96
|
class RangeValidationError < ValidationError #:nodoc:
|
@@ -115,11 +115,11 @@ module Rfm
|
|
115
115
|
end
|
116
116
|
|
117
117
|
class FileError < RfmError #:nodoc:
|
118
|
-
end
|
118
|
+
end
|
119
119
|
|
120
120
|
class UnableToOpenFileError < FileError #:nodoc:
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
extend self
|
124
124
|
# This method returns the appropriate FileMaker object depending on the error code passed to it. It
|
125
125
|
# also accepts an optional message.
|
@@ -129,15 +129,15 @@ module Rfm
|
|
129
129
|
error = klass.new(code, message)
|
130
130
|
error
|
131
131
|
end
|
132
|
-
|
132
|
+
|
133
133
|
def build_message(klass, code, message=nil) #:nodoc:
|
134
134
|
msg = ": #{message}"
|
135
135
|
msg << " " unless message.nil?
|
136
136
|
msg << "(FileMaker Error ##{code})"
|
137
|
-
|
137
|
+
|
138
138
|
"#{klass.to_s.gsub(/Rfm::Error::/, '')} occurred#{msg}"
|
139
139
|
end
|
140
|
-
|
140
|
+
|
141
141
|
def find_by_code(code) #:nodoc:
|
142
142
|
case code
|
143
143
|
when 0..99 then SystemError
|
@@ -159,8 +159,8 @@ module Rfm
|
|
159
159
|
elsif code == 306; RecordModIdDoesNotMatchError
|
160
160
|
else; ConcurrencyError; end
|
161
161
|
when 400..499
|
162
|
-
|
163
|
-
|
162
|
+
if code == 401; NoRecordsFoundError
|
163
|
+
else; GeneralError; end
|
164
164
|
when 500..599
|
165
165
|
if code == 500; DateValidationError
|
166
166
|
elsif code == 501; TimeValidationError
|
@@ -182,5 +182,5 @@ module Rfm
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
end
|
185
|
-
|
186
|
-
end
|
185
|
+
|
186
|
+
end
|
data/lib/rfm/layout.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'delegate'
|
2
|
+
|
2
3
|
module Rfm
|
3
4
|
# The Layout object represents a single FileMaker Pro layout. You use it to interact with
|
4
5
|
# records in FileMaker. *All* access to FileMaker data is done through a layout, and this
|
@@ -118,45 +119,47 @@ module Rfm
|
|
118
119
|
# * +value_lists+ is a hash of arrays. The keys are value list names, and the values in the hash
|
119
120
|
# are arrays containing the actual value list items. +value_lists+ will include every value
|
120
121
|
# list that is attached to any field on the layout
|
121
|
-
|
122
|
+
|
122
123
|
class Layout
|
123
|
-
|
124
|
+
include Config
|
124
125
|
|
125
126
|
meta_attr_accessor :db
|
126
127
|
attr_reader :field_mapping
|
127
128
|
attr_writer :resultset_meta
|
128
129
|
def_delegator :db, :server
|
129
130
|
#alias_method :database, :db # This fails if db object hasn't been set yet with meta_attr_accessor
|
130
|
-
|
131
|
+
|
132
|
+
def database
|
133
|
+
db
|
134
|
+
end
|
135
|
+
|
131
136
|
attr_accessor :model #, :parent_layout, :subs
|
132
137
|
def_delegators :meta, :field_controls, :value_lists
|
133
138
|
def_delegators :resultset_meta, :date_format, :time_format, :timestamp_format, :field_meta, :portal_meta, :table
|
134
139
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
140
|
+
# Methods that must be kept after rewrite!!!
|
141
|
+
#
|
142
|
+
# field_mapping
|
143
|
+
# db (database)
|
144
|
+
# name
|
145
|
+
# resultset_meta
|
146
|
+
# date_format
|
147
|
+
# time_format
|
148
|
+
# timestamp_format
|
149
|
+
# field_meta
|
150
|
+
# field_controls
|
151
|
+
# field_names
|
152
|
+
# field_names_no_load
|
153
|
+
# value_lists
|
154
|
+
# count
|
155
|
+
# total_count
|
156
|
+
# portal_meta
|
157
|
+
# portal_meta_no_load
|
158
|
+
# portal_names
|
159
|
+
# table
|
160
|
+
# table_no_load
|
161
|
+
# server
|
162
|
+
|
160
163
|
# Initialize a layout object. You never really need to do this. Instead, just do this:
|
161
164
|
#
|
162
165
|
# myServer = Rfm::Server.new(...)
|
@@ -170,38 +173,39 @@ module Rfm
|
|
170
173
|
#
|
171
174
|
# myServer = Rfm::Server.new(...)
|
172
175
|
# myLayout = myServer["Customers"]["Details"]
|
176
|
+
|
173
177
|
def initialize(*args) #name, db_obj
|
174
|
-
#
|
175
|
-
|
176
|
-
|
178
|
+
# self.subs ||= []
|
179
|
+
config(*args)
|
180
|
+
raise Rfm::Error::RfmError.new(0, "New instance of Rfm::Layout has no name. Attempted name '#{state[:layout]}'.") if state[:layout].to_s == ''
|
177
181
|
@loaded = false
|
178
182
|
@meta = Metadata::LayoutMeta.new(self)
|
179
183
|
self
|
180
184
|
end
|
181
185
|
|
182
186
|
def config(*args)
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
187
|
+
super(:capture_strings_with=>[:layout])
|
188
|
+
super(*args) do |params|
|
189
|
+
(self.name = params[:strings][0]) if params && params[:strings] && params[:strings].any?
|
190
|
+
(self.db = params[:objects][0]) if params && params[:objects] && params[:objects][0] && params[:objects][0].is_a?(Rfm::Database)
|
191
|
+
end
|
188
192
|
end
|
189
|
-
|
193
|
+
|
190
194
|
alias_method :db_orig, :db
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
+
def db
|
196
|
+
db_orig || (self.db = Rfm::Database.new(state[:database], state[:account_name], state[:password], self))
|
197
|
+
end
|
198
|
+
|
195
199
|
# Returns a ResultSet object containing _every record_ in the table associated with this layout.
|
196
200
|
def all(options = {})
|
197
201
|
get_records('-findall', {}, options)
|
198
202
|
end
|
199
|
-
|
203
|
+
|
200
204
|
# Returns a ResultSet containing a single random record from the table associated with this layout.
|
201
205
|
def any(options = {})
|
202
206
|
get_records('-findany', {}, options)
|
203
207
|
end
|
204
|
-
|
208
|
+
|
205
209
|
# Finds a record. Typically you will pass in a hash of field names and values. For example:
|
206
210
|
#
|
207
211
|
# myLayout.find({"First Name" => "Bill"})
|
@@ -209,17 +213,17 @@ module Rfm
|
|
209
213
|
# Values in the hash work just like value in FileMaker's Find mode. You can use any special
|
210
214
|
# symbols (+==+, +...+, +>+, etc...).
|
211
215
|
#
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
216
|
+
# Create a Filemaker 'omit' request by including an :omit key with a value of true.
|
217
|
+
#
|
218
|
+
# myLayout.find :field1 => 'val1', :field2 => 'val2', :omit => true
|
219
|
+
#
|
220
|
+
# Create multiple Filemaker find requests by passing an array of hashes to the #find method.
|
221
|
+
#
|
222
|
+
# myLayout.find [{:field1 => 'bill', :field2 => 'admin'}, {:field3 => 'inactive', :omit => true}, ...]
|
223
|
+
#
|
224
|
+
# If the value of a field in a find request is an array of strings, the string values will be logically OR'd in the query.
|
225
|
+
#
|
226
|
+
# myLayout.find :fieldOne => ['bill','mike','bob'], :fieldTwo =>'staff'
|
223
227
|
#
|
224
228
|
# If you pass anything other than a hash or an array as the first parameter, it is converted to a string and
|
225
229
|
# assumed to be FileMaker's internal id for a record (the recid).
|
@@ -227,16 +231,16 @@ module Rfm
|
|
227
231
|
# myLayout.find 54321
|
228
232
|
#
|
229
233
|
def find(find_criteria, options = {})
|
230
|
-
|
231
|
-
|
232
|
-
|
234
|
+
#puts "layout.find-#{self.object_id}"
|
235
|
+
options.merge!({:field_mapping => field_mapping.invert}) if field_mapping
|
236
|
+
get_records(*Rfm::CompoundQuery.new(find_criteria, options))
|
233
237
|
end
|
234
|
-
|
238
|
+
|
235
239
|
# Access to raw -findquery command.
|
236
240
|
def query(query_hash, options = {})
|
237
|
-
|
241
|
+
get_records('-findquery', query_hash, options)
|
238
242
|
end
|
239
|
-
|
243
|
+
|
240
244
|
# Updates the contents of the record whose internal +recid+ is specified. Send in a hash of new
|
241
245
|
# data in the +values+ parameter. Returns a RecordSet containing the modified record. For example:
|
242
246
|
#
|
@@ -249,7 +253,7 @@ module Rfm
|
|
249
253
|
get_records('-edit', {'-recid' => recid}.merge(values), options)
|
250
254
|
#get_records('-edit', {'-recid' => recid}.merge(expand_repeats(values)), options) # attempt to set repeating fields.
|
251
255
|
end
|
252
|
-
|
256
|
+
|
253
257
|
# Creates a new record in the table associated with this layout. Pass field data as a hash in the
|
254
258
|
# +values+ parameter. Returns the newly created record in a RecordSet. You can use the returned
|
255
259
|
# record to, ie, discover the values in auto-enter fields (like serial numbers).
|
@@ -264,7 +268,7 @@ module Rfm
|
|
264
268
|
def create(values, options = {})
|
265
269
|
get_records('-new', values, options)
|
266
270
|
end
|
267
|
-
|
271
|
+
|
268
272
|
# Deletes the record with the specified internal recid. Returns a ResultSet with the deleted record.
|
269
273
|
#
|
270
274
|
# For example:
|
@@ -277,171 +281,189 @@ module Rfm
|
|
277
281
|
get_records('-delete', {'-recid' => recid}, options)
|
278
282
|
return nil
|
279
283
|
end
|
280
|
-
|
284
|
+
|
281
285
|
# Retrieves metadata only, with an empty resultset.
|
282
286
|
def view(options = {})
|
283
|
-
|
287
|
+
get_records('-view', {}, options)
|
284
288
|
end
|
285
|
-
|
289
|
+
|
286
290
|
# Get the foundset_count only given criteria & options.
|
287
291
|
def count(find_criteria, options={})
|
288
|
-
|
292
|
+
find(find_criteria, options.merge({:max_records => 0})).foundset_count
|
289
293
|
end
|
290
|
-
|
294
|
+
|
291
295
|
def get_records(action, extra_params = {}, options = {})
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
296
|
+
# TODO: See auto-grammar bypbass in connection.rb.
|
297
|
+
grammar_option = state(options)[:grammar]
|
298
|
+
options.merge!(:grammar=>grammar_option) if grammar_option
|
299
|
+
template = options.delete :template
|
300
|
+
|
301
|
+
# # TODO: Remove this code it is no longer used.
|
302
|
+
# #include_portals = options[:include_portals] ? options.delete(:include_portals) : nil
|
303
|
+
# include_portals = !options[:ignore_portals]
|
304
|
+
|
301
305
|
# Apply mapping from :field_mapping, to send correct params in URL.
|
302
306
|
prms = params.merge(extra_params)
|
303
307
|
map = field_mapping.invert
|
304
308
|
options.merge!({:field_mapping => map}) if map && !map.empty?
|
305
309
|
# TODO: Make this part handle string AND symbol keys. (isn't this already done?)
|
306
310
|
#map.each{|k,v| prms[k]=prms.delete(v) if prms[v]}
|
307
|
-
|
311
|
+
|
308
312
|
#prms.dup.each_key{|k| prms[map[k.to_s]]=prms.delete(k) if map[k.to_s]}
|
309
313
|
prms.dup.each_key do |k|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
314
|
+
new_key = map[k.to_s] || k
|
315
|
+
if prms[new_key].is_a? Array
|
316
|
+
prms[new_key].each_with_index do |v, i|
|
317
|
+
prms["#{new_key}(#{i+1})"]=v
|
318
|
+
end
|
319
|
+
prms.delete new_key
|
320
|
+
else
|
321
|
+
prms[new_key]=prms.delete(k) if new_key != k
|
322
|
+
end
|
323
|
+
#puts "PRMS: #{new_key} #{prms[new_key].class} #{prms[new_key]}"
|
320
324
|
end
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
325
|
+
|
326
|
+
#c = Connection.new(action, prms, options, state.merge(:parent=>self))
|
327
|
+
c = Connection.new(action, prms, options, self)
|
328
|
+
#rslt = c.parse(template || :fmresultset, Rfm::Resultset.new(self, self))
|
329
|
+
rslt = c.parse(template, Rfm::Resultset.new(self, self))
|
330
|
+
capture_resultset_meta(rslt) unless resultset_meta_valid? #(@resultset_meta && @resultset_meta.error != '401')
|
331
|
+
rslt
|
328
332
|
end
|
329
|
-
|
333
|
+
|
330
334
|
def params
|
331
335
|
{"-db" => state[:database], "-lay" => self.name}
|
332
336
|
end
|
333
337
|
|
334
|
-
def name
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
338
|
+
def name
|
339
|
+
state[:layout].to_s
|
340
|
+
end
|
341
|
+
|
342
|
+
|
339
343
|
### Metadata from Layout ###
|
340
|
-
|
344
|
+
|
341
345
|
def meta
|
342
|
-
|
346
|
+
@loaded ? @meta : load_layout
|
343
347
|
end
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
348
|
+
|
349
|
+
def field_names
|
350
|
+
case
|
351
|
+
when @loaded
|
352
|
+
meta.field_names
|
353
|
+
when @resultset_meta
|
354
|
+
resultset_meta.field_names
|
355
|
+
else meta.field_names
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
def field_names
|
360
|
+
# case
|
361
|
+
# when @loaded; meta.field_names
|
362
|
+
# when @resultset_meta; resultset_meta.field_names
|
363
|
+
# else meta.field_names
|
364
|
+
# end
|
365
|
+
meta.field_names
|
366
|
+
end
|
367
|
+
|
368
|
+
def field_keys
|
369
|
+
# case
|
370
|
+
# when @loaded; @meta.field_keys
|
371
|
+
# when @resultset_meta; @resultset_meta.field_keys
|
372
|
+
# else meta.field_keys
|
373
|
+
# end
|
374
|
+
meta.field_keys
|
375
|
+
end
|
376
|
+
|
377
|
+
|
378
|
+
|
364
379
|
### Metadata from Resultset ###
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
380
|
+
|
381
|
+
def resultset_meta
|
382
|
+
#@resultset_meta || view.meta
|
383
|
+
resultset_meta_valid? ? @resultset_meta : view.meta
|
384
|
+
end
|
385
|
+
|
386
|
+
def resultset_meta_valid?
|
387
|
+
if @resultset_meta && @resultset_meta.error != '401'
|
388
|
+
true
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# Should always refresh
|
393
|
+
def total_count
|
394
|
+
view.total_count
|
395
|
+
end
|
396
|
+
|
397
|
+
def capture_resultset_meta(resultset)
|
398
|
+
(@resultset_meta = resultset.clone.replace([])) #unless @resultset_meta
|
399
|
+
@resultset_meta = resultset.meta
|
400
|
+
end
|
401
|
+
|
402
|
+
def portal_names
|
403
|
+
return 'UNDER-CONTSTRUCTION'
|
404
|
+
end
|
405
|
+
|
406
|
+
|
407
|
+
|
408
|
+
|
409
|
+
### Utility ###
|
410
|
+
|
389
411
|
def load_layout
|
390
|
-
|
391
|
-
|
412
|
+
#@loaded = true # This is first so parsing call to 'meta' wont cause infinite loop,
|
413
|
+
# but I changed parsing template to refer directly to inst var instead of accessor method.
|
392
414
|
connection = Connection.new('-view', {'-db' => state[:database], '-lay' => name}, {:grammar=>'FMPXMLLAYOUT'}, self)
|
393
415
|
begin
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
416
|
+
connection.parse(:fmpxmllayout, self)
|
417
|
+
@loaded = true
|
418
|
+
rescue
|
419
|
+
@meta.clear
|
420
|
+
raise $!
|
421
|
+
end
|
422
|
+
@meta
|
401
423
|
end
|
402
|
-
|
424
|
+
|
403
425
|
def check_for_errors(code=@meta['error'].to_i, raise_401=state[:raise_401])
|
404
|
-
|
426
|
+
#puts ["\nRESULTSET#check_for_errors", code, raise_401]
|
405
427
|
raise Rfm::Error.getError(code) if code != 0 && (code != 401 || raise_401)
|
406
428
|
end
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
429
|
+
|
430
|
+
def field_mapping
|
431
|
+
@field_mapping ||= load_field_mapping(state[:field_mapping])
|
432
|
+
end
|
433
|
+
|
434
|
+
def load_field_mapping(mapping={})
|
435
|
+
mapping = (mapping || {}).to_cih
|
436
|
+
def mapping.invert
|
437
|
+
super.to_cih
|
438
|
+
end
|
439
|
+
mapping
|
440
|
+
end
|
441
|
+
|
420
442
|
# Creates new class with layout name.
|
421
443
|
def modelize
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
# rescue StandardError, SyntaxError
|
433
|
-
#
|
434
|
-
#
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
444
|
+
@model ||= (
|
445
|
+
model_name = name.to_s.gsub(/\W|_/, ' ').title_case.gsub(/\s/,'')
|
446
|
+
#model_class = eval("::" + model_name + "= Class.new(Rfm::Base)")
|
447
|
+
model_class = Rfm.const_defined?(model_name) ? Rfm.const_get(model_name) : Rfm.const_set(model_name, Class.new(Rfm::Base))
|
448
|
+
model_class.class_exec(self) do |layout_obj|
|
449
|
+
@layout = layout_obj
|
450
|
+
end
|
451
|
+
model_class.config :parent=>'@layout'
|
452
|
+
model_class
|
453
|
+
)
|
454
|
+
# rescue StandardError, SyntaxError
|
455
|
+
# puts "Error in layout#modelize: #{$!}"
|
456
|
+
# nil
|
457
|
+
end
|
458
|
+
|
459
|
+
def models
|
460
|
+
#subs.collect{|s| s.model}
|
461
|
+
[@model]
|
462
|
+
end
|
463
|
+
|
464
|
+
|
465
|
+
private :load_layout, :get_records, :params, :check_for_errors
|
466
|
+
|
467
|
+
|
446
468
|
end # Layout
|
447
|
-
end # Rfm
|
469
|
+
end # Rfm
|