sequel_mapper 0.0.1 → 0.0.3

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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CODE_OF_CONDUCT.md +28 -0
  4. data/Gemfile.lock +32 -2
  5. data/MissingFeatures.md +64 -0
  6. data/README.md +141 -72
  7. data/Rakefile +29 -0
  8. data/TODO.md +16 -11
  9. data/features/env.rb +57 -0
  10. data/features/example.feature +121 -0
  11. data/features/step_definitions/example_steps.rb +46 -0
  12. data/lib/sequel_mapper.rb +6 -2
  13. data/lib/sequel_mapper/abstract_record.rb +53 -0
  14. data/lib/sequel_mapper/association_loaders.rb +52 -0
  15. data/lib/sequel_mapper/collection_mutability_proxy.rb +77 -0
  16. data/lib/sequel_mapper/configurations/conventional_association_configuration.rb +187 -0
  17. data/lib/sequel_mapper/configurations/conventional_configuration.rb +269 -0
  18. data/lib/sequel_mapper/dataset.rb +37 -0
  19. data/lib/sequel_mapper/deleted_record.rb +16 -0
  20. data/lib/sequel_mapper/dirty_map.rb +31 -0
  21. data/lib/sequel_mapper/graph_loader.rb +48 -0
  22. data/lib/sequel_mapper/graph_serializer.rb +107 -0
  23. data/lib/sequel_mapper/identity_map.rb +22 -0
  24. data/lib/sequel_mapper/lazy_object_proxy.rb +51 -0
  25. data/lib/sequel_mapper/many_to_many_association.rb +181 -0
  26. data/lib/sequel_mapper/many_to_one_association.rb +60 -0
  27. data/lib/sequel_mapper/mapper_facade.rb +180 -0
  28. data/lib/sequel_mapper/one_to_many_association.rb +51 -0
  29. data/lib/sequel_mapper/public_conveniencies.rb +27 -0
  30. data/lib/sequel_mapper/query_order.rb +32 -0
  31. data/lib/sequel_mapper/queryable_lazy_dataset_loader.rb +70 -0
  32. data/lib/sequel_mapper/relation_mapping.rb +35 -0
  33. data/lib/sequel_mapper/serializer.rb +18 -0
  34. data/lib/sequel_mapper/short_inspection_string.rb +18 -0
  35. data/lib/sequel_mapper/subset_queries_proxy.rb +11 -0
  36. data/lib/sequel_mapper/upserted_record.rb +15 -0
  37. data/lib/sequel_mapper/version.rb +1 -1
  38. data/sequel_mapper.gemspec +3 -0
  39. data/spec/config_override_spec.rb +167 -0
  40. data/spec/custom_serializers_spec.rb +77 -0
  41. data/spec/deletion_spec.rb +104 -0
  42. data/spec/graph_persistence_spec.rb +83 -88
  43. data/spec/graph_traversal_spec.rb +32 -31
  44. data/spec/new_graph_persistence_spec.rb +69 -0
  45. data/spec/object_identity_spec.rb +70 -0
  46. data/spec/ordered_association_spec.rb +46 -16
  47. data/spec/persistence_efficiency_spec.rb +186 -0
  48. data/spec/predefined_queries_spec.rb +73 -0
  49. data/spec/proxying_spec.rb +25 -19
  50. data/spec/querying_spec.rb +24 -27
  51. data/spec/readme_examples_spec.rb +35 -0
  52. data/spec/sequel_mapper/abstract_record_spec.rb +179 -0
  53. data/spec/sequel_mapper/{association_proxy_spec.rb → collection_mutability_proxy_spec.rb} +6 -6
  54. data/spec/sequel_mapper/deleted_record_spec.rb +59 -0
  55. data/spec/sequel_mapper/lazy_object_proxy_spec.rb +140 -0
  56. data/spec/sequel_mapper/public_conveniencies_spec.rb +49 -0
  57. data/spec/sequel_mapper/queryable_lazy_dataset_loader_spec.rb +103 -0
  58. data/spec/sequel_mapper/upserted_record_spec.rb +59 -0
  59. data/spec/spec_helper.rb +7 -10
  60. data/spec/support/blog_schema.rb +29 -0
  61. data/spec/support/have_persisted_matcher.rb +19 -0
  62. data/spec/support/mapper_setup.rb +234 -0
  63. data/spec/support/mock_sequel.rb +0 -1
  64. data/spec/support/object_graph_setup.rb +106 -0
  65. data/spec/support/seed_data_setup.rb +122 -0
  66. data/spec/support/sequel_persistence_setup.rb +19 -0
  67. data/spec/support/sequel_test_support.rb +159 -0
  68. metadata +121 -15
  69. data/lib/sequel_mapper/association_proxy.rb +0 -54
  70. data/lib/sequel_mapper/belongs_to_association_proxy.rb +0 -27
  71. data/lib/sequel_mapper/graph.rb +0 -174
  72. data/lib/sequel_mapper/queryable_association_proxy.rb +0 -23
  73. data/spec/sequel_mapper/belongs_to_association_proxy_spec.rb +0 -65
  74. data/spec/support/graph_fixture.rb +0 -331
  75. data/spec/support/query_counter.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2a26f63ff570a4dace02b8407237d137e91fcc86
4
- data.tar.gz: 682421f11a6baccefbe7969510f345d17ea26d71
3
+ metadata.gz: dfb105e407d34250b83618b2c789687d0fe1f86f
4
+ data.tar.gz: 01aeb7f356ab17224b3c93f10fbf8b8204258c98
5
5
  SHA512:
6
- metadata.gz: ebc65d4a2915be9f85d269c417f47d96bec45255601a8a389b88c5bdc009420fac2c9f65ad64c8cdb13fea33a877b3d8db0274264e6f3242cd2cff3f207a6111
7
- data.tar.gz: 6742b37bb795d34aeadc8fd765bc76976cafcf0e5c1b24873dc5720d1631b07cca1391c3914774acb4b8026514830ea13dcd9bcb7a35d2cb762042fc712898b3
6
+ metadata.gz: 24b33c4a55324d01e8a37321e7a19e94ff7a4f275f0960f16fda3d63691a2fba5ee8c51f6da1a3ea4eeea2c03457e9eae7470da1e48267f3ee102711d73d882a
7
+ data.tar.gz: 127f9594d9409b4b09cd7c20517d7f55e2368655f06ce713de238e59af2247ede9dd0b07ae627e5876e2581e47814724693c1f1cf799735005b049a0182848bf
@@ -1 +1 @@
1
- 2.1.3
1
+ 2.2.3
@@ -0,0 +1,28 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all
4
+ people who contribute through reporting issues, posting feature requests,
5
+ updating documentation, submitting pull requests or patches, and other
6
+ activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, age, or religion.
12
+
13
+ Examples of unacceptable behavior by participants include the use of sexual
14
+ language or imagery, derogatory comments or personal attacks, trolling, public
15
+ or private harassment, insults, or other unprofessional conduct.
16
+
17
+ Project maintainers have the right and responsibility to remove, edit, or
18
+ reject comments, commits, code, wiki edits, issues, and other contributions
19
+ that are not aligned to this Code of Conduct. Project maintainers who do not
20
+ follow the Code of Conduct may be removed from the project team.
21
+
22
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
23
+ reported by opening an issue or contacting one or more of the project
24
+ maintainers.
25
+
26
+ This Code of Conduct is adapted from the [Contributor
27
+ Covenant](http:contributor-covenant.org), version 1.0.0, available at
28
+ [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
@@ -1,15 +1,38 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sequel_mapper (0.0.1)
4
+ sequel_mapper (0.0.3)
5
+ activesupport (~> 4.0)
6
+ fetchable (~> 1.0)
5
7
  sequel (~> 4.16)
6
8
 
7
9
  GEM
8
10
  remote: https://rubygems.org/
9
11
  specs:
12
+ activesupport (4.2.4)
13
+ i18n (~> 0.7)
14
+ json (~> 1.7, >= 1.7.7)
15
+ minitest (~> 5.1)
16
+ thread_safe (~> 0.3, >= 0.3.4)
17
+ tzinfo (~> 1.1)
18
+ builder (3.2.2)
10
19
  coderay (1.1.0)
20
+ cucumber (1.3.20)
21
+ builder (>= 2.1.2)
22
+ diff-lcs (>= 1.1.3)
23
+ gherkin (~> 2.12)
24
+ multi_json (>= 1.7.5, < 2.0)
25
+ multi_test (>= 0.1.2)
11
26
  diff-lcs (1.2.5)
27
+ fetchable (1.0.0)
28
+ gherkin (2.12.2)
29
+ multi_json (~> 1.3)
30
+ i18n (0.7.0)
31
+ json (1.8.3)
12
32
  method_source (0.8.2)
33
+ minitest (5.8.3)
34
+ multi_json (1.11.1)
35
+ multi_test (0.1.2)
13
36
  pg (0.17.1)
14
37
  pry (0.10.1)
15
38
  coderay (~> 1.1.0)
@@ -28,16 +51,23 @@ GEM
28
51
  rspec-mocks (3.1.3)
29
52
  rspec-support (~> 3.1.0)
30
53
  rspec-support (3.1.2)
31
- sequel (4.16.0)
54
+ sequel (4.26.0)
32
55
  slop (3.6.0)
56
+ thread_safe (0.3.5)
57
+ tzinfo (1.2.2)
58
+ thread_safe (~> 0.1)
33
59
 
34
60
  PLATFORMS
35
61
  ruby
36
62
 
37
63
  DEPENDENCIES
38
64
  bundler (~> 1.7)
65
+ cucumber
39
66
  pg (~> 0.17.1)
40
67
  pry (~> 0.10.1)
41
68
  rake (~> 10.0)
42
69
  rspec (~> 3.1)
43
70
  sequel_mapper!
71
+
72
+ BUNDLED WITH
73
+ 1.10.6
@@ -0,0 +1,64 @@
1
+ # Missing features
2
+
3
+ The following features not included in SequelMapper are omitted purposefully to
4
+ keep the library simple and encourage good practices in application code.
5
+
6
+ Please open an issue if you feel like any of these features are essential or if
7
+ you think you can contribute to a solution please open an issue to discuss.
8
+
9
+ ## Coercion
10
+
11
+ Database supported types will be returned as expected, `Fixnum`, `DateTime`, `nil` etc.
12
+ Should you wish to enhance this data, every row is passed into the mapping's
13
+ factory function where you have the opportunity to do arbitrary transformations
14
+ before instantiating the domain object.
15
+
16
+ \*see note on transforming row data
17
+
18
+ ## Validation
19
+
20
+ This is the concern of your domain model and/or application boundaries.
21
+ SequelMapper allows you to persist any object you wish assuming schema
22
+ compatibility.
23
+
24
+ ## Database column name aliasing
25
+
26
+ While at first glance this is a simple feature, the abstraction starts to leak
27
+ when the using the query interface and guaranteeing all queries are substituted
28
+ perfectly is beyond the scope of the current version.
29
+
30
+ Should you wish to simply pass a column's key with a different parameter name
31
+ then you can again lean on the factory function to transform the row's data
32
+ before the domain object receives it.
33
+
34
+ \*see note on transforming row data
35
+
36
+ ## Cascade deletion
37
+
38
+ This is chiefly a data concern and is handled by a good database more
39
+ efficiently and effectively than any ORM could hope.
40
+
41
+ ## Database generated IDs and timestamps
42
+
43
+ While database generated values may work, available only after an object is
44
+ retrieved, they are not currently supported.
45
+
46
+ Data important to your domain should be generated in your application layer.
47
+ UUIDs make much more flexible identifiers for domain objects and further enable
48
+ decoupling and fast tests.
49
+
50
+ Timestamps are useful and important to most applications however if they are
51
+ used in your domain they should be pushed from explicitly from application
52
+ layer. You should again find this affords you more flexibility and decoupling.
53
+
54
+ There is absolutely nothing wrong with data added at time of persistence for
55
+ auditing purposes but SequelMapper will make you actively decide whether this
56
+ data should be available to the domain and what should be explicitly added.
57
+
58
+ \* Transforming row data
59
+
60
+ Adding a custom factory method to transform row data before passing it to the
61
+ domain layer is highly encouraged. However, ensure that for each custom factory
62
+ a serializer function is also supplied that SequelMapper can use to reverse the
63
+ operation for persistence.
64
+
data/README.md CHANGED
@@ -1,41 +1,62 @@
1
1
  # SequelMapper
2
2
 
3
- **Very new, much experimental, so incomplete**
3
+ ## TL;DR
4
4
 
5
- ## What it is
5
+ * A Ruby ORM that enables DDD and clean architectural styles.
6
+ * Persists plain objects while supporting arbitrarily deeply nested / circular associations
7
+ * Provides excellent database and query building support courtesy of [Sequel library](https://github.com/jeremyevans/sequel)
6
8
 
7
- SequelMapper is a data mapper that pulls rows out of your database and maps
8
- them into a graph of plain Ruby objects. The graph can then be modifed and
9
- persisted back into the database as a whole.
9
+ SequelMapper (working title) is a new, currently experimental [data mapper](http://martinfowler.com/eaaCatalog/dataMapper.html) ORM implementation for Ruby.
10
10
 
11
- The main feature is that it fully supports all the kinds of data associations
12
- that you are used to with ActiveRecord but for your POROs.
11
+ The aim is to provide a convenient way to query and persist graphs of Ruby objects (think models with associations), while keeping those object completely isolated and decoupled from the database.
13
12
 
14
- It is built on top of Jeremy Evans' Sequel library.
13
+ In contrast to Ruby's many [active record](http://martinfowler.com/eaaCatalog/activeRecord.html) implementations, domain objects require no special inherited or mixed in behavior in order to be persisted.
15
14
 
16
- ## Why is it?
15
+ ## Features
17
16
 
18
- * It seems like ROM may not be finished any time soon and I felt I could put
19
- together something functional albeit less ambitious
20
- * I love the Sequel library
21
- * I love decoupling persistence
22
- * Writing a complex datamapper is sure way to stall your project so I'm writing
23
- one for you
24
- * I am a sick person who enjoys this sort of thing
17
+ * Associations (belongs_to, has_many, has_many_through)
18
+ * Automatic 'convention over configuration' that is fully customizable
19
+ * Lazy loading for database read efficiency
20
+ * Dirty tracking for database write efficiency
21
+ * Predefined queries, scopes or subsets
22
+ * Eager loading to avoid the `n + 1` query problem
25
23
 
26
- So go on, persist those POROs, they don't even have to know about it.
24
+ There are some [conspicuous missing features](https://github.com/bestie/sequel_mapper/blob/master/MissingFeatures.md)
25
+ that you may want to read more about. If you want to contribute to solving any
26
+ of the problems listed please open an issue to discuss.
27
27
 
28
- ## Example
28
+ SequelMapper does not reinvent the wheel with querying abstraction and
29
+ migrations, instead these responsibilities are delegated to Sequel such that
30
+ its full power can be utilised.
31
+
32
+ For [querying](http://sequel.jeremyevans.net/rdoc/files/doc/querying_rdoc.html),
33
+ [migrations](http://sequel.jeremyevans.net/rdoc/files/doc/migration_rdoc.html)
34
+ and creating your [database connection](http://sequel.jeremyevans.net/rdoc/files/doc/opening_databases_rdoc.html)
35
+ see the Sequel documentation.
36
+
37
+ ## Getting started
38
+
39
+ Please try this out, experiment, open issues and pull requests. Please read the
40
+ code of conduct first.
29
41
 
30
42
  ```ruby
31
- # Let's say you have some domain objects
43
+
44
+ # 1. Define some domain objects, structs will surfice for the example
32
45
 
33
46
  User = Struct.new(:id, :first_name, :last_name, :email, :posts)
34
- Post = Struct.new(:id, :author, :subject, :body, :comments, :categories)
35
- Comment = Struct.new(:id, :post, :commenter, :body)
47
+ Post = Struct.new(:id, :author, :subject, :body, :created_at, :categories)
36
48
  Category = Struct.new(:id, :name, :posts)
37
49
 
38
- # And a relational database with some tables that look similar
50
+ ## Also assume that a conventional database schema (think Rails) is in place,
51
+ ## a column for each of the struct's attributes will be present. The posts
52
+ ## table will have `author_id` as a foreign key to the users table. There is
53
+ ## a join table named `categories_to_posts` which facilitates the many to
54
+ ## many relationship.
55
+
56
+ # 2. Configure a Sequel database connection
57
+
58
+ ## Sequel Mapper does not manage your connection for you.
59
+ ## Example assumes Postgres however Sequel supports many other databases.
39
60
 
40
61
  DB = Sequel.postgres(
41
62
  host: ENV.fetch("PGHOST"),
@@ -43,70 +64,118 @@ So go on, persist those POROs, they don't even have to know about it.
43
64
  database: ENV.fetch("PGDATABASE"),
44
65
  )
45
66
 
46
- user_mapper = SequelMapper::Graph.new(
47
- top_level_namespace: :users,
67
+ # 3. Configure mappings and associations
68
+
69
+ ## This is kept separate from your domain models as knowledge of the schema
70
+ ## is required to wire them up.
71
+
72
+ USER_MAPPER_CONFIG = SequelMapper.config(DB)
73
+ .setup_mapping(:users) { |users|
74
+ users.has_many(:posts, foreign_key: :author_id)
75
+ }
76
+ .setup_mapping(:posts) { |posts|
77
+ posts.belongs_to(:author, mapping_name: :users)
78
+ posts.has_many_through(:categories)
79
+ }
80
+ .setup_mapping(:categories) { |categories|
81
+ categories.has_many_through(:posts)
82
+ }
83
+
84
+ # 4. Create a mapper by combining a connection and a configuration
85
+
86
+ USER_MAPPER = SequelMapper.mapper(
48
87
  datastore: DB,
49
- config: mapper_config, # Config omitted
88
+ config: USER_MAPPER_CONFIG,
89
+ name: :users,
50
90
  )
51
91
 
52
- # Then this may appeal to you
53
-
54
- user = user_mapper.where(id: 1).first
55
- # => [#<struct User
56
- # id=1,
57
- # first_name="Stephen",
58
- # last_name="Best",
59
- # email="bestie@gmail.com",
60
- # posts=#<SequelMapper::AssociationProxy:0x007ffbc3c7cb50 @assoc_enum=#<Enumerator::Lazy: ...>, @removed_nodes=[]>>]
61
-
62
- user.posts
63
- # => #<SequelMapper::AssociationProxy:0x007ffbc3c7cb50 @assoc_enum=#<Enumerator::Lazy: ...>, @removed_nodes=[]>
64
- # That's lazily evaluated try ...
65
-
66
- user.posts.to_a
67
- # => [#<struct Post
68
- # id=1,
69
- # author=
70
- # #<struct User
71
- # id=1,
72
- # first_name="Stephen",
73
- # last_name="Best",
74
- # email="bestie@gmail.com",
75
- # posts=#<SequelMapper::AssociationProxy:0x007ffbc3c7cb50 @assoc_enum=#<Enumerator::Lazy: ...>, @removed_nodes=[]>>,
76
- # subject="Object mapping",
77
- # body="It is often tricky",
78
- # comments=#<SequelMapper::AssociationProxy:0x007ffbc59377b8 @assoc_enum=#<Enumerator::Lazy: ...>, @removed_nodes=[]>,
79
- # categories=#<SequelMapper::AssociationProxy:0x007ffbc5936138 @assoc_enum=#<Enumerator::Lazy: ...>, @removed_nodes=[]>>,
80
- # #<struct Post
81
- # id=2,
82
- # author=
83
- # #<struct User
84
- # id=1,
85
- # first_name="Stephen",
86
- # last_name="Best",
87
- # email="bestie@gmail.com",
88
- # posts=#<SequelMapper::AssociationProxy:0x007ffbc3c7cb50 @assoc_enum=#<Enumerator::Lazy: ...>, @removed_nodes=[]>>,
89
- # subject="Object mapping part 2",
90
- # body="Lazy load all the things!",
91
- # comments=#<SequelMapper::AssociationProxy:0x007ffbc5935990 @assoc_enum=#<Enumerator::Lazy: ...>, @removed_nodes=[]>,
92
- # categories=#<SequelMapper::AssociationProxy:0x007ffbc592fe50 @assoc_enum=#<Enumerator::Lazy: ...>, @removed_nodes=[]>>]
93
-
94
- # And then access the comments and so on ...
92
+ ## You are not limted to one mapper configuration or one database connection.
93
+ ## To handle complex situations you may create several segregated mappings
94
+ ## for your separate aggregate roots, potentially utilising multiple
95
+ ## databases and different domain object classes/compositions.
96
+
97
+ # 5. Create some objects
98
+
99
+ user = User.new(
100
+ "2f0f791c-47cf-4a00-8676-e582075bcd65",
101
+ "Hansel",
102
+ "Trickett",
103
+ "hansel@tricketts.org",
104
+ [],
105
+ )
106
+
107
+ user.posts << Post.new(
108
+ "9b75fe2b-d694-4b90-9137-6201d426dda2",
109
+ user,
110
+ "Things that I like",
111
+ "I like fish and scratching",
112
+ Time.parse("2015-10-03 21:00:00 UTC"),
113
+ [],
114
+ )
115
+
116
+ # 6. Save them
117
+
118
+ USER_MAPPER.save(user)
119
+
120
+ ## Only the (aggregate) root object needs to be passed to the mapper.
121
+
122
+ # 7. Query
123
+
124
+ user = USER_MAPPER.where(id: "2f0f791c-47cf-4a00-8676-e582075bcd65").first
125
+
126
+ # => #<struct User
127
+ # id="2f0f791c-47cf-4a00-8676-e582075bcd65",
128
+ # first_name="Stephen",
129
+ # last_name="Best",
130
+ # email="bestie@gmail.com",
131
+ # posts=#<SequelMapper::CollectionMutabilityProxy:7ff57192d510 >,
132
+
133
+ ```
134
+
135
+ ## Running the tests
136
+
137
+ ### Set the following environment variables
138
+ * PGHOST
139
+ * PGUSER
140
+ * PGDATABASE
141
+
142
+ ### Create a test database
143
+
144
+ This will create a database named from the value of `PGDATABASE`
145
+
146
+ ```
147
+ $ bundle exec rake db:create
148
+ ```
149
+
150
+ ### Run all tests (RSpec and Cucumber)
151
+ ```
152
+ $ bundle exec rake
153
+ ```
154
+
155
+ ### Should anything go awry
156
+
157
+ Drop the test database and start fresh
158
+
159
+ ```
160
+ $ bundle exec rake db:drop
95
161
  ```
96
162
 
97
163
  ## Installation
98
164
 
99
- Add this line to your application's Gemfile:
165
+ This library is still pre 1.0 so please lock down your version and update with
166
+ care.
100
167
 
101
- ```ruby
102
- gem 'sequel_mapper'
168
+ Add the following to your `Gemfile`.
169
+
170
+ ```
171
+ gem "sequel_mapper", "0.0.3"
103
172
  ```
104
173
 
105
174
  And then execute:
106
175
 
107
176
  $ bundle
108
177
 
109
- Or install it yourself as:
178
+ Or install it manually:
110
179
 
111
180
  $ gem install sequel_mapper
112
181
 
data/Rakefile CHANGED
@@ -1,2 +1,31 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
+ require 'rspec/core/rake_task'
4
+ require 'cucumber/rake/task'
5
+
6
+ RSpec::Core::RakeTask.new
7
+ Cucumber::Rake::Task.new
8
+
9
+ task :default => [
10
+ :spec,
11
+ :cucumber,
12
+ ]
13
+
14
+ require_relative "spec/support/sequel_test_support"
15
+ require_relative "spec/support/blog_schema"
16
+
17
+ namespace :db do
18
+ include SequelMapper::SequelTestSupport
19
+
20
+ task :setup => [:create] do
21
+ create_tables(BLOG_SCHEMA)
22
+ end
23
+
24
+ task :create do
25
+ create_database
26
+ end
27
+
28
+ task :drop do
29
+ drop_database
30
+ end
31
+ end