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,69 @@
1
+ module Foobara
2
+ class << self
3
+ # TODO: come up with a way to change a type's manifest... Or maybe treat Model very differently?
4
+ # ok... new manifest will be of this form...
5
+ # { <orgs|commands|types, etc, letś call this a type category...> => full_scoped_name => manifest }
6
+ #
7
+ # The manifest itself will only contain full scoped names. This is kind of analogous to a store serializer
8
+ # in the http connector.
9
+ def manifest
10
+ to_include = Namespace.global.foobara_all_organization.to_set
11
+ included = {}
12
+
13
+ h = {}
14
+
15
+ until to_include.empty?
16
+ object = to_include.first
17
+ to_include.delete(object)
18
+
19
+ unless object.scoped_path_set?
20
+ # :nocov:
21
+ raise "no scoped path set for #{object}"
22
+ # :nocov:
23
+ end
24
+
25
+ manifest_reference = object.foobara_manifest_reference.to_sym
26
+ category_symbol = Namespace.global.foobara_category_symbol_for(object)
27
+
28
+ unless category_symbol
29
+ # :nocov:
30
+ raise "no category symbol for #{object}"
31
+ # :nocov:
32
+ end
33
+
34
+ if included.key?(manifest_reference)
35
+ if included[manifest_reference] == category_symbol
36
+ next
37
+ else
38
+ # :nocov:
39
+ raise "Collision for #{manifest_reference}: #{included[manifest_reference]} and #{category_symbol}"
40
+ # :nocov:
41
+ end
42
+ end
43
+
44
+ cat = h[category_symbol] ||= {}
45
+ cat[manifest_reference] = object.foobara_manifest(to_include:)
46
+
47
+ included[manifest_reference] = category_symbol
48
+ end
49
+
50
+ h.sort.to_h
51
+ end
52
+
53
+ def all_organizations
54
+ Namespace.global.foobara_all_organization
55
+ end
56
+
57
+ def all_domains
58
+ Namespace.global.foobara_all_domain
59
+ end
60
+
61
+ def all_commands
62
+ Namespace.global.foobara_all_command
63
+ end
64
+
65
+ def all_types
66
+ Namespace.global.foobara_all_type
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,14 @@
1
+ require_relative "global_organization"
2
+
3
+ module Foobara
4
+ module GlobalDomain
5
+ foobara_namespace!(scoped_path: [])
6
+ self.foobara_parent_namespace = GlobalOrganization
7
+ GlobalOrganization.foobara_register(self)
8
+
9
+ foobara_domain!
10
+ self.foobara_domain_name = "global_domain"
11
+ self.foobara_full_domain_name = "#{GlobalOrganization.foobara_organization_name}::#{foobara_domain_name}"
12
+ self.foobara_manifest_reference = foobara_full_domain_name
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ require_relative "module_extension"
2
+
3
+ module Foobara
4
+ module GlobalOrganization
5
+ foobara_namespace!(scoped_path: [])
6
+ self.foobara_parent_namespace = Namespace.global
7
+ foobara_parent_namespace.foobara_register(self)
8
+
9
+ foobara_organization!
10
+ self.foobara_manifest_reference = self.foobara_organization_name = "global_organization"
11
+ end
12
+ end
@@ -0,0 +1,68 @@
1
+ module Foobara
2
+ module IsManifestable
3
+ def scoped_clear_caches
4
+ [
5
+ # TODO: what about this one??
6
+ # "@created_in_namespace",
7
+ "@foobara_domain"
8
+ ].each do |variable|
9
+ remove_instance_variable(variable) if instance_variable_defined?(variable)
10
+ end
11
+ super
12
+ end
13
+
14
+ def foobara_domain
15
+ return @foobara_domain if defined?(@foobara_domain)
16
+
17
+ scoped = self
18
+
19
+ while scoped
20
+ if scoped.is_a?(::Module)
21
+ if scoped.foobara_domain?
22
+ return @foobara_domain = scoped
23
+ end
24
+ end
25
+
26
+ scoped = scoped.scoped_namespace
27
+ end
28
+
29
+ @foobara_domain = GlobalDomain
30
+ end
31
+
32
+ def foobara_organization
33
+ if is_a?(::Module) && foobara_organization?
34
+ self
35
+ else
36
+ foobara_domain.foobara_organization
37
+ end
38
+ end
39
+
40
+ def foobara_manifest(to_include: Set.new)
41
+ h = {
42
+ scoped_path:,
43
+ scoped_name:,
44
+ scoped_short_name:,
45
+ scoped_prefix:,
46
+ scoped_full_path:,
47
+ scoped_full_name:,
48
+ scoped_category:,
49
+ reference: foobara_manifest_reference,
50
+ domain: foobara_domain&.foobara_manifest_reference,
51
+ organization: foobara_organization&.foobara_manifest_reference
52
+ }
53
+
54
+ parent = scoped_namespace
55
+
56
+ if parent
57
+ parent_category = Namespace.global.foobara_category_symbol_for(parent)
58
+
59
+ if parent_category
60
+ to_include << parent
61
+ h[:parent] = [parent_category, parent.foobara_manifest_reference]
62
+ end
63
+ end
64
+
65
+ h
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,12 @@
1
+ require_relative "is_manifestable"
2
+
3
+ module Foobara
4
+ # Weird that this concept lives here instead of in its own project...
5
+ module Manifestable
6
+ include Concern
7
+
8
+ module ClassMethods
9
+ include IsManifestable
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,122 @@
1
+ require_relative "organization_module_extension"
2
+ require_relative "domain_module_extension"
3
+
4
+ module Foobara
5
+ module Domain
6
+ # TODO: should we just couple domain project and commands project to simplify this connection?
7
+ # TODO: move this stuff to extensions/ directory
8
+ module ModuleExtension
9
+ class CannotBeOrganizationAndDomainAtSameTime < StandardError; end
10
+
11
+ def foobara_domain!
12
+ if foobara_organization?
13
+ # :nocov:
14
+ raise CannotBeOrganizationAndDomainAtSameTime
15
+ # :nocov:
16
+ end
17
+
18
+ include(DomainModuleExtension)
19
+
20
+ unless is_a?(Namespace::IsNamespace)
21
+ foobara_namespace!
22
+ foobara_autoset_namespace!(default_namespace: Foobara::GlobalOrganization)
23
+ foobara_autoset_scoped_path!
24
+
25
+ # TODO: wow this is awkward. We should find a cleaner way to set children on namespaces.
26
+ parent = foobara_parent_namespace
27
+ parent.foobara_register(self)
28
+ self.foobara_parent_namespace = parent
29
+ end
30
+
31
+ children = foobara_children
32
+ children = children.sort_by { |child| child.scoped_path.size }
33
+
34
+ # see if we are upgrading from prefix to domain and copy over types to Types module
35
+ children.each do |child|
36
+ next unless child.is_a?(Types::Type)
37
+
38
+ types_mod_path = scoped_full_path.dup
39
+ unless child.scoped_path.first == "Types"
40
+ types_mod_path << "Types"
41
+ end
42
+
43
+ types_mod_path += child.scoped_path[..-2]
44
+ types_mod = Util.make_module_p(types_mod_path.join("::"))
45
+
46
+ # TODO: dry this up
47
+ # TODO: this doesn't handle a type nested under a lower-case type for now
48
+ if child.scoped_short_name =~ /^[a-z]/
49
+ unless types_mod.respond_to?(child.scoped_short_name)
50
+ types_mod.singleton_class.define_method child.scoped_short_name do
51
+ child
52
+ end
53
+
54
+ unless types_mod.instance_variable_defined?(:@foobara_lowercase_constants)
55
+ # TODO: test this path or delete it if unreachable
56
+ # :nocov:
57
+ types_mod.instance_variable_set(:@foobara_lowercase_constants, [])
58
+ # :nocov:
59
+ end
60
+
61
+ types_mod.instance_variable_get(:@foobara_lowercase_constants) << child.scoped_short_name
62
+ end
63
+ else
64
+ value = if types_mod.const_defined?(child.scoped_short_name, false)
65
+ # TODO: test this path or delete it if unreachable
66
+ # :nocov:
67
+ types_mod.const_get(child.scoped_short_name, false)
68
+ # :nocov:
69
+ end
70
+
71
+ if value != child
72
+ types_mod.send(:remove_const, child.scoped_short_name) if value
73
+ # TODO: can we decouple this from the model project?
74
+ new_value = if child.extends?("::model")
75
+ child.target_class
76
+ else
77
+ # TODO: test this path or delete it if unreachable
78
+ # :nocov:
79
+ child
80
+ # :nocov:
81
+ end
82
+ types_mod.const_set(child.scoped_short_name, new_value)
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ def foobara_organization!
89
+ if foobara_domain?
90
+ # :nocov:
91
+ raise CannotBeOrganizationAndDomainAtSameTime
92
+ # :nocov:
93
+ end
94
+
95
+ include(OrganizationModuleExtension)
96
+
97
+ unless is_a?(Namespace::IsNamespace)
98
+ foobara_namespace!
99
+ self.scoped_namespace = Namespace.global
100
+ foobara_autoset_scoped_path!(make_top_level: true)
101
+
102
+ # TODO: wow this is awkward. We should find a cleaner way to set children on namespaces.
103
+ parent = foobara_parent_namespace
104
+ parent.foobara_register(self)
105
+ self.foobara_parent_namespace = parent
106
+ end
107
+ end
108
+
109
+ def foobara_domain?
110
+ false
111
+ end
112
+
113
+ def foobara_organization?
114
+ false
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ Module.include(Foobara::Domain::ModuleExtension)
121
+
122
+ Foobara.foobara_organization!
@@ -0,0 +1,52 @@
1
+ module Foobara
2
+ module Organization
3
+ class OrganizationAlreadyExistsError < StandardError; end
4
+ class NoSuchOrganization < StandardError; end
5
+
6
+ class << self
7
+ # TODO: move this to organization.rb
8
+ def to_organization(object)
9
+ case object
10
+ when nil
11
+ GlobalOrganization
12
+ when ::String, ::Symbol
13
+ organization = Namespace.global.foobara_lookup_organization(object)
14
+
15
+ unless organization
16
+ # :nocov:
17
+ raise NoSuchOrganization, "Couldn't determine organization for #{object}"
18
+ # :nocov:
19
+ end
20
+
21
+ organization
22
+ when Foobara::Scoped
23
+ if object.is_a?(Module) && object.foobara_organization?
24
+ object
25
+ else
26
+ parent = object.scoped_namespace
27
+
28
+ if parent
29
+ to_organization(parent)
30
+ else
31
+ GlobalOrganization
32
+ end
33
+ end
34
+ else
35
+ # :nocov:
36
+ raise NoSuchOrganization, "Couldn't determine organization for #{object}"
37
+ # :nocov:
38
+ end
39
+ end
40
+
41
+ def create(full_organization_name)
42
+ if Organization.to_organization(full_organization_name)
43
+ # :nocov:
44
+ raise OrganizationAlreadyExistsError, "Organization #{full_organization_name} already exists"
45
+ # :nocov:
46
+ end
47
+ rescue Organization::NoSuchOrganization
48
+ Util.make_module_p(full_organization_name) { foobara_organization! }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,50 @@
1
+ require_relative "manifestable"
2
+
3
+ module Foobara
4
+ module Domain
5
+ module OrganizationModuleExtension
6
+ # Does this really need to be a Concern?
7
+ include Concern
8
+ include Manifestable
9
+
10
+ module ClassMethods
11
+ attr_writer :foobara_organization_name, :foobara_full_organization_name
12
+
13
+ def foobara_organization_name
14
+ @foobara_organization_name || scoped_name
15
+ end
16
+
17
+ def foobara_full_organization_name
18
+ @foobara_full_organization_name || scoped_full_name
19
+ end
20
+
21
+ def foobara_organization?
22
+ true
23
+ end
24
+
25
+ def foobara_owns_domain?(domain)
26
+ foobara_each_domain(mode: Namespace::LookupMode::DIRECT) do |d|
27
+ if d == domain || (d == domain.mod if domain.respond_to?(:mod))
28
+ return true
29
+ end
30
+ end
31
+
32
+ false
33
+ end
34
+
35
+ def foobara_domains
36
+ foobara_all_domain(mode: Namespace::LookupMode::DIRECT)
37
+ end
38
+
39
+ def foobara_manifest(to_include:)
40
+ domains = foobara_domains.map do |domain|
41
+ to_include << domain
42
+ domain.foobara_manifest_reference
43
+ end.sort
44
+
45
+ super.merge(domains:)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,27 @@
1
+ require "date"
2
+ require "time"
3
+ require "bigdecimal"
4
+
5
+ module Foobara
6
+ # TODO: I think we should have a configuration that indicates if created records can have primary keys past to them
7
+ # or not. That is, do primary keys get issued by the database upon insertion? Or are they generated externally
8
+ # and passed in? Would be nice to have programmatic clarification via explicit configuration.
9
+ class Entity < Model
10
+ abstract
11
+
12
+ class << self
13
+ def install!
14
+ TypeDeclarations.register_type_declaration(TypeDeclarations::Handlers::ExtendEntityTypeDeclaration.new)
15
+
16
+ model = Namespace.global.foobara_lookup_type!(:model)
17
+ BuiltinTypes.build_and_register!(:entity, model, nil)
18
+ end
19
+
20
+ def reset_all
21
+ Entity::Concerns::Callbacks.reset_all
22
+
23
+ install!
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,241 @@
1
+ module Foobara
2
+ class Entity < Model
3
+ module Concerns
4
+ module Associations
5
+ include Concern
6
+
7
+ module ClassMethods
8
+ def associations
9
+ @associations ||= construct_associations
10
+ end
11
+
12
+ def deep_associations
13
+ @deep_associations ||= begin
14
+ deep = {}
15
+
16
+ associations.each_pair do |data_path, type|
17
+ deep[data_path] = type
18
+
19
+ entity_class = type.target_class
20
+
21
+ entity_class.deep_associations.each_pair do |sub_data_path, sub_type|
22
+ deep["#{data_path}.#{sub_data_path}"] = sub_type
23
+ end
24
+ end
25
+
26
+ deep
27
+ end
28
+ end
29
+
30
+ # TODO: stamp this metadata out somewhere, preferably on deep_associations hash somehow
31
+ def association(name, *association_identifiers)
32
+ target_association_key = association_for(association_identifiers)
33
+
34
+ is_many = target_association_key.include?("#")
35
+
36
+ define_method name do
37
+ # TODO: memoize but with some smart cache busting
38
+ values = Foobara::DataPath.values_at(target_association_key, self)
39
+
40
+ if is_many
41
+ values
42
+ else
43
+ if values.size > 1
44
+ # :nocov:
45
+ raise "Multiple records found for #{name} association but only expected 0 or 1."
46
+ # :nocov:
47
+ end
48
+
49
+ unless values.empty?
50
+ values.first
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ def association_for(association_filters)
57
+ if association_filters.size == 1
58
+ data_path = association_filters.first.to_s
59
+
60
+ if deep_associations.key?(data_path)
61
+ return data_path
62
+ end
63
+ end
64
+
65
+ result = association_filters.inject(deep_associations.keys) do |filtered, filter|
66
+ filtered_associations(filter, filtered)
67
+ end
68
+
69
+ if result.empty?
70
+ # :nocov:
71
+ raise "Could not find association matching #{association_filters}"
72
+ # :nocov:
73
+ elsif result.size > 1
74
+ # :nocov:
75
+ raise "Multiple associations matched by #{association_filters}"
76
+ # :nocov:
77
+ else
78
+ result.first
79
+ end
80
+ end
81
+
82
+ def filtered_associations(filter, association_keys = deep_associations.keys)
83
+ if filter.is_a?(::Symbol)
84
+ filter = filter.to_s
85
+ end
86
+
87
+ if filter.is_a?(::String)
88
+ if filter =~ /[A-Z]/
89
+ association_keys.select do |key|
90
+ type = deep_associations[key]
91
+ entity_class = type.target_class
92
+ entity_class.full_entity_name.include?(filter)
93
+ end
94
+ else
95
+ association_keys.select do |key|
96
+ key.include?(filter)
97
+ end
98
+ end
99
+ elsif filter.is_a?(::Class) && filter < Entity
100
+ association_keys.select do |key|
101
+ type = deep_associations[key]
102
+ entity_class = type.target_class
103
+ entity_class == filter || entity_class < filter
104
+ end
105
+ else
106
+ # :nocov:
107
+ raise "Not sure how to apply filter #{filter}"
108
+ # :nocov:
109
+ end
110
+ end
111
+
112
+ def construct_associations(
113
+ type = attributes_type,
114
+ path = DataPath.new,
115
+ result = {}
116
+ )
117
+ if type.extends?(BuiltinTypes[:entity])
118
+ result[path.to_s] = type
119
+ elsif type.extends?(BuiltinTypes[:tuple])
120
+ element_types = type.element_types
121
+
122
+ element_types&.each&.with_index do |element_type, index|
123
+ construct_associations(element_type, path.append(index), result)
124
+ end
125
+ elsif type.extends?(BuiltinTypes[:array])
126
+ # TODO: what to do about an associative array type?? Unclear how to make a key from that...
127
+ # TODO: raise if associative array contains a non-persisted record to handle this edge case for now.
128
+ element_type = type.element_type
129
+
130
+ if element_type
131
+ construct_associations(element_type, path.append(:"#"), result)
132
+ end
133
+ elsif type.extends?(BuiltinTypes[:attributes])
134
+ type.element_types.each_pair do |attribute_name, element_type|
135
+ construct_associations(element_type, path.append(attribute_name), result)
136
+ end
137
+ elsif type.extends?(BuiltinTypes[:model])
138
+ construct_associations(type.target_class.attributes_type, path, result)
139
+ elsif type.extends?(BuiltinTypes[:associative_array])
140
+ # not going to bother testing this for now
141
+ # :nocov:
142
+ if contains_associations?(type)
143
+ raise "Associative array types with associations in them are not currently supported. " \
144
+ "Use attributes type if you can or set the key_type and/or value_type to duck type"
145
+ end
146
+ # :nocov:
147
+ end
148
+
149
+ result
150
+ end
151
+
152
+ def contains_associations?(type = entity_type, initial = true)
153
+ if type.extends?(BuiltinTypes[:entity])
154
+ if initial
155
+ contains_associations?(type.element_types, false)
156
+ else
157
+ true
158
+ end
159
+ elsif type.extends?(BuiltinTypes[:array])
160
+ # TODO: what to do about an associative array type?? Unclear how to make a key from that...
161
+ # TODO: raise if associative array contains a non-persisted record to handle this edge case for now.
162
+ element_type = type.element_type
163
+
164
+ if element_type
165
+ contains_associations?(element_type, false)
166
+ end
167
+ elsif type.extends?(BuiltinTypes[:attributes])
168
+ type.element_types.values.any? do |element_type|
169
+ contains_associations?(element_type, false)
170
+ end
171
+ elsif type.extends?(BuiltinTypes[:associative_array])
172
+ element_types = type.element_types
173
+
174
+ if element_types
175
+ key_type, value_type = element_types
176
+
177
+ contains_associations?(key_type, false) ||
178
+ contains_associations?(value_type, false)
179
+ end
180
+ end
181
+ end
182
+
183
+ def that_owns(record, filters = [])
184
+ containing_records = that_own(record, filters)
185
+
186
+ unless containing_records.empty?
187
+ if containing_records.size == 1
188
+ containing_records.first
189
+ else
190
+ # :nocov:
191
+ raise "Expected only one record to own #{record} but found #{containing_records.size}"
192
+ # :nocov:
193
+ end
194
+ end
195
+ end
196
+
197
+ def that_own(record, filters = [])
198
+ association_key = association_for([record.class, *filters])
199
+
200
+ data_path = DataPath.new(association_key)
201
+
202
+ done = false
203
+
204
+ containing_records = Util.array(record)
205
+
206
+ until done
207
+ last = data_path.path.last
208
+
209
+ if last == :"#"
210
+ method = :find_all_by_attribute_containing_any_of
211
+ attribute_name = data_path.path[-2]
212
+ data_path = DataPath.new(data_path.path[0..-3])
213
+ else
214
+ method = :find_all_by_attribute_any_of
215
+ attribute_name = last
216
+ data_path = DataPath.new(data_path.path[0..-2])
217
+ end
218
+
219
+ containing_entity_class_path = data_path.to_s
220
+
221
+ entity_class = if containing_entity_class_path.empty?
222
+ done = true
223
+ self
224
+ else
225
+ deep_associations[
226
+ containing_entity_class_path
227
+ ].target_class
228
+ end
229
+
230
+ containing_records = entity_class.send(method, attribute_name, containing_records).to_a
231
+
232
+ done = true unless containing_records
233
+ end
234
+
235
+ containing_records
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end