mudis-ql 0.2.0 → 0.2.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 +4 -4
- data/README.md +4 -1
- data/lib/mudis-ql/deep_dup.rb +21 -0
- data/lib/mudis-ql/metrics_scope.rb +7 -7
- data/lib/mudis-ql/scope.rb +22 -18
- data/lib/mudis-ql/store.rb +17 -11
- data/lib/mudis-ql/version.rb +1 -1
- data/lib/mudis-ql.rb +5 -4
- data/sig/mudis-ql/deep_dup.rbs +6 -0
- metadata +10 -62
- data/spec/mudis-ql/error_handling_spec.rb +0 -330
- data/spec/mudis-ql/integration_spec.rb +0 -337
- data/spec/mudis-ql/metrics_scope_spec.rb +0 -332
- data/spec/mudis-ql/performance_spec.rb +0 -295
- data/spec/mudis-ql/scope_spec.rb +0 -260
- data/spec/mudis-ql/store_spec.rb +0 -77
- data/spec/mudis-ql_spec.rb +0 -52
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5d6b6429e7f8bd20bea39f00e45a7557c7726b1452bd1c20f7cd3d0825fff42e
|
|
4
|
+
data.tar.gz: caeef29d56a5205fcef533e54689d1b866aa7a714dc089cb66e85718ae7324ff
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 64f95d197db3478067b9d2943d892a1bfeeba2898a061a5e20587d40b2b81887b808e409fb82657f840f263a922d1a76bc679134a261eb1630e82e3b7df46dcd
|
|
7
|
+
data.tar.gz: d300fe27f9181f04d83f1a70778bb1337e0bc6ecfb81a651b5d1d48404eab77236723e9ae13c957659d18f4aa2979fef18ef46684fcf35faa8f19607f574bbcd
|
data/README.md
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# Mudis-QL
|
|
2
2
|
|
|
3
|
+
[](https://www.jetbrains.com/ruby/)
|
|
4
|
+
|
|
3
5
|
[](https://badge.fury.io/rb/mudis-ql)
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://www.rubydoc.info/github/kiebor81/mudis-ql)
|
|
5
8
|
|
|
6
9
|
A simple query DSL for [mudis](https://github.com/kiebor81/mudis) cache. Mudis-QL extends mudis by providing a SQL-like query interface for data stored in the cache, enabling you to filter, sort, and paginate cached data without needing a full database.
|
|
7
10
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MudisQL
|
|
4
|
+
# Utility for deep-duplicating nested objects to avoid mutating cached data
|
|
5
|
+
module DeepDup
|
|
6
|
+
def self.call(obj) # rubocop:disable Metrics/MethodLength
|
|
7
|
+
case obj
|
|
8
|
+
when Hash
|
|
9
|
+
obj.transform_values { |v| call(v) }
|
|
10
|
+
when Array
|
|
11
|
+
obj.map { |v| call(v) }
|
|
12
|
+
else
|
|
13
|
+
begin
|
|
14
|
+
obj.dup
|
|
15
|
+
rescue TypeError
|
|
16
|
+
obj
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -18,7 +18,7 @@ module MudisQL
|
|
|
18
18
|
#
|
|
19
19
|
# @return [Hash] top-level metrics
|
|
20
20
|
def summary
|
|
21
|
-
@metrics_data.reject { |k, _| [
|
|
21
|
+
@metrics_data.reject { |k, _| %i[least_touched buckets].include?(k) }
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
# Query least touched keys
|
|
@@ -46,7 +46,7 @@ module MudisQL
|
|
|
46
46
|
# @return [Integer] total key count
|
|
47
47
|
def total_keys
|
|
48
48
|
buckets_data = @metrics_data[:buckets] || []
|
|
49
|
-
buckets_data.sum { |b|
|
|
49
|
+
buckets_data.sum { |b| b[:keys] || b['keys'] || 0 }
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
# Get total memory across all buckets
|
|
@@ -86,7 +86,7 @@ module MudisQL
|
|
|
86
86
|
# @return [Array<Hash>] buckets exceeding threshold
|
|
87
87
|
def high_memory_buckets(threshold)
|
|
88
88
|
buckets_data = @metrics_data[:buckets] || []
|
|
89
|
-
buckets_data.select { |b| ((b[:memory_bytes] || b[
|
|
89
|
+
buckets_data.select { |b| ((b[:memory_bytes] || b['memory_bytes']) || 0) > threshold }
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
# Find buckets with many keys
|
|
@@ -95,7 +95,7 @@ module MudisQL
|
|
|
95
95
|
# @return [Array<Hash>] buckets exceeding threshold
|
|
96
96
|
def high_key_buckets(threshold)
|
|
97
97
|
buckets_data = @metrics_data[:buckets] || []
|
|
98
|
-
buckets_data.select { |b| ((b[:keys] || b[
|
|
98
|
+
buckets_data.select { |b| ((b[:keys] || b['keys']) || 0) > threshold }
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
# Get bucket distribution statistics
|
|
@@ -105,8 +105,8 @@ module MudisQL
|
|
|
105
105
|
buckets_data = @metrics_data[:buckets] || []
|
|
106
106
|
return default_distribution if buckets_data.empty?
|
|
107
107
|
|
|
108
|
-
key_counts = buckets_data.map { |b| (b[:keys] || b[
|
|
109
|
-
memory_values = buckets_data.map { |b| (b[:memory_bytes] || b[
|
|
108
|
+
key_counts = buckets_data.map { |b| (b[:keys] || b['keys']) || 0 }
|
|
109
|
+
memory_values = buckets_data.map { |b| (b[:memory_bytes] || b['memory_bytes']) || 0 }
|
|
110
110
|
|
|
111
111
|
{
|
|
112
112
|
total_buckets: buckets_data.size,
|
|
@@ -156,7 +156,7 @@ module MudisQL
|
|
|
156
156
|
def create_scope_for_array(data)
|
|
157
157
|
# Create a temporary store-like object for the array data
|
|
158
158
|
temp_store = Object.new
|
|
159
|
-
temp_store.define_singleton_method(:all) { data }
|
|
159
|
+
temp_store.define_singleton_method(:all) { data.map { |item| DeepDup.call(item) } }
|
|
160
160
|
Scope.new(temp_store)
|
|
161
161
|
end
|
|
162
162
|
|
data/lib/mudis-ql/scope.rb
CHANGED
|
@@ -35,9 +35,11 @@ module MudisQL
|
|
|
35
35
|
# query.where(age: ->(v) { v > 18 })
|
|
36
36
|
# query.where(name: /^A/)
|
|
37
37
|
def where(conditions)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
cloned = clone
|
|
39
|
+
cloned_conditions = cloned.instance_variable_get(:@conditions).dup
|
|
40
|
+
cloned_conditions << conditions
|
|
41
|
+
cloned.instance_variable_set(:@conditions, cloned_conditions)
|
|
42
|
+
cloned
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
# Order results by a field
|
|
@@ -46,9 +48,10 @@ module MudisQL
|
|
|
46
48
|
# @param direction [Symbol] :asc or :desc
|
|
47
49
|
# @return [Scope] self for chaining
|
|
48
50
|
def order(field, direction = :asc)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
cloned = clone
|
|
52
|
+
cloned.instance_variable_set(:@order_by, field.to_s)
|
|
53
|
+
cloned.instance_variable_set(:@order_direction, direction)
|
|
54
|
+
cloned
|
|
52
55
|
end
|
|
53
56
|
|
|
54
57
|
# Limit the number of results
|
|
@@ -56,8 +59,9 @@ module MudisQL
|
|
|
56
59
|
# @param value [Integer] maximum number of results
|
|
57
60
|
# @return [Scope] self for chaining
|
|
58
61
|
def limit(value)
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
cloned = clone
|
|
63
|
+
cloned.instance_variable_set(:@limit_value, value)
|
|
64
|
+
cloned
|
|
61
65
|
end
|
|
62
66
|
|
|
63
67
|
# Skip the first N results
|
|
@@ -65,8 +69,9 @@ module MudisQL
|
|
|
65
69
|
# @param value [Integer] number of results to skip
|
|
66
70
|
# @return [Scope] self for chaining
|
|
67
71
|
def offset(value)
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
cloned = clone
|
|
73
|
+
cloned.instance_variable_set(:@offset_value, value)
|
|
74
|
+
cloned
|
|
70
75
|
end
|
|
71
76
|
|
|
72
77
|
# Execute the query and return all matching records
|
|
@@ -76,15 +81,14 @@ module MudisQL
|
|
|
76
81
|
results = store.all
|
|
77
82
|
results = apply_conditions(results)
|
|
78
83
|
results = apply_order(results)
|
|
79
|
-
|
|
80
|
-
results
|
|
84
|
+
apply_pagination(results)
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
# Execute query and return first result
|
|
84
88
|
#
|
|
85
89
|
# @return [Hash, nil] first matching record or nil
|
|
86
90
|
def first
|
|
87
|
-
limit(1).all.first
|
|
91
|
+
clone.limit(1).all.first
|
|
88
92
|
end
|
|
89
93
|
|
|
90
94
|
# Execute query and return last result
|
|
@@ -105,7 +109,7 @@ module MudisQL
|
|
|
105
109
|
#
|
|
106
110
|
# @return [Boolean] true if at least one record matches
|
|
107
111
|
def exists?
|
|
108
|
-
count
|
|
112
|
+
count.positive?
|
|
109
113
|
end
|
|
110
114
|
|
|
111
115
|
# Sum numeric values of a field across matching records
|
|
@@ -144,7 +148,7 @@ module MudisQL
|
|
|
144
148
|
def group_by(field)
|
|
145
149
|
field_str = field.to_s
|
|
146
150
|
filtered = apply_conditions(store.all)
|
|
147
|
-
|
|
151
|
+
|
|
148
152
|
filtered.group_by do |record|
|
|
149
153
|
record[field_str]
|
|
150
154
|
end
|
|
@@ -209,7 +213,7 @@ module MudisQL
|
|
|
209
213
|
# Separate nil and non-nil values
|
|
210
214
|
non_nil_results = []
|
|
211
215
|
nil_results = []
|
|
212
|
-
|
|
216
|
+
|
|
213
217
|
results.each do |record|
|
|
214
218
|
val = record[@order_by]
|
|
215
219
|
if val.nil?
|
|
@@ -234,7 +238,7 @@ module MudisQL
|
|
|
234
238
|
|
|
235
239
|
# Append nil values at the end
|
|
236
240
|
sorted + nil_results
|
|
237
|
-
rescue ArgumentError
|
|
241
|
+
rescue ArgumentError
|
|
238
242
|
# If sorting fails, return unsorted results
|
|
239
243
|
results
|
|
240
244
|
end
|
|
@@ -245,7 +249,7 @@ module MudisQL
|
|
|
245
249
|
# @return [Array<Hash>] paginated records
|
|
246
250
|
def apply_pagination(results)
|
|
247
251
|
offset = [@offset_value, 0].max
|
|
248
|
-
results = results.drop(offset) if offset
|
|
252
|
+
results = results.drop(offset) if offset.positive?
|
|
249
253
|
results = results.take(@limit_value) if @limit_value && @limit_value >= 0
|
|
250
254
|
results
|
|
251
255
|
end
|
data/lib/mudis-ql/store.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require 'mudis'
|
|
4
4
|
|
|
5
5
|
module MudisQL
|
|
6
6
|
# Store wraps mudis operations for a specific namespace
|
|
@@ -20,7 +20,7 @@ module MudisQL
|
|
|
20
20
|
else
|
|
21
21
|
# When no namespace, mudis uses default internal namespace
|
|
22
22
|
# We need to call without the namespace parameter
|
|
23
|
-
[]
|
|
23
|
+
[] # mudis doesn't support listing keys without namespace
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
|
|
@@ -64,16 +64,22 @@ module MudisQL
|
|
|
64
64
|
#
|
|
65
65
|
# @return [Array<Hash>] array of records with their keys
|
|
66
66
|
def all
|
|
67
|
-
keys.
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
keys.filter_map { |key| build_record(key) }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def build_record(key)
|
|
73
|
+
value = read(key)
|
|
74
|
+
return if value.nil?
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
if value.is_a?(Hash)
|
|
77
|
+
record = DeepDup.call(value)
|
|
78
|
+
record['_key'] = key
|
|
79
|
+
record
|
|
80
|
+
else
|
|
81
|
+
{ '_key' => key, 'value' => DeepDup.call(value) }
|
|
82
|
+
end
|
|
77
83
|
end
|
|
78
84
|
end
|
|
79
85
|
end
|
data/lib/mudis-ql/version.rb
CHANGED
data/lib/mudis-ql.rb
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
4
|
-
require_relative
|
|
5
|
-
require_relative
|
|
6
|
-
require_relative
|
|
3
|
+
require_relative 'mudis-ql/version'
|
|
4
|
+
require_relative 'mudis-ql/deep_dup'
|
|
5
|
+
require_relative 'mudis-ql/store'
|
|
6
|
+
require_relative 'mudis-ql/scope'
|
|
7
|
+
require_relative 'mudis-ql/metrics_scope'
|
|
7
8
|
|
|
8
9
|
# MudisQL provides a simple query DSL for mudis cache
|
|
9
10
|
module MudisQL
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mudis-ql
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kiebor81
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-02-03 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: mudis
|
|
@@ -15,61 +15,20 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.9.
|
|
18
|
+
version: 0.9.4
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.9.
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: climate_control
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - "~>"
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: 1.1.0
|
|
33
|
-
type: :development
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - "~>"
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: 1.1.0
|
|
40
|
-
- !ruby/object:Gem::Dependency
|
|
41
|
-
name: rspec
|
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
|
43
|
-
requirements:
|
|
44
|
-
- - "~>"
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: '3.12'
|
|
47
|
-
type: :development
|
|
48
|
-
prerelease: false
|
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
-
requirements:
|
|
51
|
-
- - "~>"
|
|
52
|
-
- !ruby/object:Gem::Version
|
|
53
|
-
version: '3.12'
|
|
54
|
-
- !ruby/object:Gem::Dependency
|
|
55
|
-
name: simplecov
|
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
|
57
|
-
requirements:
|
|
58
|
-
- - "~>"
|
|
59
|
-
- !ruby/object:Gem::Version
|
|
60
|
-
version: '0.22'
|
|
61
|
-
type: :development
|
|
62
|
-
prerelease: false
|
|
63
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
-
requirements:
|
|
65
|
-
- - "~>"
|
|
66
|
-
- !ruby/object:Gem::Version
|
|
67
|
-
version: '0.22'
|
|
25
|
+
version: 0.9.4
|
|
68
26
|
description: Mudis-QL extends Mudis by providing a fluent SQL-like query interface
|
|
69
27
|
for data stored in the mudis cache
|
|
70
28
|
executables: []
|
|
71
29
|
extensions: []
|
|
72
30
|
extra_rdoc_files:
|
|
31
|
+
- sig/mudis-ql/deep_dup.rbs
|
|
73
32
|
- sig/mudis-ql/metrics_scope.rbs
|
|
74
33
|
- sig/mudis-ql/scope.rbs
|
|
75
34
|
- sig/mudis-ql/store.rbs
|
|
@@ -77,21 +36,16 @@ extra_rdoc_files:
|
|
|
77
36
|
files:
|
|
78
37
|
- README.md
|
|
79
38
|
- lib/mudis-ql.rb
|
|
39
|
+
- lib/mudis-ql/deep_dup.rb
|
|
80
40
|
- lib/mudis-ql/metrics_scope.rb
|
|
81
41
|
- lib/mudis-ql/scope.rb
|
|
82
42
|
- lib/mudis-ql/store.rb
|
|
83
43
|
- lib/mudis-ql/version.rb
|
|
84
44
|
- sig/mudis-ql.rbs
|
|
45
|
+
- sig/mudis-ql/deep_dup.rbs
|
|
85
46
|
- sig/mudis-ql/metrics_scope.rbs
|
|
86
47
|
- sig/mudis-ql/scope.rbs
|
|
87
48
|
- sig/mudis-ql/store.rbs
|
|
88
|
-
- spec/mudis-ql/error_handling_spec.rb
|
|
89
|
-
- spec/mudis-ql/integration_spec.rb
|
|
90
|
-
- spec/mudis-ql/metrics_scope_spec.rb
|
|
91
|
-
- spec/mudis-ql/performance_spec.rb
|
|
92
|
-
- spec/mudis-ql/scope_spec.rb
|
|
93
|
-
- spec/mudis-ql/store_spec.rb
|
|
94
|
-
- spec/mudis-ql_spec.rb
|
|
95
49
|
homepage: https://github.com/kiebor81/mudis-ql
|
|
96
50
|
licenses:
|
|
97
51
|
- MIT
|
|
@@ -99,6 +53,7 @@ metadata:
|
|
|
99
53
|
homepage_uri: https://github.com/kiebor81/mudis-ql
|
|
100
54
|
source_code_uri: https://github.com/kiebor81/mudis-ql
|
|
101
55
|
changelog_uri: https://github.com/kiebor81/mudis-ql/blob/main/CHANGELOG.md
|
|
56
|
+
rubygems_mfa_required: 'true'
|
|
102
57
|
rdoc_options: []
|
|
103
58
|
require_paths:
|
|
104
59
|
- lib
|
|
@@ -106,7 +61,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
106
61
|
requirements:
|
|
107
62
|
- - ">="
|
|
108
63
|
- !ruby/object:Gem::Version
|
|
109
|
-
version: '3.
|
|
64
|
+
version: '3.3'
|
|
110
65
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
66
|
requirements:
|
|
112
67
|
- - ">="
|
|
@@ -116,11 +71,4 @@ requirements: []
|
|
|
116
71
|
rubygems_version: 3.6.2
|
|
117
72
|
specification_version: 4
|
|
118
73
|
summary: A simple query DSL for Mudis cache
|
|
119
|
-
test_files:
|
|
120
|
-
- spec/mudis-ql/error_handling_spec.rb
|
|
121
|
-
- spec/mudis-ql/integration_spec.rb
|
|
122
|
-
- spec/mudis-ql/metrics_scope_spec.rb
|
|
123
|
-
- spec/mudis-ql/performance_spec.rb
|
|
124
|
-
- spec/mudis-ql/scope_spec.rb
|
|
125
|
-
- spec/mudis-ql/store_spec.rb
|
|
126
|
-
- spec/mudis-ql_spec.rb
|
|
74
|
+
test_files: []
|