hypersonicplus 0.0.0
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 +7 -0
- data/lib/hdatastructures/hfieldtable.rb +285 -0
- data/lib/hdatastructures/hhash.rb +9 -0
- data/lib/hdatastructures/hlist.rb +100 -0
- data/lib/hdatastructures/hrecord.rb +75 -0
- data/lib/hdatastructures/hspreadfieldtable.rb +129 -0
- data/lib/hdb/hdataloader.rb +75 -0
- data/lib/hdb/hdb.rb +357 -0
- data/lib/hdb/hdb_test.rb +248 -0
- data/lib/hdb/hdbgenerator.rb +211 -0
- data/lib/hdb/hdbi.rb +63 -0
- data/lib/hdb/hdbi_test.rb +133 -0
- data/lib/hdb/hfield.rb +180 -0
- data/lib/hdb/hmysql.rb +99 -0
- data/lib/hdb/hmysql2.rb +96 -0
- data/lib/hdb/hodb.rb +948 -0
- data/lib/hdb/hpgsql.rb +54 -0
- data/lib/hengine/application_controller.rb +204 -0
- data/lib/hengine/hconfiguration.rb +40 -0
- data/lib/hengine/hhotlogger.rb +13 -0
- data/lib/hengine/hlogger.rb +119 -0
- data/lib/hengine/hmalloc.rb +275 -0
- data/lib/hengine/hmoduleloader.rb +15 -0
- data/lib/hengine/hsessiondata.rb +79 -0
- data/lib/hengine/hshareddata.rb +60 -0
- data/lib/hengine/htranslate.rb +40 -0
- data/lib/hengine/hviewloader.rb +99 -0
- data/lib/hinit/hinit.rb +3 -0
- data/lib/hmisc/hcolorize.rb +100 -0
- data/lib/hmisc/hdecoratorfunctions.rb +15 -0
- data/lib/hmisc/hdir.rb +19 -0
- data/lib/hmisc/hhtmlnode.rb +27 -0
- data/lib/hmisc/hinputvalidator.rb +95 -0
- data/lib/hmisc/hio.rb +142 -0
- data/lib/hmisc/hjson.rb +16 -0
- data/lib/hsqlmanager/hpgsqldatabasemanager.rb +76 -0
- data/lib/hsqlmanager/hsqldatabasemanager.rb +349 -0
- data/lib/hsqlmanager/hsqltable.rb +16 -0
- data/lib/husermanager/husermanager.rb +122 -0
- data/lib/hwidgets/haccordionmenu.rb +117 -0
- data/lib/hwidgets/hcheckboxtag.rb +33 -0
- data/lib/hwidgets/hdbactionbuttons.rb +26 -0
- data/lib/hwidgets/hdbcombobox.rb +71 -0
- data/lib/hwidgets/hdbdialogview.rb +190 -0
- data/lib/hwidgets/hdbfilterview.rb +28 -0
- data/lib/hwidgets/hdbtableview.rb +213 -0
- data/lib/hwidgets/hdbview.rb +63 -0
- data/lib/hwidgets/hdivtag.rb +9 -0
- data/lib/hwidgets/hdropdown.rb +44 -0
- data/lib/hwidgets/hformfield.rb +91 -0
- data/lib/hwidgets/hgrouptag.rb +65 -0
- data/lib/hwidgets/hhiddeninputtag.rb +12 -0
- data/lib/hwidgets/hinputtag.rb +55 -0
- data/lib/hwidgets/hlabeltag.rb +30 -0
- data/lib/hwidgets/hmainview.rb +37 -0
- data/lib/hwidgets/hpagination.rb +65 -0
- data/lib/hwidgets/hradiobuttontag.rb +30 -0
- data/lib/hwidgets/hselecttag.rb +32 -0
- data/lib/hwidgets/htableview.rb +262 -0
- data/lib/hwidgets/htabview.rb +84 -0
- data/lib/hwidgets/htextareatag.rb +20 -0
- data/lib/hwidgets/htopnav.rb +85 -0
- data/lib/hwidgets/hwidget.rb +423 -0
- data/lib/hypersonic.rb +9 -0
- metadata +276 -0
data/lib/hdb/hmysql2.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'mysql2'
|
4
|
+
require 'hdb/hdb'
|
5
|
+
|
6
|
+
class Hash
|
7
|
+
|
8
|
+
def join(separator)
|
9
|
+
|
10
|
+
arr = []
|
11
|
+
self.each do |key, value|
|
12
|
+
arr << "#{key} = #{value}"
|
13
|
+
end
|
14
|
+
return arr.join(separator)
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Array
|
20
|
+
|
21
|
+
def hjoin(separator, quoteChar = '"')
|
22
|
+
|
23
|
+
arr = []
|
24
|
+
self.each { |value| arr << "#{value}" }
|
25
|
+
return arr.join(separator)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class HMySql2 < HDB
|
31
|
+
|
32
|
+
def initialize(host, port, dbname, user, password, timezone)
|
33
|
+
|
34
|
+
super(host, port, dbname, user, password, timezone, "hmysql2")
|
35
|
+
@result = nil
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def connect()
|
40
|
+
|
41
|
+
@connection = Mysql2::Client.new(host: @host, username: @user, password: @password, database: @dbname, port: @port.to_i)
|
42
|
+
#hl << "Server version: #{self.execute("SHOW server_version").dataByFieldIndex(0,0).to_s}"
|
43
|
+
self.execute("SET time_zone = '#{@timezone}'") if @timezone
|
44
|
+
return @connection
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def disconnect()
|
49
|
+
|
50
|
+
@connection.close()
|
51
|
+
@connection = nil
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
def _execute(queryStr = self.queryStr)
|
56
|
+
|
57
|
+
@result = @connection.query(queryStr)
|
58
|
+
|
59
|
+
return self unless @result
|
60
|
+
|
61
|
+
@resultTable = HFieldTable.new()
|
62
|
+
self.fieldNameList().each { |fieldName| @resultTable.addFieldName(fieldName) }
|
63
|
+
@resultTable.makeCaption()
|
64
|
+
@result.each_with_index do |row, i|
|
65
|
+
row.each do |fieldName, fieldValue|
|
66
|
+
@resultTable.setDataByFieldName(i, fieldName, fieldValue.to_s)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
return self
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
def fieldNameList()
|
75
|
+
|
76
|
+
fieldList = HList.new()
|
77
|
+
|
78
|
+
@result.fields.each { |fieldName| fieldList << fieldName }
|
79
|
+
|
80
|
+
return fieldList
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
def rowsAffected
|
85
|
+
return @connection.affected_rows()
|
86
|
+
end
|
87
|
+
|
88
|
+
def insert(tableName, values)
|
89
|
+
|
90
|
+
self.execute("INSERT INTO #{tableName} #{self.insertValues(values)}")
|
91
|
+
return @connection.last_id
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
data/lib/hdb/hodb.rb
ADDED
@@ -0,0 +1,948 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'hdb/hfield'
|
4
|
+
|
5
|
+
class Array
|
6
|
+
|
7
|
+
# the follow function didn't use
|
8
|
+
# return a table that contains only fields
|
9
|
+
# table = [{a:1, b:2, c:3}, {a:4, b:5, c:6}]
|
10
|
+
# table.filter([:a, :c]) => [{a:1, c:3}, {a:4, c:6}]
|
11
|
+
def filter(fields)
|
12
|
+
|
13
|
+
result = []
|
14
|
+
self.each do |row|
|
15
|
+
result << row.select { |key, value| fields.include?(key) }
|
16
|
+
end
|
17
|
+
return result
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def sortByList(fieldName, list)
|
23
|
+
|
24
|
+
return self unless list
|
25
|
+
|
26
|
+
hash = {}
|
27
|
+
self.each { |row| hash[row[fieldName]] = row }
|
28
|
+
list.each_with_index { |id, i| self[i] = hash[id] }
|
29
|
+
return self
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
# if list = [3,2,1,0] => it reverses the @table records
|
34
|
+
def sortByPositionList(list)
|
35
|
+
|
36
|
+
return self unless list
|
37
|
+
|
38
|
+
tableCopy = []
|
39
|
+
self.each_with_index { |row, i| tableCopy[i] = row }
|
40
|
+
list.each_with_index { |id, i| self[i] = tableCopy[list[i]] }
|
41
|
+
return self
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def column(fieldName, recordKey = nil)
|
46
|
+
|
47
|
+
result = []
|
48
|
+
self.each do |row|
|
49
|
+
data = row[fieldName.to_s]
|
50
|
+
data = data.value(recordKey) if data.class == HRecord and recordKey
|
51
|
+
result << data
|
52
|
+
end
|
53
|
+
return result
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
class HRecordPtr
|
60
|
+
|
61
|
+
attr_reader :odb, :tableCursor, :type
|
62
|
+
|
63
|
+
def initialize(odb, type = nil)
|
64
|
+
@odb = odb
|
65
|
+
@tableCursor = @odb.tableCursor
|
66
|
+
@type = type
|
67
|
+
end
|
68
|
+
|
69
|
+
def method_missing(sym, *args, &block)
|
70
|
+
|
71
|
+
#puts "=======================================> #{sym.to_s}".red
|
72
|
+
@odb.tableCursor = @tableCursor
|
73
|
+
return @odb.send(sym, *args, &block)
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
class HODB # Object DB
|
81
|
+
|
82
|
+
attr_reader :generate, :modelName, :parentModel, :parent, :connectionName, :hfields, :table, :source, :tmp, :toWrite, :toChange, :tableCursor, :type, :sortField
|
83
|
+
attr_reader :domain # riga da cancellare
|
84
|
+
|
85
|
+
def initialize(modelName = nil, parents = [], connectionName: "default", domain: {}, generate: true)
|
86
|
+
p "modelName: #{modelName}, parents: #{parents}, connectionName = #{connectionName}"
|
87
|
+
@generate = generate # if true build the table into db
|
88
|
+
|
89
|
+
@visited = []
|
90
|
+
|
91
|
+
@toWrite = []
|
92
|
+
@toChange = []
|
93
|
+
@toDelete = []
|
94
|
+
|
95
|
+
@vid = 0 # virtual id
|
96
|
+
|
97
|
+
@tmp = {}
|
98
|
+
@type = nil
|
99
|
+
@source = nil
|
100
|
+
@domain = domain # it's required for example to group the result of oneToMany relation or manyToMany
|
101
|
+
@modelName = modelName
|
102
|
+
@connectionName = connectionName
|
103
|
+
@parents = [] # pairs of type {ptr: 0x..., referenceFieldName: 'modelname_id'}
|
104
|
+
@hfields = {} # hypersonic fields
|
105
|
+
@tableFields = nil # fields of table
|
106
|
+
@modelFields = nil # fields of table + fields of all parents
|
107
|
+
@table = []
|
108
|
+
@tableCursor = nil
|
109
|
+
@allParents = nil
|
110
|
+
|
111
|
+
self.setParents(parents)
|
112
|
+
self.setSystemFields()
|
113
|
+
|
114
|
+
self.init()
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
def recordPtr(type = nil)
|
119
|
+
return HRecordPtr.new(self, type)
|
120
|
+
end
|
121
|
+
|
122
|
+
def newHODB(modelName, type: nil, domain: {})
|
123
|
+
_modelName = modelName.to_s.hcapitalize
|
124
|
+
#puts "newHODB: #{modelName}"
|
125
|
+
p "#{_modelName}.new(connectionName: @connectionName, domain: domain)"
|
126
|
+
odb = (Object.const_defined?(_modelName)) ? eval("#{_modelName}.new(connectionName: @connectionName, domain: domain)") : HODB.new(modelName, connectionName: @connectionName, domain: domain)
|
127
|
+
odb.source = self
|
128
|
+
odb.type = type if type
|
129
|
+
return odb
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.newOdb(modelName, connectionName = "default", domain: {})
|
134
|
+
className = modelName.hcapitalize
|
135
|
+
return eval("#{className}.new(connectionName: connectionName, domain: domain)")
|
136
|
+
end
|
137
|
+
|
138
|
+
def ptrOfRecord(fieldName, fieldValue)
|
139
|
+
|
140
|
+
return fieldValue.tableCursor if fieldValue.class == HRecordPtr # Se si tratta gia' di un ptr a un record lo restituisce
|
141
|
+
@table.each do |record|
|
142
|
+
return record if record[fieldName.to_s] == fieldValue
|
143
|
+
end
|
144
|
+
return nil
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
def allParents()
|
149
|
+
return @allParents if @allParents
|
150
|
+
@allParents = [self]
|
151
|
+
@parents.each { |parent| @allParents += parent[:ptr].allParents() }
|
152
|
+
return @allParents
|
153
|
+
end
|
154
|
+
|
155
|
+
def tableFields # return only the fields of table
|
156
|
+
self.findBy(:false, []) unless @tableFields # poputate @tableFields
|
157
|
+
return @tableFields
|
158
|
+
end
|
159
|
+
|
160
|
+
def modelFields # return all fields
|
161
|
+
return @modelFields if @modelFields
|
162
|
+
@modelFields = Marshal.load(Marshal.dump(self.tableFields()))
|
163
|
+
@parents.each { |parent| @modelFields.merge!(parent[:ptr].modelFields()) }
|
164
|
+
return @modelFields
|
165
|
+
end
|
166
|
+
|
167
|
+
def systemFields(inheritance = false)
|
168
|
+
return self.hfields(inheritance).select { |fieldName, field| field[:system] }
|
169
|
+
end
|
170
|
+
|
171
|
+
def hfields(inheritance = true)
|
172
|
+
return @hfields unless inheritance
|
173
|
+
return @allHfields if @allHfields
|
174
|
+
@allHfields = {}
|
175
|
+
@hfields.each { |fieldName, fieldValue| @allHfields[fieldName] = fieldValue }
|
176
|
+
@parents.each { |parent| @allHfields.merge!( parent[:ptr].hfields(inheritance) ) }
|
177
|
+
return @allHfields
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
# false: return only fields of table
|
182
|
+
# true: return the fields of table + parents fields
|
183
|
+
# :false: return only hfields of table
|
184
|
+
# :true: return only hfields of table + parents hfields
|
185
|
+
def fields(inheritance = false)
|
186
|
+
|
187
|
+
return inheritance if inheritance.class == Array
|
188
|
+
|
189
|
+
case inheritance
|
190
|
+
when true
|
191
|
+
return self.modelFields()
|
192
|
+
when false
|
193
|
+
return self.tableFields()
|
194
|
+
when :true
|
195
|
+
return self.hfields(:true)
|
196
|
+
when :false
|
197
|
+
return self.hfields(:false)
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
def nodeOfField(fieldName)
|
203
|
+
result = self.fields().include?(fieldName) ? [self] : []
|
204
|
+
@parents.each { |parent| result += parent[:ptr].nodeOfField(fieldName) }
|
205
|
+
return @nodes = result
|
206
|
+
end
|
207
|
+
|
208
|
+
def valueOfField(fieldName)
|
209
|
+
nodes = self.nodeOfField(fieldName)
|
210
|
+
return (nodes.any?) ? nodes[0].tableCursor[fieldName] : nil
|
211
|
+
end
|
212
|
+
|
213
|
+
def setValueOfField(fieldName, fieldValue)
|
214
|
+
nodes = self.nodeOfField(fieldName)
|
215
|
+
nodes.each { |node| node.tableCursor[fieldName] = fieldValue }
|
216
|
+
end
|
217
|
+
|
218
|
+
def setParents(parents = [])
|
219
|
+
parents.each do |modelName|
|
220
|
+
referenceFieldName = "#{modelName}_id"
|
221
|
+
parent = {modelName: modelName, referenceFieldName: referenceFieldName}
|
222
|
+
self.addField(referenceFieldName, HField.oneToOne(modelName))
|
223
|
+
#parent[:ptr] = self.newHODB(modelName, domain: @domain)
|
224
|
+
parent[:ptr] = self.newHODB(modelName)
|
225
|
+
@parents << parent
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
def setSystemFields()
|
231
|
+
self.id = HField.primaryKey
|
232
|
+
self.created_date = HField.dateTime(default: '#CURRENT_TIMESTAMP', system: true)
|
233
|
+
self.updated_date = HField.dateTime(default: '#CURRENT_TIMESTAMP', system: true)
|
234
|
+
self.ordering = HField.integer(system: true)
|
235
|
+
end
|
236
|
+
|
237
|
+
def addField(fieldName, args)
|
238
|
+
|
239
|
+
field = HField.autoComplete(@modelName, fieldName, args) # For the magic field
|
240
|
+
@hfields[fieldName] = field
|
241
|
+
hl << "addField: #{fieldName} #{field}"
|
242
|
+
|
243
|
+
end
|
244
|
+
|
245
|
+
def oneToOne(modelName, referenceFieldName)
|
246
|
+
|
247
|
+
return self.manyToOne(modelName, referenceFieldName, 'oneToOne')
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
def manyToOne(modelName, referenceFieldName, type = 'manyToOne')
|
252
|
+
|
253
|
+
return @tableCursor[modelName] if @tableCursor[modelName]
|
254
|
+
id = self.valueOfField(referenceFieldName)
|
255
|
+
@tableCursor[modelName] = odb = self.newHODB(modelName, type: type)
|
256
|
+
@visited.addIfNotPresent(odb)
|
257
|
+
puts "modelName: #{referenceFieldName}".red
|
258
|
+
@tableCursor.hprint
|
259
|
+
unless id
|
260
|
+
self.setValueOfField(referenceFieldName, odb.recordPtr(type))
|
261
|
+
return odb
|
262
|
+
end
|
263
|
+
@toChange << @tableCursor unless @toChange.include?(@tableCursor)
|
264
|
+
return odb.findBy_id(id)
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
def oneToMany(fieldName, modelName, referenceFieldName)
|
269
|
+
|
270
|
+
return @tableCursor[fieldName] if @tableCursor[fieldName]
|
271
|
+
if(self.id[0] != "#")
|
272
|
+
domain = {"#{referenceFieldName}": self.id}
|
273
|
+
odb = self.newHODB(modelName, type: 'oneToMany', domain: domain).findBy()
|
274
|
+
return @visited.addIfNotPresent(odb)
|
275
|
+
end
|
276
|
+
domain = {"#{referenceFieldName}": nil}
|
277
|
+
odb = self.newHODB(modelName, type: 'oneToMany', domain: domain)
|
278
|
+
@tableCursor[fieldName] = odb
|
279
|
+
@visited.addIfNotPresent(odb)
|
280
|
+
return odb
|
281
|
+
end
|
282
|
+
|
283
|
+
def manyToMany(modelName, joinTable, referenceFieldName, referenceFieldName2)
|
284
|
+
|
285
|
+
odb = self.oneToMany(joinTable, joinTable, referenceFieldName)
|
286
|
+
odb.type = 'manyToMany'
|
287
|
+
odb.tmp[:referenceFieldName] = referenceFieldName2
|
288
|
+
odb.tmp[:rightModelName] = modelName
|
289
|
+
return odb
|
290
|
+
|
291
|
+
end
|
292
|
+
|
293
|
+
# a_table <--> manyToMany <--> b_table
|
294
|
+
# To access to b_table from a_table -> a_table.a_table_b_table_join.rightModel
|
295
|
+
# Moreover on right model is unsense call the create function
|
296
|
+
def rightModel
|
297
|
+
|
298
|
+
rightModelName = @tmp[:rightModelName]
|
299
|
+
return @tableCursor[rightModelName] if @tableCursor[rightModelName]
|
300
|
+
|
301
|
+
ids = @table.column(@tmp[:referenceFieldName])
|
302
|
+
where = "id IN (#{ids.join(',')})"
|
303
|
+
odb = self.newHODB(rightModelName, type: 'rightTable').findBy(where) if (@type == 'manyToMany')
|
304
|
+
@visited.addIfNotPresent(odb)
|
305
|
+
return @tableCursor[rightModelName] = odb
|
306
|
+
|
307
|
+
end
|
308
|
+
|
309
|
+
def virtualField(obj, functionName, &block)
|
310
|
+
|
311
|
+
return block.call(self) if block
|
312
|
+
#hl << "obj.#{functionName.to_s}(self)"
|
313
|
+
return eval("obj.#{functionName.to_s}(self)") if obj and functionName
|
314
|
+
|
315
|
+
end
|
316
|
+
|
317
|
+
def inspection(str)
|
318
|
+
puts "=============> #{str}"
|
319
|
+
return false
|
320
|
+
end
|
321
|
+
|
322
|
+
def fieldProperty(fieldName, property)
|
323
|
+
|
324
|
+
return nil unless fieldName
|
325
|
+
hfield = self.hfields()[fieldName.to_s] || self.hfields()[fieldName.to_sym]
|
326
|
+
return hfield[property.to_s] || hfield[property.to_sym] if hfield
|
327
|
+
return nil
|
328
|
+
|
329
|
+
end
|
330
|
+
|
331
|
+
|
332
|
+
# [[:a, :b, :c], [1, 2, 3]].transpose
|
333
|
+
# => [[:a, 1], [:b, 2], [:c, 3]]
|
334
|
+
def method_missing(sym, *args, &block)
|
335
|
+
if sym =~ /^(\w+)=$/
|
336
|
+
if args[0].class == HField
|
337
|
+
self.addField($1.to_s, args[0])
|
338
|
+
elsif self.nodeOfField($1.to_s).any?
|
339
|
+
@nodes.each { |node| node.tableCursor[$1.to_s] = args[0] if node.tableCursor }
|
340
|
+
@toChange << @tableCursor if (!@toChange.include?(@tableCursor) and @tableCursor)
|
341
|
+
elsif instance_variable_defined?("@#{$1.to_s}") # is required to use attr_reader to setting
|
342
|
+
instance_variable_set("@#{$1}", args[0])
|
343
|
+
else
|
344
|
+
hl.<<("hodb::method_missing: #{$1.to_s} not found", "ERROR")
|
345
|
+
end
|
346
|
+
return
|
347
|
+
elsif sym.to_s =~ /^findBy_(.+)$/
|
348
|
+
attrs = $1.split('_and_')
|
349
|
+
attrs_with_args = [attrs, args].transpose
|
350
|
+
where = Hash[attrs_with_args]
|
351
|
+
return self.findBy(where)
|
352
|
+
elsif @hfields[sym.to_s] and @hfields[sym.to_s][:modelNameReference]
|
353
|
+
modelName = @hfields[sym.to_s][:modelNameReference]
|
354
|
+
type = self.fieldProperty(sym, :type)
|
355
|
+
return self.oneToOne(modelName, sym.to_s) if (type == 'oneToOne')
|
356
|
+
return self.manyToOne(modelName, sym.to_s) if (type == 'manyToOne')
|
357
|
+
referenceFieldName = @hfields[sym.to_s][:referenceFieldName]
|
358
|
+
return self.oneToMany(sym.to_s, modelName, referenceFieldName) if (type == 'oneToMany')
|
359
|
+
joinTable = @hfields[sym.to_s][:joinTable]
|
360
|
+
referenceFieldName2 = @hfields[sym.to_s][:referenceFieldName2]
|
361
|
+
return self.manyToMany(modelName, joinTable, referenceFieldName, referenceFieldName2) if (type == 'manyToMany')
|
362
|
+
elsif @hfields[sym.to_s] and @hfields[sym.to_s][:type] == 'virtual'
|
363
|
+
return self.virtualField(@hfields[sym.to_s][:object] || self, @hfields[sym.to_s][:functionName], &@hfields[sym.to_s][:block])
|
364
|
+
elsif sym =~ /^(\w+)_id$/
|
365
|
+
return self.manyToOne($1.to_s, sym.to_s)
|
366
|
+
elsif sym =~ /^(\w+)_table$/
|
367
|
+
return self.oneToMany(sym.to_s, $1.to_s, "#{@modelName}_id")
|
368
|
+
elsif sym =~ /^(\w+)_join$/
|
369
|
+
return self.manyToMany($1.to_s, "#{@modelName}_#{$1.to_s}_join", "#{@modelName}_id", "#{$1.to_s}_id")
|
370
|
+
elsif @tableCursor and @tableCursor.include?(sym.to_s)
|
371
|
+
return @tableCursor[sym.to_s]
|
372
|
+
#elsif sym =~ /^(\w+)_virtual$/
|
373
|
+
# return self.virtualField($1.to_s, self, &block)
|
374
|
+
else
|
375
|
+
@parents.each do |parent|
|
376
|
+
result = parent[:ptr].method_missing(sym, *args, &block)
|
377
|
+
return result if result
|
378
|
+
end
|
379
|
+
end
|
380
|
+
hl.<<("hodb::method_missing: #{sym.to_s} not found", "ERROR")
|
381
|
+
return nil
|
382
|
+
end
|
383
|
+
|
384
|
+
|
385
|
+
def reset
|
386
|
+
@parents.each { |parent| parent[:ptr].reset }
|
387
|
+
@tableCursor = nil
|
388
|
+
end
|
389
|
+
|
390
|
+
def first
|
391
|
+
self.reset
|
392
|
+
return self.next
|
393
|
+
end
|
394
|
+
|
395
|
+
def last
|
396
|
+
@tableCursor = @table.count > 0 ? @table[@table.count - 1] : nil
|
397
|
+
return self
|
398
|
+
end
|
399
|
+
|
400
|
+
def setTableCursor(tableCursor = @tableCursor)
|
401
|
+
@tableCursor = tableCursor
|
402
|
+
@id = @tableCursor["id"]
|
403
|
+
@parents.each do |parent|
|
404
|
+
parentTableCursor = @tableCursor[parent[:referenceFieldName]]
|
405
|
+
parentTableCursor = parent[:ptr].ptrOfRecord("id", parentTableCursor)
|
406
|
+
parent[:ptr].setTableCursor(parentTableCursor)
|
407
|
+
end
|
408
|
+
return self
|
409
|
+
end
|
410
|
+
|
411
|
+
def next()
|
412
|
+
|
413
|
+
index = @tableCursor ? @table.index(@tableCursor) + 1 : 0
|
414
|
+
|
415
|
+
if (index < @table.count)
|
416
|
+
@tableCursor = @table[index]
|
417
|
+
self.setTableCursor
|
418
|
+
return self
|
419
|
+
end
|
420
|
+
return nil
|
421
|
+
|
422
|
+
end
|
423
|
+
|
424
|
+
def each
|
425
|
+
|
426
|
+
self.execute unless @executed
|
427
|
+
|
428
|
+
self.reset()
|
429
|
+
while(self.next) do
|
430
|
+
yield(self)
|
431
|
+
end
|
432
|
+
|
433
|
+
@tableCursor = nil
|
434
|
+
self.init()
|
435
|
+
|
436
|
+
end
|
437
|
+
|
438
|
+
def each_with_index
|
439
|
+
i = -1
|
440
|
+
self.each do |record|
|
441
|
+
yield(self, i += 1)
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
|
446
|
+
def eachField(inheritance = true)
|
447
|
+
self.fields(inheritance).each do |fieldName, fieldValue|
|
448
|
+
fieldValue = self.data(fieldName)
|
449
|
+
fieldValue = eval("self.#{fieldName}") unless fieldValue # si tratta di campi virtual runtime
|
450
|
+
yield(fieldName, fieldValue)
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
|
455
|
+
def toFieldTable(inheritance = true)
|
456
|
+
|
457
|
+
fieldTable = HSpreadFieldTable.new
|
458
|
+
fieldTable.tableName = @modelName
|
459
|
+
|
460
|
+
self.fields(inheritance).each do |fieldName, fieldValue|
|
461
|
+
fieldTable.addFieldName(fieldName)
|
462
|
+
fieldTable.setFieldCaption(fieldName, fieldName.to_s.hcapitalize)
|
463
|
+
fieldType = self.fieldProperty(fieldName.to_s, :type)
|
464
|
+
fieldTable.setFieldType(fieldName, fieldType) if fieldType
|
465
|
+
end
|
466
|
+
|
467
|
+
self.each_with_index do |row, i|
|
468
|
+
row.eachField(inheritance) do |fieldName, fieldValue|
|
469
|
+
fieldTable.setIntoRecordByFieldName(i, fieldName, fieldValue)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
return fieldTable
|
474
|
+
|
475
|
+
end
|
476
|
+
|
477
|
+
def allRelations
|
478
|
+
result = []
|
479
|
+
result << hdb(@connectionName).normalizeWhereFormat(@domain) if @domain.class == String or @domain.any?
|
480
|
+
@parents.each do |parent|
|
481
|
+
result += ["#{@modelName}.#{parent[:referenceFieldName]} = #{parent[:ptr].modelName}.id"] + parent[:ptr].allRelations
|
482
|
+
end
|
483
|
+
return result
|
484
|
+
end
|
485
|
+
|
486
|
+
def allModels
|
487
|
+
result = []
|
488
|
+
self.allParents().each { |parent| result << parent.modelName unless result.include?(parent.modelName) }
|
489
|
+
return result
|
490
|
+
end
|
491
|
+
|
492
|
+
def modelNameOfField(fieldName)
|
493
|
+
|
494
|
+
fieldName = fieldName.to_s
|
495
|
+
node = self.nodeOfField(fieldName)
|
496
|
+
return (node.any?) ? node[0].modelName : nil
|
497
|
+
|
498
|
+
end
|
499
|
+
|
500
|
+
def modelNameAndFieldName(fieldName)
|
501
|
+
|
502
|
+
modelName = self.modelNameOfField(fieldName)
|
503
|
+
return (modelName) ? "#{modelName}.#{fieldName}" : fieldName
|
504
|
+
|
505
|
+
end
|
506
|
+
|
507
|
+
def data(fieldName)
|
508
|
+
|
509
|
+
fieldName = fieldName.to_s
|
510
|
+
node = self.nodeOfField(fieldName)
|
511
|
+
return (node.any?) ? node[0].tableCursor[fieldName] : nil
|
512
|
+
|
513
|
+
end
|
514
|
+
|
515
|
+
|
516
|
+
def normalizeWhereFormat(where)
|
517
|
+
|
518
|
+
if where.class == Hash # findBy {'c_tables.id': 1}
|
519
|
+
newWhere = {}
|
520
|
+
where.each { |fieldName, fieldValue| newWhere[self.modelNameAndFieldName(fieldName)] = fieldValue }
|
521
|
+
where = newWhere
|
522
|
+
end
|
523
|
+
|
524
|
+
return hdb(@connectionName).normalizeWhereFormat(where)
|
525
|
+
|
526
|
+
end
|
527
|
+
|
528
|
+
def init()
|
529
|
+
@where = "true"
|
530
|
+
@orderBy = "id"
|
531
|
+
@pageSize = "all"
|
532
|
+
@page = 0
|
533
|
+
end
|
534
|
+
|
535
|
+
def where(where)
|
536
|
+
@executed = false
|
537
|
+
@where = where
|
538
|
+
return self
|
539
|
+
end
|
540
|
+
def orderBy(orderBy)
|
541
|
+
@executed = false
|
542
|
+
orderBy = orderBy.hjoin(', ') if(orderBy.class == Array)
|
543
|
+
@orderBy = orderBy
|
544
|
+
return self
|
545
|
+
end
|
546
|
+
def direction(direction)
|
547
|
+
@executed = false
|
548
|
+
@direction = direction
|
549
|
+
return self
|
550
|
+
end
|
551
|
+
def pageSize(pageSize)
|
552
|
+
@executed = false
|
553
|
+
@pageSize = pageSize
|
554
|
+
return self
|
555
|
+
end
|
556
|
+
def page(page)
|
557
|
+
@executed = false
|
558
|
+
@page = page
|
559
|
+
return self
|
560
|
+
end
|
561
|
+
|
562
|
+
def sortOffLine(fieldName = "id", sortDirection = 'desc', sortMap = [])
|
563
|
+
|
564
|
+
# table = [{id:7, name:'valerio', surname:'bianchi'},
|
565
|
+
# {id:8, name:'mario', surname:'rossi'},
|
566
|
+
# {id:6, name:'laura', surname:'neri'}]
|
567
|
+
#
|
568
|
+
# table.sort_by { |row| row["name"] } =>
|
569
|
+
# {id:6, name:'laura', surname:'neri'},
|
570
|
+
# {id:8, name:'mario', surname:'rossi'},
|
571
|
+
# {id:7, name:'valerio', surname:'bianchi'}
|
572
|
+
# columnSorted = tableSorted.column("id") => [1, 3, 2]
|
573
|
+
# idColumn = @table.column("id") => [2, 3, 1]
|
574
|
+
# sortMap => [2, 1, 0]
|
575
|
+
# A this time to print the records it is enough to scan sortMap
|
576
|
+
# The first element to print is @table[2] => @table[1] => @table[0]
|
577
|
+
|
578
|
+
puts "========================================================".red
|
579
|
+
puts "======= sortOffLine =======".red
|
580
|
+
puts "========================================================".red
|
581
|
+
puts "currentModelName: #{@modelName}".red
|
582
|
+
if sortMap.empty?
|
583
|
+
node = self.nodeOfField(fieldName)[0]
|
584
|
+
return unless node
|
585
|
+
puts "modelName of #{fieldName}: #{node.modelName}".red
|
586
|
+
|
587
|
+
p node.hfields()
|
588
|
+
fieldType = node.hfields()[fieldName] ? node.hfields()[fieldName][:type] : nil
|
589
|
+
puts "type of #{fieldName}: #{fieldType}"
|
590
|
+
tableSorted = nil
|
591
|
+
if fieldType == "integer"
|
592
|
+
tableSorted = node.table.sort_by { |row| row[fieldName].to_i }
|
593
|
+
elsif fieldType == "float"
|
594
|
+
tableSorted = node.table.sort_by { |row| row[fieldName].to_f }
|
595
|
+
elsif fieldType == "time"
|
596
|
+
tableSorted = node.table.sort_by { |row| row[fieldName].to_time }
|
597
|
+
elsif fieldType == "date_time"
|
598
|
+
tableSorted = node.table.sort_by { |row| row[fieldName].to_datetime }
|
599
|
+
else
|
600
|
+
tableSorted = node.table.sort_by { |row| row[fieldName] }
|
601
|
+
end
|
602
|
+
|
603
|
+
tableSorted.reverse! if sortDirection == 'asc'
|
604
|
+
|
605
|
+
columnSorted = tableSorted.column("id")
|
606
|
+
idColumn = node.table.column("id")
|
607
|
+
columnSorted.each_with_index { |value, i| sortMap[i] = idColumn.index(value) }
|
608
|
+
p sortMap
|
609
|
+
end
|
610
|
+
|
611
|
+
@table.sortByPositionList(sortMap)
|
612
|
+
|
613
|
+
@parents.each do |parent|
|
614
|
+
parent[:ptr].sortOffLine(nil, sortDirection, sortMap)
|
615
|
+
end
|
616
|
+
|
617
|
+
end
|
618
|
+
|
619
|
+
# findByOffLine({id: 1, name: 'margherita'})
|
620
|
+
def findByOffLine(where)
|
621
|
+
|
622
|
+
tableCursor = @tableCursor
|
623
|
+
self.each do |record|
|
624
|
+
return self if where.each do |fieldName, fieldValue|
|
625
|
+
#puts "#{record.valueOfField(fieldName.to_s)} - #{fieldValue}"
|
626
|
+
break if record.valueOfField(fieldName.to_s) != fieldValue
|
627
|
+
end
|
628
|
+
end
|
629
|
+
self.setTableCursor(tableCursor) # if not found restore the tableCursor value
|
630
|
+
return self
|
631
|
+
|
632
|
+
end
|
633
|
+
|
634
|
+
# example: findBy({id: 1})
|
635
|
+
# findBy({'c_tables.id': 1}) - I can specify the field of the another table
|
636
|
+
# findBy({id: 1, name: 'ciao'}) -> c_tables.id = '1' AND c_tables.name = 'ciao'
|
637
|
+
# The follow statement isn't safe. You can use it, only if the values don't come from forms but they are statics
|
638
|
+
# findBy(["c_tables.id > 0", "c_tables.name = 'ciao'"])
|
639
|
+
# The follow statement is safe as the ? syntax and you can use the values from forms
|
640
|
+
# findBy(["c_tables.id > 0", "c_tables.name = #{q(form_field)}"])
|
641
|
+
|
642
|
+
def findBy(where = 'true', ids = nil, orderBy: nil, direction: nil, pageSize: "all", page: 0)
|
643
|
+
|
644
|
+
return self unless where
|
645
|
+
where = self.normalizeWhereFormat(where)
|
646
|
+
|
647
|
+
model = (ids == nil) ? self.allModels.join(', ') : @modelName
|
648
|
+
where = (self.allRelations << where).join(' and ') if !ids and where
|
649
|
+
|
650
|
+
hdb = hdb(@connectionName).
|
651
|
+
select("#{modelName}.*").
|
652
|
+
from(model).
|
653
|
+
where(where).
|
654
|
+
orderBy(orderBy).
|
655
|
+
direction(direction).
|
656
|
+
execute(pageSize: pageSize, page: page)
|
657
|
+
|
658
|
+
@tableFields = Hash[hdb.fieldNameList()]
|
659
|
+
@table = hdb.table.sortByList("id", ids)
|
660
|
+
@tableCursor = nil
|
661
|
+
|
662
|
+
return self if @table.count == 0
|
663
|
+
|
664
|
+
@parents.each do |parent|
|
665
|
+
ids = @table.column(parent[:referenceFieldName])
|
666
|
+
parent[:ptr].findBy("id IN (#{ids.join(',')})", ids)
|
667
|
+
end
|
668
|
+
return self.next().recordPtr('manyToOne')
|
669
|
+
|
670
|
+
end
|
671
|
+
|
672
|
+
def execute
|
673
|
+
# @executed serve per evitare di chiamare execute nelle istruzioni del tipo:
|
674
|
+
# odb.where(filter).orderBy(sortField).direction(sortDirection).pageSize(pageSize).page(page)
|
675
|
+
@executed = true
|
676
|
+
return self.findBy(@where, nil, orderBy: @orderBy, direction: @direction, pageSize: @pageSize, page: @page)
|
677
|
+
end
|
678
|
+
|
679
|
+
def all
|
680
|
+
return self.findBy()
|
681
|
+
end
|
682
|
+
|
683
|
+
def defaultValue(fieldName)
|
684
|
+
field = @hfields[fieldName.to_s]
|
685
|
+
return nil unless field
|
686
|
+
return (field[:default]) ? field[:default] : field.defaultValue()
|
687
|
+
end
|
688
|
+
|
689
|
+
def defaultRecord(record)
|
690
|
+
defaultRecord = Marshal.load(Marshal.dump(self.fields()))
|
691
|
+
defaultRecord.each { |fieldName, fieldValue| defaultRecord[fieldName.to_s] = self.defaultValue(fieldName) }
|
692
|
+
defaultRecord["id"] = "##{@vid+=1}"
|
693
|
+
record.each {|fieldName,fieldValue| defaultRecord[fieldName.to_s] = fieldValue if defaultRecord.include?(fieldName.to_s)}
|
694
|
+
@domain.each {|fieldName,fieldValue| defaultRecord[fieldName.to_s] = fieldValue if defaultRecord.include?(fieldName.to_s)} if @domain.class == Hash
|
695
|
+
puts "#{defaultRecord}".red
|
696
|
+
return defaultRecord
|
697
|
+
end
|
698
|
+
|
699
|
+
def create(record = {})
|
700
|
+
defaultRecord = self.defaultRecord(record)
|
701
|
+
@parents.each { |parent| defaultRecord[parent[:referenceFieldName]] = parent[:ptr].create(record) }
|
702
|
+
@toWrite << defaultRecord
|
703
|
+
@table << defaultRecord
|
704
|
+
self.last
|
705
|
+
return self.recordPtr("parent")
|
706
|
+
end
|
707
|
+
|
708
|
+
def setRecord(record, tableCursor = @tableCursor)
|
709
|
+
@toChange << tableCursor unless @toChange.include?(tableCursor)
|
710
|
+
record.each do |fieldName, fieldValue|
|
711
|
+
unless self.fields(true).include?(fieldName.to_s)
|
712
|
+
hl.<<("hodb::setRecord: #{fieldName.to_s} not found", "ERROR")
|
713
|
+
next
|
714
|
+
end
|
715
|
+
setValueOfField(fieldName.to_s, fieldValue)
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
719
|
+
|
720
|
+
def write(values = {})
|
721
|
+
hl << "********************************* write(#{@type}) *********************************"
|
722
|
+
return self unless @toWrite.include?(@tableCursor)
|
723
|
+
return self unless values
|
724
|
+
puts "#{values}".red
|
725
|
+
@tableCursor.merge!(values)
|
726
|
+
@tableCursor["id"] = "#default" if @tableCursor["id"][0] == "#"
|
727
|
+
@tableCursor.each do |fieldName, fieldValue|
|
728
|
+
if fieldValue.class == HRecordPtr
|
729
|
+
if fieldValue.type == "parent"
|
730
|
+
@tableCursor[fieldName] = fieldValue.write(values).id
|
731
|
+
elsif fieldValue.type == "manyToOne" or fieldValue.type == "oneToOne"
|
732
|
+
@tableCursor[fieldName] = fieldValue.write().id
|
733
|
+
elsif fieldValue.type == nil # questo caso non deve verificarsi
|
734
|
+
hl.<<("hodb::write: ", "ERROR")
|
735
|
+
fieldValue.tableCursor.hprint
|
736
|
+
end
|
737
|
+
end
|
738
|
+
end
|
739
|
+
# intersect rimuove ad es. i campy oneToMany e i campi inseriti dalla merge! sopra se non fanno parte del @tableCursor
|
740
|
+
@tableCursor["id"] = hdb(@connectionName).insert(@modelName, @tableCursor.intersect(self.fields))
|
741
|
+
@tableCursor.each do |fieldName, fieldValue|
|
742
|
+
if fieldValue.class <= HODB and (fieldValue.type == 'oneToMany' or fieldValue.type == 'manyToMany' or fieldValue.type == 'rightTable')
|
743
|
+
referenceFieldName = fieldValue.domain.keys[0].to_s
|
744
|
+
fieldValue.writeAll({"#{referenceFieldName}" => @tableCursor["id"]})
|
745
|
+
end
|
746
|
+
end
|
747
|
+
@toWrite.delete(@tableCursor)
|
748
|
+
return self
|
749
|
+
end
|
750
|
+
|
751
|
+
def writeAll(values = {})
|
752
|
+
|
753
|
+
puts "********************* writeAll ********************".pink
|
754
|
+
|
755
|
+
@toDelete.each { |record| self.delete({id: record["id"]}) }
|
756
|
+
@toDelete.clear
|
757
|
+
|
758
|
+
toWrite = @toWrite.dup
|
759
|
+
toWrite.each do |record|
|
760
|
+
@tableCursor = record
|
761
|
+
self.write(values)
|
762
|
+
end
|
763
|
+
return self
|
764
|
+
end
|
765
|
+
|
766
|
+
def save(values = {})
|
767
|
+
hl << "********************************* save(#{@type} - #{@modelName}) *********************************"
|
768
|
+
#return self unless @toChange.include?(@tableCursor)
|
769
|
+
puts "#{values}".red
|
770
|
+
@tableCursor.hprint
|
771
|
+
@tableCursor.merge!(values)
|
772
|
+
@tableCursor["id"] = "#default" if @tableCursor["id"][0] == "#"
|
773
|
+
self.setTableCursor(@tableCursor)
|
774
|
+
@tableCursor.each do |fieldName, fieldValue|
|
775
|
+
if fieldValue.class <= HODB and (fieldValue.type == 'manyToOne' or fieldValue.type == 'oneToOne')
|
776
|
+
puts "call: #{fieldName} - #{fieldValue.domain}".red
|
777
|
+
@tableCursor[fieldName] = fieldValue.saveAll().id
|
778
|
+
end
|
779
|
+
end
|
780
|
+
@parents.each { |parent| parent[:ptr].save(values) }
|
781
|
+
# intersect rimuove ad es. i campy oneToMany e i campi inseriti dalla merge! sopra se non fanno parte del @tableCursor
|
782
|
+
hdb(@connectionName).update(@modelName, @tableCursor.intersect(self.fields), {id: @tableCursor["id"]})
|
783
|
+
@tableCursor.each do |fieldName, fieldValue|
|
784
|
+
if fieldValue.class <= HODB and (fieldValue.type == 'oneToMany' or fieldValue.type == 'manyToMany' or fieldValue.type == 'rightTable')
|
785
|
+
p "saveAll".red
|
786
|
+
fieldValue.saveAll()
|
787
|
+
end
|
788
|
+
end
|
789
|
+
@toChange.delete(@tableCursor)
|
790
|
+
return self
|
791
|
+
end
|
792
|
+
|
793
|
+
def saveAll(values = {})
|
794
|
+
toChange = @toChange.dup
|
795
|
+
toChange.each do |record|
|
796
|
+
@tableCursor = record
|
797
|
+
self.save(values)
|
798
|
+
end
|
799
|
+
return self
|
800
|
+
end
|
801
|
+
|
802
|
+
def delete(where = "TRUE", ids = nil)
|
803
|
+
|
804
|
+
where = self.normalizeWhereFormat(where)
|
805
|
+
|
806
|
+
model = (ids == nil) ? self.allModels.join(', ') : @modelName
|
807
|
+
where = (self.allRelations << where).join(' and ') unless ids
|
808
|
+
|
809
|
+
@tableCursor = nil
|
810
|
+
table = hdb(@connectionName).select("#{modelName}.*").from(model).where(where).execute.table
|
811
|
+
return self if table.count == 0
|
812
|
+
|
813
|
+
ids = table.column(:id)
|
814
|
+
hdb(@connectionName).delete(@modelName, "id IN (#{ids.join(',')})")
|
815
|
+
|
816
|
+
ids.each { |id| @table.delete(self.ptrOfRecord("id", id)) }
|
817
|
+
|
818
|
+
@parents.each do |parent|
|
819
|
+
ids = table.column(parent[:referenceFieldName])
|
820
|
+
parent[:ptr].delete("id IN (#{ids.join(',')})", ids)
|
821
|
+
end
|
822
|
+
return self
|
823
|
+
|
824
|
+
end
|
825
|
+
|
826
|
+
|
827
|
+
def _remove(record = @tableCursor)
|
828
|
+
|
829
|
+
record = record.tableCursor if record.class == HRecordPtr
|
830
|
+
puts "_remove: #{record}".pink
|
831
|
+
puts "============================".red
|
832
|
+
if (record["id"][0] == "#")
|
833
|
+
@parents.each { |parent| record[parent[:referenceFieldName]]._remove }
|
834
|
+
@toWrite.delete(record)
|
835
|
+
@toChange.delete(record)
|
836
|
+
else
|
837
|
+
@parents.each do |parent|
|
838
|
+
referenceFieldName = parent[:referenceFieldName]
|
839
|
+
id = record[referenceFieldName]
|
840
|
+
parent[:ptr].remove(id)
|
841
|
+
end
|
842
|
+
@toDelete << record
|
843
|
+
end
|
844
|
+
@table.delete(record)
|
845
|
+
|
846
|
+
end
|
847
|
+
|
848
|
+
# virtual remove => the real removal happens with apply
|
849
|
+
def remove(recordId = @tableCursor["id"])
|
850
|
+
|
851
|
+
puts "remove: #{@modelName} - #{recordId}".yellow
|
852
|
+
self.findByOffLine({id: recordId})
|
853
|
+
self._remove(@tableCursor)
|
854
|
+
|
855
|
+
end
|
856
|
+
|
857
|
+
|
858
|
+
def apply
|
859
|
+
puts "************************* apply **********************".pink
|
860
|
+
self.writeAll
|
861
|
+
self.saveAll
|
862
|
+
@parents.each { |parent| parent[:ptr].apply }
|
863
|
+
@visited.each do |odb|
|
864
|
+
puts "####################################=> #{odb.modelName}".pink
|
865
|
+
odb.apply
|
866
|
+
end
|
867
|
+
@visited.clear
|
868
|
+
end
|
869
|
+
|
870
|
+
def columnWidth(fieldName, inheritance = true)
|
871
|
+
|
872
|
+
return @colsWidth[fieldName] if @colsWidth.include?(fieldName)
|
873
|
+
|
874
|
+
maxLength = fieldName.length
|
875
|
+
self.each do |row|
|
876
|
+
row.eachField(inheritance) do |fieldName, fieldValue|
|
877
|
+
len = fieldValue.to_s.length
|
878
|
+
maxLength = len if maxLength < len and fieldValue.class != HRecordPtr and fieldValue.class > HODB
|
879
|
+
end
|
880
|
+
end
|
881
|
+
|
882
|
+
return @colsWidth[fieldName] = maxLength
|
883
|
+
|
884
|
+
end
|
885
|
+
|
886
|
+
def showValue(fieldName, fieldValue, color = nil, separator = '|')
|
887
|
+
|
888
|
+
fieldValue = fieldValue.object_id if fieldValue.class == HRecordPtr or fieldValue.class <= HODB
|
889
|
+
value = " #{fieldValue.to_s.center(self.columnWidth(fieldName))} #{separator}"
|
890
|
+
unless color
|
891
|
+
print value
|
892
|
+
else
|
893
|
+
print eval "'#{value}'.#{color}"
|
894
|
+
end
|
895
|
+
end
|
896
|
+
|
897
|
+
def showHeader(color, inheritance = true)
|
898
|
+
|
899
|
+
puts
|
900
|
+
print eval "' >> #{@modelName.to_s} <<'.#{color}"
|
901
|
+
puts
|
902
|
+
self.fields(inheritance).each do |fieldName, fieldValue|
|
903
|
+
self.showValue(fieldName, "-" * self.columnWidth(fieldName, inheritance), color, '+' )
|
904
|
+
end
|
905
|
+
puts
|
906
|
+
self.fields(inheritance).each do |fieldName, fieldValue|
|
907
|
+
self.showValue(fieldName, fieldName, color, '|')
|
908
|
+
end
|
909
|
+
puts
|
910
|
+
self.fields(inheritance).each do |fieldName, fieldValue|
|
911
|
+
self.showValue(fieldName, "-" * self.columnWidth(fieldName, inheritance), color, '+' )
|
912
|
+
end
|
913
|
+
puts
|
914
|
+
end
|
915
|
+
|
916
|
+
def show(color = 'hight_cyan', inheritance = true)
|
917
|
+
@colsWidth = {}
|
918
|
+
@parents.each do |parent|
|
919
|
+
parent[:ptr].show(color, inheritance) unless (inheritance)
|
920
|
+
end
|
921
|
+
self.showHeader(color, inheritance)
|
922
|
+
self.each do |row|
|
923
|
+
row.eachField(inheritance) do |fieldName, fieldValue|
|
924
|
+
self.showValue(fieldName, fieldValue, 'white')
|
925
|
+
end
|
926
|
+
puts
|
927
|
+
end
|
928
|
+
end
|
929
|
+
|
930
|
+
def self.test1
|
931
|
+
a = HODB.new({a: 1, b: 2, c: 3})
|
932
|
+
a.a = 0
|
933
|
+
p a.a
|
934
|
+
p a.b
|
935
|
+
a.d = 40 # make a variable automatically
|
936
|
+
p a.d
|
937
|
+
end
|
938
|
+
|
939
|
+
def self.test2
|
940
|
+
odb = HODB.new
|
941
|
+
odb.name = HField.text(caption: 'Name', mandatory: true, readonly: false)
|
942
|
+
odb.name = "hypersonic"
|
943
|
+
p odb.hfields(:name), odb.name
|
944
|
+
end
|
945
|
+
|
946
|
+
end
|
947
|
+
|
948
|
+
#HODB.test2
|