knjrbfw 0.0.21 → 0.0.22

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.
@@ -5,7 +5,6 @@ class KnjDB_mysql
5
5
  def initialize(knjdb_ob)
6
6
  @knjdb = knjdb_ob
7
7
  @opts = @knjdb.opts
8
- @encoding = @opts[:encoding]
9
8
  @escape_table = "`"
10
9
  @escape_col = "`"
11
10
  @escape_val = "'"
@@ -13,6 +12,12 @@ class KnjDB_mysql
13
12
  @esc_col = "`"
14
13
  @mutex = Mutex.new
15
14
 
15
+ if @opts[:encoding]
16
+ @encoding = @opts[:encoding]
17
+ else
18
+ @encoding = "utf8"
19
+ end
20
+
16
21
  if @knjdb.opts.key?(:port)
17
22
  @port = @knjdb.opts[:port].to_i
18
23
  else
@@ -88,8 +93,8 @@ class KnjDB_mysql
88
93
  @jdbc_loaded = true
89
94
  end
90
95
 
91
- @conn = java.sql::DriverManager.getConnection("jdbc:mysql://#{@knjdb.opts[:host]}:#{@port}/#{@knjdb.opts[:db]}?user=#{@knjdb.opts[:user]}&password=#{@knjdb.opts[:pass]}&populateInsertRowWithDefaultValues=true&zeroDateTimeBehavior=round")
92
- query("SET SQL_MODE = ''")
96
+ @conn = java.sql::DriverManager.getConnection("jdbc:mysql://#{@knjdb.opts[:host]}:#{@port}/#{@knjdb.opts[:db]}?user=#{@knjdb.opts[:user]}&password=#{@knjdb.opts[:pass]}&populateInsertRowWithDefaultValues=true&zeroDateTimeBehavior=round&characterEncoding=#{@encoding}")
97
+ self.query("SET SQL_MODE = ''")
93
98
  else
94
99
  raise "Unknown subtype: #{@subtype}"
95
100
  end
@@ -495,12 +500,12 @@ class KnjDB_java_mysql_result
495
500
  if @as_hash
496
501
  ret = {}
497
502
  1.upto(@keys.length) do |count|
498
- ret[@keys[count - 1]] = @result.string(count).to_s.encode("utf-8")
503
+ ret[@keys[count - 1]] = @result.string(count)
499
504
  end
500
505
  else
501
506
  ret = []
502
507
  1.upto(@count) do |count|
503
- ret << @result.string(count).to_s.encode("utf-8")
508
+ ret << @result.string(count)
504
509
  end
505
510
  end
506
511
 
@@ -112,7 +112,7 @@ class KnjDB_mysql::Columns::Column
112
112
  end
113
113
 
114
114
  def drop
115
- @args[:db].query("ALTER TABLE `#{@args[:table].name}` DROP COLUMN `#{self.name}`")
115
+ @args[:db].query("ALTER TABLE `#{@args[:table_name]}` DROP COLUMN `#{self.name}`")
116
116
  end
117
117
 
118
118
  def change(data)
@@ -22,7 +22,17 @@ class KnjDB_mysql::Indexes::Index
22
22
 
23
23
  def drop
24
24
  sql = "DROP INDEX `#{self.name}` ON `#{self.table.name}`"
25
- @args[:db].query(sql)
25
+
26
+ begin
27
+ @args[:db].query(sql)
28
+ rescue => e
29
+ #The index has already been dropped - ignore.
30
+ if e.message.index("check that column/key exists") != nil
31
+ #ignore.
32
+ else
33
+ raise e
34
+ end
35
+ end
26
36
  end
27
37
 
28
38
  def data
@@ -2,7 +2,6 @@ require "#{$knjpath}wref"
2
2
 
3
3
  class KnjDB_mysql::Tables
4
4
  attr_reader :db, :driver, :list
5
- attr_accessor :list_should_be_reloaded
6
5
 
7
6
  def initialize(args)
8
7
  @args = args
@@ -83,7 +82,6 @@ class KnjDB_mysql::Tables
83
82
  sql << ")"
84
83
 
85
84
  @db.query(sql)
86
- @list_should_be_reloaded = true
87
85
 
88
86
  if data["indexes"]
89
87
  table_obj = self[name]
@@ -400,8 +400,48 @@ class Knj::Db
400
400
  return ret
401
401
  end
402
402
 
403
+ #Clones the connection, executes a unbuffered query and closes the connection again.
404
+ def cloned_conn(args = nil, &block)
405
+ subtype = @opts[:subtype]
406
+
407
+ #MySQL2-driver doesnt support unbuffered queries yet.
408
+ if @opts[:type] == "mysql" and @opts[:subtype] == "mysql2"
409
+ subtype = "mysql"
410
+ end
411
+
412
+ clone_conn_args = {
413
+ :subtype => subtype,
414
+ :threadsafe => false
415
+ }
416
+
417
+ clone_conn_args.merge!(args[:clone_args]) if args and args[:clone_args]
418
+ dbconn = self.clone_conn(clone_conn_args)
419
+
420
+ begin
421
+ yield(dbconn)
422
+ ensure
423
+ dbconn.close
424
+ end
425
+ end
426
+
403
427
  #Executes a query and returns the result. If a block is given the result is iterated over that block instead and it returns nil.
404
- def q(str, &block)
428
+ def q(str, args = nil, &block)
429
+ #If the query should be executed in a new connection unbuffered.
430
+ if args
431
+ if args[:cloned_ubuf]
432
+ raise "No block given." if !block
433
+
434
+ self.cloned_conn(:clone_args => args[:clone_args]) do |cloned_conn|
435
+ ret = cloned_conn.query_ubuf(str)
436
+ ret.each(&block)
437
+ end
438
+
439
+ return nil
440
+ else
441
+ raise "Invalid arguments given: '#{args}'."
442
+ end
443
+ end
444
+
405
445
  ret = self.query(str)
406
446
 
407
447
  if block
@@ -40,7 +40,7 @@ class Knj::Db::Revision
40
40
  @db = db
41
41
 
42
42
  #Check for normal bugs and raise apropiate error.
43
- raise "'schema' argument was not a Hash." if !schema.is_a?(Hash)
43
+ raise "'schema' argument was not a Hash: '#{schema.class.name}'." if !schema.is_a?(Hash)
44
44
  raise "':return_keys' is not 'symbols' - Knjdbrevision will not work without it." if db.opts[:return_keys] != "symbols"
45
45
  raise "No tables given." if !schema.has_key?("tables")
46
46
 
@@ -137,6 +137,8 @@ class Knj::Db::Revision
137
137
  print "Column not found: #{table_obj.name}.#{col_data["name"]}.\n" if args["debug"]
138
138
 
139
139
  if col_data.has_key?("renames")
140
+ raise "'renames' was not an array for column '#{table_obj.name}.#{col_data["name"]}'." if !col_data["renames"].is_a?(Array)
141
+
140
142
  rename_found = false
141
143
  col_data["renames"].each do |col_name|
142
144
  begin
@@ -236,6 +238,11 @@ class Knj::Db::Revision
236
238
  end
237
239
  end
238
240
 
241
+ if !table_data.key?("columns")
242
+ print "Notice: Skipping creation of '#{table_name}' because no columns were given in hash.\n"
243
+ next
244
+ end
245
+
239
246
  if table_data["on_create"]
240
247
  table_data["on_create"].call("db" => db, "table_name" => table_name, "table_data" => table_data)
241
248
  end
@@ -258,7 +265,7 @@ class Knj::Db::Revision
258
265
  schema["tables_remove"].each do |table_name, table_data|
259
266
  begin
260
267
  table_obj = db.tables[table_name.to_sym]
261
- table_data["callback"].call if table_data.is_a?(Hash) and table_data["callback"]
268
+ table_data["callback"].call("db" => db, "table" => table_obj) if table_data.is_a?(Hash) and table_data["callback"]
262
269
  table_obj.drop
263
270
  rescue Knj::Errors::NotFound => e
264
271
  next
@@ -1,4 +1,5 @@
1
1
  module Knj::Locales
2
+ #Returns the primary locale, secondary locale and the two put together.
2
3
  def self.lang
3
4
  match = self.locale.to_s.match(/^([a-z]{2})_([A-Z]{2})/)
4
5
  raise "Could not understand language: #{self.locale}." if !match
@@ -6,10 +7,11 @@ module Knj::Locales
6
7
  return {
7
8
  "first" => match[1],
8
9
  "second" => match[2],
9
- "full" => match[1] + "_" + match[2]
10
+ "full" => "#{match[1]}_#{match[2]}"
10
11
  }
11
12
  end
12
13
 
14
+ #Returns various localized information about the environment.
13
15
  def self.localeconv
14
16
  f = Knj::Locales.lang["first"]
15
17
 
@@ -35,28 +37,33 @@ module Knj::Locales
35
37
  }
36
38
  end
37
39
 
40
+ #Returns a float from the formatted string according to the current locale.
38
41
  def self.number_in(num_str)
39
42
  lc = Knj::Locales.localeconv
40
43
  num_str = num_str.to_s.gsub(lc["thousands_sep"], "").gsub(lc["decimal_point"], ".").to_f
41
44
  return num_str
42
45
  end
43
46
 
47
+ #Returns the given number as a formatted string according to the current locale.
44
48
  def self.number_out(num_str, dec = 2)
45
49
  lc = Knj::Locales.localeconv
46
50
  return Knj::Php.number_format(num_str, dec, lc["decimal_point"], lc["thousands_sep"])
47
51
  end
48
52
 
53
+ #Returns the current locale for the current environment.
49
54
  def self.locale
50
55
  begin
51
- return _session[:locale]
56
+ return _session[:locale] if _session[:locale].to_s.strip.length > 0
52
57
  rescue NameError
53
- if Thread.current[:locale]
54
- return Thread.current[:locale]
55
- elsif $locale
56
- return $locale
57
- elsif ENV["LANGUAGE"]
58
- return ENV["LANGUAGE"]
59
- end
58
+ #ignore.
59
+ end
60
+
61
+ if Thread.current[:locale]
62
+ return Thread.current[:locale]
63
+ elsif $locale
64
+ return $locale
65
+ elsif ENV["LANGUAGE"]
66
+ return ENV["LANGUAGE"]
60
67
  end
61
68
 
62
69
  raise "Could not figure out locale."
@@ -13,10 +13,13 @@ class Knj::Objects
13
13
  @args[:module] = Kernel if !@args[:module]
14
14
  @args[:cache] = :weak if !@args.key?(:cache)
15
15
  @objects = {}
16
+ @locks = {}
16
17
  @data = {}
17
18
  @mutex_require = Mutex.new
18
19
 
19
- require "weakref" if @args[:cache] == :weak and !Kernel.const_defined?(:WeakRef)
20
+ if @args[:cache] == :weak
21
+ require "#{$knjpath}wref"
22
+ end
20
23
 
21
24
  @events = Knj::Event_handler.new
22
25
  @events.add_event(
@@ -57,8 +60,16 @@ class Knj::Objects
57
60
  end
58
61
 
59
62
  def init_class(classname)
63
+ classname = classname.to_sym
60
64
  return false if @objects.key?(classname)
61
- @objects[classname] = {}
65
+
66
+ if @args[:cache] == :weak
67
+ @objects[classname] = Knj::Wref_map.new
68
+ else
69
+ @objects[classname] = {}
70
+ end
71
+
72
+ @locks[classname] = Mutex.new
62
73
  end
63
74
 
64
75
  #Returns a cloned version of the @objects variable. Cloned because iteration on it may crash some of the other methods in Ruby 1.9+
@@ -72,10 +83,12 @@ class Knj::Objects
72
83
  return objs_cloned
73
84
  end
74
85
 
86
+ #Returns the database-connection used by this instance of Objects.
75
87
  def db
76
88
  return @args[:db]
77
89
  end
78
90
 
91
+ #Returns the total count of objects currently held by this instance.
79
92
  def count_objects
80
93
  count = 0
81
94
  @objects.keys.each do |key|
@@ -85,6 +98,7 @@ class Knj::Objects
85
98
  return count
86
99
  end
87
100
 
101
+ #This connects a block to an event. When the event is called the block will be executed.
88
102
  def connect(args, &block)
89
103
  raise "No object given." if !args["object"]
90
104
  raise "No signals given." if !args.key?("signal") and !args.key?("signals")
@@ -94,8 +108,9 @@ class Knj::Objects
94
108
  @callbacks[args["object"]][conn_id] = args
95
109
  end
96
110
 
111
+ #This method is used to call the connected callbacks for an event.
97
112
  def call(args, &block)
98
- classstr = args["object"].class.to_s
113
+ classstr = args["object"].class.to_s.split("::").last
99
114
 
100
115
  if @callbacks.key?(classstr)
101
116
  @callbacks[classstr].clone.each do |callback_key, callback|
@@ -132,10 +147,12 @@ class Knj::Objects
132
147
 
133
148
  def requireclass(classname, args = {})
134
149
  classname = classname.to_sym
135
-
136
150
  return false if @objects.key?(classname)
137
151
 
138
152
  @mutex_require.synchronize do
153
+ #Maybe the classname got required meanwhile the synchronized wait - check again.
154
+ return false if @objects.key?(classname)
155
+
139
156
  if (@args[:require] or !@args.key?(:require)) and (!args.key?(:require) or args[:require])
140
157
  filename = "#{@args[:class_path]}/#{@args[:class_pre]}#{classname.to_s.downcase}.rb"
141
158
  filename_req = "#{@args[:class_path]}/#{@args[:class_pre]}#{classname.to_s.downcase}"
@@ -164,7 +181,7 @@ class Knj::Objects
164
181
  self.load_class(classname, args)
165
182
  end
166
183
 
167
- @objects[classname] = {}
184
+ self.init_class(classname)
168
185
  end
169
186
  end
170
187
 
@@ -195,48 +212,44 @@ class Knj::Objects
195
212
  raise Knj::Errors::InvalidData, "Unknown data: '#{data.class.to_s}'."
196
213
  end
197
214
 
198
- if @objects.key?(classname) and @objects[classname].key?(id)
215
+ if @objects.key?(classname)
199
216
  case @args[:cache]
200
217
  when :weak
201
- begin
202
- obj = @objects[classname][id].__getobj__
203
-
204
- if obj.is_a?(Knj::Datarow) and obj.respond_to?(:table) and obj.respond_to?(:id) and obj.table.to_sym == classname and obj.id.to_i == id
205
- return obj
206
- else
207
- #This actually happens sometimes... WTF!? - knj
208
- raise WeakRef::RefError
209
- end
210
- rescue WeakRef::RefError
211
- @objects[classname].delete(id)
212
- rescue NoMethodError => e
213
- #NoMethodError because the object might have been deleted from the cache, and __getobj__ then throws it.
214
- raise e if e.message != "undefined method `__getobj__' for nil:NilClass"
218
+ if obj = @objects[classname].get!(id) and obj.id.to_i == id
219
+ return obj
215
220
  end
216
221
  else
217
- return @objects[classname][id]
222
+ return @objects[classname][id] if @objects[classname].key?(id)
218
223
  end
219
224
  end
220
225
 
221
226
  self.requireclass(classname) if !@objects.key?(classname)
222
227
 
223
- if @args[:datarow] or @args[:custom]
224
- obj = @args[:module].const_get(classname).new(Knj::Hash_methods.new(:ob => self, :data => data))
225
- else
226
- args = [data]
227
- args = args | @args[:extra_args] if @args[:extra_args]
228
- obj = @args[:module].const_get(classname).new(*args)
229
- end
230
-
231
- case @args[:cache]
232
- when :weak
233
- @objects[classname][id] = WeakRef.new(obj)
234
- when :none
228
+ @locks[classname].synchronize do
229
+ #Maybe the object got spawned while we waited for the lock? If so we shouldnt spawn another instance.
230
+ if obj = @objects[classname].get!(id) and obj.id.to_i == id
235
231
  return obj
232
+ end
233
+
234
+ #Spawn object.
235
+ if @args[:datarow] or @args[:custom]
236
+ obj = @args[:module].const_get(classname).new(Knj::Hash_methods.new(:ob => self, :data => data))
236
237
  else
237
- @objects[classname][id] = obj
238
+ args = [data]
239
+ args = args | @args[:extra_args] if @args[:extra_args]
240
+ obj = @args[:module].const_get(classname).new(*args)
241
+ end
242
+
243
+ #Save object in cache.
244
+ case @args[:cache]
245
+ when :none
246
+ return obj
247
+ else
248
+ @objects[classname][id] = obj
249
+ end
238
250
  end
239
251
 
252
+ #Return spawned object.
240
253
  return obj
241
254
  end
242
255
 
@@ -386,10 +399,8 @@ class Knj::Objects
386
399
  end
387
400
 
388
401
  if RUBY_VERSION[0..2] == 1.8 and Knj::Php.class_exists("Dictionary")
389
- print "Spawning dictionary.\n" if args[:debug]
390
402
  list = Dictionary.new
391
403
  else
392
- print "Spawning normal hash.\n" if args[:debug]
393
404
  list = {}
394
405
  end
395
406
 
@@ -403,10 +414,7 @@ class Knj::Objects
403
414
  list["0"] = _("None")
404
415
  end
405
416
 
406
- print "Doing loop\n" if args[:debug]
407
417
  self.list(classname, args[:list_args]) do |object|
408
- print "Object: #{object.id}\n" if args[:debug]
409
-
410
418
  if object.respond_to?(:name)
411
419
  list[object.id] = object.name
412
420
  elsif object.respond_to?(:title)
@@ -416,15 +424,27 @@ class Knj::Objects
416
424
  end
417
425
  end
418
426
 
419
- print "Returning...\n" if args[:debug]
420
427
  return list
421
428
  end
422
429
 
423
430
  #Returns a list of a specific object by running specific SQL against the database.
424
- def list_bysql(classname, sql, d = nil, &block)
431
+ def list_bysql(classname, sql, args = nil, &block)
425
432
  classname = classname.to_sym
426
433
  ret = [] if !block
427
- @args[:db].q(sql) do |d_obs|
434
+ qargs = nil
435
+
436
+ if args
437
+ args.each do |key, val|
438
+ case key
439
+ when :cloned_ubuf
440
+ qargs = {:cloned_ubuf => true}
441
+ else
442
+ raise "Invalid key: '#{key}'."
443
+ end
444
+ end
445
+ end
446
+
447
+ @args[:db].q(sql, qargs) do |d_obs|
428
448
  if block
429
449
  block.call(self.get(classname, d_obs))
430
450
  else
@@ -432,10 +452,14 @@ class Knj::Objects
432
452
  end
433
453
  end
434
454
 
435
- return ret if !block
455
+ if !block
456
+ return ret
457
+ else
458
+ return nil
459
+ end
436
460
  end
437
461
 
438
- # Add a new object to the database and to the cache.
462
+ #Add a new object to the database and to the cache.
439
463
  def add(classname, data = {})
440
464
  classname = classname.to_sym
441
465
  self.requireclass(classname)
@@ -577,7 +601,7 @@ class Knj::Objects
577
601
  classname = classname.to_sym
578
602
 
579
603
  return false if !@objects.key?(classname)
580
- @objects[classname] = {}
604
+ @objects.delete(classname)
581
605
  end
582
606
 
583
607
  #Delete an object. Both from the database and from the cache.
@@ -588,13 +612,22 @@ class Knj::Objects
588
612
  object.delete if object.respond_to?(:delete)
589
613
 
590
614
  if @args[:datarow]
615
+ #If autodelete is set by 'has_many'-method, go through it and delete the various objects first.
616
+ object.class.autodelete_data.each do |adel_data|
617
+ self.list(adel_data[:classname], {adel_data[:colname].to_s => object.id}) do |obj_del|
618
+ self.delete(obj_del)
619
+ end
620
+ end
621
+
622
+ #If depend is set by 'has_many'-method, check if any objects exists and raise error if so.
591
623
  object.class.depending_data.each do |dep_data|
592
- objs = self.list(dep_data[:classname], {dep_data[:colname].to_s => object.id, "limit" => 1})
593
- if !objs.empty?
594
- raise "Cannot delete <#{object.class.name}:#{object.id}> because <#{objs[0].class.name}:#{objs[0].id}> depends on it."
624
+ obj = self.get_by(dep_data[:classname], {dep_data[:colname].to_s => object.id})
625
+ if obj
626
+ raise "Cannot delete <#{object.class.name}:#{object.id}> because <#{obj.class.name}:#{obj.id}> depends on it."
595
627
  end
596
628
  end
597
629
 
630
+ #Delete any translations that has been set on the object by 'has_translation'-method.
598
631
  if object.class.translations
599
632
  _kas.trans_del(object)
600
633
  end
@@ -668,18 +701,7 @@ class Knj::Objects
668
701
  #Runs through all objects-weaklink-references and removes the weaklinks if the object has been recycled.
669
702
  def clean_all_weak
670
703
  @objects.keys.each do |classn|
671
- @objects[classn].keys.each do |object_id|
672
- object = @objects[classn][object_id]
673
-
674
- begin
675
- if !object or !object.weakref_alive?
676
- @objects[classn].delete(object_id)
677
- end
678
- rescue WeakRef::RefError
679
- #This happens if the object has been collected.
680
- @objects[classn].delete(object_id)
681
- end
682
- end
704
+ @objects[classn].clean
683
705
  end
684
706
  end
685
707
 
@@ -707,4 +729,4 @@ class Knj::Objects
707
729
  end
708
730
  end
709
731
 
710
- require "#{$knjpath}objects/objects_sqlhelper"
732
+ require "#{$knjpath}objects/objects_sqlhelper"