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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/lib/hdatastructures/hfieldtable.rb +285 -0
  3. data/lib/hdatastructures/hhash.rb +9 -0
  4. data/lib/hdatastructures/hlist.rb +100 -0
  5. data/lib/hdatastructures/hrecord.rb +75 -0
  6. data/lib/hdatastructures/hspreadfieldtable.rb +129 -0
  7. data/lib/hdb/hdataloader.rb +75 -0
  8. data/lib/hdb/hdb.rb +357 -0
  9. data/lib/hdb/hdb_test.rb +248 -0
  10. data/lib/hdb/hdbgenerator.rb +211 -0
  11. data/lib/hdb/hdbi.rb +63 -0
  12. data/lib/hdb/hdbi_test.rb +133 -0
  13. data/lib/hdb/hfield.rb +180 -0
  14. data/lib/hdb/hmysql.rb +99 -0
  15. data/lib/hdb/hmysql2.rb +96 -0
  16. data/lib/hdb/hodb.rb +948 -0
  17. data/lib/hdb/hpgsql.rb +54 -0
  18. data/lib/hengine/application_controller.rb +204 -0
  19. data/lib/hengine/hconfiguration.rb +40 -0
  20. data/lib/hengine/hhotlogger.rb +13 -0
  21. data/lib/hengine/hlogger.rb +119 -0
  22. data/lib/hengine/hmalloc.rb +275 -0
  23. data/lib/hengine/hmoduleloader.rb +15 -0
  24. data/lib/hengine/hsessiondata.rb +79 -0
  25. data/lib/hengine/hshareddata.rb +60 -0
  26. data/lib/hengine/htranslate.rb +40 -0
  27. data/lib/hengine/hviewloader.rb +99 -0
  28. data/lib/hinit/hinit.rb +3 -0
  29. data/lib/hmisc/hcolorize.rb +100 -0
  30. data/lib/hmisc/hdecoratorfunctions.rb +15 -0
  31. data/lib/hmisc/hdir.rb +19 -0
  32. data/lib/hmisc/hhtmlnode.rb +27 -0
  33. data/lib/hmisc/hinputvalidator.rb +95 -0
  34. data/lib/hmisc/hio.rb +142 -0
  35. data/lib/hmisc/hjson.rb +16 -0
  36. data/lib/hsqlmanager/hpgsqldatabasemanager.rb +76 -0
  37. data/lib/hsqlmanager/hsqldatabasemanager.rb +349 -0
  38. data/lib/hsqlmanager/hsqltable.rb +16 -0
  39. data/lib/husermanager/husermanager.rb +122 -0
  40. data/lib/hwidgets/haccordionmenu.rb +117 -0
  41. data/lib/hwidgets/hcheckboxtag.rb +33 -0
  42. data/lib/hwidgets/hdbactionbuttons.rb +26 -0
  43. data/lib/hwidgets/hdbcombobox.rb +71 -0
  44. data/lib/hwidgets/hdbdialogview.rb +190 -0
  45. data/lib/hwidgets/hdbfilterview.rb +28 -0
  46. data/lib/hwidgets/hdbtableview.rb +213 -0
  47. data/lib/hwidgets/hdbview.rb +63 -0
  48. data/lib/hwidgets/hdivtag.rb +9 -0
  49. data/lib/hwidgets/hdropdown.rb +44 -0
  50. data/lib/hwidgets/hformfield.rb +91 -0
  51. data/lib/hwidgets/hgrouptag.rb +65 -0
  52. data/lib/hwidgets/hhiddeninputtag.rb +12 -0
  53. data/lib/hwidgets/hinputtag.rb +55 -0
  54. data/lib/hwidgets/hlabeltag.rb +30 -0
  55. data/lib/hwidgets/hmainview.rb +37 -0
  56. data/lib/hwidgets/hpagination.rb +65 -0
  57. data/lib/hwidgets/hradiobuttontag.rb +30 -0
  58. data/lib/hwidgets/hselecttag.rb +32 -0
  59. data/lib/hwidgets/htableview.rb +262 -0
  60. data/lib/hwidgets/htabview.rb +84 -0
  61. data/lib/hwidgets/htextareatag.rb +20 -0
  62. data/lib/hwidgets/htopnav.rb +85 -0
  63. data/lib/hwidgets/hwidget.rb +423 -0
  64. data/lib/hypersonic.rb +9 -0
  65. metadata +276 -0
@@ -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
+
@@ -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