db_fuel 1.0.0.pre.alpha → 1.2.0.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c90c249149cb9a69ba04ba4fbd9932ced38651dd67fa52710f1f2baf55b965e0
4
- data.tar.gz: 2cd95f53e9e16b90aa94aefa36ebe17c3f4ebcd9db308aa2d504327823394f62
3
+ metadata.gz: b4f5691edb9519be2c43b787f9eeee14d2e2e83fcf9071e21dbef2442449d3fa
4
+ data.tar.gz: a95cc6d63d3eba9256c022891328352662b64cf8e0391a92962609f6d3a8062c
5
5
  SHA512:
6
- metadata.gz: 02b7fa4938884bb81987105fa6be014490a7cbf2c01d58679d9185acae8ded68998b42f3bab854dbdeb9b8b565b9e9b596ad37ce91b0852e702e8ce46d98626d
7
- data.tar.gz: ea64e9426e672b57f399d82e0fab173fdcf20319febbfcb6dcee9722d6cf7c645af3bc051d048a227b434b29294b19d2cd0876be9d06c50d0d357506bfc0544d
6
+ metadata.gz: 36c2477f3010bd60a7ef7a49f60f7a5302d2cec2ad8be034d83e18923eed07820578a87993a9ebc07e1121c8853d45e5060eaca4d4895222afb3b69b8a8b61f9
7
+ data.tar.gz: 54f65f7f0d56271bacb6b67512f10135b4d22ddb64dd0a7d1fc864e6d2cd29a0d7e4579056f518cf517b5b3353715bafc489743d596cc8bd8e3e9a0812d6755b
@@ -1,6 +1,7 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 2.5
3
3
  NewCops: enable
4
+ SuggestExtensions: false
4
5
 
5
6
  Layout/LineLength:
6
7
  Max: 100
@@ -8,7 +9,7 @@ Layout/LineLength:
8
9
  - db_fuel.gemspec
9
10
 
10
11
  Metrics/BlockLength:
11
- ExcludedMethods:
12
+ IgnoredMethods:
12
13
  - let
13
14
  - it
14
15
  - describe
@@ -0,0 +1 @@
1
+ ruby 2.6.6
@@ -1,6 +1,17 @@
1
- # 1.0.0 (TBD)
1
+ # 1.1.0 (Decmeber 1st, 2020)
2
2
 
3
- Initial implementation.
3
+ New Jobs:
4
+
5
+ * db_fuel/active_record/find_or_insert
6
+ * db_fuel/active_record/insert
7
+ * db_fuel/active_record/update
8
+
9
+ # 1.0.0 (November 18th, 2020)
10
+
11
+ Initial implementation. Includes jobs:
12
+
13
+ * db_fuel/dbee/query
14
+ * db_fuel/dbee/range
4
15
 
5
16
  # 0.0.1
6
17
 
data/README.md CHANGED
@@ -1,5 +1,424 @@
1
- # Db Fuel
1
+ # DB Fuel
2
2
 
3
- ---
3
+ [![Gem Version](https://badge.fury.io/rb/db_fuel.svg)](https://badge.fury.io/rb/db_fuel) [![Build Status](https://travis-ci.org/bluemarblepayroll/db_fuel.svg?branch=master)](https://travis-ci.org/bluemarblepayroll/db_fuel) [![Maintainability](https://api.codeclimate.com/v1/badges/21945483950d9c35fabb/maintainability)](https://codeclimate.com/github/bluemarblepayroll/db_fuel/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/21945483950d9c35fabb/test_coverage)](https://codeclimate.com/github/bluemarblepayroll/db_fuel/test_coverage) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
 
5
- Under construction.
5
+ This library is a plugin for [Burner](https://github.com/bluemarblepayroll/burner). Burner, by itself, cannot use a database. So, if you wish to use a database as a data source or as a target for mutation then you need to add a library similar to this.
6
+
7
+ ## Installation
8
+
9
+ To install through Rubygems:
10
+
11
+ ````bash
12
+ gem install db_fuel
13
+ ````
14
+
15
+ You can also add this to your Gemfile:
16
+
17
+ ````bash
18
+ bundle add db_fuel
19
+ ````
20
+
21
+ ## Jobs
22
+
23
+ Refer to the [Burner](https://github.com/bluemarblepayroll/burner) library for more specific information on how Burner works. This section will just focus on what this library directly adds.
24
+
25
+ ### ActiveRecord Jobs
26
+
27
+ * **db_fuel/active_record/find_or_insert** [name, table_name, attributes, debug, primary_key, register, separator, timestamps, unique_attributes]: An extension of the `db_fuel/active_record/insert` job that adds an existence check before SQL insertion. The `unique_attributes` will be converted to WHERE clauses for performing the existence check.
28
+ * **db_fuel/active_record/insert** [name, table_name, attributes, debug, primary_key, register, separator, timestamps]: This job can take the objects in a register and insert them into a database table. If primary_key is specified then its key will be set to the primary key. Note that composite primary keys are not supported. Attributes defines which object properties to convert to SQL. Refer to the class and constructor specification for more detail.
29
+ * **db_fuel/active_record/update_all** [name, table_name, attributes, debug, register, separator, timestamps, unique_attributes]: This job can take the objects in a register and updates them within a database table. Attributes defines which object properties to convert to SQL SET clauses while unique_attributes translate to WHERE clauses. One or more records may be updated at a time. Refer to the class and constructor specification for more detail.
30
+ * **db_fuel/active_record/update** [name, table_name, attributes, debug, register, primary_key, separator, timestamps, unique_attributes]: This job can take the unique objects in a register and updates them within a database table. Attributes defines which object properties to convert to SQL SET clauses while unique_attributes translate to WHERE clauses to find the records to update. The primary_key is used to update the unique record. Only one record will be updated per statement. Refer to the class and constructor specification for more detail.
31
+ * **db_fuel/active_record/upsert** [name, table_name, attributes, debug, primary_key, register, separator, timestamps, unique_attributes]: This job can take the objects in a register and either inserts or updates them within a database table. Attributes defines which object properties to convert to SQL SET clauses while each key in unique_attributes become a WHERE clause in order to check for the existence of a specific record. The updated record will use the primary_key specified to perform the UPDATE operation. Note that composite primary keys are not supported. Refer to the class and constructor specification for more detail.
32
+
33
+ ### Dbee Jobs
34
+
35
+ * **db_fuel/dbee/query** [model, query, register]: Pass in a [Dbee](https://github.com/bluemarblepayroll/dbee) model and query and store the results in the specified register. Refer to the [Dbee](https://github.com/bluemarblepayroll/dbee) library directly on how to craft a model or query.
36
+ * **db_fuel/dbee/range** [key, key_path, model, query, register, separator]: Similar to `db_fuel/dbee/query` with the addition of being able to grab a list of values from the register to use as a Dbee EQUALS/IN filter. This helps to dynamically limit the resulting record set. The key is used to specify where to grab the list of values, while the key_path will be used to craft the [Dbee equal's filter](https://github.com/bluemarblepayroll/dbee/blob/master/lib/dbee/query/filters/equals.rb). Separator is exposed in case nested object support is necessary.
37
+
38
+ ## Examples
39
+
40
+ In all the examples we will assume we have the following schema:
41
+
42
+ ````ruby
43
+ ActiveRecord::Schema.define do
44
+ create_table :statuses do |t|
45
+ t.string :code, null: false, limit: 25
46
+ t.integer :priority, null: false, default: 0
47
+ t.timestamps
48
+ end
49
+
50
+ create_table :patients do |t|
51
+ t.string :chart_number
52
+ t.string :first_name
53
+ t.string :middle_name
54
+ t.string :last_name
55
+ t.references :status
56
+ t.timestamps
57
+ end
58
+ end
59
+ ````
60
+
61
+ ### Querying the Database
62
+
63
+ The `db_fuel/dbee/query` job can be utilized to process a SQL query and store the results in a Burner::Payload register.
64
+
65
+ Let's say for example we have a list of patients we would like to retrieve:
66
+
67
+ ````ruby
68
+ pipeline = {
69
+ jobs: [
70
+ {
71
+ name: 'retrieve_patients',
72
+ type: 'db_fuel/dbee/query',
73
+ model: {
74
+ name: :patients
75
+ },
76
+ query: {
77
+ fields: [
78
+ { key_path: :id },
79
+ { key_path: :first_name }
80
+ ],
81
+ sorters: [
82
+ { key_path: :first_name }
83
+ ]
84
+ },
85
+ register: :patients
86
+ }
87
+ ]
88
+ }
89
+
90
+ payload = Burner::Payload.new
91
+
92
+ Burner::Pipeline.make(pipeline).execute(payload: payload)
93
+ ````
94
+
95
+ If we were to inspect the contents of `payload` we should see the patient's result set loaded:
96
+
97
+ ````ruby
98
+ payload['patients'] # array in form of: [ { "id" => 1, "first_name" => "Something" }, ... ]
99
+ ````
100
+
101
+ ### Limiting Result Sets
102
+
103
+ The `db_fuel/dbee/query` does not provide a way to dynamically connect the query to existing data. You are free to put any Dbee query filters in the query declaration, but what if you would like to further limit this based on the knowledge of a range of values? The `db_fuel/dbee/range` job is meant to do exactly this. On the surface it is mainly an extension of the `db_fuel/dbee/query` job.
104
+
105
+ Let's say we would like to query patients but we want to limit it to an inputted list of first names:
106
+
107
+ ````ruby
108
+ pipeline = {
109
+ jobs: [
110
+ {
111
+ name: :load_first_names,
112
+ type: 'b/value/static',
113
+ register: :patients,
114
+ value: [
115
+ { fname: 'Bozo' },
116
+ { fname: 'Bugs' },
117
+ ]
118
+ },
119
+ {
120
+ name: 'retrieve_patients',
121
+ type: 'db_fuel/dbee/range',
122
+ model: {
123
+ name: :patients
124
+ },
125
+ query: {
126
+ fields: [
127
+ { key_path: :id },
128
+ { key_path: :first_name }
129
+ ],
130
+ sorters: [
131
+ { key_path: :first_name }
132
+ ]
133
+ },
134
+ register: :patients,
135
+ key: :fname,
136
+ key_path: :first_name
137
+ }
138
+ ]
139
+ }
140
+
141
+ payload = Burner::Payload.new
142
+
143
+ Burner::Pipeline.make(pipeline).execute(payload: payload)
144
+ ````
145
+
146
+ If we were to inspect the contents of `payload` we should see the patient's result set loaded:
147
+
148
+ ````ruby
149
+ payload['patients'] # array in form of: [ { "id" => 1, "first_name" => "Something" }, ... ]
150
+ ````
151
+
152
+ The only difference between the query and range jobs should be the latter is limited based on the incoming first names.
153
+
154
+ ### Updating the Database
155
+
156
+ #### Inserting Records
157
+
158
+ We can deal with persistence using the db_fuel/active_record/* jobs. In order to insert new records we can use the `db_fuel/active_record/insert` job. For example:
159
+
160
+ ````ruby
161
+ pipeline = {
162
+ jobs: [
163
+ {
164
+ name: :load_patients,
165
+ type: 'b/value/static',
166
+ register: :patients,
167
+ value: [
168
+ { chart_number: 'B0001', first_name: 'Bugs', last_name: 'Bunny' },
169
+ { chart_number: 'B0002', first_name: 'Babs', last_name: 'Bunny' }
170
+ ]
171
+ },
172
+ {
173
+ name: 'insert_patients',
174
+ type: 'db_fuel/active_record/insert',
175
+ register: :patients,
176
+ attributes: [
177
+ { key: :chart_number },
178
+ { key: :first_name },
179
+ { key: :last_name }
180
+ ],
181
+ table_name: 'patients',
182
+ primary_key: {
183
+ key: :id
184
+ }
185
+ }
186
+ ]
187
+ }
188
+
189
+ payload = Burner::Payload.new
190
+
191
+ Burner::Pipeline.make(pipeline).execute(payload: payload)
192
+ ````
193
+
194
+ There should now be two new patients, AB0 and AB1, present in the table `patients`.
195
+
196
+ Notes:
197
+
198
+ * Since we specified the `primary_key`, the records' `id` attributes should be set to their respective primary key values.
199
+ * Composite primary keys are not currently supported.
200
+ * Set `debug: true` to print out each INSERT statement in the output (not for production use.)
201
+
202
+ #### Inserting Only New Records
203
+
204
+ Another job `db_fuel/active_record/find_or_insert` allows for an existence check to performed each insertion. If a record is found then it will not insert the record. If `primary_key` is set then the existence check will also still set the primary key on the payload's respective object. Note that composite primary keys are not currently supported. We can build on the above insert example for only inserting new patients if their chart_number is unique:
205
+
206
+ ````ruby
207
+ pipeline = {
208
+ jobs: [
209
+ {
210
+ name: :load_patients,
211
+ type: 'b/value/static',
212
+ register: :patients,
213
+ value: [
214
+ { chart_number: 'B0001', first_name: 'Bugs', last_name: 'Bunny' },
215
+ { chart_number: 'B0002', first_name: 'Babs', last_name: 'Bunny' }
216
+ ]
217
+ },
218
+ {
219
+ name: 'insert_patients',
220
+ type: 'db_fuel/active_record/insert',
221
+ register: :patients,
222
+ attributes: [
223
+ { key: :chart_number },
224
+ { key: :first_name },
225
+ { key: :last_name }
226
+ ],
227
+ table_name: 'patients',
228
+ primary_key: {
229
+ key: :id
230
+ },
231
+ unique_attributes: [
232
+ { key: :chart_number }
233
+ ]
234
+ }
235
+ ]
236
+ }
237
+
238
+ payload = Burner::Payload.new
239
+
240
+ Burner::Pipeline.make(pipeline).execute(payload: payload)
241
+ ````
242
+
243
+ Now only records where the chart_number does not match an existing record will be inserted.
244
+
245
+ #### Updating Records
246
+
247
+ Let's say we now want to update these unique records' last names:
248
+
249
+ ````ruby
250
+ pipeline = {
251
+ jobs: [
252
+ {
253
+ name: :load_patients,
254
+ type: 'b/value/static',
255
+ register: :patients,
256
+ value: [
257
+ { chart_number: 'B0001', last_name: 'Fox' },
258
+ { chart_number: 'B0002', last_name: 'Smurf' }
259
+ ]
260
+ },
261
+ {
262
+ name: 'update_patients',
263
+ type: 'db_fuel/active_record/update',
264
+ register: :patients,
265
+ attributes: [
266
+ { key: :last_name }
267
+ ],
268
+ table_name: 'patients',
269
+ primary_key: {
270
+ key: :id
271
+ },
272
+ unique_attributes: [
273
+ { key: :chart_number }
274
+ ]
275
+ }
276
+ ]
277
+ }
278
+
279
+ payload = Burner::Payload.new
280
+
281
+ Burner::Pipeline.make(pipeline).execute(payload: payload)
282
+ ````
283
+
284
+ Each database record should have been updated with their new respective last names based on the primary key specified.
285
+
286
+ #### Updating All Records
287
+
288
+ Let's say we want to update those records' midddle names:
289
+
290
+ ````ruby
291
+ pipeline = {
292
+ jobs: [
293
+ {
294
+ name: :load_patients,
295
+ type: 'b/value/static',
296
+ register: :patients,
297
+ value: [
298
+ { chart_number: 'B0001', middle_name: 'Rabbit' },
299
+ { chart_number: 'C0001', middle_name: 'Elf' }
300
+ ]
301
+ },
302
+ {
303
+ name: 'update_patients',
304
+ type: 'db_fuel/active_record/update_all',
305
+ register: :patients,
306
+ attributes: [
307
+ { key: :last_name }
308
+ ],
309
+ table_name: 'patients',
310
+ unique_attributes: [
311
+ { key: :chart_number }
312
+ ]
313
+ }
314
+ ]
315
+ }
316
+
317
+ payload = Burner::Payload.new
318
+
319
+ Burner::Pipeline.make(pipeline).execute(payload: payload)
320
+ ````
321
+
322
+ Each database record should have been updated with their new respective middle names based on chart_number.
323
+
324
+ #### Upserting Records
325
+
326
+ Let's say we don't know if these chart_number values already exist or not.
327
+ So we want db_fuel to either insert a record if the chart_number doesn't exist or update the record if the chart_number already exists.
328
+
329
+ ````ruby
330
+ pipeline = {
331
+ jobs: [
332
+ {
333
+ name: :load_patients,
334
+ type: 'b/value/static',
335
+ register: :patients,
336
+ value: [
337
+ { chart_number: 'B0002', first_name: 'Babs', last_name: 'Bunny' },
338
+ { chart_number: 'B0003', first_name: 'Daffy', last_name: 'Duck' }
339
+ ]
340
+ },
341
+ {
342
+ name: 'update_patients',
343
+ type: 'db_fuel/active_record/upsert',
344
+ register: :patients,
345
+ attributes: [
346
+ { key: :chart_number },
347
+ { key: :first_name },
348
+ { key: :last_name }
349
+ ],
350
+ table_name: 'patients',
351
+ primary_key: {
352
+ key: :id
353
+ },
354
+ unique_attributes: [
355
+ { key: :chart_number }
356
+ ]
357
+ }
358
+ ]
359
+ }
360
+
361
+ payload = Burner::Payload.new
362
+
363
+ Burner::Pipeline.make(pipeline).execute(payload: payload)
364
+ ````
365
+
366
+ Each database record should have been either inserted or updated with their corresponding values. In this case Babs' last name
367
+ was switched back to Bunny and a new record was created for Daffy Duck.
368
+
369
+ Notes:
370
+
371
+ * The `unique_attributes` translate to WHERE clauses.
372
+ * Set `debug: true` to print out each UPDATE statement in the output (not for production use.)
373
+ ## Contributing
374
+
375
+ ### Development Environment Configuration
376
+
377
+ Basic steps to take to get this repository compiling:
378
+
379
+ 1. Install [Ruby](https://www.ruby-lang.org/en/documentation/installation/) (check db_fuel.gemspec for versions supported)
380
+ 2. Install bundler (gem install bundler)
381
+ 3. Clone the repository (git clone git@github.com:bluemarblepayroll/db_fuel.git)
382
+ 4. Navigate to the root folder (cd db_fuel)
383
+ 5. Install dependencies (bundle)
384
+
385
+ ### Running Tests
386
+
387
+ To execute the test suite run:
388
+
389
+ ````bash
390
+ bundle exec rspec spec --format documentation
391
+ ````
392
+
393
+ Alternatively, you can have Guard watch for changes:
394
+
395
+ ````bash
396
+ bundle exec guard
397
+ ````
398
+
399
+ Also, do not forget to run Rubocop:
400
+
401
+ ````bash
402
+ bundle exec rubocop
403
+ ````
404
+
405
+ ### Publishing
406
+
407
+ Note: ensure you have proper authorization before trying to publish new versions.
408
+
409
+ After code changes have successfully gone through the Pull Request review process then the following steps should be followed for publishing new versions:
410
+
411
+ 1. Merge Pull Request into master
412
+ 2. Update `lib/db_fuel/version.rb` using [semantic versioning](https://semver.org/)
413
+ 3. Install dependencies: `bundle`
414
+ 4. Update `CHANGELOG.md` with release notes
415
+ 5. Commit & push master to remote and ensure CI builds master successfully
416
+ 6. Run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
417
+
418
+ ## Code of Conduct
419
+
420
+ Everyone interacting in this codebase, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/bluemarblepayroll/db_fuel/blob/master/CODE_OF_CONDUCT.md).
421
+
422
+ ## License
423
+
424
+ This project is MIT Licensed.