lib/active_graph/model_schema.rb
require 'set'
module ActiveGraph
# This is here to support the removed functionality of being able to
# defined indexes and constraints on models
# This code should be removed later
module ModelSchema
MODEL_INDEXES = {}
MODEL_CONSTRAINTS = {}
REQUIRED_INDEXES = {}
class << self
def add_defined_constraint(model, property_name)
MODEL_CONSTRAINTS[model] ||= Set.new
MODEL_CONSTRAINTS[model] << property_name.to_sym
end
def add_defined_index(model, property_name)
MODEL_INDEXES[model] ||= Set.new
MODEL_INDEXES[model] << property_name.to_sym
end
def add_required_index(model, property_name)
REQUIRED_INDEXES[model] ||= Set.new
REQUIRED_INDEXES[model] << property_name.to_sym
end
def defined_constraint?(model, property_name)
MODEL_CONSTRAINTS[model] &&
MODEL_CONSTRAINTS[model].include?(property_name.to_sym)
end
def model_constraints
return @model_constraints if @model_constraints
constraints = ActiveGraph::Base.constraints.each_with_object({}) do |row, result|
result[row[:label]] ||= []
result[row[:label]] << row[:properties]
end
@model_constraints = schema_elements_list(MODEL_CONSTRAINTS, constraints)
end
def model_indexes
return @model_indexes if @model_indexes
indexes = ActiveGraph::Base.indexes.each_with_object({}) do |row, result|
result[row[:label]] ||= []
result[row[:label]] << row[:properties]
end
@model_indexes = schema_elements_list(MODEL_INDEXES, indexes) +
schema_elements_list(REQUIRED_INDEXES, indexes).reject(&:last)
# reject required indexes which are already in the DB
end
# should be private
def schema_elements_list(by_model, db_results)
by_model.flat_map do |model, property_names|
label = model.mapped_label_name.to_sym
property_names.map do |property_name|
exists = db_results[label] && db_results[label].include?([property_name])
[model, label, property_name, exists]
end
end
end
def ensure_model_data_state!
# If we load a new model, reset everything
if @previously_loaded_models_count != ActiveGraph::Node.loaded_classes.size
# Make sure we've finalized id_property details and have called
# add_ constraint/index methods above
ActiveGraph::Node.loaded_classes.each(&:ensure_id_property_info!)
reload_models_data!
end
end
def reload_models_data!
@previously_loaded_models_count = ActiveGraph::Node.loaded_classes.size
@model_indexes = @model_constraints = nil
end
def legacy_model_schema_informations
ensure_model_data_state!
data = {index: [], constraint: []}
each_schema_element do |type, model, label, property_name|
data[type] << {label: label, property_name: property_name, model: model}
end
data
end
def validate_model_schema!
ensure_model_data_state!
messages = {index: [], constraint: []}
each_schema_element do |type, model, label, property_name, exists|
if exists
log_warning!(type, model, property_name) if model.id_property_name.to_sym != property_name
else
messages[type] << force_add_message(type, label, property_name)
end
end
return if messages.values.all?(&:empty?)
fail ::ActiveGraph::DeprecatedSchemaDefinitionError, validation_error_message(messages)
end
def validation_error_message(messages)
<<MSG
Some schema elements were defined by the model (which is no longer supported), but they do not exist in the database. Run the following to create them if you haven't already:
#{messages[:constraint].join("\n")}
#{messages[:index].join("\n")}
And then run `rake neo4j:migrate`
(zshell users may need to escape the brackets)
MSG
end
def force_add_message(index_or_constraint, label, property_name)
"rake neo4j:generate_schema_migration[#{index_or_constraint},#{label},#{property_name}]"
end
def log_warning!(index_or_constraint, model, property_name)
ActiveGraph::Base.logger.warn "WARNING: The #{index_or_constraint} option is no longer supported (Defined on #{model.name} for #{property_name})"
end
private
def each_schema_element
[[:constraint, model_constraints], [:index, model_indexes]].each do |type, schema_elements|
schema_elements.each do |args|
yield(type, *args)
end
end
end
end
end
end