Module: MoneyAttribute::MigrationExtensions::Helper
- Included in:
- SchemaStatements, TableDefinition
- Defined in:
- lib/money_attribute/migration_extensions/helper.rb
Overview
Shared argument-parsing logic for migration helpers.
Resolves accessor names, column overrides, and amount type configuration into concrete column definitions. Included by both SchemaStatements and TableDefinition.
Constant Summary collapse
- AMOUNT_CONFIG =
{ crypto_decimal: { type: :decimal, precision: 36, scale: 18 }, fiat_decimal: { type: :decimal, precision: 20, scale: 4 }, fiat_integer: { type: :bigint } }.freeze
- CURRENCY_MIN_LIMIT =
8- CURRENCY_DEFAULT_LIMIT =
20
Instance Attribute Summary collapse
-
#AMOUNT_CONFIG ⇒ Hash{Symbol => Hash}
Mapping of symbolic type names to column type/hash pairs.
-
#CURRENCY_DEFAULT_LIMIT ⇒ Integer
Default currency column string limit (20).
-
#CURRENCY_MIN_LIMIT ⇒ Integer
Minimum allowed currency column string limit (8).
Instance Attribute Details
#AMOUNT_CONFIG ⇒ Hash{Symbol => Hash}
Returns mapping of symbolic type names to column type/hash pairs.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/money_attribute/migration_extensions/helper.rb', line 18 module Helper AMOUNT_CONFIG = { crypto_decimal: { type: :decimal, precision: 36, scale: 18 }, fiat_decimal: { type: :decimal, precision: 20, scale: 4 }, fiat_integer: { type: :bigint } }.freeze CURRENCY_MIN_LIMIT = 8 CURRENCY_DEFAULT_LIMIT = 20 private # Parses arguments for a single-column (amount-only) migration. # # @param accessor [Symbol, String] the money attribute name # @param options [Hash] column options # @option options [Symbol] :column explicit column name override # @option options [Symbol] :type amount type (+:fiat_decimal+, # +:crypto_decimal+, +:fiat_integer+) # @option options [Boolean] :null whether the column allows NULL # @option options [Object] :default default value for the column # @return [Array(String, Hash)] column name and merged options hash # @raise [ArgumentError] if +precision:+ or +scale:+ are given, or # type is unrecognized # @api private def parse_money_amount_args(accessor, ) ||= {} if .key?(:precision) || .key?(:scale) raise ArgumentError, 'precision:/scale: are not configurable — money_attribute uses fixed, ' \ 'vetted values per type (:crypto_decimal, :fiat_decimal, :fiat_integer) ' \ 'to prevent under-precision bugs, particularly for crypto amounts.' end column = ([:column] || accessor).to_s config = AMOUNT_CONFIG[[:type] || :fiat_decimal] unless config raise ArgumentError, "Invalid type #{[:type]}. Use :crypto_decimal, :fiat_decimal or :fiat_integer" end = { null: [:null], default: [:default] }.compact [column, config.merge()] end # Parses arguments for the currency column in a composite migration. # # @param accessor [Symbol, String] the money attribute name # @param options [Hash] currency column options # @option options [Symbol] :column explicit currency column name override # @option options [Integer] :limit string limit for the column # @option options [Boolean] :null whether the column allows NULL # @option options [Object] :default default value for the column # @return [Array(String, Hash)] column name and merged options hash # @raise [ArgumentError] if limit is below {CURRENCY_MIN_LIMIT} # @api private def parse_currency_args(accessor, ) ||= {} limit = ([:limit] || CURRENCY_DEFAULT_LIMIT).to_i if limit < CURRENCY_MIN_LIMIT raise ArgumentError, "currency limit: #{limit} is too small to hold an ISO 4217 code and crypto popular codes" \ "(minimum #{CURRENCY_MIN_LIMIT}). Omit limit: to use the default of #{CURRENCY_DEFAULT_LIMIT}, " \ "or pass a value >= #{CURRENCY_MIN_LIMIT}." end column = currency_column_name(accessor, [:column]) [column, { limit:, null: [:null], default: [:default] }.compact] end # Resolves the currency column name for the given accessor. # # Resolution order: # 1. Explicit +column_override+ → returned as-is # 2. Accessor is +:amount+ → +currency+ # 3. Accessor ends with +_amount+ → strips suffix and appends +_currency+ # 4. Otherwise → +<accessor>_currency+ # # @param accessor [Symbol, String] the money attribute name # @param column_override [Symbol, String, nil] explicit column name # @return [String] the resolved currency column name # @api private def currency_column_name(accessor, column_override) return column_override.to_s if column_override name = accessor.to_s return 'currency' if name == 'amount' radical = name.end_with?('_amount') ? name.sub(/_amount$/, '') : name "#{radical}_currency" end # Parses arguments for a composite (amount + currency) migration. # # Delegates to {#parse_money_amount_args} and {#parse_currency_args} # using the nested +:amount+ and +:currency+ option keys. # # @param accessor [Symbol, String] the money attribute name # @param options [Hash] migration options # @option options [Hash] :amount amount column options # @option options [Hash] :currency currency column options # @return [Array(String, String, Hash, Hash)] amount column name, # currency column name, amount options, currency options # @api private def parse_money_args(accessor, = {}) amount_column, = parse_money_amount_args(accessor, [:amount]) currency_column, = parse_currency_args(accessor, [:currency]) [amount_column, currency_column, , ] end end |
#CURRENCY_DEFAULT_LIMIT ⇒ Integer
Returns default currency column string limit (20).
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/money_attribute/migration_extensions/helper.rb', line 18 module Helper AMOUNT_CONFIG = { crypto_decimal: { type: :decimal, precision: 36, scale: 18 }, fiat_decimal: { type: :decimal, precision: 20, scale: 4 }, fiat_integer: { type: :bigint } }.freeze CURRENCY_MIN_LIMIT = 8 CURRENCY_DEFAULT_LIMIT = 20 private # Parses arguments for a single-column (amount-only) migration. # # @param accessor [Symbol, String] the money attribute name # @param options [Hash] column options # @option options [Symbol] :column explicit column name override # @option options [Symbol] :type amount type (+:fiat_decimal+, # +:crypto_decimal+, +:fiat_integer+) # @option options [Boolean] :null whether the column allows NULL # @option options [Object] :default default value for the column # @return [Array(String, Hash)] column name and merged options hash # @raise [ArgumentError] if +precision:+ or +scale:+ are given, or # type is unrecognized # @api private def parse_money_amount_args(accessor, ) ||= {} if .key?(:precision) || .key?(:scale) raise ArgumentError, 'precision:/scale: are not configurable — money_attribute uses fixed, ' \ 'vetted values per type (:crypto_decimal, :fiat_decimal, :fiat_integer) ' \ 'to prevent under-precision bugs, particularly for crypto amounts.' end column = ([:column] || accessor).to_s config = AMOUNT_CONFIG[[:type] || :fiat_decimal] unless config raise ArgumentError, "Invalid type #{[:type]}. Use :crypto_decimal, :fiat_decimal or :fiat_integer" end = { null: [:null], default: [:default] }.compact [column, config.merge()] end # Parses arguments for the currency column in a composite migration. # # @param accessor [Symbol, String] the money attribute name # @param options [Hash] currency column options # @option options [Symbol] :column explicit currency column name override # @option options [Integer] :limit string limit for the column # @option options [Boolean] :null whether the column allows NULL # @option options [Object] :default default value for the column # @return [Array(String, Hash)] column name and merged options hash # @raise [ArgumentError] if limit is below {CURRENCY_MIN_LIMIT} # @api private def parse_currency_args(accessor, ) ||= {} limit = ([:limit] || CURRENCY_DEFAULT_LIMIT).to_i if limit < CURRENCY_MIN_LIMIT raise ArgumentError, "currency limit: #{limit} is too small to hold an ISO 4217 code and crypto popular codes" \ "(minimum #{CURRENCY_MIN_LIMIT}). Omit limit: to use the default of #{CURRENCY_DEFAULT_LIMIT}, " \ "or pass a value >= #{CURRENCY_MIN_LIMIT}." end column = currency_column_name(accessor, [:column]) [column, { limit:, null: [:null], default: [:default] }.compact] end # Resolves the currency column name for the given accessor. # # Resolution order: # 1. Explicit +column_override+ → returned as-is # 2. Accessor is +:amount+ → +currency+ # 3. Accessor ends with +_amount+ → strips suffix and appends +_currency+ # 4. Otherwise → +<accessor>_currency+ # # @param accessor [Symbol, String] the money attribute name # @param column_override [Symbol, String, nil] explicit column name # @return [String] the resolved currency column name # @api private def currency_column_name(accessor, column_override) return column_override.to_s if column_override name = accessor.to_s return 'currency' if name == 'amount' radical = name.end_with?('_amount') ? name.sub(/_amount$/, '') : name "#{radical}_currency" end # Parses arguments for a composite (amount + currency) migration. # # Delegates to {#parse_money_amount_args} and {#parse_currency_args} # using the nested +:amount+ and +:currency+ option keys. # # @param accessor [Symbol, String] the money attribute name # @param options [Hash] migration options # @option options [Hash] :amount amount column options # @option options [Hash] :currency currency column options # @return [Array(String, String, Hash, Hash)] amount column name, # currency column name, amount options, currency options # @api private def parse_money_args(accessor, = {}) amount_column, = parse_money_amount_args(accessor, [:amount]) currency_column, = parse_currency_args(accessor, [:currency]) [amount_column, currency_column, , ] end end |
#CURRENCY_MIN_LIMIT ⇒ Integer
Returns minimum allowed currency column string limit (8).
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/money_attribute/migration_extensions/helper.rb', line 18 module Helper AMOUNT_CONFIG = { crypto_decimal: { type: :decimal, precision: 36, scale: 18 }, fiat_decimal: { type: :decimal, precision: 20, scale: 4 }, fiat_integer: { type: :bigint } }.freeze CURRENCY_MIN_LIMIT = 8 CURRENCY_DEFAULT_LIMIT = 20 private # Parses arguments for a single-column (amount-only) migration. # # @param accessor [Symbol, String] the money attribute name # @param options [Hash] column options # @option options [Symbol] :column explicit column name override # @option options [Symbol] :type amount type (+:fiat_decimal+, # +:crypto_decimal+, +:fiat_integer+) # @option options [Boolean] :null whether the column allows NULL # @option options [Object] :default default value for the column # @return [Array(String, Hash)] column name and merged options hash # @raise [ArgumentError] if +precision:+ or +scale:+ are given, or # type is unrecognized # @api private def parse_money_amount_args(accessor, ) ||= {} if .key?(:precision) || .key?(:scale) raise ArgumentError, 'precision:/scale: are not configurable — money_attribute uses fixed, ' \ 'vetted values per type (:crypto_decimal, :fiat_decimal, :fiat_integer) ' \ 'to prevent under-precision bugs, particularly for crypto amounts.' end column = ([:column] || accessor).to_s config = AMOUNT_CONFIG[[:type] || :fiat_decimal] unless config raise ArgumentError, "Invalid type #{[:type]}. Use :crypto_decimal, :fiat_decimal or :fiat_integer" end = { null: [:null], default: [:default] }.compact [column, config.merge()] end # Parses arguments for the currency column in a composite migration. # # @param accessor [Symbol, String] the money attribute name # @param options [Hash] currency column options # @option options [Symbol] :column explicit currency column name override # @option options [Integer] :limit string limit for the column # @option options [Boolean] :null whether the column allows NULL # @option options [Object] :default default value for the column # @return [Array(String, Hash)] column name and merged options hash # @raise [ArgumentError] if limit is below {CURRENCY_MIN_LIMIT} # @api private def parse_currency_args(accessor, ) ||= {} limit = ([:limit] || CURRENCY_DEFAULT_LIMIT).to_i if limit < CURRENCY_MIN_LIMIT raise ArgumentError, "currency limit: #{limit} is too small to hold an ISO 4217 code and crypto popular codes" \ "(minimum #{CURRENCY_MIN_LIMIT}). Omit limit: to use the default of #{CURRENCY_DEFAULT_LIMIT}, " \ "or pass a value >= #{CURRENCY_MIN_LIMIT}." end column = currency_column_name(accessor, [:column]) [column, { limit:, null: [:null], default: [:default] }.compact] end # Resolves the currency column name for the given accessor. # # Resolution order: # 1. Explicit +column_override+ → returned as-is # 2. Accessor is +:amount+ → +currency+ # 3. Accessor ends with +_amount+ → strips suffix and appends +_currency+ # 4. Otherwise → +<accessor>_currency+ # # @param accessor [Symbol, String] the money attribute name # @param column_override [Symbol, String, nil] explicit column name # @return [String] the resolved currency column name # @api private def currency_column_name(accessor, column_override) return column_override.to_s if column_override name = accessor.to_s return 'currency' if name == 'amount' radical = name.end_with?('_amount') ? name.sub(/_amount$/, '') : name "#{radical}_currency" end # Parses arguments for a composite (amount + currency) migration. # # Delegates to {#parse_money_amount_args} and {#parse_currency_args} # using the nested +:amount+ and +:currency+ option keys. # # @param accessor [Symbol, String] the money attribute name # @param options [Hash] migration options # @option options [Hash] :amount amount column options # @option options [Hash] :currency currency column options # @return [Array(String, String, Hash, Hash)] amount column name, # currency column name, amount options, currency options # @api private def parse_money_args(accessor, = {}) amount_column, = parse_money_amount_args(accessor, [:amount]) currency_column, = parse_currency_args(accessor, [:currency]) [amount_column, currency_column, , ] end end |