ginjo-rfm 3.0.9 → 3.0.10
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.
- 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
|