hypersonic-plus 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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