dynamic-records-meritfront 3.0.3 → 3.0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +31 -23
- data/lib/dynamic-records-meritfront/version.rb +1 -1
- data/lib/dynamic-records-meritfront.rb +36 -14
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0b267bcbccbdacef50a52ad1880100ee74e644224acc0a6602b89b3b61cf4b8
|
4
|
+
data.tar.gz: 6335a84f567063727283fc2e87420f1d1020564aa412b699fb9bc8f48f4a1bb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a130aa5128a8c25ed5f484035257f8d69ce5b3507bb6598bd9396a6396f1ff29fa0ff474e28a6ea92e3b22152060bea0857413e9c546c2472e41825258e8519
|
7
|
+
data.tar.gz: fb3cdfb3901573ba28a9b20240af8e0714b4440a7caf7c4d8abbaf024629faadd3fcb17ad126f392232cc681fd176de89ed045c4e90f5bf9da59a00ba89b96df
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dynamic-records-meritfront (3.0.
|
4
|
+
dynamic-records-meritfront (3.0.11)
|
5
5
|
hashid-rails
|
6
6
|
|
7
7
|
GEM
|
@@ -24,7 +24,7 @@ GEM
|
|
24
24
|
hashids (1.0.6)
|
25
25
|
i18n (1.12.0)
|
26
26
|
concurrent-ruby (~> 1.0)
|
27
|
-
minitest (5.
|
27
|
+
minitest (5.17.0)
|
28
28
|
rake (12.3.3)
|
29
29
|
tzinfo (2.0.5)
|
30
30
|
concurrent-ruby (~> 1.0)
|
data/README.md
CHANGED
@@ -45,16 +45,12 @@ Or install it yourself as:
|
|
45
45
|
|
46
46
|
## Usage
|
47
47
|
|
48
|
-
### Apply to your ApplicationRecord class as such
|
48
|
+
### Apply to your ApplicationRecord class as such (or whatever subclass of ActiveRecord::Base you have)
|
49
49
|
|
50
50
|
```ruby
|
51
51
|
class ApplicationRecord < ActiveRecord::Base
|
52
52
|
self.abstract_class = true
|
53
53
|
include DynamicRecordsMeritfront
|
54
|
-
|
55
|
-
#DYNAMIC_SQL_RAW determines whether dynamic_sql method returns a ActiveRecord::Response object or an Array.
|
56
|
-
#They both have pros and cons. False returns the array.
|
57
|
-
DynamicRecordsMeritfront::DYNAMIC_SQL_RAW = false
|
58
54
|
end
|
59
55
|
```
|
60
56
|
|
@@ -67,15 +63,11 @@ A better and safer way to write sql. Can return either a Hash, ActiveRecord::Res
|
|
67
63
|
|
68
64
|
```ruby
|
69
65
|
User.dynamic_sql('select * from users') #returns all users
|
70
|
-
ApplicationRecord.dynamic_sql('select
|
66
|
+
ApplicationRecord.dynamic_sql('select * from users') #returns all user column information in an array
|
71
67
|
```
|
72
68
|
|
73
69
|
with options:
|
74
70
|
- options not stated below: considered sql arguments, and will replace their ":option_name" with a sql argument. Always use sql arguments to avoid sql injection. Lists are converted into a format such as ```{1,2,3,4}```. Lists of lists are converted into ```(1,2,3), (4,5,6), (7,8,9)``` etc. So as to allow easy inserts/upserts.
|
75
|
-
- raw: whether to return a ActiveRecord::Response object or a hash when called on an abstract class (like ApplicationRecord). Default can be switched with DYNAMIC_SQL_RAW variable on the class level.
|
76
|
-
|
77
|
-
other less critical options:
|
78
|
-
|
79
71
|
- prepare: Defaults to true. Gets passed to ActiveRecord::Base.connection.exec_query as a parameter. Should change whether the command will be prepared, which means that on subsequent calls the command will be faster. Downsides are when, for example, the sql query has hard-coded arguments, the query always changes, causing technical issues as the number of prepared statements stack up.
|
80
72
|
- multi_query: allows more than one query (you can seperate an insert and an update with ';' I dont know how else to say it.)
|
81
73
|
this disables other options including sql_arguments. Not sure how it effects prepared statements. Not super useful.
|
@@ -149,27 +141,28 @@ Get users who match a list of ids. Uses a postgresql Array, see the potential is
|
|
149
141
|
Do an upsert
|
150
142
|
|
151
143
|
```ruby
|
144
|
+
time = DateTime.now
|
152
145
|
rows = uzrs.map{|u| [
|
153
146
|
u.id, #user_id
|
154
147
|
self.id, #conversation_id
|
155
148
|
from, #invited_by
|
156
|
-
|
157
|
-
|
149
|
+
:time, #created_at (We use symbols to denote other sql arguments)
|
150
|
+
:time, #updated_at
|
158
151
|
]}
|
159
152
|
ApplicationRecord.dynamic_sql("upsert_conversation_invites_2", %Q{
|
160
153
|
INSERT INTO conversation_participants (user_id, conversation_id, invited_by, created_at, updated_at)
|
161
154
|
VALUES :rows
|
162
155
|
ON CONFLICT (conversation_id,user_id)
|
163
156
|
DO UPDATE SET updated_at = :time
|
164
|
-
}, rows: rows, time:
|
157
|
+
}, rows: rows, time: time)
|
165
158
|
```
|
166
|
-
This will output sql similar to below. Note this can be done for multiple conversation_participants. Also note that
|
159
|
+
This will output sql similar to below. Note this can be done for multiple conversation_participants. Also note that we sent only one time variable during our request instead of duplicating it.
|
167
160
|
```sql
|
168
161
|
INSERT INTO conversation_participants (user_id, conversation_id, invited_by, created_at, updated_at)
|
169
162
|
VALUES ($1,$2,$3,$4,$4)
|
170
163
|
ON CONFLICT (conversation_id,user_id)
|
171
164
|
DO UPDATE SET updated_at = $4
|
172
|
-
-- [["rows_1", 15], ["rows_2", 67], ["rows_3", 6], [
|
165
|
+
-- [["rows_1", 15], ["rows_2", 67], ["rows_3", 6], [:time, "2022-10-13 20:49:27.441372"]]
|
173
166
|
```
|
174
167
|
</details>
|
175
168
|
|
@@ -244,10 +237,10 @@ obj.has_association?(:votes) #false
|
|
244
237
|
```
|
245
238
|
</details>
|
246
239
|
|
247
|
-
#### self.
|
240
|
+
#### self.instaload_sql( *optional* name, insta_array, opts = { })
|
248
241
|
*instaloads* a bunch of diffrent models at the same time by casting them to json before returning them. Kinda cool. Maybe a bit overcomplicated. Seems to be more efficient to preloading when i tested it.
|
249
242
|
- name is passed to dynamic_sql and is the name of the sql request
|
250
|
-
- opts are passed to dynamic_sql
|
243
|
+
- opts are passed to dynamic_sql
|
251
244
|
- requires a list of instaload method output which provides information for how to treat each sql block.
|
252
245
|
|
253
246
|
```ruby
|
@@ -264,7 +257,7 @@ out = ApplicationRecord.instaload_sql([
|
|
264
257
|
|
265
258
|
```ruby
|
266
259
|
# the ruby entered
|
267
|
-
output = ApplicationRecord.
|
260
|
+
output = ApplicationRecord.instaload_sql([
|
268
261
|
User.instaload('SELECT id FROM users WHERE users.id = ANY (:user_ids) AND users.created_at > :time', table_name: 'limited_users', relied_on: true),
|
269
262
|
User.instaload(%Q{
|
270
263
|
SELECT friends.smaller_user_id AS id, friends.bigger_user_id AS friended_to
|
@@ -323,7 +316,7 @@ the output:
|
|
323
316
|
</details>
|
324
317
|
|
325
318
|
#### self.instaload(sql, table_name: nil, relied_on: false, dont_return: false)
|
326
|
-
A method used to prepare data for the
|
319
|
+
A method used to prepare data for the instaload_sql method. It returns a hash of options.
|
327
320
|
- klass called on: if called on an abstract class (ApplicationRecord) it will return a list of hashes with the data. Otherwise returns a list of the classes records.
|
328
321
|
- table_name: sets the name of the temporary postgresql table. This can then be used in further instaload sql snippets.
|
329
322
|
- relied_on: will make it so other instaload sql snippets can reference this table (it makes it use posrgresql's WITH operator)
|
@@ -349,7 +342,7 @@ User.instaload('SELECT id FROM users WHERE users.id = ANY (:user_ids) AND users.
|
|
349
342
|
</details>
|
350
343
|
|
351
344
|
#### self.dynamic_attach(instaload_sql_output, base_name, attach_name, base_on: nil, attach_on: nil, one_to_one: false)
|
352
|
-
taking the output of the
|
345
|
+
taking the output of the instaload_sql method, this method creates relations between the models.
|
353
346
|
- base_name: the name of the table we will be attaching to
|
354
347
|
- attach_name: the name of the table that will be attached
|
355
348
|
- base_on: put a proc here to override the matching key for the base table. Default is, for a user and post type, {|user| user.id}
|
@@ -357,7 +350,7 @@ taking the output of the dynamic_instaload_sql, this method attaches the models
|
|
357
350
|
- one_to_one: switches between a one-to-one relationship or not
|
358
351
|
|
359
352
|
<details>
|
360
|
-
<summary> attach information for each limited_user in the
|
353
|
+
<summary> attach information for each limited_user in the instaload_sql example </summary>
|
361
354
|
|
362
355
|
```ruby
|
363
356
|
|
@@ -456,13 +449,28 @@ since things may be broken already, it seemed like a good time to do this.
|
|
456
449
|
- this also tells me that uniq'ing variables to decrease the number of them was a bad idea which could cause random failures.
|
457
450
|
- functionality improvements
|
458
451
|
- The biggest change is that names are now optional! name_modifiers is now depreciated functionality as it serves no useful purpose. Will leave in for compatibility but take out of documentation. Used to think the name was related to prepared statements. This will lead simpler ruby code.
|
459
|
-
- If name is left out, the name will be set to the location in your app which called the method. For example, when dynamic_sql was called from irb, the name was: "(irb):45:in `irb_binding'". This is done using stack trace functionality.
|
452
|
+
- If name is left out, the name will be set to the location in your app which called the method. For example, when dynamic_sql was called from irb, the name was: "(irb):45:in `irb_binding'". This is done using stack trace functionality. In another case the name was "app/models/report.rb:364:in `refresh_db_methods'"
|
460
453
|
- dynamic_instaload_sql is now just instaload_sql. dynamic_instaload_sql has been aliased.
|
461
454
|
- Name is optional on instaload_sql aswell
|
462
455
|
- MultiAttributeArrays (array's of arrays) which can be passed into dynamic_sql largely for inserts/upserts will now treat symbols as an attribute name. This leads to more consise sql without running into above error.
|
463
456
|
- When dynamic_sql errors out, it now posts some helpful information to the log.
|
464
457
|
- Added a test script. No experience testing, so its just a method you pass a model, and then it does a rollback to reverse any changes.
|
465
|
-
|
458
|
+
|
459
|
+
v3.0.6
|
460
|
+
- Further simplifications of the library. After looking further into ActiveRecord::Response objects I realized that they respond to .map .first [3] and other Array methods. In addition to this they have the .rows and .cols methods. Feel like I should of caught this earlier, but anyway, functionaly i will be setting DYNAMIC_SQL_RAW to true by default. docs-wise I am removing any reference to the raw option and DYNAMIC_SQL_RAW. This is mainly as ActiveRecord::Response acts as an Array with more functionality.
|
461
|
+
|
462
|
+
<<<<<<< HEAD
|
463
|
+
3.0.11
|
464
|
+
- error fix to do with multi row expressions and sql variables. No breaking changes.
|
465
|
+
|
466
|
+
## Questions
|
467
|
+
- Q: does the name of a sql operation have anything to do with prepared statements?
|
468
|
+
- A: no, the prepared statement determines uniqueness in some other way, dont worry about collisions. The only issue with prepared statements that I can determine is when you write a statement where things change every time, thus preparing potentially infinite prepared statements. This can be alleviated by using sql arguments correctly. Using arguments correctly also will stop sql injection attacks so. You know. Do it properly. Dont just hard code them into the query.
|
469
|
+
- Q: The default name of my sql statements looks like a stack trace? Whats going on?
|
470
|
+
- A: We set the location of where you called the function as the default name for easy debugging. Its not an error, we just take some info from the stacktrace. It also includes the method name which can provide some insite into what the query is doing. Makes logs alot nicer to look at.
|
471
|
+
- Q: Whats MeritFront?
|
472
|
+
- A: I am making a social media platform
|
473
|
+
|
466
474
|
## Contributing
|
467
475
|
|
468
476
|
Bug reports and pull requests are welcome on GitHub at https://github.com/LukeClancy/dynamic-records-meritfront. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/LukeClancy/dynamic-records-meritfront/blob/master/CODE_OF_CONDUCT.md).
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require "dynamic-records-meritfront/version"
|
2
2
|
require 'hashid/rails'
|
3
3
|
|
4
|
+
#this file contains multiple classes which should honestly be split up
|
5
|
+
|
4
6
|
module DynamicRecordsMeritfront
|
5
7
|
extend ActiveSupport::Concern
|
6
8
|
|
@@ -17,7 +19,7 @@ module DynamicRecordsMeritfront
|
|
17
19
|
#should work, probably able to override by redefining in ApplicationRecord class.
|
18
20
|
#Note we defined here as it breaks early on as Rails.application returns nil
|
19
21
|
PROJECT_NAME = Rails.application.class.to_s.split("::").first.to_s.downcase
|
20
|
-
DYNAMIC_SQL_RAW =
|
22
|
+
DYNAMIC_SQL_RAW = true
|
21
23
|
end
|
22
24
|
class DynamicSqlVariables
|
23
25
|
attr_accessor :sql_hash
|
@@ -27,11 +29,17 @@ module DynamicRecordsMeritfront
|
|
27
29
|
self.params = params
|
28
30
|
end
|
29
31
|
|
32
|
+
def key_index(key)
|
33
|
+
k = sql_hash.keys.index(key)
|
34
|
+
k += 1 unless k.nil?
|
35
|
+
k
|
36
|
+
end
|
37
|
+
|
30
38
|
def add_key_value(key, value = nil)
|
31
39
|
value = params[key] if value.nil?
|
32
40
|
#tracks the variable and returns the keys sql variable number
|
33
41
|
sql_hash[key] ||= convert_to_query_attribute(key, value)
|
34
|
-
return
|
42
|
+
return key_index(key)
|
35
43
|
end
|
36
44
|
|
37
45
|
def next_sql_num
|
@@ -392,18 +400,27 @@ module DynamicRecordsMeritfront
|
|
392
400
|
#replace MultiRowExpressions
|
393
401
|
v = params[key]
|
394
402
|
#check if it looks like one
|
395
|
-
|
396
|
-
if v.class == MultiRowExpression or
|
403
|
+
looks_like_multi_row_expression = ((v.class == Array) and (not v.first.nil?) and (v.first.class == Array))
|
404
|
+
if v.class == MultiRowExpression or looks_like_multi_row_expression
|
397
405
|
#we need to substitute with the correct sql now.
|
398
|
-
v = MultiRowExpression.new(v) if
|
406
|
+
v = MultiRowExpression.new(v) if looks_like_multi_row_expression #standardize
|
399
407
|
#process into appropriate sql while keeping track of variables
|
400
408
|
sql_for_replace = v.for_query(key, var_track)
|
401
409
|
#replace the key with the sql
|
402
410
|
sql.gsub!(":#{key}", sql_for_replace)
|
403
411
|
else
|
404
|
-
|
405
|
-
|
406
|
-
|
412
|
+
#check if its currently in the sql argument list
|
413
|
+
x = var_track.key_index(key)
|
414
|
+
if x.nil?
|
415
|
+
#if not, get the next number that it will be assigned and replace the key w/ that number.
|
416
|
+
x = var_track.next_sql_num
|
417
|
+
if sql.gsub!(":#{key}", "$#{x}")
|
418
|
+
#only actually add to sql arguments when we know the attribute was used.
|
419
|
+
var_track.add_key_value(key, v)
|
420
|
+
end
|
421
|
+
else
|
422
|
+
#its already in use as a sql argument and has a number, use that number.
|
423
|
+
sql.gsub!(":#{key}", "$#{x}")
|
407
424
|
end
|
408
425
|
end
|
409
426
|
end
|
@@ -437,12 +454,6 @@ module DynamicRecordsMeritfront
|
|
437
454
|
#no I am not actually this cool see https://stackoverflow.com/questions/30826015/convert-pgresult-to-an-active-record-model
|
438
455
|
ret = ret.to_a
|
439
456
|
return ret.map{|r| dynamic_init(instantiate_class, r)}
|
440
|
-
# fields = ret.columns
|
441
|
-
# vals = ret.rows
|
442
|
-
# ret = vals.map { |v|
|
443
|
-
# dynamic_init()
|
444
|
-
# instantiate_class.instantiate(Hash[fields.zip(v)])
|
445
|
-
# }
|
446
457
|
else
|
447
458
|
if raw
|
448
459
|
return ret
|
@@ -593,6 +604,17 @@ module DynamicRecordsMeritfront
|
|
593
604
|
raise StandardError.new('Bad return') unless out["b"]
|
594
605
|
puts 'pass 7'
|
595
606
|
|
607
|
+
puts "test dynamic_sql V3.0.6 error to do with multi_attribute_arrays which is hard to describe"
|
608
|
+
time = DateTime.now
|
609
|
+
values = [[1, :time, :time], [2, :time, :time]]
|
610
|
+
out = ar.dynamic_sql(%Q{
|
611
|
+
insert into #{mtname} (id, created_at, updated_at)
|
612
|
+
values :values
|
613
|
+
on conflict (id)
|
614
|
+
do update set updated_at = :time
|
615
|
+
}, time: time, values: values)
|
616
|
+
puts 'pass 8'
|
617
|
+
|
596
618
|
raise ActiveRecord::Rollback
|
597
619
|
#ApplicationRecord.dynamic_sql("SELECT * FROM")
|
598
620
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynamic-records-meritfront
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luke Clancy
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hashid-rails
|
@@ -54,7 +54,7 @@ metadata:
|
|
54
54
|
homepage_uri: https://github.com/LukeClancy/dynamic-records-meritfront
|
55
55
|
source_code_uri: https://github.com/LukeClancy/dynamic-records-meritfront
|
56
56
|
changelog_uri: https://github.com/LukeClancy/dynamic-records-meritfront/blob/main/README.md
|
57
|
-
post_install_message:
|
57
|
+
post_install_message:
|
58
58
|
rdoc_options: []
|
59
59
|
require_paths:
|
60
60
|
- lib
|
@@ -69,8 +69,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
69
69
|
- !ruby/object:Gem::Version
|
70
70
|
version: '0'
|
71
71
|
requirements: []
|
72
|
-
rubygems_version: 3.
|
73
|
-
signing_key:
|
72
|
+
rubygems_version: 3.3.7
|
73
|
+
signing_key:
|
74
74
|
specification_version: 4
|
75
75
|
summary: Helpers for active record that allow for more abstract and fine-grained code.
|
76
76
|
test_files: []
|