datashift 0.16.0 → 0.40.0
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.
- checksums.yaml +4 -4
- data/{LICENSE.txt → LICENSE} +0 -0
- data/Rakefile +1 -20
- data/datashift.thor +125 -0
- data/lib/applications/apache_poi_extensions.rb +21 -52
- data/lib/applications/excel.rb +64 -57
- data/lib/applications/hssf_row_extensions.rb +66 -0
- data/lib/applications/jexcel_file.rb +99 -95
- data/lib/applications/jexcel_file_extensions.rb +76 -83
- data/lib/applications/jruby/word.rb +36 -36
- data/lib/applications/ruby_poi_translations.rb +34 -32
- data/lib/applications/spreadsheet_extensions.rb +21 -19
- data/lib/datashift.rb +49 -59
- data/lib/datashift/binder.rb +217 -0
- data/lib/datashift/column_packer.rb +21 -72
- data/lib/datashift/configuration.rb +317 -0
- data/lib/datashift/context_factory.rb +88 -0
- data/lib/datashift/core_ext/array.rb +15 -0
- data/lib/datashift/core_ext/csv_ext.rb +46 -0
- data/lib/datashift/core_ext/string.rb +49 -0
- data/lib/datashift/core_ext/to_b.rb +11 -0
- data/lib/datashift/delimiters.rb +55 -61
- data/lib/datashift/doc_context.rb +137 -0
- data/lib/datashift/excel_base.rb +93 -81
- data/lib/datashift/exceptions.rb +30 -28
- data/lib/datashift/file_definitions.rb +44 -39
- data/lib/datashift/guards.rb +5 -5
- data/lib/datashift/header.rb +25 -0
- data/lib/datashift/headers.rb +94 -0
- data/lib/datashift/inbound_data/column.rb +44 -0
- data/lib/datashift/inbound_data/lookup_support.rb +33 -0
- data/lib/datashift/inbound_data/method_binding.rb +139 -0
- data/lib/datashift/load_object.rb +37 -12
- data/lib/datashift/logging.rb +54 -27
- data/lib/datashift/mandatory.rb +39 -0
- data/lib/datashift/mapping/data_flow_schema.rb +198 -0
- data/lib/datashift/{model_mapper.rb → mapping/mapper_utils.rb} +30 -10
- data/lib/datashift/model_methods/catalogue.rb +183 -0
- data/lib/datashift/model_methods/collection.rb +140 -0
- data/lib/datashift/model_methods/model_method.rb +162 -0
- data/lib/datashift/model_methods/model_methods_manager.rb +76 -0
- data/lib/datashift/model_methods/operator.rb +62 -0
- data/lib/datashift/node_collection.rb +26 -0
- data/lib/datashift/node_context.rb +68 -0
- data/lib/datashift/populator.rb +308 -282
- data/lib/datashift/progress_monitor.rb +91 -0
- data/lib/datashift/querying.rb +110 -52
- data/lib/datashift/templates/import_export_config.erb +55 -0
- data/lib/datashift/transformation/factory.rb +219 -0
- data/lib/datashift/transformation/remove.rb +44 -0
- data/lib/datashift/version.rb +3 -0
- data/lib/exporters/configuration.rb +84 -0
- data/lib/exporters/csv_exporter.rb +54 -52
- data/lib/exporters/excel_exporter.rb +80 -61
- data/lib/exporters/exporter_base.rb +8 -8
- data/lib/generators/config_generator.rb +218 -0
- data/lib/generators/csv_generator.rb +13 -70
- data/lib/generators/excel_generator.rb +23 -111
- data/lib/generators/generator_base.rb +15 -70
- data/lib/loaders/configuration.rb +90 -0
- data/lib/loaders/csv_loader.rb +63 -101
- data/lib/loaders/excel_loader.rb +71 -156
- data/lib/loaders/failure_data.rb +40 -0
- data/lib/loaders/file_loader.rb +16 -0
- data/lib/loaders/loader_base.rb +82 -410
- data/lib/loaders/loader_factory.rb +42 -0
- data/lib/loaders/paperclip/attachment_loader.rb +157 -140
- data/lib/loaders/paperclip/datashift_paperclip.rb +18 -35
- data/lib/loaders/paperclip/image_loading.rb +40 -35
- data/lib/loaders/reporters/basic_stdout_reporter.rb +40 -0
- data/lib/loaders/reporters/reporter.rb +26 -0
- data/lib/tasks/config.thor +65 -0
- data/{tasks → lib/tasks}/config/seed_fu_product_template.erb +0 -0
- data/{tasks → lib/tasks}/config/tidy_config.txt +0 -0
- data/lib/tasks/export.thor +192 -0
- data/lib/tasks/generate.thor +190 -0
- data/lib/tasks/import.thor +142 -0
- data/lib/{thor → tasks}/paperclip.thor +69 -69
- data/{tasks → lib/tasks/to_convert_to_thor}/db_tasks.rake +20 -20
- data/lib/tasks/tools.thor +109 -0
- data/spec/MissingAttachmentRecords/DEMO_001_ror_bag.jpeg +0 -0
- data/spec/MissingAttachmentRecords/DEMO_002_Powerstation.jpeg +0 -0
- data/spec/MissingAttachmentRecords/DEMO_003_ror_mug.jpeg +0 -0
- data/spec/MissingAttachmentRecords/DEMO_004_ror_ringer.jpeg +0 -0
- data/spec/datashift/binder_spec.rb +266 -0
- data/spec/datashift/config_generator_spec.rb +186 -0
- data/spec/datashift/configuration.rb +66 -0
- data/spec/datashift/context_factory_spec.rb +63 -0
- data/spec/datashift/data_flow_schema_spec.rb +150 -0
- data/spec/datashift/datashift_spec.rb +52 -0
- data/spec/datashift/excel_base_spec.rb +57 -0
- data/spec/datashift/excel_spec.rb +188 -0
- data/spec/datashift/failure_data_spec.rb +27 -0
- data/spec/{file_definitions.rb → datashift/file_definitions.rb} +9 -10
- data/spec/datashift/headers_spec.rb +56 -0
- data/spec/datashift/inbound_data_spec.rb +47 -0
- data/spec/datashift/mapper_utils_spec.rb +38 -0
- data/spec/datashift/method_binding_spec.rb +60 -0
- data/spec/datashift/model_method_spec.rb +109 -0
- data/spec/datashift/model_methods_catalogue.rb +111 -0
- data/spec/datashift/model_methods_collection_spec.rb +138 -0
- data/spec/datashift/model_methods_manager_spec.rb +329 -0
- data/spec/datashift/populator_spec.rb +117 -0
- data/spec/datashift/thor_spec.rb +314 -0
- data/spec/datashift/transformation/factory_spec.rb +195 -0
- data/spec/datashift/transformation/transformer_remove_spec.rb +43 -0
- data/spec/dummy/Gemfile +53 -0
- data/spec/dummy/Gemfile.lock +197 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +16 -0
- data/spec/dummy/app/assets/javascripts/categories.js +2 -0
- data/spec/dummy/app/assets/javascripts/digitals.js +2 -0
- data/spec/dummy/app/assets/javascripts/empties.js +2 -0
- data/spec/dummy/app/assets/javascripts/loader_releases.js +2 -0
- data/spec/dummy/app/assets/javascripts/long_and_complex_table_linked_to_versions.js +2 -0
- data/spec/dummy/app/assets/javascripts/milestones.js +2 -0
- data/spec/dummy/app/assets/javascripts/owners.js +2 -0
- data/spec/dummy/app/assets/javascripts/projects.js +2 -0
- data/spec/dummy/app/assets/javascripts/users.js +2 -0
- data/spec/dummy/app/assets/javascripts/versions.js +2 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/assets/stylesheets/categories.css +4 -0
- data/spec/dummy/app/assets/stylesheets/digitals.css +4 -0
- data/spec/dummy/app/assets/stylesheets/empties.css +4 -0
- data/spec/dummy/app/assets/stylesheets/loader_releases.css +4 -0
- data/spec/dummy/app/assets/stylesheets/long_and_complex_table_linked_to_versions.css +4 -0
- data/spec/dummy/app/assets/stylesheets/milestones.css +4 -0
- data/spec/dummy/app/assets/stylesheets/owners.css +4 -0
- data/spec/dummy/app/assets/stylesheets/projects.css +4 -0
- data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/spec/dummy/app/assets/stylesheets/users.css +4 -0
- data/spec/dummy/app/assets/stylesheets/versions.css +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/categories_controller.rb +58 -0
- data/spec/dummy/app/controllers/digitals_controller.rb +58 -0
- data/spec/dummy/app/controllers/empties_controller.rb +58 -0
- data/spec/dummy/app/controllers/loader_releases_controller.rb +58 -0
- data/spec/dummy/app/controllers/long_and_complex_table_linked_to_versions_controller.rb +58 -0
- data/spec/dummy/app/controllers/milestones_controller.rb +58 -0
- data/spec/dummy/app/controllers/owners_controller.rb +58 -0
- data/spec/dummy/app/controllers/projects_controller.rb +58 -0
- data/spec/dummy/app/controllers/users_controller.rb +58 -0
- data/spec/dummy/app/controllers/versions_controller.rb +58 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/helpers/categories_helper.rb +2 -0
- data/spec/dummy/app/helpers/digitals_helper.rb +2 -0
- data/spec/dummy/app/helpers/empties_helper.rb +2 -0
- data/spec/dummy/app/helpers/loader_releases_helper.rb +2 -0
- data/spec/dummy/app/helpers/long_and_complex_table_linked_to_versions_helper.rb +2 -0
- data/spec/dummy/app/helpers/milestones_helper.rb +2 -0
- data/spec/dummy/app/helpers/owners_helper.rb +2 -0
- data/spec/dummy/app/helpers/projects_helper.rb +2 -0
- data/spec/dummy/app/helpers/users_helper.rb +2 -0
- data/spec/dummy/app/helpers/versions_helper.rb +2 -0
- data/spec/dummy/app/models/category.rb +6 -0
- data/spec/dummy/app/models/digital.rb +22 -0
- data/spec/dummy/app/models/empty.rb +2 -0
- data/spec/dummy/app/models/loader_release.rb +10 -0
- data/spec/dummy/app/models/long_and_complex_table_linked_to_version.rb +6 -0
- data/spec/dummy/app/models/milestone.rb +15 -0
- data/spec/dummy/app/models/owner.rb +13 -0
- data/spec/dummy/app/models/project.rb +53 -0
- data/spec/dummy/app/models/user.rb +5 -0
- data/spec/dummy/app/models/version.rb +7 -0
- data/spec/dummy/app/views/categories/_form.html.erb +17 -0
- data/spec/dummy/app/views/categories/edit.html.erb +6 -0
- data/spec/dummy/app/views/categories/index.html.erb +25 -0
- data/spec/dummy/app/views/categories/new.html.erb +5 -0
- data/spec/dummy/app/views/categories/show.html.erb +4 -0
- data/spec/dummy/app/views/digitals/_form.html.erb +17 -0
- data/spec/dummy/app/views/digitals/edit.html.erb +6 -0
- data/spec/dummy/app/views/digitals/index.html.erb +25 -0
- data/spec/dummy/app/views/digitals/new.html.erb +5 -0
- data/spec/dummy/app/views/digitals/show.html.erb +4 -0
- data/spec/dummy/app/views/empties/_form.html.erb +17 -0
- data/spec/dummy/app/views/empties/edit.html.erb +6 -0
- data/spec/dummy/app/views/empties/index.html.erb +25 -0
- data/spec/dummy/app/views/empties/new.html.erb +5 -0
- data/spec/dummy/app/views/empties/show.html.erb +4 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/loader_releases/_form.html.erb +17 -0
- data/spec/dummy/app/views/loader_releases/edit.html.erb +6 -0
- data/spec/dummy/app/views/loader_releases/index.html.erb +25 -0
- data/spec/dummy/app/views/loader_releases/new.html.erb +5 -0
- data/spec/dummy/app/views/loader_releases/show.html.erb +4 -0
- data/spec/dummy/app/views/long_and_complex_table_linked_to_versions/_form.html.erb +17 -0
- data/spec/dummy/app/views/long_and_complex_table_linked_to_versions/edit.html.erb +6 -0
- data/spec/dummy/app/views/long_and_complex_table_linked_to_versions/index.html.erb +25 -0
- data/spec/dummy/app/views/long_and_complex_table_linked_to_versions/new.html.erb +5 -0
- data/spec/dummy/app/views/long_and_complex_table_linked_to_versions/show.html.erb +4 -0
- data/spec/dummy/app/views/milestones/_form.html.erb +17 -0
- data/spec/dummy/app/views/milestones/edit.html.erb +6 -0
- data/spec/dummy/app/views/milestones/index.html.erb +25 -0
- data/spec/dummy/app/views/milestones/new.html.erb +5 -0
- data/spec/dummy/app/views/milestones/show.html.erb +4 -0
- data/spec/dummy/app/views/owners/_form.html.erb +17 -0
- data/spec/dummy/app/views/owners/edit.html.erb +6 -0
- data/spec/dummy/app/views/owners/index.html.erb +25 -0
- data/spec/dummy/app/views/owners/new.html.erb +5 -0
- data/spec/dummy/app/views/owners/show.html.erb +4 -0
- data/spec/dummy/app/views/projects/_form.html.erb +17 -0
- data/spec/dummy/app/views/projects/edit.html.erb +6 -0
- data/spec/dummy/app/views/projects/index.html.erb +25 -0
- data/spec/dummy/app/views/projects/new.html.erb +5 -0
- data/spec/dummy/app/views/projects/show.html.erb +4 -0
- data/spec/dummy/app/views/users/_form.html.erb +17 -0
- data/spec/dummy/app/views/users/edit.html.erb +6 -0
- data/spec/dummy/app/views/users/index.html.erb +25 -0
- data/spec/dummy/app/views/users/new.html.erb +5 -0
- data/spec/dummy/app/views/users/show.html.erb +4 -0
- data/spec/dummy/app/views/versions/_form.html.erb +17 -0
- data/spec/dummy/app/views/versions/edit.html.erb +6 -0
- data/spec/dummy/app/views/versions/index.html.erb +25 -0
- data/spec/dummy/app/views/versions/new.html.erb +5 -0
- data/spec/dummy/app/views/versions/show.html.erb +4 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +9 -0
- data/spec/dummy/bin/rake +9 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/bin/spring +16 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +26 -0
- data/spec/dummy/config/boot.rb +3 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +76 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20110803201325_create_test_bed.rb +98 -0
- data/spec/dummy/db/migrate/20121009161700_add_digitals.rb +24 -0
- data/spec/dummy/db/migrate/20161005123106_create_digitals.rb +8 -0
- data/spec/dummy/db/migrate/20161005123106_create_long_and_complex_table_linked_to_versions.rb +8 -0
- data/spec/dummy/db/migrate/20161005123107_create_loader_releases.rb +8 -0
- data/spec/dummy/db/migrate/20161005123108_create_owners.rb +8 -0
- data/spec/dummy/db/migrate/20161005123109_create_empties.rb +8 -0
- data/spec/dummy/db/migrate/20161005123110_create_projects.rb +8 -0
- data/spec/dummy/db/migrate/20161005123111_create_users.rb +8 -0
- data/spec/dummy/db/migrate/20161005123111_create_versions.rb +8 -0
- data/spec/dummy/db/migrate/20161005123112_create_milestones.rb +8 -0
- data/spec/dummy/db/migrate/20161005123113_create_categories.rb +8 -0
- data/spec/dummy/db/schema.rb +93 -0
- data/spec/dummy/db/seeds.rb +9 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +69 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/robots.txt +5 -0
- data/spec/dummy/sandbox_example.thor +4 -0
- data/spec/dummy/test/controllers/categories_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/digitals_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/empties_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/loader_releases_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/long_and_complex_table_linked_to_versions_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/milestones_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/owners_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/projects_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/users_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/versions_controller_test.rb +49 -0
- data/spec/dummy/test/factories/categories.rb +5 -0
- data/spec/dummy/test/factories/digitals.rb +5 -0
- data/spec/dummy/test/factories/empties.rb +5 -0
- data/spec/dummy/test/factories/loader_releases.rb +5 -0
- data/spec/dummy/test/factories/long_and_complex_table_linked_to_versions.rb +5 -0
- data/spec/dummy/test/factories/milestones.rb +5 -0
- data/spec/dummy/test/factories/owners.rb +5 -0
- data/spec/dummy/test/factories/projects.rb +5 -0
- data/spec/dummy/test/factories/users.rb +5 -0
- data/spec/dummy/test/factories/versions.rb +5 -0
- data/spec/dummy/test/models/category_test.rb +7 -0
- data/spec/dummy/test/models/digital_test.rb +7 -0
- data/spec/dummy/test/models/empty_test.rb +7 -0
- data/spec/dummy/test/models/loader_release_test.rb +7 -0
- data/spec/dummy/test/models/long_and_complex_table_linked_to_version_test.rb +7 -0
- data/spec/dummy/test/models/milestone_test.rb +7 -0
- data/spec/dummy/test/models/owner_test.rb +7 -0
- data/spec/dummy/test/models/project_test.rb +7 -0
- data/spec/dummy/test/models/user_test.rb +7 -0
- data/spec/dummy/test/models/version_test.rb +7 -0
- data/spec/dummy/test/test_helper.rb +10 -0
- data/spec/exporters/csv_exporter_spec.rb +240 -0
- data/spec/exporters/csv_generator_spec.rb +139 -0
- data/spec/exporters/excel_exporter_spec.rb +193 -0
- data/spec/exporters/excel_generator_spec.rb +181 -0
- data/spec/exporters/generator_base_spec.rb +45 -0
- data/spec/factories/categories.rb +7 -0
- data/spec/factories/factories.rb +18 -0
- data/spec/factories/milestone.rb +16 -0
- data/spec/factories/projects.rb +41 -0
- data/spec/fixtures/BadAssociationName.xls +0 -0
- data/spec/fixtures/DemoNegativeTesting.xls +0 -0
- data/spec/fixtures/ProjectConfiguration.yml +18 -0
- data/spec/fixtures/ProjectsMultiCategories.xls +0 -0
- data/spec/fixtures/ProjectsMultiCategoriesHeaderLookup.xls +0 -0
- data/spec/fixtures/ProjectsSingleCategories.xls +0 -0
- data/spec/fixtures/ProjectsSingleCategories.xlsx +0 -0
- data/spec/fixtures/SimpleProjects.xls +0 -0
- data/spec/fixtures/config/database.yml +28 -0
- data/spec/fixtures/csv/BadAssociationName.csv +6 -0
- data/spec/fixtures/csv/DemoNegativeTesting.csv +6 -0
- data/spec/fixtures/csv/ProjectsMultiCategories.csv +5 -0
- data/spec/fixtures/csv/ProjectsMultiCategoriesHeaderLookup.csv +5 -0
- data/spec/fixtures/csv/ProjectsSingleCategories.csv +5 -0
- data/spec/fixtures/csv/SimpleProjects.csv +4 -0
- data/spec/fixtures/db/migrate/20110803201325_create_test_bed.rb +98 -0
- data/spec/fixtures/db/migrate/20121009161700_add_digitals.rb +24 -0
- data/spec/fixtures/db/seeds.rb +9 -0
- data/spec/fixtures/images/DEMO_001_ror_bag.jpeg +0 -0
- data/spec/fixtures/images/DEMO_002_Powerstation.jpeg +0 -0
- data/spec/fixtures/images/DEMO_003_ror_mug.jpeg +0 -0
- data/spec/fixtures/images/DEMO_004_ror_ringer.jpeg +0 -0
- data/spec/fixtures/load_datashift.thor +3 -0
- data/spec/fixtures/models/category.rb +6 -0
- data/spec/fixtures/models/digital.rb +22 -0
- data/spec/fixtures/models/empty.rb +2 -0
- data/spec/fixtures/models/loader_release.rb +10 -0
- data/spec/fixtures/models/long_and_complex_table_linked_to_version.rb +6 -0
- data/spec/fixtures/models/milestone.rb +15 -0
- data/spec/fixtures/models/owner.rb +13 -0
- data/spec/fixtures/models/project.rb +53 -0
- data/spec/fixtures/models/user.rb +5 -0
- data/spec/fixtures/models/version.rb +7 -0
- data/spec/fixtures/results/exp_project_assoc_headers.xls +0 -0
- data/spec/fixtures/results/exp_project_collection_spec.csv +2 -0
- data/spec/fixtures/results/exp_project_export.xls +0 -0
- data/spec/fixtures/results/exp_project_first_export.xls +0 -0
- data/spec/fixtures/results/exp_project_plus_assoc.xls +0 -0
- data/spec/fixtures/results/exp_project_plus_assoc_export_spec.csv +9 -0
- data/spec/fixtures/results/gen_project_plus_assoc_template.xls +0 -0
- data/spec/fixtures/results/gen_project_plus_some_assoc_template.xls +0 -0
- data/spec/fixtures/results/gen_project_template.xls +0 -0
- data/spec/fixtures/results/project_and_assoc_in_hash_export.xls +0 -0
- data/spec/fixtures/results/project_and_assoc_in_json_export.csv +9 -0
- data/spec/fixtures/results/project_and_assoc_in_json_export.xls +0 -0
- data/spec/fixtures/results/project_export_spec_with_custom_delim_,.csv +2 -0
- data/spec/fixtures/results/project_export_spec_with_custom_delim_/302/243.csv +2 -0
- data/spec/fixtures/results/project_export_spec_with_custom_delim_/302/247.csv +2 -0
- data/spec/fixtures/results/project_plus_assoc_template.csv +1 -0
- data/spec/fixtures/results/project_plus_some_assoc_template.csv +1 -0
- data/spec/fixtures/results/project_remove_export_spec.csv +2 -0
- data/spec/fixtures/results/project_template.csv +1 -0
- data/spec/fixtures/results/project_with_methods_export_spec.csv +2 -0
- data/spec/fixtures/results/thor_spec_gen_project.csv +1 -0
- data/spec/fixtures/sandbox_example.thor +4 -0
- data/spec/fixtures/simple_export_spec.xls +0 -0
- data/spec/fixtures/simple_template_spec.xls +0 -0
- data/spec/fixtures/test_model_defs.rb +7 -0
- data/spec/loaders/csv_loader_spec.rb +206 -0
- data/spec/loaders/data_flow_excel_loader_spec.rb +290 -0
- data/spec/loaders/excel_loader_failures_spec.rb +67 -0
- data/spec/loaders/excel_loader_spec.rb +294 -0
- data/spec/loaders/loader_base_spec.rb +29 -0
- data/spec/loaders/paperclip_loader_spec.rb +106 -0
- data/spec/log/datashift.log +14930 -0
- data/spec/private/digitals/1/DEMO_003_ror_mug.jpeg +0 -0
- data/spec/private/digitals/2/DEMO_002_Powerstation.jpeg +0 -0
- data/spec/private/digitals/3/DEMO_004_ror_ringer.jpeg +0 -0
- data/spec/private/digitals/4/DEMO_001_ror_bag.jpeg +0 -0
- data/spec/spec_helper.rb +26 -230
- data/spec/support/clear_and_manage_contexts.rb +25 -0
- data/spec/support/database_cleaner.rb +32 -0
- data/spec/support/datashift_test_helpers.rb +153 -0
- data/spec/support/files_paths_helper.rb +13 -0
- data/spec/support/fixtures/results/mapping_template.yaml +15 -0
- data/spec/support/sandbox.rb +136 -0
- metadata +804 -85
- data/README.markdown +0 -274
- data/README.rdoc +0 -19
- data/VERSION +0 -1
- data/datashift.gemspec +0 -48
- data/lib/applications/jruby/old_pre_proxy_jexcel_file.rb +0 -437
- data/lib/datashift/data_transforms.rb +0 -83
- data/lib/datashift/mapping_file_definitions.rb +0 -88
- data/lib/datashift/mapping_service.rb +0 -91
- data/lib/datashift/method_detail.rb +0 -165
- data/lib/datashift/method_details_manager.rb +0 -95
- data/lib/datashift/method_dictionary.rb +0 -281
- data/lib/datashift/method_mapper.rb +0 -174
- data/lib/datashift/thor_base.rb +0 -38
- data/lib/generators/mapping_generator.rb +0 -112
- data/lib/helpers/core_ext/csv_file.rb +0 -33
- data/lib/helpers/core_ext/to_b.rb +0 -24
- data/lib/loaders/reporter.rb +0 -58
- data/lib/thor/export.thor +0 -175
- data/lib/thor/generate.thor +0 -191
- data/lib/thor/import.thor +0 -110
- data/lib/thor/mapping.thor +0 -65
- data/lib/thor/tools.thor +0 -84
- data/spec/Gemfile +0 -31
- data/spec/Gemfile.lock +0 -134
- data/spec/csv_exporter_spec.rb +0 -144
- data/spec/csv_generator_spec.rb +0 -159
- data/spec/csv_loader_spec.rb +0 -212
- data/spec/datashift_spec.rb +0 -55
- data/spec/excel_exporter_spec.rb +0 -199
- data/spec/excel_generator_spec.rb +0 -203
- data/spec/excel_loader_spec.rb +0 -237
- data/spec/excel_spec.rb +0 -203
- data/spec/loader_base_spec.rb +0 -166
- data/spec/mapping_spec.rb +0 -117
- data/spec/method_dictionary_spec.rb +0 -300
- data/spec/method_mapper_spec.rb +0 -100
- data/spec/model_mapper_spec.rb +0 -41
- data/spec/paperclip_loader_spec.rb +0 -92
- data/spec/populator_spec.rb +0 -128
- data/spec/thor_spec.rb +0 -90
- data/tasks/file_tasks.rake +0 -37
- data/tasks/word_to_seedfu.rake +0 -167
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Copyright:: (c) Autotelik Media Ltd 2016
|
|
2
|
+
# Author :: Tom Statter
|
|
3
|
+
# Date :: May 2016
|
|
4
|
+
# License:: MIT
|
|
5
|
+
#
|
|
6
|
+
# Details:: Holds the current context and load object related to a failure
|
|
7
|
+
#
|
|
8
|
+
module DataShift
|
|
9
|
+
|
|
10
|
+
class FailureData
|
|
11
|
+
|
|
12
|
+
attr_accessor :load_object
|
|
13
|
+
attr_accessor :node_context
|
|
14
|
+
|
|
15
|
+
attr_accessor :error_messages
|
|
16
|
+
|
|
17
|
+
# The database object, and the inbound context that failed
|
|
18
|
+
def initialize(load_object, node_context, error_messages = [])
|
|
19
|
+
@load_object = load_object
|
|
20
|
+
@node_context = node_context
|
|
21
|
+
|
|
22
|
+
@error_messages = [*error_messages]
|
|
23
|
+
|
|
24
|
+
@error_messages += load_object.errors.full_messages if(load_object)
|
|
25
|
+
@error_messages.uniq!
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def errors
|
|
29
|
+
error_messages
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def destroy_failed_object
|
|
33
|
+
if load_object.respond_to?('destroy') && !load_object.new_record?
|
|
34
|
+
load_object.destroy
|
|
35
|
+
reset
|
|
36
|
+
end if load_object
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Copyright:: (c) Autotelik Media Ltd 2015
|
|
2
|
+
# Author :: Tom Statter
|
|
3
|
+
# Date :: May 2015
|
|
4
|
+
# License:: MIT
|
|
5
|
+
#
|
|
6
|
+
# Details:: Module for File based loaders
|
|
7
|
+
#
|
|
8
|
+
module DataShift
|
|
9
|
+
|
|
10
|
+
module FileLoader
|
|
11
|
+
|
|
12
|
+
attr_reader :file_name
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
data/lib/loaders/loader_base.rb
CHANGED
|
@@ -1,232 +1,143 @@
|
|
|
1
|
-
# Copyright:: (c) Autotelik Media Ltd
|
|
1
|
+
# Copyright:: (c) Autotelik Media Ltd 2015
|
|
2
2
|
# Author :: Tom Statter
|
|
3
|
-
# Date :: Aug
|
|
3
|
+
# Date :: Aug 2015
|
|
4
4
|
# License:: MIT
|
|
5
5
|
#
|
|
6
6
|
# Details:: Base class for loaders, providing a process hook which populates a model,
|
|
7
7
|
# based on a method map and supplied value from a file - i.e a single column/row's string value.
|
|
8
8
|
# Note that although a single column, the string can be formatted to contain multiple values.
|
|
9
9
|
#
|
|
10
|
-
# Tightly coupled with
|
|
10
|
+
# Tightly coupled with Binder classes (in lib/engine) which contains full details of
|
|
11
11
|
# a file's column and it's correlated AR associations.
|
|
12
12
|
#
|
|
13
|
-
|
|
13
|
+
require 'datashift/binder'
|
|
14
|
+
require 'datashift/querying'
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
require 'datashift/querying'
|
|
16
|
+
module DataShift
|
|
17
17
|
|
|
18
18
|
class LoaderBase
|
|
19
19
|
|
|
20
20
|
include DataShift::Logging
|
|
21
21
|
include DataShift::Querying
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
attr_accessor :method_mapper
|
|
26
|
-
|
|
27
|
-
# The inbound row/line number
|
|
28
|
-
attr_accessor :current_row_idx
|
|
29
|
-
|
|
30
|
-
attr_accessor :load_object_class, :load_object
|
|
23
|
+
attr_accessor :file_name
|
|
24
|
+
attr_accessor :binder
|
|
31
25
|
|
|
32
|
-
attr_accessor :
|
|
33
|
-
attr_accessor :populator
|
|
26
|
+
attr_accessor :doc_context
|
|
34
27
|
|
|
35
|
-
|
|
28
|
+
# Fwd calls onto the DocumentContext
|
|
29
|
+
extend Forwardable
|
|
36
30
|
|
|
31
|
+
def_delegators :doc_context,
|
|
32
|
+
:load_object,
|
|
33
|
+
:loaded_count, :failed_count,
|
|
34
|
+
:headers, :reporters, :reporters=
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# Setup loading
|
|
42
|
-
#
|
|
43
|
-
# Options to drive building the method dictionary for a class, enabling headers to be mapped to operators on that class.
|
|
44
|
-
#
|
|
45
|
-
# Options
|
|
46
|
-
# :reload : Force load of the method dictionary for object_class even if already loaded
|
|
47
|
-
# :instance_methods : Include setter/delegate style instance methods for assignment, as well as AR columns
|
|
48
|
-
# :verbose : Verbose logging and to STDOUT
|
|
49
|
-
#
|
|
50
|
-
def initialize(object_class, object = nil, options = {})
|
|
51
|
-
@load_object_class = object_class
|
|
52
|
-
|
|
53
|
-
logger.info("Loading objects of type #{@load_object_class} (#{object}")
|
|
36
|
+
attr_reader :configuration
|
|
54
37
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
elsif(options[:populator].is_a?(Class))
|
|
58
|
-
options[:populator].new
|
|
59
|
-
else
|
|
60
|
-
DataShift::Populator.new
|
|
61
|
-
end
|
|
38
|
+
def initialize
|
|
39
|
+
@file_name = ''
|
|
62
40
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
#puts "DEBUG Building Method Dictionary for class #{object_class}"
|
|
41
|
+
@doc_context = DocContext.new(Object)
|
|
42
|
+
@binder = Binder.new
|
|
66
43
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
# Create dictionary of data on all possible 'setter' methods which can be used to
|
|
71
|
-
# populate or integrate an object of type @load_object_class
|
|
72
|
-
DataShift::MethodDictionary.build_method_details(@load_object_class)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
@method_mapper = DataShift::MethodMapper.new
|
|
76
|
-
@config = options.dup # clone can cause issues like 'can't modify frozen hash'
|
|
44
|
+
@configuration = DataShift::Loaders::Configuration.call
|
|
45
|
+
end
|
|
77
46
|
|
|
78
|
-
|
|
47
|
+
def setup_load_class(load_class)
|
|
48
|
+
@doc_context = DocContext.new( MapperUtils.ensure_class(load_class) )
|
|
49
|
+
end
|
|
79
50
|
|
|
80
|
-
|
|
51
|
+
def run(file_name, object_class)
|
|
52
|
+
@file_name = file_name
|
|
81
53
|
|
|
82
|
-
|
|
54
|
+
setup_load_class(object_class)
|
|
83
55
|
|
|
84
|
-
|
|
56
|
+
logger.info("Loading objects of type #{load_object_class}")
|
|
85
57
|
|
|
86
|
-
|
|
58
|
+
# no implementation - derived classes must implement
|
|
59
|
+
perform_load
|
|
87
60
|
end
|
|
88
61
|
|
|
89
|
-
|
|
90
|
-
# Based on filename call appropriate loading function
|
|
91
|
-
# Currently supports :
|
|
92
|
-
# Excel/Open Office files saved as .xls
|
|
93
|
-
# CSV files
|
|
94
|
-
#
|
|
95
|
-
# OPTIONS :
|
|
96
|
-
#
|
|
97
|
-
# [:dummy] : Perform a dummy run - attempt to load everything but then roll back
|
|
98
|
-
#
|
|
99
|
-
# strict : Raise an exception of any headers can't be mapped to an attribute/association
|
|
100
|
-
# ignore : List of column headers to ignore when building operator map
|
|
101
|
-
# mandatory : List of columns that must be present in headers
|
|
102
|
-
#
|
|
103
|
-
# force_inclusion : List of columns that do not map to any operator but should be includeed in processing.
|
|
104
|
-
# This provides the opportunity for loaders to provide specific methods to handle these fields
|
|
105
|
-
# when no direct operator is available on the model or it's associations
|
|
62
|
+
# Reset the loader, including database object to be populated, and load counts
|
|
106
63
|
#
|
|
107
|
-
def
|
|
108
|
-
|
|
109
|
-
|
|
64
|
+
def reset(object = nil)
|
|
65
|
+
doc_context.reset(object)
|
|
66
|
+
end
|
|
110
67
|
|
|
111
|
-
|
|
68
|
+
def abort_on_failure?
|
|
69
|
+
!! configuration.abort_on_failure
|
|
70
|
+
end
|
|
112
71
|
|
|
113
|
-
|
|
72
|
+
def load_object_class
|
|
73
|
+
doc_context.klass
|
|
74
|
+
end
|
|
114
75
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
perform_excel_load(file_name, options)
|
|
119
|
-
elsif(ext.casecmp('.csv') == 0)
|
|
120
|
-
perform_csv_load(file_name, options)
|
|
121
|
-
else
|
|
122
|
-
raise DataShift::UnsupportedFileType, "#{ext} files not supported - Try .csv or OpenOffice/Excel .xls"
|
|
123
|
-
end
|
|
76
|
+
def set_headers(headings)
|
|
77
|
+
logger.info("Setting parsed headers to [#{headings.inspect}]")
|
|
78
|
+
doc_context.headers = headings
|
|
124
79
|
end
|
|
125
80
|
|
|
126
81
|
def report
|
|
127
|
-
|
|
82
|
+
reporters.each(&:report)
|
|
128
83
|
end
|
|
129
84
|
|
|
130
85
|
# Core API
|
|
131
|
-
#
|
|
132
|
-
# Given a list of free text column names from a file,
|
|
133
|
-
# map all headers to a MethodDetail instance containing details on operator, look ups etc.
|
|
134
|
-
#
|
|
135
|
-
# These are available through @method_mapper.method_details
|
|
136
|
-
#
|
|
137
|
-
# Options:
|
|
138
|
-
# [:strict] : Raise an exception of any headers can't be mapped to an attribute/association
|
|
139
|
-
# [:ignore] : List of column headers to ignore when building operator map
|
|
140
|
-
# [:mandatory] : List of columns that must be present in headers
|
|
141
|
-
#
|
|
142
|
-
# [:force_inclusion] : List of columns that do not map to any operator but should be includeed in processing.
|
|
143
|
-
#
|
|
144
|
-
# This provides the opportunity for :
|
|
145
|
-
#
|
|
146
|
-
# 1) loaders to provide specific methods to handle these fields, when no direct operator
|
|
147
|
-
# is available on the model or it's associations
|
|
148
86
|
#
|
|
149
|
-
#
|
|
150
|
-
#
|
|
87
|
+
# Returns an instance of DataShift::Binder
|
|
88
|
+
#
|
|
89
|
+
# Given a list of free text column names from inbound headers,
|
|
90
|
+
# map all headers to a domain model containing details on operator, look ups etc.
|
|
91
|
+
#
|
|
92
|
+
# See configuration options
|
|
93
|
+
#
|
|
94
|
+
# [:ignore] : List of column headers to ignore when building operator ma
|
|
151
95
|
# [:include_all] : Include all headers in processing - takes precedence of :force_inclusion
|
|
152
96
|
#
|
|
153
|
-
def
|
|
154
|
-
@headers = headers
|
|
97
|
+
def bind_headers( headers )
|
|
155
98
|
|
|
156
|
-
|
|
99
|
+
logger.info("Binding #{headers.size} inbound headers to #{load_object_class.name}")
|
|
157
100
|
|
|
158
|
-
|
|
101
|
+
@binder ||= DataShift::Binder.new
|
|
159
102
|
|
|
160
103
|
begin
|
|
161
|
-
|
|
104
|
+
binder.map_inbound_headers(load_object_class, headers)
|
|
162
105
|
rescue => e
|
|
163
|
-
puts e.inspect, e.backtrace
|
|
164
106
|
logger.error("Failed to map header row to set of database operators : #{e.inspect}")
|
|
165
|
-
|
|
107
|
+
logger.error( e.backtrace )
|
|
108
|
+
raise MappingDefinitionError, 'Failed to map header row to set of database operators'
|
|
166
109
|
end
|
|
167
110
|
|
|
168
|
-
unless
|
|
169
|
-
logger.warn("Following headings couldn't be mapped to #{load_object_class}
|
|
170
|
-
|
|
171
|
-
end
|
|
111
|
+
unless binder.missing_bindings.empty?
|
|
112
|
+
logger.warn("Following headings couldn't be mapped to #{load_object_class}:")
|
|
113
|
+
binder.missing_bindings.each { |m| logger.warn("Heading [#{m.inbound_name}] - Index (#{m.inbound_index})") }
|
|
172
114
|
|
|
173
|
-
|
|
174
|
-
@method_mapper.missing_mandatory(mandatory).each { |er| puts "ERROR: Mandatory column missing - expected column '#{er}'" }
|
|
175
|
-
raise MissingMandatoryError, "Mandatory columns missing - please fix and retry."
|
|
115
|
+
raise MappingDefinitionError, "Missing mappings for columns : #{binder.missing_bindings.join(',')}" if configuration.strict
|
|
176
116
|
end
|
|
177
117
|
|
|
178
|
-
|
|
179
|
-
end
|
|
180
|
-
|
|
118
|
+
mandatory = DataShift::Mandatory.new(configuration.mandatory)
|
|
181
119
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
@populator.default_values.each do |dname, dv|
|
|
187
|
-
|
|
188
|
-
method_detail = MethodDictionary.find_method_detail( load_object_class, dname )
|
|
189
|
-
|
|
190
|
-
if(method_detail)
|
|
191
|
-
logger.debug "Applying default value [#{dname}] on (#{method_detail.operator})"
|
|
192
|
-
@populator.prepare_and_assign(method_detail, load_object, dv)
|
|
193
|
-
else
|
|
194
|
-
logger.warn "No operator found for default [#{dname}] trying basic assignment"
|
|
195
|
-
begin
|
|
196
|
-
@populator.insistent_assignment(load_object, dv, dname)
|
|
197
|
-
rescue
|
|
198
|
-
logger.error "Badly specified default - could not set #{dname}(#{dv})"
|
|
199
|
-
end
|
|
120
|
+
unless mandatory.contains_all?(binder)
|
|
121
|
+
mandatory.missing_columns.each do |er|
|
|
122
|
+
logger.error "Mandatory column missing - expected column '#{er}'"
|
|
200
123
|
end
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
# Core API - Given a single free text column name from a file, search method mapper for
|
|
205
|
-
# associated operator on base object class.
|
|
206
|
-
#
|
|
207
|
-
# If suitable association found, process row data and then assign to current load_object
|
|
208
|
-
def find_and_process(column_name, data)
|
|
209
|
-
|
|
210
|
-
puts "WARNING: MethodDictionary empty for class #{load_object_class}" unless(MethodDictionary.for?(load_object_class))
|
|
211
|
-
|
|
212
|
-
method_detail = MethodDictionary.find_method_detail( load_object_class, column_name )
|
|
213
124
|
|
|
214
|
-
|
|
215
|
-
process(method_detail, data)
|
|
216
|
-
else
|
|
217
|
-
puts "No matching method found for column #{column_name}"
|
|
218
|
-
@load_object.errors.add(:base, "No matching method found for column #{column_name}")
|
|
125
|
+
raise MissingMandatoryError, 'Mandatory columns missing - see logs - please fix and retry.'
|
|
219
126
|
end
|
|
127
|
+
|
|
128
|
+
binder
|
|
220
129
|
end
|
|
221
130
|
|
|
131
|
+
# We can bind inbound 'fields' to associated model columns, from any source, not just headers
|
|
132
|
+
alias bind_fields bind_headers
|
|
222
133
|
|
|
223
134
|
# Any Config under key 'LoaderBase' is merged over existing options - taking precedence.
|
|
224
|
-
#
|
|
135
|
+
#
|
|
225
136
|
# Any Config under a key equal to the full name of the Loader class (e.g DataShift::SpreeEcom::ImageLoader)
|
|
226
137
|
# is merged over existing options - taking precedence.
|
|
227
|
-
#
|
|
138
|
+
#
|
|
228
139
|
# Format :
|
|
229
|
-
#
|
|
140
|
+
#
|
|
230
141
|
# LoaderClass:
|
|
231
142
|
# option: value
|
|
232
143
|
#
|
|
@@ -234,260 +145,21 @@ module DataShift
|
|
|
234
145
|
|
|
235
146
|
logger.info("Reading Datashift loader config from: #{yaml_file.inspect}")
|
|
236
147
|
|
|
237
|
-
data = YAML
|
|
148
|
+
data = YAML.load( ERB.new( IO.read(yaml_file) ).result )
|
|
238
149
|
|
|
239
150
|
logger.info("Read Datashift config: #{data.inspect}")
|
|
240
151
|
|
|
241
|
-
|
|
242
|
-
@config.merge!(data['LoaderBase'])
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
if(data[self.class.name])
|
|
246
|
-
@config.merge!(data[self.class.name])
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
@populator.configure_from(load_object_class, yaml_file)
|
|
250
|
-
logger.info("Loader Options : #{@config.inspect}")
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
# Return the find_by (where) operator, if specified, otherwise use the heading operator.
|
|
255
|
-
# i.e where operator embedded in row ,takes precedence over operator in column heading
|
|
256
|
-
#
|
|
257
|
-
# Treat rest of the node as the value to use in the where clause e.g
|
|
258
|
-
# price:0.99
|
|
259
|
-
#
|
|
260
|
-
# Column headings will be used, if the row only contains data e.g
|
|
261
|
-
# 0.99
|
|
262
|
-
#
|
|
263
|
-
# We leave it to caller to manage any other aspects or problems in 'rest'
|
|
264
|
-
#
|
|
265
|
-
def get_operator_and_data(inbound_data)
|
|
266
|
-
|
|
267
|
-
where_operator, data = inbound_data.split(Delimiters::name_value_delim)
|
|
268
|
-
|
|
269
|
-
md = @populator.current_method_detail
|
|
270
|
-
|
|
271
|
-
# Find by operator embedded in row takes precedence over operator in column heading
|
|
272
|
-
if((data.nil? || data.empty?) && md.find_by_operator)
|
|
273
|
-
if((where_operator.nil? || where_operator.empty?)) #colum completely empty - check for defaults
|
|
274
|
-
if(md.find_by_value)
|
|
275
|
-
data = md.find_by_value
|
|
276
|
-
else
|
|
277
|
-
data = Populator::header_default_data(md.operator)
|
|
278
|
-
end
|
|
279
|
-
else
|
|
280
|
-
data = where_operator
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
# row contains single entry only so take operator from header via method details
|
|
284
|
-
where_operator = md.find_by_operator
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
logger.debug("LoaderBase - get_operator_and_data - [#{where_operator}] - [#{data}]")
|
|
288
|
-
|
|
289
|
-
return where_operator, data
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
# Process a value string from a column.
|
|
293
|
-
# Assigning value(s) to correct association on @load_object.
|
|
294
|
-
# Method detail represents a column from a file and it's correlated AR associations.
|
|
295
|
-
# Value string which may contain multiple values for a collection association.
|
|
296
|
-
#
|
|
297
|
-
def process(method_detail, value)
|
|
298
|
-
|
|
299
|
-
current_method_detail = method_detail
|
|
300
|
-
|
|
301
|
-
current_value, current_attribute_hash = @populator.prepare_data(method_detail, value)
|
|
302
|
-
|
|
303
|
-
# TODO - Move ALL of this into Populator properly
|
|
304
|
-
if(current_method_detail.operator_for(:has_many))
|
|
305
|
-
|
|
306
|
-
if(current_method_detail.operator_class && current_value)
|
|
307
|
-
|
|
308
|
-
# there are times when we need to save early, for example before assigning to
|
|
309
|
-
# has_and_belongs_to associations which require the load_object has an id for the join table
|
|
152
|
+
@config.merge!(data['LoaderBase']) if data['LoaderBase']
|
|
310
153
|
|
|
311
|
-
|
|
154
|
+
@config.merge!(data[self.class.name]) if data[self.class.name]
|
|
312
155
|
|
|
313
|
-
|
|
314
|
-
# Size:large|Colour:red,green,blue => ['Size:large', 'Colour:red,green,blue']
|
|
315
|
-
columns = current_value.to_s.split( Delimiters::multi_assoc_delim )
|
|
156
|
+
DataShift::Transformation.factory { |f| f.configure_from(load_object_class, yaml_file) }
|
|
316
157
|
|
|
317
|
-
|
|
318
|
-
# find_by_size( 'large' )
|
|
319
|
-
# find_all_by_colour( ['red','green','blue'] )
|
|
158
|
+
ContextFactory.configure(load_object_class, yaml_file)
|
|
320
159
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
find_operator, col_values = get_operator_and_data( col_str )
|
|
324
|
-
|
|
325
|
-
raise "Cannot perform DB find by #{find_operator}. Expected format key:value" unless(find_operator && col_values)
|
|
326
|
-
|
|
327
|
-
find_by_values = col_values.split(Delimiters::multi_value_delim)
|
|
328
|
-
|
|
329
|
-
find_by_values << current_method_detail.find_by_value if(current_method_detail.find_by_value)
|
|
330
|
-
|
|
331
|
-
found_values = []
|
|
332
|
-
|
|
333
|
-
#if(find_by_values.size() == 1)
|
|
334
|
-
# logger.info("Find or create #{current_method_detail.operator_class} with #{find_operator} = #{find_by_values.inspect}")
|
|
335
|
-
# item = current_method_detail.operator_class.where(find_operator => find_by_values.first).first_or_create
|
|
336
|
-
#else
|
|
337
|
-
# logger.info("Find #{current_method_detail.operator_class} with #{find_operator} = values #{find_by_values.inspect}")
|
|
338
|
-
# current_method_detail.operator_class.where(find_operator => find_by_values).all
|
|
339
|
-
#end
|
|
340
|
-
|
|
341
|
-
operator_class = current_method_detail.operator_class
|
|
342
|
-
|
|
343
|
-
logger.info("Find #{current_method_detail.operator_class} with #{find_operator} = #{find_by_values.inspect}")
|
|
344
|
-
|
|
345
|
-
find_by_values.each do |v|
|
|
346
|
-
begin
|
|
347
|
-
found_values << operator_class.where(find_operator => v).first_or_create
|
|
348
|
-
rescue => e
|
|
349
|
-
logger.error(e.inspect)
|
|
350
|
-
# TODO some way to define if this is a fatal error or not ?
|
|
351
|
-
end
|
|
352
|
-
end
|
|
353
|
-
|
|
354
|
-
logger.info("Scan result #{found_values.inspect}")
|
|
355
|
-
|
|
356
|
-
unless(find_by_values.size == found_values.size)
|
|
357
|
-
found = found_values.collect {|f| f.send(find_operator) }
|
|
358
|
-
@load_object.errors.add( current_method_detail.operator, "Association with key(s) #{(find_by_values - found).inspect} NOT found")
|
|
359
|
-
logger.error "Association [#{current_method_detail.operator}] with key(s) #{(find_by_values - found).inspect} NOT found - Not added."
|
|
360
|
-
next if(found_values.empty?)
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
logger.info("Assigning #{found_values.inspect} (#{found_values.class})")
|
|
364
|
-
|
|
365
|
-
# Lookup Assoc's Model done, now add the found value(s) to load model's collection
|
|
366
|
-
@populator.prepare_and_assign(current_method_detail, @load_object, found_values)
|
|
367
|
-
end # END HAS_MANY
|
|
368
|
-
end
|
|
369
|
-
else
|
|
370
|
-
# Nice n simple straight assignment to a column variable
|
|
371
|
-
#puts "INFO: LOADER BASE processing #{method_detail.name}"
|
|
372
|
-
@populator.assign(load_object)
|
|
373
|
-
end
|
|
374
|
-
end
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
# Loading failed. Store a failed object and if requested roll back (destroy) the current load object
|
|
378
|
-
# For use case where object saved early but subsequent required columns fail to process
|
|
379
|
-
# so the load object is invalid
|
|
380
|
-
|
|
381
|
-
def failure( object = @load_object, rollback = false)
|
|
382
|
-
if(object)
|
|
383
|
-
@reporter.add_failed_object(object)
|
|
384
|
-
|
|
385
|
-
if(rollback && object.respond_to?('destroy') && !object.new_record?)
|
|
386
|
-
klass = object.class
|
|
387
|
-
object.destroy
|
|
388
|
-
object = klass.new
|
|
389
|
-
end
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
def save_and_report
|
|
394
|
-
unless(save)
|
|
395
|
-
failure
|
|
396
|
-
logger.error "Failed to save row (#{current_row_idx}) - [#{@current_row}]"
|
|
397
|
-
logger.error load_object.errors.inspect if(load_object)
|
|
398
|
-
else
|
|
399
|
-
logger.info("Successfully SAVED Object with ID #{load_object.id} for Row #{@current_row}")
|
|
400
|
-
@reporter.add_loaded_object(@load_object)
|
|
401
|
-
@reporter.success_inbound_count += 1
|
|
402
|
-
end
|
|
403
|
-
end
|
|
404
|
-
|
|
405
|
-
def save
|
|
406
|
-
return unless( @load_object )
|
|
407
|
-
|
|
408
|
-
puts "DEBUG: SAVING #{@load_object.class} : #{@load_object.inspect}" if(verbose)
|
|
409
|
-
begin
|
|
410
|
-
return @load_object.save
|
|
411
|
-
rescue => e
|
|
412
|
-
logger.error( "Save Error : #{e.inspect} on #{@load_object.class}")
|
|
413
|
-
logger.error(e.backtrace)
|
|
414
|
-
end
|
|
415
|
-
|
|
416
|
-
false
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
# Reset the loader, including database object to be populated, and load counts
|
|
420
|
-
#
|
|
421
|
-
def reset(object = nil)
|
|
422
|
-
@load_object = object || new_load_object
|
|
423
|
-
@reporter.reset
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
def new_load_object
|
|
428
|
-
@load_object = @load_object_class.new
|
|
429
|
-
@load_object
|
|
430
|
-
end
|
|
431
|
-
|
|
432
|
-
def abort_on_failure?
|
|
433
|
-
@config[:abort_on_failure].to_s == 'true'
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
def loaded_count
|
|
437
|
-
reporter.loaded_objects.size
|
|
438
|
-
end
|
|
439
|
-
|
|
440
|
-
def failed_count
|
|
441
|
-
reporter.failed_objects.size
|
|
442
|
-
end
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
# Check whether headers contains supplied list
|
|
446
|
-
def headers_contain_mandatory?( mandatory_list )
|
|
447
|
-
[ [*mandatory_list] - @headers].flatten.empty?
|
|
448
|
-
end
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
# Check whether headers contains supplied list
|
|
452
|
-
def missing_mandatory_headers( mandatory_list )
|
|
453
|
-
[ [*mandatory_list] - @headers].flatten
|
|
454
|
-
end
|
|
455
|
-
|
|
456
|
-
def find_or_new( klass, condition_hash = {} )
|
|
457
|
-
@records[klass] = klass.find(:all, :conditions => condition_hash)
|
|
458
|
-
if @records[klass].any?
|
|
459
|
-
return @records[klass].first
|
|
460
|
-
else
|
|
461
|
-
return klass.new
|
|
462
|
-
end
|
|
463
|
-
end
|
|
464
|
-
|
|
465
|
-
protected
|
|
466
|
-
|
|
467
|
-
# Take current column data and split into each association
|
|
468
|
-
# Supported Syntax :
|
|
469
|
-
# assoc_find_name:value | assoc2_find_name:value | etc
|
|
470
|
-
def get_each_assoc
|
|
471
|
-
current_value = @populator.current_value.to_s.split( Delimiters::multi_assoc_delim )
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
private
|
|
475
|
-
|
|
476
|
-
# This method usually called during processing to avoid errors with associations like
|
|
477
|
-
# <ActiveRecord::RecordNotSaved: You cannot call create unless the parent is saved>
|
|
478
|
-
# If the object is still invalid at this point probably indicates compulsory
|
|
479
|
-
# columns on model have not been processed before associations on that model
|
|
480
|
-
# TODO smart ordering of columns dynamically ourselves rather than relying on incoming data order
|
|
481
|
-
def save_if_new
|
|
482
|
-
return unless(load_object.new_record?)
|
|
483
|
-
|
|
484
|
-
if(load_object.valid?)
|
|
485
|
-
save
|
|
486
|
-
else
|
|
487
|
-
raise DataShift::SaveError.new("Cannot Save - Invalid #{load_object.class} Record - #{load_object.errors.full_messages}")
|
|
488
|
-
end
|
|
160
|
+
logger.info("Loader Options : #{@config.inspect}")
|
|
489
161
|
end
|
|
490
162
|
|
|
491
163
|
end
|
|
492
164
|
|
|
493
|
-
end
|
|
165
|
+
end
|