gadget 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f6feadef1150080b07735c8d7d83516d87bceea9
4
+ data.tar.gz: 9c74000e08c87120b794c6871f8126198c9d248b
5
+ SHA512:
6
+ metadata.gz: e0ce84932a8c25607920db5a7111e8a3e37c70fc4eb6c486c467d0b7fd488246f880a0853e9bc226f100f750db631197f5ae7290fb1d266fcba30df01f8e7985
7
+ data.tar.gz: 1a6fc7958a2c250af87035cb7619270db989462a02c052b6db2e9bfd1ec3fd12fefe7154415bf6150e9cd511848dd0816f4c49fdafafd8b7a4aad2cd75dd5326
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ /.ruby-gemset
20
+ /.ruby-version
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Craig S. Cottingham
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,51 @@
1
+ # Gadget
2
+
3
+ Some methods for getting metadata and other deep details from a PostgreSQL database.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'gadget'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install gadget
18
+
19
+ ## Usage
20
+
21
+ `#tables(conn)`
22
+
23
+ Returns a list of all tables in the schema reachable through `conn`.
24
+
25
+ `#columns(conn, tablename=nil)`
26
+
27
+ Returns a list of all columns in the schema reachable through `conn`.
28
+ If `tablename` is given, returns the columns in only that table.
29
+
30
+ `#foreign_keys(conn, tablename=nil)`
31
+
32
+ Returns a list of all foreign keys in the schema reachable through `conn`.
33
+ If `tablename` is given, returns the foreign keys in only that table.
34
+
35
+ `#dependencies(conn)`
36
+
37
+ Returns a structure representing the dependencies between tables in the schema reachable through `conn`.
38
+ Table A is defined as dependent on table B if A contains a foreign key reference to B.
39
+
40
+ `#tables_in_dependency_order(conn)`
41
+
42
+ Returns a list of all tables in the schema reachable through `conn`, ordered such that any given table
43
+ appears later in the list than all of its dependencies.
44
+
45
+ ## Contributing
46
+
47
+ 1. Fork it
48
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
49
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
50
+ 4. Push to the branch (`git push origin my-new-feature`)
51
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'gadget'
4
+
5
+ require 'pg'
6
+
7
+ dbname = ARGV.shift
8
+
9
+ conn = PG::Connection.open(:dbname => dbname)
10
+ tables = Gadget.tables_in_dependency_order(conn)
11
+ conn.close
12
+ p tables
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'gadget/version'
6
+
7
+ Gem::Specification.new do | spec |
8
+ spec.name = 'gadget'
9
+ spec.version = Gadget::VERSION
10
+ spec.authors = [ 'Craig S. Cottingham' ]
11
+ spec.email = [ 'craig.cottingham@gmail.com' ]
12
+ spec.summary = %q{Some methods for getting metadata and other deep details from a PostgreSQL database.}
13
+ spec.description = File.read(File.join(File.dirname(__FILE__), 'README.md'))
14
+ spec.homepage = ''
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = [ 'lib' ]
21
+
22
+ spec.add_dependency 'pg', '~> 0.17.0'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.3'
25
+ spec.add_development_dependency 'rake'
26
+ end
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+
3
+ require 'pg'
4
+ require 'tsort'
5
+
6
+ require 'gadget/version'
7
+
8
+ module Gadget
9
+
10
+ class TsortableHash < Hash
11
+ include ::TSort
12
+ alias tsort_each_node each_key
13
+ def tsort_each_child(node, &block)
14
+ (fetch(node) || []).each(&block)
15
+ end
16
+ end
17
+
18
+ def self.tables(conn)
19
+ rs = conn.exec("SELECT c.oid, t.tablename FROM pg_tables t INNER JOIN pg_class c ON c.relname=t.tablename WHERE t.schemaname='public' ORDER BY t.tablename")
20
+ tuples = rs.reduce({}) { | h, row | h[row['tablename']] = { :oid => row['oid'] }; h }
21
+ rs.clear
22
+ tuples
23
+ end
24
+
25
+ def self.columns(conn, tablename = nil)
26
+ sql = <<-END_OF_SQL
27
+ SELECT t.tablename, a.attname
28
+ FROM pg_attribute a
29
+ INNER JOIN pg_class c ON a.attrelid=c.oid
30
+ INNER JOIN pg_tables t ON c.relname=t.tablename
31
+ END_OF_SQL
32
+ if tablename.nil?
33
+ rs = conn.exec(sql)
34
+ else
35
+ sql += " WHERE t.tablename=$1"
36
+ rs = conn.exec_params(sql, [ tablename ])
37
+ end
38
+ # tuples = rs.map { | row | row }
39
+ tuples = rs.reduce({}) { | h, row | h[row['tablename']] ||= { :columns => [] }; h[row['tablename']][:columns] << row['attname']; h }
40
+ rs.clear
41
+ tuples
42
+ end
43
+
44
+ def self.foreign_keys(conn, tablename = nil)
45
+ sql = <<-END_OF_SQL
46
+ SELECT t1.tablename AS tablename, t2.tablename AS refname
47
+ FROM pg_constraint
48
+ INNER JOIN pg_class c1 ON pg_constraint.conrelid=c1.oid
49
+ INNER JOIN pg_tables t1 ON c1.relname=t1.tablename
50
+ INNER JOIN pg_class c2 ON pg_constraint.confrelid=c2.oid
51
+ INNER JOIN pg_tables t2 ON c2.relname=t2.tablename
52
+ WHERE t1.schemaname='public'
53
+ AND t2.schemaname='public'
54
+ AND pg_constraint.contype='f'
55
+ END_OF_SQL
56
+ if tablename.nil?
57
+ rs = conn.exec(sql)
58
+ else
59
+ sql += " AND t1.tablename=$1"
60
+ rs = conn.exec_params(sql, [ tablename ])
61
+ end
62
+ tuples = rs.reduce({}) { | h, row | h[row['tablename']] ||= { :refs => [] }; h[row['tablename']][:refs] << row['refname']; h }
63
+ rs.clear
64
+ tuples
65
+ end
66
+
67
+ def self.dependencies(conn)
68
+ tables = self.tables(conn)
69
+ foreign_keys = self.foreign_keys(conn)
70
+ dependencies = tables.reduce({}) do | h, (tablename, _) |
71
+ h[tablename] = []
72
+ refs = foreign_keys[tablename]
73
+ unless refs.nil?
74
+ refs[:refs].each { | ref | h[tablename] << ref }
75
+ end
76
+ h
77
+ end
78
+ end
79
+
80
+ def self.tables_in_dependency_order(conn)
81
+ self.dependencies(conn).reduce(TsortableHash.new) { | h, (k, v) | h[k] = v; h }.tsort
82
+ end
83
+
84
+ def self.dependency_graph(conn)
85
+ puts "digraph dependencies {"
86
+ self.dependencies(conn).each do | tablename, deps |
87
+ if deps.empty?
88
+ puts %Q<"#{tablename}">
89
+ else
90
+ deps.each { | dep | puts %Q|"#{tablename}" -> "#{dep}"| }
91
+ end
92
+ end
93
+ puts "}"
94
+ end
95
+
96
+ end
@@ -0,0 +1,3 @@
1
+ module Gadget
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gadget
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Craig S. Cottingham
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pg
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.17.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.17.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: |
56
+ # Gadget
57
+
58
+ Some methods for getting metadata and other deep details from a PostgreSQL database.
59
+
60
+ ## Installation
61
+
62
+ Add this line to your application's Gemfile:
63
+
64
+ gem 'gadget'
65
+
66
+ And then execute:
67
+
68
+ $ bundle
69
+
70
+ Or install it yourself as:
71
+
72
+ $ gem install gadget
73
+
74
+ ## Usage
75
+
76
+ `#tables(conn)`
77
+
78
+ Returns a list of all tables in the schema reachable through `conn`.
79
+
80
+ `#columns(conn, tablename=nil)`
81
+
82
+ Returns a list of all columns in the schema reachable through `conn`.
83
+ If `tablename` is given, returns the columns in only that table.
84
+
85
+ `#foreign_keys(conn, tablename=nil)`
86
+
87
+ Returns a list of all foreign keys in the schema reachable through `conn`.
88
+ If `tablename` is given, returns the foreign keys in only that table.
89
+
90
+ `#dependencies(conn)`
91
+
92
+ Returns a structure representing the dependencies between tables in the schema reachable through `conn`.
93
+ Table A is defined as dependent on table B if A contains a foreign key reference to B.
94
+
95
+ `#tables_in_dependency_order(conn)`
96
+
97
+ Returns a list of all tables in the schema reachable through `conn`, ordered such that any given table
98
+ appears later in the list than all of its dependencies.
99
+
100
+ ## Contributing
101
+
102
+ 1. Fork it
103
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
104
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
105
+ 4. Push to the branch (`git push origin my-new-feature`)
106
+ 5. Create new Pull Request
107
+ email:
108
+ - craig.cottingham@gmail.com
109
+ executables:
110
+ - gadget
111
+ extensions: []
112
+ extra_rdoc_files: []
113
+ files:
114
+ - ".gitignore"
115
+ - Gemfile
116
+ - LICENSE.txt
117
+ - README.md
118
+ - Rakefile
119
+ - bin/gadget
120
+ - gadget.gemspec
121
+ - lib/gadget.rb
122
+ - lib/gadget/version.rb
123
+ homepage: ''
124
+ licenses:
125
+ - MIT
126
+ metadata: {}
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ requirements: []
142
+ rubyforge_project:
143
+ rubygems_version: 2.2.0.rc.1
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: Some methods for getting metadata and other deep details from a PostgreSQL
147
+ database.
148
+ test_files: []