foobara 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (359) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +5 -0
  3. data/.rubocop.yml +20 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +10 -0
  6. data/DECISION_LOG.md +220 -0
  7. data/Guardfile +9 -0
  8. data/LICENSE-AGPL.txt +666 -0
  9. data/LICENSE.txt +4 -0
  10. data/README.md +50 -0
  11. data/Rakefile +10 -0
  12. data/concepts.md +153 -0
  13. data/projects/builtin_types/lib/foobara/builtin_types.rb +67 -0
  14. data/projects/builtin_types/src/README.md +140 -0
  15. data/projects/builtin_types/src/array/casters/arrayable.rb +22 -0
  16. data/projects/builtin_types/src/array/supported_processors/element_type_declaration.rb +41 -0
  17. data/projects/builtin_types/src/array/supported_validators/size.rb +43 -0
  18. data/projects/builtin_types/src/associative_array/casters/array.rb +22 -0
  19. data/projects/builtin_types/src/associative_array/supported_processors/key_type_declaration.rb +44 -0
  20. data/projects/builtin_types/src/associative_array/supported_processors/value_type_declaration.rb +44 -0
  21. data/projects/builtin_types/src/atomic_duck.rb +6 -0
  22. data/projects/builtin_types/src/attributes/casters/array.rb +33 -0
  23. data/projects/builtin_types/src/attributes/casters/hash.rb +28 -0
  24. data/projects/builtin_types/src/attributes/supported_processors/element_type_declarations.rb +89 -0
  25. data/projects/builtin_types/src/attributes/supported_transformers/defaults/type_declaration_extension/extend_attributes_type_declaration/desugarizers/move_defaults_from_element_types_to_root.rb +40 -0
  26. data/projects/builtin_types/src/attributes/supported_transformers/defaults/type_declaration_extension/extend_attributes_type_declaration/desugarizers/symbolize_defaults.rb +31 -0
  27. data/projects/builtin_types/src/attributes/supported_transformers/defaults/type_declaration_extension/extend_attributes_type_declaration/type_declaration_validators/hash_with_symbolic_keys.rb +37 -0
  28. data/projects/builtin_types/src/attributes/supported_transformers/defaults/type_declaration_extension/extend_attributes_type_declaration/type_declaration_validators/valid_attribute_names.rb +60 -0
  29. data/projects/builtin_types/src/attributes/supported_transformers/defaults.rb +41 -0
  30. data/projects/builtin_types/src/attributes/supported_validators/required/type_declaration_extension/extend_attributes_type_declaration/desugarizers/move_required_from_element_types_to_root.rb +55 -0
  31. data/projects/builtin_types/src/attributes/supported_validators/required/type_declaration_extension/extend_attributes_type_declaration/type_declaration_validators/array_of_symbols.rb +47 -0
  32. data/projects/builtin_types/src/attributes/supported_validators/required/type_declaration_extension/extend_attributes_type_declaration/type_declaration_validators/array_with_valid_attribute_names.rb +54 -0
  33. data/projects/builtin_types/src/attributes/supported_validators/required.rb +51 -0
  34. data/projects/builtin_types/src/big_decimal/casters/integer.rb +21 -0
  35. data/projects/builtin_types/src/big_decimal/casters/string.rb +24 -0
  36. data/projects/builtin_types/src/boolean/casters/numeric.rb +21 -0
  37. data/projects/builtin_types/src/boolean/casters/string_or_symbol.rb +27 -0
  38. data/projects/builtin_types/src/builtin_types.rb +189 -0
  39. data/projects/builtin_types/src/date/casters/hash.rb +23 -0
  40. data/projects/builtin_types/src/date/casters/string.rb +40 -0
  41. data/projects/builtin_types/src/datetime/casters/date.rb +21 -0
  42. data/projects/builtin_types/src/datetime/casters/hash.rb +77 -0
  43. data/projects/builtin_types/src/datetime/casters/seconds_since_epoch.rb +21 -0
  44. data/projects/builtin_types/src/datetime/casters/string.rb +31 -0
  45. data/projects/builtin_types/src/duck/supported_casters/allow_nil.rb +38 -0
  46. data/projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/class_desugarizer.rb +29 -0
  47. data/projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/instance_of_class_desugarizer.rb +31 -0
  48. data/projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/instance_of_symbol_desugarizer.rb +31 -0
  49. data/projects/builtin_types/src/duck/supported_validators/instance_of/type_declaration_extension/extend_registered_type_declaration/type_declaration_validators/is_valid_class.rb +43 -0
  50. data/projects/builtin_types/src/duck/supported_validators/instance_of.rb +42 -0
  51. data/projects/builtin_types/src/duck/supported_validators/one_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/cast_one_of.rb +37 -0
  52. data/projects/builtin_types/src/duck/supported_validators/one_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/module_desugarizer.rb +41 -0
  53. data/projects/builtin_types/src/duck/supported_validators/one_of.rb +41 -0
  54. data/projects/builtin_types/src/duck.rb +6 -0
  55. data/projects/builtin_types/src/duckture.rb +6 -0
  56. data/projects/builtin_types/src/email/transformers/downcase.rb +15 -0
  57. data/projects/builtin_types/src/email/validator_base.rb +94 -0
  58. data/projects/builtin_types/src/float/casters/integer.rb +21 -0
  59. data/projects/builtin_types/src/float/casters/string.rb +24 -0
  60. data/projects/builtin_types/src/integer/casters/string.rb +23 -0
  61. data/projects/builtin_types/src/number/supported_validators/max.rb +41 -0
  62. data/projects/builtin_types/src/number/supported_validators/min.rb +41 -0
  63. data/projects/builtin_types/src/string/casters/numeric.rb +21 -0
  64. data/projects/builtin_types/src/string/casters/symbol.rb +21 -0
  65. data/projects/builtin_types/src/string/supported_transformers/downcase.rb +11 -0
  66. data/projects/builtin_types/src/string/supported_validators/matches.rb +41 -0
  67. data/projects/builtin_types/src/string/supported_validators/max_length.rb +37 -0
  68. data/projects/builtin_types/src/symbol/casters/string.rb +21 -0
  69. data/projects/builtin_types/src/tuple/supported_processors/element_type_declarations/type_declaration_extension/extend_tuple_type_declaration/desugarizers/set_size.rb +32 -0
  70. data/projects/builtin_types/src/tuple/supported_processors/element_type_declarations/type_declaration_extension/extend_tuple_type_declaration/type_declaration_validators/size_matches.rb +50 -0
  71. data/projects/builtin_types/src/tuple/supported_processors/element_type_declarations.rb +59 -0
  72. data/projects/callback/lib/foobara/callback.rb +1 -0
  73. data/projects/callback/src/block/after.rb +10 -0
  74. data/projects/callback/src/block/around.rb +10 -0
  75. data/projects/callback/src/block/before.rb +10 -0
  76. data/projects/callback/src/block/concerns/block_parameter_not_allowed.rb +21 -0
  77. data/projects/callback/src/block/concerns/block_parameter_required.rb +21 -0
  78. data/projects/callback/src/block/concerns/keyword_argumentable_block.rb +31 -0
  79. data/projects/callback/src/block/concerns/single_argument_block.rb +22 -0
  80. data/projects/callback/src/block/concerns/type.rb +17 -0
  81. data/projects/callback/src/block/error.rb +10 -0
  82. data/projects/callback/src/block.rb +83 -0
  83. data/projects/callback/src/registry/base.rb +90 -0
  84. data/projects/callback/src/registry/chained_conditioned.rb +24 -0
  85. data/projects/callback/src/registry/chained_multiple_action.rb +24 -0
  86. data/projects/callback/src/registry/conditioned.rb +101 -0
  87. data/projects/callback/src/registry/multiple_action.rb +110 -0
  88. data/projects/callback/src/registry/single_action.rb +15 -0
  89. data/projects/callback/src/runner.rb +89 -0
  90. data/projects/callback/src/set.rb +56 -0
  91. data/projects/command/lib/foobara/command.rb +9 -0
  92. data/projects/command/src/command/entity_helpers.rb +145 -0
  93. data/projects/command/src/command.rb +36 -0
  94. data/projects/command/src/concerns/callbacks.rb +93 -0
  95. data/projects/command/src/concerns/description.rb +23 -0
  96. data/projects/command/src/concerns/domain_mappers.rb +35 -0
  97. data/projects/command/src/concerns/entities.rb +88 -0
  98. data/projects/command/src/concerns/errors.rb +181 -0
  99. data/projects/command/src/concerns/errors_type.rb +124 -0
  100. data/projects/command/src/concerns/inputs.rb +59 -0
  101. data/projects/command/src/concerns/inputs_type.rb +58 -0
  102. data/projects/command/src/concerns/namespace.rb +49 -0
  103. data/projects/command/src/concerns/reflection.rb +137 -0
  104. data/projects/command/src/concerns/result.rb +25 -0
  105. data/projects/command/src/concerns/result_type.rb +29 -0
  106. data/projects/command/src/concerns/runtime.rb +119 -0
  107. data/projects/command/src/concerns/state_machine.rb +12 -0
  108. data/projects/command/src/concerns/subcommands.rb +102 -0
  109. data/projects/command/src/concerns/transactions.rb +81 -0
  110. data/projects/command/src/state_machine.rb +57 -0
  111. data/projects/command/src/transformed_command.rb +459 -0
  112. data/projects/command_connectors/lib/foobara/command_connectors.rb +12 -0
  113. data/projects/command_connectors/src/command_connector.rb +401 -0
  114. data/projects/command_connectors/src/command_registry/allowed_rule.rb +29 -0
  115. data/projects/command_connectors/src/command_registry/exposed_command.rb +140 -0
  116. data/projects/command_connectors/src/command_registry/exposed_domain.rb +30 -0
  117. data/projects/command_connectors/src/command_registry/exposed_organization.rb +30 -0
  118. data/projects/command_connectors/src/command_registry.rb +257 -0
  119. data/projects/command_connectors/src/commands/describe.rb +36 -0
  120. data/projects/command_connectors/src/commands/list_commands.rb +51 -0
  121. data/projects/command_connectors/src/commands/ping.rb +21 -0
  122. data/projects/command_connectors/src/commands/query_git_commit_info.rb +81 -0
  123. data/projects/command_connectors/src/request.rb +99 -0
  124. data/projects/command_connectors/src/response.rb +17 -0
  125. data/projects/command_connectors/src/serializer.rb +25 -0
  126. data/projects/command_connectors/src/serializers/aggregate_serializer.rb +32 -0
  127. data/projects/command_connectors/src/serializers/atomic_serializer.rb +25 -0
  128. data/projects/command_connectors/src/serializers/entities_to_primary_keys_serializer.rb +28 -0
  129. data/projects/command_connectors/src/serializers/errors_serializer.rb +18 -0
  130. data/projects/command_connectors/src/serializers/json_serializer.rb +20 -0
  131. data/projects/command_connectors/src/serializers/noop_serializer.rb +20 -0
  132. data/projects/command_connectors/src/serializers/record_store_serializer.rb +31 -0
  133. data/projects/command_connectors/src/serializers/success_serializer.rb +14 -0
  134. data/projects/command_connectors/src/serializers/yaml_serializer.rb +20 -0
  135. data/projects/command_connectors/src/transformers/auth_errors_transformer.rb +35 -0
  136. data/projects/command_connectors/src/transformers/load_aggregates_pre_commit_transformer.rb +36 -0
  137. data/projects/command_connectors_http/lib/foobara/command_connectors_http.rb +6 -0
  138. data/projects/command_connectors_http/src/http/commands/get_options.rb +16 -0
  139. data/projects/command_connectors_http/src/http/commands/help/presenter/command.rb +14 -0
  140. data/projects/command_connectors_http/src/http/commands/help/presenter/domain.rb +14 -0
  141. data/projects/command_connectors_http/src/http/commands/help/presenter/entity.rb +14 -0
  142. data/projects/command_connectors_http/src/http/commands/help/presenter/error.rb +14 -0
  143. data/projects/command_connectors_http/src/http/commands/help/presenter/model.rb +14 -0
  144. data/projects/command_connectors_http/src/http/commands/help/presenter/organization.rb +14 -0
  145. data/projects/command_connectors_http/src/http/commands/help/presenter/processor.rb +14 -0
  146. data/projects/command_connectors_http/src/http/commands/help/presenter/processor_class.rb +14 -0
  147. data/projects/command_connectors_http/src/http/commands/help/presenter/root.rb +14 -0
  148. data/projects/command_connectors_http/src/http/commands/help/presenter/type.rb +14 -0
  149. data/projects/command_connectors_http/src/http/commands/help/presenter.rb +162 -0
  150. data/projects/command_connectors_http/src/http/commands/help/templates/command.html.erb +11 -0
  151. data/projects/command_connectors_http/src/http/commands/help/templates/domain.html.erb +1 -0
  152. data/projects/command_connectors_http/src/http/commands/help/templates/entity.html.erb +1 -0
  153. data/projects/command_connectors_http/src/http/commands/help/templates/error.html.erb +1 -0
  154. data/projects/command_connectors_http/src/http/commands/help/templates/model.html.erb +1 -0
  155. data/projects/command_connectors_http/src/http/commands/help/templates/organization.html.erb +1 -0
  156. data/projects/command_connectors_http/src/http/commands/help/templates/processor.html.erb +1 -0
  157. data/projects/command_connectors_http/src/http/commands/help/templates/processor_class.html.erb +1 -0
  158. data/projects/command_connectors_http/src/http/commands/help/templates/root.html.erb +3 -0
  159. data/projects/command_connectors_http/src/http/commands/help/templates/type.html.erb +1 -0
  160. data/projects/command_connectors_http/src/http/commands/help.rb +98 -0
  161. data/projects/command_connectors_http/src/http/request.rb +98 -0
  162. data/projects/command_connectors_http/src/http/response.rb +14 -0
  163. data/projects/command_connectors_http/src/http.rb +84 -0
  164. data/projects/common/lib/foobara/common.rb +11 -0
  165. data/projects/common/src/data_path.rb +272 -0
  166. data/projects/common/src/error.rb +215 -0
  167. data/projects/common/src/error_collection.rb +97 -0
  168. data/projects/common/src/error_key.rb +168 -0
  169. data/projects/common/src/outcome.rb +101 -0
  170. data/projects/common/src/possible_error.rb +80 -0
  171. data/projects/common/src/runtime_error.rb +24 -0
  172. data/projects/concerns/lib/foobara/concerns.rb +1 -0
  173. data/projects/concerns/src/concern.rb +93 -0
  174. data/projects/delegate/lib/foobara/delegate.rb +1 -0
  175. data/projects/delegate/src/extensions/module.rb +12 -0
  176. data/projects/domain/lib/foobara/domain.rb +25 -0
  177. data/projects/domain/src/domain.rb +65 -0
  178. data/projects/domain/src/domain_mapper/registry.rb +47 -0
  179. data/projects/domain/src/domain_mapper.rb +162 -0
  180. data/projects/domain/src/domain_module_extension.rb +510 -0
  181. data/projects/domain/src/extensions/foobara.rb +69 -0
  182. data/projects/domain/src/global_domain.rb +14 -0
  183. data/projects/domain/src/global_organization.rb +12 -0
  184. data/projects/domain/src/is_manifestable.rb +68 -0
  185. data/projects/domain/src/manifestable.rb +12 -0
  186. data/projects/domain/src/module_extension.rb +122 -0
  187. data/projects/domain/src/organization.rb +52 -0
  188. data/projects/domain/src/organization_module_extension.rb +50 -0
  189. data/projects/entity/lib/foobara/entity.rb +27 -0
  190. data/projects/entity/src/concerns/associations.rb +241 -0
  191. data/projects/entity/src/concerns/attributes.rb +170 -0
  192. data/projects/entity/src/concerns/callbacks.rb +97 -0
  193. data/projects/entity/src/concerns/initialization.rb +127 -0
  194. data/projects/entity/src/concerns/persistence.rb +142 -0
  195. data/projects/entity/src/concerns/primary_key.rb +43 -0
  196. data/projects/entity/src/concerns/queries.rb +96 -0
  197. data/projects/entity/src/concerns/reflection.rb +51 -0
  198. data/projects/entity/src/concerns/transactions.rb +31 -0
  199. data/projects/entity/src/concerns/types.rb +31 -0
  200. data/projects/entity/src/entity.rb +61 -0
  201. data/projects/entity/src/extensions/builtin_types/entity/casters/hash.rb +33 -0
  202. data/projects/entity/src/extensions/builtin_types/entity/validators/attributes_declaration.rb +32 -0
  203. data/projects/entity/src/extensions/builtin_types/entity.rb +6 -0
  204. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/attributes_handler_desugarizer.rb +14 -0
  205. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/hash_desugarizer.rb +43 -0
  206. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/model_class_desugarizer.rb +21 -0
  207. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/primary_key_desugarizer.rb +19 -0
  208. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/to_type_transformer.rb +64 -0
  209. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/validate_primary_key_is_symbol.rb +35 -0
  210. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/validate_primary_key_present.rb +27 -0
  211. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration/validate_primary_key_references_attribute.rb +36 -0
  212. data/projects/entity/src/extensions/type_declarations/handlers/extend_entity_type_declaration.rb +11 -0
  213. data/projects/entity/src/new_prepend.rb +21 -0
  214. data/projects/entity/src/not_found_error.rb +72 -0
  215. data/projects/enumerated/lib/foobara/enumerated.rb +1 -0
  216. data/projects/enumerated/src/accessors.rb +61 -0
  217. data/projects/enumerated/src/values.rb +121 -0
  218. data/projects/foobara/lib/foobara/all.rb +44 -0
  219. data/projects/in_memory_crud_driver/lib/foobara/in_memory_crud_driver.rb +3 -0
  220. data/projects/in_memory_crud_driver/src/in_memory.rb +10 -0
  221. data/projects/in_memory_crud_driver_minimal/lib/foobara/in_memory_crud_driver_minimal.rb +1 -0
  222. data/projects/in_memory_crud_driver_minimal/src/in_memory_minimal.rb +113 -0
  223. data/projects/manifest/lib/foobara/manifest.rb +4 -0
  224. data/projects/manifest/src/foobara/manifest/array.rb +13 -0
  225. data/projects/manifest/src/foobara/manifest/attributes.rb +40 -0
  226. data/projects/manifest/src/foobara/manifest/base_manifest.rb +161 -0
  227. data/projects/manifest/src/foobara/manifest/command.rb +59 -0
  228. data/projects/manifest/src/foobara/manifest/domain.rb +43 -0
  229. data/projects/manifest/src/foobara/manifest/entity.rb +35 -0
  230. data/projects/manifest/src/foobara/manifest/error.rb +33 -0
  231. data/projects/manifest/src/foobara/manifest/model.rb +43 -0
  232. data/projects/manifest/src/foobara/manifest/organization.rb +45 -0
  233. data/projects/manifest/src/foobara/manifest/possible_error.rb +30 -0
  234. data/projects/manifest/src/foobara/manifest/processor.rb +11 -0
  235. data/projects/manifest/src/foobara/manifest/processor_class.rb +11 -0
  236. data/projects/manifest/src/foobara/manifest/root_manifest.rb +112 -0
  237. data/projects/manifest/src/foobara/manifest/type.rb +86 -0
  238. data/projects/manifest/src/foobara/manifest/type_declaration.rb +117 -0
  239. data/projects/model/lib/foobara/model.rb +23 -0
  240. data/projects/model/src/concerns/reflection.rb +22 -0
  241. data/projects/model/src/concerns/types.rb +104 -0
  242. data/projects/model/src/extensions/builtin_types/model/casters/hash.rb +23 -0
  243. data/projects/model/src/extensions/builtin_types/model/transformers/mutable.rb +26 -0
  244. data/projects/model/src/extensions/builtin_types/model/validators/attributes_declaration.rb +33 -0
  245. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/attributes_handler_desugarizer.rb +24 -0
  246. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/hash_desugarizer.rb +32 -0
  247. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/model_class_desugarizer.rb +119 -0
  248. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/to_type_transformer.rb +57 -0
  249. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration.rb +21 -0
  250. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/hash_desugarizer.rb +37 -0
  251. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/model_class_type_desugarizer.rb +25 -0
  252. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/mutable_validator.rb +46 -0
  253. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/normalize_mutable_attributes_desugarizer.rb +28 -0
  254. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/to_type_transformer.rb +27 -0
  255. data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration.rb +31 -0
  256. data/projects/model/src/extensions/type_declarations/handlers/registered_type_declaration/model_class_desugarizer.rb +23 -0
  257. data/projects/model/src/model.rb +320 -0
  258. data/projects/monorepo/lib/foobara/monorepo/project.rb +52 -0
  259. data/projects/monorepo/lib/foobara/monorepo.rb +63 -0
  260. data/projects/namespace/lib/foobara/namespace.rb +4 -0
  261. data/projects/namespace/src/ambiguous_registry.rb +104 -0
  262. data/projects/namespace/src/base_registry.rb +66 -0
  263. data/projects/namespace/src/extensions/module.rb +5 -0
  264. data/projects/namespace/src/is_namespace.rb +352 -0
  265. data/projects/namespace/src/namespace/lookup_mode.rb +41 -0
  266. data/projects/namespace/src/namespace.rb +61 -0
  267. data/projects/namespace/src/namespace_helpers.rb +273 -0
  268. data/projects/namespace/src/prefixless_registry.rb +54 -0
  269. data/projects/namespace/src/scoped.rb +113 -0
  270. data/projects/namespace/src/unambiguous_registry.rb +65 -0
  271. data/projects/persistence/lib/foobara/persistence.rb +22 -0
  272. data/projects/persistence/src/entity_attributes_crud_driver.rb +241 -0
  273. data/projects/persistence/src/entity_base/table.rb +14 -0
  274. data/projects/persistence/src/entity_base/transaction/concerns/entity_callback_handling.rb +157 -0
  275. data/projects/persistence/src/entity_base/transaction/concerns/state_transitions.rb +83 -0
  276. data/projects/persistence/src/entity_base/transaction/concerns/transaction_tracking.rb +53 -0
  277. data/projects/persistence/src/entity_base/transaction/state_machine.rb +27 -0
  278. data/projects/persistence/src/entity_base/transaction.rb +163 -0
  279. data/projects/persistence/src/entity_base/transaction_table/concerns/queries.rb +42 -0
  280. data/projects/persistence/src/entity_base/transaction_table/concerns/record_tracking.rb +134 -0
  281. data/projects/persistence/src/entity_base/transaction_table.rb +620 -0
  282. data/projects/persistence/src/entity_base.rb +114 -0
  283. data/projects/persistence/src/persistence.rb +172 -0
  284. data/projects/state_machine/lib/foobara/state_machine.rb +1 -0
  285. data/projects/state_machine/src/callbacks.rb +158 -0
  286. data/projects/state_machine/src/log_entry.rb +13 -0
  287. data/projects/state_machine/src/state_machine.rb +91 -0
  288. data/projects/state_machine/src/sugar.rb +125 -0
  289. data/projects/state_machine/src/transition_log.rb +19 -0
  290. data/projects/state_machine/src/validations.rb +69 -0
  291. data/projects/thread_parent/lib/foobara/thread_parent.rb +1 -0
  292. data/projects/thread_parent/src/thread_parent.rb +38 -0
  293. data/projects/type_declarations/lib/foobara/type_declarations.rb +131 -0
  294. data/projects/type_declarations/src/attributes.rb +34 -0
  295. data/projects/type_declarations/src/caster.rb +7 -0
  296. data/projects/type_declarations/src/desugarizer.rb +25 -0
  297. data/projects/type_declarations/src/dsl/attributes.rb +199 -0
  298. data/projects/type_declarations/src/element_processor.rb +7 -0
  299. data/projects/type_declarations/src/error_extension.rb +73 -0
  300. data/projects/type_declarations/src/handlers/extend_array_type_declaration/array_desugarizer.rb +31 -0
  301. data/projects/type_declarations/src/handlers/extend_array_type_declaration/element_type_declaration_desugarizer.rb +37 -0
  302. data/projects/type_declarations/src/handlers/extend_array_type_declaration/to_type_transformer.rb +22 -0
  303. data/projects/type_declarations/src/handlers/extend_array_type_declaration/type_set_to_array_desugarizer.rb +36 -0
  304. data/projects/type_declarations/src/handlers/extend_array_type_declaration.rb +14 -0
  305. data/projects/type_declarations/src/handlers/extend_associative_array_type_declaration/to_type_transformer.rb +28 -0
  306. data/projects/type_declarations/src/handlers/extend_associative_array_type_declaration.rb +20 -0
  307. data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/dsl_desugarizer.rb +25 -0
  308. data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/element_type_declarations_desugarizer.rb +34 -0
  309. data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/hash_desugarizer.rb +60 -0
  310. data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/to_type_transformer.rb +21 -0
  311. data/projects/type_declarations/src/handlers/extend_attributes_type_declaration.rb +16 -0
  312. data/projects/type_declarations/src/handlers/extend_registered_type_declaration/to_type_transformer.rb +75 -0
  313. data/projects/type_declarations/src/handlers/extend_registered_type_declaration.rb +23 -0
  314. data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/array_desugarizer.rb +30 -0
  315. data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/to_type_transformer.rb +24 -0
  316. data/projects/type_declarations/src/handlers/extend_tuple_type_declaration.rb +13 -0
  317. data/projects/type_declarations/src/handlers/registered_type_declaration/desugarizer_metadata_cleanup_desugarizer.rb +29 -0
  318. data/projects/type_declarations/src/handlers/registered_type_declaration/short_type_name_desugarizer.rb +65 -0
  319. data/projects/type_declarations/src/handlers/registered_type_declaration/strict_desugarizer.rb +32 -0
  320. data/projects/type_declarations/src/handlers/registered_type_declaration/strict_stringified_desugarizer.rb +39 -0
  321. data/projects/type_declarations/src/handlers/registered_type_declaration/symbol_desugarizer.rb +26 -0
  322. data/projects/type_declarations/src/handlers/registered_type_declaration/to_type_transformer.rb +28 -0
  323. data/projects/type_declarations/src/handlers/registered_type_declaration/type_desugarizer.rb +24 -0
  324. data/projects/type_declarations/src/handlers/registered_type_declaration.rb +26 -0
  325. data/projects/type_declarations/src/processor.rb +7 -0
  326. data/projects/type_declarations/src/to_type_transformer.rb +11 -0
  327. data/projects/type_declarations/src/transformer.rb +7 -0
  328. data/projects/type_declarations/src/type_builder.rb +112 -0
  329. data/projects/type_declarations/src/type_declaration_error.rb +9 -0
  330. data/projects/type_declarations/src/type_declaration_handler.rb +120 -0
  331. data/projects/type_declarations/src/type_declaration_handler_registry.rb +27 -0
  332. data/projects/type_declarations/src/type_declaration_validator.rb +19 -0
  333. data/projects/type_declarations/src/type_declarations.rb +128 -0
  334. data/projects/type_declarations/src/typed_transformer.rb +89 -0
  335. data/projects/type_declarations/src/validator.rb +7 -0
  336. data/projects/type_declarations/src/with_registries.rb +41 -0
  337. data/projects/types/lib/foobara/types.rb +11 -0
  338. data/projects/types/src/element_processor.rb +7 -0
  339. data/projects/types/src/extensions/error.rb +32 -0
  340. data/projects/types/src/type/concerns/reflection.rb +79 -0
  341. data/projects/types/src/type/concerns/supported_processor_registration.rb +56 -0
  342. data/projects/types/src/type.rb +375 -0
  343. data/projects/types/src/types.rb +4 -0
  344. data/projects/value/lib/foobara/value.rb +7 -0
  345. data/projects/value/src/caster.rb +84 -0
  346. data/projects/value/src/data_error.rb +27 -0
  347. data/projects/value/src/processor/casting.rb +123 -0
  348. data/projects/value/src/processor/multi.rb +63 -0
  349. data/projects/value/src/processor/pipeline.rb +27 -0
  350. data/projects/value/src/processor/runner.rb +38 -0
  351. data/projects/value/src/processor/selection.rb +90 -0
  352. data/projects/value/src/processor.rb +358 -0
  353. data/projects/value/src/transformer.rb +84 -0
  354. data/projects/value/src/validator.rb +53 -0
  355. data/projects/version/lib/foobara/version.rb +4 -0
  356. data/projects/version/src/version.rb +5 -0
  357. data/projects/weak_object_set/lib/foobara/weak_object_set.rb +3 -0
  358. data/projects/weak_object_set/src/weak_object_set.rb +163 -0
  359. metadata +445 -0
@@ -0,0 +1,620 @@
1
+ module Foobara
2
+ module Persistence
3
+ class InvalidRecordError < StandardError
4
+ attr_accessor :record
5
+
6
+ def initialize(record)
7
+ self.record = record
8
+
9
+ super("Cannot persist invalid record #{record}: #{record.validation_errors}")
10
+ end
11
+ end
12
+
13
+ class EntityBase
14
+ # TODO: move this under Transaction
15
+ class TransactionTable
16
+ class NoRecordFound < StandardError; end
17
+
18
+ include Concerns::RecordTracking
19
+ include Concerns::Queries
20
+
21
+ attr_accessor :entity_attributes_crud_driver_table,
22
+ :entity_class,
23
+ :transaction
24
+
25
+ def initialize(transaction, entity_class)
26
+ self.transaction = transaction
27
+ self.entity_class = entity_class
28
+ self.entity_attributes_crud_driver_table = transaction.entity_attributes_crud_driver.table_for(entity_class)
29
+
30
+ super()
31
+ end
32
+
33
+ def find_tracked(record_id)
34
+ unless record_id
35
+ # :nocov:
36
+ raise ArgumentError, "Cannot use a blank primary key value"
37
+ # :nocov:
38
+ end
39
+
40
+ if record_id.is_a?(::String) && record_id.empty?
41
+ # :nocov:
42
+ raise ArgumentError, "Cannot use a blank primary key value"
43
+ # :nocov:
44
+ end
45
+
46
+ if record_id.is_a?(::Symbol) && record_id.to_s.empty?
47
+ # :nocov:
48
+ raise ArgumentError, "Cannot use a blank primary key value"
49
+ # :nocov:
50
+ end
51
+
52
+ tracked_records.find_by_key(record_id)
53
+ end
54
+
55
+ def first
56
+ found_attributes = normalize_attributes(entity_attributes_crud_driver_table.first)
57
+
58
+ if found_attributes
59
+ record_id = primary_key_for_attributes(found_attributes)
60
+
61
+ record = tracked_records.find_by_key(record_id) || transaction.loaded(entity_class, found_attributes)
62
+
63
+ record || marked_created.first
64
+ end
65
+ end
66
+
67
+ def load(entity_or_record_id)
68
+ if entity_or_record_id.is_a?(Entity)
69
+ if entity_or_record_id.loaded?
70
+ # :nocov:
71
+ raise "#{entity_or_record_id} is already loaded!"
72
+ # :nocov:
73
+ end
74
+
75
+ entity = tracked_records[entity_or_record_id]
76
+
77
+ if entity && !entity.equal?(entity_or_record_id)
78
+ # :nocov:
79
+ raise "This transaction is already tracking a different entity with the same primary key." \
80
+ "Try passing in the primary key instead of constructing an unloaded entity to pass in."
81
+ # :nocov:
82
+ end
83
+
84
+ record_id = entity.primary_key
85
+ else
86
+ record_id = entity_or_record_id
87
+
88
+ if record_id.is_a?(::Hash)
89
+ # :nocov:
90
+ raise ArgumentError, "Unlikely that you meant to use a hash as a primary key"
91
+ # :nocov:
92
+ end
93
+
94
+ unless record_id
95
+ # :nocov:
96
+ raise ArgumentError, "Cannot use a blank primary key value"
97
+ # :nocov:
98
+ end
99
+
100
+ if record_id.is_a?(::String) && record_id.empty?
101
+ # :nocov:
102
+ raise ArgumentError, "Cannot use a blank primary key value"
103
+ # :nocov:
104
+ end
105
+
106
+ if record_id.is_a?(::Symbol) && record_id.to_s.empty?
107
+ # :nocov:
108
+ raise ArgumentError, "Cannot use a blank primary key value"
109
+ # :nocov:
110
+ end
111
+
112
+ entity = tracked_records.find_by_key(record_id)
113
+
114
+ if entity&.loaded?
115
+ return entity
116
+ end
117
+ end
118
+
119
+ if entity
120
+ loading(entity) do
121
+ attributes = normalize_attributes(entity_attributes_crud_driver_table.find!(record_id))
122
+
123
+ unless attributes
124
+ # :nocov:
125
+ raise NoRecordFound, "could not find record for #{entity_class.full_entity_name}:#{record_id}"
126
+ # :nocov:
127
+ end
128
+
129
+ entity.successfully_loaded(attributes)
130
+ end
131
+ else
132
+ attributes = normalize_attributes(entity_attributes_crud_driver_table.find!(record_id))
133
+
134
+ unless attributes
135
+ # :nocov:
136
+ raise NoRecordFound, "could not find record for #{entity_class.full_entity_name}:#{record_id}"
137
+ # :nocov:
138
+ end
139
+
140
+ transaction.loaded(entity_class, attributes)
141
+ end
142
+ end
143
+
144
+ def load_many(record_ids_or_entities)
145
+ to_load_record_ids = []
146
+ entities = {}
147
+
148
+ record_ids_or_entities.each do |entity_or_record_id|
149
+ if entity_or_record_id.is_a?(Entity)
150
+ if entity_or_record_id.loaded?
151
+ next
152
+ end
153
+
154
+ entity = tracked_records[entity_or_record_id]
155
+
156
+ if entity && !entity.equal?(entity_or_record_id)
157
+ # :nocov:
158
+ raise "This transaction is already tracking a different entity with the same primary key." \
159
+ "Try passing in the primary key instead of constructing an unloaded entity to pass in."
160
+ # :nocov:
161
+ end
162
+
163
+ record_id = entity.primary_key
164
+ to_load_record_ids << record_id
165
+ entities[record_id] = entity
166
+ else
167
+ record_id = entity_or_record_id
168
+
169
+ if record_id.is_a?(::Hash)
170
+ # :nocov:
171
+ raise ArgumentError, "Unlikely that you meant to use a hash as a primary key"
172
+ # :nocov:
173
+ end
174
+
175
+ # TODO: encapsulate this record_id verification
176
+ unless record_id
177
+ # :nocov:
178
+ raise ArgumentError, "Cannot use a blank primary key value"
179
+ # :nocov:
180
+ end
181
+
182
+ if record_id.is_a?(::String) && record_id.empty?
183
+ # :nocov:
184
+ raise ArgumentError, "Cannot use a blank primary key value"
185
+ # :nocov:
186
+ end
187
+
188
+ if record_id.is_a?(::Symbol) && record_id.to_s.empty?
189
+ # :nocov:
190
+ raise ArgumentError, "Cannot use a blank primary key value"
191
+ # :nocov:
192
+ end
193
+
194
+ entity = tracked_records.find_by_key(record_id)
195
+
196
+ if entity
197
+ if entity.loaded?
198
+ entities[record_id] = entity
199
+ end
200
+ else
201
+ entities[record_id] = entity_class.thunk(record_id)
202
+ to_load_record_ids << record_id
203
+ end
204
+ end
205
+ end
206
+
207
+ entity_attributes_crud_driver_table.find_many!(to_load_record_ids).each do |attributes|
208
+ attributes = normalize_attributes(attributes)
209
+ record_id = primary_key_for_attributes(attributes)
210
+ entity = entities[record_id]
211
+ entity.successfully_loaded(attributes)
212
+ entities[record_id] = entity
213
+ end
214
+
215
+ record_ids_or_entities.map do |record_id_or_entity|
216
+ if record_id_or_entity.is_a?(Entity)
217
+ record_id_or_entity
218
+ else
219
+ entities[record_id_or_entity]
220
+ end
221
+ end
222
+ end
223
+
224
+ def find_by_attribute(attribute_name, value)
225
+ find_by(attribute_name => value)
226
+ end
227
+
228
+ def find_all_by_attribute(attribute_name, value)
229
+ find_many_by(attribute_name => value)
230
+ end
231
+
232
+ def find_by_attribute_containing(attribute_name, value)
233
+ value = entity_class.attributes_type.element_types[attribute_name].element_type.process_value!(value)
234
+
235
+ tracked_records.each do |record|
236
+ next if hard_deleted?(record)
237
+
238
+ # TODO: what if there are multiple??
239
+ if record.read_attribute(attribute_name).include?(value)
240
+ return record
241
+ end
242
+ end
243
+
244
+ found_attributes = entity_attributes_crud_driver_table.find_by_attribute_containing(
245
+ attribute_name,
246
+ to_persistable(value, false)
247
+ )
248
+
249
+ if found_attributes
250
+ entity_class.loaded(normalize_attributes(found_attributes))
251
+ end
252
+ end
253
+
254
+ def find_by(attributes_filter)
255
+ element_types = entity_class.attributes_type.element_types
256
+
257
+ attributes_filter = attributes_filter.to_h do |attribute_name, value|
258
+ [attribute_name, element_types[attribute_name].process_value!(value)]
259
+ end
260
+
261
+ attributes_filter = to_persistable(attributes_filter, false)
262
+
263
+ tracked_records.each do |record|
264
+ next if hard_deleted?(record)
265
+
266
+ if entity_attributes_crud_driver_table.matches_attributes_filter?(record.attributes, attributes_filter)
267
+ return record
268
+ end
269
+ end
270
+
271
+ found_attributes = entity_attributes_crud_driver_table.find_by(attributes_filter)
272
+
273
+ if found_attributes
274
+ found_attributes = normalize_attributes(found_attributes)
275
+ record_id = primary_key_for_attributes(found_attributes)
276
+
277
+ record = find_tracked(record_id)
278
+ return record if record
279
+
280
+ entity_class.loaded(found_attributes)
281
+ end
282
+ end
283
+
284
+ def find_many_by(attributes_filter)
285
+ attributes_filter = entity_class.attributes_type.process_value!(attributes_filter)
286
+
287
+ yielded_ids = Set.new
288
+
289
+ Enumerator.new do |yielder|
290
+ tracked_records.each do |record|
291
+ next if hard_deleted?(record)
292
+
293
+ if entity_attributes_crud_driver_table.matches_attributes_filter?(record.attributes, attributes_filter)
294
+ yielded_ids << record.primary_key
295
+ yielder << record
296
+ end
297
+ end
298
+
299
+ entity_attributes_crud_driver_table.find_many_by(attributes_filter).each do |found_attributes|
300
+ found_attributes = normalize_attributes(found_attributes)
301
+ record_id = primary_key_for_attributes(found_attributes)
302
+
303
+ next if yielded_ids.include?(record_id)
304
+
305
+ record = find_tracked(record_id) || entity_class.loaded(found_attributes)
306
+
307
+ yielder << record
308
+ end
309
+ end
310
+ end
311
+
312
+ def find_all_by_attribute_containing_any_of(attribute_name, values)
313
+ values = Util.array(values)
314
+ return [] if values.empty?
315
+
316
+ value_type = entity_class.attributes_type.element_types[attribute_name].element_type
317
+
318
+ values = values.map do |value|
319
+ value_type.process_value!(value)
320
+ end
321
+
322
+ yielded_ids = Set.new
323
+
324
+ Enumerator.new do |yielder|
325
+ tracked_records.each do |record|
326
+ next if hard_deleted?(record)
327
+
328
+ record_values = record.read_attribute(attribute_name)
329
+ next unless record_values
330
+ next if record_values.empty?
331
+
332
+ # TODO: what if there are multiple??
333
+ values.each do |value|
334
+ if record_values.include?(value)
335
+ yielded_ids << record.primary_key
336
+ yielder << record
337
+ end
338
+ end
339
+ end
340
+
341
+ values = values.map do |value|
342
+ to_persistable(value, false)
343
+ end
344
+
345
+ entity_attributes_crud_driver_table.find_all_by_attribute_containing_any_of(
346
+ attribute_name, values
347
+ ).each do |found_attributes|
348
+ found_attributes = normalize_attributes(found_attributes)
349
+ record_id = primary_key_for_attributes(found_attributes)
350
+
351
+ next if yielded_ids.include?(record_id)
352
+
353
+ record = find_tracked(record_id) || entity_class.loaded(found_attributes)
354
+
355
+ yielder << record
356
+ end
357
+ end
358
+ end
359
+
360
+ def find_all_by_attribute_any_of(attribute_name, values)
361
+ values = Util.array(values)
362
+ return [] if values.empty?
363
+
364
+ value_type = entity_class.attributes_type.element_types[attribute_name]
365
+
366
+ values = values.map do |value|
367
+ value_type.process_value!(value)
368
+ end
369
+
370
+ yielded_ids = Set.new
371
+
372
+ Enumerator.new do |yielder|
373
+ tracked_records.each do |record|
374
+ next if hard_deleted?(record)
375
+
376
+ record_value = record.read_attribute(attribute_name)
377
+
378
+ # TODO: what if there are multiple??
379
+ if values.include?(record_value)
380
+ yielded_ids << record.primary_key
381
+ yielder << record
382
+ end
383
+ end
384
+
385
+ values = values.map do |value|
386
+ to_persistable(value, false)
387
+ end
388
+
389
+ entity_attributes_crud_driver_table.find_all_by_attribute_any_of(
390
+ attribute_name, values
391
+ ).each do |found_attributes|
392
+ found_attributes = normalize_attributes(found_attributes)
393
+ record_id = primary_key_for_attributes(found_attributes)
394
+
395
+ next if yielded_ids.include?(record_id)
396
+
397
+ record = find_tracked(record_id) || entity_class.loaded(found_attributes)
398
+
399
+ yielder << record
400
+ end
401
+ end
402
+ end
403
+
404
+ def track_unloaded_thunk(record)
405
+ tracked(record)
406
+ end
407
+
408
+ def track_created(entity)
409
+ if entity.persisted?
410
+ # :nocov:
411
+ raise "Cannot insert #{entity} because it's already persisted."
412
+ # :nocov:
413
+ end
414
+
415
+ created(entity)
416
+ end
417
+
418
+ def track_loaded(entity)
419
+ tracked_records << entity
420
+ end
421
+
422
+ def hard_delete_all!
423
+ tracked_records.each do |record|
424
+ record.hard_delete! unless record.hard_deleted?
425
+ end
426
+
427
+ entity_attributes_crud_driver_table.hard_delete_all
428
+
429
+ all_hard_deleted
430
+ end
431
+
432
+ def count
433
+ persisted_count = entity_attributes_crud_driver_table.count
434
+
435
+ persisted_count + marked_created.count - marked_hard_deleted.count
436
+ end
437
+
438
+ def exists?(record_id)
439
+ record = tracked_records.find_by_key(record_id)
440
+ # TODO: stamp the fact that it exists on the record somehow or in the record_tracking concern.
441
+
442
+ (record && !record.hard_deleted? && (!record.persisted? || record.loaded?)) ||
443
+ entity_attributes_crud_driver_table.exists?(record_id)
444
+ end
445
+
446
+ def all_exist?(record_ids)
447
+ to_check_ids = record_ids.reject do |record_id|
448
+ record = tracked_records.find_by_key(record_id)
449
+ record && !record.hard_deleted? && (!record.persisted? || record.loaded?)
450
+ end
451
+
452
+ to_check_ids.empty? || entity_attributes_crud_driver_table.all_exist?(to_check_ids)
453
+ end
454
+
455
+ def primary_key_for_attributes(attributes)
456
+ attributes[entity_class.primary_key_attribute]
457
+ end
458
+
459
+ def to_persistable(object, initial = true)
460
+ case object
461
+ when Entity
462
+ if initial
463
+ to_persistable(object.attributes, false)
464
+ else
465
+ object.primary_key
466
+ end
467
+ when Model
468
+ to_persistable(object.attributes, false)
469
+ when ::Hash
470
+ object.transform_values do |value|
471
+ to_persistable(value, false)
472
+ end
473
+ when ::Array
474
+ object.map do |element|
475
+ to_persistable(element, false)
476
+ end
477
+ else
478
+ object
479
+ end
480
+ end
481
+
482
+ def validate!
483
+ marked_created.each do |record|
484
+ unless record.valid?
485
+ raise InvalidRecordError, record
486
+ end
487
+ end
488
+
489
+ marked_updated.each do |record|
490
+ unless record.valid?
491
+ raise InvalidRecordError, record
492
+ end
493
+ end
494
+ end
495
+
496
+ def flush_created!
497
+ marked_created.each do |record|
498
+ tracked_records.delete(record)
499
+
500
+ flush_created_associations!(record)
501
+
502
+ # TODO: do this in bulk
503
+ attributes = entity_attributes_crud_driver_table.insert(to_persistable(record))
504
+ record.write_attributes_without_callbacks(attributes)
505
+
506
+ # we need to update finding the tracked object by key and removing/reading it seems to be the simplest
507
+ # way to accomplish that at the moment
508
+ tracked_records << record
509
+
510
+ record.is_persisted = record.is_loaded = true
511
+ record.is_created = false
512
+ record.save_persisted_attributes
513
+ end
514
+
515
+ marked_created.clear
516
+ end
517
+
518
+ def flush_created_record!(record)
519
+ tracked_records.delete(record)
520
+
521
+ flush_created_associations!(record)
522
+
523
+ unmark_created(record)
524
+
525
+ attributes = entity_attributes_crud_driver_table.insert(to_persistable(record))
526
+ record.write_attributes_without_callbacks(attributes)
527
+
528
+ # we need to update finding the tracked object by key and removing/reading it seems to be the simplest
529
+ # way to accomplish that at the moment
530
+ tracked_records << record
531
+
532
+ record.is_persisted = record.is_loaded = true
533
+ record.is_created = false
534
+ record.save_persisted_attributes
535
+ end
536
+
537
+ def flush_created_associations!(record)
538
+ entity_class.associations.each_key do |association_data_path|
539
+ DataPath.values_at(association_data_path, record).each do |associated_record|
540
+ next unless associated_record.created?
541
+
542
+ transaction = Persistence::EntityBase::Transaction.open_transaction_for(associated_record)
543
+
544
+ unless transaction
545
+ # :nocov:
546
+ raise "No open transaction for #{associated_record}"
547
+ # :nocov:
548
+ end
549
+
550
+ if transaction.created?(associated_record)
551
+ transaction.flush_created_record!(associated_record)
552
+ end
553
+ end
554
+ end
555
+ end
556
+
557
+ def flush_updated_and_hard_deleted!
558
+ # TODO: use bulk operations to improve performance...
559
+ marked_updated.each do |record|
560
+ attributes = entity_attributes_crud_driver_table.update(to_persistable(record))
561
+ record.write_attributes_without_callbacks(attributes)
562
+ record.save_persisted_attributes
563
+ end
564
+
565
+ marked_updated.clear
566
+
567
+ # TODO: use bulk operations to improve performance...
568
+ marked_hard_deleted.each do |record|
569
+ entity_attributes_crud_driver_table.hard_delete(record.primary_key)
570
+ record.save_persisted_attributes
571
+ end
572
+
573
+ marked_hard_deleted.clear
574
+ end
575
+
576
+ def rollback!
577
+ # TODO: could pause record tracking while doing this as a performance boost
578
+ # is it really safe to do this without callbacks?? What about other systems listening
579
+ # to those callbacks? This feels wrong.
580
+ # TODO: fix this
581
+ marked_updated.each(&:restore_without_callbacks!)
582
+ marked_hard_deleted.each(&:restore_without_callbacks!)
583
+ marked_created.each(&:hard_delete_without_callbacks!)
584
+
585
+ rolled_back
586
+ end
587
+
588
+ def revert!
589
+ # TODO: could pause record tracking while doing this as a performance boost
590
+ marked_updated.each(&:restore_without_callbacks!)
591
+ marked_hard_deleted.each(&:restore_without_callbacks!)
592
+ marked_created.each(&:restore_without_callbacks!)
593
+
594
+ reverted
595
+ end
596
+
597
+ def tracking?(record)
598
+ tracked_records.include?(record)
599
+ end
600
+
601
+ private
602
+
603
+ def normalize_attributes(attributes)
604
+ if attributes
605
+ begin
606
+ attributes = attributes.transform_keys(&:to_sym)
607
+
608
+ primary_key_name = entity_class.primary_key_attribute
609
+ primary_key_value = attributes[primary_key_name]
610
+
611
+ attributes[primary_key_name] = entity_class.primary_key_type.cast!(primary_key_value)
612
+
613
+ attributes
614
+ end
615
+ end
616
+ end
617
+ end
618
+ end
619
+ end
620
+ end