diff --git a/.byebug_history b/.byebug_history new file mode 100644 index 0000000..e69de29 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ab40d21..4a4496b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,5 +2,5 @@ *Description of changes:* - -By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. +By submitting this pull request, I confirm that my contribution is made under +the terms of the Apache 2.0 license. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..391d314 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,85 @@ +name: CI + +on: + push: + branches: + - main + + pull_request: + branches: + - main + +env: + ruby_version: 3.3 + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + ruby: [2.7, '3.0', 3.1, 3.2, 3.3, jruby-9.4] + rails: [7.1, 7.2, '8.0', main] + + exclude: + # Rails 7.2 is Ruby >= 3.1 + - rails: 7.2 + ruby: 2.7 + - rails: 7.2 + ruby: 3.0 + # Rails 8.0 is Ruby >= 3.2 + - rails: '8.0' + ruby: 2.7 + - rails: '8.0' + ruby: 3.0 + - rails: '8.0' + ruby: 3.1 + - rails: '8.0' + ruby: jruby-9.4 + # Rails main is Ruby >= 3.2 + - rails: main + ruby: 2.7 + - rails: main + ruby: 3.0 + - rails: main + ruby: 3.1 + - rails: main + ruby: jruby-9.4 + + steps: + - uses: actions/checkout@v4 + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + + - name: Install gems + run: bundle install + env: + BUNDLE_GEMFILE: gemfiles/rails-${{ matrix.rails }}.gemfile + + - name: Test + run: bundle exec rake test + env: + BUNDLE_GEMFILE: gemfiles/rails-${{ matrix.rails }}.gemfile + + rubocop: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ env.ruby_version }} + + - name: Install gems + run: | + bundle config set --local with 'development' + bundle install + + - name: Rubocop + run: bundle exec rake rubocop diff --git a/.gitignore b/.gitignore index 916630f..9ded959 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ -.ruby-version -.yardoc/ +.idea/ Gemfile.lock -doc +gemfiles/*.gemfile.lock + +test/dummy/app/models +test/dummy/db/migrate +test/dummy/log/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index deec4bd..b914b3f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "tasks/release"] path = tasks/release - url = https://github.com/aws/aws-sdk-ruby-release-tools.git + url = git@github.com:aws/aws-sdk-ruby-release-tools.git diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..775c62b --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--require spec_helper +--format documentation \ No newline at end of file diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..4a2e0c3 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,22 @@ +inherit_from: .rubocop_todo.yml + +AllCops: + NewCops: enable + TargetRubyVersion: 2.7 + SuggestExtensions: false + Exclude: + - 'tasks/release/**/*' + - 'test/dummy/**/*.rb' + - 'test/fixtures/**/*.rb' + +Gemspec/RequireMFA: + Enabled: false + +Metrics/BlockLength: + Exclude: + - 'test/**/*.rb' + +Naming/FileName: + Exclude: + - 'gemfiles/*.gemfile' + - 'lib/aws-record-rails.rb' \ No newline at end of file diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 0000000..a0a24ec --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,73 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2024-11-16 00:17:52 UTC using RuboCop version 1.68.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 9 +# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 29 + +# Offense count: 4 +# Configuration parameters: CountComments, CountAsOne. +Metrics/ClassLength: + Max: 219 + +# Offense count: 4 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/CyclomaticComplexity: + Max: 11 + +# Offense count: 11 +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +Metrics/MethodLength: + Max: 32 + +# Offense count: 2 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/PerceivedComplexity: + Max: 11 + +# Offense count: 1 +# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros. +# NamePrefix: is_, has_, have_ +# ForbiddenPrefixes: is_, has_, have_ +# AllowedMethods: is_a? +# MethodDefinitionMacros: define_method, define_singleton_method +Naming/PredicateName: + Exclude: + - 'spec/**/*' + - 'lib/generators/aws_record/base.rb' + +# Offense count: 9 +# Configuration parameters: AllowedConstants. +Style/Documentation: + Exclude: + - 'spec/**/*' + - 'test/**/*' + - 'lib/generators/aws_record/active_model.rb' + - 'lib/generators/aws_record/base.rb' + - 'lib/generators/aws_record/erb/erb_generator.rb' + - 'lib/generators/aws_record/model/model_generator.rb' + - 'lib/generators/aws_record/resource/resource_generator.rb' + - 'lib/generators/aws_record/scaffold/scaffold_generator.rb' + - 'lib/generators/aws_record/scaffold_controller/scaffold_controller_generator.rb' + - 'lib/generators/generated_attribute.rb' + - 'lib/generators/secondary_index.rb' + +# Offense count: 4 +# This cop supports safe autocorrection (--autocorrect). +Style/IfUnlessModifier: + Exclude: + - 'lib/generators/aws_record/base.rb' + - 'lib/generators/secondary_index.rb' + +# Offense count: 11 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. +# URISchemes: http, https +Layout/LineLength: + Max: 180 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 74c6d35..0000000 --- a/.travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -language: ruby - -rvm: - - 2.1 - - 2.2 - - 2.3 - - 2.4 - - 2.5 - - 2.6 - - 2.7 - - jruby-9.1 - - jruby-9.2 - -sudo: false - -script: bundle exec rake release:test - -bundler_args: --without docs release repl diff --git a/.yardopts b/.yardopts index 638b94a..23707ae 100644 --- a/.yardopts +++ b/.yardopts @@ -1,4 +1,4 @@ ---title 'AWS SDK Ruby Record Rails Generator' +--title 'ActiveRecord DynamoDB' --template-path doc-src/templates --plugin sitemap --hide-api private diff --git a/CHANGELOG.md b/CHANGELOG.md index dc4b6e2..1c836a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,4 @@ Unreleased Changes ------------------ -1.0.0.pre.2 (2018-07-09) ------------------- - -* Feature - Add scoffolding commands to generators. - -1.0.0.pre.1 (2018-06-13) ------------------- - -* Feature - Initial Beta release of Ruby on Rails generator support for the `aws-record` gem. When included in your Ruby on Rails project, you will be able to generate models using the command line which interface with Amazon DynamoDB via the `aws-record` gem. +* Feature - Initial version of this gem. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 3b64466..5b627cf 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,4 @@ ## Code of Conduct -This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). -For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact opensource-codeofconduct@amazon.com with any additional questions or comments. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c5a7710..c4b6a1c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,9 @@ # Contributing Guidelines -Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional +Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional documentation, we greatly value feedback and contributions from our community. -Please read through this document before submitting any issues or pull requests to ensure we have all the necessary +Please read through this document before submitting any issues or pull requests to ensure we have all the necessary information to effectively respond to your bug report or contribution. @@ -11,7 +11,7 @@ information to effectively respond to your bug report or contribution. We welcome you to use the GitHub issue tracker to report bugs or suggest features. -When filing an issue, please check [existing open](https://github.com/awslabs/aws-record-generator/issues), or [recently closed](https://github.com/awslabs/aws-record-generator/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already +When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: * A reproducible test case or series of steps @@ -23,7 +23,7 @@ reported the issue. Please try to include as much information as you can. Detail ## Contributing via Pull Requests Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: -1. You are working against the latest source on the *master* branch. +1. You are working against the latest source on the *main* branch. 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. @@ -36,17 +36,17 @@ To send us a pull request, please: 5. Send us a pull request, answering any default questions in the pull request interface. 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. -GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and +GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). ## Finding contributions to work on -Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/awslabs/aws-record-generator/labels/help%20wanted) issues is a great place to start. +Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. ## Code of Conduct -This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). -For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact opensource-codeofconduct@amazon.com with any additional questions or comments. @@ -56,6 +56,4 @@ If you discover a potential security issue in this project we ask that you notif ## Licensing -See the [LICENSE](https://github.com/awslabs/aws-record-generator/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. - -We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. +See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. diff --git a/Gemfile b/Gemfile index abadff0..b6a58a3 100644 --- a/Gemfile +++ b/Gemfile @@ -1,14 +1,20 @@ -source "https://rubygems.org" +# frozen_string_literal: true + +source 'https://rubygems.org' gemspec gem 'rake', require: false +group :development do + gem 'byebug', platforms: :ruby + gem 'rubocop' +end + group :test do - gem 'rspec' - gem 'cucumber' - gem 'capybara' - gem 'simplecov', require: false + gem 'bcrypt' + gem 'minitest-spec-rails' + gem 'rspec-rails' end group :docs do @@ -16,3 +22,6 @@ group :docs do gem 'yard-sitemap', '~> 1.0' end +group :release do + gem 'octokit' +end diff --git a/LICENSE b/LICENSE index d645695..67db858 100644 --- a/LICENSE +++ b/LICENSE @@ -173,30 +173,3 @@ defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/NOTICE b/NOTICE index b242379..616fc58 100644 --- a/NOTICE +++ b/NOTICE @@ -1,2 +1 @@ -AWS Record Generator -Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/README.md b/README.md index a035d4f..bf8bca0 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,61 @@ -# AWS Record Rails Generators have been moved to aws-sdk-rails +# ActiveRecord models with DynamoDB -This feature has been moved to [aws-sdk-rails](https://github.com/aws/aws-sdk-rails). +[![Gem Version](https://badge.fury.io/rb/aws-record-rails.svg)](https://badge.fury.io/rb/aws-record-rails) +[![Build Status](https://github.com/aws/aws-record-rails/workflows/CI/badge.svg)](https://github.com/aws/aws-record-rails/actions) +[![Github forks](https://img.shields.io/github/forks/aws/aws-record-rails.svg)](https://github.com/aws/aws-record-rails/network) +[![Github stars](https://img.shields.io/github/stars/aws/aws-record-rails.svg)](https://github.com/aws/aws-record-rails/stargazers) -This documentation will remain for historical purposes. +This gem contains generators for +[ActiveRecord](https://guides.rubyonrails.org/active_record_basics.html) +models using DynamoDB with +[`Aws::Record`](https://docs.aws.amazon.com/sdk-for-ruby/aws-record/api/Aws/Record.html). -## AWS Record Generator +## Installation -Allows the generation of aws-record models using a Rails generator +Add this gem to your Rails project's Gemfile: -## Links of Interest +```ruby +gem 'aws-sdk-rails', '~> 4' +gem 'aws-record-rails', '~> 0' +``` -* [aws-record Documentation](https://docs.aws.amazon.com/awssdkrubyrecord/api/) -* [DynamoDB Developers Guide](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html) +Then run `bundle install`. -## Installation +This gem also brings in the following AWS gems: -You can install the gem from RubyGems using the `--pre` flag -`gem install 'aws-record-generator' --pre` +* `aws-record` -> `aws-sdk-dynamodb` -This automatically includes a dependency on the `aws-record` gem, major version 2, as well as a dependency on `>= Rails v4.2` +You will have to ensure that you provide credentials for the SDK to use. See the +latest [AWS SDK for Ruby Docs](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/index.html#Configuration) +for details. -## Usage +If you're running your Rails application on Amazon EC2, the AWS SDK will +check Amazon EC2 instance metadata for credentials to load. Learn more: +[IAM Roles for Amazon EC2](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html) +## Usage -### Setup - -You can either invoke the generator by calling `rails g aws_record:model ...` +Invoke the generator by calling `rails generate aws_record:model ...` -If DynamoDB will be the only datastore you plan on using you can also set `aws-record-generator` to be your project's default orm with +If DynamoDB will be the only datastore you plan on using, you can also set +`aws_record` to be your project's default orm with: ```ruby config.generators do |g| - g.orm :aws_record + g.orm :aws_record end ``` -Which will cause `aws_record:model` to be invoked by the Rails model generator. +Which will cause `aws_record:model` to be invoked with `rails generate model ...` ### Generating a model -Generating a model can be as simple as: `rails g aws_record:model Forum --table-config primary:10-5` -`aws-record-generator` will automatically create a `uuid:hash_key` field for you, and a table config with the provided r/w units +Generating a model can be as simple as: + + rails generate aws_record:model Forum --table-config primary:10-5 + +The generator will automatically create a `uuid:hash_key` field for you, and +a table config with the provided r/w units: ```ruby # app/models/forum.rb @@ -67,12 +82,11 @@ module ModelTableConfig end end end - ``` More complex models can be created by adding more fields to the model as well as other options: -`rails g aws_record Forum post_id:rkey author_username post_title post_body tags:sset:default_value{Set.new}` + rails generate aws_record Forum post_id:rkey author_username post_title post_body tags:sset:default_value{Set.new} ```ruby # app/models/forum.rb @@ -92,14 +106,12 @@ end # db/table_config/forum_config.rb # ... - ``` -Finally you can attach a variety of options to your fields, and even `ActiveModel` validations to the models: +Finally you can attach a variety of options to your fields, and even +`ActiveModel` validations to the models: -`rails g aws_record:model Forum forum_uuid:hkey post_id:rkey author_username post_title post_body tags:sset:default_value{Set.new} created_at:datetime:db_attr_name{PostCreatedAtTime} moderation:boolean:default_value{false} --table-config=primary:5-2 AuthorIndex:12-14 --required=post_title --length-validations=post_body:50-1000 --gsi=AuthorIndex:hkey{author_username}` - -Which results in the following files being generated: + rails generate aws_record:model Forum forum_uuid:hkey post_id:rkey author_username post_title post_body tags:sset:default_value{Set.new} created_at:datetime:db_attr_name{PostCreatedAtTime} moderation:boolean:default_value{false} --table-config=primary:5-2 AuthorIndex:12-14 --required=post_title --length-validations=post_body:50-1000 --gsi=AuthorIndex:hkey{author_username}` ```ruby @@ -137,13 +149,14 @@ end ``` -To migrate your new models and begin using them you can run the provided rake task: `rails aws_record:migrate` +To migrate your new models and begin using them you can run the provided rake task: + bundle exec rails aws_record:migrate ### Scaffolding -If you invoke `aws_record:scaffold` instead of `aws_record:model` then the generator will construct a full controller-view-model structure. - +If you invoke `aws_record:scaffold` instead of `aws_record:model` then the +generator will construct a full controller-view-model structure. ### Docs @@ -153,51 +166,46 @@ The syntax for creating an aws-record model follows: The possible field types are: -Field Name | aws-record attribute type ----------------- | ------------- -`bool \| boolean` | :boolean_attr -`date` | :date_attr -`datetime` | :datetime_attr -`float` | :float_attr -`int \| integer` | :integer_attr -`list` | :list_attr -`map` | :map_attr -`num_set \| numeric_set \| nset` | :numeric_set_attr -`string_set \| s_set \| sset` | :string_set_attr -`string` | :string_attr - - -If a type is not provided `aws-record-generator` will assume the field is of type `:string_attr` +| Field Name | aws-record attribute type | +|----------------------------------|---------------------------| +| `bool \| boolean` | :boolean_attr | +| `date` | :date_attr | +| `datetime` | :datetime_attr | +| `float` | :float_attr | +| `int \| integer` | :integer_attr | +| `list` | :list_attr | +| `map` | :map_attr | +| `num_set \| numeric_set \| nset` | :numeric_set_attr | +| `string_set \| s_set \| sset` | :string_set_attr | +| `string` | :string_attr | + +If a type is not provided the generator will assume the field is of type `:string_attr` Additionally a number of options may be attached as a comma seperated list to the field: -Field Option Name | aws-record option ----------------- | ------------- -`hkey` | marks an attribute as a hash_key -`rkey` | marks an attribute as a range_key -`persist_nil` | will persist nil values in a attribute -`db_attr_name{NAME}` | sets a secondary name for an attribute, these must be unique across attribute names -`ddb_type{S\|N\|B\|BOOL\|SS\|NS\|BS\|M\|L}` | sets the dynamo_db_type for an attribute -`default_value{Object}` | sets the default value for an attribute - -The standard rules apply for using options in a model. Additional reading can be found [here](#links-of-interest) - -Command Option Names | Purpose --------------------- | ----------- - [--skip-namespace], [--no-skip-namespace] | Skip namespace (affects only isolated applications) - [--disable-mutation-tracking], [--no-disable-mutation-tracking] | Disables dirty tracking - [--timestamps], [--no-timestamps] | Adds created, updated timestamps to the model - --table-config=primary:R-W [SecondaryIndex1:R-W]... | Declares the r/w units for the model as well as any secondary indexes - [--gsi=name:hkey{field_name}[,rkey{field_name},proj_type{ALL\|KEYS_ONLY\|INCLUDE}]...] | Allows for the declaration of secondary indexes - [--required=field1...] | A list of attributes that are required for an instance of the model - [--length-validations=field1:MIN-MAX...] | Validations on the length of attributes in a model - [--table-name=name] | Sets the name of the table in DynamoDB, if different than the model name - [--skip-table-config] | Doesn't generate a table config for the model - [--password-digest] | Adds a password field (note that you must have bcrypt has a dependency) that automatically hashes and manages the model password - [--scaffold] | Adds helpers methods that are used by the scaffolding +| Field Option Name | aws-record option | +|---------------------------------------------|-------------------------------------------------------------------------------------| +| `hkey` | marks an attribute as a hash_key | +| `rkey` | marks an attribute as a range_key | +| `persist_nil` | will persist nil values in a attribute | +| `db_attr_name{NAME}` | sets a secondary name for an attribute, these must be unique across attribute names | +| `ddb_type{S\|N\|B\|BOOL\|SS\|NS\|BS\|M\|L}` | sets the dynamo_db_type for an attribute | +| `default_value{Object}` | sets the default value for an attribute | + +Additional options: + +| Command Option Names | Purpose | +|----------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------| +| [--skip-namespace], [--no-skip-namespace] | Skip namespace (affects only isolated applications) | +| [--disable-mutation-tracking], [--no-disable-mutation-tracking] | Disables dirty tracking | +| [--timestamps], [--no-timestamps] | Adds created, updated timestamps to the model | +| --table-config=primary:R-W [SecondaryIndex1:R-W]... | Declares the r/w units for the model as well as any secondary indexes | +| [--gsi=name:hkey{field_name}[,rkey{field_name},proj_type{ALL\|KEYS_ONLY\|INCLUDE}]...] | Allows for the declaration of secondary indexes | +| [--required=field1 ...] | A list of attributes that are required for an instance of the model | +| [--length-validations=field1:MIN-MAX...] | Validations on the length of attributes in a model | +| [--table-name=name] | Sets the name of the table in DynamoDB, if different than the model name | +| [--skip-table-config] | Doesn't generate a table config for the model | +| [--password-digest] | Adds a password field (note that you must have bcrypt has a dependency) that automatically hashes and manages the model password | +| [--scaffold] | Adds helpers methods that are used by the scaffolding | The included rake task `aws_record:migrate` will run all of the migrations in `app/db/table_config` - -## License - -This library is licensed under the Apache 2.0 License. diff --git a/Rakefile b/Rakefile index a9c9569..7714fec 100644 --- a/Rakefile +++ b/Rakefile @@ -1,28 +1,18 @@ -require 'rspec/core/rake_task' +# frozen_string_literal: true -$REPO_ROOT = File.dirname(__FILE__) -$LOAD_PATH.unshift(File.join($REPO_ROOT, 'lib')) -$VERSION = ENV['VERSION'] || File.read(File.join($REPO_ROOT, 'VERSION')).strip +require 'rake/testtask' +require 'rubocop/rake_task' -task 'test:coverage:clear' do - sh("rm -rf #{File.join($REPO_ROOT, 'coverage')}") +Dir.glob('tasks/**/*.rake').each do |task_file| + load task_file end -desc 'run unit tests' -RSpec::Core::RakeTask.new do |t| - t.rspec_opts = "-I #{$REPO_ROOT}/lib -I #{$REPO_ROOT}/spec" - t.pattern = "#{$REPO_ROOT}/spec" -end -task :spec => 'test:coverage:clear' +RuboCop::RakeTask.new -desc 'run cucumber (integration) tests' -task 'cucumber' do - exec('bundle exec cucumber') +Rake::TestTask.new do |t| + t.libs << 'test' + t.pattern = 'test/**/*_test.rb' + t.warning = false end -task :default => :spec -task 'release:test' => :spec - -Dir.glob('**/*.rake').each do |task_file| - load task_file -end +task 'release:test' => :test diff --git a/VERSION b/VERSION index 63c07f7..6e8bf73 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0.pre.2 +0.1.0 diff --git a/aws-record-generator.gemspec b/aws-record-generator.gemspec deleted file mode 100644 index 56e06df..0000000 --- a/aws-record-generator.gemspec +++ /dev/null @@ -1,19 +0,0 @@ -version = File.read(File.expand_path('../VERSION', __FILE__)).strip - -Gem::Specification.new do |spec| - spec.name = "aws-record-generator" - spec.version = version - spec.authors = ["Amazon Web Services"] - spec.email = ["mamuller@amazon.com", "alexwoo@amazon.com"] - - spec.summary = "Rails generators for aws-record" - spec.description = "Rails generators for aws-record models" - spec.homepage = "https://github.com/awslabs/aws-record-generator" - spec.license = "Apache 2.0" - - spec.require_paths = ["lib"] - spec.files = Dir['lib/tasks/table_config_migrate_task.rake', 'lib/**/*.rb', 'lib/**/*.tt'] - - spec.add_dependency('aws-record', '~> 2.1') - spec.add_dependency('rails', '>= 4.2') -end diff --git a/aws-record-rails.gemspec b/aws-record-rails.gemspec new file mode 100644 index 0000000..05163ee --- /dev/null +++ b/aws-record-rails.gemspec @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +version = File.read(File.expand_path('VERSION', __dir__)).strip + +Gem::Specification.new do |spec| + spec.name = 'aws-record-rails' + spec.version = version + spec.author = 'Amazon Web Services' + spec.email = ['aws-dr-rubygems@amazon.com'] + spec.summary = 'Aws::Record integration for Rails' + spec.description = 'Includes Aws::Record scaffold generators for Rails' + spec.homepage = 'https://github.com/aws/aws-record-rails' + spec.license = 'Apache-2.0' + spec.files = Dir['LICENSE', 'CHANGELOG.md', 'VERSION', 'lib/**/*'] + + spec.add_dependency('aws-record', '~> 2') + + spec.add_dependency('railties', '>= 7.1.0') + + spec.required_ruby_version = '>= 2.7' +end diff --git a/doc-src/templates/default/layout/html/footer.erb b/doc-src/templates/default/layout/html/footer.erb index 5b9d553..41529dc 100644 --- a/doc-src/templates/default/layout/html/footer.erb +++ b/doc-src/templates/default/layout/html/footer.erb @@ -4,7 +4,3 @@ <%= YARD::VERSION %> (ruby-<%= RUBY_VERSION %>). - - - - diff --git a/doc-src/templates/default/layout/html/layout.erb b/doc-src/templates/default/layout/html/layout.erb index 83ecb73..8ba2fb9 100644 --- a/doc-src/templates/default/layout/html/layout.erb +++ b/doc-src/templates/default/layout/html/layout.erb @@ -4,7 +4,7 @@ <%= erb(:headers) %> - + diff --git a/features/model/model.feature b/features/model/model.feature deleted file mode 100644 index d418363..0000000 --- a/features/model/model.feature +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -# language: en -@dynamodb @modelgen -Feature: Aws::Record::Generators::ModelGenerator - -Scenario: Create a New Table with ModelGenerator - When we run the rails command line with: - """ - g aws_record:model BasicModel id:hkey count:int:rkey --table_config=primary:11-4 - """ - Then a "model" should be generated matching fixture at: "fixtures/cucumber/model/basic_model.rb" - And a "table_config" should be generated matching fixture at: "fixtures/cucumber/table_config/basic_model_config.rb" - When we run the rails command line with: - """ - aws_record:migrate - """ - - Then eventually the table should exist in DynamoDB - And the TableConfig should be compatible with the remote table - And the TableConfig should be an exact match with the remote table - -Scenario: Create a New Table that has a Global Secondary Index with ModelGenerator - When we run the rails command line with: - """ - g aws_record:model BasicSecondaryIndexModel id:hkey count:int:rkey title --table_config primary:11.4 secondary_idx:10-5 --gsi=secondary_idx:hkey{title} - """ - Then a "model" should be generated matching fixture at: "fixtures/cucumber/model/basic_secondary_index_model.rb" - And a "table_config" should be generated matching fixture at: "fixtures/cucumber/table_config/basic_secondary_index_model_config.rb" - When we run the rails command line with: - """ - aws_record:migrate - """ - - Then eventually the table should exist in DynamoDB - And the TableConfig should be compatible with the remote table - And the TableConfig should be an exact match with the remote table diff --git a/features/model/step_definitions.rb b/features/model/step_definitions.rb deleted file mode 100644 index 3d3758b..0000000 --- a/features/model/step_definitions.rb +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require 'securerandom' -require 'aws-record-generator' - -Before do - @gen_helper = AwsRecord::Generators::GeneratorTestHelper.new(AwsRecord::Generators::ModelGenerator, "tmp") - @file_prefix = nil -end - -After("@modelgen") do - @gen_helper.cleanup -end - -When("we run the rails command line with:") do |cmd| - if cmd.start_with?('g aws_record:model') || cmd.start_with?('g aws_record:scaffold') - @model_name = cmd.split(' ')[2] - @table_name = "#{@model_name}_#{SecureRandom.uuid}" - cmd << " --table-name=#{@table_name}" - - begin - @client.describe_table(table_name: @table_name) - abort("#{@table_name} already exists in DynamoDB") - rescue Aws::DynamoDB::Errors::ResourceNotFoundException; end - end - - @gen_helper.run_in_test_app cmd -end - -Then("a {string} should be generated matching fixture at: {string}") do |generated_type, fixture_file_path| - file_name = fixture_file_path.split('/')[-1] - file_prefix = file_name.split('.')[0] - - if generated_type == "model" - generated_file_path = File.join(@gen_helper.destination_root, "app/models/#{file_prefix}.rb") - @gen_helper.assert_model_rand_table_name(generated_file_path, fixture_file_path, @table_name) - - require "#{generated_file_path}" - @model = Object.const_get("#{@model_name}") - elsif generated_type == "table_config" - generated_file_path = File.join(@gen_helper.destination_root, "db/table_config/#{file_prefix}.rb") - @gen_helper.assert_file_fixture(generated_file_path, fixture_file_path) - - load generated_file_path - @table_config = ModelTableConfig.config - end -end diff --git a/features/scaffold/scaffold.feature b/features/scaffold/scaffold.feature deleted file mode 100644 index ba6ef29..0000000 --- a/features/scaffold/scaffold.feature +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -# language: en -@dynamodb @modelgen @scaffoldtest -Feature: Aws::Record::Generators::ScaffoldGenerator -Scenario: Create a New Scaffold with ScaffoldGenerator - When we run the rails command line with: - """ - g aws_record:scaffold Dog id:hkey name is_good_boy:bool --table_config=primary:11-4 - """ - Then a "model" should be generated matching fixture at: "fixtures/cucumber/model/dog.rb" - And a "table_config" should be generated matching fixture at: "fixtures/cucumber/table_config/dog_config.rb" - - When we run the rails command line with: - """ - aws_record:migrate - """ - Then eventually the table should exist in DynamoDB - And the TableConfig should be compatible with the remote table - And the TableConfig should be an exact match with the remote table - - When we navigate to /dogs - And we click on New Dog - And we fill the dog_id field with TestDog - And we fill the dog_name field with Fido - And we set dog_is_good_boy - And we click on Create Dog - Then the current page should be /dogs/TestDog - - When we click on Back - Then the current page should be /dogs - And the page should have content: - """ - Dogs - Id Name Is good boy - TestDog Fido true Show Edit Destroy - - New Dog - """ - - When we click on Show - Then the current page should be /dogs/TestDog - And the page should have content: - """ - Id: TestDog - Name: Fido - Is good boy: true - Edit | Back - """ - - When we click on Back - Then the current page should be /dogs - And the page should have content: - """ - Dogs - Id Name Is good boy - TestDog Fido true Show Edit Destroy - - New Dog - """ - - When we click on Edit - Then the current page should be /dogs/TestDog/edit - And the page should have content: - """ - Editing Dog - Id - Name - Is good boy - Show | Back - """ - - And we fill the dog_name field with Rover - And we click on Update Dog - And the current page should be /dogs/TestDog - - When we click on Back - Then the current page should be /dogs - And the page should have content: - """ - Dogs - Id Name Is good boy - TestDog Rover true Show Edit Destroy - - New Dog - """ - - When we click on Destroy - And we accept the alert - Then the current page should be /dogs - And the page should have content: - """ - Dogs - Id Name Is good boy - - New Dog - """ - And the page should not have content: - """ - TestDog Rover true Show Edit Destroy - """ - \ No newline at end of file diff --git a/features/scaffold/step_definitions.rb b/features/scaffold/step_definitions.rb deleted file mode 100644 index fff8218..0000000 --- a/features/scaffold/step_definitions.rb +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require 'capybara/cucumber' -require 'aws-record-generator' -require 'active_model' -require "open-uri" - -Before("@scaffoldtest") do - Capybara.configure do |config| - config.run_server = false - config.always_include_port = true - config.default_driver = :selenium_chrome_headless - config.app_host = 'http://localhost:8080' - end - - Dir.chdir "tmp/test_app" - @rails_app = Kernel.spawn("rails server --port 8080", :out => "tmp/test_server.log") - Dir.chdir "../../" - - begin - sleep(5) # Wait for test server to boot - URI.parse("http://localhost:8080").read - rescue Exception => e - abort("Test Server Error: #{e}") - end -end - -After("@scaffoldtest") do - Process.kill("TERM", @rails_app) - Process.wait(@rails_app) -end - -When (/^we navigate to (.+)$/) do |url| - visit url -end - -When (/^we fill the (.+) field with (.+)$/) do |field, value| - fill_in field, with: value, visible: false -end - -When (/^we set (.+)$/) do |field| - check field, visible: false -end - -When (/^we click on (.+)$/) do |name| - click_on name, visible: false -end - -When ("we accept the alert") do - page.driver.browser.switch_to.alert.accept -end - -Then (/^the current page should be (.+)$/) do |page_url| - expect(page).to have_current_path(page_url) -end - -Then ("the page should have content:") do |content| - expect(page).to have_content(content) -end - -Then ("the page should not have content:") do |content| - expect(page).to have_no_content(content) -end diff --git a/features/step_definitions.rb b/features/step_definitions.rb deleted file mode 100644 index 0fb71f6..0000000 --- a/features/step_definitions.rb +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require 'aws-record' - -def cleanup_table - begin - puts "Cleaning Up Table: #{@table_name}" - @client.delete_table(table_name: @table_name) - puts "Cleaned up table: #{@table_name}" - @table_name = nil - rescue Aws::DynamoDB::Errors::ResourceNotFoundException - puts "Cleanup: Table #{@table_name} doesn't exist, continuing." - @table_name = nil - rescue Aws::DynamoDB::Errors::ResourceInUseException => e - puts "Failed to delete table, waiting to retry." - @client.wait_until(:table_exists, table_name: @table_name) - sleep(10) - retry - end -end - -Before do - if !ENV.key? "AWS_RECORD_GENERATOR_TEST_REGION" - raise NameError.new("Please set your AWS_RECORD_GENERATOR_TEST_REGION") - end - - @client = Aws::DynamoDB::Client.new(region: ENV["AWS_RECORD_GENERATOR_TEST_REGION"]) -end - -After("@dynamodb") do - cleanup_table -end - -Then(/^eventually the table should exist in DynamoDB$/) do - @client.wait_until(:table_exists, table_name: @table_name) do |w| - w.delay = 5 - w.max_attempts = 25 - end - true -end - -Then(/^the TableConfig should be compatible with the remote table$/) do - expect(@table_config.compatible?).to be_truthy -end - -Then(/^the TableConfig should be an exact match with the remote table$/) do - expect(@table_config.exact_match?).to be_truthy -end diff --git a/fixtures/cucumber/model/basic_model.rb b/fixtures/cucumber/model/basic_model.rb deleted file mode 100644 index c4f4fe0..0000000 --- a/fixtures/cucumber/model/basic_model.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'aws-record' - -class BasicModel - include Aws::Record - - string_attr :id, hash_key: true - integer_attr :count, range_key: true - set_table_name "#table_name#" -end diff --git a/fixtures/cucumber/model/basic_secondary_index_model.rb b/fixtures/cucumber/model/basic_secondary_index_model.rb deleted file mode 100644 index a568609..0000000 --- a/fixtures/cucumber/model/basic_secondary_index_model.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'aws-record' - -class BasicSecondaryIndexModel - include Aws::Record - - string_attr :id, hash_key: true - integer_attr :count, range_key: true - string_attr :title - - global_secondary_index( - :secondary_idx, - hash_key: :title, - projection: { - projection_type: "ALL" - } - ) - set_table_name "#table_name#" -end diff --git a/fixtures/cucumber/model/dog.rb b/fixtures/cucumber/model/dog.rb deleted file mode 100644 index a17b4c1..0000000 --- a/fixtures/cucumber/model/dog.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'aws-record' - -class Dog - include Aws::Record - extend ActiveModel::Naming - - string_attr :id, hash_key: true - string_attr :name - boolean_attr :is_good_boy - - # Scaffolding helpers - def initialize(args = {}) - super - @errors = ActiveModel::Errors.new(self) - end - - attr_reader :errors - - def to_model - self - end - - def to_param - return nil unless persisted? - - hkey = public_send(self.class.hash_key) - if self.class.range_key - rkey = public_send(self.class.range_key) - "#{CGI.escape(hkey)}&#{CGI.escape(rkey)}" - else - "#{CGI.escape(hkey)}" - end - end - set_table_name "#table_name#" -end diff --git a/fixtures/cucumber/table_config/basic_model_config.rb b/fixtures/cucumber/table_config/basic_model_config.rb deleted file mode 100644 index 7235731..0000000 --- a/fixtures/cucumber/table_config/basic_model_config.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'aws-record' - -module ModelTableConfig - def self.config - Aws::Record::TableConfig.define do |t| - t.model_class BasicModel - - t.read_capacity_units 11 - t.write_capacity_units 4 - end - end -end diff --git a/fixtures/cucumber/table_config/basic_secondary_index_model_config.rb b/fixtures/cucumber/table_config/basic_secondary_index_model_config.rb deleted file mode 100644 index 3a3cf2e..0000000 --- a/fixtures/cucumber/table_config/basic_secondary_index_model_config.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'aws-record' - -module ModelTableConfig - def self.config - Aws::Record::TableConfig.define do |t| - t.model_class BasicSecondaryIndexModel - - t.read_capacity_units 11 - t.write_capacity_units 4 - - t.global_secondary_index(:secondary_idx) do |i| - i.read_capacity_units 10 - i.write_capacity_units 5 - end - end - end -end diff --git a/fixtures/unit/model/test_scaffold_helpers.rb b/fixtures/unit/model/test_scaffold_helpers.rb deleted file mode 100644 index faea03d..0000000 --- a/fixtures/unit/model/test_scaffold_helpers.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'aws-record' - -class TestScaffoldHelpers - include Aws::Record - extend ActiveModel::Naming - - string_attr :uuid, hash_key: true - - # Scaffolding helpers - def initialize(args = {}) - super - @errors = ActiveModel::Errors.new(self) - end - - attr_reader :errors - - def to_model - self - end - - def to_param - return nil unless persisted? - - hkey = public_send(self.class.hash_key) - if self.class.range_key - rkey = public_send(self.class.range_key) - "#{CGI.escape(hkey)}&#{CGI.escape(rkey)}" - else - "#{CGI.escape(hkey)}" - end - end -end diff --git a/gemfiles/rails-7.1.gemfile b/gemfiles/rails-7.1.gemfile new file mode 100644 index 0000000..babb65f --- /dev/null +++ b/gemfiles/rails-7.1.gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +eval_gemfile '../Gemfile' + +gem 'rails', '~> 7.1.0' diff --git a/gemfiles/rails-7.2.gemfile b/gemfiles/rails-7.2.gemfile new file mode 100644 index 0000000..6866a47 --- /dev/null +++ b/gemfiles/rails-7.2.gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +eval_gemfile '../Gemfile' + +gem 'rails', '~> 7.2.0' diff --git a/gemfiles/rails-8.0.gemfile b/gemfiles/rails-8.0.gemfile new file mode 100644 index 0000000..cd3dbac --- /dev/null +++ b/gemfiles/rails-8.0.gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +eval_gemfile '../Gemfile' + +gem 'rails', '~> 8.0.0' diff --git a/gemfiles/rails-main.gemfile b/gemfiles/rails-main.gemfile new file mode 100644 index 0000000..80b01d9 --- /dev/null +++ b/gemfiles/rails-main.gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +eval_gemfile '../Gemfile' + +gem 'rails', github: 'rails/rails' diff --git a/lib/aws-record-generator.rb b/lib/aws-record-generator.rb deleted file mode 100644 index 4e16f53..0000000 --- a/lib/aws-record-generator.rb +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require_relative 'generators/generated_attribute' -require_relative 'generators/secondary_index' -require_relative 'generators/test_helper' -require_relative 'generators/aws_record/base' - -require_relative 'generators/aws_record/model/model_generator' -require_relative 'generators/aws_record/resource/resource_generator' -require_relative 'generators/aws_record/erb/erb_generator' -require_relative 'generators/aws_record/scaffold/scaffold_generator' -require_relative 'generators/aws_record/scaffold_controller/scaffold_controller_generator' - -require 'aws-record' -require 'rails/railtie' - -module AwsRecord - class Railtie < Rails::Railtie - rake_tasks do - load 'tasks/table_config_migrate_task.rake' - end - end -end diff --git a/lib/aws-record-rails.rb b/lib/aws-record-rails.rb new file mode 100644 index 0000000..32a7b49 --- /dev/null +++ b/lib/aws-record-rails.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require_relative 'generators/generated_attribute' +require_relative 'generators/secondary_index' +require_relative 'generators/aws_record/base' + +require_relative 'generators/aws_record/model/model_generator' +require_relative 'generators/aws_record/resource/resource_generator' +require_relative 'generators/aws_record/erb/erb_generator' +require_relative 'generators/aws_record/scaffold/scaffold_generator' +require_relative 'generators/aws_record/scaffold_controller/scaffold_controller_generator' + +require 'aws-record' + +module Aws + module Record + module Rails + VERSION = File.read(File.expand_path('../VERSION', __dir__)).strip + + # @api private + class Railtie < ::Rails::Railtie + rake_tasks do + load 'tasks/aws_record/migrate.rake' + end + end + end + end +end diff --git a/lib/generators/aws_record/active_model.rb b/lib/generators/aws_record/active_model.rb index 7ece636..d31b0d3 100644 --- a/lib/generators/aws_record/active_model.rb +++ b/lib/generators/aws_record/active_model.rb @@ -1,80 +1,68 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. +# frozen_string_literal: true module AwsRecord - module Generators - class ActiveModel - attr_reader :name - - def initialize(name) - @name = name - end - - # GET index - def self.all(klass) - "#{klass}.scan" - end - - # GET show - # GET edit - # PATCH/PUT update - # DELETE destroy - def self.find(klass, attrs) - hkey = attrs.select{|attr| attr.options[:hash_key]}[0] - rkey = attrs.select{|attr| attr.options[:range_key]} - rkey = !rkey.empty? ? rkey[0] : nil + module Generators + class ActiveModel + attr_reader :name + + def initialize(name) + @name = name + end + + # GET index + def self.all(klass) + "#{klass}.scan" + end - if rkey - """lambda { + # GET show + # GET edit + # PATCH/PUT update + # DELETE destroy + def self.find(klass, attrs) + hkey = attrs.select { |attr| attr.options[:hash_key] }[0] + rkey = attrs.select { |attr| attr.options[:range_key] } + rkey = rkey.empty? ? nil : rkey[0] + + if rkey + "lambda { id = params[:id].split('&').map{ |param| CGI.unescape(param) } #{klass}.find(#{hkey.name}: id[0], #{rkey.name}: id[1]) - }.call()""" - else - "#{klass}.find(#{hkey.name}: CGI.unescape(params[:id]))" - end - end - - # GET new - # POST create - def self.build(klass, params = nil) - if params - "#{klass}.new(#{params})" - else - "#{klass}.new" - end - end - - # POST create - def save - "#{name}.save" - end - - # PATCH/PUT update - def update(params = nil) - "#{name}.update(#{params})" - end - - # POST create - # PATCH/PUT update - def errors - "#{name}.errors" + }.call()" + else + "#{klass}.find(#{hkey.name}: CGI.unescape(params[:id]))" end - - # DELETE destroy - def destroy - "#{name}.delete!" + end + + # GET new + # POST create + def self.build(klass, params = nil) + if params + "#{klass}.new(#{params})" + else + "#{klass}.new" end end + + # POST create + def save + "#{name}.save" + end + + # PATCH/PUT update + def update(params = nil) + "#{name}.update(#{params})" + end + + # POST create + # PATCH/PUT update + def errors + "#{name}.errors" + end + + # DELETE destroy + def destroy + "#{name}.delete!" + end end end - \ No newline at end of file +end diff --git a/lib/generators/aws_record/base.rb b/lib/generators/aws_record/base.rb index d153fe5..6e310df 100644 --- a/lib/generators/aws_record/base.rb +++ b/lib/generators/aws_record/base.rb @@ -1,228 +1,212 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. +# frozen_string_literal: true + +require 'rails/generators' module AwsRecord - module Generators - class Base < Rails::Generators::NamedBase - argument :attributes, type: :array, default: [], banner: "field[:type][:opts]...", desc: "Describes the fields in the model" - check_class_collision - - class_option :disable_mutation_tracking, type: :boolean, desc: "Disables dirty tracking" - class_option :timestamps, type: :boolean, desc: "Adds created, updated timestamps to the model" - class_option :table_config, type: :hash, default: {}, banner: "primary:R-W [SecondaryIndex1:R-W]...", desc: "Declares the r/w units for the model as well as any secondary indexes", :required => true - class_option :gsi, type: :array, default: [], banner: "name:hkey{field_name}[,rkey{field_name},proj_type{ALL|KEYS_ONLY|INCLUDE}]...", desc: "Allows for the declaration of secondary indexes" - class_option :table_name, type: :string, banner: "model_table_name" - class_option :password_digest, type: :boolean, desc: "Whether to add a password_digest field to the model" - - class_option :required, type: :array, default: [], banner: "field1...", desc: "A list of attributes that are required for an instance of the model" - class_option :length_validations, type: :hash, default: {}, banner: "field1:MIN-MAX...", desc: "Validations on the length of attributes in a model" - class_option :scaffold, type: :boolean, desc: "Adds helper methods that scaffolding uses" - - attr_accessor :primary_read_units, :primary_write_units, :gsi_rw_units, :gsis, :required_attrs, :length_validations - - private - - def initialize(args, *options) - options[0] << "--skip-table-config" if options[1][:behavior] == :revoke - @parse_errors = [] - - super - ensure_unique_fields - ensure_hkey - parse_gsis! - parse_table_config! - parse_validations! - - if !@parse_errors.empty? - STDERR.puts "The following errors were encountered while trying to parse the given attributes" - STDERR.puts - STDERR.puts @parse_errors - STDERR.puts - - abort("Please fix the errors before proceeding.") - end + module Generators + class Base < Rails::Generators::NamedBase + argument :attributes, type: :array, default: [], banner: 'field[:type][:opts]...', + desc: 'Describes the fields in the model' + check_class_collision + + class_option :disable_mutation_tracking, type: :boolean, desc: 'Disables dirty tracking' + class_option :timestamps, type: :boolean, desc: 'Adds created, updated timestamps to the model' + class_option :table_config, type: :hash, default: {}, banner: 'primary:R-W [SecondaryIndex1:R-W]...', + desc: 'Declares the r/w units for the model as well as any secondary indexes', required: true + class_option :gsi, type: :array, default: [], + banner: 'name:hkey{field_name}[,rkey{field_name},proj_type{ALL|KEYS_ONLY|INCLUDE}]...', desc: 'Allows for the declaration of secondary indexes' + class_option :table_name, type: :string, banner: 'model_table_name' + class_option :password_digest, type: :boolean, desc: 'Whether to add a password_digest field to the model' + + class_option :required, type: :array, default: [], banner: 'field1...', + desc: 'A list of attributes that are required for an instance of the model' + class_option :length_validations, type: :hash, default: {}, banner: 'field1:MIN-MAX...', + desc: 'Validations on the length of attributes in a model' + class_option :scaffold, type: :boolean, desc: 'Adds helper methods that scaffolding uses' + + attr_accessor :primary_read_units, :primary_write_units, :gsi_rw_units, :gsis, :required_attrs, + :length_validations + + private + + def initialize(args, *options) + options[0] << '--skip-table-config' if options[1][:behavior] == :revoke + @parse_errors = [] + + super + ensure_unique_fields + ensure_hkey + parse_gsis! + parse_table_config! + parse_validations! + + return if @parse_errors.empty? + + warn 'The following errors were encountered while trying to parse the given attributes' + $stderr.puts + warn @parse_errors + $stderr.puts + + abort('Please fix the errors before proceeding.') + end + + def parse_attributes! + self.attributes = (attributes || []).map do |attr| + GeneratedAttribute.parse(attr) + rescue ArgumentError => e + @parse_errors << e + next end - - def parse_attributes! - - self.attributes = (attributes || []).map do |attr| - begin - GeneratedAttribute.parse(attr) - rescue ArgumentError => e - @parse_errors << e - next - end - end - self.attributes = self.attributes.compact - - if options['password_digest'] - self.attributes << GeneratedAttribute.new("password_digest", :string_attr, :digest => true) - end + self.attributes = attributes.compact - if options['timestamps'] - self.attributes << GeneratedAttribute.parse("created:datetime:default_value{Time.now}") - self.attributes << GeneratedAttribute.parse("updated:datetime:default_value{Time.now}") - end + if options['password_digest'] + attributes << GeneratedAttribute.new('password_digest', :string_attr, digest: true) end - - def ensure_unique_fields - used_names = Set.new - duplicate_fields = [] - - self.attributes.each do |attr| - - if used_names.include? attr.name - duplicate_fields << [:attribute, attr.name] - end - used_names.add attr.name - - if attr.options.key? :database_attribute_name - raw_db_attr_name = attr.options[:database_attribute_name].delete('"') # db attribute names are wrapped with " to make template generation easier - - if used_names.include? raw_db_attr_name - duplicate_fields << [:database_attribute_name, raw_db_attr_name] - end - - used_names.add raw_db_attr_name - end - end - - if !duplicate_fields.empty? - duplicate_fields.each do |invalid_attr| - @parse_errors << ArgumentError.new("Found duplicated field name: #{invalid_attr[1]}, in attribute#{invalid_attr[0]}") - end - end + + return unless options['timestamps'] + + attributes << GeneratedAttribute.parse('created:datetime:default_value{Time.now}') + attributes << GeneratedAttribute.parse('updated:datetime:default_value{Time.now}') + end + + def ensure_unique_fields + used_names = Set.new + duplicate_fields = [] + + attributes.each do |attr| + duplicate_fields << [:attribute, attr.name] if used_names.include? attr.name + used_names.add attr.name + + next unless attr.options.key? :database_attribute_name + + raw_db_attr_name = attr.options[:database_attribute_name].delete('"') # db attribute names are wrapped with " to make template generation easier + + duplicate_fields << [:database_attribute_name, raw_db_attr_name] if used_names.include? raw_db_attr_name + + used_names.add raw_db_attr_name end - - def ensure_hkey - uuid_member = nil - hkey_member = nil - rkey_member = nil - - self.attributes.each do |attr| - if attr.options.key? :hash_key - if hkey_member - @parse_errors << ArgumentError.new("Redefinition of hash_key attr: #{attr.name}, original declaration of hash_key on: #{hkey_member.name}") - next - end - - hkey_member = attr - elsif attr.options.key? :range_key - if rkey_member - @parse_errors << ArgumentError.new("Redefinition of range_key attr: #{attr.name}, original declaration of range_key on: #{hkey_member.name}") - next - end - - rkey_member = attr - end - - if attr.name.include? "uuid" - uuid_member = attr + + return if duplicate_fields.empty? + + duplicate_fields.each do |invalid_attr| + @parse_errors << ArgumentError.new("Found duplicated field name: #{invalid_attr[1]}, in attribute#{invalid_attr[0]}") + end + end + + def ensure_hkey + uuid_member = nil + hkey_member = nil + rkey_member = nil + + attributes.each do |attr| + if attr.options.key? :hash_key + if hkey_member + @parse_errors << ArgumentError.new("Redefinition of hash_key attr: #{attr.name}, original declaration of hash_key on: #{hkey_member.name}") + next end - end - - if !hkey_member - if uuid_member - uuid_member.options[:hash_key] = true - else - self.attributes.unshift GeneratedAttribute.parse("uuid:hkey") + + hkey_member = attr + elsif attr.options.key? :range_key + if rkey_member + @parse_errors << ArgumentError.new("Redefinition of range_key attr: #{attr.name}, original declaration of range_key on: #{hkey_member.name}") + next end + + rkey_member = attr end + + uuid_member = attr if attr.name.include? 'uuid' end - - def mutation_tracking_disabled? - options['disable_mutation_tracking'] + + return if hkey_member + + if uuid_member + uuid_member.options[:hash_key] = true + else + attributes.unshift GeneratedAttribute.parse('uuid:hkey') end - - def has_validations? - !@required_attrs.empty? || !@length_validations.empty? + end + + def mutation_tracking_disabled? + options['disable_mutation_tracking'] + end + + def has_validations? + !@required_attrs.empty? || !@length_validations.empty? + end + + def parse_table_config! + return unless options['table_config'] + + @primary_read_units, @primary_write_units = parse_rw_units('primary') + + @gsi_rw_units = @gsis.to_h do |idx| + [idx.name, parse_rw_units(idx.name)] end - def parse_table_config! - return unless options['table_config'] - - @primary_read_units, @primary_write_units = parse_rw_units("primary") - - @gsi_rw_units = @gsis.map { |idx| - [idx.name, parse_rw_units(idx.name)] - }.to_h - - options['table_config'].each do |config, rw_units| - if config == "primary" - next - else - gsi = @gsis.select { |idx| idx.name == config} - - if gsi.empty? - @parse_errors << ArgumentError.new("Could not find a gsi declaration for #{config}") - end - end - end + options['table_config'].each_key do |config| + next if config == 'primary' + + gsi = @gsis.select { |idx| idx.name == config } + + @parse_errors << ArgumentError.new("Could not find a gsi declaration for #{config}") if gsi.empty? end - - def parse_rw_units(name) - if !options['table_config'].key? name - @parse_errors << ArgumentError.new("Please provide a table_config definition for #{name}") - else - rw_units = options['table_config'][name] - return rw_units.gsub(/[,.-]/, ':').split(':').reject { |s| s.empty? } - end + end + + def parse_rw_units(name) + if options['table_config'].key? name + rw_units = options['table_config'][name] + rw_units.gsub(/[,.-]/, ':').split(':').reject(&:empty?) + else + @parse_errors << ArgumentError.new("Please provide a table_config definition for #{name}") end - - def parse_gsis! - @gsis = (options['gsi'] || []).map do |raw_idx| - begin - idx = SecondaryIndex.parse(raw_idx) - - attributes = self.attributes.select { |attr| attr.name == idx.hash_key} - if attributes.empty? - @parse_errors << ArgumentError.new("Could not find attribute #{idx.hash_key} for gsi #{idx.name} hkey") - next - end - - if idx.range_key - attributes = self.attributes.select { |attr| attr.name == idx.range_key} - if attributes.empty? - @parse_errors << ArgumentError.new("Could not find attribute #{idx.range_key} for gsi #{idx.name} rkey") - next - end - end - - idx - rescue ArgumentError => e - @parse_errors << e + end + + def parse_gsis! + @gsis = (options['gsi'] || []).map do |raw_idx| + idx = SecondaryIndex.parse(raw_idx) + + attributes = self.attributes.select { |attr| attr.name == idx.hash_key } + if attributes.empty? + @parse_errors << ArgumentError.new("Could not find attribute #{idx.hash_key} for gsi #{idx.name} hkey") + next + end + + if idx.range_key + attributes = self.attributes.select { |attr| attr.name == idx.range_key } + if attributes.empty? + @parse_errors << ArgumentError.new("Could not find attribute #{idx.range_key} for gsi #{idx.name} rkey") next end end - - @gsis = @gsis.compact + + idx + rescue ArgumentError => e + @parse_errors << e + next end - - def parse_validations! - @required_attrs = options['required'] - @required_attrs.each do |val_attr| - @parse_errors << ArgumentError.new("No such field #{val_attr} in required validations") if !self.attributes.any? { |attr| attr.name == val_attr } + + @gsis = @gsis.compact + end + + def parse_validations! + @required_attrs = options['required'] + @required_attrs.each do |val_attr| + @parse_errors << ArgumentError.new("No such field #{val_attr} in required validations") if attributes.none? do |attr| + attr.name == val_attr end - - @length_validations = options['length_validations'].map do |val_attr, bounds| - @parse_errors << ArgumentError.new("No such field #{val_attr} in required validations") if !self.attributes.any? { |attr| attr.name == val_attr } - - bounds = bounds.gsub(/[,.-]/, ':').split(':').reject { |s| s.empty? } - [val_attr, "#{bounds[0]}..#{bounds[1]}"] + end + + @length_validations = options['length_validations'].map do |val_attr, bounds| + @parse_errors << ArgumentError.new("No such field #{val_attr} in required validations") if attributes.none? do |attr| + attr.name == val_attr end - @length_validations = @length_validations.to_h + + bounds = bounds.gsub(/[,.-]/, ':').split(':').reject(&:empty?) + [val_attr, "#{bounds[0]}..#{bounds[1]}"] end + @length_validations = @length_validations.to_h end end end - \ No newline at end of file +end diff --git a/lib/generators/aws_record/erb/erb_generator.rb b/lib/generators/aws_record/erb/erb_generator.rb index 279f665..ae240e7 100755 --- a/lib/generators/aws_record/erb/erb_generator.rb +++ b/lib/generators/aws_record/erb/erb_generator.rb @@ -1,49 +1,38 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. +# frozen_string_literal: true -require "rails/generators/erb" -require "rails/generators/resource_helpers" +require 'rails/generators/erb' +require 'rails/generators/resource_helpers' module AwsRecord module Generators class ErbGenerator < Base include Rails::Generators::ResourceHelpers - source_root File.expand_path('../templates', __FILE__) + source_root File.expand_path('templates', __dir__) - argument :attributes, type: :array, default: [], banner: "field:type field:type" + argument :attributes, type: :array, default: [], banner: 'field:type field:type' def initialize(args, *options) - options[0] << "--skip-table-config" + options[0] << '--skip-table-config' super end def create_root_folder - empty_directory File.join("app/views", controller_file_path) + empty_directory File.join('app/views', controller_file_path) end def copy_view_files available_views.each do |view| formats.each do |format| filename = filename_with_extensions(view, format) - template filename, File.join("app/views", controller_file_path, filename) + template filename, File.join('app/views', controller_file_path, filename) end end end - private + private def available_views - %w(index edit show new _form) + %w[index edit show new _form] end def formats @@ -59,9 +48,8 @@ def handler end def filename_with_extensions(name, file_format = format) - [name, file_format, handler].compact.join(".") + [name, file_format, handler].compact.join('.') end - end end end diff --git a/lib/generators/aws_record/model/model_generator.rb b/lib/generators/aws_record/model/model_generator.rb index f99871e..417bcb3 100644 --- a/lib/generators/aws_record/model/model_generator.rb +++ b/lib/generators/aws_record/model/model_generator.rb @@ -1,37 +1,25 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. +# frozen_string_literal: true -require 'rails/generators' -require 'aws-record-generator' require 'generators/aws_record/base' module AwsRecord module Generators class ModelGenerator < Base - def initialize(args, *options) - self.class.source_root File.expand_path('../templates', __FILE__) + self.class.source_root File.expand_path('templates', __dir__) super end def create_model - template "model.rb", File.join("app/models", class_path, "#{file_name}.rb") + template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb") end def create_table_config - template "table_config.rb", File.join("db/table_config", class_path, "#{file_name}_config.rb") if options["table_config"] - end + return unless options['table_config'] + template 'table_config.rb', + File.join('db/table_config', class_path, "#{file_name}_config.rb") + end end end end diff --git a/lib/generators/aws_record/model/templates/model.rb.tt b/lib/generators/aws_record/model/templates/model.rb.tt index cb0fe03..02cb548 100644 --- a/lib/generators/aws_record/model/templates/model.rb.tt +++ b/lib/generators/aws_record/model/templates/model.rb.tt @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' <% if has_validations? -%> require 'active_model' diff --git a/lib/generators/aws_record/model/templates/table_config.rb.tt b/lib/generators/aws_record/model/templates/table_config.rb.tt index c904ddc..19d7587 100644 --- a/lib/generators/aws_record/model/templates/table_config.rb.tt +++ b/lib/generators/aws_record/model/templates/table_config.rb.tt @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' module ModelTableConfig diff --git a/lib/generators/aws_record/resource/resource_generator.rb b/lib/generators/aws_record/resource/resource_generator.rb index 18c7c30..c2df9c0 100755 --- a/lib/generators/aws_record/resource/resource_generator.rb +++ b/lib/generators/aws_record/resource/resource_generator.rb @@ -1,18 +1,7 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. +# frozen_string_literal: true -require "rails/generators/rails/resource_route/resource_route_generator" -require "rails/generators/resource_helpers" +require 'rails/generators/rails/resource_route/resource_route_generator' +require 'rails/generators/resource_helpers' require 'generators/aws_record/active_model' module AwsRecord @@ -23,6 +12,7 @@ class ResourceGenerator < ModelGenerator hook_for :resource_route, in: :rails, required: true private + def orm_class @orm_class = AwsRecord::Generators::ActiveModel end diff --git a/lib/generators/aws_record/scaffold/scaffold_generator.rb b/lib/generators/aws_record/scaffold/scaffold_generator.rb index dfb4f7a..aca5523 100755 --- a/lib/generators/aws_record/scaffold/scaffold_generator.rb +++ b/lib/generators/aws_record/scaffold/scaffold_generator.rb @@ -1,37 +1,28 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require "rails/generators/rails/scaffold/scaffold_generator" -require "generators/aws_record/resource/resource_generator" +# frozen_string_literal: true + +require 'rails/generators/rails/scaffold/scaffold_generator' +require 'generators/aws_record/resource/resource_generator' module AwsRecord module Generators class ScaffoldGenerator < ResourceGenerator - source_root File.expand_path('../../model/templates', __FILE__) + source_root File.expand_path('../model/templates', __dir__) remove_class_option :orm remove_class_option :actions class_option :api, type: :boolean - class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets" - class_option :stylesheet_engine, desc: "Engine for Stylesheets" + class_option :stylesheets, type: :boolean, desc: 'Generate Stylesheets' + class_option :stylesheet_engine, desc: 'Engine for Stylesheets' class_option :assets, type: :boolean class_option :resource_route, type: :boolean class_option :scaffold_stylesheet, type: :boolean def handle_skip @options = @options.merge(stylesheets: false) unless options[:assets] - @options = @options.merge(stylesheet_engine: false) unless options[:stylesheets] && options[:scaffold_stylesheet] + return if options[:stylesheets] && options[:scaffold_stylesheet] + + @options = @options.merge(stylesheet_engine: false) end hook_for :scaffold_controller, in: :aws_record, required: true @@ -41,14 +32,13 @@ def handle_skip end hook_for :stylesheet_engine, in: :rails do |stylesheet_engine| - if behavior == :invoke - invoke stylesheet_engine, [controller_name] - end + invoke stylesheet_engine, [controller_name] if behavior == :invoke end private + def initialize(args, *options) - options[0] << "--scaffold" + options[0] << '--scaffold' super end end diff --git a/lib/generators/aws_record/scaffold_controller/scaffold_controller_generator.rb b/lib/generators/aws_record/scaffold_controller/scaffold_controller_generator.rb index 8747067..bdac82a 100755 --- a/lib/generators/aws_record/scaffold_controller/scaffold_controller_generator.rb +++ b/lib/generators/aws_record/scaffold_controller/scaffold_controller_generator.rb @@ -1,43 +1,33 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require "rails/generators/resource_helpers" +# frozen_string_literal: true + +require 'rails/generators/resource_helpers' require 'generators/aws_record/active_model' module AwsRecord module Generators class ScaffoldControllerGenerator < Base include Rails::Generators::ResourceHelpers - source_root File.expand_path('../templates', __FILE__) + source_root File.expand_path('templates', __dir__) - check_class_collision suffix: "Controller" + check_class_collision suffix: 'Controller' class_option :helper, type: :boolean - class_option :orm, banner: "NAME", type: :string, required: true, - desc: "ORM to generate the controller for" + class_option :orm, banner: 'NAME', type: :string, required: true, + desc: 'ORM to generate the controller for' class_option :api, type: :boolean, - desc: "Generates API controller" + desc: 'Generates API controller' - argument :attributes, type: :array, default: [], banner: "field:type field:type" + argument :attributes, type: :array, default: [], banner: 'field:type field:type' def initialize(args, *options) - options[0] << "--skip-table-config" + options[0] << '--skip-table-config' super end def create_controller_files - template_file = options.api? ? "api_controller.rb" : "controller.rb" - template template_file, File.join("app/controllers", controller_class_path, "#{controller_file_name}_controller.rb") + template_file = options.api? ? 'api_controller.rb' : 'controller.rb' + template template_file, + File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb") end hook_for :template_engine, in: :aws_record do |template_engine| @@ -48,10 +38,11 @@ def create_controller_files # Invoke the helper using the controller name (pluralized) hook_for :helper, as: :scaffold, in: :rails do |invoked| - invoke invoked, [ controller_name ] + invoke invoked, [controller_name] end private + def orm_class @orm_class = AwsRecord::Generators::ActiveModel end diff --git a/lib/generators/generated_attribute.rb b/lib/generators/generated_attribute.rb index 0126678..9610d56 100644 --- a/lib/generators/generated_attribute.rb +++ b/lib/generators/generated_attribute.rb @@ -1,42 +1,32 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. +# frozen_string_literal: true module AwsRecord module Generators class GeneratedAttribute - - OPTS = %w(hkey rkey persist_nil db_attr_name ddb_type default_value) - INVALID_HKEY_TYPES = %i(map_attr list_attr numeric_set_attr string_set_attr) + OPTS = %w[hkey rkey persist_nil db_attr_name ddb_type default_value].freeze + INVALID_HKEY_TYPES = %i[map_attr list_attr numeric_set_attr string_set_attr].freeze attr_reader :name, :type attr_accessor :options def field_type case @type - when :integer_attr then :number_field - when :date_attr then :date_select - when :datetime_attr then :datetime_select - when :boolean_attr then :check_box - else :text_field + when :integer_attr then :number_field + when :date_attr then :date_select + when :datetime_attr then :datetime_select + when :boolean_attr then :check_box + else :text_field end end class << self - def parse(field_definition) name, type, opts = field_definition.split(':') - type = "string" if not type - type, opts = "string", type if OPTS.any? { |opt| type.include? opt } - + type ||= 'string' + if OPTS.any? { |opt| type.include? opt } + opts = type + type = 'string' + end + opts = opts.split(',') if opts type, opts = parse_type_and_options(name, type, opts) validate_opt_combs(name, type, opts) @@ -47,65 +37,71 @@ def parse(field_definition) private def validate_opt_combs(name, type, opts) - if opts - is_hkey = opts.key?(:hash_key) - is_rkey = opts.key?(:range_key) + return unless opts - raise ArgumentError.new("Field #{name} cannot be a range key and hash key simultaneously") if is_hkey && is_rkey - raise ArgumentError.new("Field #{name} cannot be a hash key and be of type #{type}") if is_hkey and INVALID_HKEY_TYPES.include? type + is_hkey = opts.key?(:hash_key) + is_rkey = opts.key?(:range_key) + + if is_hkey && is_rkey + raise ArgumentError, + "Field #{name} cannot be a range key and hash key simultaneously" end + return unless is_hkey && INVALID_HKEY_TYPES.include?(type) + + raise ArgumentError, + "Field #{name} cannot be a hash key and be of type #{type}" end - + def parse_type_and_options(name, type, opts) - opts = [] if not opts - return parse_type(name, type), opts.map { |opt| parse_option(name, opt) }.to_h + opts ||= [] + [parse_type(name, type), opts.to_h { |opt| parse_option(name, opt) }] end def parse_option(name, opt) case opt - when "hkey" - return :hash_key, true - when "rkey" - return :range_key, true - when "persist_nil" - return :persist_nil, true + when 'hkey' + [:hash_key, true] + when 'rkey' + [:range_key, true] + when 'persist_nil' + [:persist_nil, true] when /db_attr_name\{(\w+)\}/ - return :database_attribute_name, '"' + $1 + '"' + [:database_attribute_name, "\"#{::Regexp.last_match(1)}\""] when /ddb_type\{(S|N|B|BOOL|SS|NS|BS|M|L)\}/i - return :dynamodb_type, '"' + $1.upcase + '"' + [:dynamodb_type, "\"#{::Regexp.last_match(1).upcase}\""] when /default_value\{(.+)\}/ - return :default_value, $1 + [:default_value, ::Regexp.last_match(1)] else - raise ArgumentError.new("You provided an invalid option for #{name}: #{opt}") + raise ArgumentError, "You provided an invalid option for #{name}: #{opt}" end end def parse_type(name, type) case type.downcase - when "bool", "boolean" + when 'bool', 'boolean' :boolean_attr - when "date" + when 'date' :date_attr - when "datetime" + when 'datetime' :datetime_attr - when "float" + when 'float' :float_attr - when "int", "integer" + when 'int', 'integer' :integer_attr - when "list" + when 'list' :list_attr - when "map" + when 'map' :map_attr - when "num_set", "numeric_set", "nset" + when 'num_set', 'numeric_set', 'nset' :numeric_set_attr - when "string_set", "s_set", "sset" + when 'string_set', 's_set', 'sset' :string_set_attr - when "string" + when 'string' :string_attr else - raise ArgumentError.new("Invalid type for #{name}: #{type}") + raise ArgumentError, "Invalid type for #{name}: #{type}" end end end @@ -127,8 +123,8 @@ def polymorphic? end def column_name - if @name == "password_digest" - "password" + if @name == 'password_digest' + 'password' else @name end diff --git a/lib/generators/secondary_index.rb b/lib/generators/secondary_index.rb index cf7189f..1914e76 100644 --- a/lib/generators/secondary_index.rb +++ b/lib/generators/secondary_index.rb @@ -1,21 +1,9 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. +# frozen_string_literal: true module AwsRecord module Generators class SecondaryIndex - - PROJ_TYPES = %w(ALL KEYS_ONLY INCLUDE) + PROJ_TYPES = %w[ALL KEYS_ONLY INCLUDE].freeze attr_reader :name, :hash_key, :range_key, :projection_type class << self @@ -28,45 +16,50 @@ def parse(key_definition) end private - def parse_raw_options(raw_opts) - raw_opts = [] if not raw_opts - raw_opts.map { |opt| get_option_value(opt) }.to_h - end - def get_option_value(raw_option) - case raw_option + def parse_raw_options(raw_opts) + raw_opts ||= [] + raw_opts.to_h { |opt| get_option_value(opt) } + end + + def get_option_value(raw_option) + case raw_option - when /hkey\{(\w+)\}/ - return :hash_key, $1 - when /rkey\{(\w+)\}/ - return :range_key, $1 - when /proj_type\{(\w+)\}/ - return :projection_type, $1 - else - raise ArgumentError.new("Invalid option for secondary index #{raw_option}") - end + when /hkey\{(\w+)\}/ + [:hash_key, ::Regexp.last_match(1)] + when /rkey\{(\w+)\}/ + [:range_key, ::Regexp.last_match(1)] + when /proj_type\{(\w+)\}/ + [:projection_type, ::Regexp.last_match(1)] + else + raise ArgumentError, "Invalid option for secondary index #{raw_option}" end + end end def initialize(name, opts) - raise ArgumentError.new("You must provide a name") if not name - raise ArgumentError.new("You must provide a hash key") if not opts[:hash_key] + raise ArgumentError, 'You must provide a name' unless name + raise ArgumentError, 'You must provide a hash key' unless opts[:hash_key] if opts.key? :projection_type - raise ArgumentError.new("Invalid projection type #{opts[:projection_type]}") if not PROJ_TYPES.include? opts[:projection_type] - raise NotImplementedError.new("ALL is the only projection type currently supported") if opts[:projection_type] != "ALL" + unless PROJ_TYPES.include? opts[:projection_type] + raise ArgumentError, "Invalid projection type #{opts[:projection_type]}" + end + if opts[:projection_type] != 'ALL' + raise NotImplementedError, 'ALL is the only projection type currently supported' + end else - opts[:projection_type] = "ALL" + opts[:projection_type] = 'ALL' end if opts[:hash_key] == opts[:range_key] - raise ArgumentError.new("#{opts[:hash_key]} cannot be both the rkey and hkey for gsi #{name}") + raise ArgumentError, "#{opts[:hash_key]} cannot be both the rkey and hkey for gsi #{name}" end @name = name @hash_key = opts[:hash_key] @range_key = opts[:range_key] - @projection_type = '"' + "#{opts[:projection_type]}" + '"' + @projection_type = "\"#{opts[:projection_type]}\"" end end end diff --git a/lib/generators/test_helper.rb b/lib/generators/test_helper.rb deleted file mode 100644 index 3de9428..0000000 --- a/lib/generators/test_helper.rb +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require "rails/generators/rails/app/app_generator" -require "rails/generators/testing/behaviour" -require "rails/generators/testing/assertions" -require "fileutils" -require "minitest/spec" - -module AwsRecord - module Generators - class GeneratorTestHelper - include Minitest::Assertions - attr_accessor :assertions - - include Rails::Generators::Testing::Behaviour - include Rails::Generators::Testing::Assertions - include FileUtils - - def initialize(klass, dest) - @temp_root = File.expand_path(dest) - - GeneratorTestHelper.tests klass - temp_app_dest = File.join(File.expand_path(@temp_root, __dir__), "test_app") - GeneratorTestHelper.destination temp_app_dest - - destination_root_is_set? - prepare_destination - setup_test_app - ensure_current_path - - self.assertions = 0 - end - - def run_in_test_app(cmd) - cd destination_root - a = `rails #{cmd}` - - ensure_current_path - end - - def assert_file_fixture(generated_file, actual_file) - assert File.exist?(generated_file), "Expected file #{generated_file.inspect} to exist, but does not" - assert File.exist?(actual_file), "Expected file #{actual_file.inspect} to exist, but does not" - assert identical? generated_file, actual_file - end - - def assert_model_rand_table_name(generated_file, actual_file, table_name) - assert File.exist?(generated_file), "Expected file #{generated_file.inspect} to exist, but does not" - assert File.exist?(actual_file), "Expected file #{actual_file.inspect} to exist, but does not" - - fixture = File.read(actual_file) - generated = File.read(generated_file) - fixture = fixture.gsub(/#table_name#/, table_name) - - assert fixture == generated - end - - def cleanup - rm_rf @temp_root - end - - def run_generator(args = default_arguments, config = {}) - result = nil - capture(:stderr) do - result = super - end - result - end - - private - - def setup_test_app - Rails::Generators::AppGenerator.start [destination_root, '--skip-bundle', '--skip-git', '--skip-spring', '--skip-test', '--force', '--quiet', '--skip-webpack-install'] - `echo 'gem "aws-record-generator", :path => "../../"' >> "#{destination_root}/Gemfile"` - `bundle install --gemfile "#{destination_root}/Gemfile"` - end - end - end -end diff --git a/fixtures/unit/table_config_migrate_task.rake b/lib/tasks/aws_record/migrate.rake similarity index 60% rename from fixtures/unit/table_config_migrate_task.rake rename to lib/tasks/aws_record/migrate.rake index da3c38b..f9d945d 100644 --- a/fixtures/unit/table_config_migrate_task.rake +++ b/lib/tasks/aws_record/migrate.rake @@ -1,10 +1,11 @@ -desc "Run all table configs in table_config folder" +# frozen_string_literal: true +desc 'Run all table configs in db/table_config folder' namespace :aws_record do task migrate: :environment do Dir[File.join('db', 'table_config', '**/*.rb')].each do |filename| - puts "running #{filename}" - load(filename) + puts "running #{filename}.rb" + require(File.expand_path(filename)) table_config = ModelTableConfig.config table_config.migrate! unless table_config.compatible? diff --git a/lib/tasks/table_config_migrate_task.rake b/lib/tasks/table_config_migrate_task.rake deleted file mode 100644 index 0c0898d..0000000 --- a/lib/tasks/table_config_migrate_task.rake +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -desc "Run all table configs in table_config folder" - -namespace :aws_record do - task migrate: :environment do - Dir[File.join('db', 'table_config', '**/*.rb')].each do |filename| - puts "running #{filename}" - require (File.expand_path(filename)) - - table_config = ModelTableConfig.config - table_config.migrate! unless table_config.compatible? - end - end -end diff --git a/spec/aws-record-generator/generators/aws_record/generated_attribute_spec.rb b/spec/aws-record-generator/generators/aws_record/generated_attribute_spec.rb deleted file mode 100644 index d0831aa..0000000 --- a/spec/aws-record-generator/generators/aws_record/generated_attribute_spec.rb +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require 'spec_helper' - -module AwsRecord - module Generators - describe GeneratedAttribute do - - context 'when given valid input' do - it 'sets the name and type correctly' do - params = "uuid:int" - - attribute = GeneratedAttribute.parse(params) - expect(attribute.name).to eq("uuid") - expect(attribute.type).to eq(:integer_attr) - end - - it 'properly defaults to string_attr when only a name is provided' do - params = "uuid" - - attribute = GeneratedAttribute.parse(params) - expect(attribute.name).to eq("uuid") - expect(attribute.type).to eq(:string_attr) - end - - it 'properly parses all valid types for an attribute' do - VALID_TYPES = { - "bool" => :boolean_attr, - "boolean" => :boolean_attr, - "date" => :date_attr, - "datetime" => :datetime_attr, - "float" => :float_attr, - "int" => :integer_attr, - "integer" => :integer_attr, - "list" => :list_attr, - "map" => :map_attr, - "num_set" => :numeric_set_attr, - "numeric_set" => :numeric_set_attr, - "nset" => :numeric_set_attr, - "string_set" => :string_set_attr, - "s_set" => :string_set_attr, - "sset" => :string_set_attr, - "string" => :string_attr - } - - base_params = "uuid:" - VALID_TYPES.each do |input, attr_type| - input_params = "#{base_params}#{input}" - - attribute = GeneratedAttribute.parse(input_params) - expect(attribute.name).to eq("uuid") - expect(attribute.type).to eq(attr_type) - end - end - - context 'properly handles attribute options' do - - VALID_OPTIONS = { - "hkey" => [:hash_key, true], - "rkey" => [:range_key, true], - "persist_nil" => [:persist_nil, true], - "db_attr_name{PostTitle}" => [:database_attribute_name, '"PostTitle"'], - "ddb_type{BOOL}" => [:dynamodb_type, '"BOOL"'], - "default_value{9}" => [:default_value, "9"] - } - - it 'properly handles all valid options' do - base_params = "uuid:" - VALID_OPTIONS.each do |opt, parsed_opt| - input_params = "#{base_params}#{opt}" - - attribute = GeneratedAttribute.parse(input_params) - expect(attribute.name).to eq("uuid") - expect(attribute.type).to eq(:string_attr) - expect(attribute.options.to_a).to eq([parsed_opt]) - end - end - - context 'properly handles using options in combination with one another' do - it 'allows fields to have a default value and a ddb_type' do - params = "is_context:bool:persist_nil,ddb_type{BOOL}" - - attribute = GeneratedAttribute.parse(params) - expect(attribute.name).to eq("is_context") - expect(attribute.type).to eq(:boolean_attr) - expect(attribute.options.to_a).to eq([[:persist_nil, true], [:dynamodb_type, '"BOOL"']]) - end - - it 'allows a key field to have a db_attr_name' do - params = "uuid:hkey,db_attr_name{PostTitle}" - - attribute = GeneratedAttribute.parse(params) - expect(attribute.name).to eq("uuid") - expect(attribute.type).to eq(:string_attr) - expect(attribute.options.to_a).to eq([[:hash_key, true], [:database_attribute_name, '"PostTitle"']]) - end - end - end - - it 'properly infers that a type has not been provided when other options are' do - params = "uuid:hkey" - - attribute = GeneratedAttribute.parse(params) - expect(attribute.name).to eq("uuid") - expect(attribute.type).to eq(:string_attr) - expect(attribute.options.to_a).to eq([[:hash_key, true]]) - end - end - - context 'when invalid input is provided' do - - it 'properly detects when an invalid type is provided' do - params = "uuid:invalid_type:hkey" - - expect { - attribute = GeneratedAttribute.parse(params) - }.to raise_error(ArgumentError) - end - - it 'properly detects when an invalid opt is provided' do - params = "uuid:hkey,invalid_opt" - - expect { - attribute = GeneratedAttribute.parse(params) - }.to raise_error(ArgumentError) - end - - it 'detects when a field is declared as both an hkey and rkey' do - params = "uuid:string:hkey,rkey" - - expect { - attribute = GeneratedAttribute.parse(params) - }.to raise_error(ArgumentError) - end - - it 'detects when a map_attr is declared as a hkey' do - params = "uuid:map:hkey" - - expect { - attribute = GeneratedAttribute.parse(params) - }.to raise_error(ArgumentError) - end - - end - end - end -end diff --git a/spec/aws-record-generator/generators/aws_record/model/model_generator_spec.rb b/spec/aws-record-generator/generators/aws_record/model/model_generator_spec.rb deleted file mode 100644 index 1e51b9c..0000000 --- a/spec/aws-record-generator/generators/aws_record/model/model_generator_spec.rb +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require 'spec_helper' - -def generate_and_assert_model(name, *opts) - file_name = name.underscore - opts.unshift name - @gen_helper.run_generator opts - - generated_file_path = File.join(@gen_helper.destination_root, "app/models/#{file_name}.rb") - fixture_file_path = File.expand_path("fixtures/unit/model/#{file_name}.rb") - @gen_helper.assert_file_fixture(generated_file_path, fixture_file_path) -end - -def generate_and_assert_table_config(name, *opts) - file_name = name.underscore - opts.unshift name - @gen_helper.run_generator opts - - generated_file_path = File.join(@gen_helper.destination_root, "db/table_config/#{file_name}_config.rb") - fixture_file_path = File.expand_path("fixtures/unit/table_config/#{file_name}_config.rb") - @gen_helper.assert_file_fixture(generated_file_path, fixture_file_path) -end - -module AwsRecord - module Generators - - describe ModelGenerator do - before(:all) do - @gen_helper = GeneratorTestHelper.new(ModelGenerator, "tmp") - end - - after(:all) do - @gen_helper.cleanup - end - - context 'properly generates basic models' do - it 'properly creates a model with one field' do - generate_and_assert_model 'TestModelBasic', "uuid:hkey", "--table-config=primary:5-2" - end - - context 'creates an hkey when one is not provided' do - it 'creates a uuid hkey when no fields are provided' do - generate_and_assert_model 'TestModelFieldsAbsentAutoUuid', "--table-config=primary:5-2" - end - - it 'creates a uuid hkey when fields are provided but an hkey is not' do - generate_and_assert_model "TestModelFieldsPresentAutoUuid", "name", "--table-config=primary:5-2" - end - - it 'adds an hkey option to the uuid attribute if it is present, but no other field is an hkey' do - generate_and_assert_model "TestModelAutoHkey", "uuid", "--table-config=primary:5-2" - end - end - - it 'allows the user to disable mutation tracking' do - generate_and_assert_model "TestModelMutTracking", "uuid:hkey", "--disable-mutation-tracking", "--table-config=primary:5-2" - end - - it 'allows the user to generate models with multiple fields and options' do - generate_and_assert_model "TestModelComplex", "forum_uuid:hkey", "post_id:rkey", "author_username", "post_title", "post_body", "tags:sset:default_value{Set.new}", "created_at:datetime:db_attr_name{PostCreatedAtTime}", "moderation:boolean:default_value{false}", "--table-config=primary:5-2" - end - - it 'enforces the uniqueness of field names' do - expect { - @gen_helper.run_generator ["TestModel_Err", "uuid:hkey", "uuid", "--table-config=primary:5-2"] - }.to raise_error(SystemExit) - - @gen_helper.assert_no_file(File.join(@gen_helper.destination_root, "app/models/test_model_err.rb")) - end - - it 'enforces the uniqueness of field db_attribute_name across fields' do - expect { - @gen_helper.run_generator ["TestModel_Err", "uuid:hkey", "long_title:db_attr_name{uuid}", "--table-config=primary:5-2"] - }.to raise_error(SystemExit) - - @gen_helper.assert_no_file(File.join(@gen_helper.destination_root, "app/models/test_model_err.rb")) - end - - it 'raises an ArgumentError if any of the fields have errors' do - expect { - @gen_helper.run_generator ["TestModel_Err", "uuid:invalid_type:hkey", "uuid:hkey,invalid_opt", "uuid:string:hkey,rkey", "uuid:map:hkey", "--table-config=primary:5-2"] - }.to raise_error(SystemExit) - end - - it 'allows the user to specify a custom table name' do - generate_and_assert_model "TestModelSetTableName", "--table-config=primary:5-2", "--table-name=CustomTableName" - end - - end - - context 'properly generated table configs based on input' do - it 'throws an error when no table config attributes are provided' do - expect { - generate_and_assert_table_config "TableConfigTestModel1", "uuid:hkey" - }.to raise_error(SystemExit) - end - - it 'properly generates the table_config when primary r/w units are provided' do - generate_and_assert_table_config "TableConfigTestModel2", "--table-config=primary:20-10" - end - end - - context 'properly handles generating secondary indexes' do - context 'gsis are properly inserted into models' do - it 'generates a gsi with only rkey' do - generate_and_assert_model "TestModelGSIBasic", "gsi_hkey", "--gsi=SecondaryIndex:hkey{gsi_hkey}", "--table-config=primary:5-2", "SecondaryIndex:5-2" - end - - it 'generates a gsi with rkey and hkey' do - generate_and_assert_model "TestModelGSIKeys", "gsi_hkey", "gsi_rkey", "--gsi=SecondaryIndex:hkey{gsi_hkey},rkey{gsi_rkey}", "--table-config=primary:5-2", "SecondaryIndex:5-2" - end - - it 'generates a model with multiple gsis' do - generate_and_assert_model "TestModelGSIMult", "gsi_hkey", "gsi2_hkey", "--gsi=SecondaryIndex:hkey{gsi_hkey}", "SecondaryIndex2:hkey{gsi2_hkey}", "--table-config=primary:5-2", "SecondaryIndex:5-2", "SecondaryIndex2:5-2" - end - - it 'enforces that a given hkey is a valid field in the model' do - expect { - @gen_helper.run_generator ["TestModel_Err", "gsi_rkey", "--gsi=SecondaryIndex:hkey{gsi_hkey},rkey{gsi_rkey}", "--table-config=primary:5-2", "SecondaryIndex:5-2"] - }.to raise_error(SystemExit) - - @gen_helper.assert_no_file(File.join(@gen_helper.destination_root, "app/models/test_model_err.rb")) - end - - it 'enforces that a given rkey is a valid field in the model' do - expect { - @gen_helper.run_generator ["TestModel_Err", "gsi_hkey", "--gsi=SecondaryIndex:hkey{gsi_hkey},rkey{gsi_rkey}", "--table-config=primary:5-2", "SecondaryIndex:5-2"] - }.to raise_error(SystemExit) - - @gen_helper.assert_no_file(File.join(@gen_helper.destination_root, "app/models/test_model_err.rb")) - end - end - - context 'gsis are properly added into table_configs' do - it 'throws an error when no r/w unit info is provided' do - expect { - generate_and_assert_table_config "TestTableConfigGSIBasic", "gsi_hkey", "--gsi=SecondaryIndex:hkey{gsi_hkey}", "--table-config=primary:5-2" - }.to raise_error(SystemExit) - end - - it 'the user can provide r/w values for a table config' do - generate_and_assert_table_config "TestTableConfigGSIProvided", "gsi_hkey", "--gsi=SecondaryIndex:hkey{gsi_hkey}", "--table-config=primary:5-2", "SecondaryIndex:50-100" - end - - it 'generates a table_config with multiple gsis' do - generate_and_assert_table_config "TestTable_ConfigGSIMult", "gsi_hkey", "gsi2_hkey", "--gsi=SecondaryIndex:hkey{gsi_hkey}", "SecondaryIndex2:hkey{gsi2_hkey}", "--table-config=primary:5-2", "SecondaryIndex:10-11", "SecondaryIndex2:40-20" - end - - it 'errors out when the user provides r/w values for a secondary index that does not exist' do - expect { - generate_and_assert_table_config "TestModel_Err", "gsi_hkey", "--gsi=SecondaryIndex:hkey{gsi_hkey}", "--table-config=primary:5-2", "SecondaryIndexes:50-100" - }.to raise_error(SystemExit) - end - end - end - - context 'allows users to automatically add timestamps to their model' do - it 'creates timestamps when the flag is enabled' do - generate_and_assert_model "TestModelTimestamps", "--timestamps", "--table_config=primary:5-2" - end - end - - context 'allows use of basic ActiveModel validations' do - it 'allows specification of required validations' do - generate_and_assert_model "TestRequiredValidations", "title", "body", "--required=title,body", "--table_config=primary:5-2" - end - - it 'allows specification of length validations' do - generate_and_assert_model "TestLengthValidations", "title", "body", "--length-validations=title:5-10", "body:100-250", "--table_config=primary:5-2" - end - - it 'allows specification of a combination of validations' do - generate_and_assert_model "TestValidations", "title", "body", "--required=title,body", "--length-validations=title:5-10", "body:100-250", "--table_config=primary:5-2" - end - end - - context 'allows you to disable table_config generation' do - it 'allows specification of required validations' do - @gen_helper.run_generator ["TestSkipTableConfig", "--skip-table-config"] - @gen_helper.assert_no_file(File.join(@gen_helper.destination_root, "db/table_config/test_skip_table_config_config.rb")) - end - end - - it 'allows the generation of scaffold helpers' do - generate_and_assert_model "TestScaffoldHelpers", "--table_config=primary:5-2", "--scaffold" - end - - it 'allows the generation of a password digest field' do - generate_and_assert_model "TestPasswordDigest", "--table_config=primary:5-2", "--password-digest" - end - - end - end -end diff --git a/spec/aws-record-generator/generators/aws_record/resource/resource_generator_spec.rb b/spec/aws-record-generator/generators/aws_record/resource/resource_generator_spec.rb deleted file mode 100644 index 06e71b6..0000000 --- a/spec/aws-record-generator/generators/aws_record/resource/resource_generator_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require 'spec_helper' - -module AwsRecord - module Generators - - describe ResourceGenerator do - before(:all) do - @gen_helper = GeneratorTestHelper.new(ResourceGenerator, "tmp") - end - - after(:all) do - @gen_helper.cleanup - end - - it 'displays the options for inherited options' do - content = @gen_helper.run_generator ["--help"] - @gen_helper.assert_match(/--table-config=primary:R-W/, content) - end - - it 'generates the files of inherited invocations' do - @gen_helper.run_generator ["InheritedFileGenerationTest", "--table-config=primary:5-3"] - - %w(app/models/inherited_file_generation_test.rb db/table_config/inherited_file_generation_test_config.rb).each do |path| - @gen_helper.assert_file(path) - end - end - - it 'removes a route on revoke' do - @gen_helper.run_generator ["account", "--table-config=primary:12-4"] - @gen_helper.run_generator ["account"], behavior: :revoke - - @gen_helper.assert_file "config/routes.rb" do |route| - @gen_helper.refute_match(/resources :accounts$/, route) - end - end - - end - end -end diff --git a/spec/aws-record-generator/generators/aws_record/scaffold_controller/scaffold_controller_generator_spec.rb b/spec/aws-record-generator/generators/aws_record/scaffold_controller/scaffold_controller_generator_spec.rb deleted file mode 100644 index 9bd36ff..0000000 --- a/spec/aws-record-generator/generators/aws_record/scaffold_controller/scaffold_controller_generator_spec.rb +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require 'spec_helper' - -module AwsRecord - module Generators - - describe ScaffoldControllerGenerator do - before(:all) do - @gen_helper = GeneratorTestHelper.new(ScaffoldControllerGenerator, "tmp") - end - - after(:all) do - @gen_helper.cleanup - end - - it 'generates the controller skeleton properly' do - @gen_helper.run_generator ["ControllerSkeletonTest", "name", "age:int", "--skip-table-config"] - - @gen_helper.assert_file "app/controllers/controller_skeleton_tests_controller.rb" do |content| - @gen_helper.assert_match(/class ControllerSkeletonTestsController < ApplicationController/, content) - - @gen_helper.assert_instance_method :index, content do |m| - @gen_helper.assert_match(/@controller_skeleton_tests = ControllerSkeletonTest\.scan/, m) - end - - @gen_helper.assert_instance_method :show, content - - @gen_helper.assert_instance_method :new, content do |m| - @gen_helper.assert_match(/@controller_skeleton_test = ControllerSkeletonTest\.new/, m) - end - - @gen_helper.assert_instance_method :edit, content - - @gen_helper.assert_instance_method :create, content do |m| - @gen_helper.assert_match(/@controller_skeleton_test = ControllerSkeletonTest\.new\(controller_skeleton_test_params\)/, m) - @gen_helper.assert_match(/@controller_skeleton_test\.save/, m) - end - - @gen_helper.assert_instance_method :update, content do |m| - @gen_helper.assert_match(/@controller_skeleton_test\.update\(controller_skeleton_test_params\)/, m) - end - - @gen_helper.assert_instance_method :destroy, content do |m| - @gen_helper.assert_match(/@controller_skeleton_test\.delete!/, m) - @gen_helper.assert_match(/Controller skeleton test was successfully destroyed./, m) - end - - @gen_helper.assert_instance_method :set_controller_skeleton_test, content do |m| - @gen_helper.assert_match(/@controller_skeleton_test = ControllerSkeletonTest\.find\(uuid: CGI.unescape\(params\[:id\]\)\)/, m) - end - - @gen_helper.assert_instance_method :controller_skeleton_test_params, content do |m| - @gen_helper.assert_match(/params\.require\(:controller_skeleton_test\)\.permit\(:uuid, :name, :age\)/, m) - end - end - end - - it 'generates the api-controller skeleton properly' do - @gen_helper.run_generator ["ApiControllerSkeletonTest", "--api","--skip-table-config"] - - @gen_helper.assert_file "app/controllers/api_controller_skeleton_tests_controller.rb" do |content| - @gen_helper.assert_match(/class ApiControllerSkeletonTestsController < ApplicationController/, content) - @gen_helper.refute_match(/respond_to/, content) - - @gen_helper.assert_match(/before_action :set_api_controller_skeleton_test, only: \[:show, :update, :destroy\]/, content) - - @gen_helper.assert_instance_method :index, content do |m| - @gen_helper.assert_match(/@api_controller_skeleton_tests = ApiControllerSkeletonTest\.scan/, m) - @gen_helper.assert_match(/render json: @api_controller_skeleton_tests/, m) - end - - @gen_helper.assert_instance_method :show, content do |m| - @gen_helper.assert_match(/render json: @api_controller_skeleton_test/, m) - end - - @gen_helper.assert_instance_method :create, content do |m| - @gen_helper.assert_match(/@api_controller_skeleton_test = ApiControllerSkeletonTest\.new\(api_controller_skeleton_test_params\)/, m) - @gen_helper.assert_match(/@api_controller_skeleton_test\.save/, m) - @gen_helper.assert_match(/@api_controller_skeleton_test\.errors/, m) - end - - @gen_helper.assert_instance_method :update, content do |m| - @gen_helper.assert_match(/@api_controller_skeleton_test\.update\(api_controller_skeleton_test_params\)/, m) - @gen_helper.assert_match(/@api_controller_skeleton_test\.errors/, m) - end - - @gen_helper.assert_instance_method :destroy, content do |m| - @gen_helper.assert_match(/@api_controller_skeleton_test\.delete!/, m) - end - end - - @gen_helper.assert_no_file "app/views/api_controller_skeleton_tests/index.html.erb" - @gen_helper.assert_no_file "app/views/api_controller_skeleton_tests/edit.html.erb" - @gen_helper.assert_no_file "app/views/api_controller_skeleton_tests/show.html.erb" - @gen_helper.assert_no_file "app/views/api_controller_skeleton_tests/new.html.erb" - @gen_helper.assert_no_file "app/views/api_controller_skeleton_tests/_form.html.erb" - end - end - end -end diff --git a/spec/aws-record-generator/generators/aws_record/secondary_index_spec.rb b/spec/aws-record-generator/generators/aws_record/secondary_index_spec.rb deleted file mode 100644 index be69a4d..0000000 --- a/spec/aws-record-generator/generators/aws_record/secondary_index_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require 'spec_helper' - -module AwsRecord - module Generators - describe SecondaryIndex do - - context 'when given correct params' do - it 'sets its properties correctly' do - params = "Model:hkey{uuid},rkey{title}" - - idx = SecondaryIndex.parse(params) - expect(idx.name).to eq("Model") - expect(idx.hash_key).to eq("uuid") - expect(idx.range_key).to eq("title") - expect(idx.projection_type).to eq('"ALL"') - end - - it 'sets its properties correctly independent of input order' do - params = "Model:proj_type{ALL},hkey{uuid}" - - idx = SecondaryIndex.parse(params) - expect(idx.name).to eq("Model") - expect(idx.hash_key).to eq("uuid") - expect(idx.range_key).to eq(nil) - expect(idx.projection_type).to eq('"ALL"') - end - - it 'correctly handles underscores in field names' do - params = "Model:hkey{long_uuid}" - - idx = SecondaryIndex.parse(params) - expect(idx.name).to eq("Model") - expect(idx.hash_key).to eq("long_uuid") - end - end - - context 'when given incorrect params' do - - it 'handles not being given a hash_key' do - params = "Model:rkey{title}" - - expect { - idx = SecondaryIndex.parse(params) - }.to raise_error(ArgumentError) - end - - it 'handles not being given any keys' do - params = "Model" - - expect { - idx = SecondaryIndex.parse(params) - }.to raise_error(ArgumentError) - end - end - - context 'when using a projection' do - it 'correctly handles an ALL projection type' do - params = "Model:hkey{uuid},proj_type{ALL}" - - idx = SecondaryIndex.parse(params) - expect(idx.projection_type).to eq('"ALL"') - end - - it 'correctly handles an KEYS_ONLY projection type' do - params = "Model:hkey{uuid},proj_type{KEYS_ONLY}" - - expect { - idx = SecondaryIndex.parse(params) - }.to raise_error(NotImplementedError) - end - - it 'correctly handles an INCLUDE projection type' do - params = "Model:hkey{uuid},proj_type{INCLUDE}" - - expect { - idx = SecondaryIndex.parse(params) - }.to raise_error(NotImplementedError) - end - - it 'handles invalid projection type types' do - params = "Model:hkey{uuid},proj_type{INCLUDES}" - - expect { - idx = SecondaryIndex.parse(params) - }.to raise_error(ArgumentError) - end - end - end - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb deleted file mode 100644 index 8ed2d0d..0000000 --- a/spec/spec_helper.rb +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may not -# use this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions -# and limitations under the License. - -require 'aws-record-generator' diff --git a/tasks/release b/tasks/release index 6475953..109aae0 160000 --- a/tasks/release +++ b/tasks/release @@ -1 +1 @@ -Subproject commit 6475953e6c531cc2c494a7dc9987a1feff199414 +Subproject commit 109aae0714a9f965031a79af9e59247d25da7c92 diff --git a/test/dummy/app/controllers/api_controller_skeleton_tests_controller.rb b/test/dummy/app/controllers/api_controller_skeleton_tests_controller.rb new file mode 100644 index 0000000..2b6fe7e --- /dev/null +++ b/test/dummy/app/controllers/api_controller_skeleton_tests_controller.rb @@ -0,0 +1,53 @@ +class ApiControllerSkeletonTestsController < ApplicationController + before_action :set_api_controller_skeleton_test, only: [:show, :update, :destroy] + + # GET /api_controller_skeleton_tests + def index + # Warning: This performs a full table scan, which can be very expensive if a table has many entries. + # It is strongly recommended to implement alternative approaches such as paginated queries. + @api_controller_skeleton_tests = ApiControllerSkeletonTest.scan + + render json: @api_controller_skeleton_tests + end + + # GET /api_controller_skeleton_tests/1 + def show + render json: @api_controller_skeleton_test + end + + # POST /api_controller_skeleton_tests + def create + @api_controller_skeleton_test = ApiControllerSkeletonTest.new(api_controller_skeleton_test_params) + + if @api_controller_skeleton_test.save + render json: @api_controller_skeleton_test, status: :created, location: @api_controller_skeleton_test + else + render json: @api_controller_skeleton_test.errors, status: :unprocessable_entity + end + end + + # PATCH/PUT /api_controller_skeleton_tests/1 + def update + if @api_controller_skeleton_test.update(api_controller_skeleton_test_params) + render json: @api_controller_skeleton_test + else + render json: @api_controller_skeleton_test.errors, status: :unprocessable_entity + end + end + + # DELETE /api_controller_skeleton_tests/1 + def destroy + @api_controller_skeleton_test.delete! + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_api_controller_skeleton_test + @api_controller_skeleton_test = ApiControllerSkeletonTest.find(uuid: CGI.unescape(params[:id])) + end + + # Only allow a trusted parameter "white list" through. + def api_controller_skeleton_test_params + params.require(:api_controller_skeleton_test).permit(:uuid) + end +end diff --git a/test/dummy/app/controllers/application_controller.rb b/test/dummy/app/controllers/application_controller.rb new file mode 100644 index 0000000..09705d1 --- /dev/null +++ b/test/dummy/app/controllers/application_controller.rb @@ -0,0 +1,2 @@ +class ApplicationController < ActionController::Base +end diff --git a/test/dummy/app/controllers/controller_skeleton_tests_controller.rb b/test/dummy/app/controllers/controller_skeleton_tests_controller.rb new file mode 100644 index 0000000..27363d1 --- /dev/null +++ b/test/dummy/app/controllers/controller_skeleton_tests_controller.rb @@ -0,0 +1,60 @@ +class ControllerSkeletonTestsController < ApplicationController + before_action :set_controller_skeleton_test, only: [:show, :edit, :update, :destroy] + + # GET /controller_skeleton_tests + def index + # Warning: This performs a full table scan, which can be very expensive if a table has many entries. + # It is strongly recommended to implement alternative approaches such as paginated queries. + @controller_skeleton_tests = ControllerSkeletonTest.scan + end + + # GET /controller_skeleton_tests/1 + def show + end + + # GET /controller_skeleton_tests/new + def new + @controller_skeleton_test = ControllerSkeletonTest.new + end + + # GET /controller_skeleton_tests/1/edit + def edit + end + + # POST /controller_skeleton_tests + def create + @controller_skeleton_test = ControllerSkeletonTest.new(controller_skeleton_test_params) + + if @controller_skeleton_test.save + redirect_to @controller_skeleton_test, notice: 'Controller skeleton test was successfully created.' + else + render :new + end + end + + # PATCH/PUT /controller_skeleton_tests/1 + def update + if @controller_skeleton_test.update(controller_skeleton_test_params) + redirect_to @controller_skeleton_test, notice: 'Controller skeleton test was successfully updated.' + else + render :edit + end + end + + # DELETE /controller_skeleton_tests/1 + def destroy + @controller_skeleton_test.delete! + redirect_to controller_skeleton_tests_url, notice: 'Controller skeleton test was successfully destroyed.' + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_controller_skeleton_test + @controller_skeleton_test = ControllerSkeletonTest.find(uuid: CGI.unescape(params[:id])) + end + + # Only allow a trusted parameter "white list" through. + def controller_skeleton_test_params + params.require(:controller_skeleton_test).permit(:uuid, :name, :age) + end +end diff --git a/test/dummy/app/controllers/inherited_file_generation_tests_controller.rb b/test/dummy/app/controllers/inherited_file_generation_tests_controller.rb new file mode 100644 index 0000000..995969c --- /dev/null +++ b/test/dummy/app/controllers/inherited_file_generation_tests_controller.rb @@ -0,0 +1,60 @@ +class InheritedFileGenerationTestsController < ApplicationController + before_action :set_inherited_file_generation_test, only: [:show, :edit, :update, :destroy] + + # GET /inherited_file_generation_tests + def index + # Warning: This performs a full table scan, which can be very expensive if a table has many entries. + # It is strongly recommended to implement alternative approaches such as paginated queries. + @inherited_file_generation_tests = InheritedFileGenerationTest.scan + end + + # GET /inherited_file_generation_tests/1 + def show + end + + # GET /inherited_file_generation_tests/new + def new + @inherited_file_generation_test = InheritedFileGenerationTest.new + end + + # GET /inherited_file_generation_tests/1/edit + def edit + end + + # POST /inherited_file_generation_tests + def create + @inherited_file_generation_test = InheritedFileGenerationTest.new(inherited_file_generation_test_params) + + if @inherited_file_generation_test.save + redirect_to @inherited_file_generation_test, notice: 'Inherited file generation test was successfully created.' + else + render :new + end + end + + # PATCH/PUT /inherited_file_generation_tests/1 + def update + if @inherited_file_generation_test.update(inherited_file_generation_test_params) + redirect_to @inherited_file_generation_test, notice: 'Inherited file generation test was successfully updated.' + else + render :edit + end + end + + # DELETE /inherited_file_generation_tests/1 + def destroy + @inherited_file_generation_test.delete! + redirect_to inherited_file_generation_tests_url, notice: 'Inherited file generation test was successfully destroyed.' + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_inherited_file_generation_test + @inherited_file_generation_test = InheritedFileGenerationTest.find(uuid: CGI.unescape(params[:id])) + end + + # Only allow a trusted parameter "white list" through. + def inherited_file_generation_test_params + params.require(:inherited_file_generation_test).permit(:uuid) + end +end diff --git a/test/dummy/app/helpers/api_controller_skeleton_tests_helper.rb b/test/dummy/app/helpers/api_controller_skeleton_tests_helper.rb new file mode 100644 index 0000000..fe88b37 --- /dev/null +++ b/test/dummy/app/helpers/api_controller_skeleton_tests_helper.rb @@ -0,0 +1,2 @@ +module ApiControllerSkeletonTestsHelper +end diff --git a/test/dummy/app/helpers/controller_skeleton_tests_helper.rb b/test/dummy/app/helpers/controller_skeleton_tests_helper.rb new file mode 100644 index 0000000..bc60ab6 --- /dev/null +++ b/test/dummy/app/helpers/controller_skeleton_tests_helper.rb @@ -0,0 +1,2 @@ +module ControllerSkeletonTestsHelper +end diff --git a/test/dummy/app/helpers/inherited_file_generation_tests_helper.rb b/test/dummy/app/helpers/inherited_file_generation_tests_helper.rb new file mode 100644 index 0000000..b780984 --- /dev/null +++ b/test/dummy/app/helpers/inherited_file_generation_tests_helper.rb @@ -0,0 +1,2 @@ +module InheritedFileGenerationTestsHelper +end diff --git a/test/dummy/app/views/controller_skeleton_tests/_form.html.erb b/test/dummy/app/views/controller_skeleton_tests/_form.html.erb new file mode 100644 index 0000000..d13095c --- /dev/null +++ b/test/dummy/app/views/controller_skeleton_tests/_form.html.erb @@ -0,0 +1,32 @@ +<%= form_with(model: controller_skeleton_test, local: true) do |form| %> + <% if controller_skeleton_test.errors.any? %> +
+

<%= pluralize(controller_skeleton_test.errors.count, "error") %> prohibited this controller_skeleton_test from being saved:

+ + +
+ <% end %> + +
+ <%= form.label :uuid %> + <%= form.text_field :uuid %> +
+ +
+ <%= form.label :name %> + <%= form.text_field :name %> +
+ +
+ <%= form.label :age %> + <%= form.number_field :age %> +
+ +
+ <%= form.submit %> +
+<% end %> diff --git a/test/dummy/app/views/controller_skeleton_tests/edit.html.erb b/test/dummy/app/views/controller_skeleton_tests/edit.html.erb new file mode 100644 index 0000000..a6c5405 --- /dev/null +++ b/test/dummy/app/views/controller_skeleton_tests/edit.html.erb @@ -0,0 +1,6 @@ +

Editing Controller Skeleton Test

+ +<%= render 'form', controller_skeleton_test: @controller_skeleton_test %> + +<%= link_to 'Show', @controller_skeleton_test %> | +<%= link_to 'Back', controller_skeleton_tests_path %> diff --git a/test/dummy/app/views/controller_skeleton_tests/index.html.erb b/test/dummy/app/views/controller_skeleton_tests/index.html.erb new file mode 100644 index 0000000..808e39d --- /dev/null +++ b/test/dummy/app/views/controller_skeleton_tests/index.html.erb @@ -0,0 +1,31 @@ +

<%= notice %>

+ +

Controller Skeleton Tests

+ + + + + + + + + + + + + <% @controller_skeleton_tests.each do |controller_skeleton_test| %> + + + + + + + + + <% end %> + +
UuidNameAge
<%= controller_skeleton_test.uuid %><%= controller_skeleton_test.name %><%= controller_skeleton_test.age %><%= link_to 'Show', controller_skeleton_test %><%= link_to 'Edit', edit_controller_skeleton_test_path(controller_skeleton_test) %><%= link_to 'Destroy', controller_skeleton_test, method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New Controller Skeleton Test', new_controller_skeleton_test_path %> diff --git a/test/dummy/app/views/controller_skeleton_tests/new.html.erb b/test/dummy/app/views/controller_skeleton_tests/new.html.erb new file mode 100644 index 0000000..2f2652a --- /dev/null +++ b/test/dummy/app/views/controller_skeleton_tests/new.html.erb @@ -0,0 +1,5 @@ +

New Controller Skeleton Test

+ +<%= render 'form', controller_skeleton_test: @controller_skeleton_test %> + +<%= link_to 'Back', controller_skeleton_tests_path %> diff --git a/test/dummy/app/views/controller_skeleton_tests/show.html.erb b/test/dummy/app/views/controller_skeleton_tests/show.html.erb new file mode 100644 index 0000000..f9f1f69 --- /dev/null +++ b/test/dummy/app/views/controller_skeleton_tests/show.html.erb @@ -0,0 +1,19 @@ +

<%= notice %>

+ +

+ Uuid: + <%= @controller_skeleton_test.uuid %> +

+ +

+ Name: + <%= @controller_skeleton_test.name %> +

+ +

+ Age: + <%= @controller_skeleton_test.age %> +

+ +<%= link_to 'Edit', edit_controller_skeleton_test_path(@controller_skeleton_test) %> | +<%= link_to 'Back', controller_skeleton_tests_path %> diff --git a/test/dummy/app/views/inherited_file_generation_tests/_form.html.erb b/test/dummy/app/views/inherited_file_generation_tests/_form.html.erb new file mode 100644 index 0000000..c972b2d --- /dev/null +++ b/test/dummy/app/views/inherited_file_generation_tests/_form.html.erb @@ -0,0 +1,22 @@ +<%= form_with(model: inherited_file_generation_test, local: true) do |form| %> + <% if inherited_file_generation_test.errors.any? %> +
+

<%= pluralize(inherited_file_generation_test.errors.count, "error") %> prohibited this inherited_file_generation_test from being saved:

+ + +
+ <% end %> + +
+ <%= form.label :uuid %> + <%= form.text_field :uuid %> +
+ +
+ <%= form.submit %> +
+<% end %> diff --git a/test/dummy/app/views/inherited_file_generation_tests/edit.html.erb b/test/dummy/app/views/inherited_file_generation_tests/edit.html.erb new file mode 100644 index 0000000..081a39a --- /dev/null +++ b/test/dummy/app/views/inherited_file_generation_tests/edit.html.erb @@ -0,0 +1,6 @@ +

Editing Inherited File Generation Test

+ +<%= render 'form', inherited_file_generation_test: @inherited_file_generation_test %> + +<%= link_to 'Show', @inherited_file_generation_test %> | +<%= link_to 'Back', inherited_file_generation_tests_path %> diff --git a/test/dummy/app/views/inherited_file_generation_tests/index.html.erb b/test/dummy/app/views/inherited_file_generation_tests/index.html.erb new file mode 100644 index 0000000..6415e28 --- /dev/null +++ b/test/dummy/app/views/inherited_file_generation_tests/index.html.erb @@ -0,0 +1,27 @@ +

<%= notice %>

+ +

Inherited File Generation Tests

+ + + + + + + + + + + <% @inherited_file_generation_tests.each do |inherited_file_generation_test| %> + + + + + + + <% end %> + +
Uuid
<%= inherited_file_generation_test.uuid %><%= link_to 'Show', inherited_file_generation_test %><%= link_to 'Edit', edit_inherited_file_generation_test_path(inherited_file_generation_test) %><%= link_to 'Destroy', inherited_file_generation_test, method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New Inherited File Generation Test', new_inherited_file_generation_test_path %> diff --git a/test/dummy/app/views/inherited_file_generation_tests/new.html.erb b/test/dummy/app/views/inherited_file_generation_tests/new.html.erb new file mode 100644 index 0000000..5f73abe --- /dev/null +++ b/test/dummy/app/views/inherited_file_generation_tests/new.html.erb @@ -0,0 +1,5 @@ +

New Inherited File Generation Test

+ +<%= render 'form', inherited_file_generation_test: @inherited_file_generation_test %> + +<%= link_to 'Back', inherited_file_generation_tests_path %> diff --git a/test/dummy/app/views/inherited_file_generation_tests/show.html.erb b/test/dummy/app/views/inherited_file_generation_tests/show.html.erb new file mode 100644 index 0000000..97079d3 --- /dev/null +++ b/test/dummy/app/views/inherited_file_generation_tests/show.html.erb @@ -0,0 +1,9 @@ +

<%= notice %>

+ +

+ Uuid: + <%= @inherited_file_generation_test.uuid %> +

+ +<%= link_to 'Edit', edit_inherited_file_generation_test_path(@inherited_file_generation_test) %> | +<%= link_to 'Back', inherited_file_generation_tests_path %> diff --git a/test/dummy/config.ru b/test/dummy/config.ru new file mode 100644 index 0000000..871646a --- /dev/null +++ b/test/dummy/config.ru @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +# This file indicates the Rails root directory diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb new file mode 100644 index 0000000..de66244 --- /dev/null +++ b/test/dummy/config/application.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require 'rails' +require 'action_controller/railtie' +require 'active_model' + +require 'aws-record-rails' + +# @api private +module Dummy + class Application < Rails::Application + config.load_defaults Rails::VERSION::STRING.to_f + config.eager_load = true + config.secret_key_base = 'secret' + end +end diff --git a/test/dummy/config/boot.rb b/test/dummy/config/boot.rb new file mode 100644 index 0000000..fab86f1 --- /dev/null +++ b/test/dummy/config/boot.rb @@ -0,0 +1 @@ +require 'bundler/setup' diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb new file mode 100644 index 0000000..12cded5 --- /dev/null +++ b/test/dummy/config/routes.rb @@ -0,0 +1 @@ +# Necessary for test \ No newline at end of file diff --git a/fixtures/cucumber/table_config/dog_config.rb b/test/dummy/db/table_config/account_config.rb similarity index 63% rename from fixtures/cucumber/table_config/dog_config.rb rename to test/dummy/db/table_config/account_config.rb index c991fb7..302d4f5 100644 --- a/fixtures/cucumber/table_config/dog_config.rb +++ b/test/dummy/db/table_config/account_config.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + require 'aws-record' module ModelTableConfig def self.config Aws::Record::TableConfig.define do |t| - t.model_class Dog + t.model_class Account - t.read_capacity_units 11 + t.read_capacity_units 12 t.write_capacity_units 4 end end diff --git a/test/dummy/db/table_config/inherited_file_generation_test_config.rb b/test/dummy/db/table_config/inherited_file_generation_test_config.rb new file mode 100644 index 0000000..56485ec --- /dev/null +++ b/test/dummy/db/table_config/inherited_file_generation_test_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class InheritedFileGenerationTest + + t.read_capacity_units 5 + t.write_capacity_units 3 + end + end +end diff --git a/test/dummy/db/table_config/test_length_validations_config.rb b/test/dummy/db/table_config/test_length_validations_config.rb new file mode 100644 index 0000000..8ba46a3 --- /dev/null +++ b/test/dummy/db/table_config/test_length_validations_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestLengthValidations + + t.read_capacity_units 5 + t.write_capacity_units 2 + end + end +end diff --git a/test/dummy/db/table_config/test_model_auto_hkey_config.rb b/test/dummy/db/table_config/test_model_auto_hkey_config.rb new file mode 100644 index 0000000..5aed9e8 --- /dev/null +++ b/test/dummy/db/table_config/test_model_auto_hkey_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestModelAutoHkey + + t.read_capacity_units 5 + t.write_capacity_units 2 + end + end +end diff --git a/fixtures/unit/table_config/table_config_test_model_default_units_config.rb b/test/dummy/db/table_config/test_model_basic_config.rb similarity index 73% rename from fixtures/unit/table_config/table_config_test_model_default_units_config.rb rename to test/dummy/db/table_config/test_model_basic_config.rb index be293fa..ae797e2 100644 --- a/fixtures/unit/table_config/table_config_test_model_default_units_config.rb +++ b/test/dummy/db/table_config/test_model_basic_config.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require 'aws-record' module ModelTableConfig def self.config Aws::Record::TableConfig.define do |t| - t.model_class TableConfigTestModelDefaultUnits + t.model_class TestModelBasic t.read_capacity_units 5 t.write_capacity_units 2 diff --git a/test/dummy/db/table_config/test_model_complex_config.rb b/test/dummy/db/table_config/test_model_complex_config.rb new file mode 100644 index 0000000..f37e431 --- /dev/null +++ b/test/dummy/db/table_config/test_model_complex_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestModelComplex + + t.read_capacity_units 5 + t.write_capacity_units 2 + end + end +end diff --git a/test/dummy/db/table_config/test_model_fields_absent_auto_uuid_config.rb b/test/dummy/db/table_config/test_model_fields_absent_auto_uuid_config.rb new file mode 100644 index 0000000..b63ed9f --- /dev/null +++ b/test/dummy/db/table_config/test_model_fields_absent_auto_uuid_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestModelFieldsAbsentAutoUuid + + t.read_capacity_units 5 + t.write_capacity_units 2 + end + end +end diff --git a/test/dummy/db/table_config/test_model_fields_present_auto_uuid_config.rb b/test/dummy/db/table_config/test_model_fields_present_auto_uuid_config.rb new file mode 100644 index 0000000..947f70b --- /dev/null +++ b/test/dummy/db/table_config/test_model_fields_present_auto_uuid_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestModelFieldsPresentAutoUuid + + t.read_capacity_units 5 + t.write_capacity_units 2 + end + end +end diff --git a/test/dummy/db/table_config/test_model_gsi_basic_config.rb b/test/dummy/db/table_config/test_model_gsi_basic_config.rb new file mode 100644 index 0000000..71c112e --- /dev/null +++ b/test/dummy/db/table_config/test_model_gsi_basic_config.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestModelGsiBasic + + t.read_capacity_units 5 + t.write_capacity_units 2 + + t.global_secondary_index(:SecondaryIndex) do |i| + i.read_capacity_units 5 + i.write_capacity_units 2 + end + end + end +end diff --git a/fixtures/unit/table_config/test_table_config_gsi_basic_config.rb b/test/dummy/db/table_config/test_model_gsi_keys_config.rb similarity index 82% rename from fixtures/unit/table_config/test_table_config_gsi_basic_config.rb rename to test/dummy/db/table_config/test_model_gsi_keys_config.rb index cd68151..e09e044 100644 --- a/fixtures/unit/table_config/test_table_config_gsi_basic_config.rb +++ b/test/dummy/db/table_config/test_model_gsi_keys_config.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require 'aws-record' module ModelTableConfig def self.config Aws::Record::TableConfig.define do |t| - t.model_class TestTableConfigGsiBasic + t.model_class TestModelGsiKeys t.read_capacity_units 5 t.write_capacity_units 2 diff --git a/test/dummy/db/table_config/test_model_gsi_mult_config.rb b/test/dummy/db/table_config/test_model_gsi_mult_config.rb new file mode 100644 index 0000000..244c400 --- /dev/null +++ b/test/dummy/db/table_config/test_model_gsi_mult_config.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestModelGsiMult + + t.read_capacity_units 5 + t.write_capacity_units 2 + + t.global_secondary_index(:SecondaryIndex) do |i| + i.read_capacity_units 5 + i.write_capacity_units 2 + end + + t.global_secondary_index(:SecondaryIndex2) do |i| + i.read_capacity_units 5 + i.write_capacity_units 2 + end + end + end +end diff --git a/test/dummy/db/table_config/test_model_mut_tracking_config.rb b/test/dummy/db/table_config/test_model_mut_tracking_config.rb new file mode 100644 index 0000000..396b2cd --- /dev/null +++ b/test/dummy/db/table_config/test_model_mut_tracking_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestModelMutTracking + + t.read_capacity_units 5 + t.write_capacity_units 2 + end + end +end diff --git a/test/dummy/db/table_config/test_model_set_table_name_config.rb b/test/dummy/db/table_config/test_model_set_table_name_config.rb new file mode 100644 index 0000000..651dd77 --- /dev/null +++ b/test/dummy/db/table_config/test_model_set_table_name_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestModelSetTableName + + t.read_capacity_units 5 + t.write_capacity_units 2 + end + end +end diff --git a/test/dummy/db/table_config/test_model_timestamps_config.rb b/test/dummy/db/table_config/test_model_timestamps_config.rb new file mode 100644 index 0000000..b3cbc90 --- /dev/null +++ b/test/dummy/db/table_config/test_model_timestamps_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestModelTimestamps + + t.read_capacity_units 5 + t.write_capacity_units 2 + end + end +end diff --git a/test/dummy/db/table_config/test_password_digest_config.rb b/test/dummy/db/table_config/test_password_digest_config.rb new file mode 100644 index 0000000..cfcf142 --- /dev/null +++ b/test/dummy/db/table_config/test_password_digest_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestPasswordDigest + + t.read_capacity_units 5 + t.write_capacity_units 2 + end + end +end diff --git a/test/dummy/db/table_config/test_required_validations_config.rb b/test/dummy/db/table_config/test_required_validations_config.rb new file mode 100644 index 0000000..010243a --- /dev/null +++ b/test/dummy/db/table_config/test_required_validations_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestRequiredValidations + + t.read_capacity_units 5 + t.write_capacity_units 2 + end + end +end diff --git a/fixtures/unit/table_config/test_table_config_gsi_mult_config.rb b/test/dummy/db/table_config/test_table_config_gsi_mult_config.rb similarity index 94% rename from fixtures/unit/table_config/test_table_config_gsi_mult_config.rb rename to test/dummy/db/table_config/test_table_config_gsi_mult_config.rb index b10cdb4..8b0d2dc 100644 --- a/fixtures/unit/table_config/test_table_config_gsi_mult_config.rb +++ b/test/dummy/db/table_config/test_table_config_gsi_mult_config.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' module ModelTableConfig diff --git a/fixtures/unit/table_config/test_table_config_gsi_provided_config.rb b/test/dummy/db/table_config/test_table_config_gsi_provided_config.rb similarity index 92% rename from fixtures/unit/table_config/test_table_config_gsi_provided_config.rb rename to test/dummy/db/table_config/test_table_config_gsi_provided_config.rb index 2ef92e8..332ef8f 100644 --- a/fixtures/unit/table_config/test_table_config_gsi_provided_config.rb +++ b/test/dummy/db/table_config/test_table_config_gsi_provided_config.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' module ModelTableConfig diff --git a/fixtures/unit/table_config/table_config_test_model2_config.rb b/test/dummy/db/table_config/test_table_config_test_model2_config.rb similarity index 71% rename from fixtures/unit/table_config/table_config_test_model2_config.rb rename to test/dummy/db/table_config/test_table_config_test_model2_config.rb index 47c00ec..8186d53 100644 --- a/fixtures/unit/table_config/table_config_test_model2_config.rb +++ b/test/dummy/db/table_config/test_table_config_test_model2_config.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require 'aws-record' module ModelTableConfig def self.config Aws::Record::TableConfig.define do |t| - t.model_class TableConfigTestModel2 + t.model_class TestTableConfigTestModel2 t.read_capacity_units 20 t.write_capacity_units 10 diff --git a/fixtures/unit/table_config/table_config_test_model1_config.rb b/test/dummy/db/table_config/test_validations_config.rb similarity index 73% rename from fixtures/unit/table_config/table_config_test_model1_config.rb rename to test/dummy/db/table_config/test_validations_config.rb index 446fb28..f987acf 100644 --- a/fixtures/unit/table_config/table_config_test_model1_config.rb +++ b/test/dummy/db/table_config/test_validations_config.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require 'aws-record' module ModelTableConfig def self.config Aws::Record::TableConfig.define do |t| - t.model_class TableConfigTestModel1 + t.model_class TestValidations t.read_capacity_units 5 t.write_capacity_units 2 diff --git a/fixtures/unit/model/test_length_validations.rb b/test/fixtures/models/test_length_validations.rb similarity index 90% rename from fixtures/unit/model/test_length_validations.rb rename to test/fixtures/models/test_length_validations.rb index 17d31d1..ce82d4f 100644 --- a/fixtures/unit/model/test_length_validations.rb +++ b/test/fixtures/models/test_length_validations.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' require 'active_model' diff --git a/fixtures/unit/model/test_model_auto_hkey.rb b/test/fixtures/models/test_model_auto_hkey.rb similarity index 77% rename from fixtures/unit/model/test_model_auto_hkey.rb rename to test/fixtures/models/test_model_auto_hkey.rb index d18e688..628dae7 100644 --- a/fixtures/unit/model/test_model_auto_hkey.rb +++ b/test/fixtures/models/test_model_auto_hkey.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestModelAutoHkey diff --git a/fixtures/unit/model/test_model_basic.rb b/test/fixtures/models/test_model_basic.rb similarity index 77% rename from fixtures/unit/model/test_model_basic.rb rename to test/fixtures/models/test_model_basic.rb index 6db96d4..997183f 100644 --- a/fixtures/unit/model/test_model_basic.rb +++ b/test/fixtures/models/test_model_basic.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestModelBasic diff --git a/fixtures/unit/model/test_model_complex.rb b/test/fixtures/models/test_model_complex.rb similarity index 92% rename from fixtures/unit/model/test_model_complex.rb rename to test/fixtures/models/test_model_complex.rb index 5ce1c60..0bc0886 100644 --- a/fixtures/unit/model/test_model_complex.rb +++ b/test/fixtures/models/test_model_complex.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestModelComplex diff --git a/fixtures/unit/model/test_model_fields_absent_auto_uuid.rb b/test/fixtures/models/test_model_fields_absent_auto_uuid.rb similarity index 79% rename from fixtures/unit/model/test_model_fields_absent_auto_uuid.rb rename to test/fixtures/models/test_model_fields_absent_auto_uuid.rb index 03ae341..3d20e85 100644 --- a/fixtures/unit/model/test_model_fields_absent_auto_uuid.rb +++ b/test/fixtures/models/test_model_fields_absent_auto_uuid.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestModelFieldsAbsentAutoUuid diff --git a/fixtures/unit/model/test_model_fields_present_auto_uuid.rb b/test/fixtures/models/test_model_fields_present_auto_uuid.rb similarity index 82% rename from fixtures/unit/model/test_model_fields_present_auto_uuid.rb rename to test/fixtures/models/test_model_fields_present_auto_uuid.rb index 740893d..b9ca2fc 100644 --- a/fixtures/unit/model/test_model_fields_present_auto_uuid.rb +++ b/test/fixtures/models/test_model_fields_present_auto_uuid.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestModelFieldsPresentAutoUuid diff --git a/fixtures/unit/model/test_model_gsi_basic.rb b/test/fixtures/models/test_model_gsi_basic.rb similarity index 89% rename from fixtures/unit/model/test_model_gsi_basic.rb rename to test/fixtures/models/test_model_gsi_basic.rb index 094c65e..a6d85e0 100644 --- a/fixtures/unit/model/test_model_gsi_basic.rb +++ b/test/fixtures/models/test_model_gsi_basic.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestModelGsiBasic diff --git a/fixtures/unit/model/test_model_gsi_keys.rb b/test/fixtures/models/test_model_gsi_keys.rb similarity index 90% rename from fixtures/unit/model/test_model_gsi_keys.rb rename to test/fixtures/models/test_model_gsi_keys.rb index f98f9b9..2c10e2c 100644 --- a/fixtures/unit/model/test_model_gsi_keys.rb +++ b/test/fixtures/models/test_model_gsi_keys.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestModelGsiKeys diff --git a/fixtures/unit/model/test_model_gsi_mult.rb b/test/fixtures/models/test_model_gsi_mult.rb similarity index 93% rename from fixtures/unit/model/test_model_gsi_mult.rb rename to test/fixtures/models/test_model_gsi_mult.rb index a71d24a..5f6c122 100644 --- a/fixtures/unit/model/test_model_gsi_mult.rb +++ b/test/fixtures/models/test_model_gsi_mult.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestModelGsiMult diff --git a/fixtures/unit/model/test_model_mut_tracking.rb b/test/fixtures/models/test_model_mut_tracking.rb similarity index 81% rename from fixtures/unit/model/test_model_mut_tracking.rb rename to test/fixtures/models/test_model_mut_tracking.rb index 04602d9..c152d36 100644 --- a/fixtures/unit/model/test_model_mut_tracking.rb +++ b/test/fixtures/models/test_model_mut_tracking.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestModelMutTracking diff --git a/fixtures/unit/model/test_model_set_table_name.rb b/test/fixtures/models/test_model_set_table_name.rb similarity index 82% rename from fixtures/unit/model/test_model_set_table_name.rb rename to test/fixtures/models/test_model_set_table_name.rb index 220db11..4eebe74 100644 --- a/fixtures/unit/model/test_model_set_table_name.rb +++ b/test/fixtures/models/test_model_set_table_name.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestModelSetTableName diff --git a/fixtures/unit/model/test_model_timestamps.rb b/test/fixtures/models/test_model_timestamps.rb similarity index 87% rename from fixtures/unit/model/test_model_timestamps.rb rename to test/fixtures/models/test_model_timestamps.rb index dbccc30..4962533 100644 --- a/fixtures/unit/model/test_model_timestamps.rb +++ b/test/fixtures/models/test_model_timestamps.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestModelTimestamps diff --git a/fixtures/unit/model/test_password_digest.rb b/test/fixtures/models/test_password_digest.rb similarity index 86% rename from fixtures/unit/model/test_password_digest.rb rename to test/fixtures/models/test_password_digest.rb index 0dd2018..cba679f 100644 --- a/fixtures/unit/model/test_password_digest.rb +++ b/test/fixtures/models/test_password_digest.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' class TestPasswordDigest diff --git a/fixtures/unit/model/test_required_validations.rb b/test/fixtures/models/test_required_validations.rb similarity index 89% rename from fixtures/unit/model/test_required_validations.rb rename to test/fixtures/models/test_required_validations.rb index 7f893cf..303bb5e 100644 --- a/fixtures/unit/model/test_required_validations.rb +++ b/test/fixtures/models/test_required_validations.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' require 'active_model' diff --git a/fixtures/unit/model/test_validations.rb b/test/fixtures/models/test_validations.rb similarity index 91% rename from fixtures/unit/model/test_validations.rb rename to test/fixtures/models/test_validations.rb index bab7f89..3a8f222 100644 --- a/fixtures/unit/model/test_validations.rb +++ b/test/fixtures/models/test_validations.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'aws-record' require 'active_model' diff --git a/test/fixtures/table_config/test_table_config_gsi_mult_config.rb b/test/fixtures/table_config/test_table_config_gsi_mult_config.rb new file mode 100644 index 0000000..8b0d2dc --- /dev/null +++ b/test/fixtures/table_config/test_table_config_gsi_mult_config.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestTableConfigGsiMult + + t.read_capacity_units 5 + t.write_capacity_units 2 + + t.global_secondary_index(:SecondaryIndex) do |i| + i.read_capacity_units 10 + i.write_capacity_units 11 + end + + t.global_secondary_index(:SecondaryIndex2) do |i| + i.read_capacity_units 40 + i.write_capacity_units 20 + end + end + end +end diff --git a/test/fixtures/table_config/test_table_config_gsi_provided_config.rb b/test/fixtures/table_config/test_table_config_gsi_provided_config.rb new file mode 100644 index 0000000..332ef8f --- /dev/null +++ b/test/fixtures/table_config/test_table_config_gsi_provided_config.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + def self.config + Aws::Record::TableConfig.define do |t| + t.model_class TestTableConfigGsiProvided + + t.read_capacity_units 5 + t.write_capacity_units 2 + + t.global_secondary_index(:SecondaryIndex) do |i| + i.read_capacity_units 50 + i.write_capacity_units 100 + end + end + end +end diff --git a/fixtures/unit/table_config/table_config_test_model_declared_units_config.rb b/test/fixtures/table_config/test_table_config_test_model2_config.rb similarity index 71% rename from fixtures/unit/table_config/table_config_test_model_declared_units_config.rb rename to test/fixtures/table_config/test_table_config_test_model2_config.rb index 66bfec8..8186d53 100644 --- a/fixtures/unit/table_config/table_config_test_model_declared_units_config.rb +++ b/test/fixtures/table_config/test_table_config_test_model2_config.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require 'aws-record' module ModelTableConfig def self.config Aws::Record::TableConfig.define do |t| - t.model_class TableConfigTestModelDeclaredUnits + t.model_class TestTableConfigTestModel2 t.read_capacity_units 20 t.write_capacity_units 10 diff --git a/test/generators/aws_record/model/generated_attribute_test.rb b/test/generators/aws_record/model/generated_attribute_test.rb new file mode 100644 index 0000000..4b5094b --- /dev/null +++ b/test/generators/aws_record/model/generated_attribute_test.rb @@ -0,0 +1,140 @@ +# frozen_string_literal: true + +require 'test_helper' + +module AwsRecord + module Generators + # @api private + class GeneratedAttributeTest < Minitest::Test + describe 'when given valid input' do + it 'sets the name and type correctly' do + params = 'uuid:int' + + attribute = GeneratedAttribute.parse(params) + expect(attribute.name).to eq('uuid') + expect(attribute.type).to eq(:integer_attr) + end + + it 'properly defaults to string_attr when only a name is provided' do + params = 'uuid' + + attribute = GeneratedAttribute.parse(params) + expect(attribute.name).to eq('uuid') + expect(attribute.type).to eq(:string_attr) + end + + it 'properly parses all valid types for an attribute' do + base_params = 'uuid:' + { + 'bool' => :boolean_attr, + 'boolean' => :boolean_attr, + 'date' => :date_attr, + 'datetime' => :datetime_attr, + 'float' => :float_attr, + 'int' => :integer_attr, + 'integer' => :integer_attr, + 'list' => :list_attr, + 'map' => :map_attr, + 'num_set' => :numeric_set_attr, + 'numeric_set' => :numeric_set_attr, + 'nset' => :numeric_set_attr, + 'string_set' => :string_set_attr, + 's_set' => :string_set_attr, + 'sset' => :string_set_attr, + 'string' => :string_attr + }.each do |input, attr_type| + input_params = "#{base_params}#{input}" + + attribute = GeneratedAttribute.parse(input_params) + expect(attribute.name).to eq('uuid') + expect(attribute.type).to eq(attr_type) + end + end + + describe 'properly handles attribute options' do + it 'properly handles all valid options' do + base_params = 'uuid:' + { + 'hkey' => [:hash_key, true], + 'rkey' => [:range_key, true], + 'persist_nil' => [:persist_nil, true], + 'db_attr_name{PostTitle}' => [:database_attribute_name, '"PostTitle"'], + 'ddb_type{BOOL}' => [:dynamodb_type, '"BOOL"'], + 'default_value{9}' => [:default_value, '9'] + }.each do |opt, parsed_opt| + input_params = "#{base_params}#{opt}" + + attribute = GeneratedAttribute.parse(input_params) + expect(attribute.name).to eq('uuid') + expect(attribute.type).to eq(:string_attr) + expect(attribute.options.to_a).to eq([parsed_opt]) + end + end + + describe 'properly handles using options in combination with one another' do + it 'allows fields to have a default value and a ddb_type' do + params = 'is_describe:bool:persist_nil,ddb_type{BOOL}' + + attribute = GeneratedAttribute.parse(params) + expect(attribute.name).to eq('is_describe') + expect(attribute.type).to eq(:boolean_attr) + expect(attribute.options.to_a).to eq([[:persist_nil, true], [:dynamodb_type, '"BOOL"']]) + end + + it 'allows a key field to have a db_attr_name' do + params = 'uuid:hkey,db_attr_name{PostTitle}' + + attribute = GeneratedAttribute.parse(params) + expect(attribute.name).to eq('uuid') + expect(attribute.type).to eq(:string_attr) + expect(attribute.options.to_a).to eq([[:hash_key, true], [:database_attribute_name, '"PostTitle"']]) + end + end + end + + it 'properly infers that a type has not been provided when other options are' do + params = 'uuid:hkey' + + attribute = GeneratedAttribute.parse(params) + expect(attribute.name).to eq('uuid') + expect(attribute.type).to eq(:string_attr) + expect(attribute.options.to_a).to eq([[:hash_key, true]]) + end + end + + describe 'when invalid input is provided' do + it 'properly detects when an invalid type is provided' do + params = 'uuid:invalid_type:hkey' + + expect do + GeneratedAttribute.parse(params) + end.to raise_error(ArgumentError) + end + + it 'properly detects when an invalid opt is provided' do + params = 'uuid:hkey,invalid_opt' + + expect do + GeneratedAttribute.parse(params) + end.to raise_error(ArgumentError) + end + + it 'detects when a field is declared as both an hkey and rkey' do + params = 'uuid:string:hkey,rkey' + + expect do + GeneratedAttribute.parse(params) + end.to raise_error(ArgumentError) + end + + it 'detects when a map_attr is declared as a hkey' do + params = 'uuid:map:hkey' + + expect do + GeneratedAttribute.parse(params) + end.to raise_error(ArgumentError) + end + end + end + end +end diff --git a/test/generators/aws_record/model/model_generator_test.rb b/test/generators/aws_record/model/model_generator_test.rb new file mode 100644 index 0000000..5762f8b --- /dev/null +++ b/test/generators/aws_record/model/model_generator_test.rb @@ -0,0 +1,269 @@ +# frozen_string_literal: true + +require 'test_helper' + +require 'fileutils' +require 'generators/aws_record/model/model_generator' + +module AwsRecord + module Generators + # @api private + class ModelGeneratorTest < Rails::Generators::TestCase + tests ModelGenerator + destination File.expand_path('../../../dummy', __dir__) + + def assert_file_fixture(fixture_file, generated_file) + exp = File.read(fixture_file) + act = File.read(generated_file) + assert exp == act + end + + def run_generator(args, config = {}) + result = nil + capture(:stderr) do + result = super(args, config) + end + result + end + + def test_model_basic + run_generator %w[TestModelBasic uuid:hkey --table-config=primary:5-2 -f] + assert_file 'app/models/test_model_basic.rb' + assert_file_fixture( + 'test/fixtures/models/test_model_basic.rb', + 'test/dummy/app/models/test_model_basic.rb' + ) + end + + def test_model_fields_absent_auto_uuid + run_generator %w[TestModelFieldsAbsentAutoUuid --table-config=primary:5-2 -f] + assert_file 'app/models/test_model_fields_absent_auto_uuid.rb' + assert_file_fixture( + 'test/fixtures/models/test_model_fields_absent_auto_uuid.rb', + 'test/dummy/app/models/test_model_fields_absent_auto_uuid.rb' + ) + end + + def test_model_fields_present_auto_uuid + run_generator %w[TestModelFieldsPresentAutoUuid name --table-config=primary:5-2 -f] + assert_file 'app/models/test_model_fields_present_auto_uuid.rb' + assert_file_fixture( + 'test/fixtures/models/test_model_fields_present_auto_uuid.rb', + 'test/dummy/app/models/test_model_fields_present_auto_uuid.rb' + ) + end + + def test_model_auto_hkey + run_generator %w[TestModelAutoHkey uuid --table-config=primary:5-2 -f] + assert_file 'app/models/test_model_auto_hkey.rb' + assert_file_fixture( + 'test/fixtures/models/test_model_auto_hkey.rb', + 'test/dummy/app/models/test_model_auto_hkey.rb' + ) + end + + def test_model_mut_tracking + run_generator %w[TestModelMutTracking uuid:hkey --disable-mutation-tracking --table-config=primary:5-2 -f] + assert_file 'app/models/test_model_mut_tracking.rb' + assert_file_fixture( + 'test/fixtures/models/test_model_mut_tracking.rb', + 'test/dummy/app/models/test_model_mut_tracking.rb' + ) + end + + def test_model_complex + run_generator %w[TestModelComplex forum_uuid:hkey post_id:rkey author_username post_title post_body + tags:sset:default_value{Set.new} created_at:datetime:db_attr_name{PostCreatedAtTime} moderation:boolean:default_value{false} --table-config=primary:5-2 -f] + assert_file 'app/models/test_model_complex.rb' + assert_file_fixture( + 'test/fixtures/models/test_model_complex.rb', + 'test/dummy/app/models/test_model_complex.rb' + ) + end + + def test_enforce_uniqueness_of_field_names + expect do + run_generator %w[TestModel_Err uuid:hkey uuid --table-config=primary:5-2 -f] + end.to raise_error(SystemExit) + assert_no_file 'app/models/test_model_err.rb' + end + + def test_enforce_uniqueness_of_db_attribute_name + expect do + run_generator %w[TestModel_Err uuid:hkey long_title:db_attr_name{uuid} --table-config=primary:5-2 -f] + end.to raise_error(SystemExit) + assert_no_file 'app/models/test_model_err.rb' + end + + def test_enforce_errors_handled + expect do + run_generator %w[TestModel_Err uuid:invalid_type:hkey uuid:hkey,invalid_opt uuid:string:hkey,rkey + uuid:map:hkey --table-config=primary:5-2 -f] + end.to raise_error(SystemExit) + assert_no_file 'app/models/test_model_err.rb' + end + + def test_model_set_table_name + run_generator %w[TestModelSetTableName --table-config=primary:5-2 --table-name=CustomTableName -f] + assert_file 'app/models/test_model_set_table_name.rb' + assert_file_fixture( + 'test/fixtures/models/test_model_set_table_name.rb', + 'test/dummy/app/models/test_model_set_table_name.rb' + ) + end + + def test_table_config_test_model1_config + expect do + run_generator %w[TestTableConfigTestModel1 uuid:hkey -f] + end.to raise_error(SystemExit) + assert_no_file 'db/table_config/test_table_config_test_model1_config.rb' + end + + def test_table_config_test_model2_config + run_generator %w[TestTableConfigTestModel2 --table-config=primary:20-10 -f] + assert_file 'db/table_config/test_table_config_test_model2_config.rb' + assert_file_fixture( + 'test/fixtures/table_config/test_table_config_test_model2_config.rb', + 'test/dummy/db/table_config/test_table_config_test_model2_config.rb' + ) + end + + def test_model_gsi_basic + run_generator %w[TestModelGSIBasic gsi_hkey --gsi=SecondaryIndex:hkey{gsi_hkey} --table-config=primary:5-2 + SecondaryIndex:5-2 -f] + assert_file 'app/models/test_model_gsi_basic.rb' + assert_file_fixture( + 'test/fixtures/models/test_model_gsi_basic.rb', + 'test/dummy/app/models/test_model_gsi_basic.rb' + ) + end + + def test_model_gsi_keys + run_generator %w[TestModelGSIKeys gsi_hkey gsi_rkey --gsi=SecondaryIndex:hkey{gsi_hkey},rkey{gsi_rkey} + --table-config=primary:5-2 SecondaryIndex:5-2 -f] + assert_file 'app/models/test_model_gsi_keys.rb' + assert_file_fixture( + 'test/fixtures/models/test_model_gsi_keys.rb', + 'test/dummy/app/models/test_model_gsi_keys.rb' + ) + end + + def test_model_gsi_mult + run_generator %w[TestModelGSIMult gsi_hkey gsi2_hkey --gsi=SecondaryIndex:hkey{gsi_hkey} + SecondaryIndex2:hkey{gsi2_hkey} --table-config=primary:5-2 SecondaryIndex:5-2 SecondaryIndex2:5-2 -f] + assert_file 'app/models/test_model_gsi_mult.rb' + assert_file_fixture( + 'test/fixtures/models/test_model_gsi_mult.rb', + 'test/dummy/app/models/test_model_gsi_mult.rb' + ) + end + + def test_enforce_given_hkey_is_valid + expect do + run_generator %w[TestModel_Err gsi_rkey --gsi=SecondaryIndex:hkey{gsi_hkey},rkey{gsi_rkey} + --table-config=primary:5-2 SecondaryIndex:5-2 -f] + end.to raise_error(SystemExit) + assert_no_file 'app/models/test_model_err.rb' + end + + def test_enforce_given_rkey_is_valid + expect do + run_generator %w[TestModel_Err gsi_hkey --gsi=SecondaryIndex:hkey{gsi_hkey},rkey{gsi_rkey} + --table-config=primary:5-2 SecondaryIndex:5-2 -f] + end.to raise_error(SystemExit) + assert_no_file 'app/models/test_model_err.rb' + end + + def test_table_config_gsi_basic_config + expect do + run_generator %w[TestTableConfigGSIBasic gsi_hkey --gsi=SecondaryIndex:hkey{gsi_hkey} + --table-config=primary:5-2 -f] + end.to raise_error(SystemExit) + assert_no_file 'db/table_config/test_table_config_gsi_basic_config.rb' + end + + def test_table_config_gsi_provided_config + run_generator %w[TestTableConfigGSIProvided gsi_hkey --gsi=SecondaryIndex:hkey{gsi_hkey} + --table-config=primary:5-2 SecondaryIndex:50-100 -f] + assert_file 'db/table_config/test_table_config_gsi_provided_config.rb' + assert_file_fixture( + 'test/fixtures/table_config/test_table_config_gsi_provided_config.rb', + 'test/dummy/db/table_config/test_table_config_gsi_provided_config.rb' + ) + end + + def test_table_config_gsi_mult_config + run_generator %w[TestTableConfigGSIMult gsi_hkey gsi2_hkey --gsi=SecondaryIndex:hkey{gsi_hkey} + SecondaryIndex2:hkey{gsi2_hkey} --table-config=primary:5-2 SecondaryIndex:10-11 SecondaryIndex2:40-20] + assert_file 'db/table_config/test_table_config_gsi_mult_config.rb' + assert_file_fixture( + 'test/fixtures/table_config/test_table_config_gsi_mult_config.rb', + 'test/dummy/db/table_config/test_table_config_gsi_mult_config.rb' + ) + end + + def test_values_for_nonexistant_index + expect do + run_generator %w[TestModel_Err gsi_hkey --gsi=SecondaryIndex:hkey{gsi_hkey} --table-config=primary:5-2 + SecondaryIndexes:50-100] + end.to raise_error(SystemExit) + assert_no_file 'app/models/test_model_err.rb' + end + + def test_model_timestamps + run_generator %w[TestModelTimestamps --timestamps --table_config=primary:5-2 -f] + assert_file 'app/models/test_model_timestamps.rb' + assert_file_fixture( + 'test/fixtures/models/test_model_timestamps.rb', + 'test/dummy/app/models/test_model_timestamps.rb' + ) + end + + def test_required_validations + run_generator %w[TestRequiredValidations title body --required=title body --table_config=primary:5-2 -f] + assert_file 'app/models/test_required_validations.rb' + assert_file_fixture( + 'test/fixtures/models/test_required_validations.rb', + 'test/dummy/app/models/test_required_validations.rb' + ) + end + + def test_length_validations + run_generator %w[TestLengthValidations title body --length-validations=title:5-10 body:100-250 + --table_config=primary:5-2 -f] + assert_file 'app/models/test_length_validations.rb' + assert_file_fixture( + 'test/fixtures/models/test_length_validations.rb', + 'test/dummy/app/models/test_length_validations.rb' + ) + end + + def test_validations + run_generator %w[TestValidations title body --required=title body --length-validations=title:5-10 body:100-250 + --table_config=primary:5-2 -f] + assert_file 'app/models/test_validations.rb' + assert_file_fixture( + 'test/fixtures/models/test_validations.rb', + 'test/dummy/app/models/test_validations.rb' + ) + end + + def test_password_digest + run_generator %w[TestPasswordDigest --table_config=primary:5-2 --password-digest] + assert_file 'app/models/test_password_digest.rb' + assert_file_fixture( + 'test/fixtures/models/test_password_digest.rb', + 'test/dummy/app/models/test_password_digest.rb' + ) + end + + # it 'allows the generation of scaffold helpers' do + # generate_and_assert_model "TestScaffoldHelpers", "--table_config=primary:5-2", "--scaffold" + # end + # + # it 'allows the generation of a password digest field' do + # generate_and_assert_model "TestPasswordDigest", "--table_config=primary:5-2", "--password-digest" + # end + end + end +end diff --git a/test/generators/aws_record/model/secondary_index_test.rb b/test/generators/aws_record/model/secondary_index_test.rb new file mode 100644 index 0000000..c3a778a --- /dev/null +++ b/test/generators/aws_record/model/secondary_index_test.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'test_helper' + +module AwsRecord + module Generators + # @api private + class SecondaryIndexTest < Minitest::Test + describe 'when given correct params' do + it 'sets its properties correctly' do + params = 'Model:hkey{uuid},rkey{title}' + + idx = SecondaryIndex.parse(params) + expect(idx.name).to eq('Model') + expect(idx.hash_key).to eq('uuid') + expect(idx.range_key).to eq('title') + expect(idx.projection_type).to eq('"ALL"') + end + + it 'sets its properties correctly independent of input order' do + params = 'Model:proj_type{ALL},hkey{uuid}' + + idx = SecondaryIndex.parse(params) + expect(idx.name).to eq('Model') + expect(idx.hash_key).to eq('uuid') + expect(idx.range_key).to eq(nil) + expect(idx.projection_type).to eq('"ALL"') + end + + it 'correctly handles underscores in field names' do + params = 'Model:hkey{long_uuid}' + + idx = SecondaryIndex.parse(params) + expect(idx.name).to eq('Model') + expect(idx.hash_key).to eq('long_uuid') + end + end + + describe 'when given incorrect params' do + it 'handles not being given a hash_key' do + params = 'Model:rkey{title}' + + expect do + SecondaryIndex.parse(params) + end.to raise_error(ArgumentError) + end + + it 'handles not being given any keys' do + params = 'Model' + + expect do + SecondaryIndex.parse(params) + end.to raise_error(ArgumentError) + end + end + + describe 'when using a projection' do + it 'correctly handles an ALL projection type' do + params = 'Model:hkey{uuid},proj_type{ALL}' + + idx = SecondaryIndex.parse(params) + expect(idx.projection_type).to eq('"ALL"') + end + + it 'correctly handles an KEYS_ONLY projection type' do + params = 'Model:hkey{uuid},proj_type{KEYS_ONLY}' + + expect do + SecondaryIndex.parse(params) + end.to raise_error(NotImplementedError) + end + + it 'correctly handles an INCLUDE projection type' do + params = 'Model:hkey{uuid},proj_type{INCLUDE}' + + expect do + SecondaryIndex.parse(params) + end.to raise_error(NotImplementedError) + end + + it 'handles invalid projection type types' do + params = 'Model:hkey{uuid},proj_type{INCLUDES}' + + expect do + SecondaryIndex.parse(params) + end.to raise_error(ArgumentError) + end + end + end + end +end diff --git a/test/generators/aws_record/resource/resource_generator_test.rb b/test/generators/aws_record/resource/resource_generator_test.rb new file mode 100644 index 0000000..ae6347d --- /dev/null +++ b/test/generators/aws_record/resource/resource_generator_test.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'test_helper' + +require 'generators/aws_record/resource/resource_generator' + +module AwsRecord + module Generators + # @api private + class ResourceGeneratorTest < Rails::Generators::TestCase + tests ResourceGenerator + destination File.expand_path('../../../dummy', __dir__) + + def run_generator(args, config = {}) + result = nil + capture(:stderr) do + result = super(args, config) + end + result + end + + def test_displays_options + content = run_generator ['--help'] + assert_match(/--table-config=primary:R-W/, content) + end + + def test_generates_files + run_generator %w[InheritedFileGenerationTest --table-config=primary:5-3] + + %w[app/models/inherited_file_generation_test.rb + db/table_config/inherited_file_generation_test_config.rb].each do |path| + assert_file(path) + end + end + + def test_removes_route_on_revoke + run_generator %w[account --table-config=primary:12-4] + run_generator %w[account], behavior: :revoke + + assert_file 'config/routes.rb' do |route| + refute_match(/resources :accounts$/, route) + end + end + end + end +end diff --git a/test/generators/aws_record/scaffold/scaffold_controller_generator_test.rb b/test/generators/aws_record/scaffold/scaffold_controller_generator_test.rb new file mode 100644 index 0000000..474686a --- /dev/null +++ b/test/generators/aws_record/scaffold/scaffold_controller_generator_test.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +require 'test_helper' + +require 'generators/aws_record/scaffold_controller/scaffold_controller_generator' + +module AwsRecord + module Generators + # @api private + class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase + tests ScaffoldControllerGenerator + destination File.expand_path('../../../dummy', __dir__) + + def run_generator(args, config = {}) + result = nil + capture(:stderr) do + result = super(args, config) + end + result + end + + def test_generates_controller_skeleton_properly + run_generator %w[ControllerSkeletonTest name age:int --skip-table-config -f] + + assert_file 'app/controllers/controller_skeleton_tests_controller.rb' do |content| + assert_match(/class ControllerSkeletonTestsController < ApplicationController/, content) + + assert_instance_method :index, content do |m| + assert_match(/@controller_skeleton_tests = ControllerSkeletonTest\.scan/, m) + end + + assert_instance_method :show, content + + assert_instance_method :new, content do |m| + assert_match(/@controller_skeleton_test = ControllerSkeletonTest\.new/, m) + end + + assert_instance_method :edit, content + + assert_instance_method :create, content do |m| + assert_match(/@controller_skeleton_test = ControllerSkeletonTest\.new\(controller_skeleton_test_params\)/, + m) + assert_match(/@controller_skeleton_test\.save/, m) + end + + assert_instance_method :update, content do |m| + assert_match(/@controller_skeleton_test\.update\(controller_skeleton_test_params\)/, m) + end + + assert_instance_method :destroy, content do |m| + assert_match(/@controller_skeleton_test\.delete!/, m) + assert_match(/Controller skeleton test was successfully destroyed./, m) + end + + assert_instance_method :set_controller_skeleton_test, content do |m| + assert_match( + /@controller_skeleton_test = ControllerSkeletonTest\.find\(uuid: CGI.unescape\(params\[:id\]\)\)/, m + ) + end + + assert_instance_method :controller_skeleton_test_params, content do |m| + assert_match(/params\.require\(:controller_skeleton_test\)\.permit\(:uuid, :name, :age\)/, m) + end + end + end + + def test_generates_api_controller_skeleton_properly + run_generator %w[ApiControllerSkeletonTest --api --skip-table-config -f] + + assert_file 'app/controllers/api_controller_skeleton_tests_controller.rb' do |content| + assert_match(/class ApiControllerSkeletonTestsController < ApplicationController/, content) + refute_match(/respond_to/, content) + + assert_match(/before_action :set_api_controller_skeleton_test, only: \[:show, :update, :destroy\]/, content) + + assert_instance_method :index, content do |m| + assert_match(/@api_controller_skeleton_tests = ApiControllerSkeletonTest\.scan/, m) + assert_match(/render json: @api_controller_skeleton_tests/, m) + end + + assert_instance_method :show, content do |m| + assert_match(/render json: @api_controller_skeleton_test/, m) + end + + assert_instance_method :create, content do |m| + assert_match( + /@api_controller_skeleton_test = ApiControllerSkeletonTest\.new\(api_controller_skeleton_test_params\)/, m + ) + assert_match(/@api_controller_skeleton_test\.save/, m) + assert_match(/@api_controller_skeleton_test\.errors/, m) + end + + assert_instance_method :update, content do |m| + assert_match(/@api_controller_skeleton_test\.update\(api_controller_skeleton_test_params\)/, m) + assert_match(/@api_controller_skeleton_test\.errors/, m) + end + + assert_instance_method :destroy, content do |m| + assert_match(/@api_controller_skeleton_test\.delete!/, m) + end + end + + assert_no_file 'app/views/api_controller_skeleton_tests/index.html.erb' + assert_no_file 'app/views/api_controller_skeleton_tests/edit.html.erb' + assert_no_file 'app/views/api_controller_skeleton_tests/show.html.erb' + assert_no_file 'app/views/api_controller_skeleton_tests/new.html.erb' + assert_no_file 'app/views/api_controller_skeleton_tests/_form.html.erb' + end + end + end +end diff --git a/test/tasks/aws_record/migrate_rake_task_test.rb b/test/tasks/aws_record/migrate_rake_task_test.rb new file mode 100644 index 0000000..583ae0b --- /dev/null +++ b/test/tasks/aws_record/migrate_rake_task_test.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'test_helper' + +require 'rake' + +module AwsRecord + # @api private + class MigrateRakeTest < ActiveSupport::TestCase + before do + Rake.application.rake_require 'tasks/aws_record/migrate' + Rake::Task.define_task(:environment) + end + + # Functionality for these methods are tested in aws-record. + # For this test, just validate the task can be invoked and calls the + # appropriate method. + it 'has a migrate task' do + expect(Dir).to receive(:[]).and_return([File.join(__dir__, 'test_table_config')]) + expect($stdout).to receive(:puts).with(/test_table_config.rb/) + Rake.application.invoke_task 'aws_record:migrate' + assert_mock ModelTableConfig.mock + end + end +end diff --git a/test/tasks/aws_record/test_table_config.rb b/test/tasks/aws_record/test_table_config.rb new file mode 100644 index 0000000..b4a472c --- /dev/null +++ b/test/tasks/aws_record/test_table_config.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'aws-record' + +module ModelTableConfig + class << self + def config + @mock = MiniTest::Mock.new + @mock.expect(:compatible?, false) + @mock.expect(:migrate!, nil) + end + + attr_reader :mock + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..53af6d6 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'minitest/autorun' +require 'minitest/unit' +require 'rspec/expectations/minitest_integration' +require 'rspec/mocks/minitest_integration' +require 'minitest-spec-rails' + +ENV['RAILS_ENV'] = 'test' + +require_relative 'dummy/config/application' + +Rails.application.initialize!