litetags 0.1.0 → 0.2.0

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: d429447c6ac8c7de8a04aed16f1ccdde4e093d027544d90ba4d97bada4aefeb1
4
- data.tar.gz: 40ab43074326f34593f08d51d7363eed85345a867b3e6aff8d72e917add41ed6
3
+ metadata.gz: ca6f6ddb7c14a7e8348471c9d55b53818e4e6c0f52649998671ee819eb172122
4
+ data.tar.gz: f008123f5380ad4f0a623c91c39668b9db59184d907b447bd6fcd601db3e6d02
5
5
  SHA512:
6
- metadata.gz: ff42f221f0f1c551fb749d3c1b19b88707472c1f8c0075ca55760b674c7496ad2fc53ae5726fe77dd3f08fbef385b19d63a2cbd5749c270700f03d48538fd654
7
- data.tar.gz: b03cf9917b103ae62c984c8ecca3a2977f82bf7ec42c6f3fea925370101618a478073ea8e16ceaa5f879a40f1a561b7a3ce3904a588e4a64197b5dad91d7cdd7
6
+ metadata.gz: 3d681f1715cdfd3a2e12b4d00840aa16bc363c7ac48e48ca9622a0046635ad3918bb910f58314da7e80e772ba9df8d8ee3ebc9a0374cc13b50be6b299c6734dd
7
+ data.tar.gz: 64b52cbe30e8669e813270d3c1b2a842d658f9f62cf90ae4457f5b2080ddbd22bf87c3135314e0ca97daede33bd482c02113adbc862a8179b8a0181e75ad4672
data/Gemfile.lock CHANGED
@@ -1,12 +1,28 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- litetags (0.1.0)
4
+ litetags (0.2.0)
5
+ activerecord (~> 6.1)
5
6
 
6
7
  GEM
7
8
  remote: https://rubygems.org/
8
9
  specs:
10
+ activemodel (6.1.7.4)
11
+ activesupport (= 6.1.7.4)
12
+ activerecord (6.1.7.4)
13
+ activemodel (= 6.1.7.4)
14
+ activesupport (= 6.1.7.4)
15
+ activesupport (6.1.7.4)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 1.6, < 2)
18
+ minitest (>= 5.1)
19
+ tzinfo (~> 2.0)
20
+ zeitwerk (~> 2.3)
9
21
  ast (2.4.2)
22
+ concurrent-ruby (1.2.2)
23
+ docile (1.4.0)
24
+ i18n (1.14.1)
25
+ concurrent-ruby (~> 1.0)
10
26
  json (2.6.3)
11
27
  language_server-protocol (3.17.0.3)
12
28
  lint_roller (1.1.0)
@@ -36,6 +52,13 @@ GEM
36
52
  rubocop (>= 1.7.0, < 2.0)
37
53
  rubocop-ast (>= 0.4.0)
38
54
  ruby-progressbar (1.13.0)
55
+ simplecov (0.22.0)
56
+ docile (~> 1.1)
57
+ simplecov-html (~> 0.11)
58
+ simplecov_json_formatter (~> 0.1)
59
+ simplecov-html (0.12.3)
60
+ simplecov_json_formatter (0.1.4)
61
+ sqlite3 (1.6.3-arm64-darwin)
39
62
  standard (1.30.1)
40
63
  language_server-protocol (~> 3.17.0.2)
41
64
  lint_roller (~> 1.0)
@@ -48,7 +71,10 @@ GEM
48
71
  standard-performance (1.1.2)
49
72
  lint_roller (~> 1.1)
50
73
  rubocop-performance (~> 1.18.0)
74
+ tzinfo (2.0.6)
75
+ concurrent-ruby (~> 1.0)
51
76
  unicode-display_width (2.4.2)
77
+ zeitwerk (2.6.11)
52
78
 
53
79
  PLATFORMS
54
80
  arm64-darwin-21
@@ -57,6 +83,8 @@ DEPENDENCIES
57
83
  litetags!
58
84
  minitest (~> 5.0)
59
85
  rake (~> 13.0)
86
+ simplecov
87
+ sqlite3
60
88
  standard (~> 1.3)
61
89
 
62
90
  BUNDLED WITH
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Litetags
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/litetags.rb CHANGED
@@ -1,8 +1,128 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "litetags/version"
4
+ require "active_record"
4
5
 
5
6
  module Litetags
6
- class Error < StandardError; end
7
- # Your code goes here...
7
+ def self.included(klass)
8
+ klass.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+ def tag_columns(*column_names)
13
+ @tag_columns ||= {}
14
+
15
+ tag_columns_sanitize_list(column_names).each do |column_name|
16
+ @tag_columns[column_name] ||= false
17
+ end
18
+
19
+ @tag_columns.each do |column_name, initialized|
20
+ next if initialized
21
+
22
+ column_name = column_name.to_s
23
+ method_name = column_name.downcase
24
+
25
+ # JSON_EACH("{table}"."{column}")
26
+ json_each = Arel::Nodes::NamedFunction.new("JSON_EACH", [arel_table[column_name]])
27
+
28
+ # SELECT DISTINCT value FROM "{table}", JSON_EACH("{table}"."{column}")
29
+ define_singleton_method :"unique_#{method_name}" do |conditions = "true"|
30
+ select("value")
31
+ .from([arel_table, json_each])
32
+ .distinct
33
+ .pluck("value")
34
+ .sort
35
+ end
36
+
37
+ # SELECT value, COUNT(*) AS count FROM "{table}", JSON_EACH("{table}"."{column}") GROUP BY value ORDER BY value
38
+ define_singleton_method :"#{method_name}_cloud" do |conditions = "true"|
39
+ select("value")
40
+ .from([arel_table, json_each])
41
+ .group("value")
42
+ .order("value")
43
+ .pluck(Arel.sql("value, COUNT(*) AS count"))
44
+ .to_h
45
+ end
46
+
47
+ # SELECT "{table}".* FROM "{table}" WHERE "{table}"."{column}" IS NOT NULL AND "{table}"."{column}" != '[]'
48
+ scope :"with_#{method_name}", -> {
49
+ where.not(arel_table[column_name].eq(nil))
50
+ .where.not(arel_table[column_name].eq([]))
51
+ }
52
+
53
+ # SELECT "{table}".* FROM "{table}" WHERE ("{table}"."{column}" IS NULL OR "{table}"."{column}" = '[]')
54
+ scope :"without_#{method_name}", -> {
55
+ where(arel_table[column_name].eq(nil))
56
+ .or(where(arel_table[column_name].eq([])))
57
+ }
58
+
59
+ # SELECT "{table}".* FROM "{table}" WHERE EXISTS (SELECT 1 FROM JSON_EACH("{table}"."{column}") WHERE value IN ({values}) LIMIT 1)
60
+ scope :"with_any_#{method_name}", ->(*items) {
61
+ values = tag_columns_sanitize_list(items)
62
+ overlap = Arel::SelectManager.new(json_each)
63
+ .project(1)
64
+ .where(Arel.sql("value").in(values))
65
+ .take(1)
66
+ .exists
67
+
68
+ where overlap
69
+ }
70
+
71
+ # SELECT "{table}".* FROM "{table}" WHERE (SELECT COUNT(*) FROM JSON_EACH("{table}"."{column}") WHERE value IN ({values})) = {values.size};
72
+ scope :"with_all_#{method_name}", ->(*items) {
73
+ values = tag_columns_sanitize_list(items)
74
+ count = Arel::SelectManager.new(json_each)
75
+ .project(Arel.star.count)
76
+ .where(Arel.sql("value").in(values))
77
+ contains = Arel::Nodes::Equality.new(count, values.size)
78
+
79
+ where contains
80
+ }
81
+
82
+ # SELECT "{table}".* FROM "{table}" WHERE NOT EXISTS (SELECT 1 FROM JSON_EACH("{table}"."{column}") WHERE value IN ({values}) LIMIT 1)
83
+ scope :"without_any_#{method_name}", ->(*items) {
84
+ values = tag_columns_sanitize_list(items)
85
+ overlap = Arel::SelectManager.new(json_each)
86
+ .project(1)
87
+ .where(Arel.sql("value").in(values))
88
+ .take(1)
89
+ .exists
90
+ where.not overlap
91
+ }
92
+
93
+ # SELECT "{table}".* FROM "{table}" WHERE (SELECT COUNT(*) FROM JSON_EACH("{table}"."{column}") WHERE value IN ({values})) != {values.size};
94
+ scope :"without_all_#{method_name}", ->(*items) {
95
+ values = tag_columns_sanitize_list(items)
96
+ count = Arel::SelectManager.new(json_each)
97
+ .project(Arel.star.count)
98
+ .where(Arel.sql("value").in(values))
99
+ contains = Arel::Nodes::Equality.new(count, values.size)
100
+ where.not contains
101
+ }
102
+
103
+ before_validation -> { self[column_name] = self.class.tag_columns_sanitize_list(self[column_name]) }
104
+
105
+ define_method :"has_any_#{method_name}?" do |*values|
106
+ values = self.class.tag_columns_sanitize_list(values)
107
+ existing = self.class.tag_columns_sanitize_list(self[column_name])
108
+ (values & existing).present?
109
+ end
110
+
111
+ define_method :"has_all_#{method_name}?" do |*values|
112
+ values = self.class.tag_columns_sanitize_list(values)
113
+ existing = self.class.tag_columns_sanitize_list(self[column_name])
114
+ (values & existing).size == values.size
115
+ end
116
+
117
+ alias_method :"has_#{method_name.singularize}?", :"has_all_#{method_name}?"
118
+
119
+ @tag_columns[column_name] = true
120
+ end
121
+ end
122
+
123
+ def tag_columns_sanitize_list(values = [])
124
+ return [] if values.nil?
125
+ values.select(&:present?).map(&:to_s).uniq.sort
126
+ end
127
+ end
8
128
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: litetags
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Margheim
@@ -9,7 +9,49 @@ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
11
  date: 2023-08-10 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '6.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '6.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: simplecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
13
55
  description:
14
56
  email:
15
57
  - stephen.margheim@gmail.com