Skip to content

Commit

Permalink
Modularize Aws::Record
Browse files Browse the repository at this point in the history
  • Loading branch information
mullermp committed Oct 24, 2024
1 parent 3bbbf0a commit c7c33e8
Show file tree
Hide file tree
Showing 83 changed files with 9,633 additions and 362 deletions.
11 changes: 8 additions & 3 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ AllCops:
- 'spec/dummy/**/*'
- 'spec/fixtures/**/*'
- 'spec/fixtures/**/*'
- 'db/**/*'

Gemspec/DevelopmentDependencies:
EnforcedStyle: Gemfile
Expand All @@ -31,17 +30,23 @@ Style/GlobalVars:
Metrics/BlockLength:
Exclude:
- 'spec/**/*.rb'
- aws-sdk-rails.gemspec
- 'test/**/*.rb'

Metrics/ClassLength:
Exclude:
- 'spec/**/*.rb'
- 'test/**/*.rb'

Metrics/ModuleLength:
Exclude:
- 'spec/**/*.rb'
- 'test/**/*.rb'

Style/HashSyntax:
EnforcedShorthandSyntax: never

Style/Documentation:
Exclude:
- 'lib/generators/**/*.rb'
- 'lib/aws/rails/notifications.rb'
- 'spec/**/*.rb'
- 'test/**/*.rb'
8 changes: 0 additions & 8 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,31 +67,23 @@ Naming/AccessorMethodName:
Naming/PredicateName:
Exclude:
- 'spec/**/*'
- 'lib/generators/aws_record/base.rb'

# Offense count: 9
# Configuration parameters: AllowedConstants.
Style/Documentation:
Exclude:
- 'spec/**/*'
- 'test/**/*'
- 'lib/active_job/queue_adapters/sqs_adapter.rb'
- 'lib/aws/rails/notifications.rb'
- 'lib/aws/rails/sqs_active_job/configuration.rb'
- 'lib/aws/rails/sqs_active_job/job_runner.rb'
- 'lib/aws/rails/sqs_active_job/lambda_handler.rb'
- 'lib/generators/aws_record/base.rb'
- 'lib/generators/aws_record/generated_attribute.rb'
- 'lib/generators/aws_record/model/model_generator.rb'
- 'lib/generators/aws_record/secondary_index.rb'

# Offense count: 5
# This cop supports safe autocorrection (--autocorrect).
Style/IfUnlessModifier:
Exclude:
- 'lib/aws/rails/middleware/ebs_sqs_active_job_middleware.rb'
- 'lib/generators/aws_record/base.rb'
- 'lib/generators/aws_record/secondary_index.rb'

# Offense count: 23
# This cop supports safe autocorrection (--autocorrect).
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Unreleased Changes
------------------

* Feature - Prepare modularization of `aws-record`.

4.1.0 (2024-09-27)
------------------

Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ group :development, :test do
end

group :development do
gem 'byebug', platforms: :ruby
gem 'rubocop'
end

group :test do
gem 'bcrypt'
gem 'minitest-spec-rails'
gem 'rspec-rails'
gem 'webmock'
end
Expand Down
125 changes: 74 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ This gem also brings in the following AWS gems:
* `aws-sdk-sesv2`
* `aws-sdk-sqs`
* `aws-sdk-sns`
* `aws-record`
* `aws-sessionstore-dynamodb`

You will have to ensure that you provide credentials for the SDK to use. See the
Expand Down Expand Up @@ -575,17 +574,27 @@ FIFO queues require a message group id to be provided for the job. It is determi
2. If `message_group_id` is not defined or the result is `nil`, the default value will be used.
You can optionally specify a custom value in your config as the default that will be used by all jobs.

## AWS Record Generators
## AWS Record Model Generators

This package also pulls in the [\`aws-record\` gem](https://github.com/aws/aws-sdk-ruby-record)
and provides generators for creating models and a rake task for performing
table config migrations.
This package provides generators for creating `Aws::Record` models and table
configurations that are backed by DynamoDB, and a rake task for performing
the migrations.

To enable this feature, add the following to your Gemfile:

```ruby
gem 'aws-record', '~> 2'
```

### Setup

You can either invoke the generator by calling `rails g aws_record:model ...`
You can either invoke the generator by calling

```bash
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|
Expand All @@ -594,11 +603,15 @@ end
```
Which will cause `aws_record:model` to be invoked by the Rails model generator.


### 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:

```bash
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
Expand Down Expand Up @@ -629,7 +642,9 @@ 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}`
```bash
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
Expand All @@ -653,7 +668,9 @@ end

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}`
```bash
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}
```

Which results in the following files being generated:

Expand All @@ -673,7 +690,7 @@ class Forum
string_attr :post_title
string_attr :post_body
string_set_attr :tags, default_value: Set.new
datetime_attr :created_at, database_attribute_name: "PostCreatedAtTime"
datetime_attr :created_at, database_attribute_name: 'PostCreatedAtTime'
boolean_attr :moderation, default_value: false
global_secondary_index(
Expand All @@ -691,56 +708,62 @@ end
# ...
```

To migrate your new models and begin using them you can run the provided rake task: `rails aws_record:migrate`
### Running Table Config Migrations

### Docs
The included rake task `aws_record:migrate` will run all of the migrations in
`app/db/table_config`:

```bash
rake aws_record:migrate
```

### Model generator attributes

The syntax for creating an aws-record model follows:

`rails generate aws_record:model NAME [field[:type][:opts]...] [options]`
```bash
rails generate aws_record:model NAME [field[:type][:opts]...] [options]
```

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

| 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, it will assume the field is of type `:string_attr`.

Additionally a number of options may be attached as a comma separated 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
| 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

The included rake task `aws_record:migrate` will run all of the migrations in `app/db/table_config`
| 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 |
12 changes: 11 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'rspec/core/rake_task'
require 'rake/testtask'
require 'rubocop/rake_task'

$REPO_ROOT = File.dirname(__FILE__)
Expand All @@ -14,6 +15,15 @@ RuboCop::RakeTask.new

RSpec::Core::RakeTask.new(:spec)

# Eventually, migrate all tests back into the minitest
# runner. But use minitest-spec-rails to enable syntax.
# Currently, rails generator specs are not running.
Rake::TestTask.new('test:rails') do |t|
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.warning = false
end

task :db_migrate do
Dir.chdir('spec/dummy') do
version = ENV.delete('VERSION') # ActiveRecord uses this
Expand All @@ -22,6 +32,6 @@ task :db_migrate do
end
end

task test: %i[db_migrate spec]
task test: [:db_migrate, :spec, 'test:rails']
task default: :test
task 'release:test' => :test
2 changes: 1 addition & 1 deletion gemfiles/rails-main.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ group :test do
# this is not published for some reason
git: 'https://github.com/jruby/activerecord-jdbc-adapter',
glob: 'activerecord-jdbcsqlite3-adapter/activerecord-jdbcsqlite3-adapter.gemspec'
gem 'sqlite3', '~> 2.0.0', platform: :ruby
gem 'sqlite3', platform: :ruby
end
2 changes: 0 additions & 2 deletions lib/aws-sdk-rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@

require_relative 'action_dispatch/session/dynamodb_store'

require_relative 'generators/aws_record/base'

module Aws
module Rails
VERSION = File.read(File.expand_path('../VERSION', __dir__)).strip
Expand Down
2 changes: 1 addition & 1 deletion lib/aws/rails/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Railtie < ::Rails::Railtie

rake_tasks do
load 'tasks/dynamo_db/session_store.rake'
load 'tasks/aws_record/migrate.rake'
load 'tasks/aws_record/migrate.rake' if defined?(Aws::Record)
end
end

Expand Down
Loading

0 comments on commit c7c33e8

Please sign in to comment.