mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-15 01:05:49 +08:00
Ruby's compact module syntax (`module Migrations::Database::Schema::DSL`) breaks lexical constant lookup — `Module.nesting` only includes the innermost constant, so every cross-module reference must be fully qualified. In practice this means writing `Migrations::Database::Schema::Helpers` even when you're already inside `Migrations::Database::Schema`. Nested module definitions restore the full nesting chain, which brings several practical benefits: - **Less verbose code**: references like `Schema::Helpers`, `Database::IntermediateDB`, or `Converters::Base::ProgressStep` work without repeating the full path from root - **Easier to write new code**: contributors don't need to remember which prefixes are required — if you're inside the namespace, short names just work - **Fewer aliasing workarounds**: removes the need for constants like `MappingType = Migrations::Importer::MappingType` that existed solely to shorten references - **Standard Ruby style**: consistent with how most Ruby projects and gems structure their namespaces The diff is large but mechanical — no logic changes, just module wrapping and shortening references that the nesting now resolves. Generated code (intermediate_db models/enums) keeps fully qualified references like `Migrations::Database.format_*` since it must work regardless of the configured output namespace. - Convert 138 lib files from compact to nested module definitions - Remove now-redundant fully qualified prefixes and aliases - Update model and enum writers to generate nested modules with correct indentation - Regenerate all intermediate_db models and enums
221 lines
4.4 KiB
Ruby
221 lines
4.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Migrations
|
|
module Database
|
|
module Schema
|
|
module Helpers
|
|
# Canonical datatypes after normalization (used in resolved schema validation)
|
|
VALID_DATATYPES = %i[blob boolean date datetime float inet integer json numeric text].freeze
|
|
|
|
# Pre-normalization aliases that map to a canonical datatype
|
|
DATATYPE_ALIASES = {
|
|
binary: :blob,
|
|
string: :text,
|
|
enum: :text,
|
|
uuid: :text,
|
|
jsonb: :json,
|
|
}.freeze
|
|
|
|
# All types accepted as DSL type overrides (pre-normalization)
|
|
VALID_TYPE_OVERRIDES =
|
|
(VALID_DATATYPES.map(&:to_s) + DATATYPE_ALIASES.keys.map(&:to_s)).to_set.freeze
|
|
|
|
SQLITE_KEYWORDS = %w[
|
|
abort
|
|
action
|
|
add
|
|
after
|
|
all
|
|
alter
|
|
always
|
|
analyze
|
|
and
|
|
as
|
|
asc
|
|
attach
|
|
autoincrement
|
|
before
|
|
begin
|
|
between
|
|
by
|
|
cascade
|
|
case
|
|
cast
|
|
check
|
|
collate
|
|
column
|
|
commit
|
|
conflict
|
|
constraint
|
|
create
|
|
cross
|
|
current
|
|
current_date
|
|
current_time
|
|
current_timestamp
|
|
database
|
|
default
|
|
deferrable
|
|
deferred
|
|
delete
|
|
desc
|
|
detach
|
|
distinct
|
|
do
|
|
drop
|
|
each
|
|
else
|
|
end
|
|
escape
|
|
except
|
|
exclude
|
|
exclusive
|
|
exists
|
|
explain
|
|
fail
|
|
filter
|
|
first
|
|
following
|
|
for
|
|
foreign
|
|
from
|
|
full
|
|
generated
|
|
glob
|
|
group
|
|
groups
|
|
having
|
|
if
|
|
ignore
|
|
immediate
|
|
in
|
|
index
|
|
indexed
|
|
initially
|
|
inner
|
|
insert
|
|
instead
|
|
intersect
|
|
into
|
|
is
|
|
isnull
|
|
join
|
|
key
|
|
last
|
|
left
|
|
like
|
|
limit
|
|
match
|
|
materialized
|
|
natural
|
|
no
|
|
not
|
|
nothing
|
|
notnull
|
|
null
|
|
nulls
|
|
of
|
|
offset
|
|
on
|
|
or
|
|
order
|
|
others
|
|
outer
|
|
over
|
|
partition
|
|
plan
|
|
pragma
|
|
preceding
|
|
primary
|
|
query
|
|
raise
|
|
range
|
|
recursive
|
|
references
|
|
regexp
|
|
reindex
|
|
release
|
|
rename
|
|
replace
|
|
restrict
|
|
returning
|
|
right
|
|
rollback
|
|
row
|
|
rows
|
|
savepoint
|
|
select
|
|
set
|
|
table
|
|
temp
|
|
temporary
|
|
then
|
|
ties
|
|
to
|
|
transaction
|
|
trigger
|
|
unbounded
|
|
union
|
|
unique
|
|
update
|
|
using
|
|
vacuum
|
|
values
|
|
view
|
|
virtual
|
|
when
|
|
where
|
|
window
|
|
with
|
|
without
|
|
].freeze
|
|
private_constant :SQLITE_KEYWORDS
|
|
|
|
def self.escape_identifier(identifier)
|
|
if SQLITE_KEYWORDS.include?(identifier)
|
|
%Q("#{identifier}")
|
|
else
|
|
identifier
|
|
end
|
|
end
|
|
|
|
def self.to_singular_classname(snake_case_string)
|
|
snake_case_string.downcase.singularize.camelize
|
|
end
|
|
|
|
def self.to_const_name(name)
|
|
name.parameterize.underscore.upcase
|
|
end
|
|
|
|
def self.db_label(namespace)
|
|
namespace.split("::").last
|
|
end
|
|
|
|
def self.format_ruby_file(path)
|
|
system(
|
|
"bundle",
|
|
"exec",
|
|
"stree",
|
|
"write",
|
|
path,
|
|
exception: true,
|
|
out: File::NULL,
|
|
err: File::NULL,
|
|
)
|
|
rescue StandardError
|
|
raise "Failed to run `bundle exec stree write '#{path}'`"
|
|
end
|
|
|
|
def self.format_ruby_files(directory)
|
|
format_ruby_file(File.join(directory, "*.rb"))
|
|
end
|
|
|
|
# Plugin directory names use hyphens (discourse-ai), but Ruby symbols
|
|
# use underscores (discourse_ai). Normalize for manifest lookups.
|
|
def self.normalize_plugin_name(name)
|
|
name.to_s.tr("_", "-")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|