Module: ReactiveRecord

Included in:
Generators::InstallGenerator
Defined in:
lib/reactive_record.rb,
lib/reactive_record/version.rb,
lib/generators/reactive_record/install_generator.rb

Defined Under Namespace

Modules: Generators

Constant Summary collapse

VERSION =
"0.0.4"

Instance Method Summary collapse

Instance Method Details

#cols_with_contype(db, table_name, type) ⇒ Object



73
74
75
76
77
78
79
80
81
# File 'lib/reactive_record.rb', line 73

def cols_with_contype db, table_name, type
  db.exec """
    SELECT column_name, conname
    FROM pg_constraint, information_schema.columns
    WHERE table_name = $1
    AND contype = $2
    AND ordinal_position = any(conkey);
  """, [table_name, type]
end

#column_nameObject



83
84
85
# File 'lib/reactive_record.rb', line 83

def column_name
  lambda {|row| row['column_name']}
end

#constraints(db, table) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/reactive_record.rb', line 41

def constraints db, table
  db.exec("""
    SELECT c.relname AS table_name,
           con.conname AS constraint_name,
           pg_get_constraintdef( con.oid, false) AS constraint_src
    FROM pg_constraint con
      JOIN pg_namespace n on (n.oid = con.connamespace)
      JOIN pg_class c on (c.oid = con.conrelid)
    WHERE con.conrelid != 0
    AND c.relname = $1
    ORDER BY con.conname;
  """, [table])
end

#generate_constraints(db, table) ⇒ Object



55
56
57
58
59
60
61
62
63
# File 'lib/reactive_record.rb', line 55

def generate_constraints db, table
  key_or_pkey = lambda do |row|
    row['constraint_name'].end_with?('_key') || row['constraint_name'].end_with?('_pkey')
  end

  constraints(db, table)
    .reject(&key_or_pkey)
    .map(&parse_constraint)
end

#model_definition(db, table_name) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/reactive_record.rb', line 8

def model_definition db, table_name
  header = "class #{table_name.classify.pluralize} < ActiveRecord::Base\n"
  footer = "end\n"

  body = []
  body << "set_table_name '#{table_name}'"
  body << "set_primary_key :#{primary_key db, table_name}"
  body << "#{validate_definition non_nullable_columns(db, table_name), 'presence'}"
  body << "#{validate_definition unique_columns(db, table_name), 'uniqueness'}"

  generate_constraints(db, table_name).each do |con|
    body << con
  end

  indent = "  "
  body = indent + body.join("\n" + indent) + "\n"
  header + body + footer
end

#non_nullable_columns(db, table_name) ⇒ Object



106
107
108
109
110
111
112
113
114
# File 'lib/reactive_record.rb', line 106

def non_nullable_columns db, table_name
  result = db.exec """
    SELECT column_name
    FROM information_schema.columns
    WHERE table_name = $1
    AND is_nullable = $2
  """, [table_name, 'NO']
  result.map { |r| r['column_name'] }
end

#parse_constraintObject



65
66
67
68
69
70
71
# File 'lib/reactive_record.rb', line 65

def parse_constraint
  lambda do |row|
    src = row['constraint_src']
    parser = ConstraintParser::Parser.new(ConstraintParser::Lexer.new(StringIO.new src))
    parser.parse.gen
  end
end

#primary_key(db, table_name) ⇒ Object



91
92
93
94
95
96
97
# File 'lib/reactive_record.rb', line 91

def primary_key db, table_name
  matching_primary_key = lambda {|row| row['conname'] == "#{table_name}_pkey"}
  cols_with_contype(db, table_name, 'p')
    .select(&matching_primary_key)
    .map(&column_name)
    .first
end

#table_nameObject



87
88
89
# File 'lib/reactive_record.rb', line 87

def table_name
  lambda {|row| row['table_name']}
end

#table_names(db) ⇒ Object



33
34
35
36
37
38
39
# File 'lib/reactive_record.rb', line 33

def table_names db
  results = db.exec(
    "select table_name from information_schema.tables where table_schema = $1",
    ['public']
  )
  results.map { |r| r['table_name'] }
end

#unique_columns(db, table_name) ⇒ Object



99
100
101
102
103
104
# File 'lib/reactive_record.rb', line 99

def unique_columns db, table_name
  matching_unique_constraint = lambda {|row| row['conname'] == "#{table_name}_#{row['column_name']}_key"}
  cols_with_contype(db, table_name, 'u')
    .select(&matching_unique_constraint)
    .map(&column_name)
end

#validate_definition(cols, type) ⇒ Object



27
28
29
30
31
# File 'lib/reactive_record.rb', line 27

def validate_definition cols, type
  return '' if cols.empty?
  symbols = cols.map { |c| ":#{c}" }
  "validate #{symbols.join ', '}, #{type}: true"
end