|
1 | 1 | # frozen_string_literal: true |
2 | 2 |
|
3 | 3 | module FixtureBot |
4 | | - class Row < Data.define(:table, :name, :literal_values, :association_refs, :tag_refs) |
5 | | - class Definition |
6 | | - attr_reader :literal_values, :association_refs, :tag_refs |
7 | | - |
8 | | - def initialize(table, schema) |
9 | | - @literal_values = {} |
10 | | - @association_refs = {} |
11 | | - @tag_refs = {} |
12 | | - |
13 | | - define_column_methods(table) |
14 | | - define_association_methods(table) |
15 | | - define_join_table_methods(table, schema) |
16 | | - end |
17 | | - |
18 | | - private |
19 | | - |
20 | | - def define_column_methods(table) |
21 | | - table.columns.each do |col| |
22 | | - define_singleton_method(col) do |value| |
23 | | - @literal_values[col] = value |
24 | | - end |
25 | | - end |
26 | | - end |
27 | | - |
28 | | - def define_association_methods(table) |
29 | | - table.belongs_to_associations.each do |assoc| |
30 | | - define_singleton_method(assoc.name) do |ref| |
31 | | - @association_refs[assoc.name] = ref |
32 | | - end |
33 | | - end |
34 | | - end |
35 | | - |
36 | | - def define_join_table_methods(table, schema) |
37 | | - schema.join_tables.each_value do |jt| |
38 | | - if jt.left_table == table.name |
39 | | - define_singleton_method(jt.right_table) do |*refs| |
40 | | - @tag_refs[jt.name] = { table: jt.right_table, refs: refs } |
41 | | - end |
42 | | - elsif jt.right_table == table.name |
43 | | - define_singleton_method(jt.left_table) do |*refs| |
44 | | - @tag_refs[jt.name] = { table: jt.left_table, refs: refs } |
45 | | - end |
46 | | - end |
47 | | - end |
48 | | - end |
49 | | - end |
50 | | - |
51 | | - class Builder |
52 | | - def initialize(row:, table:, defaults:, join_tables:) |
53 | | - @row = row |
54 | | - @table = table |
55 | | - @defaults = defaults |
56 | | - @join_tables = join_tables |
57 | | - end |
58 | | - |
59 | | - def id |
60 | | - @id ||= Key.generate(@row.table, @row.name) |
61 | | - end |
62 | | - |
63 | | - def record |
64 | | - result = { id: id } |
65 | | - @table.columns.each do |col| |
66 | | - if @row.literal_values.key?(col) |
67 | | - result[col] = @row.literal_values[col] |
68 | | - elsif foreign_key_values.key?(col) |
69 | | - result[col] = foreign_key_values[col] |
70 | | - elsif defaulted_values.key?(col) |
71 | | - result[col] = defaulted_values[col] |
72 | | - end |
73 | | - end |
74 | | - result |
75 | | - end |
76 | | - |
77 | | - def join_rows |
78 | | - @row.tag_refs.flat_map do |join_table_name, tag_info| |
79 | | - jt = @join_tables[join_table_name] |
80 | | - tag_info[:refs].map do |tag_ref| |
81 | | - build_join_row(jt, tag_info[:table], tag_ref) |
82 | | - end |
83 | | - end |
84 | | - end |
85 | | - |
86 | | - private |
87 | | - |
88 | | - def build_join_row(jt, other_table, tag_ref) |
89 | | - other_id = Key.generate(other_table, tag_ref) |
90 | | - |
91 | | - if jt.left_table == @row.table |
92 | | - { |
93 | | - key: :"#{@row.name}_#{tag_ref}", |
94 | | - join_table: jt.name, |
95 | | - row: { jt.left_foreign_key => id, jt.right_foreign_key => other_id } |
96 | | - } |
97 | | - else |
98 | | - { |
99 | | - key: :"#{tag_ref}_#{@row.name}", |
100 | | - join_table: jt.name, |
101 | | - row: { jt.left_foreign_key => other_id, jt.right_foreign_key => id } |
102 | | - } |
103 | | - end |
104 | | - end |
105 | | - |
106 | | - def foreign_key_values |
107 | | - @foreign_key_values ||= @row.association_refs.each_with_object({}) do |(assoc_name, ref), hash| |
108 | | - assoc = @table.belongs_to_associations.find { |a| a.name == assoc_name } |
109 | | - hash[assoc.foreign_key] = Key.generate(assoc.table, ref) |
110 | | - end |
111 | | - end |
112 | | - |
113 | | - def defaulted_values |
114 | | - @defaulted_values ||= @defaults.each_with_object({}) do |(col, block), result| |
115 | | - next if @row.literal_values.key?(col) |
116 | | - next if foreign_key_values.key?(col) |
117 | | - |
118 | | - context = Default::Context.new( |
119 | | - record_name: @row.name, |
120 | | - literal_values: @row.literal_values |
121 | | - ) |
122 | | - result[col] = context.instance_eval(&block) |
123 | | - end |
124 | | - end |
125 | | - end |
126 | | - end |
| 4 | + Row = Data.define(:table, :name, :literal_values, :association_refs, :tag_refs) |
127 | 5 | end |
0 commit comments