-
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_schemaThis 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? # => trueThere 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 indexCheck 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 stringAs 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 deferrableIf 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
endYou 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 nils, 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 # => []