-
Notifications
You must be signed in to change notification settings - Fork 1
Schema analysis DSL
After applying the schema to your database DbSchema exposes it's current structure
as a DbSchema::Definitions::Schema
object at DbSchema.current_schema
.
schema = DbSchema.current_schema
This method does not query the database in any way, it just returns a pre-cached object.
DbSchema::Definitions::Schema
instance is a nested structure describing all tables, fields,
indexes, enum types etc; you can inspect them in various ways.
You can get a table definition with #table
:
schema.table(:users)
# or just
schema[:users]
If you just need to check if a given table is present you can use #has_table?
:
schema.has_table?(:users)
Table's #field
method returns a field definition:
schema.table(:users).field(:email)
# or
schema[:users][:email]
Fields have a set of attributes you can query:
field = schema.table(:users).field(:email)
field.name # this field's name
field.null? # is the field nullable (NOT NULL fields return false)
field.type # the field's type as a symbol
field.default # the field's default value
field.attributes # the field's type-specific attributes
#has_field?
can be used to check if a table has a given field:
schema.table(:users).has_field?(:email)
Index definition may be obtained with a Table#index
method and queried for their attributes:
index = schema.table(:users).index(:users_email_index)
index.name # name of the index (in case you wonder)
index.primary? # is the index a primary key
index.unique? # is the index unique
index.type # the type of this index as a symbol (:btree, :gist etc)
index.condition # condition of the index (if it is a partial index)
A special case is the primary key index; you can get it with Table#primary_key
:
pkey = schema.table(:users).primary_key
pkey.primary? # => true
There are several methods that check an index existance:
# check index by it's name
schema.table(:users).has_index?(:users_email_index)
# check if table has any index on given columns (exactly in that order)
schema.table(:users).has_index_on?(:email)
schema.table(:users).has_index_on?(:first_name, :last_name)
# check if table has a unique index on given columns
schema.table(:users).has_unique_index_on?(:first_name, :last_name)
# check if table has a primary key
schema.table(:users).has_primary_key?
#has_index_on?
and #has_unique_index_on?
only search for indexes on table
columns; they ignore expression indexes like lower(email)
.
Indexed columns and expressions can also be queried for their attributes:
index = schema.table(:users).index(:users_email_index)
index.columns.first.name # name of the field (e.g. :name) or full expression string (like "lower(email)")
index.columns.first.expression? # is it an expression
index.columns.first.asc? # is the column order ascending in the index
index.columns.first.desc? # is the column order descending in the index
Check constraints can be searched for with #check
:
check = schema.table(:users).check(:valid_age)
check.name # the name of the constraint
check.condition # the SQL condition string
As before, #has_check?
can be used to check if a check constraint with the
given name exists in that table.
Foreign key can be picked by it's name with #foreign_key
:
fkey = schema.table(:posts).foreign_key(:posts_user_id_fkey)
fkey.name # key's name
fkey.fields # array of fields in the key
fkey.table # name of the table referenced by the key
fkey.references_primary_key? # is the foreign key referencing a primary key
fkey.keys # array of the referenced columns (unless a primary key is referenced, in which case an empty array is returned)
fkey.on_update # action to make when referenced columns are updated
fkey.on_delete # action to make when referenced records are deleted
fkey.deferrable? # is the foreign key constraint deferrable
If you need to check if a table has a specific foreign key you have 2 options:
# check foreign key by name
schema.table(:posts).has_foreign_key?(:posts_user_id_fkey)
# check if a table is referencing another table with a foreign key
schema.table(:posts).has_foreign_key_to?(:users)
You can get the enum type information with Schema#enum
:
user_role = schema.enum(:user_role)
user_role.name # type's name
user_role.values # type's values (as an array of symbols)
This can be handy if you want to define model methods dynamically:
class User < SomeORM::BaseClass
class << self
def roles
DbSchema.current_schema.enum(:user_role).values
end
end
roles.each do |role|
define_method("#{role}?") do # def admin?
self.role == role # self.role == :admin
end # end
end
end
You can check if an enum type exists with #has_enum?
:
schema.has_enum?(:user_role)
Extensions don't have any attributes so you can only check if an extension is enabled:
schema.has_extension?(:hstore)
If methods like #table
or #field
can't find an object with a given
name in your schema they return a null object that has a fully compatible
interface with a usual object (e.g. NullTable
has the same methods as
a usual Table
) but it's methods return nil
s, empty structures
and other null objects so you can safely chain your method calls without
continuous nil-checking. This concerns #table
, #field
, #index
, #check
,
#foreign_key
, and #enum
methods.
schema.table(:users).field(:bar).name # => nil
schema.table(:foo).field(:bar).name # => nil
schema.table(:foo).index(:foo_bar_index).columns # => []
schema.enum(:baz).values # => []