lib/pg_objects/parser.rb in pg_objects-1.0.3 vs lib/pg_objects/parser.rb in pg_objects-1.2.0

- old
+ new

@@ -1,47 +1,96 @@ require 'pg_query' -module PgObjects - ## - # Reads directives from SQL-comments - # - # --!depends_on [name_of_dependency] - # - # name_of_dependency: short or full name of object as well as object_name - # - class Parser - # rubocop: disable Style/WordArray - ROUTES = [ - ['DefineStmt', 'defnames', 0, 'String', 'str'], - ['CreateFunctionStmt', 'funcname', 0, 'String', 'str'], - ['CreateTrigStmt', 'trigname'], - ['CreateEventTrigStmt', 'trigname'], - ['CompositeTypeStmt', 'typevar', 'RangeVar', 'relname'], - ['ViewStmt', 'view', 'RangeVar', 'relname'], - ['CreateConversionStmt', 'conversion_name', 0, 'String', 'str'], - ['CreateTableAsStmt', 'into', 'IntoClause', 'rel', 'RangeVar', 'relname'], - ['CreateOpClassStmt', 'opclassname', 0, 'String', 'str'] - ].freeze - # rubocop: enable Style/WordArray +## +# Reads directives from SQL-comments +# +# --!depends_on [name_of_dependency] +# +# name_of_dependency: short or full name of object as well as object_name +# +class PgObjects::Parser + PG_ENTITIES = %i[operator_class trigger define_statement conversion event_trigger type function table].freeze - class << self - def fetch_directives(text) - { - depends_on: fetch_dependencies(text) - } - end + def initialize(source) + @source = source + end - def fetch_object_name(text) - parsed = PgQuery.parse(text).tree.dig(0, 'RawStmt', 'stmt') - ROUTES.map { |route| parsed.dig(*route) }.compact[0] - rescue PgQuery::ParseError, NoMethodError - nil - end + def fetch_directives + { + depends_on: fetch_dependencies + } + end - private + def fetch_object_name + parse_query + object_name + rescue PgQuery::ParseError, NoMethodError + nil + end - def fetch_dependencies(text) - text.split("\n").grep(/^(--|#)!/).map { |ln| ln.split[1] if ln =~ /!depends_on/ }.compact - end - end + private + + attr_reader :stmt, :parsed + + def parse_query + @parsed = PgQuery.parse(@source) + + @stmt = parsed.tree.stmts[0].stmt + end + + def object_name + PG_ENTITIES.filter_map { |entity| send(:"check_#{entity}") }.first + end + + def fetch_dependencies + @source.split("\n").grep(/^(--|#)!/).map { |ln| ln.split[1] if ln =~ /!depends_on/ }.compact + end + + # also views + def table? = parsed.tables.size.positive? + + def check_table + parsed.tables[0] if table? + end + + def function? = parsed.functions.size.positive? + + def check_function + parsed.functions[0] if function? + end + + def operator_class? = stmt.respond_to?(:create_op_class_stmt) && stmt.create_op_class_stmt.present? + + def check_operator_class + stmt.create_op_class_stmt.opclassname[0].string.sval if operator_class? + end + + def trigger? = stmt.respond_to?(:create_trig_stmt) && stmt.create_trig_stmt.present? + + def check_trigger + stmt.create_trig_stmt.trigname if trigger? + end + + def define_statement? = stmt.respond_to?(:define_stmt) && stmt.define_stmt.present? + + def check_define_statement + stmt.define_stmt.defnames[0].string.sval if define_statement? + end + + def conversion? = stmt.respond_to?(:create_conversion_stmt) && stmt.create_conversion_stmt.present? + + def check_conversion + stmt.create_conversion_stmt.conversion_name[0].string.sval if conversion? + end + + def event_trigger? = stmt.respond_to?(:create_event_trig_stmt) && stmt.create_event_trig_stmt.present? + + def check_event_trigger + stmt.create_event_trig_stmt.trigname if event_trigger? + end + + def type? = stmt.respond_to?(:composite_type_stmt) && stmt.composite_type_stmt.present? + + def check_type + stmt.composite_type_stmt.typevar.relname if type? end end