quickbase_client 1.0.2 → 1.0.3
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/README.rdoc +2 -0
- data/lib/QuickBaseClient.rb +145 -91
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -29,6 +29,8 @@ More information about the QuickBase Client is available here -
|
|
29
29
|
|
30
30
|
== Change History
|
31
31
|
|
32
|
+
1.0.3 - 12/07/2010 - Various small method improvements.
|
33
|
+
|
32
34
|
1.0.2 - 12/05/2010 - Added removeFileAttachment().
|
33
35
|
|
34
36
|
1.0.1 - 11/26/2010 - Will now use HTTPClient instead of Net::HTTP, if you already have HTTPClient.
|
data/lib/QuickBaseClient.rb
CHANGED
@@ -13,10 +13,16 @@
|
|
13
13
|
|
14
14
|
require 'rexml/document'
|
15
15
|
require 'net/https'
|
16
|
-
require 'socket'
|
17
16
|
require 'json'
|
18
17
|
require 'QuickBaseMisc'
|
19
18
|
|
19
|
+
begin
|
20
|
+
require 'httpclient'
|
21
|
+
USING_HTTPCLIENT = true
|
22
|
+
rescue LoadError
|
23
|
+
USING_HTTPCLIENT = false
|
24
|
+
end
|
25
|
+
|
20
26
|
module QuickBase
|
21
27
|
|
22
28
|
# QuickBase client: Version 1.0.0: Ruby wrapper class for QuickBase HTTP API.
|
@@ -144,25 +150,36 @@ class Client
|
|
144
150
|
|
145
151
|
# Initializes the connection to QuickBase.
|
146
152
|
def setHTTPConnection( useSSL, org = "www", domain = "quickbase", proxy_options = nil )
|
153
|
+
@useSSL = useSSL
|
147
154
|
@org = org
|
148
155
|
@domain = domain
|
149
|
-
if
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
156
|
+
if USING_HTTPCLIENT
|
157
|
+
if proxy_options
|
158
|
+
@httpConnection = HTTPClient.new( "#{proxy_options["proxy_server"]}:#{proxy_options["proxy_port"] || useSSL ? "443" : "80"}" )
|
159
|
+
@httpConnection.set_auth(proxy_options["proxy_server"], proxy_options["proxy_user"], proxy_options["proxy_password"])
|
160
|
+
else
|
161
|
+
@httpConnection = HTTPClient.new
|
162
|
+
end
|
163
|
+
else
|
164
|
+
if proxy_options
|
165
|
+
@httpProxy = Net::HTTP::Proxy(proxy_options["proxy_server"], proxy_options["proxy_port"], proxy_options["proxy_user"], proxy_options["proxy_password"])
|
166
|
+
@httpConnection = @httpProxy.new( "#{@org}.#{@domain}.com", useSSL ? 443 : 80)
|
167
|
+
else
|
168
|
+
@httpConnection = Net::HTTP.new( "#{@org}.#{@domain}.com", useSSL ? 443 : 80 )
|
169
|
+
end
|
170
|
+
@httpConnection.use_ssl = useSSL
|
171
|
+
@httpConnection.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
172
|
+
end
|
157
173
|
end
|
158
174
|
|
159
175
|
# Causes useful information to be printed to the screen for every HTTP request.
|
160
176
|
def debugHTTPConnection()
|
161
|
-
@httpConnection.set_debug_output $stdout if @httpConnection
|
177
|
+
@httpConnection.set_debug_output $stdout if @httpConnection and USING_HTTPCLIENT == false
|
162
178
|
end
|
163
179
|
|
164
180
|
# Sets the QuickBase URL and port to use for requests.
|
165
181
|
def setqbhost( useSSL, org = "www", domain = "quickbase" )
|
182
|
+
@useSSL = useSSL
|
166
183
|
@org = org
|
167
184
|
@domain = domain
|
168
185
|
@qbhost = useSSL ? "https://#{@org}.#{@domain}.com:443" : "http://#{@org}.#{@domain}.com"
|
@@ -216,8 +233,14 @@ class Client
|
|
216
233
|
begin
|
217
234
|
|
218
235
|
# send the request
|
219
|
-
|
220
|
-
|
236
|
+
if USING_HTTPCLIENT
|
237
|
+
response = @httpConnection.post( @requestURL, @requestXML, @requestHeaders )
|
238
|
+
@responseCode = response.status
|
239
|
+
@responseXML = response.content
|
240
|
+
else
|
241
|
+
@responseCode, @responseXML = @httpConnection.post( @requestURL, @requestXML, @requestHeaders )
|
242
|
+
end
|
243
|
+
|
221
244
|
printResponse( @responseCode, @responseXML ) if @printRequestsAndResponses
|
222
245
|
|
223
246
|
if not isHTMLRequest
|
@@ -352,7 +375,7 @@ class Client
|
|
352
375
|
fire( "onProcessResponse" )
|
353
376
|
|
354
377
|
parseResponseXML( responseXML )
|
355
|
-
@ticket
|
378
|
+
@ticket ||= getResponseValue( :ticket )
|
356
379
|
@udata = getResponseValue( :udata )
|
357
380
|
getErrorInfoFromResponse
|
358
381
|
end
|
@@ -388,6 +411,7 @@ class Client
|
|
388
411
|
# Gets the value for a specific field at the top level
|
389
412
|
# of the XML returned from QuickBase.
|
390
413
|
def getResponseValue( field )
|
414
|
+
@fieldValue = nil
|
391
415
|
if field and @responseXMLdoc
|
392
416
|
@fieldValue = @responseXMLdoc.root.elements[ field.to_s ]
|
393
417
|
@fieldValue = fieldValue.text if fieldValue and fieldValue.has_text?
|
@@ -490,13 +514,14 @@ class Client
|
|
490
514
|
|
491
515
|
# Returns the value of a field property, or nil.
|
492
516
|
def lookupFieldPropertyByName( fieldName, property )
|
517
|
+
theproperty = nil
|
493
518
|
if isValidFieldProperty?(property)
|
494
519
|
fid = lookupFieldIDByName( fieldName )
|
495
520
|
field = lookupField( fid ) if fid
|
496
|
-
theproperty = nil
|
497
521
|
theproperty = field.elements[ property ] if field
|
498
522
|
theproperty = theproperty.text if theproperty and theproperty.has_text?
|
499
523
|
end
|
524
|
+
theproperty
|
500
525
|
end
|
501
526
|
|
502
527
|
# Returns whether a field will show a Total on reports.
|
@@ -691,7 +716,7 @@ class Client
|
|
691
716
|
|
692
717
|
# Returns an array of XML sub-elements with the specified attribute value.
|
693
718
|
def findElementsByAttributeValue( elements, attribute_name, attribute_value )
|
694
|
-
elementArray =
|
719
|
+
elementArray = []
|
695
720
|
if elements
|
696
721
|
if elements.is_a?( REXML::Element )
|
697
722
|
elements.each_element_with_attribute( attribute_name, attribute_value ) { |e| elementArray << e }
|
@@ -708,7 +733,7 @@ class Client
|
|
708
733
|
|
709
734
|
# Returns an array of XML sub-elements with the specified attribute name.
|
710
735
|
def findElementsByAttributeName( elements, attribute_name )
|
711
|
-
elementArray =
|
736
|
+
elementArray = []
|
712
737
|
if elements
|
713
738
|
elements.each_element_with_attribute( attribute_name ) { |e| elementArray << e }
|
714
739
|
end
|
@@ -955,7 +980,7 @@ class Client
|
|
955
980
|
if getSchema(dbid)
|
956
981
|
if @chdbids
|
957
982
|
chdbidArray = findElementsByAttributeName( @chdbids, "name" )
|
958
|
-
|
983
|
+
numTables = chdbidArray.length
|
959
984
|
end
|
960
985
|
end
|
961
986
|
numTables
|
@@ -990,11 +1015,9 @@ class Client
|
|
990
1015
|
|
991
1016
|
# Returns whether a given string represents a valid QuickBase field type.
|
992
1017
|
def isValidFieldType?( type )
|
993
|
-
|
994
|
-
@validFieldTypes = %w{ checkbox dblink date duration email file fkey float formula currency
|
1018
|
+
@validFieldTypes ||= %w{ checkbox dblink date duration email file fkey float formula currency
|
995
1019
|
lookup phone percent rating recordid text timeofday timestamp url userid icalendarbutton }
|
996
|
-
|
997
|
-
ret = @validFieldTypes.include?( type )
|
1020
|
+
@validFieldTypes.include?( type )
|
998
1021
|
end
|
999
1022
|
|
1000
1023
|
# Returns a field type string given the more human-friendly label for a field type.
|
@@ -1109,7 +1132,7 @@ class Client
|
|
1109
1132
|
# * filename: if the field is a file attachment field, the name of the file that should be displayed in QuickBase.
|
1110
1133
|
# * value: the value to set in this field. If the field is a file attachment field, the name of the file that should be uploaded into QuickBase.
|
1111
1134
|
def addFieldValuePair( name, fid, filename, value )
|
1112
|
-
@fvlist
|
1135
|
+
@fvlist ||= []
|
1113
1136
|
@fvlist << FieldValuePairXML.new( self, name, fid, filename, value ).to_s
|
1114
1137
|
@fvlist
|
1115
1138
|
end
|
@@ -1147,7 +1170,7 @@ class Client
|
|
1147
1170
|
fid = lookupField( id )
|
1148
1171
|
if fid
|
1149
1172
|
fname = lookupFieldNameFromID( id )
|
1150
|
-
@fnames
|
1173
|
+
@fnames ||= []
|
1151
1174
|
@fnames << fname
|
1152
1175
|
else
|
1153
1176
|
raise "verifyFieldList: '#{id}' is not a valid field ID"
|
@@ -1162,7 +1185,7 @@ class Client
|
|
1162
1185
|
fnames.each { |name|
|
1163
1186
|
fid = lookupFieldIDByName( name )
|
1164
1187
|
if fid
|
1165
|
-
@fids
|
1188
|
+
@fids ||= []
|
1166
1189
|
@fids << fid
|
1167
1190
|
else
|
1168
1191
|
raise "verifyFieldList: '#{name}' is not a valid field name"
|
@@ -1230,8 +1253,8 @@ class Client
|
|
1230
1253
|
queryOperator = ""
|
1231
1254
|
|
1232
1255
|
if @queryOperators.nil?
|
1233
|
-
@queryOperators =
|
1234
|
-
@queryOperatorFieldType =
|
1256
|
+
@queryOperators = {}
|
1257
|
+
@queryOperatorFieldType = {}
|
1235
1258
|
|
1236
1259
|
@queryOperators[ "CT" ] = [ "contains", "[]" ]
|
1237
1260
|
@queryOperators[ "XCT" ] = [ "does not contain", "![]" ]
|
@@ -1288,16 +1311,20 @@ class Client
|
|
1288
1311
|
|
1289
1312
|
# Get a field's base type using its name.
|
1290
1313
|
def lookupBaseFieldTypeByName( fieldName )
|
1314
|
+
type = ""
|
1291
1315
|
fid = lookupFieldIDByName( fieldName )
|
1292
1316
|
field = lookupField( fid ) if fid
|
1293
1317
|
type = field.attributes[ "base_type" ] if field
|
1318
|
+
type
|
1294
1319
|
end
|
1295
1320
|
|
1296
1321
|
# Get a field's type using its name.
|
1297
1322
|
def lookupFieldTypeByName( fieldName )
|
1323
|
+
type = ""
|
1298
1324
|
fid = lookupFieldIDByName( fieldName )
|
1299
1325
|
field = lookupField( fid ) if fid
|
1300
1326
|
type = field.attributes[ "field_type" ] if field
|
1327
|
+
type
|
1301
1328
|
end
|
1302
1329
|
|
1303
1330
|
# Returns the string required for emebedding CSV data in a request.
|
@@ -1438,7 +1465,7 @@ class Client
|
|
1438
1465
|
# Converts a string into an array, given a field separator.
|
1439
1466
|
# '"' followed by the field separator are treated the same way as just the field separator.
|
1440
1467
|
def splitString( string, fieldSeparator = "," )
|
1441
|
-
ra =
|
1468
|
+
ra = []
|
1442
1469
|
string.chomp!
|
1443
1470
|
if string.include?( "\"" )
|
1444
1471
|
a=string.split( "\"#{fieldSeparator}" )
|
@@ -1456,7 +1483,7 @@ class Client
|
|
1456
1483
|
# Returns the URL-encoded version of a non-printing character.
|
1457
1484
|
def escapeXML( char )
|
1458
1485
|
if @xmlEscapes.nil?
|
1459
|
-
@xmlEscapes =
|
1486
|
+
@xmlEscapes = {}
|
1460
1487
|
(0..255).each{ |i| @xmlEscapes[ i.chr ] = sprintf( "&#%03d;", i ) }
|
1461
1488
|
end
|
1462
1489
|
return @xmlEscapes[ char ] if @xmlEscapes[ char ]
|
@@ -1556,10 +1583,10 @@ class Client
|
|
1556
1583
|
if @events.include?( event )
|
1557
1584
|
if handler and handler.is_a?( EventHandler )
|
1558
1585
|
if @eventSubscribers.nil?
|
1559
|
-
@eventSubscribers =
|
1586
|
+
@eventSubscribers = {}
|
1560
1587
|
end
|
1561
1588
|
if not @eventSubscribers.include?( event )
|
1562
|
-
@eventSubscribers[ event ] =
|
1589
|
+
@eventSubscribers[ event ] = []
|
1563
1590
|
end
|
1564
1591
|
if not @eventSubscribers[ event ].include?( handler )
|
1565
1592
|
@eventSubscribers[ event ] << handler
|
@@ -1741,7 +1768,7 @@ class Client
|
|
1741
1768
|
# API_DeleteAppZip
|
1742
1769
|
def deleteAppZip( dbid )
|
1743
1770
|
@dbid = dbid
|
1744
|
-
sendRequest( :deleteAppZip
|
1771
|
+
sendRequest( :deleteAppZip )
|
1745
1772
|
return self if @chainAPIcalls
|
1746
1773
|
@responseCode
|
1747
1774
|
end
|
@@ -1864,7 +1891,7 @@ class Client
|
|
1864
1891
|
# API_ChangeRecordOwner
|
1865
1892
|
def _changeRecordOwner( rid, newowner ) changeRecordOwner( @dbid, rid, newowner ) end
|
1866
1893
|
|
1867
|
-
# API_ChangeUserRole
|
1894
|
+
# API_ChangeUserRole.
|
1868
1895
|
def changeUserRole( dbid, userid, roleid, newroleid )
|
1869
1896
|
@dbid, @userid, @roleid, @newroleid = dbid, userid, roleid, newroleid
|
1870
1897
|
|
@@ -2027,8 +2054,12 @@ class Client
|
|
2027
2054
|
|
2028
2055
|
return self if @chainAPIcalls
|
2029
2056
|
|
2030
|
-
if
|
2031
|
-
@records
|
2057
|
+
if block_given?
|
2058
|
+
if @records
|
2059
|
+
@records.each { |element| yield element }
|
2060
|
+
else
|
2061
|
+
yield nil
|
2062
|
+
end
|
2032
2063
|
else
|
2033
2064
|
@records
|
2034
2065
|
end
|
@@ -2071,7 +2102,7 @@ class Client
|
|
2071
2102
|
@numMatches
|
2072
2103
|
end
|
2073
2104
|
|
2074
|
-
#
|
2105
|
+
# API_DoQueryCount, using the active table id.
|
2075
2106
|
def _doQueryCount( query ) doQueryCount( @dbid, query ) end
|
2076
2107
|
|
2077
2108
|
# Download a file's contents from a file attachment field in QuickBase.
|
@@ -2082,7 +2113,7 @@ class Client
|
|
2082
2113
|
|
2083
2114
|
@downLoadFileURL = "http://#{@org}.#{@domain}.com/up/#{dbid}/a/r#{rid}/e#{fid}/v#{vid}"
|
2084
2115
|
|
2085
|
-
if @
|
2116
|
+
if @useSSL
|
2086
2117
|
@downLoadFileURL.gsub!( "http:", "https:" )
|
2087
2118
|
end
|
2088
2119
|
|
@@ -2097,8 +2128,14 @@ class Client
|
|
2097
2128
|
|
2098
2129
|
begin
|
2099
2130
|
|
2100
|
-
|
2101
|
-
|
2131
|
+
if USING_HTTPCLIENT
|
2132
|
+
response = @httpConnection.get( @downLoadFileURL, nil, @requestHeaders )
|
2133
|
+
@responseCode = response.status
|
2134
|
+
@fileContents = response.body.content if response.body
|
2135
|
+
else
|
2136
|
+
@responseCode, @fileContents = @httpConnection.get( @downLoadFileURL, @requestHeaders )
|
2137
|
+
end
|
2138
|
+
|
2102
2139
|
rescue Net::HTTPBadResponse => @lastError
|
2103
2140
|
rescue Net::HTTPHeaderSyntaxError => @lastError
|
2104
2141
|
rescue StandardError => @lastError
|
@@ -2362,6 +2399,7 @@ class Client
|
|
2362
2399
|
|
2363
2400
|
@dbid, @pageid, @pagename = dbid, pageid, pagename
|
2364
2401
|
|
2402
|
+
xmlRequestData = nil
|
2365
2403
|
if @pageid
|
2366
2404
|
xmlRequestData = toXML( :pageid, @pageid )
|
2367
2405
|
elsif @pagename
|
@@ -2683,7 +2721,7 @@ class Client
|
|
2683
2721
|
def importFromCSV( dbid, records_csv, clist, skipfirst = nil, msInUTC = nil )
|
2684
2722
|
|
2685
2723
|
@dbid, @records_csv, @clist, @skipfirst, @msInUTC = dbid, records_csv, clist, skipfirst, msInUTC
|
2686
|
-
@clist
|
2724
|
+
@clist ||= "0"
|
2687
2725
|
|
2688
2726
|
xmlRequestData = toXML( :records_csv, @records_csv )
|
2689
2727
|
xmlRequestData << toXML( :clist, @clist )
|
@@ -2726,8 +2764,12 @@ class Client
|
|
2726
2764
|
|
2727
2765
|
@pages = getResponseValue( :pages )
|
2728
2766
|
return self if @chainAPIcalls
|
2729
|
-
if
|
2730
|
-
@pages
|
2767
|
+
if block_given?
|
2768
|
+
if @pages
|
2769
|
+
@pages.each{ |element| yield element }
|
2770
|
+
else
|
2771
|
+
yield nil
|
2772
|
+
end
|
2731
2773
|
else
|
2732
2774
|
@pages
|
2733
2775
|
end
|
@@ -2841,7 +2883,7 @@ class Client
|
|
2841
2883
|
sendRequest( :setAppData )
|
2842
2884
|
|
2843
2885
|
return self if @chainAPIcalls
|
2844
|
-
|
2886
|
+
@appdata
|
2845
2887
|
end
|
2846
2888
|
|
2847
2889
|
# API_SetAppData, using the active table id.
|
@@ -3196,10 +3238,10 @@ class Client
|
|
3196
3238
|
|
3197
3239
|
getSchema(dbid)
|
3198
3240
|
|
3199
|
-
values =
|
3200
|
-
fieldIDs =
|
3241
|
+
values = {}
|
3242
|
+
fieldIDs = {}
|
3201
3243
|
if fieldNames and fieldNames.is_a?( String )
|
3202
|
-
values[ fieldNames ] =
|
3244
|
+
values[ fieldNames ] = []
|
3203
3245
|
fieldID = lookupFieldIDByName( fieldNames )
|
3204
3246
|
if fieldID
|
3205
3247
|
fieldIDs[ fieldNames ] = fieldID
|
@@ -3209,7 +3251,7 @@ class Client
|
|
3209
3251
|
elsif fieldNames and fieldNames.is_a?( Array )
|
3210
3252
|
fieldNames.each{ |name|
|
3211
3253
|
if name
|
3212
|
-
values[ name ] =
|
3254
|
+
values[ name ] = []
|
3213
3255
|
fieldID = lookupFieldIDByName( name )
|
3214
3256
|
if fieldID
|
3215
3257
|
fieldIDs[ fieldID ] = name
|
@@ -3220,7 +3262,7 @@ class Client
|
|
3220
3262
|
}
|
3221
3263
|
elsif fieldNames.nil?
|
3222
3264
|
getFieldNames(dbid).each{|name|
|
3223
|
-
values[ name ] =
|
3265
|
+
values[ name ] = []
|
3224
3266
|
fieldID = lookupFieldIDByName( name )
|
3225
3267
|
fieldIDs[ fieldID ] = name
|
3226
3268
|
}
|
@@ -3341,7 +3383,7 @@ class Client
|
|
3341
3383
|
numRecords = 0
|
3342
3384
|
numRecords = queryResults[fieldNames[0]].length if queryResults[fieldNames[0]]
|
3343
3385
|
(0..(numRecords-1)).each{|recNum|
|
3344
|
-
recordHash =
|
3386
|
+
recordHash = {}
|
3345
3387
|
fieldNames.each{|fieldName|
|
3346
3388
|
recordHash[fieldName]=queryResults[fieldName][recNum]
|
3347
3389
|
}
|
@@ -3356,8 +3398,8 @@ class Client
|
|
3356
3398
|
# Same as iterateRecords but with fields optionally filtered by Ruby regular expressions.
|
3357
3399
|
# e.g. iterateFilteredRecords( "dhnju5y7", [{"Name" => "[A-E].+}","Address"] ) { |values| puts values["Name"], values["Address"] }
|
3358
3400
|
def iterateFilteredRecords( dbid, fieldNames, query = nil, qid = nil, qname = nil, clist = nil, slist = nil, fmt = "structured", options = nil )
|
3359
|
-
fields =
|
3360
|
-
regexp =
|
3401
|
+
fields = []
|
3402
|
+
regexp = {}
|
3361
3403
|
fieldNames.each{|field|
|
3362
3404
|
if field.is_a?(Hash)
|
3363
3405
|
fields << field.keys[0]
|
@@ -3403,10 +3445,10 @@ class Client
|
|
3403
3445
|
if tablesAndFields and tablesAndFields.is_a?(Array)
|
3404
3446
|
|
3405
3447
|
# get all the records from QuickBase that we might need - fewer API calls is faster than processing extra data
|
3406
|
-
tables =
|
3407
|
-
numRecords =
|
3408
|
-
tableRecords =
|
3409
|
-
joinfield =
|
3448
|
+
tables = []
|
3449
|
+
numRecords = {}
|
3450
|
+
tableRecords = {}
|
3451
|
+
joinfield = {}
|
3410
3452
|
|
3411
3453
|
tablesAndFields.each{|tableAndFields|
|
3412
3454
|
if tableAndFields and tableAndFields.is_a?(Hash)
|
@@ -3445,10 +3487,10 @@ class Client
|
|
3445
3487
|
joinfieldValue = tableRecords[tables[0]][joinfield[tables[0]]][i]
|
3446
3488
|
|
3447
3489
|
# save the other tables' record indices of records containing the joinfield value
|
3448
|
-
tableIndices =
|
3490
|
+
tableIndices = []
|
3449
3491
|
|
3450
3492
|
(1..(numTables-1)).each{|tableNum|
|
3451
|
-
tableIndices[tableNum] =
|
3493
|
+
tableIndices[tableNum] = []
|
3452
3494
|
(0..(numRecords[tables[tableNum]]-1)).each{|j|
|
3453
3495
|
if joinfieldValue == tableRecords[tables[tableNum]][joinfield[tables[tableNum]]][j]
|
3454
3496
|
tableIndices[tableNum] << j
|
@@ -3464,14 +3506,14 @@ class Client
|
|
3464
3506
|
|
3465
3507
|
if buildJoinRecord
|
3466
3508
|
|
3467
|
-
joinRecord =
|
3509
|
+
joinRecord = {}
|
3468
3510
|
|
3469
3511
|
tableRecords[tables[0]].each_key{|field|
|
3470
3512
|
joinRecord[field] = tableRecords[tables[0]][field][i]
|
3471
3513
|
}
|
3472
3514
|
|
3473
3515
|
# nested loops for however many tables we have
|
3474
|
-
currentIndex =
|
3516
|
+
currentIndex = []
|
3475
3517
|
numTables.times{ currentIndex << 0 }
|
3476
3518
|
loop {
|
3477
3519
|
(1..(numTables-1)).each{|tableNum|
|
@@ -3521,7 +3563,7 @@ class Client
|
|
3521
3563
|
|
3522
3564
|
if tables and tables.is_a?(Array)
|
3523
3565
|
if fieldNames and fieldNames.is_a?(Array)
|
3524
|
-
tableRecords =
|
3566
|
+
tableRecords = []
|
3525
3567
|
tables.each{|table|
|
3526
3568
|
if table and table.is_a?(Hash) and table["dbid"]
|
3527
3569
|
tableRecords << getAllValuesForFields( table["dbid"],
|
@@ -3543,13 +3585,13 @@ class Client
|
|
3543
3585
|
else
|
3544
3586
|
raise "'tables' must be an Array of Hashes."
|
3545
3587
|
end
|
3546
|
-
usedRecords =
|
3588
|
+
usedRecords = {}
|
3547
3589
|
tableRecords.each{|queryResults|
|
3548
3590
|
if queryResults
|
3549
3591
|
numRecords = 0
|
3550
3592
|
numRecords = queryResults[fieldNames[0]].length if queryResults[fieldNames[0]]
|
3551
3593
|
(0..(numRecords-1)).each{|recNum|
|
3552
|
-
recordHash =
|
3594
|
+
recordHash = {}
|
3553
3595
|
fieldNames.each{|fieldName|
|
3554
3596
|
recordHash[fieldName]=queryResults[fieldName][recNum]
|
3555
3597
|
}
|
@@ -3587,11 +3629,11 @@ class Client
|
|
3587
3629
|
getSchema(dbid)
|
3588
3630
|
|
3589
3631
|
slist = ""
|
3590
|
-
summaryRecord =
|
3591
|
-
doesTotal =
|
3592
|
-
doesAverage =
|
3593
|
-
summaryField =
|
3594
|
-
fieldType =
|
3632
|
+
summaryRecord = {}
|
3633
|
+
doesTotal = {}
|
3634
|
+
doesAverage = {}
|
3635
|
+
summaryField = {}
|
3636
|
+
fieldType = {}
|
3595
3637
|
|
3596
3638
|
fieldNames.each{ |fieldName|
|
3597
3639
|
fieldType[fieldName] = lookupFieldTypeByName(fieldName)
|
@@ -3642,7 +3684,7 @@ class Client
|
|
3642
3684
|
yield summaryRecord
|
3643
3685
|
|
3644
3686
|
count=0
|
3645
|
-
summaryRecord =
|
3687
|
+
summaryRecord = {}
|
3646
3688
|
fieldNames.each{|fieldName|
|
3647
3689
|
if doesTotal[fieldName]
|
3648
3690
|
summaryRecord["#{fieldName}:Total"] = 0
|
@@ -3813,7 +3855,7 @@ class Client
|
|
3813
3855
|
# Find the lowest value for one or more fields in the records returned by a query.
|
3814
3856
|
# e.g. minimumsHash = min("dfdfafff",["Date Sent","Quantity","Part Name"])
|
3815
3857
|
def min( dbid, fieldNames, query = nil, qid = nil, qname = nil, clist = nil, slist = nil, fmt = "structured", options = nil )
|
3816
|
-
min =
|
3858
|
+
min = {}
|
3817
3859
|
hasValues = false
|
3818
3860
|
iterateRecords(dbid,fieldNames,query,qid,qname,clist,slist,fmt,options){|record|
|
3819
3861
|
fieldNames.each{|field|
|
@@ -3840,7 +3882,7 @@ class Client
|
|
3840
3882
|
# Find the highest value for one or more fields in the records returned by a query.
|
3841
3883
|
# e.g. maximumsHash = max("dfdfafff",["Date Sent","Quantity","Part Name"])
|
3842
3884
|
def max( dbid, fieldNames, query = nil, qid = nil, qname = nil, clist = nil, slist = nil, fmt = "structured", options = nil )
|
3843
|
-
max =
|
3885
|
+
max = {}
|
3844
3886
|
hasValues = false
|
3845
3887
|
iterateRecords(dbid,fieldNames,query,qid,qname,clist,slist,fmt,options){|record|
|
3846
3888
|
fieldNames.each{|field|
|
@@ -3867,7 +3909,7 @@ class Client
|
|
3867
3909
|
# Returns the number non-null values for one or more fields in the records returned by a query.
|
3868
3910
|
# e.g. countsHash = count("dfdfafff",["Date Sent","Quantity","Part Name"])
|
3869
3911
|
def count( dbid, fieldNames, query = nil, qid = nil, qname = nil, clist = nil, slist = nil, fmt = "structured", options = nil )
|
3870
|
-
count =
|
3912
|
+
count = {}
|
3871
3913
|
fieldNames.each{|field| count[field]=0 }
|
3872
3914
|
hasValues = false
|
3873
3915
|
iterateRecords(dbid,fieldNames,query,qid,qname,clist,slist,fmt,options){|record|
|
@@ -3885,7 +3927,7 @@ class Client
|
|
3885
3927
|
# Returns the sum of the values for one or more fields in the records returned by a query.
|
3886
3928
|
# e.g. sumsHash = sum("dfdfafff",["Date Sent","Quantity","Part Name"])
|
3887
3929
|
def sum( dbid, fieldNames, query = nil, qid = nil, qname = nil, clist = nil, slist = nil, fmt = "structured", options = nil )
|
3888
|
-
sum =
|
3930
|
+
sum = {}
|
3889
3931
|
hasValues = false
|
3890
3932
|
iterateRecords(dbid,fieldNames,query,qid,qname,clist,slist,fmt,options){|record|
|
3891
3933
|
fieldNames.each{|field|
|
@@ -3914,9 +3956,9 @@ class Client
|
|
3914
3956
|
# Returns the average of the values for one or more fields in the records returned by a query.
|
3915
3957
|
# e.g. averagesHash = average("dfdfafff",["Date Sent","Quantity","Part Name"])
|
3916
3958
|
def average( dbid, fieldNames, query = nil, qid = nil, qname = nil, clist = nil, slist = nil, fmt = "structured", options = nil )
|
3917
|
-
count =
|
3959
|
+
count = {}
|
3918
3960
|
fieldNames.each{|field| count[field]=0 }
|
3919
|
-
sum =
|
3961
|
+
sum = {}
|
3920
3962
|
iterateRecords(dbid,fieldNames,query,qid,qname,clist,slist,fmt,options){|record|
|
3921
3963
|
fieldNames.each{|field|
|
3922
3964
|
value = record[field]
|
@@ -3937,7 +3979,7 @@ class Client
|
|
3937
3979
|
end
|
3938
3980
|
}
|
3939
3981
|
}
|
3940
|
-
average =
|
3982
|
+
average = {}
|
3941
3983
|
hasValues = false
|
3942
3984
|
fieldNames.each{|field|
|
3943
3985
|
if sum[field] and count[field] > 0
|
@@ -4009,7 +4051,7 @@ class Client
|
|
4009
4051
|
end
|
4010
4052
|
field = lookupField( fid )
|
4011
4053
|
if field
|
4012
|
-
choices =
|
4054
|
+
choices = []
|
4013
4055
|
choicesProc = proc { |element|
|
4014
4056
|
if element.is_a?(REXML::Element)
|
4015
4057
|
if element.name == "choice" and element.has_text?
|
@@ -4028,7 +4070,7 @@ class Client
|
|
4028
4070
|
# Get an array of all the record IDs for a specified table.
|
4029
4071
|
# e.g. IDs = getAllRecordIDs( "dhnju5y7" ){ |id| puts "Record #{id}" }
|
4030
4072
|
def getAllRecordIDs( dbid )
|
4031
|
-
rids =
|
4073
|
+
rids = []
|
4032
4074
|
if dbid
|
4033
4075
|
getSchema( dbid )
|
4034
4076
|
next_record_id = getResponseElement( "table/original/next_record_id" )
|
@@ -4055,7 +4097,7 @@ class Client
|
|
4055
4097
|
# Returns a hash with the structure { "duplicated values" => [ rid, rid, ... ] }
|
4056
4098
|
def findDuplicateRecordIDs( fnames, fids, dbid = @dbid, ignoreCase = true )
|
4057
4099
|
verifyFieldList( fnames, fids, dbid )
|
4058
|
-
duplicates =
|
4100
|
+
duplicates = {}
|
4059
4101
|
if @fids
|
4060
4102
|
cslist = @fids.join( "." )
|
4061
4103
|
ridFields = lookupFieldsByType( "recordid" )
|
@@ -4063,11 +4105,11 @@ class Client
|
|
4063
4105
|
cslist << "."
|
4064
4106
|
recordidFid = ridFields.last.attributes["id"]
|
4065
4107
|
cslist << recordidFid
|
4066
|
-
valuesUsed =
|
4108
|
+
valuesUsed = {}
|
4067
4109
|
doQuery( @dbid, nil, nil, nil, cslist ) { |record|
|
4068
4110
|
next unless record.is_a?( REXML::Element) and record.name == "record"
|
4069
4111
|
recordID = ""
|
4070
|
-
recordValues =
|
4112
|
+
recordValues = []
|
4071
4113
|
record.each { |f|
|
4072
4114
|
if f.is_a?( REXML::Element) and f.name == "f" and f.has_text?
|
4073
4115
|
if recordidFid == f.attributes["id"]
|
@@ -4078,7 +4120,7 @@ class Client
|
|
4078
4120
|
end
|
4079
4121
|
}
|
4080
4122
|
if not valuesUsed[ recordValues ]
|
4081
|
-
valuesUsed[ recordValues ] =
|
4123
|
+
valuesUsed[ recordValues ] = []
|
4082
4124
|
end
|
4083
4125
|
valuesUsed[ recordValues ] << recordID
|
4084
4126
|
}
|
@@ -4108,7 +4150,7 @@ class Client
|
|
4108
4150
|
if options and not options.is_a?( Hash )
|
4109
4151
|
raise "deleteDuplicateRecords: 'options' parameter must be a Hash"
|
4110
4152
|
else
|
4111
|
-
options =
|
4153
|
+
options = {}
|
4112
4154
|
options[ "keeplastrecord" ] = true
|
4113
4155
|
options[ "ignoreCase" ] = true
|
4114
4156
|
end
|
@@ -4132,7 +4174,7 @@ class Client
|
|
4132
4174
|
end
|
4133
4175
|
end
|
4134
4176
|
}
|
4135
|
-
newRecordIDs =
|
4177
|
+
newRecordIDs = []
|
4136
4178
|
if @fvlist and @fvlist.length > 0
|
4137
4179
|
numCopies.times {
|
4138
4180
|
addRecord( dbid, @fvlist )
|
@@ -4186,7 +4228,7 @@ class Client
|
|
4186
4228
|
excel.Quit
|
4187
4229
|
|
4188
4230
|
csvData = ""
|
4189
|
-
targetFieldIDs =
|
4231
|
+
targetFieldIDs = []
|
4190
4232
|
|
4191
4233
|
if fieldNames and fieldNames.length > 0
|
4192
4234
|
fieldNames.each{ |fieldNameRow|
|
@@ -4261,7 +4303,7 @@ class Client
|
|
4261
4303
|
if dbid
|
4262
4304
|
getSchema( dbid )
|
4263
4305
|
|
4264
|
-
targetFieldIDs =
|
4306
|
+
targetFieldIDs = []
|
4265
4307
|
|
4266
4308
|
if targetFieldNames and targetFieldNames.is_a?( Array )
|
4267
4309
|
targetFieldNames.each{ |fieldName|
|
@@ -4271,8 +4313,8 @@ class Client
|
|
4271
4313
|
end
|
4272
4314
|
|
4273
4315
|
useAddRecord = false
|
4274
|
-
invalidLines =
|
4275
|
-
validLines =
|
4316
|
+
invalidLines = []
|
4317
|
+
validLines = []
|
4276
4318
|
|
4277
4319
|
linenum = 1
|
4278
4320
|
IO.foreach( filename ){ |line|
|
@@ -4437,6 +4479,18 @@ class Client
|
|
4437
4479
|
def _updateFile( filename, fileAttachmentFieldName )
|
4438
4480
|
updateFile( @dbid, @rid, filename, fileAttachmentFieldName )
|
4439
4481
|
end
|
4482
|
+
|
4483
|
+
# Remove the file from a File Attachment field in an existing record.
|
4484
|
+
# e.g. removeFileAttachment( "bdxxxibz4", "6", "Document" )
|
4485
|
+
def removeFileAttachment( dbid, rid , fileAttachmentFieldName )
|
4486
|
+
updateFile( dbid, rid, "delete", fileAttachmentFieldName )
|
4487
|
+
end
|
4488
|
+
|
4489
|
+
# Remove the file from a File Attachment field in an existing record in the active table
|
4490
|
+
# e.g. _removeFileAttachment( "6", "Document" )
|
4491
|
+
def _removeFileAttachment( rid , fileAttachmentFieldName )
|
4492
|
+
updateFile( @dbid, rid, "delete", fileAttachmentFieldName )
|
4493
|
+
end
|
4440
4494
|
|
4441
4495
|
# Translate a simple SQL SELECT statement to a QuickBase query and run it.
|
4442
4496
|
#
|
@@ -4457,14 +4511,14 @@ class Client
|
|
4457
4511
|
slist = nil
|
4458
4512
|
state = nil
|
4459
4513
|
dbname = ""
|
4460
|
-
columns =
|
4461
|
-
sortFields =
|
4514
|
+
columns = []
|
4515
|
+
sortFields = []
|
4462
4516
|
limit = nil
|
4463
4517
|
offset = nil
|
4464
4518
|
options = nil
|
4465
4519
|
getRecordCount = false
|
4466
4520
|
|
4467
|
-
queryFields =
|
4521
|
+
queryFields = []
|
4468
4522
|
query = "{'["
|
4469
4523
|
queryState = "getFieldName"
|
4470
4524
|
queryField = ""
|
@@ -4774,7 +4828,7 @@ class Client
|
|
4774
4828
|
|
4775
4829
|
end
|
4776
4830
|
|
4777
|
-
# Iterate @records XML and yield only
|
4831
|
+
# Iterate @records XML and yield only 'record' elements.
|
4778
4832
|
def eachRecord( records = @records )
|
4779
4833
|
if records and block_given?
|
4780
4834
|
records.each { |record|
|
@@ -4787,7 +4841,7 @@ class Client
|
|
4787
4841
|
nil
|
4788
4842
|
end
|
4789
4843
|
|
4790
|
-
# Iterate record XML and yield only
|
4844
|
+
# Iterate record XML and yield only 'f' elements.
|
4791
4845
|
def eachField( record = @record )
|
4792
4846
|
if record and block_given?
|
4793
4847
|
record.each{ |field|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 1
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 1.0.
|
8
|
+
- 3
|
9
|
+
version: 1.0.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Gareth Lewis
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-12-
|
17
|
+
date: 2010-12-07 00:00:00 -08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|