class ObjectFramework::SQLite::Schema
Declared SQLite tables, foreign keys, and consecutive schema migrations. Version 1 creates the initial tables. Storage finalizes this declaration and applies pending migrations transactionally during construction.
Constants
- TYPES
Attributes
Public Class Methods
Source
# File lib/object_framework/sqlite/schema.rb, line 17 def self.from_mappings(mappings) mappings.validate! keys = mappings.flat_map do |mapping| mapping.associations.select { |item| item.kind == :belongs_to }.map do |association| ForeignKey.new(table: mapping.table, column: association.foreign_key, target: mappings.fetch(association.target).table) end end new(tables: mappings.to_h { |mapping| [mapping.table, mapping.schema] }, foreign_keys: keys) end
Validates domain mappings and derives tables and belongs-to foreign keys. Returns a schema that can still receive migration declarations.
Source
# File lib/object_framework/sqlite/schema.rb, line 27 def initialize(tables:, foreign_keys: []) @tables = tables.to_h do |name, columns| fields = columns.to_h { |column, type| [identifier(column), validate_type(type)] } raise ConfigurationError, "SQLite tables require a string id" unless fields[:id] == :string [identifier(name), fields] end @foreign_keys = foreign_keys.dup.freeze @initial_tables = @tables.transform_values { |columns| columns.dup.freeze }.freeze @migrations = [Migration.new(version: 1, actions: [].freeze)] end
Public Instance Methods
Source
# File lib/object_framework/sqlite/schema.rb, line 78 def create_statements @initial_tables.map do |name, columns| fields = columns.map do |column, type| "#{quote(column)} #{TYPES.fetch(type)}#{column == :id ? ' PRIMARY KEY NOT NULL' : ''}" end foreign_keys.select { |key| key.table == name }.each do |key| fields << "FOREIGN KEY (#{quote(key.column)}) REFERENCES #{quote(key.target)} (\"id\") DEFERRABLE INITIALLY DEFERRED" end "CREATE TABLE #{quote(name)} (#{fields.join(', ')}) STRICT" end end
Source
# File lib/object_framework/sqlite/schema.rb, line 69 def finalize! return self if frozen? foreign_keys.each { |key| type(key.table, key.column); type(key.target, :id) } @tables.each_value(&:freeze) @tables.freeze @migrations.freeze freeze end
Source
# File lib/object_framework/sqlite/schema.rb, line 62 def identifier(name); Persistence::Query.identifier(name); end
Source
# File lib/object_framework/sqlite/schema.rb, line 42 def migration(version, &declaration) raise ConfigurationError, "Schema is finalized" if frozen? raise ConfigurationError, "Migration versions must be consecutive" unless version == @migrations.last.version + 1 editor = Editor.new(self) editor.instance_eval(&declaration) @migrations << Migration.new(version:, actions: editor.actions.each(&:freeze).freeze) self end
Declares the next consecutive version using Editor#add_column. Declare migrations before constructing Storage. Returns self.
schema.migration(2) { add_column :orders, :note, type: :string }
Source
# File lib/object_framework/sqlite/schema.rb, line 61 def quote(name); '"' + identifier(name).to_s + '"'; end
Source
# File lib/object_framework/sqlite/schema.rb, line 53 def table(name) @tables.fetch(identifier(name)) { raise ConfigurationError, "Unregistered SQLite table" } end
Source
# File lib/object_framework/sqlite/schema.rb, line 57 def type(table_name, column) table(table_name).fetch(identifier(column)) { raise ConfigurationError, "Unregistered SQLite column" } end
Source
# File lib/object_framework/sqlite/schema.rb, line 64 def validate_type(type) raise ConfigurationError, "Unknown SQLite field type" unless TYPES.key?(type) type end
Source
# File lib/object_framework/sqlite/schema.rb, line 51 def version; @migrations.last.version; end