lafcadio 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/lib/lafcadio.rb +32 -0
  2. data/lib/lafcadio.rb~ +32 -0
  3. data/lib/lafcadio/TestSuite.rb +16 -0
  4. data/lib/lafcadio/dateTime.rb +2 -0
  5. data/lib/lafcadio/dateTime/Month.rb +93 -0
  6. data/lib/lafcadio/domain.rb +119 -0
  7. data/lib/lafcadio/domain.rb~ +119 -0
  8. data/lib/lafcadio/domain/DomainObject.rb +375 -0
  9. data/lib/lafcadio/domain/DomainObject.rb~ +371 -0
  10. data/lib/lafcadio/domain/MapObject.rb +22 -0
  11. data/lib/lafcadio/domain/ObjectType.rb +80 -0
  12. data/lib/lafcadio/includer.rb +18 -0
  13. data/lib/lafcadio/mock.rb +2 -0
  14. data/lib/lafcadio/mock/MockDbBridge.rb +78 -0
  15. data/lib/lafcadio/mock/MockDbBridge.rb~ +74 -0
  16. data/lib/lafcadio/mock/MockObjectStore.rb +20 -0
  17. data/lib/lafcadio/objectField.rb +14 -0
  18. data/lib/lafcadio/objectField/AutoIncrementField.rb +25 -0
  19. data/lib/lafcadio/objectField/BooleanField.rb +83 -0
  20. data/lib/lafcadio/objectField/DateField.rb +33 -0
  21. data/lib/lafcadio/objectField/DateTimeField.rb +25 -0
  22. data/lib/lafcadio/objectField/DecimalField.rb +41 -0
  23. data/lib/lafcadio/objectField/EmailField.rb +28 -0
  24. data/lib/lafcadio/objectField/EnumField.rb +62 -0
  25. data/lib/lafcadio/objectField/FieldValueError.rb +4 -0
  26. data/lib/lafcadio/objectField/IntegerField.rb +15 -0
  27. data/lib/lafcadio/objectField/LinkField.rb +92 -0
  28. data/lib/lafcadio/objectField/LinkField.rb~ +86 -0
  29. data/lib/lafcadio/objectField/MoneyField.rb +13 -0
  30. data/lib/lafcadio/objectField/MonthField.rb +16 -0
  31. data/lib/lafcadio/objectField/ObjectField.rb +142 -0
  32. data/lib/lafcadio/objectField/PasswordField.rb +29 -0
  33. data/lib/lafcadio/objectField/StateField.rb +13 -0
  34. data/lib/lafcadio/objectField/SubsetLinkField.rb +25 -0
  35. data/lib/lafcadio/objectField/TextField.rb +23 -0
  36. data/lib/lafcadio/objectField/TextListField.rb +21 -0
  37. data/lib/lafcadio/objectField/TimeStampField.rb +15 -0
  38. data/lib/lafcadio/objectStore.rb +100 -0
  39. data/lib/lafcadio/objectStore/Cache.rb +81 -0
  40. data/lib/lafcadio/objectStore/Committer.rb +65 -0
  41. data/lib/lafcadio/objectStore/CouldntMatchObjectTypeError.rb +4 -0
  42. data/lib/lafcadio/objectStore/DbBridge.rb +140 -0
  43. data/lib/lafcadio/objectStore/DbBridge.rb~ +140 -0
  44. data/lib/lafcadio/objectStore/DomainComparable.rb +25 -0
  45. data/lib/lafcadio/objectStore/DomainObjectInitError.rb +9 -0
  46. data/lib/lafcadio/objectStore/DomainObjectNotFoundError.rb +4 -0
  47. data/lib/lafcadio/objectStore/DomainObjectProxy.rb +62 -0
  48. data/lib/lafcadio/objectStore/DomainObjectSqlMaker.rb +74 -0
  49. data/lib/lafcadio/objectStore/ObjectStore.rb +207 -0
  50. data/lib/lafcadio/objectStore/ObjectStore.rb~ +207 -0
  51. data/lib/lafcadio/objectStore/SqlValueConverter.rb +30 -0
  52. data/lib/lafcadio/objectStore/SqlValueConverter.rb~ +30 -0
  53. data/lib/lafcadio/query.rb +203 -0
  54. data/lib/lafcadio/query/Compare.rb +55 -0
  55. data/lib/lafcadio/query/CompoundCondition.rb +39 -0
  56. data/lib/lafcadio/query/Condition.rb +66 -0
  57. data/lib/lafcadio/query/Condition.rb~ +66 -0
  58. data/lib/lafcadio/query/Equals.rb +45 -0
  59. data/lib/lafcadio/query/In.rb +20 -0
  60. data/lib/lafcadio/query/Like.rb +48 -0
  61. data/lib/lafcadio/query/Link.rb +20 -0
  62. data/lib/lafcadio/query/Max.rb +32 -0
  63. data/lib/lafcadio/query/Max.rb~ +25 -0
  64. data/lib/lafcadio/query/Not.rb +21 -0
  65. data/lib/lafcadio/query/Query.rb +92 -0
  66. data/lib/lafcadio/schema.rb +2 -0
  67. data/lib/lafcadio/schema/CreateTableStatement.rb +61 -0
  68. data/lib/lafcadio/schema/CreateTableStatement.rb~ +59 -0
  69. data/lib/lafcadio/test.rb +2 -0
  70. data/lib/lafcadio/test/LafcadioTestCase.rb +17 -0
  71. data/lib/lafcadio/test/testconfig.dat +13 -0
  72. data/lib/lafcadio/util.rb +180 -0
  73. data/lib/lafcadio/util/Context.rb +61 -0
  74. data/lib/lafcadio/util/ContextualService.rb +33 -0
  75. data/lib/lafcadio/util/English.rb +117 -0
  76. data/lib/lafcadio/util/HashOfArrays.rb +48 -0
  77. data/lib/lafcadio/util/LafcadioConfig.rb +25 -0
  78. data/lib/lafcadio/util/QueueHash.rb +67 -0
  79. data/lib/lafcadio/util/UsStates.rb +29 -0
  80. data/lib/lafcadio/xml.rb +2 -0
  81. metadata +135 -0
@@ -0,0 +1,13 @@
1
+ require 'lafcadio/util/UsStates'
2
+ require 'lafcadio/objectField/EnumField'
3
+
4
+ module Lafcadio
5
+ # A StateField is a specialized subclass of EnumField; its possible values are
6
+ # any of the 50 states of the United States, stored as each state's two-letter
7
+ # postal code.
8
+ class StateField < EnumField
9
+ def initialize(objectType, name = "state", englishName = nil)
10
+ super objectType, name, UsStates.states, englishName
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ require 'lafcadio/objectField/LinkField'
2
+
3
+ module Lafcadio
4
+ class SubsetLinkField < LinkField #:nodoc:
5
+ def SubsetLinkField.instantiationParameters( fieldElt )
6
+ parameters = super( fieldElt )
7
+ parameters['subsetField'] = fieldElt.attributes['subsetField']
8
+ parameters
9
+ end
10
+
11
+ def SubsetLinkField.instantiateWithParameters( domainClass, parameters )
12
+ self.new( domainClass, parameters['linkedType'],
13
+ parameters['subsetField'], parameters['name'],
14
+ parameters['englishName'] )
15
+ end
16
+
17
+ attr_accessor :subsetField
18
+
19
+ def initialize(objectType, linkedType, subsetField,
20
+ name = linkedType.name.downcase, englishName = nil)
21
+ super(objectType, linkedType, name, englishName)
22
+ @subsetField = subsetField
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ require 'lafcadio/objectField/ObjectField'
2
+
3
+ module Lafcadio
4
+ # A TextField is expected to contain a string value.
5
+ class TextField < ObjectField
6
+ attr_accessor :large, :size
7
+
8
+ def initialize(objectType, name, englishName = nil)
9
+ super objectType, name, englishName
10
+ @large = false
11
+ end
12
+
13
+ def valueForSQL(value) #:nodoc:
14
+ if value
15
+ value = value.gsub(/(\\?')/) { |m| m.length == 1 ? "''" : m }
16
+ value = value.gsub(/\\/) { '\\\\' }
17
+ "'#{value}'"
18
+ else
19
+ "null"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ require 'lafcadio/objectField/ObjectField'
2
+
3
+ module Lafcadio
4
+ # TextListField maps to any String SQL field that tries to represent a
5
+ # quick-and-dirty list with a comma-separated string. It returns an Array.
6
+ # For example, a SQL field with the value "john,bill,dave", then the Ruby
7
+ # field will have the value <tt>[ "john", "bill", "dave" ]</tt>.
8
+ class TextListField < ObjectField
9
+ def valueFromSQL(sqlString, lookupLink = true) #:nodoc:
10
+ if sqlString
11
+ sqlString.split ','
12
+ else
13
+ []
14
+ end
15
+ end
16
+
17
+ def valueForSQL(objectValue) #:nodoc:
18
+ "'" + objectValue.join(',') + "'"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'lafcadio/objectField/DateTimeField'
2
+
3
+ module Lafcadio
4
+ class TimeStampField < DateTimeField #:nodoc:
5
+ def initialize(objectType, name = 'timeStamp', englishName = nil)
6
+ super( objectType, name, englishName )
7
+ @hideDisplay = true
8
+ @notNull = false
9
+ end
10
+
11
+ def dbWillAutomaticallyWrite
12
+ true
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,100 @@
1
+ require 'lafcadio/includer'
2
+ Includer.include( 'objectStore' )
3
+ require 'lafcadio/util/English'
4
+
5
+ module Lafcadio
6
+ class FieldMatchError < StandardError; end
7
+
8
+ class ObjectStore
9
+ class MethodDispatch #:nodoc:
10
+ attr_reader :symbol, :args
11
+
12
+ def initialize( orig_method, maybe_proc, *orig_args )
13
+ @orig_method = orig_method
14
+ @maybe_proc = maybe_proc
15
+ @orig_args = orig_args
16
+ @methodName = orig_method.id2name
17
+ if @methodName =~ /^get(.*)$/
18
+ dispatch_get_method
19
+ else
20
+ raise_no_method_error
21
+ end
22
+ end
23
+
24
+ def dispatch_get_plural
25
+ if @orig_args.size == 0 && @maybe_proc.nil?
26
+ @symbol = :getAll
27
+ @args = [ @domain_class ]
28
+ else
29
+ searchTerm = @orig_args[0]
30
+ fieldName = @orig_args[1]
31
+ if searchTerm.nil? && @maybe_proc.nil? && fieldName.nil?
32
+ msg = "ObjectStore\##{ @orig_method } needs a field name as its " +
33
+ "second argument if its first argument is nil"
34
+ raise( ArgumentError, msg, caller )
35
+ end
36
+ dispatch_get_plural_by_query_block_or_search_term( searchTerm,
37
+ fieldName )
38
+ end
39
+ end
40
+
41
+ def dispatch_get_plural_by_query_block
42
+ inferrer = Query::Inferrer.new( @domain_class ) { |obj|
43
+ @maybe_proc.call( obj )
44
+ }
45
+ @symbol = :getSubset
46
+ @args = [ inferrer.execute ]
47
+ end
48
+
49
+ def dispatch_get_plural_by_query_block_or_search_term( searchTerm,
50
+ fieldName )
51
+ if !@maybe_proc.nil? && searchTerm.nil?
52
+ dispatch_get_plural_by_query_block
53
+ elsif @maybe_proc.nil? && ( !( searchTerm.nil? && fieldName.nil? ) )
54
+ @symbol = :getFiltered
55
+ @args = [ @domain_class.name, searchTerm, fieldName ]
56
+ else
57
+ raise( ArgumentError,
58
+ "Shouldn't send both a query block and a search term",
59
+ caller )
60
+ end
61
+ end
62
+
63
+ def dispatch_get_method
64
+ begin
65
+ dispatch_get_singular
66
+ rescue CouldntMatchObjectTypeError
67
+ objectTypeName = English.singular( method_name_after_get )
68
+ begin
69
+ @domain_class = DomainObject.
70
+ getObjectTypeFromString( objectTypeName )
71
+ dispatch_get_plural
72
+ rescue CouldntMatchObjectTypeError
73
+ raise_no_method_error
74
+ end
75
+ end
76
+ end
77
+
78
+ def dispatch_get_singular
79
+ objectType = DomainObject.
80
+ getObjectTypeFromString( method_name_after_get )
81
+ if @orig_args[0].class <= Integer
82
+ @symbol = :get
83
+ @args = [ objectType, @orig_args[0] ]
84
+ elsif @orig_args[0].class <= DomainObject
85
+ @symbol = :getMapObject
86
+ @args = [ objectType, @orig_args[0], @orig_args[1] ]
87
+ end
88
+ end
89
+
90
+ def method_name_after_get
91
+ @orig_method.id2name =~ /^get(.*)$/
92
+ $1
93
+ end
94
+
95
+ def raise_no_method_error
96
+ raise( NoMethodError, "undefined method '#{ @methodName }'", caller )
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,81 @@
1
+ require 'lafcadio/util/ContextualService'
2
+
3
+ module Lafcadio
4
+ class ObjectStore < ContextualService
5
+ class Cache #:nodoc:
6
+ def initialize( dbBridge )
7
+ @dbBridge = dbBridge
8
+ @objects = {}
9
+ @collections_by_query = {}
10
+ @commit_times = {}
11
+ end
12
+
13
+ def hashByObjectType(objectType)
14
+ unless @objects[objectType]
15
+ @objects[objectType] = {}
16
+ end
17
+ @objects[objectType]
18
+ end
19
+
20
+ # Returns a cached domain object, or nil if none is found.
21
+ def get(objectType, pkId)
22
+ hashByObjectType(objectType)[pkId].clone
23
+ end
24
+
25
+ # Saves a domain object.
26
+ def save(dbObject)
27
+ hashByObjectType(dbObject.objectType)[dbObject.pkId] = dbObject
28
+ flush_collection_cache( dbObject.objectType )
29
+ end
30
+
31
+ def getByQuery( query )
32
+ unless @collections_by_query[query]
33
+ newObjects = @dbBridge.getCollectionByQuery(query)
34
+ newObjects.each { |dbObj| save dbObj }
35
+ @collections_by_query[query] = newObjects.collect { |dobj|
36
+ dobj.pkId
37
+ }
38
+ end
39
+ collection = []
40
+ @collections_by_query[query].each { |pkId|
41
+ dobj = get( query.objectType, pkId )
42
+ collection << dobj if dobj
43
+ }
44
+ collection
45
+ end
46
+
47
+ # Returns an array of all domain objects of a given type.
48
+ def getAll(objectType)
49
+ hashByObjectType(objectType).values.collect { |d_obj| d_obj.clone }
50
+ end
51
+
52
+ # Flushes a domain object.
53
+ def flush(dbObject)
54
+ hashByObjectType(dbObject.objectType).delete dbObject.pkId
55
+ flush_collection_cache( dbObject.objectType )
56
+ end
57
+
58
+ def flush_collection_cache( objectType )
59
+ @collections_by_query.keys.each { |query|
60
+ if query.objectType == objectType
61
+ @collections_by_query.delete( query )
62
+ end
63
+ }
64
+ end
65
+
66
+ def last_commit_time( domain_class, pkId )
67
+ by_domain_class = @commit_times[domain_class]
68
+ by_domain_class ? by_domain_class[pkId] : nil
69
+ end
70
+
71
+ def set_commit_time( d_obj )
72
+ by_domain_class = @commit_times[d_obj.objectType]
73
+ if by_domain_class.nil?
74
+ by_domain_class = {}
75
+ @commit_times[d_obj.objectType] = by_domain_class
76
+ end
77
+ by_domain_class[d_obj.pkId] = Time.now
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,65 @@
1
+ require 'lafcadio/objectStore/ObjectStore'
2
+
3
+ module Lafcadio
4
+ class Committer #:nodoc:
5
+ INSERT = 1
6
+ UPDATE = 2
7
+ DELETE = 3
8
+
9
+ attr_reader :commitType, :dbObject
10
+
11
+ def initialize(dbObject, dbBridge)
12
+ @dbObject = dbObject
13
+ @dbBridge = dbBridge
14
+ @objectStore = Context.instance.getObjectStore
15
+ @commitType = nil
16
+ end
17
+
18
+ def setCommitType
19
+ if @dbObject.delete
20
+ @commitType = DELETE
21
+ elsif @dbObject.pkId
22
+ @commitType = UPDATE
23
+ else
24
+ @commitType = INSERT
25
+ end
26
+ end
27
+
28
+ def execute
29
+ setCommitType
30
+ @dbObject.lastCommit = getLastCommit
31
+ @dbObject.preCommitTrigger
32
+ if @dbObject.delete
33
+ dependentClasses = @dbObject.objectType.dependentClasses
34
+ dependentClasses.keys.each { |aClass|
35
+ field = dependentClasses[aClass]
36
+ collection = @objectStore.getFiltered( aClass.name, @dbObject,
37
+ field.name )
38
+ collection.each { |dependentObject|
39
+ if field.deleteCascade
40
+ dependentObject.delete = true
41
+ else
42
+ dependentObject.send( field.name + '=', nil )
43
+ end
44
+ @objectStore.commit(dependentObject)
45
+ }
46
+ }
47
+ end
48
+ @dbBridge.commit @dbObject
49
+ unless @dbObject.pkId
50
+ @dbObject.pkId = @dbBridge.lastPkIdInserted
51
+ end
52
+ @dbObject.postCommitTrigger
53
+ end
54
+
55
+ def getLastCommit
56
+ if @dbObject.delete
57
+ DomainObject::COMMIT_DELETE
58
+ elsif @dbObject.pkId
59
+ DomainObject::COMMIT_EDIT
60
+ else
61
+ DomainObject::COMMIT_ADD
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,4 @@
1
+ module Lafcadio
2
+ class CouldntMatchObjectTypeError < RuntimeError #:nodoc:
3
+ end
4
+ end
@@ -0,0 +1,140 @@
1
+ require 'rubygems'
2
+
3
+ require 'dbi'
4
+ require_gem 'log4r'
5
+ require 'lafcadio/util/LafcadioConfig'
6
+
7
+ module Lafcadio
8
+ class DbBridge #:nodoc:
9
+ @@dbh = nil
10
+ @@lastPkIdInserted = nil
11
+ @@dbName = nil
12
+ @@connectionClass = DBI
13
+
14
+ def DbBridge.setDbName(dbName)
15
+ @@dbName = dbName
16
+ end
17
+
18
+ def DbBridge._load(aString)
19
+ aString =~ /dbh:/
20
+ dbString = $'
21
+ begin
22
+ dbh = Marshal.load(dbString)
23
+ rescue TypeError
24
+ dbh = nil
25
+ end
26
+ new dbh
27
+ end
28
+
29
+ def DbBridge.flushConnection
30
+ @@dbh = nil
31
+ end
32
+
33
+ def DbBridge.setConnectionClass( aClass )
34
+ @@connectionClass = aClass
35
+ end
36
+
37
+ def DbBridge.disconnect
38
+ @@dbh.disconnect if @@dbh
39
+ end
40
+
41
+ def initialize(dbh = nil)
42
+ if dbh == nil
43
+ if @@dbh == nil
44
+ config = LafcadioConfig.new
45
+ dbName = @@dbName || config['dbname']
46
+ dbAndHost = nil
47
+ if dbName && config['dbhost']
48
+ dbAndHost = "dbi:Mysql:#{ dbName }:#{ config['dbhost'] }"
49
+ else
50
+ dbAndHost = "dbi:#{config['dbconn']}"
51
+ end
52
+ @@dbh = @@connectionClass.connect( dbAndHost, config['dbuser'],
53
+ config['dbpassword'] )
54
+ end
55
+ else
56
+ @@dbh = dbh
57
+ end
58
+ @dbh = @@dbh
59
+ ObjectSpace.define_finalizer( self, proc { |id| DbBridge.disconnect } )
60
+ end
61
+
62
+ def maybeLog(sql)
63
+ config = LafcadioConfig.new
64
+ if config['logSql'] == 'y'
65
+ sqllog = Log4r::Logger['sql'] || Log4r::Logger.new( 'sql' )
66
+ filename = File.join( config['logdir'], config['sqlLogFile'] || 'sql' )
67
+ outputter = Log4r::FileOutputter.new( 'outputter',
68
+ { :filename => filename } )
69
+ sqllog.outputters = outputter
70
+ sqllog.info sql
71
+ end
72
+ end
73
+
74
+ def commit(dbObject)
75
+ require 'lafcadio/objectStore/DomainObjectSqlMaker'
76
+ sqlMaker = DomainObjectSqlMaker.new(dbObject)
77
+ sqlMaker.sqlStatements.each { |sql, binds| executeCommit( sql, binds ) }
78
+ if sqlMaker.sqlStatements[0].first =~ /insert/
79
+ sql = 'select last_insert_id()'
80
+ result = executeSelect( sql )
81
+ @@lastPkIdInserted = result[0]['last_insert_id()'].to_i
82
+ end
83
+ end
84
+
85
+ def executeCommit( sql, binds )
86
+ @dbh.do( sql, *binds )
87
+ end
88
+
89
+ def getCollectionByQuery(query)
90
+ require 'lafcadio/objectStore/SqlValueConverter'
91
+ objectType = query.objectType
92
+ coll = []
93
+ objects = []
94
+ result = executeSelect query.toSql
95
+ result.each { |row_hash|
96
+ converter = SqlValueConverter.new(objectType, row_hash)
97
+ obj = objectType.new converter
98
+ objects << obj
99
+ }
100
+ coll = coll.concat objects
101
+ coll
102
+ end
103
+
104
+ def executeSelect(sql)
105
+ maybeLog sql
106
+ begin
107
+ @dbh.select_all( sql )
108
+ rescue DBI::DatabaseError => e
109
+ raise $!.to_s + ": #{ e.errstr }"
110
+ end
111
+ end
112
+
113
+ def _dump(aDepth)
114
+ if @db.respond_to? '_dump'
115
+ dbDump = @db._dump
116
+ else
117
+ dbDump = @db.class.to_s
118
+ end
119
+ "dbh:#{dbDump}"
120
+ end
121
+
122
+ def lastPkIdInserted
123
+ @@lastPkIdInserted
124
+ end
125
+
126
+ def group_query( query )
127
+ row = executeSelect( query.toSql )[0]
128
+ result = []
129
+ row.each { |val|
130
+ if query.field_name != query.objectType.sqlPrimaryKeyName
131
+ a_field = query.objectType.getField( query.field_name )
132
+ result << a_field.valueFromSQL( val )
133
+ else
134
+ result << val.to_i
135
+ end
136
+ }
137
+ result
138
+ end
139
+ end
140
+ end