dm-cutie-extras 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
File without changes
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2009, Cory ODaniel
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a
4
+ copy of this software and associated documentation files (the "Software"),
5
+ to deal in the Software without restriction, including without limitation
6
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the
8
+ Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
+ DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,62 @@
1
+ Description
2
+ =============
3
+ dm-cutie-extras is a pack of extra stuff for dm-cutie and dm-cutie-ui.
4
+
5
+
6
+ Usage
7
+ ============
8
+ require 'dm-core'
9
+ require 'dm-cutie'
10
+ require 'dm-cutie-extras'
11
+
12
+ DataMapper::Cutie::Extras.load :mysql_query_plan
13
+
14
+ DataMapper::Cutie.start(true)
15
+
16
+
17
+ Creating Views
18
+ ==============
19
+ If your hook includes a DataMapper model and you are writing a view, the view name should
20
+ be the plural of your model name
21
+
22
+
23
+ Writing Tracker Hooks
24
+ =====================
25
+ See documentation @ http://github.com/coryodaniel/dm-cutie/
26
+
27
+
28
+ Adding Custom Columns to Views
29
+ ==============================
30
+ The partial 'grid' takes three keys to create its local variables: :columns, :records, :adhoc_columns (discussed next)
31
+
32
+ Columns should be respond to #each, it will generally be a DataMapper PropertySet. Each element in columns will be used in a #send method call on each of the elements in records. That means instead of doing the standard
33
+ partial :grid, :locals => { :columns => MyModel.properties, :records => @my_collection}
34
+
35
+ You can add any other columns you want as long as there is a method that a 'record' will respond to. For example, every object has a 'class' method, so you could do
36
+ partial :grid,
37
+ :locals => {
38
+ :columns => MyModel.properties.to_a + [:class],
39
+ :records => @my_collection
40
+ }
41
+
42
+ This would cause the class name to be output in a column (pretty useless), but you can add any method you want to the class and simply add its name to the set of elements being passed to :columns
43
+
44
+
45
+ As an alternative method you can pass a column name to a proc in the :adhoc_columns parameter
46
+ partial :grid,
47
+ :locals => {
48
+ :columns => MyModel.properties,
49
+ :records => @my_collection,
50
+ :adhoc_columns => {
51
+ :my_cool_class_name => lambda{|my_record| my_record.class }
52
+ }
53
+ }
54
+
55
+ This would result in a column named 'my_cool_class_name' with a value of 'MyModel'. Obviously you can be more creative :)
56
+
57
+ Note: the proc should accept one parameter, the specific record from the collection of items passed to :records
58
+
59
+ IMPORTANT NOTE:
60
+ Remember, if you are adding additional columns to the grid, make sure you pass the column names to the 'menu' partial if you want the ability to hide that column.
61
+
62
+
@@ -0,0 +1,94 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+ require "extlib"
6
+
7
+ require 'rake'
8
+ require 'rake/clean'
9
+ require 'spec/rake/spectask'
10
+ require "spec"
11
+ require 'rake/rdoctask'
12
+ require 'rake/gempackagetask'
13
+
14
+ ROOT = Pathname(__FILE__).dirname.expand_path
15
+ require ROOT + 'lib/dm-cutie-extras/version'
16
+
17
+ @spec = Gem::Specification.new do |s|
18
+ s.name = %q{dm-cutie-extras}
19
+ s.version = DataMapper::Cutie::Extras::VERSION
20
+
21
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
22
+ s.authors = ["Cory ODaniel"]
23
+ s.date = %q{2009-10-15}
24
+ s.summary = %q{DM Cutie's Extras}
25
+ s.description = %q{Cool additional hooks for DM Cutie.}
26
+
27
+ s.email = %q{cutie@coryodaniel.com}
28
+
29
+ s.extra_rdoc_files = ["README.markdown", "LICENSE", "History.txt", "TODO.markdown"]
30
+ s.files = ["LICENSE", "README.markdown", "Rakefile", "TODO.markdown",
31
+ "lib/dm-cutie-extras.rb",
32
+ "lib/dm-cutie-extras/version.rb",
33
+ ]
34
+ s.files += Dir[ "lib/dm-cutie-extras/views/*"]
35
+ s.files += Dir[ "lib/dm-cutie-extras/hooks/*"]
36
+
37
+ s.add_dependency "extlib",">=0.9.12"
38
+ s.add_dependency "dm-core", '>=0.10.0'
39
+ s.add_dependency "dm-types", '>=0.10.0'
40
+
41
+ s.has_rdoc = true
42
+ s.homepage = "http://github.com/coryodaniel/dm-cutie-extras"
43
+ s.require_paths = ["lib"]
44
+ s.rubygems_version = %q{1.2.0}
45
+ end
46
+
47
+ [ ROOT, ROOT.parent ].each do |dir|
48
+ Pathname.glob(dir.join('tasks/**/*.rb').to_s).each { |f| require f }
49
+ end
50
+
51
+ NAME = @spec.name
52
+ GEM_VERSION = DataMapper::Cutie::Extras::VERSION
53
+
54
+ Rake::GemPackageTask.new(@spec) do |pkg|
55
+ pkg.gem_spec = @spec
56
+ end
57
+
58
+ desc "install the plugin locally"
59
+ task :install => [:package] do
60
+ sh %{sudo gem install #{install_home} pkg/#{NAME}-#{GEM_VERSION} --no-update-sources}
61
+ end
62
+
63
+ desc "create a gemspec file"
64
+ task :make_spec do
65
+ File.open("#{NAME}.gemspec", "w") do |file|
66
+ file.puts @spec.to_ruby
67
+ end
68
+ end
69
+
70
+ Rake::RDocTask.new do |rdoc|
71
+ files = ["README.markdown", "History.txt", "LICENSE", "lib/**/*.rb"]
72
+ rdoc.rdoc_files.add(files)
73
+ rdoc.main = "README.markdown"
74
+ rdoc.title = "DM Cutie Extras"
75
+
76
+ rdoc.rdoc_dir = "doc/rdoc"
77
+ rdoc.options << "--line-numbers" << "--inline-source"
78
+ end
79
+
80
+ Spec::Rake::SpecTask.new do |t|
81
+ t.spec_files = Dir["./spec/**/*_spec.rb"]
82
+ t.spec_files.unshift './spec/spec_helper.rb'
83
+
84
+ t.libs = ['lib']
85
+ t.spec_opts << "--color" << "--format" << "specdoc" #"progress"
86
+
87
+ if ENV['RCOV']
88
+ t.rcov = true
89
+ t.rcov_opts << '--exclude' << 'pkg,spec,interactive.rb,install_test_suite.rb,lib/gems,' + Gem.path.join(',')
90
+ t.rcov_opts << '--text-summary'
91
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
92
+ t.rcov_opts << '--only-uncovered'
93
+ end
94
+ end
@@ -0,0 +1,60 @@
1
+ MysqlIndex
2
+ =============
3
+ * Percent of times used (Need a way to set dependencies between hooks)
4
+ * mysql_index count times used queryplan.keys.split(',').member? index.key_name
5
+ * mysql_index count times used queryplan.possible_keys_.split(',').member? index.key_name
6
+
7
+ * link MysqlIndex to executed OR generalized query ?
8
+ * Offer DROP INDEX on mysql_index
9
+ * redundant index detection http://www.paragon-cs.com/presentations/querytuning.pdf
10
+
11
+
12
+ MysqlOptimizations (Probably highly correlated to MysqlExecutionStep...)
13
+ ===================
14
+ * Offer ADD INDEX on generalized_query (Optimize Queries like this)
15
+
16
+
17
+ Amazon SimpleDB
18
+ ===============
19
+ * Cost calculation
20
+
21
+
22
+ MysqlExecutionStep
23
+ ==================
24
+ * full table scans causes:
25
+ * no WHERE clause
26
+ * no index on any field in WHERE clause
27
+ * poor selectivity on an indexed field
28
+ * too many records meet WHERE conditions
29
+ * MySQL version less than 5.0 and using OR in a WHERE clause
30
+ * using SELECT * FROM
31
+ * select_type optimizers
32
+ * if MysqlExecutionStep.select_type =~ /DEPENDENT/i # Correlated subquery, consider rewriting as join
33
+ * type optimizers
34
+ * extra optimizers
35
+ * distinct
36
+ * full scan on NULL key
37
+ * Impossible WHERE noticed after reading const table
38
+ * No tables
39
+ * Not exists
40
+ * Range checked for each record (index map: N)
41
+ * Select tables optimized away
42
+ * Using filesort
43
+ * Using index
44
+ * Using index for group-by
45
+ * Using sort_union(...), Using union(...), Using intersect(...)
46
+ * Using temporary
47
+ * Using where
48
+ * Using where with pushed condition
49
+ * covering index useful
50
+ * When you have large tables
51
+ * When you have long rows (BLOBS for example)
52
+ * When extra columns do not increase key length significantly
53
+ * When you have a large join with a number of secondary table lookups
54
+ * When a lot of rows match the same key value
55
+
56
+ Analyze joins
57
+ =============
58
+ * Repository Storage 'strongest' relationships (storage that a given storage is most frequently joined with)
59
+ * Repository Storage 'weakest' relationship
60
+ * Repository Storage w/ no relationship
@@ -0,0 +1,28 @@
1
+ module DataMapper
2
+ module Cutie
3
+ class Extras
4
+ class << self
5
+
6
+ def view_path
7
+ @_view_paths ||={}
8
+ end
9
+
10
+ def root
11
+ @_root_path ||= File.expand_path(File.dirname(__FILE__)) / 'dm-cutie-extras'
12
+ end
13
+
14
+ def load(*_hooks)
15
+ _hooks.each do |_hook|
16
+ require DataMapper::Cutie::Extras.root / 'hooks' / _hook
17
+ hook_view_path = DataMapper::Cutie::Extras.root / 'views' / "#{_hook.to_s.pluralize}.erb"
18
+
19
+ if File.exist? hook_view_path
20
+ DataMapper::Cutie::Extras.view_path[_hook] = hook_view_path
21
+ end
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,63 @@
1
+ # Tracker Hook for recording mysql query plans
2
+ #
3
+ class MysqlExecutionStep
4
+ include DataMapper::Cutie::Tracker::Hook::Abstract
5
+ include DataMapper::Resource
6
+
7
+ STATEMENT = "EXPLAIN EXTENDED %s"
8
+
9
+ belongs_to :executed_query
10
+ property :id, Serial
11
+
12
+ property :order, Integer, :nullable => false #the order the step was executed in
13
+ property :type, String
14
+ property :select_type, String
15
+ property :table, String #denormalized, duplicate, you can get this through self.generalized_query.query_storage_links.first(:primary_storage => true).repository_storage.table_name
16
+ property :possible_keys,String
17
+ property :used_key, String # maps to: OpenStruct#key
18
+ property :used_key_len, String # maps to: OpenStruct#key_len
19
+ property :ref, String
20
+ property :rows, Integer
21
+ property :filtered, Float
22
+ property :extra, String
23
+
24
+ def self.hook_name; "MySQL Execution Steps" end;
25
+ def self.supported_statements; [:select]; end;
26
+ def self.supported_adapters; [:mysql]; end;
27
+
28
+ def self.execute(target_repo, query_str)
29
+ repository(target_repo.to_sym).adapter.query MysqlExecutionStep::STATEMENT % query_str
30
+ end
31
+
32
+ def self.track( executed_query )
33
+ # Perform the EXPLAIN against the original target repo
34
+ raw_query_plan = MysqlExecutionStep.execute(
35
+ executed_query.generalized_query.primary_storage.repo_name,
36
+ executed_query.statement
37
+ )
38
+
39
+ #Store the MysqlExecutionSteps in the DM Cutie repo
40
+ DataMapper::Cutie.repo do
41
+ raw_query_plan.each_with_index do |raw_query_step, idx|
42
+ attribs = raw_query_step.attributes
43
+ attribs.delete(:id) #get rid of the rowID from MySQL
44
+ attribs[:used_key] = attribs.delete(:key)
45
+ attribs[:used_key_len] = attribs.delete(:key_len)
46
+ query_step = MysqlExecutionStep.new(attribs)
47
+ query_step.order = idx + 1
48
+ query_step.executed_query = executed_query
49
+
50
+ query_step.save
51
+ end
52
+ end
53
+ end #end track
54
+ end
55
+
56
+ # Let executed query know it just got some mysql_execution_steps
57
+ ExecutedQuery.send :has, (1/0.to_f), :mysql_execution_steps
58
+
59
+ # Let Cutie know she needs to treat this as an internal model
60
+ DataMapper::Cutie.add_internal_model :mysql_execution_step
61
+
62
+ # Let cutie know she has a new hook
63
+ DataMapper::Cutie.add_tracker_hook :mysql_execution_step
@@ -0,0 +1,132 @@
1
+ # This isn't a Tracker::Hook, its actually and After Create hook for RepositoryStorage and ExecutedQuery
2
+ #
3
+ # In calculating the selectivity, since the number of records can change, I do the average selectivity
4
+ # and the final selectivity (on stopping Dm Cutie)
5
+ #
6
+ class MysqlIndex
7
+ include DataMapper::Resource
8
+
9
+ STATEMENT = "SHOW INDEX FROM %s"
10
+
11
+ belongs_to :repository_storage
12
+ property :id, Serial
13
+ property :non_unique, Boolean
14
+ property :key_name, String
15
+ property :sequence_in_index, Integer # maps to: OpenStruct#Seq_in_index
16
+ property :table, String #denormalized, accessible through repository_storage
17
+ property :column_name, String
18
+ property :collation, String
19
+ property :cardinality, Integer
20
+ property :sub_part, Integer
21
+ property :packed, String
22
+ property :null, String
23
+ property :index_type, String
24
+
25
+ ######### SELECTIVITY #########
26
+ # The distinctness of the values in the column
27
+ property :distinct_count, Integer, :default => 0, :nullable => false
28
+
29
+ # denormalized, this is the count of 'executed_queries' that are related to this index
30
+ # @note there is no direction relationship (belongs_to/has) to executed_query in this model
31
+ property :execution_count, Integer, :default => 0, :nullable => false
32
+
33
+ # methods for selectivity
34
+ # selectivity is calculated by count(*) / count(distinct(COLUMN_NAME)) the closer to 1.0
35
+ # the better the index
36
+ def selectivity
37
+ ( distinct_count.to_f / self.repository_storage.record_count.to_f )
38
+ end
39
+
40
+ # Shortcut method to R:W of repo
41
+ def table_read_to_write_ratio
42
+ self.repository_storage.read_to_write_ratio
43
+ end
44
+
45
+ # TODO Row length could be a useful addition to calculating this
46
+ # TODO Potential Uses vs Actual Uses could be a useful addition to calculating this
47
+ #
48
+ def usefulness
49
+ # Number of records, read to write ratio, selectivity
50
+ num_records = self.repository_storage.record_count
51
+ num_reads = self.repository_storage.total_selects
52
+ num_writes = self.repository_storage.total_inserts +
53
+ self.repository_storage.total_deletes +
54
+ self.repository_storage.total_updates
55
+
56
+ records_processed = num_records * execution_count
57
+ total_operations = (num_reads + num_writes).to_f
58
+ read_percentage = (num_reads / total_operations)
59
+ # write_percentage = (num_writes / total_operations)
60
+ return(
61
+ (total_operations * read_percentage * selectivity) / total_operations
62
+ )
63
+ end
64
+
65
+ # detect duplicate indexes
66
+ def duplicate
67
+ MysqlIndex.all(
68
+ :id.not => self.id,
69
+ :table => self.table,
70
+ :index_type => self.index_type,
71
+ :column_name => self.column_name
72
+ ).count != 0
73
+ end
74
+
75
+ ######### CLASS METHODS #########
76
+ def self.execute( target_repo, storage_name )
77
+ repository(target_repo.to_sym).adapter.query MysqlIndex::STATEMENT % storage_name
78
+ end
79
+
80
+ # Track the selectivity of an index
81
+ def self.process_executed_query( executed_query )
82
+ executing_repo = executed_query.generalized_query.primary_storage
83
+
84
+ MysqlIndex.all(MysqlIndex.repository_storage.id => executing_repo.id).each do |mysql_index|
85
+ # Get to the repo BEING tracked for distinct count
86
+ distinct_column_count = DataMapper.repository(executing_repo.repo_name.to_sym) do |exec_repo|
87
+ exec_repo.adapter.query(
88
+ "SELECT COUNT(DISTINCT(`#{mysql_index.column_name}`)) FROM `#{mysql_index.table}`"
89
+ ).first
90
+ end
91
+
92
+ DataMapper::Transaction.new.link do
93
+ mysql_index.distinct_count = distinct_column_count
94
+ mysql_index.execution_count += 1
95
+ mysql_index.save
96
+ end
97
+ end
98
+ end
99
+
100
+
101
+
102
+ # Track the indexes on a Repository Storage
103
+ def self.process_repository_storage( repository_storage )
104
+ # Perform the SHOW index on the repos storage
105
+ raw_index_list = MysqlIndex.execute( repository_storage.repo_name, repository_storage.storage_name )
106
+
107
+ #Store the MysqlIndex in the DM Cutie repo
108
+ DataMapper::Cutie.repo do
109
+ raw_index_list.each_with_index do |shown_index, idx|
110
+ attribs = shown_index.attributes
111
+ attribs.delete(:comment)
112
+ attribs[:sequence_in_index] = attribs.delete(:seq_in_index)
113
+ mysql_index = MysqlIndex.new(attribs)
114
+ mysql_index.repository_storage = repository_storage
115
+
116
+ mysql_index.save
117
+ end
118
+ end
119
+ end #end process_repository_storage
120
+
121
+ end
122
+
123
+ # Let executed query know it just got some mysql_execution_steps
124
+ RepositoryStorage.send :has, (1/0.to_f), :mysql_indexes
125
+
126
+ # Let Cutie know she needs to treat this as an internal model
127
+ DataMapper::Cutie.add_internal_model :mysql_index
128
+
129
+ # Add this to the after(:create) for RepositoryStorage
130
+ RepositoryStorage.send(:after,:create){ MysqlIndex.process_repository_storage self }
131
+
132
+ ExecutedQuery.send(:after, :create){ MysqlIndex.process_executed_query self }
@@ -0,0 +1,48 @@
1
+ # Tracker Hook for recording mysql warnings
2
+ #
3
+ class MysqlWarning
4
+ include DataMapper::Cutie::Tracker::Hook::Abstract
5
+ include DataMapper::Resource
6
+
7
+ STATEMENT = "SHOW WARNINGS"
8
+
9
+ belongs_to :executed_query
10
+ property :id, Serial
11
+
12
+ property :level, String
13
+ property :code, Integer
14
+ property :message, Text
15
+
16
+ def self.hook_name; "MySQL Warnings" end;
17
+ def self.supported_statements; [:select, :insert, :update, :delete]; end;
18
+ def self.supported_adapters; [:mysql]; end;
19
+
20
+ def self.track( executed_query )
21
+ # Perform the show warings
22
+ raw_warnings = repository(
23
+ executed_query.generalized_query.primary_storage.repo_name.to_sym
24
+ ).adapter.query MysqlWarning::STATEMENT % executed_query.statement
25
+
26
+ #Store the MysqlWarning in the DM Cutie repo
27
+ DataMapper::Cutie.repo do
28
+ raw_warnings.each_with_index do |raw_warning, idx|
29
+ next if raw_warning.attributes[:level] =~ /^note$/i
30
+ attribs = raw_warning.attributes
31
+ mysql_warning = MysqlWarning.new(attribs)
32
+ mysql_warning.executed_query = executed_query
33
+ mysql_warning.save
34
+ end
35
+ end
36
+ end #end track
37
+
38
+
39
+ end
40
+
41
+ # Let executed query know it just got some mysql_warnings
42
+ ExecutedQuery.send :has, (1/0.to_f), :mysql_warnings
43
+
44
+ # Let Cutie know she needs to treat this as an internal model
45
+ DataMapper::Cutie.add_internal_model :mysql_warning
46
+
47
+ # Let cutie know she has a new hook
48
+ DataMapper::Cutie.add_tracker_hook :mysql_warning
@@ -0,0 +1,55 @@
1
+ # Tracker Hook for recording sqlite3 query plans
2
+ #
3
+ class Sqlite3ExecutionStep
4
+ include DataMapper::Cutie::Tracker::Hook::Abstract
5
+ include DataMapper::Resource
6
+
7
+ STATEMENT = "EXPLAIN QUERY PLAN %s"
8
+
9
+ belongs_to :executed_query
10
+ property :id, Serial
11
+
12
+ property :order, Integer, :nullable => false #the order the step was executed in
13
+ property :from, Integer, :nullable => false #the table the step was performed against
14
+ property :detail, Text # "TABLE people WITH INDEX index_people_person_name_idx"
15
+
16
+ def self.hook_name
17
+ "Sqlite3 Execution Steps"
18
+ end
19
+ def self.supported_statements
20
+ [:select, :insert, :update, :delete]
21
+ end
22
+ def self.supported_adapters
23
+ [:sqlite3]
24
+ end
25
+
26
+ def self.track( executed_query )
27
+ # Perform the EXPLAIN against the original target repo
28
+ raw_query_plan = repository(
29
+ executed_query.generalized_query.primary_storage.repo_name.to_sym
30
+ ).adapter.query Sqlite3ExecutionStep::STATEMENT % executed_query.statement
31
+
32
+ #Store the Sqlite3ExecutionStep in the DM Cutie repo
33
+ DataMapper::Cutie.repo do
34
+ raw_query_plan.each_with_index do |raw_query_step, idx|
35
+ attribs = raw_query_step.attributes
36
+ query_step = Sqlite3ExecutionStep.new(attribs)
37
+ query_step.order = attribs[:order]
38
+ query_step.from = attribs[:from]
39
+ query_step.detail = attribs[:detail]
40
+ query_step.executed_query = executed_query
41
+ query_step.save
42
+ end
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ # Tell executed query it has sqlite3 execution steps
49
+ ExecutedQuery.send :has, (1/0.to_f), :sqlite3_execution_steps
50
+
51
+ # Let Cutie know she needs to treat this as an internal model
52
+ DataMapper::Cutie.add_internal_model :sqlite3_execution_step
53
+
54
+ # Let cutie know she has a new hook
55
+ DataMapper::Cutie.add_tracker_hook :sqlite3_execution_step
@@ -0,0 +1,7 @@
1
+ module DataMapper
2
+ module Cutie
3
+ module Extras
4
+ VERSION = '0.0.3'.freeze
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,47 @@
1
+ <%
2
+ # This should be an array of DM Properties or symbols, essentially things
3
+ # that can be 'sent' to each of your records
4
+ # @my_record.send(_element_in_columns_array_)
5
+
6
+ @columns = YOUR_MODEL.properties
7
+ %>
8
+
9
+ <%= partial :menu, :locals => {:columns => @columns} %>
10
+
11
+ <%
12
+ query = {}
13
+
14
+ # @example: ExecutedQuery.generalized_query.query_storage_links.repository_storage
15
+ # @note: Yours will likeley by YOUR_MODEL.executed_query.generalized_query.query_storage_links.repository_storage
16
+ #
17
+ # The point in this is that DM CutieUI allows you to filter result sets by Repository, Adapter and Model
18
+ # This builds the join statement for narrowing that down. You just have to set up how to find the relationshps
19
+ # between this model and the RepositoryStorage model
20
+ relationship_path_to_repo_storage_model = YOUR_MODEL.relationship.path.to.repository_storage
21
+
22
+ unless ram_filters[:repository].blank?
23
+ query[relationship_path_to_repo_storage_model.repo_name]= ram_filters[:repository]
24
+ end
25
+
26
+ unless ram_filters[:adapter].blank?
27
+ query[relationship_path_to_repo_storage_model.adapter_name]= ram_filters[:adapter]
28
+ end
29
+
30
+ unless ram_filters[:model].blank?
31
+ query[relationship_path_to_repo_storage_model.model_name]= ram_filters[:model]
32
+ end
33
+
34
+ # Additionally parameters may come in with specific values to filter from the result set
35
+ # query = parse_params(YOUR_MODEL).merge(query)
36
+
37
+ @records = YOUR_MODEL.all(query)
38
+ %>
39
+
40
+ <%= partial :grid,
41
+ :locals => {
42
+ :columns => @columns,
43
+ :records => @records,
44
+ :adhoc_columns => {},
45
+ :relationships => YOUR_MODEL.relationships
46
+ }
47
+ %>
@@ -0,0 +1,71 @@
1
+ <% help_link %>
2
+ <% @columns = MysqlExecutionStep.properties %>
3
+ <%= partial :menu, :locals => {:columns => @columns } %>
4
+
5
+ <%
6
+ query = {}
7
+ path_to_repo_storage = MysqlExecutionStep.executed_query.generalized_query.query_storage_links.repository_storage
8
+ unless ram_filters[:repository].blank?
9
+ query[path_to_repo_storage.repo_name]= ram_filters[:repository]
10
+ end
11
+
12
+ unless ram_filters[:adapter].blank?
13
+ query[path_to_repo_storage.adapter_name]= ram_filters[:adapter]
14
+ end
15
+
16
+ unless ram_filters[:model].blank?
17
+ query[path_to_repo_storage.model_name]= ram_filters[:model]
18
+ end
19
+
20
+ query = parse_params(MysqlExecutionStep).merge(query)
21
+ @records = MysqlExecutionStep.all(query)
22
+ %>
23
+
24
+ <%= partial :grid,
25
+ :locals => {
26
+ :columns => @columns,
27
+ :records => @records,
28
+ :relationships => MysqlExecutionStep.relationships
29
+ }
30
+ %>
31
+
32
+ <a name="help">
33
+ <div class="help_container">
34
+ <p>
35
+ <a href="http://dev.mysql.com/doc/refman/5.0/en/using-explain.html">
36
+ Details on MySQL's explain statement can be read up on here.
37
+ </a>
38
+ </p>
39
+ <p>
40
+ Below is a list of column explanations
41
+ <ul>
42
+ <li>select_type - type of SELECT</li>
43
+ <li>table - the name of the table or alias</li>
44
+ <li>type - the type of join used for the query</li>
45
+ <li>possible_keys - indexes MySQL could possible use</li>
46
+ <li>used_key - indexes MySQL actually used</li>
47
+ <li>used_key_len - the total length of keys used</li>
48
+ <li>ref - any columns used with key to retrieve results</li>
49
+ <li>rows - estimated number of rows returned</li>
50
+ <li>extra - additional details</li>
51
+ </ul>
52
+
53
+ Below is a list of the MySQL Execution Plan step 'types'. They are listed in order from best to worst.
54
+ <ul>
55
+ <li>system</li>
56
+ <li>const</li>
57
+ <li>eq_ref</li>
58
+ <li>ref</li>
59
+ <li>fulltext</li>
60
+ <li>ref_or_null</li>
61
+ <li>index_merge</li>
62
+ <li>unique_subquery</li>
63
+ <li>index_subquery</li>
64
+ <li>range</li>
65
+ <li>index</li>
66
+ <li>all</li>
67
+ </ul>
68
+ </p>
69
+
70
+ </div>
71
+ </a>
@@ -0,0 +1,45 @@
1
+ <% @columns = MysqlIndex.properties.to_a + [:usefulness, :selectivity, :table_read_to_write_ratio, :usefulness, :duplicate] %>
2
+
3
+ <%= partial :menu, :locals => {:columns => @columns} %>
4
+
5
+ <%
6
+ query = {}
7
+
8
+ unless ram_filters[:repository].blank?
9
+ query[MysqlIndex.repository_storage.repo_name]= ram_filters[:repository]
10
+ end
11
+
12
+ unless ram_filters[:adapter].blank?
13
+ query[MysqlIndex.repository_storage.adapter_name]= ram_filters[:adapter]
14
+ end
15
+
16
+ unless ram_filters[:model].blank?
17
+ query[MysqlIndex.repository_storage.model_name]= ram_filters[:model]
18
+ end
19
+ query = parse_params(MysqlIndex).merge(query)
20
+ @records = MysqlIndex.all(query)
21
+ %>
22
+
23
+ <%= partial :grid,
24
+ :locals => {
25
+ :columns => @columns,
26
+ :records => @records,
27
+ :adhoc_columns => {},
28
+ :relationships => MysqlIndex.relationships
29
+ }
30
+ %>
31
+
32
+ <a name="help">
33
+ <div class="help_container">
34
+ <p>
35
+ <em>Selectivity</em> measures the selectiveness of an index. The closer to '1' the better, the closer it is to '0' the MySQL optimizer will probably not use it.
36
+ Unused indexes should be dropped because they still slow down write performance.
37
+ </p>
38
+ <p>
39
+ <em>Duplicate</em> determines whether a duplicate (same index_type) index is on the table/column. Duplicate indexes require <em>n</em> times the index management, and should be avoided
40
+ </p>
41
+ <p>
42
+ <em>Usefulness</em> is just a weight to compare indexes on the same table to determine how useful an index may be. This calculation will change over time as this mysql_index plugin gets more refined. From 0 to 1, the closer to 1 the better.
43
+ </p>
44
+ </div>
45
+ </a>
@@ -0,0 +1,35 @@
1
+ <%
2
+ @columns = MysqlWarning.properties
3
+ %>
4
+
5
+ <%= partial :menu, :locals => {:columns => @columns} %>
6
+
7
+ <%
8
+ query = {}
9
+
10
+ relationship_path_to_repo_storage_model = MysqlWarning.executed_query.generalized_query.query_storage_links.repository_storage
11
+
12
+ unless ram_filters[:repository].blank?
13
+ query[relationship_path_to_repo_storage_model.repo_name]= ram_filters[:repository]
14
+ end
15
+
16
+ unless ram_filters[:adapter].blank?
17
+ query[relationship_path_to_repo_storage_model.adapter_name]= ram_filters[:adapter]
18
+ end
19
+
20
+ unless ram_filters[:model].blank?
21
+ query[relationship_path_to_repo_storage_model.model_name]= ram_filters[:model]
22
+ end
23
+
24
+ query = parse_params(MysqlWarning).merge(query)
25
+ @records = MysqlWarning.all(query)
26
+ %>
27
+
28
+ <%= partial :grid,
29
+ :locals => {
30
+ :columns => @columns,
31
+ :records => @records,
32
+ :adhoc_columns => {},
33
+ :relationships => MysqlWarning.relationships
34
+ }
35
+ %>
@@ -0,0 +1,29 @@
1
+ <% @columns = Sqlite3ExecutionStep.properties %>
2
+ <%= partial :menu, :locals => {:columns => @columns} %>
3
+
4
+ <%
5
+ query = {}
6
+ path_to_repo_storage = Sqlite3ExecutionStep.executed_query.generalized_query.query_storage_links.repository_storage
7
+ unless ram_filters[:repository].blank?
8
+ query[path_to_repo_storage.repo_name]= ram_filters[:repository]
9
+ end
10
+
11
+ unless ram_filters[:adapter].blank?
12
+ query[path_to_repo_storage.adapter_name]= ram_filters[:adapter]
13
+ end
14
+
15
+ unless ram_filters[:model].blank?
16
+ query[path_to_repo_storage.model_name]= ram_filters[:model]
17
+ end
18
+
19
+ query = parse_params(Sqlite3ExecutionStep).merge(query)
20
+ @records = Sqlite3ExecutionStep.all(query)
21
+ %>
22
+
23
+ <%= partial :grid,
24
+ :locals => {
25
+ :columns => @columns,
26
+ :records => @records,
27
+ :relationships => Sqlite3ExecutionStep.relationships
28
+ }
29
+ %>
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-cutie-extras
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
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: Cool additional hooks for DM Cutie.
46
+ email: cutie@coryodaniel.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - README.markdown
53
+ - LICENSE
54
+ - History.txt
55
+ - TODO.markdown
56
+ files:
57
+ - LICENSE
58
+ - README.markdown
59
+ - Rakefile
60
+ - TODO.markdown
61
+ - lib/dm-cutie-extras.rb
62
+ - lib/dm-cutie-extras/version.rb
63
+ - History.txt
64
+ - lib/dm-cutie-extras/views/_template_.erb
65
+ - lib/dm-cutie-extras/views/mysql_execution_steps.erb
66
+ - lib/dm-cutie-extras/views/mysql_indexes.erb
67
+ - lib/dm-cutie-extras/views/mysql_warnings.erb
68
+ - lib/dm-cutie-extras/views/sqlite3_execution_steps.erb
69
+ - lib/dm-cutie-extras/hooks/mysql_execution_step.rb
70
+ - lib/dm-cutie-extras/hooks/mysql_index.rb
71
+ - lib/dm-cutie-extras/hooks/mysql_warning.rb
72
+ - lib/dm-cutie-extras/hooks/sqlite3_execution_step.rb
73
+ has_rdoc: true
74
+ homepage: http://github.com/coryodaniel/dm-cutie-extras
75
+ licenses: []
76
+
77
+ post_install_message:
78
+ rdoc_options: []
79
+
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: "0"
87
+ version:
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: "0"
93
+ version:
94
+ requirements: []
95
+
96
+ rubyforge_project:
97
+ rubygems_version: 1.3.5
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: DM Cutie's Extras
101
+ test_files: []
102
+