aurora-data-api 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 344043ce8593c877dc10b721e2b1724ea96265ed5411fbef7828a7c670a3d40e
4
- data.tar.gz: b3b440e30ef5b87abb26d987c8a35951cdb5e4c135181fc20ef9d59142a1f625
3
+ metadata.gz: 9e9e12802725256d0bdc9d33f440906b71ae20924215188db1f65b7be77e5474
4
+ data.tar.gz: baaf18e32b395d14ae044ece3c23cad990b9bee6a199819a49e423bd99996e18
5
5
  SHA512:
6
- metadata.gz: dd445671cf4c71684bcc20f24e0eea75d82218dd6959d338cc87e6faafd59a02644fd95fa31e8310645b2796114ea3d541ffd4fa71eb92c81846fd775fcba56e
7
- data.tar.gz: dcdcf6717773ed3bc9921193eddac358496fc19aa90a4e4b7e3ba41c87096ecdc932e69fdd968f37b269e06e6a3ccf0812f755e87e79ee24af167bb65766cbea
6
+ metadata.gz: 303da4d601927f8419139e23b21f8d5b42a218a7ff6cea2132f89e2a80aea7074563e1f9826b5419e90a9da6812bf46e1490a9444ca50a9ad19a22a2ac23f29a
7
+ data.tar.gz: 6c08a977905060290ae36b5bc2abdb6c94dda4bbaabd68915037052cec4cd9b8c6dbb4be92d9edc9c2cb055ffa71e96e77b73bd692b213794493d6725baf7638
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.1.1 - 2022-06-02
2
+
3
+ - Fix some issues (experimental)
4
+
1
5
  ## 0.1.0 - 2022-05-31
2
6
 
3
7
  - Initial release (experimental)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- aurora-data-api (0.1.0)
4
+ aurora-data-api (0.1.1)
5
5
  aws-sdk-rdsdataservice (~> 1.35.0)
6
6
  thor
7
7
 
@@ -15,7 +15,7 @@ GEM
15
15
  tzinfo (~> 2.0)
16
16
  ast (2.4.2)
17
17
  aws-eventstream (1.2.0)
18
- aws-partitions (1.591.0)
18
+ aws-partitions (1.592.0)
19
19
  aws-sdk-core (3.131.1)
20
20
  aws-eventstream (~> 1, >= 1.0.2)
21
21
  aws-partitions (~> 1, >= 1.525.0)
data/README.md CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  A kind of ORM for Amazon Aurora Serverless v1.
4
4
 
5
- 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 the database adapter.
5
+ 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.
6
+
7
+ 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.
6
8
 
7
9
  PostgreSQL is the only target as of now.
8
10
 
@@ -213,10 +215,15 @@ The following variables should be defined:
213
215
  ENV['PGDATABASE'] # Database name
214
216
  ENV['RDS_RESOURCE_ARN'] # Resource ARN of RDS Aurora Serverless
215
217
  ENV['RDS_SECRET_ARN'] # Secret ARN that is stored in AWS Secrets Manager
218
+ ENV['TZ'] # (Optional) Timezone. Internal default is "UTC"
216
219
  ```
217
220
 
218
221
  RDS_SECRET_ARN has to be attached to an IAM role of the "application".
219
222
 
223
+ ## Example project with Serverless Project
224
+
225
+ See [example](https://github.com/hasumikin/aurora-data-api/tree/master/example)
226
+
220
227
  ## Development
221
228
 
222
229
  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.
data/Steepfile CHANGED
@@ -1,5 +1,5 @@
1
1
  target :lib do
2
2
  signature "sig"
3
3
  check "lib"
4
- library "time"
4
+ library "time", "date"
5
5
  end
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ["hasumikin@gmail.com"]
10
10
 
11
11
  spec.summary = "A kind of ORM for Amazon Aurora Serverless v1"
12
- spec.description = "Assuming you are using AWS Lambda as a backend, Aurora Serverless v1 (NOT v2) as a database, and Data API as an adapter"
12
+ spec.description = "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."
13
13
  spec.homepage = "https://github.com/hasumikin/aurora-data-api"
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = ">= 2.7.0"
data/example/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'aurora-data-api', github: 'hasumikin/aurora-data-api'
3
+ gem 'aurora-data-api'
4
4
  gem 'aws-sdk-lambda'
5
5
 
6
6
  group :test, :development do
data/example/Gemfile.lock CHANGED
@@ -1,14 +1,9 @@
1
- GIT
2
- remote: https://github.com/hasumikin/aurora-data-api.git
3
- revision: 70ae5070c8391c6be2ac9b4209425308ed01f2e7
1
+ GEM
2
+ remote: https://rubygems.org/
4
3
  specs:
5
4
  aurora-data-api (0.1.0)
6
5
  aws-sdk-rdsdataservice (~> 1.35.0)
7
6
  thor
8
-
9
- GEM
10
- remote: https://rubygems.org/
11
- specs:
12
7
  aws-eventstream (1.2.0)
13
8
  aws-partitions (1.594.0)
14
9
  aws-sdk-core (3.131.1)
@@ -39,7 +34,7 @@ PLATFORMS
39
34
  x86_64-linux
40
35
 
41
36
  DEPENDENCIES
42
- aurora-data-api!
37
+ aurora-data-api
43
38
  aws-sdk-lambda
44
39
  rake
45
40
  test-unit-rr
data/example/README.md CHANGED
@@ -2,44 +2,119 @@
2
2
 
3
3
  ### Stack
4
4
 
5
+ - Ruby + aurora-data-api gem
5
6
  - Serverless Framework
6
- - Lamdda functions (outside VPC)
7
- - RDS Aurora Serverless v1 (inside VPC) +
7
+ - Lambda functions outside VPC
8
+ - RDS Aurora Serverless v1 inside VPC + Data API (HTTP endpoint)
9
+ - Secrets Manager, IAM, etc.
8
10
 
9
- ### Getting started
11
+ ### Try in your local computer with docker
10
12
 
11
13
  ```sh
12
14
  docker compose build
13
- docker compose run --rm serverless rake db:create_database
14
- docker compose run --rm serverless bundle exec aurora-data-api export
15
- docker compose run --rm serverless rake db:migrate_dry_run
16
- docker compose run --rm serverless rake db:migrate
17
15
  ```
16
+
17
+ #### Create database
18
+
19
+ ```sh
20
+ docker compose run --rm serverless rake db:create
21
+ ```
22
+
23
+ #### Confirm the SQL of migration
24
+
18
25
  ```sh
19
26
  docker compose run --rm serverless rake db:migrate_dry_run
20
- => -- Nothing is modified --
21
27
  ```
28
+
29
+ #### Migrate
30
+
31
+ ```sh
32
+ docker compose run --rm serverless rake db:migrate
33
+ ```
34
+
35
+ #### Start containers
36
+
22
37
  ```sh
23
38
  docker compose up
24
39
  ```
40
+
41
+ ### APIs
42
+
25
43
  ```sh
26
44
  curl http://localhost:4000/offline/hello
27
45
  ```
28
46
 
47
+ #### Create a user
48
+
29
49
  ```sh
30
50
  curl -X POST http://localhost:4000/offline/create_user \
31
51
  -H 'Content-Type: application/json' \
32
52
  -d '{"name":"HASUMI Hitoshi", "internet_account":"hasumikin"}'
53
+ ```
54
+
55
+ #### List users
33
56
 
57
+ ```sh
58
+ curl http://localhost:4000/offline/users
59
+ ```
60
+
61
+ #### Update the user
62
+
63
+ ```sh
34
64
  curl -X PUT http://localhost:4000/offline/update_user \
35
65
  -H 'Content-Type: application/json' \
36
66
  -d '{"id":1, "name":"anonymous", "internet_account":"hasumikin"}'
67
+ ```
37
68
 
69
+ #### Create an entry
70
+
71
+ ```sh
38
72
  curl -X POST http://localhost:4000/offline/create_entry \
39
73
  -H 'Content-Type: application/json' \
40
74
  -d '{"title":"My first atrticle", "user_id":1}'
75
+ ```
76
+
77
+ #### List entries
78
+
79
+ ```sh
80
+ curl http://localhost:4000/offline/entries
81
+ ```
41
82
 
83
+ #### Delete the entry
84
+
85
+ ```sh
42
86
  curl -X POST http://localhost:4000/offline/delete_entry \
43
87
  -H 'Content-Type: application/json' \
44
88
  -d '{"entry_id":1}'
45
89
  ```
90
+
91
+ ### Deploy to AWS
92
+
93
+ Supposing you have an AWS credential in $HOME/.aws/credentials.
94
+ It has to have almost administrative permission in order to provision a Serverless Framework app:
95
+
96
+ ```
97
+ [YourAWSProfileName]
98
+ aws_access_key_id=AKIAxxxxxxxxxxxxxxxxx
99
+ aws_secret_access_key=xxxxxxxxxxxxxxxxxxxxxxxxxx
100
+ ```
101
+
102
+ ```sh
103
+ serverless deploy --stage production --aws-profile [YourAWSProfileName]
104
+ ```
105
+
106
+ About 30 minutes later, all stacks should've been provisioned in AWS.
107
+
108
+ - You can see API endpoints by `sls info --stage production --aws-profile [YourAWSProfileName]`
109
+ - Open the AWS management console
110
+ - Find *RDS_SECRET_ARN* value lools like `arn:aws:secretsmanager:ap-northeast-1:01234567890:secret:aurora-data-api-example-production-AuroraUserSecret-xxxxxx` in "Secrets Manager"
111
+
112
+ <img src="https://raw.githubusercontent.com/hasumikin/aurora-data-api/master/example/doc/query-edidor.png" width="400" />
113
+
114
+ - Go to "RDS" > "Query Editor" of and connect with the secret ARN above, then run the content of `db/schema.sql` to create tables
115
+
116
+ Now that you can call APIs like:
117
+
118
+ ```sh
119
+ curl https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/production/hello
120
+ ```
data/example/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  namespace "db" do
3
3
  desc "Create database"
4
- task :create_database do
4
+ task :create do
5
5
  sql = <<~SQL
6
6
  CREATE DATABASE #{ENV['PGDATABASE']}
7
7
  TEMPLATE template0 ENCODING 'UTF-8' LC_COLLATE 'C' LC_CTYPE 'C';
@@ -10,7 +10,7 @@ namespace "db" do
10
10
  end
11
11
 
12
12
  desc "Drop database"
13
- task :drop_database do
13
+ task :drop do
14
14
  sql = <<~SQL
15
15
  DROP DATABASE #{ENV['PGDATABASE']};
16
16
  SQL
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Dir.glob("/var/runtime/bundler/gems/**").each do |dir|
4
- $LOAD_PATH.unshift("#{dir}/lib/")
5
- end
6
-
7
3
  require "json"
8
4
  require "aurora-data-api"
9
5
  require_relative "../depots/user_depot"
@@ -6,6 +6,7 @@ class Entry < AuroraDataApi::Model
6
6
  col :user, :User, table: :users, null: false
7
7
  col :title, String
8
8
  col :body, String
9
+ col :publish_date, Date
9
10
  timestamp
10
11
  end
11
12
  end
Binary file
@@ -108,7 +108,7 @@ resources:
108
108
  AutoPause: true
109
109
  MaxCapacity: ${self:custom.myEnvironment.DBMaxCapacity.${sls:stage}, 2}
110
110
  MinCapacity: 2
111
- SecondsUntilAutoPause: 900 # 15 min for example
111
+ SecondsUntilAutoPause: 3600 # 60 min for example
112
112
  DBSubnetGroupName:
113
113
  Ref: DBSubnetGroup
114
114
  DBSecret:
data/exe/aurora-data-api CHANGED
@@ -2,9 +2,8 @@
2
2
 
3
3
  require "aurora-data-api/version"
4
4
  require "thor"
5
-
6
- class Date
7
- end
5
+ require "date"
6
+ require "fileutils"
8
7
 
9
8
  module AuroraDataApi
10
9
  class Error < StandardError; end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "date"
4
+ require "tzinfo"
5
+
3
6
  module AuroraDataApi
4
7
  class Depot
5
8
  def self.[](model, &block)
@@ -13,6 +16,7 @@ module AuroraDataApi
13
16
  @model = model
14
17
  instance_eval { block.call }
15
18
  @data_service = DataService.new
19
+ @observed_utc_offset = TZInfo::Timezone.get(ENV['TZ'] || "UTC").observed_utc_offset
16
20
  end
17
21
 
18
22
  def table_name
@@ -103,7 +107,9 @@ module AuroraDataApi
103
107
  when "text"
104
108
  col.value.gsub("''", "'")
105
109
  when "timestamptz"
106
- Time.parse(col.value) + 9 * 60 * 60 # workaround
110
+ Time.parse(col.value) + @observed_utc_offset
111
+ when "date"
112
+ Date.parse(col.value)
107
113
  else
108
114
  col.value
109
115
  end
@@ -44,7 +44,7 @@ module AuroraDataApi
44
44
  end
45
45
 
46
46
  def self.relationship_by(table_sym)
47
- result = Model::SCHEMA[name&.to_sym].select { |_k, v|
47
+ result = Model::SCHEMA[to_s.to_sym].select { |_k, v|
48
48
  v.is_a? Hash
49
49
  }.select { |_k, v|
50
50
  v.dig(:opt, :table) == table_sym
@@ -94,7 +94,7 @@ module AuroraDataApi
94
94
  if @struct[method_name].nil?
95
95
  col_id = "#{method_name}_#{literal_id}".to_sym
96
96
  if members.include?(col_id) && @struct[col_id]
97
- col_model = SCHEMA[self.class.name&.to_sym][:cols].dig(method_name, :type)
97
+ col_model = SCHEMA[self.class.to_s.to_sym][:cols].dig(method_name, :type)
98
98
  return nil unless col_model
99
99
  @struct[method_name] = AuroraDataApi.const_get("#{col_model}Depot".to_sym).select(
100
100
  %(where "#{literal_id}" = :id), id: @struct[col_id]
@@ -109,7 +109,7 @@ module AuroraDataApi
109
109
  end
110
110
 
111
111
  def table_name
112
- SCHEMA[self.class.name&.to_sym][:table_name]
112
+ SCHEMA[self.class.to_s.to_sym][:table_name]
113
113
  end
114
114
 
115
115
  def literal_id
@@ -120,7 +120,7 @@ module AuroraDataApi
120
120
  {}.tap do |hash|
121
121
  members.each do |member|
122
122
  next if member == literal_id && !include_id
123
- next if SCHEMA[self.class.name&.to_sym][:cols][member][:type].is_a? Symbol
123
+ next if SCHEMA[self.class.to_s.to_sym][:cols][member][:type].is_a? Symbol
124
124
  send(member).then { |v| hash[member] = v }
125
125
  end
126
126
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AuroraDataApi
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
@@ -9,6 +9,3 @@ module AuroraDataApi
9
9
  class Error < StandardError; end
10
10
  # Your code goes here...
11
11
  end
12
-
13
- class Date
14
- end
@@ -2,9 +2,6 @@ module AuroraDataApi
2
2
  Error: StandardError
3
3
  end
4
4
 
5
- class Date
6
- end
7
-
8
5
  module Aws
9
6
  def self.config: -> Hash[Symbol, untyped]
10
7
 
data/sig/model.rbs CHANGED
@@ -2,20 +2,32 @@
2
2
 
3
3
  # Classes
4
4
  module AuroraDataApi
5
+ type attribute = Symbol | Time | Date | Integer | Symbol | bool | nil
6
+ type attribute_type = singleton(String)
7
+ | singleton(Time)
8
+ | singleton(Date)
9
+ | singleton(Integer)
10
+ | Symbol
11
+
5
12
  class Model
6
- SCHEMA: Hash[untyped, untyped]
7
- STRUCTS: Hash[untyped, untyped]
13
+ SCHEMA: Hash[Symbol, untyped]
14
+ STRUCTS: Hash[Symbol, untyped]
8
15
  @struct: untyped
9
16
 
17
+ type col_opt = Hash[:table, Symbol]
18
+ | Hash[:null, bool]
19
+ | Hash[:unique, bool]
20
+ | Hash[:default, untyped]
21
+
10
22
  def self.model_name: -> Symbol
11
23
  def self.literal_id: (Symbol lit) -> Symbol
12
24
  def self.table: (Symbol name) -> Symbol
13
25
  def self.table_name: -> Symbol
14
26
  def self.schema: () { () -> void } -> void
15
- def self.col: (Symbol name, singleton(String) | singleton(Time) | singleton(Date) | singleton(Integer) | Symbol type, ?Hash[Symbol, Symbol | bool] opt) -> void
27
+ def self.col: (Symbol name, attribute_type type, ?col_opt opt) -> void
16
28
  def self.timestamp: -> void
17
29
  def self.relationship_by: (Symbol table_sym) -> [untyped, untyped]?
18
- def initialize: (**Hash[Symbol, untyped]) -> void
30
+ def initialize: (**Hash[Symbol, attribute]) -> void
19
31
 
20
32
  attr_reader id: Integer?
21
33
  attr_reader timestamp: bool
@@ -25,11 +37,11 @@ module AuroraDataApi
25
37
  def set_timestamp: (at: :update | :create) -> bool
26
38
  def members: -> Array[Symbol]
27
39
  def respond_to_missing?: (untyped symbol, untyped include_private) -> true
28
- def method_missing: (untyped method_name, *untyped args) -> nil
40
+ def method_missing: (Symbol method_name, *untyped args) -> nil
29
41
  def table_name: -> Symbol
30
42
  def literal_id: -> Symbol
31
- def build_params: (?include_id: bool) -> Hash[Symbol, untyped]
32
- def attributes: -> Hash[Symbol, untyped]
43
+ def build_params: (?include_id: bool) -> Hash[Symbol, attribute]
44
+ def attributes: -> Hash[Symbol, attribute]
33
45
  def _set_id: (Integer? id) -> void
34
46
  def _destroy: -> bool
35
47
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aurora-data-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - HASUMI Hitoshi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-05-31 00:00:00.000000000 Z
11
+ date: 2022-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-rdsdataservice
@@ -38,8 +38,8 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- description: Assuming you are using AWS Lambda as a backend, Aurora Serverless v1
42
- (NOT v2) as a database, and Data API as an adapter
41
+ description: Doesn't depend on ActiveRecord and takes advantage of PORO (plain old
42
+ Ruby object) like Array, Hash, and Struct internally so you can easily hack.
43
43
  email:
44
44
  - hasumikin@gmail.com
45
45
  executables:
@@ -75,6 +75,7 @@ files:
75
75
  - example/compose.yml
76
76
  - example/db/.gitignore
77
77
  - example/db/.keep
78
+ - example/doc/query-edidor.png
78
79
  - example/package-lock.json
79
80
  - example/package.json
80
81
  - example/serverless.yml