Skip to content

A kind of ORM for Amazon Aurora Serverless NOT depending on ActiveRecord

License

Notifications You must be signed in to change notification settings

hasumikin/aurora-data-api

Repository files navigation

AuroraDataApi Ruby

A kind of ORM for Amazon Aurora Serverless v1.

Supposing that you are using Ruby (typically on AWS Lambda) as an application, Aurora Serverless v1 (NOT v2) as a database, and Data API as a database adapter.

This gem doesn't depend on ActiveRecord and takes advantage of PORO (plain old Ruby object) like Array, Hash, and Struct internally so you can easily hack.

PostgreSQL is the only target as of now.

Installation

Add this line to your application's Gemfile:

gem 'aurora-data-api'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install aurora-data-api

Usage

Let's say we're developing a blog that has three models:

  • User: able to post an entry and to comment on any entry
  • Entry: an article
  • Comment: a comment on an entry
class User < AuroraDataApi::Model
  schema do
    col :name,             String
    col :internet_account, String
    timestamp # Creates :created_at and :updated_at
  end

  def twitter
    "https://twitter.com/#{internet_account}"
  end
end

class Entry < AuroraDataApi::Model
  schema do
    col :user,  :User  # User.to_sym
    col :title, String
    col :body,  String
    timestamp
  end
end

class Comment < AuroraDataApi::Model
  schema do
    col :user,  :User  # User.to_sym
    col :entry, :Entry, table: :entries  #...(*)
    col :body,  String
    timestamp
  end
end

# (*)
# The plural of "entry" is too difficult for aurora-data-api.
# So you need to explicitly tell gem the table name.
require_relative '../models/user'
UserDepot = AuroraDataApi::Depot[User] do
end

require_relative '../models/entry'
EntryDepot = AuroraDataApi::Depot[Entry] do
end

require_relative '../models/comment'
CommentDepot = AuroraDataApi::Depot[Comment] do
end

Insert a user

user = User.new(name: "HASUMI Hitoshi", internet_account: "hasumikin")
user.id                 # => nil
UserDepot.insert(user)  # => 1
user.id                 # => 1

Update the user

user.internet_account = "HASUMIKIN"
UserDepot.update(user)  # => true (false if failed)
user.internet_account   # => "HASUMIKIN"

Delete the user

UserDepot.delete(user)  # => true (false if failed)
user.id                 # => nil

Find a user

hasumikin = UserDepot.select(
  "WHERE internet_account = :internet_account",
  internet_account: "hasumikin"
).first

Post an entry

my_entry = Entry.new(
  user: hasumikin,
  title: "My first article",
  body: "Hey, this is an article about Ruby."
)
EntryDepot.insert(my_entry)

Update the entry

my_entry.body = "Hey, this is an article about Ruby whick is a happy language!"
EntryDepot.update(my_entry)

Delete the entry

EntryDepot.delete(my_entry)

Count comments

count = CommentDepot.count(
  "WHERE entry_id = :entry_id",
  entry_id: my_entry.id
)

Select comments

comments = CommentDepot.select(<<~SQL, user_id: hasumikin.id)
  INNER JOIN ENTRY ON entry.id = comment.entry_id
  WHERE entry.user_id = :user_id
  ORDER BY comment.created_at
  LIMIT 10 OFFSET 0
SQL
comments.class                 # => Array
comments.first.class           # => Comment
comments.first.body            # => "I have a question, ..."
comments.first.entry.class     # => Entry
comments.first.entry.title     # => "My first article"
comments.first.entry.user.name # => "HASUMI Hitoshi"

As of the current version, the last call comments.first.entry.user.name will execute another query so it may cause an N+1 problem.

Typical application structure

your_app
├── Gemfile        # It includes `gem 'aurora-data-api'`
├── app
│   ├── handlers  # You may have Lambda functions here
│   ├── models
│   │   ├── comment.rb
│   │   ├── entry.rb
│   │   └── user.rb
│   └── depots
│       ├── comment_depot.rb
│       ├── entry_depot.rb
│       └── user_depot.rb
├── db
│   └── shcema.sql
└── serverless.yml # aurora-data-api is perfect for Serverless Framework

aurora-data-api doesn't have a generator to initiate the structure. Make it manually instead like:

mkdir -p app/models app/depots db

Migration

The following command overwrites db/schema.sql (for only PostgreSQL) by aggregating app/models/*.rb

bundle exec aurora-data-api export

We recommend to use @k0kubun's sqldef to manage migration.

See k0kubun/sqldef

Environment variables

The following variables should be defined:

ENV['PGDATABASE']       # Database name
ENV['RDS_RESOURCE_ARN'] # Resource ARN of RDS Aurora Serverless
ENV['RDS_SECRET_ARN']   # Secret ARN that is stored in AWS Secrets Manager
ENV['TZ']               # (Optional) Timezone. Internal default is "UTC"

RDS_SECRET_ARN has to be attached to an IAM role of the "application".

Example project with Serverless Project

See example

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/hasumikin/aurora-data-api. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the AuroraDataApi project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

About

A kind of ORM for Amazon Aurora Serverless NOT depending on ActiveRecord

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published