meta_db 0.1.0
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.
- checksums.yaml +7 -0
 - data/.gitignore +18 -0
 - data/.rspec +3 -0
 - data/.ruby-version +1 -0
 - data/.travis.yml +7 -0
 - data/Gemfile +6 -0
 - data/README.md +37 -0
 - data/Rakefile +6 -0
 - data/TODO +12 -0
 - data/bin/console +14 -0
 - data/bin/setup +8 -0
 - data/lib/meta_db.rb +182 -0
 - data/lib/meta_db/connection.rb +97 -0
 - data/lib/meta_db/db_object.rb +352 -0
 - data/lib/meta_db/dump.rb +31 -0
 - data/lib/meta_db/version.rb +3 -0
 - data/meta_db.gemspec +40 -0
 - metadata +129 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA256:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 1e0499ce2a211cd8e953ffd5ce447913f59d7f40d4db6c56b3515d1f0f810d74
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: cca551c4c6e6537d267ab140f789977cca5ca2a8ccac12d976527780071e3e02
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 2d8670680900ef650d36a453904f13e635c996e1634ccbf0d9cf197355652eb84f74cb07405f0a62e632a5ee70f5425381886edfddc1eb8d32c42a5065804ee7
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 452f2f681469529b9deb7f7e70ca91cc492c9d7a87d2c0bf22d6c7fd36f7e2e74a1635f6b7a15b80312d793851142fadc5ce9289c62b362e12812b539b07b7db
         
     | 
    
        data/.gitignore
    ADDED
    
    | 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /.bundle/
         
     | 
| 
      
 2 
     | 
    
         
            +
            /.yardoc
         
     | 
| 
      
 3 
     | 
    
         
            +
            /_yardoc/
         
     | 
| 
      
 4 
     | 
    
         
            +
            /coverage/
         
     | 
| 
      
 5 
     | 
    
         
            +
            /doc/
         
     | 
| 
      
 6 
     | 
    
         
            +
            /pkg/
         
     | 
| 
      
 7 
     | 
    
         
            +
            /spec/reports/
         
     | 
| 
      
 8 
     | 
    
         
            +
            /tmp/
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            # rspec failure tracking
         
     | 
| 
      
 11 
     | 
    
         
            +
            .rspec_status
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            # Ignore Gemfile.lock. See https://stackoverflow.com/questions/4151495/should-gemfile-lock-be-included-in-gitignore
         
     | 
| 
      
 14 
     | 
    
         
            +
            /Gemfile.lock
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            # Ignore generated yaml and marshall files
         
     | 
| 
      
 17 
     | 
    
         
            +
            /*.yaml
         
     | 
| 
      
 18 
     | 
    
         
            +
            /*.marshal
         
     | 
    
        data/.rspec
    ADDED
    
    
    
        data/.ruby-version
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ruby-2.6.6
         
     | 
    
        data/.travis.yml
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # MetaDb
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Models the meta data (schema) of a database. The model implements parts of the
         
     | 
| 
      
 4 
     | 
    
         
            +
            information schema and extends it with postgresql specific features and
         
     | 
| 
      
 5 
     | 
    
         
            +
            features for practical use. 
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            This is work in progress. Use at your own peril
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            Add this line to your application's Gemfile:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 14 
     | 
    
         
            +
            gem 'meta_db'
         
     | 
| 
      
 15 
     | 
    
         
            +
            ```
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            And then execute:
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                $ bundle
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            Or install it yourself as:
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                $ gem install meta_db
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            TODO: Write usage instructions here
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            ## Development
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/clrgit/meta_db.
         
     | 
    
        data/Rakefile
    ADDED
    
    
    
        data/TODO
    ADDED
    
    | 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            o Tests
         
     | 
| 
      
 2 
     | 
    
         
            +
            o Handle trigger constraints
         
     | 
| 
      
 3 
     | 
    
         
            +
            o Handle exclusion constraints
         
     | 
| 
      
 4 
     | 
    
         
            +
            o Handle array types better
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            + Use information_schema
         
     | 
| 
      
 7 
     | 
    
         
            +
            + Implement Schema
         
     | 
| 
      
 8 
     | 
    
         
            +
            + Default values
         
     | 
| 
      
 9 
     | 
    
         
            +
            + Include schemas in [] and lookup on MetaDb::Db
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            - Rename to PgMeta
         
     | 
| 
      
 12 
     | 
    
         
            +
            - Implement RDBMS
         
     | 
    
        data/bin/console
    ADDED
    
    | 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "bundler/setup"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "meta_db"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # You can add fixtures and/or initialization code here to make experimenting
         
     | 
| 
      
 7 
     | 
    
         
            +
            # with your gem easier. You can also use a different console, if you like.
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            # (If you use this, don't forget to add pry to your Gemfile!)
         
     | 
| 
      
 10 
     | 
    
         
            +
            # require "pry"
         
     | 
| 
      
 11 
     | 
    
         
            +
            # Pry.start
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            require "irb"
         
     | 
| 
      
 14 
     | 
    
         
            +
            IRB.start(__FILE__)
         
     | 
    
        data/bin/setup
    ADDED
    
    
    
        data/lib/meta_db.rb
    ADDED
    
    | 
         @@ -0,0 +1,182 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "meta_db/version"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "indented_io"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'pg'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            require 'meta_db/connection.rb'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'meta_db/db_object.rb'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            module MetaDb
         
     | 
| 
      
 12 
     | 
    
         
            +
              # TODO
         
     | 
| 
      
 13 
     | 
    
         
            +
              def self.load_yaml(file)
         
     | 
| 
      
 14 
     | 
    
         
            +
                YAML.load_file(file)
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              def self.save_yaml(db, file, pretty: true)
         
     | 
| 
      
 18 
     | 
    
         
            +
                File.open(file, 'w') do |f|
         
     | 
| 
      
 19 
     | 
    
         
            +
                  arg = pretty ? { :indentation => 3 } : {}
         
     | 
| 
      
 20 
     | 
    
         
            +
                  f.write(YAML.dump(db, arg))
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              def self.load_marshal(file)
         
     | 
| 
      
 25 
     | 
    
         
            +
                File.open(file) { |f| Marshal.load(f) }
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              def self.save_marshal(db, file)
         
     | 
| 
      
 29 
     | 
    
         
            +
                File.open(file, 'w') { |f| Marshal.dump(db, f) }
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              # The options argument is a hash as PG::Connection options. :host, :port,
         
     | 
| 
      
 33 
     | 
    
         
            +
              # :dbname, :user, and :password are some of the most used
         
     | 
| 
      
 34 
     | 
    
         
            +
              def self.load_pg_conn(options)
         
     | 
| 
      
 35 
     | 
    
         
            +
                PostgresConnection.open(options) { |conn| load_conn(conn) }
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            private
         
     | 
| 
      
 39 
     | 
    
         
            +
              # Connect to the given database and return a MetaDb::Db object. If host is
         
     | 
| 
      
 40 
     | 
    
         
            +
              # nil, a socket is used to connect to the database
         
     | 
| 
      
 41 
     | 
    
         
            +
              #
         
     | 
| 
      
 42 
     | 
    
         
            +
              # The connection object should support #name and #exec
         
     | 
| 
      
 43 
     | 
    
         
            +
              def self.load_conn(conn)
         
     | 
| 
      
 44 
     | 
    
         
            +
                # TODO: Start transaction
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                # Build database
         
     | 
| 
      
 47 
     | 
    
         
            +
                r = conn.select %(
         
     | 
| 
      
 48 
     | 
    
         
            +
                  select  usename::varchar
         
     | 
| 
      
 49 
     | 
    
         
            +
                  from    pg_database d
         
     | 
| 
      
 50 
     | 
    
         
            +
                  join    pg_user u on u.usesysid = d.datdba
         
     | 
| 
      
 51 
     | 
    
         
            +
                  where   d.datname = '#{conn.database}'
         
     | 
| 
      
 52 
     | 
    
         
            +
                )
         
     | 
| 
      
 53 
     | 
    
         
            +
                r.size == 1 or raise "Internal error"
         
     | 
| 
      
 54 
     | 
    
         
            +
                db = MetaDb::Database.new(conn.database, r.each_array.first)
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                # Build schemas
         
     | 
| 
      
 57 
     | 
    
         
            +
                conn.select(%(
         
     | 
| 
      
 58 
     | 
    
         
            +
                  select  schema_name::varchar as name,
         
     | 
| 
      
 59 
     | 
    
         
            +
                          schema_owner::varchar as owner
         
     | 
| 
      
 60 
     | 
    
         
            +
                  from    information_schema.schemata
         
     | 
| 
      
 61 
     | 
    
         
            +
                  where   schema_name !~ '^pg_' AND schema_name <> 'information_schema' 
         
     | 
| 
      
 62 
     | 
    
         
            +
                )).each_hash { |row|
         
     | 
| 
      
 63 
     | 
    
         
            +
                  row[:database] = db
         
     | 
| 
      
 64 
     | 
    
         
            +
                  MetaDb::Schema.init(row)
         
     | 
| 
      
 65 
     | 
    
         
            +
                }
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                # Build tables
         
     | 
| 
      
 68 
     | 
    
         
            +
                conn.select(%(
         
     | 
| 
      
 69 
     | 
    
         
            +
                  select  table_schema::varchar as schema,
         
     | 
| 
      
 70 
     | 
    
         
            +
                          table_name::varchar as name,
         
     | 
| 
      
 71 
     | 
    
         
            +
                          table_type::varchar as type,
         
     | 
| 
      
 72 
     | 
    
         
            +
                          is_insertable_into = 'YES' as "insertable?",
         
     | 
| 
      
 73 
     | 
    
         
            +
                          is_typed = 'YES' as "typed?"
         
     | 
| 
      
 74 
     | 
    
         
            +
                  from    information_schema.tables
         
     | 
| 
      
 75 
     | 
    
         
            +
                  where   table_schema !~ '^pg_' AND table_schema <> 'information_schema'
         
     | 
| 
      
 76 
     | 
    
         
            +
                )).each_hash { |row|
         
     | 
| 
      
 77 
     | 
    
         
            +
                  row[:schema] = db.dot row[:schema]
         
     | 
| 
      
 78 
     | 
    
         
            +
                  klass = (row[:type] == 'VIEW' ? MetaDb::View : MetaDb::Table)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  klass.init(row)
         
     | 
| 
      
 80 
     | 
    
         
            +
                }
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                # Build columns
         
     | 
| 
      
 83 
     | 
    
         
            +
                conn.select(%(
         
     | 
| 
      
 84 
     | 
    
         
            +
                  select  table_schema::varchar || '.' || table_name as table,
         
     | 
| 
      
 85 
     | 
    
         
            +
                          ordinal_position as ordinal,
         
     | 
| 
      
 86 
     | 
    
         
            +
                          column_name::varchar as name,
         
     | 
| 
      
 87 
     | 
    
         
            +
                          data_type::varchar as type,
         
     | 
| 
      
 88 
     | 
    
         
            +
                          column_default as default,
         
     | 
| 
      
 89 
     | 
    
         
            +
                          is_identity = 'YES' as "identity?",
         
     | 
| 
      
 90 
     | 
    
         
            +
                          is_generated = 'YES' as "generated?",
         
     | 
| 
      
 91 
     | 
    
         
            +
                          is_nullable = 'YES' as "nullable?",
         
     | 
| 
      
 92 
     | 
    
         
            +
                          is_updatable = 'YES' as "updatable?"
         
     | 
| 
      
 93 
     | 
    
         
            +
                  from    information_schema.columns
         
     | 
| 
      
 94 
     | 
    
         
            +
                  where   table_schema !~ '^pg_' AND table_schema <> 'information_schema'
         
     | 
| 
      
 95 
     | 
    
         
            +
                )).each_hash { |row|
         
     | 
| 
      
 96 
     | 
    
         
            +
                  row[:table] = db.dot row[:table]
         
     | 
| 
      
 97 
     | 
    
         
            +
                  MetaDb::Column.init(row)
         
     | 
| 
      
 98 
     | 
    
         
            +
                }
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                # Build simple constraints
         
     | 
| 
      
 101 
     | 
    
         
            +
                conn.select(%(
         
     | 
| 
      
 102 
     | 
    
         
            +
                  select  c.constraint_type::varchar,
         
     | 
| 
      
 103 
     | 
    
         
            +
                          c.table_schema || '.' || c.table_name as table,
         
     | 
| 
      
 104 
     | 
    
         
            +
                          c.constraint_name::varchar as name,
         
     | 
| 
      
 105 
     | 
    
         
            +
                          cc.check_clause as expression,
         
     | 
| 
      
 106 
     | 
    
         
            +
                          (
         
     | 
| 
      
 107 
     | 
    
         
            +
                            select  array_agg(column_name::varchar)
         
     | 
| 
      
 108 
     | 
    
         
            +
                            from    information_schema.constraint_column_usage ccu
         
     | 
| 
      
 109 
     | 
    
         
            +
                            where   ccu.table_schema = c.table_schema
         
     | 
| 
      
 110 
     | 
    
         
            +
                            and     ccu.table_name = c.table_name
         
     | 
| 
      
 111 
     | 
    
         
            +
                            and     ccu.constraint_schema = c.constraint_schema
         
     | 
| 
      
 112 
     | 
    
         
            +
                            and     ccu.constraint_name = c.constraint_name
         
     | 
| 
      
 113 
     | 
    
         
            +
                          ) as columns
         
     | 
| 
      
 114 
     | 
    
         
            +
                  from    information_schema.table_constraints c
         
     | 
| 
      
 115 
     | 
    
         
            +
                    left join information_schema.check_constraints cc
         
     | 
| 
      
 116 
     | 
    
         
            +
                      on cc.constraint_schema = c.table_schema and
         
     | 
| 
      
 117 
     | 
    
         
            +
                         cc.constraint_name = c.constraint_name
         
     | 
| 
      
 118 
     | 
    
         
            +
                  where   c.table_schema !~ '^pg_' AND c.table_schema <> 'information_schema'
         
     | 
| 
      
 119 
     | 
    
         
            +
                  and     c.constraint_type in ('PRIMARY KEY', 'UNIQUE', 'CHECK')
         
     | 
| 
      
 120 
     | 
    
         
            +
                )).each_hash { |row|
         
     | 
| 
      
 121 
     | 
    
         
            +
                  row[:table] = db.dot row[:table]
         
     | 
| 
      
 122 
     | 
    
         
            +
                  row[:columns] = lookup_columns(row[:table], row[:columns] || [])
         
     | 
| 
      
 123 
     | 
    
         
            +
                  case row[:constraint_type]
         
     | 
| 
      
 124 
     | 
    
         
            +
                    when "PRIMARY KEY"; MetaDb::PrimaryKeyConstraint.init(row)
         
     | 
| 
      
 125 
     | 
    
         
            +
                    when "UNIQUE"; MetaDb::UniqueConstraint.init(row)
         
     | 
| 
      
 126 
     | 
    
         
            +
                    when "CHECK"; MetaDb::CheckConstraint.init(row)
         
     | 
| 
      
 127 
     | 
    
         
            +
                  else
         
     | 
| 
      
 128 
     | 
    
         
            +
                    raise "Oops"
         
     | 
| 
      
 129 
     | 
    
         
            +
                  end
         
     | 
| 
      
 130 
     | 
    
         
            +
                }
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                # Build referential constraints
         
     | 
| 
      
 133 
     | 
    
         
            +
                #
         
     | 
| 
      
 134 
     | 
    
         
            +
                # Referential constraints has to be initialized after unique constraints
         
     | 
| 
      
 135 
     | 
    
         
            +
                #
         
     | 
| 
      
 136 
     | 
    
         
            +
                # The GROUP BY is necessary because we re-assign constraints from schema to
         
     | 
| 
      
 137 
     | 
    
         
            +
                # table. This requires joining key_column_usage again to get the name of
         
     | 
| 
      
 138 
     | 
    
         
            +
                # the referenced table and that yields a row for each column in the unique
         
     | 
| 
      
 139 
     | 
    
         
            +
                # key (TODO: Can this be omitted?)
         
     | 
| 
      
 140 
     | 
    
         
            +
                #
         
     | 
| 
      
 141 
     | 
    
         
            +
                conn.select(%(
         
     | 
| 
      
 142 
     | 
    
         
            +
                  select  rc.constraint_schema::varchar as schema,
         
     | 
| 
      
 143 
     | 
    
         
            +
                          rc.constraint_name::varchar as name,
         
     | 
| 
      
 144 
     | 
    
         
            +
                          cu_refing.table_schema || '.' || cu_refing.table_name as "referencing_table",
         
     | 
| 
      
 145 
     | 
    
         
            +
                          (
         
     | 
| 
      
 146 
     | 
    
         
            +
                            select  array_agg(column_name::varchar order by ordinal_position)
         
     | 
| 
      
 147 
     | 
    
         
            +
                            from    information_schema.key_column_usage kcu
         
     | 
| 
      
 148 
     | 
    
         
            +
                            where   kcu.constraint_name = rc.constraint_name
         
     | 
| 
      
 149 
     | 
    
         
            +
                          ) as "referencing_columns",
         
     | 
| 
      
 150 
     | 
    
         
            +
                          cu_refed.table_schema || '.' || cu_refed.table_name || '.' || cu_refed.constraint_name 
         
     | 
| 
      
 151 
     | 
    
         
            +
                              as "referenced_constraint"
         
     | 
| 
      
 152 
     | 
    
         
            +
                  from    information_schema.referential_constraints rc
         
     | 
| 
      
 153 
     | 
    
         
            +
                  join    information_schema.key_column_usage cu_refing on 
         
     | 
| 
      
 154 
     | 
    
         
            +
                              cu_refing.constraint_schema = rc.constraint_schema
         
     | 
| 
      
 155 
     | 
    
         
            +
                              and cu_refing.constraint_name = rc.constraint_name
         
     | 
| 
      
 156 
     | 
    
         
            +
                  join    information_schema.key_column_usage cu_refed on 
         
     | 
| 
      
 157 
     | 
    
         
            +
                              cu_refed.constraint_schema = rc.unique_constraint_schema
         
     | 
| 
      
 158 
     | 
    
         
            +
                              and cu_refed.constraint_name = rc.unique_constraint_name
         
     | 
| 
      
 159 
     | 
    
         
            +
                  where   cu_refing.table_schema !~ '^pg_' AND cu_refing.table_schema <> 'information_schema'
         
     | 
| 
      
 160 
     | 
    
         
            +
                  group by
         
     | 
| 
      
 161 
     | 
    
         
            +
                          rc.constraint_schema,
         
     | 
| 
      
 162 
     | 
    
         
            +
                          rc.constraint_name,
         
     | 
| 
      
 163 
     | 
    
         
            +
                          cu_refing.table_schema,
         
     | 
| 
      
 164 
     | 
    
         
            +
                          cu_refing.table_name,
         
     | 
| 
      
 165 
     | 
    
         
            +
                          cu_refed.table_schema,
         
     | 
| 
      
 166 
     | 
    
         
            +
                          cu_refed.table_name,
         
     | 
| 
      
 167 
     | 
    
         
            +
                          cu_refed.constraint_name
         
     | 
| 
      
 168 
     | 
    
         
            +
                )).each_hash { |row|
         
     | 
| 
      
 169 
     | 
    
         
            +
                  row[:schema] = db.dot row[:schema]
         
     | 
| 
      
 170 
     | 
    
         
            +
                  row[:referencing_table] = db.dot row[:referencing_table]
         
     | 
| 
      
 171 
     | 
    
         
            +
                  row[:referencing_columns] = lookup_columns(row[:referencing_table], row[:referencing_columns])
         
     | 
| 
      
 172 
     | 
    
         
            +
                  row[:referenced_constraint] = db.dot row[:referenced_constraint]
         
     | 
| 
      
 173 
     | 
    
         
            +
                  MetaDb::ReferentialConstraint.init(row)
         
     | 
| 
      
 174 
     | 
    
         
            +
                }
         
     | 
| 
      
 175 
     | 
    
         
            +
                db
         
     | 
| 
      
 176 
     | 
    
         
            +
              end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
              def self.lookup_columns(table, column_names)
         
     | 
| 
      
 179 
     | 
    
         
            +
                column_names.map { |n| table.children[n] }
         
     | 
| 
      
 180 
     | 
    
         
            +
              end
         
     | 
| 
      
 181 
     | 
    
         
            +
            end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,97 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            module MetaDb
         
     | 
| 
      
 3 
     | 
    
         
            +
              class Connection
         
     | 
| 
      
 4 
     | 
    
         
            +
                # In derived classes, no initialization may take place after the call to
         
     | 
| 
      
 5 
     | 
    
         
            +
                # super because otherwise #initialize would call the user-supplied block
         
     | 
| 
      
 6 
     | 
    
         
            +
                # with a partial initialized object
         
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(options)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @conn = self.class.connect(options)
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def self.open(options, &block)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  if block_given?
         
     | 
| 
      
 13 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 14 
     | 
    
         
            +
                      conn = self.new(options)
         
     | 
| 
      
 15 
     | 
    
         
            +
                      return yield(conn)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    ensure
         
     | 
| 
      
 17 
     | 
    
         
            +
                      conn&.close
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  else
         
     | 
| 
      
 20 
     | 
    
         
            +
                    self.new(options)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def host() raise end
         
     | 
| 
      
 25 
     | 
    
         
            +
                def port() raise end
         
     | 
| 
      
 26 
     | 
    
         
            +
                def database() raise end
         
     | 
| 
      
 27 
     | 
    
         
            +
                def user() raise end
         
     | 
| 
      
 28 
     | 
    
         
            +
                def password() raise end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                # Escapes s as a SQL string value
         
     | 
| 
      
 31 
     | 
    
         
            +
                def escape(s) raise end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def execute(sql) raise end
         
     | 
| 
      
 34 
     | 
    
         
            +
                def select(sql, &block) raise end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def close() raise end
         
     | 
| 
      
 37 
     | 
    
         
            +
                def closed?() raise end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              private
         
     | 
| 
      
 40 
     | 
    
         
            +
                def self.connect(options) raise end
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              class Result
         
     | 
| 
      
 44 
     | 
    
         
            +
                def initialize(result) @result = result end
         
     | 
| 
      
 45 
     | 
    
         
            +
                def size() raise end
         
     | 
| 
      
 46 
     | 
    
         
            +
                def each_hash() raise end
         
     | 
| 
      
 47 
     | 
    
         
            +
                def each_array() raise end
         
     | 
| 
      
 48 
     | 
    
         
            +
                def to_a() each_array end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              class PostgresResult < Result
         
     | 
| 
      
 52 
     | 
    
         
            +
                def size()
         
     | 
| 
      
 53 
     | 
    
         
            +
                  @result.ntuples
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def each_hash(&block) 
         
     | 
| 
      
 57 
     | 
    
         
            +
                  if block_given?
         
     | 
| 
      
 58 
     | 
    
         
            +
                    each_hash.each(&block)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  else
         
     | 
| 
      
 60 
     | 
    
         
            +
                    @result.map { |row| row.map { |field, value| [field.to_sym, value] }.to_h }
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                def each_array(&block)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  if block_given?
         
     | 
| 
      
 66 
     | 
    
         
            +
                    each_array.each(&block)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  else
         
     | 
| 
      
 68 
     | 
    
         
            +
                    @result.each_row
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                def to_a() @result.values end
         
     | 
| 
      
 73 
     | 
    
         
            +
              end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
              class PostgresConnection < Connection
         
     | 
| 
      
 76 
     | 
    
         
            +
                def host() @conn.host end
         
     | 
| 
      
 77 
     | 
    
         
            +
                def port() @conn.port end
         
     | 
| 
      
 78 
     | 
    
         
            +
                def database() @conn.db end
         
     | 
| 
      
 79 
     | 
    
         
            +
                def user() @conn.user end
         
     | 
| 
      
 80 
     | 
    
         
            +
                def password() @conn.pass end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                def escape(s) @conn.escape_string(s) end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                def execute(sql) @conn.exec(sql) end
         
     | 
| 
      
 85 
     | 
    
         
            +
                def select(sql) PostgresResult.new(@conn.exec(sql)) end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                def close() @conn.finish end
         
     | 
| 
      
 88 
     | 
    
         
            +
                def closed?() @conn.finished? end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
              private
         
     | 
| 
      
 91 
     | 
    
         
            +
                def self.connect(options) 
         
     | 
| 
      
 92 
     | 
    
         
            +
                  conn = PG::Connection.new(options) 
         
     | 
| 
      
 93 
     | 
    
         
            +
                  conn.type_map_for_results = PG::BasicTypeMapForResults.new conn
         
     | 
| 
      
 94 
     | 
    
         
            +
                  conn
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
              end
         
     | 
| 
      
 97 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,352 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            require 'meta_db/dump.rb'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module MetaDb
         
     | 
| 
      
 5 
     | 
    
         
            +
              class DbObject
         
     | 
| 
      
 6 
     | 
    
         
            +
                # Used to multi-assign values and for dump
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                # TODO: rename db_attr or 'column', and create read/writer methods
         
     | 
| 
      
 9 
     | 
    
         
            +
                def self.attrs(*attrs)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  attrs = Array(attrs)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  if attrs.empty?
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @attrs
         
     | 
| 
      
 13 
     | 
    
         
            +
                  else
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @attrs = attrs
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def self.init(row)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  h = []
         
     | 
| 
      
 20 
     | 
    
         
            +
                  self.attrs.each { |a| h << row[a] if row.key?(a) }
         
     | 
| 
      
 21 
     | 
    
         
            +
                  self.new(*h)
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                attrs :parent, :name, :children
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                # Name of object. Unique within contianing object. Not nil
         
     | 
| 
      
 27 
     | 
    
         
            +
                attr_reader :name 
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                # Parent DbObject. Non-nil except for the top-level MetaDb::Database object
         
     | 
| 
      
 30 
     | 
    
         
            +
                attr_reader :parent
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                # Hash from name to contained objects
         
     | 
| 
      
 33 
     | 
    
         
            +
                attr_reader :children
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def initialize(parent, name)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @name, @parent = name, parent
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @children = {}
         
     | 
| 
      
 38 
     | 
    
         
            +
                  parent&.send(:attach, self)
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                # Unique dot-separated list of names leading from the top-level MetaDb::Database object to 
         
     | 
| 
      
 42 
     | 
    
         
            +
                # self. Omits the first path-element if strip is true
         
     | 
| 
      
 43 
     | 
    
         
            +
                def path(strip: false)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  r = []
         
     | 
| 
      
 45 
     | 
    
         
            +
                  node = self
         
     | 
| 
      
 46 
     | 
    
         
            +
                  while node
         
     | 
| 
      
 47 
     | 
    
         
            +
                    r << node.name
         
     | 
| 
      
 48 
     | 
    
         
            +
                    node = node.parent
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                  r.pop if strip
         
     | 
| 
      
 51 
     | 
    
         
            +
                  r.reverse.compact.join(".")
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                # Return child object with the given name
         
     | 
| 
      
 55 
     | 
    
         
            +
                def [](name) @children[name] end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                # Recursively lookup object by dot-separated list of names. If strip is true, the first element
         
     | 
| 
      
 58 
     | 
    
         
            +
                # will be stripped from the path
         
     | 
| 
      
 59 
     | 
    
         
            +
                def dot(path, strip: false)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  elems = path.split(".")
         
     | 
| 
      
 61 
     | 
    
         
            +
                  elems.shift if strip
         
     | 
| 
      
 62 
     | 
    
         
            +
                  elems.inject(self) { |a,e| a[e] } or raise "Can't lookup '#{path}' in #{self.path}"
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                # Compare two objects by identity
         
     | 
| 
      
 66 
     | 
    
         
            +
                def <=>(r) path <=> r.path end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                # Mostly for debug
         
     | 
| 
      
 69 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 70 
     | 
    
         
            +
                  string = StringIO.new
         
     | 
| 
      
 71 
     | 
    
         
            +
                  stdout = $stdout
         
     | 
| 
      
 72 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 73 
     | 
    
         
            +
                    $stdout = string
         
     | 
| 
      
 74 
     | 
    
         
            +
                    dump
         
     | 
| 
      
 75 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 76 
     | 
    
         
            +
                    $stdout = stdout
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                  string.string
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              protected
         
     | 
| 
      
 82 
     | 
    
         
            +
                def constrain_children(klass)
         
     | 
| 
      
 83 
     | 
    
         
            +
                  children.values.select { |v| v.is_a?(klass) }
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
              private
         
     | 
| 
      
 87 
     | 
    
         
            +
                def attach(child)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  !@children.key?(child.name) or raise "Duplicate child key: #{child.name.inspect}"
         
     | 
| 
      
 89 
     | 
    
         
            +
                  child.instance_variable_set(:@parent, self)
         
     | 
| 
      
 90 
     | 
    
         
            +
                  @children[child.name] = child
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                def detach(child)
         
     | 
| 
      
 94 
     | 
    
         
            +
                  @children.key?(child.name) or raise "Non-existing child key: #{child.name.inspect}"
         
     | 
| 
      
 95 
     | 
    
         
            +
                  child.instance_variable_set(:@parent, nil)
         
     | 
| 
      
 96 
     | 
    
         
            +
                  @children.delete(child.name)
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
              class Database < DbObject
         
     | 
| 
      
 101 
     | 
    
         
            +
                attrs :name, :owner, :schemas
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                # List of schemas
         
     | 
| 
      
 104 
     | 
    
         
            +
                def schemas()
         
     | 
| 
      
 105 
     | 
    
         
            +
                  @schemas ||= children.values
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                # Owner of the database
         
     | 
| 
      
 109 
     | 
    
         
            +
                attr_reader :owner
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                def initialize(name, owner)
         
     | 
| 
      
 112 
     | 
    
         
            +
                  super(nil, name)
         
     | 
| 
      
 113 
     | 
    
         
            +
                  @owner = owner
         
     | 
| 
      
 114 
     | 
    
         
            +
                end
         
     | 
| 
      
 115 
     | 
    
         
            +
              end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
              class Schema < DbObject
         
     | 
| 
      
 118 
     | 
    
         
            +
                attrs :database, :name, :owner, :tables, :views, :functions, :procedures
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                # Database of the schema
         
     | 
| 
      
 121 
     | 
    
         
            +
                alias_method :database, :parent
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                # Owner of the schema
         
     | 
| 
      
 124 
     | 
    
         
            +
                attr_reader :owner
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                # List of tables (and views)
         
     | 
| 
      
 127 
     | 
    
         
            +
                def tables() @tables ||= constrain_children(MetaDb::Table) end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                # List of views
         
     | 
| 
      
 130 
     | 
    
         
            +
                def views() @views ||= constrain_children(MetaDb::View) end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                # List of functions
         
     | 
| 
      
 133 
     | 
    
         
            +
                def functions() @functions ||= constrain_children(MetaDb::Function) end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                # List of procedures
         
     | 
| 
      
 136 
     | 
    
         
            +
                def procedures() @procedures ||= constrain_children(MetaDb::Procedure) end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                def initialize(database, name, owner)
         
     | 
| 
      
 139 
     | 
    
         
            +
                  super(database, name)
         
     | 
| 
      
 140 
     | 
    
         
            +
                  @owner = owner
         
     | 
| 
      
 141 
     | 
    
         
            +
                end
         
     | 
| 
      
 142 
     | 
    
         
            +
              end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
              class Table < DbObject
         
     | 
| 
      
 145 
     | 
    
         
            +
                attrs \
         
     | 
| 
      
 146 
     | 
    
         
            +
                  :schema, :name, :type, :table?, :view?, :insertable?, :typed?, :columns,
         
     | 
| 
      
 147 
     | 
    
         
            +
                  :primary_key_columns, :constraints, :referential_constraints, :triggers
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                # Schema of the table. Redefines #parent
         
     | 
| 
      
 150 
     | 
    
         
            +
                alias_method :schema, :parent
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                # Type of table. Either 'BASE TABLE' or 'VIEW'
         
     | 
| 
      
 153 
     | 
    
         
            +
                attr_reader :type
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                # True iff table is a real table and not a view
         
     | 
| 
      
 156 
     | 
    
         
            +
                def table?() true end
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                # True iff table is a view
         
     | 
| 
      
 159 
     | 
    
         
            +
                def view?() !table? end
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
                # True if the table/view is insertable
         
     | 
| 
      
 162 
     | 
    
         
            +
                def insertable?() @is_insertable end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                # True if the table/view is typed
         
     | 
| 
      
 165 
     | 
    
         
            +
                def typed?() @is_typed end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                # List of columns. Columns are sorted by ordinal
         
     | 
| 
      
 168 
     | 
    
         
            +
                def columns() @columns ||= constrain_children(MetaDb::Column).sort end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                # The primary key column. nil if the table has multiple primary key columns
         
     | 
| 
      
 171 
     | 
    
         
            +
                def primary_key_column
         
     | 
| 
      
 172 
     | 
    
         
            +
                  return @primary_key_column if @primary_key_column != :undefined
         
     | 
| 
      
 173 
     | 
    
         
            +
                  if primary_key_columns.size == 1
         
     | 
| 
      
 174 
     | 
    
         
            +
                    @primary_key_column = primary_key_columns.first
         
     | 
| 
      
 175 
     | 
    
         
            +
                  else
         
     | 
| 
      
 176 
     | 
    
         
            +
                    @primary_key_column = nil
         
     | 
| 
      
 177 
     | 
    
         
            +
                  end
         
     | 
| 
      
 178 
     | 
    
         
            +
                end
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                # List of primary key columns
         
     | 
| 
      
 181 
     | 
    
         
            +
                #
         
     | 
| 
      
 182 
     | 
    
         
            +
                # Note: Assigned by PrimaryKeyConstraint#initialize
         
     | 
| 
      
 183 
     | 
    
         
            +
                attr_reader :primary_key_columns
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                # List of constraints
         
     | 
| 
      
 186 
     | 
    
         
            +
                def constraints() 
         
     | 
| 
      
 187 
     | 
    
         
            +
                  @constraints ||= constrain_children(MetaDb::Constraint) 
         
     | 
| 
      
 188 
     | 
    
         
            +
                end
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                # List of referential constraints
         
     | 
| 
      
 191 
     | 
    
         
            +
                def referential_constraints() 
         
     | 
| 
      
 192 
     | 
    
         
            +
                  @referential_constraints ||= constrain_children(MetaDb::ReferentialConstraint) 
         
     | 
| 
      
 193 
     | 
    
         
            +
                end
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
      
 195 
     | 
    
         
            +
                # List of triggers
         
     | 
| 
      
 196 
     | 
    
         
            +
                def triggers() @triggers ||= constrain_children(MetaDb::Trigger) end
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                def initialize(schema, name, type, is_insertable, is_typed)
         
     | 
| 
      
 199 
     | 
    
         
            +
                  super(schema, name)
         
     | 
| 
      
 200 
     | 
    
         
            +
                  @type, @is_insertable, @is_typed = type, is_insertable, is_typed
         
     | 
| 
      
 201 
     | 
    
         
            +
                  @primary_key_column = :undefined
         
     | 
| 
      
 202 
     | 
    
         
            +
                  @primary_key_columns = []
         
     | 
| 
      
 203 
     | 
    
         
            +
                end
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
              end
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
              class View < Table
         
     | 
| 
      
 208 
     | 
    
         
            +
                def table?() false end
         
     | 
| 
      
 209 
     | 
    
         
            +
              end
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
              class Column < DbObject
         
     | 
| 
      
 212 
     | 
    
         
            +
                attrs \
         
     | 
| 
      
 213 
     | 
    
         
            +
                  :table, :ordinal, :name, :type, :default, :identity?, :generated?,
         
     | 
| 
      
 214 
     | 
    
         
            +
                  :nullable?, :updatable?, :primary_key?
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
                # Table of the column
         
     | 
| 
      
 217 
     | 
    
         
            +
                alias_method :table, :parent
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
                # Ordinal number of the column
         
     | 
| 
      
 220 
     | 
    
         
            +
                attr_reader :ordinal
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
                # Type of the column
         
     | 
| 
      
 223 
     | 
    
         
            +
                attr_reader :type
         
     | 
| 
      
 224 
     | 
    
         
            +
             
     | 
| 
      
 225 
     | 
    
         
            +
                # Default value
         
     | 
| 
      
 226 
     | 
    
         
            +
                attr_reader :default
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
                # True if column is an identity column
         
     | 
| 
      
 229 
     | 
    
         
            +
                def identity?() @is_identity end
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
                # True if column is auto generated
         
     | 
| 
      
 232 
     | 
    
         
            +
                def generated?() @is_generated end
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                # True if column is nullable
         
     | 
| 
      
 235 
     | 
    
         
            +
                def nullable?() @is_nullable end
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
                # True if column is updatable
         
     | 
| 
      
 238 
     | 
    
         
            +
                def updatable?() @is_updatable end
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
                # True if column is the single primary key of the table. Always false for tables
         
     | 
| 
      
 241 
     | 
    
         
            +
                # with multiple primary keys
         
     | 
| 
      
 242 
     | 
    
         
            +
                def primary_key?() table.table? && self == table.primary_key_column end
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
                # True is column is (part of) the primary key of the table
         
     | 
| 
      
 245 
     | 
    
         
            +
                def primary_key_column?() table.table? && table.primary_key_columns.include?(self) end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
                def initialize(table, ordinal, name, type, default, is_identity, is_generated, is_nullable, is_updatable)
         
     | 
| 
      
 248 
     | 
    
         
            +
                  super(table, name)
         
     | 
| 
      
 249 
     | 
    
         
            +
                  @type, @ordinal, @default, @is_identity, @is_generated, @is_nullable, @is_updatable =
         
     | 
| 
      
 250 
     | 
    
         
            +
                      type, ordinal, default, is_identity, is_generated, is_nullable, is_updatable
         
     | 
| 
      
 251 
     | 
    
         
            +
                end
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
                # Compare columns by table and ordinal
         
     | 
| 
      
 254 
     | 
    
         
            +
                def <=>(other)
         
     | 
| 
      
 255 
     | 
    
         
            +
                  if other.is_a?(Column) && table == other.table
         
     | 
| 
      
 256 
     | 
    
         
            +
                    ordinal <=> other.ordinal
         
     | 
| 
      
 257 
     | 
    
         
            +
                  else
         
     | 
| 
      
 258 
     | 
    
         
            +
                    super
         
     | 
| 
      
 259 
     | 
    
         
            +
                  end
         
     | 
| 
      
 260 
     | 
    
         
            +
                end
         
     | 
| 
      
 261 
     | 
    
         
            +
              end
         
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
      
 263 
     | 
    
         
            +
              class Constraint < DbObject
         
     | 
| 
      
 264 
     | 
    
         
            +
                attrs :table, :name, :columns
         
     | 
| 
      
 265 
     | 
    
         
            +
             
     | 
| 
      
 266 
     | 
    
         
            +
                # Table of the constraint
         
     | 
| 
      
 267 
     | 
    
         
            +
                alias_method :table, :parent
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
                # List of columns in the constraint. Empty for CheckConstraint objects
         
     | 
| 
      
 270 
     | 
    
         
            +
                attr_reader :columns
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
                # Constraint kind. Either :primary_key, :foreign_key, :unique, or :check
         
     | 
| 
      
 273 
     | 
    
         
            +
                def kind() CONSTRAINT_KINDS[self.class] end
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
                def initialize(table, name, columns)
         
     | 
| 
      
 276 
     | 
    
         
            +
                  super(table, name)
         
     | 
| 
      
 277 
     | 
    
         
            +
                  @columns = columns
         
     | 
| 
      
 278 
     | 
    
         
            +
                end
         
     | 
| 
      
 279 
     | 
    
         
            +
              end
         
     | 
| 
      
 280 
     | 
    
         
            +
             
     | 
| 
      
 281 
     | 
    
         
            +
              class PrimaryKeyConstraint < Constraint
         
     | 
| 
      
 282 
     | 
    
         
            +
                attrs :table, :name, :columns
         
     | 
| 
      
 283 
     | 
    
         
            +
             
     | 
| 
      
 284 
     | 
    
         
            +
                def initialize(table, name, columns)
         
     | 
| 
      
 285 
     | 
    
         
            +
                  super
         
     | 
| 
      
 286 
     | 
    
         
            +
                  columns.each { |c| c.table.primary_key_columns << c }
         
     | 
| 
      
 287 
     | 
    
         
            +
                end
         
     | 
| 
      
 288 
     | 
    
         
            +
              end
         
     | 
| 
      
 289 
     | 
    
         
            +
             
     | 
| 
      
 290 
     | 
    
         
            +
              class UniqueConstraint < Constraint
         
     | 
| 
      
 291 
     | 
    
         
            +
                attrs :table, :name, :columns
         
     | 
| 
      
 292 
     | 
    
         
            +
              end
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
              # Note that #columns is always empty for check constraints
         
     | 
| 
      
 295 
     | 
    
         
            +
              class CheckConstraint < Constraint
         
     | 
| 
      
 296 
     | 
    
         
            +
                attrs :table, :name, :expression
         
     | 
| 
      
 297 
     | 
    
         
            +
             
     | 
| 
      
 298 
     | 
    
         
            +
                # SQL check expression
         
     | 
| 
      
 299 
     | 
    
         
            +
                attr_reader :expression
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
      
 301 
     | 
    
         
            +
                # Half-baked SQL-to-ruby expression transpiler
         
     | 
| 
      
 302 
     | 
    
         
            +
                def ruby_expression # Very simple
         
     | 
| 
      
 303 
     | 
    
         
            +
                  @ruby ||= sql.sub(/\((.*)\)/, "\\1").gsub(/\((\w+) IS NOT NULL\)/, "!\\1.nil?").gsub(/ OR /, " || ")
         
     | 
| 
      
 304 
     | 
    
         
            +
                end
         
     | 
| 
      
 305 
     | 
    
         
            +
             
     | 
| 
      
 306 
     | 
    
         
            +
                def initialize(table, name, expression)
         
     | 
| 
      
 307 
     | 
    
         
            +
                  super(table, name, [])
         
     | 
| 
      
 308 
     | 
    
         
            +
                  @expression = expression
         
     | 
| 
      
 309 
     | 
    
         
            +
                end
         
     | 
| 
      
 310 
     | 
    
         
            +
              end
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
              class ReferentialConstraint < Constraint
         
     | 
| 
      
 313 
     | 
    
         
            +
                attrs :referencing_table, :name, :referencing_columns, :referenced_constraint
         
     | 
| 
      
 314 
     | 
    
         
            +
             
     | 
| 
      
 315 
     | 
    
         
            +
                # The referencing tabla
         
     | 
| 
      
 316 
     | 
    
         
            +
                alias_method :referencing_table, :table
         
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
      
 318 
     | 
    
         
            +
                # The referencing columns. Can't be empty
         
     | 
| 
      
 319 
     | 
    
         
            +
                alias_method :referencing_columns, :columns
         
     | 
| 
      
 320 
     | 
    
         
            +
             
     | 
| 
      
 321 
     | 
    
         
            +
                # The referenced constraint
         
     | 
| 
      
 322 
     | 
    
         
            +
                attr_reader :referenced_constraint
         
     | 
| 
      
 323 
     | 
    
         
            +
             
     | 
| 
      
 324 
     | 
    
         
            +
                # The referenced table
         
     | 
| 
      
 325 
     | 
    
         
            +
                def referenced_table() referenced_constraint.table end
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
                # The referenced columns
         
     | 
| 
      
 328 
     | 
    
         
            +
                def referenced_columns() referenced_constraints.columns end
         
     | 
| 
      
 329 
     | 
    
         
            +
             
     | 
| 
      
 330 
     | 
    
         
            +
                def initialize(referencing_table, name, referencing_columns, referenced_constraint)
         
     | 
| 
      
 331 
     | 
    
         
            +
                  super(referencing_table, name, referencing_columns)
         
     | 
| 
      
 332 
     | 
    
         
            +
                  @referenced_constraint = referenced_constraint
         
     | 
| 
      
 333 
     | 
    
         
            +
                end
         
     | 
| 
      
 334 
     | 
    
         
            +
              end
         
     | 
| 
      
 335 
     | 
    
         
            +
             
     | 
| 
      
 336 
     | 
    
         
            +
              class Function < DbObject
         
     | 
| 
      
 337 
     | 
    
         
            +
              end
         
     | 
| 
      
 338 
     | 
    
         
            +
             
     | 
| 
      
 339 
     | 
    
         
            +
              class Procedure < DbObject
         
     | 
| 
      
 340 
     | 
    
         
            +
              end
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
      
 342 
     | 
    
         
            +
              class Trigger < DbObject
         
     | 
| 
      
 343 
     | 
    
         
            +
              end
         
     | 
| 
      
 344 
     | 
    
         
            +
             
     | 
| 
      
 345 
     | 
    
         
            +
              CONSTRAINT_KINDS = {
         
     | 
| 
      
 346 
     | 
    
         
            +
                PrimaryKeyConstraint => :primary_key,
         
     | 
| 
      
 347 
     | 
    
         
            +
                ReferentialConstraint => :foreign_key,
         
     | 
| 
      
 348 
     | 
    
         
            +
                UniqueConstraint => :unique,
         
     | 
| 
      
 349 
     | 
    
         
            +
                CheckConstraint => :check
         
     | 
| 
      
 350 
     | 
    
         
            +
              }
         
     | 
| 
      
 351 
     | 
    
         
            +
            end
         
     | 
| 
      
 352 
     | 
    
         
            +
             
     | 
    
        data/lib/meta_db/dump.rb
    ADDED
    
    | 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            require 'indented_io'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module MetaDb
         
     | 
| 
      
 5 
     | 
    
         
            +
              class DbObject
         
     | 
| 
      
 6 
     | 
    
         
            +
                def dump
         
     | 
| 
      
 7 
     | 
    
         
            +
                  puts self.class.to_s
         
     | 
| 
      
 8 
     | 
    
         
            +
                  dump_attrs
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
                
         
     | 
| 
      
 11 
     | 
    
         
            +
                def dump_attrs(*attrs)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  attrs = Array(attrs)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  attrs = self.class.attrs if attrs.empty?
         
     | 
| 
      
 14 
     | 
    
         
            +
                  indent {
         
     | 
| 
      
 15 
     | 
    
         
            +
                    for attr in Array(attrs)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      value = self.send(attr)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      case value
         
     | 
| 
      
 18 
     | 
    
         
            +
                        when Array
         
     | 
| 
      
 19 
     | 
    
         
            +
                          puts "#{attr}:"
         
     | 
| 
      
 20 
     | 
    
         
            +
                          indent { value.each { |v| v.dump } }
         
     | 
| 
      
 21 
     | 
    
         
            +
                        when DbObject
         
     | 
| 
      
 22 
     | 
    
         
            +
                          puts "#{attr}: #{value.name} (#{value.class})"
         
     | 
| 
      
 23 
     | 
    
         
            +
                      else
         
     | 
| 
      
 24 
     | 
    
         
            +
                        puts "#{attr}: #{self.send(attr).inspect}"
         
     | 
| 
      
 25 
     | 
    
         
            +
                      end
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  }
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
    
        data/meta_db.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            lib = File.expand_path("../lib", __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "meta_db/version"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.name          = "meta_db"
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.version       = MetaDb::VERSION
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.authors       = ["Claus Rasmussen"]
         
     | 
| 
      
 10 
     | 
    
         
            +
              spec.email         = ["claus.l.rasmussen@gmail.com"]
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              spec.summary       = %q{Meta model of database}
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.description   = %q{Reads in the information schema of a database and models it as ruby objects}
         
     | 
| 
      
 14 
     | 
    
         
            +
              spec.homepage      = "http://www.nowhere.com/meta_db"
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
         
     | 
| 
      
 17 
     | 
    
         
            +
              # to allow pushing to a single host or delete this section to allow pushing to any host.
         
     | 
| 
      
 18 
     | 
    
         
            +
              if spec.respond_to?(:metadata)
         
     | 
| 
      
 19 
     | 
    
         
            +
                spec.metadata["allowed_push_host"] = "https://rubygems.org"
         
     | 
| 
      
 20 
     | 
    
         
            +
              else
         
     | 
| 
      
 21 
     | 
    
         
            +
                raise "RubyGems 2.0 or newer is required to protect against " \
         
     | 
| 
      
 22 
     | 
    
         
            +
                  "public gem pushes."
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              # Specify which files should be added to the gem when it is released.
         
     | 
| 
      
 26 
     | 
    
         
            +
              # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
         
     | 
| 
      
 27 
     | 
    
         
            +
              spec.files         = Dir.chdir(File.expand_path('..', __FILE__)) do
         
     | 
| 
      
 28 
     | 
    
         
            +
                `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
              spec.bindir        = "exe"
         
     | 
| 
      
 31 
     | 
    
         
            +
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         
     | 
| 
      
 32 
     | 
    
         
            +
              spec.require_paths = ["lib"]
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              spec.add_development_dependency "bundler", "~> 1.16"
         
     | 
| 
      
 35 
     | 
    
         
            +
              spec.add_development_dependency "rake", "~> 10.0"
         
     | 
| 
      
 36 
     | 
    
         
            +
              spec.add_development_dependency "rspec", "~> 3.0"
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              spec.add_dependency "indented_io"
         
     | 
| 
      
 39 
     | 
    
         
            +
              spec.add_dependency "pg"
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,129 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: meta_db
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.0
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Claus Rasmussen
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: exe
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2020-07-05 00:00:00.000000000 Z
         
     | 
| 
      
 12 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 13 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 14 
     | 
    
         
            +
              name: bundler
         
     | 
| 
      
 15 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 16 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 17 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 18 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 19 
     | 
    
         
            +
                    version: '1.16'
         
     | 
| 
      
 20 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 26 
     | 
    
         
            +
                    version: '1.16'
         
     | 
| 
      
 27 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 28 
     | 
    
         
            +
              name: rake
         
     | 
| 
      
 29 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 31 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 32 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: '10.0'
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 37 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 38 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 39 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 40 
     | 
    
         
            +
                    version: '10.0'
         
     | 
| 
      
 41 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 42 
     | 
    
         
            +
              name: rspec
         
     | 
| 
      
 43 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 44 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 45 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 46 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 47 
     | 
    
         
            +
                    version: '3.0'
         
     | 
| 
      
 48 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 49 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 50 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: '3.0'
         
     | 
| 
      
 55 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 56 
     | 
    
         
            +
              name: indented_io
         
     | 
| 
      
 57 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 58 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 59 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 60 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 61 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 62 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 63 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 64 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 65 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 66 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 67 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 68 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 69 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 70 
     | 
    
         
            +
              name: pg
         
     | 
| 
      
 71 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 72 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 73 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 74 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 75 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 76 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 77 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 78 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 79 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 80 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 81 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 82 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 83 
     | 
    
         
            +
            description: Reads in the information schema of a database and models it as ruby objects
         
     | 
| 
      
 84 
     | 
    
         
            +
            email:
         
     | 
| 
      
 85 
     | 
    
         
            +
            - claus.l.rasmussen@gmail.com
         
     | 
| 
      
 86 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 87 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 88 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 89 
     | 
    
         
            +
            files:
         
     | 
| 
      
 90 
     | 
    
         
            +
            - ".gitignore"
         
     | 
| 
      
 91 
     | 
    
         
            +
            - ".rspec"
         
     | 
| 
      
 92 
     | 
    
         
            +
            - ".ruby-version"
         
     | 
| 
      
 93 
     | 
    
         
            +
            - ".travis.yml"
         
     | 
| 
      
 94 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 95 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 96 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 97 
     | 
    
         
            +
            - TODO
         
     | 
| 
      
 98 
     | 
    
         
            +
            - bin/console
         
     | 
| 
      
 99 
     | 
    
         
            +
            - bin/setup
         
     | 
| 
      
 100 
     | 
    
         
            +
            - lib/meta_db.rb
         
     | 
| 
      
 101 
     | 
    
         
            +
            - lib/meta_db/connection.rb
         
     | 
| 
      
 102 
     | 
    
         
            +
            - lib/meta_db/db_object.rb
         
     | 
| 
      
 103 
     | 
    
         
            +
            - lib/meta_db/dump.rb
         
     | 
| 
      
 104 
     | 
    
         
            +
            - lib/meta_db/version.rb
         
     | 
| 
      
 105 
     | 
    
         
            +
            - meta_db.gemspec
         
     | 
| 
      
 106 
     | 
    
         
            +
            homepage: http://www.nowhere.com/meta_db
         
     | 
| 
      
 107 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 108 
     | 
    
         
            +
            metadata:
         
     | 
| 
      
 109 
     | 
    
         
            +
              allowed_push_host: https://rubygems.org
         
     | 
| 
      
 110 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 111 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 112 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 113 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 114 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 115 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 116 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 117 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 118 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 119 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 120 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 121 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 122 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 123 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 124 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 125 
     | 
    
         
            +
            rubygems_version: 3.0.8
         
     | 
| 
      
 126 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 127 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 128 
     | 
    
         
            +
            summary: Meta model of database
         
     | 
| 
      
 129 
     | 
    
         
            +
            test_files: []
         
     |