class ActiveRecord::ConnectionAdapters::PostgreSQLGeometryColumnDefinition

Constants

GEOMETRY_TYPES
SPATIAL_COLUMN_TYPES

Attributes

base[R]
column_name[R]
default[RW]
null[RW]
options[R]

Public Class Methods

new(base, column_name, opts) click to toggle source
Calls superclass method
# File lib/active_record/postgresql_extensions/geometry.rb, line 51
def initialize(base, column_name, opts)
  @base = base
  @column_name = column_name

  @options = {
    :spatial_column_type => :geometry,
    :geometry_type => :geometry,
    :add_constraints => true,
    :force_constraints => false,
    :add_geometry_columns_entry => true,
    :create_gist_index => true,
    :srid => ActiveRecord::PostgreSQLExtensions::PostGIS.UNKNOWN_SRID
  }.merge(opts)

  if options[:ndims].blank?
    options[:ndims] = if options[:geometry_type].to_s.upcase =~ /M$/
      3
    else
      2
    end
  end

  assert_valid_spatial_column_type(options[:spatial_column_type])
  assert_valid_geometry_type(options[:geometry_type])
  assert_valid_ndims(options[:ndims], options[:geometry_type])

  column_type = if ActiveRecord::PostgreSQLExtensions::PostGIS.VERSION[:lib] < '2.0'
    options[:spatial_column_type]
  else
    column_args = [ options[:geometry_type].to_s.upcase ]

    if ![ 0, -1 ].include?(options[:srid])
      column_args << options[:srid]
    end

    "#{options[:spatial_column_type]}(#{column_args.join(', ')})"
  end

  super(base, column_name, column_type)

  @default = options[:default]
  @null = options[:null]

  if options[:add_constraints] && (
    ActiveRecord::PostgreSQLExtensions::PostGIS.VERSION[:lib] < '2.0' ||
    options[:force_constraints]
  )
    table_constraints << PostgreSQLCheckConstraint.new(
      base,
      "ST_srid(#{base.quote_column_name(column_name)}) = (#{options[:srid].to_i})",
      :name => "enforce_srid_#{column_name}"
    )

    table_constraints << PostgreSQLCheckConstraint.new(
      base,
      "ST_ndims(#{base.quote_column_name(column_name)}) = #{options[:ndims].to_i}",
      :name => "enforce_dims_#{column_name}"
    )

    if options[:geometry_type].to_s.upcase != 'GEOMETRY'
      table_constraints << PostgreSQLCheckConstraint.new(
        base,
        "geometrytype(#{base.quote_column_name(column_name)}) = '#{options[:geometry_type].to_s.upcase}'::text OR #{base.quote_column_name(column_name)} IS NULL",
        :name => "enforce_geotype_#{column_name}"
      )
    end
  end
end

Public Instance Methods

geometry_column_index(table_name) click to toggle source
# File lib/active_record/postgresql_extensions/geometry.rb, line 150
def geometry_column_index(table_name)
  return [] unless options[:create_gist_index]

  current_scoped_schema, current_table_name = extract_schema_and_table_names(table_name)

  index_name = if options[:create_gist_index].is_a?(String)
    options[:create_gist_index]
  else
    "#{current_table_name}_#{column_name}_gist_index"
  end

  [
    PostgreSQLIndexDefinition.new(
      base,
      index_name,
      { current_scoped_schema => current_table_name },
      column_name,
      :using => :gist
    ).to_s
  ]
end
geometry_columns_entry(table_name) click to toggle source
# File lib/active_record/postgresql_extensions/geometry.rb, line 120
def geometry_columns_entry(table_name)
  return [] unless options[:add_geometry_columns_entry] &&
    options[:spatial_column_type].to_s != 'geography' &&
    ActiveRecord::PostgreSQLExtensions::PostGIS.VERSION[:lib] < '2.0'

  current_scoped_schema, current_table_name = extract_schema_and_table_names(table_name)

  [
    sprintf(
      "DELETE FROM \"geometry_columns\" WHERE f_table_catalog = '' AND " +
      "f_table_schema = %s AND " +
      "f_table_name = %s AND " +
      "f_geometry_column = %s;",
      base.quote(current_scoped_schema.to_s),
      base.quote(current_table_name.to_s),
      base.quote(column_name.to_s)
    ),

    sprintf(
      "INSERT INTO \"geometry_columns\" VALUES ('', %s, %s, %s, %d, %d, %s);",
      base.quote(current_scoped_schema.to_s),
      base.quote(current_table_name.to_s),
      base.quote(column_name.to_s),
      options[:ndims].to_i,
      options[:srid].to_i,
      base.quote(options[:geometry_type].to_s.upcase)
    )
  ]
end
table_constraints() click to toggle source
# File lib/active_record/postgresql_extensions/geometry.rb, line 181
def table_constraints
  @table_constraints ||= []
end
to_sql() click to toggle source
# File lib/active_record/postgresql_extensions/geometry.rb, line 172
def to_sql
  column_sql = "#{base.quote_column_name(name)} #{sql_type}"
  column_options = {}
  column_options[:null] = null unless null.nil?
  column_options[:default] = default unless default.nil?
  add_column_options!(column_sql, column_options) unless type.to_sym == :primary_key
  column_sql
end

Private Instance Methods

assert_valid_geometry_type(type) click to toggle source
# File lib/active_record/postgresql_extensions/geometry.rb, line 220
def assert_valid_geometry_type(type)
  if !GEOMETRY_TYPES.include?(type.to_s.upcase)
    raise ActiveRecord::InvalidGeometryType.new(type)
  end unless type.nil?
end
assert_valid_ndims(ndims, type) click to toggle source
# File lib/active_record/postgresql_extensions/geometry.rb, line 232
def assert_valid_ndims(ndims, type)
  if !ndims.blank?
    if type.to_s.upcase =~ /([A-Z]+M)$/ && ndims != 3
      raise ActiveRecord::InvalidGeometryDimensions.new("Invalid PostGIS geometry dimensions (#{$1} requires 3 dimensions)")
    elsif ndims < 0 || ndims > 4
      ralse ActiveRecord::InvalidGeometryDimensions.new("Invalid PostGIS geometry dimensions (should be between 0 and 4 inclusive) - #{ndims}")
    end
  end
end
assert_valid_spatial_column_type(type) click to toggle source
# File lib/active_record/postgresql_extensions/geometry.rb, line 226
def assert_valid_spatial_column_type(type)
  if !SPATIAL_COLUMN_TYPES.include?(type.to_s)
    raise ActiveRecord::InvalidSpatialColumnType.new(type)
  end unless type.nil?
end
extract_schema_and_table_names(table_name) click to toggle source
# File lib/active_record/postgresql_extensions/geometry.rb, line 242
def extract_schema_and_table_names(table_name)
  # We want to split up the schema and the table name for the
  # upcoming geometry_columns rows and GiST index.
  if table_name.is_a?(Hash)
    [ table_name.keys.first, table_name.values.first ]
  elsif base.current_scoped_schema
    [ base.current_scoped_schema, table_name ]
  else
    schema, table_name = base.extract_schema_and_table_names(table_name)
    [ schema || 'public', table_name ]
  end
end