dm-cutie 0.3.16

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ # Link between an generalized query and a repository_storage, has boolean to track if it was the primary storage,
2
+ # ie, that of the model that generated the query
3
+
4
+ class QueryStorageLink
5
+ include DataMapper::Resource
6
+
7
+ belongs_to :repository_storage
8
+ belongs_to :generalized_query
9
+
10
+ property :repository_storage_id, Integer, :key => true
11
+ property :generalized_query_id, Integer, :key => true
12
+
13
+ property :primary_storage, Boolean, :default => true
14
+
15
+ end
@@ -0,0 +1,67 @@
1
+ require 'digest/sha1'
2
+
3
+ # Storage information for a particular model & repository
4
+ # This table is a denormalized combination of Repositories and Models
5
+ class RepositoryStorage
6
+ include DataMapper::Resource
7
+
8
+ has n, :query_storage_links
9
+
10
+ after(:save){
11
+ DataMapper.logger.debug "Created RepositoryStorage ##{self.id}, #{self.signature}"
12
+ }
13
+
14
+ property :id, Serial
15
+ property :repo_name, String, :nullable => false
16
+ property :storage_name, String, :nullable => false
17
+ property :adapter_name, String, :nullable => false
18
+ property :model_name, String, :nullable => false
19
+
20
+ property :record_count, Integer, :nullable => false, :default => 0
21
+
22
+ property :signature, String, :length => 40, :nullable => false, :unique_index => true
23
+
24
+ def RepositoryStorage.find_or_make(r,a,s,m)
25
+ _signature = RepositoryStorage.names_to_signature(r,a,s,m)
26
+
27
+ _rs = RepositoryStorage.first(:signature => _signature) || RepositoryStorage.new
28
+
29
+ if _rs.new?
30
+ _rs.signature = _signature
31
+ _rs.repo_name = r
32
+ _rs.adapter_name = a
33
+ _rs.storage_name = s
34
+ _rs.model_name = m
35
+ _rs.save
36
+ end
37
+ _rs
38
+ end
39
+
40
+ def count_operation(op)
41
+ GeneralizedQuery.all(GeneralizedQuery.query_storage_links.repository_storage.id => self.id, :operation => op).length
42
+ end
43
+
44
+ def total_selects
45
+ @total_selects ||= count_operation(:select)
46
+ end
47
+ def total_inserts
48
+ @total_inserts ||= count_operation(:insert)
49
+ end
50
+ def total_deletes
51
+ @total_deletes ||= count_operation(:delete)
52
+ end
53
+ def total_updates
54
+ @total_updates ||= count_operation(:update)
55
+ end
56
+ def read_to_write_ratio
57
+ "#{total_selects}:#{total_inserts+total_deletes+total_updates}"
58
+ end
59
+
60
+ # @param r [~String] Repository name
61
+ # @param s [~String] Storage name
62
+ # @param a [~String] Adapter name
63
+ # @param m [~String] Model name
64
+ def RepositoryStorage.names_to_signature(r,a,s,m)
65
+ Digest::SHA1.hexdigest("#{r}>#{a}>#{s}>#{m}")
66
+ end
67
+ end
@@ -0,0 +1,16 @@
1
+ require 'bigdecimal'
2
+
3
+ # module DataMapper
4
+ # module Cutie
5
+ # module Tracker
6
+ # module DataObjects
7
+ # end
8
+ # end
9
+ # end
10
+ # end
11
+
12
+ require DataMapper::Cutie.root / :tracker / :data_objects / :overrides
13
+ require DataMapper::Cutie.root / :tracker / :data_objects / :helper
14
+
15
+ # DataMapper::Adapters::DataObjectsAdapter.extend DataMapper::Cutie::Tracker::DataObjects::Overrides
16
+ # DataMapper::Adapters::DataObjectsAdapter.extend DataMapper::Cutie::Tracker::DataObjects::Helper
@@ -0,0 +1,85 @@
1
+ require 'bigdecimal'
2
+ #
3
+ # @note: This adds a few helper methods to DataObjectsAdapter
4
+ #
5
+ class DataMapper::Adapters::DataObjectsAdapter
6
+
7
+ # This source method is 6 calls deep in apps started with a bin like merb, rails; otherwise, we are looking for the last line
8
+ # /Volumes/Workspace/dm-cutie-0.3.13/lib/dm-cutie/tracker/data_objects_adapter_helper.rb:38:in `read'
9
+ # /Volumes/Workspace/dm-core-0.10.1/lib/dm-core/adapters/data_objects_adapter.rb:266:in `with_connection'
10
+ # /Volumes/Workspace/dm-cutie-0.3.13/lib/dm-cutie/tracker/data_objects_adapter_override.rb:67:in `read'
11
+ # /Volumes/Workspace/dm-core-0.10.1/lib/dm-core/repository.rb:141:in `read'
12
+ # /Volumes/Workspace/dm-core-0.10.1/lib/dm-core/model.rb:303:in `first'
13
+ # /Volumes/Workspace/dm-core-0.10.1/lib/dm-core/model.rb:204:in `get'
14
+ # /Volumes/Workspace/dm-cutie-0.3.13/kickstart.rb:50
15
+ #
16
+ def _calls_deep;6;end;
17
+
18
+ # Accessor for query timers
19
+ def query_timers;(@__query_timers ||= {});end;
20
+
21
+ # - bind_statement: binds values to a SQL statement
22
+ #
23
+ # @param statement [~String] SQL Statement
24
+ # @param *bind_values [*splat] Values to bind
25
+ #
26
+ # @return [String] Bound SQL Statement
27
+ #
28
+ def bind_statement(statement, *bind_values)
29
+ _ret_stmnt = ''
30
+ with_connection do |connection|
31
+ command = connection.create_command(statement)
32
+ _ret_stmnt = command.send :escape_sql, *bind_values
33
+ end
34
+ _ret_stmnt
35
+ end
36
+
37
+ def start_tracking_timer(query)
38
+ if DataMapper::Cutie.tracking_query?(query)
39
+ query_timers[query.object_id] = Time.now
40
+ end
41
+ end
42
+
43
+ def track_query(query, statement, bind_values)
44
+ if DataMapper::Cutie.tracking_query? query
45
+ query_start_time = query_timers.delete(query.object_id)
46
+ query_end_time = Time.now
47
+
48
+ _call_info = caller[_calls_deep] || caller.last
49
+ _call_info = _call_info.split(':')
50
+
51
+ DataMapper::Cutie.repo do
52
+ generalized_query = GeneralizedQuery.find_or_make query, statement
53
+ DataMapper.logger.debug "BEGAN PROFILING ~ #{query.model} : #{generalized_query.operation}"
54
+ executed_query = ExecutedQuery.new
55
+
56
+ executed_query.statement = bind_statement(statement, bind_values)
57
+
58
+ executed_query.repo_signature = Digest::SHA1.hexdigest("#{query.repository.name}: #{executed_query.statement}")
59
+ executed_query.signature = Digest::SHA1.hexdigest(executed_query.statement)
60
+
61
+ executed_query.elapsed_time = BigDecimal.new(query_end_time.to_f.to_s) - BigDecimal.new(query_start_time.to_f.to_s)
62
+ executed_query.executed_at = query_start_time
63
+
64
+ # Manhandle the data if its too big, should the fields just be blobs instead?
65
+ executed_query.caller_file = _call_info[0][ -255, _call_info[0].length ] if _call_info[0]
66
+ executed_query.caller_line = _call_info[1]
67
+ executed_query.caller_method = _call_info[2][ 0, 255 ] if _call_info[2]
68
+
69
+ executed_query.bind_values = bind_values
70
+ executed_query.generalized_query = generalized_query
71
+
72
+ executed_query.save
73
+
74
+ DataMapper::Cutie.process_tracker_hooks(
75
+ query.repository.adapter.options[:adapter], # The current adapter
76
+ generalized_query.operation, # The current operation
77
+ executed_query # The currently executed query
78
+ )
79
+
80
+ end # Finish DataMapper::Cutie.repo context
81
+
82
+ end #End if tracking_query?
83
+ end
84
+
85
+ end
@@ -0,0 +1,161 @@
1
+ class DataMapper::Adapters::DataObjectsAdapter
2
+ def create(resources)
3
+ resources.each do |resource|
4
+ model = resource.model
5
+ serial = model.serial(name)
6
+ attributes = resource.dirty_attributes
7
+
8
+ properties = []
9
+ bind_values = []
10
+
11
+ # make the order of the properties consistent
12
+ model.properties(name).each do |property|
13
+ next unless attributes.key?(property)
14
+
15
+ bind_value = attributes[property]
16
+
17
+ # skip insering NULL for columns that are serial or without a default
18
+ next if bind_value.nil? && (property.serial? || !property.default?)
19
+
20
+ # if serial is being set explicitly, do not set it again
21
+ if property.equal?(serial)
22
+ serial = nil
23
+ end
24
+
25
+ properties << property
26
+ bind_values << bind_value
27
+ end
28
+
29
+ statement = insert_statement(model, properties, serial)
30
+
31
+ #### BEGIN DataMapper::Cutie ####
32
+ # @note: Need a Query object for the tracker or to rewrite what the tracker takes, it was easier to just
33
+ # make a BS Query object to pass in since the other CRUD methods have a query object.
34
+ query = DataMapper::Query.new(resource.repository, resource.model)
35
+
36
+ start_tracking_timer(query)
37
+
38
+ result = execute(statement, *bind_values)
39
+
40
+ #### END DataMapper::Cutie ####
41
+ track_query(query, statement, bind_values)
42
+
43
+ if result.to_i == 1 && serial
44
+ serial.set!(resource, result.insert_id)
45
+ end
46
+ end
47
+ end
48
+
49
+ # Constructs and executes SELECT query, then instantiates
50
+ # one or many object from result set.
51
+ #
52
+ # @param [Query] query
53
+ # composition of the query to perform
54
+ #
55
+ # @return [Array]
56
+ # result set of the query
57
+ #
58
+ # @api semipublic
59
+ def read(query)
60
+ fields = query.fields
61
+ types = fields.map { |property| property.primitive }
62
+
63
+ statement, bind_values = select_statement(query)
64
+
65
+ records = []
66
+
67
+ with_connection do |connection|
68
+ command = connection.create_command(statement)
69
+ command.set_types(types)
70
+
71
+ #### BEGIN DataMapper::Cutie ####
72
+ start_tracking_timer(query)
73
+
74
+ reader = command.execute_reader(*bind_values)
75
+
76
+ track_query(query, statement, bind_values)
77
+ #### END DataMapper::Cutie ####
78
+
79
+ begin
80
+ while reader.next!
81
+ records << fields.zip(reader.values).to_hash
82
+ end
83
+ ensure
84
+ reader.close
85
+ end
86
+ end
87
+
88
+ records
89
+ end
90
+
91
+ # Constructs and executes UPDATE statement for given
92
+ # attributes and a query
93
+ #
94
+ # @param [Hash(Property => Object)] attributes
95
+ # hash of attribute values to set, keyed by Property
96
+ # @param [Collection] collection
97
+ # collection of records to be updated
98
+ #
99
+ # @return [Integer]
100
+ # the number of records updated
101
+ #
102
+ # @api semipublic
103
+ def update(attributes, collection)
104
+ query = collection.query
105
+
106
+ # TODO: if the query contains any links, a limit or an offset
107
+ # use a subselect to get the rows to be updated
108
+
109
+ properties = []
110
+ bind_values = []
111
+
112
+ # make the order of the properties consistent
113
+ query.model.properties(name).each do |property|
114
+ next unless attributes.key?(property)
115
+ properties << property
116
+ bind_values << attributes[property]
117
+ end
118
+
119
+ statement, conditions_bind_values = update_statement(properties, query)
120
+
121
+ bind_values.concat(conditions_bind_values)
122
+
123
+ #### BEGIN DataMapper::Cutie ####
124
+ start_tracking_timer(query)
125
+
126
+ result = execute(statement, *bind_values).to_i
127
+
128
+ #### END DataMapper::Cutie ####
129
+ track_query(query, statement, bind_values)
130
+
131
+ result
132
+ end
133
+
134
+ # Constructs and executes DELETE statement for given query
135
+ #
136
+ # @param [Collection] collection
137
+ # collection of records to be deleted
138
+ #
139
+ # @return [Integer]
140
+ # the number of records deleted
141
+ #
142
+ # @api semipublic
143
+ def delete(collection)
144
+ query = collection.query
145
+
146
+ # TODO: if the query contains any links, a limit or an offset
147
+ # use a subselect to get the rows to be deleted
148
+
149
+ statement, bind_values = delete_statement(query)
150
+
151
+ #### BEGIN DataMapper::Cutie ####
152
+ start_tracking_timer(query)
153
+
154
+ result = execute(statement, *bind_values).to_i
155
+
156
+ #### END DataMapper::Cutie ####
157
+ track_query(query, statement, bind_values)
158
+
159
+ result
160
+ end
161
+ end
@@ -0,0 +1,57 @@
1
+ module DataMapper
2
+ module Cutie
3
+ module Tracker
4
+ module Hook
5
+ module Abstract
6
+ def self.included(model)
7
+ model.extend DataMapper::Cutie::Tracker::Hook::Abstract::ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ # - supported_statements - Statements supported by this tracker hook
12
+ #
13
+ # @example
14
+ # [:delete]
15
+ #
16
+ # @return [Array[Symbol]]
17
+ #
18
+ def supported_statements
19
+ [:select, :insert, :update, :delete]
20
+ end
21
+
22
+ # - supported_adapters - List of adapters that will use this hook
23
+ #
24
+ # @example
25
+ # [ :mysql, :sqlite3 ]
26
+ #
27
+ # @return [Array[Symbol]]
28
+ #
29
+ def supported_adapters
30
+ raise Exception, "#{self.class}.supported_adapters was not implemented"
31
+ end
32
+
33
+ # - track - Factory method that is called to start your hook
34
+ #
35
+ # @param executed_query [ExecutedQuery] - the executed query
36
+ #
37
+ # return [NilClass]
38
+ #
39
+ def track( executed_query )
40
+ raise Exception, "#{self.class}.track was not implemented"
41
+ end
42
+
43
+ # - hook_name - The name of your hook
44
+ #
45
+ # @return [String]
46
+ #
47
+ def hook_name
48
+ raise Exception, "#{self.class}.hook_name was not implemented"
49
+ end
50
+ end
51
+
52
+ module InstanceMethods;end;
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,5 @@
1
+ module DataMapper
2
+ module Cutie
3
+ VERSION = '0.3.16'.freeze
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-cutie
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.16
5
+ platform: ruby
6
+ authors:
7
+ - Cory ODaniel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-15 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: extlib
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.12
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: dm-core
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.10.0
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: dm-types
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.10.0
44
+ version:
45
+ description: DataMapper's Query Tracker; She is super thorough and easy as hell, just the way you like it.
46
+ email: cutie@coryodaniel.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - README.markdown
53
+ - LICENSE
54
+ - History.txt
55
+ files:
56
+ - LICENSE
57
+ - README.markdown
58
+ - Rakefile
59
+ - lib/dm-cutie.rb
60
+ - lib/dm-cutie/cutie.rb
61
+ - lib/dm-cutie/version.rb
62
+ - lib/dm-cutie/models/executed_query.rb
63
+ - lib/dm-cutie/models/query_storage_link.rb
64
+ - lib/dm-cutie/models/repository_storage.rb
65
+ - lib/dm-cutie/models/generalized_query.rb
66
+ - lib/dm-cutie/tracker/data_objects.rb
67
+ - lib/dm-cutie/tracker/data_objects/helper.rb
68
+ - lib/dm-cutie/tracker/data_objects/overrides.rb
69
+ - lib/dm-cutie/tracker/hook/abstract.rb
70
+ - History.txt
71
+ has_rdoc: true
72
+ homepage: http://github.com/coryodaniel/dm-cutie
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "0"
91
+ version:
92
+ requirements: []
93
+
94
+ rubyforge_project:
95
+ rubygems_version: 1.3.5
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: DataMapper's Original Query Tracker'
99
+ test_files: []
100
+