familia 1.2.1 → 2.0.0.pre.pre
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/.github/workflows/ci.yml +68 -0
- data/.github/workflows/docs.yml +64 -0
- data/.gitignore +4 -0
- data/.pre-commit-config.yaml +3 -1
- data/.rubocop.yml +16 -9
- data/.rubocop_todo.yml +177 -31
- data/.yardopts +9 -0
- data/CLAUDE.md +141 -0
- data/Gemfile +15 -2
- data/Gemfile.lock +76 -34
- data/README.md +39 -23
- data/bin/irb +3 -0
- data/docs/connection_pooling.md +317 -0
- data/familia.gemspec +9 -5
- data/lib/familia/base.rb +19 -9
- data/lib/familia/connection.rb +232 -65
- data/lib/familia/core_ext.rb +1 -1
- data/lib/familia/datatype/commands.rb +59 -0
- data/lib/familia/{redistype → datatype}/serialization.rb +9 -13
- data/lib/familia/{redistype → datatype}/types/hashkey.rb +25 -25
- data/lib/familia/{redistype → datatype}/types/list.rb +13 -13
- data/lib/familia/{redistype → datatype}/types/sorted_set.rb +20 -20
- data/lib/familia/{redistype → datatype}/types/string.rb +22 -21
- data/lib/familia/{redistype → datatype}/types/unsorted_set.rb +11 -11
- data/lib/familia/datatype.rb +243 -0
- data/lib/familia/errors.rb +5 -2
- data/lib/familia/features/expiration.rb +33 -34
- data/lib/familia/features/quantization.rb +9 -3
- data/lib/familia/features/safe_dump.rb +2 -3
- data/lib/familia/features.rb +2 -2
- data/lib/familia/horreum/class_methods.rb +97 -110
- data/lib/familia/horreum/commands.rb +46 -51
- data/lib/familia/horreum/connection.rb +82 -0
- data/lib/familia/horreum/{relations_management.rb → related_fields_management.rb} +37 -35
- data/lib/familia/horreum/serialization.rb +61 -198
- data/lib/familia/horreum/settings.rb +6 -17
- data/lib/familia/horreum/utils.rb +11 -10
- data/lib/familia/horreum.rb +69 -60
- data/lib/familia/logging.rb +12 -12
- data/lib/familia/multi_result.rb +72 -0
- data/lib/familia/refinements.rb +7 -44
- data/lib/familia/settings.rb +11 -11
- data/lib/familia/utils.rb +123 -90
- data/lib/familia/version.rb +4 -21
- data/lib/familia.rb +17 -12
- data/lib/middleware/database_middleware.rb +150 -0
- data/try/configuration/scenarios_try.rb +65 -0
- data/try/core/connection_try.rb +58 -0
- data/try/core/errors_try.rb +93 -0
- data/try/core/extensions_try.rb +26 -0
- data/try/{10_familia_try.rb → core/familia_extended_try.rb} +11 -10
- data/try/{00_familia_try.rb → core/familia_try.rb} +5 -3
- data/try/core/middleware_try.rb +68 -0
- data/try/core/refinements_try.rb +39 -0
- data/try/core/settings_try.rb +76 -0
- data/try/core/tools_try.rb +54 -0
- data/try/core/utils_try.rb +189 -0
- data/try/{26_redis_bool_try.rb → datatypes/boolean_try.rb} +4 -2
- data/try/datatypes/datatype_base_try.rb +69 -0
- data/try/{25_redis_type_hash_try.rb → datatypes/hash_try.rb} +5 -3
- data/try/{23_redis_type_list_try.rb → datatypes/list_try.rb} +5 -3
- data/try/{22_redis_type_set_try.rb → datatypes/set_try.rb} +5 -3
- data/try/{21_redis_type_zset_try.rb → datatypes/sorted_set_try.rb} +6 -4
- data/try/{24_redis_type_string_try.rb → datatypes/string_try.rb} +8 -8
- data/try/edge_cases/empty_identifiers_try.rb +48 -0
- data/try/{92_symbolize_try.rb → edge_cases/hash_symbolization_try.rb} +12 -7
- data/try/edge_cases/json_serialization_try.rb +85 -0
- data/try/edge_cases/race_conditions_try.rb +60 -0
- data/try/edge_cases/reserved_keywords_try.rb +59 -0
- data/try/{93_string_coercion_try.rb → edge_cases/string_coercion_try.rb} +60 -59
- data/try/edge_cases/ttl_side_effects_try.rb +51 -0
- data/try/features/expiration_try.rb +86 -0
- data/try/features/quantization_try.rb +90 -0
- data/try/{35_feature_safedump_try.rb → features/safe_dump_advanced_try.rb} +7 -6
- data/try/features/safe_dump_try.rb +137 -0
- data/try/{test_helpers.rb → helpers/test_helpers.rb} +25 -60
- data/try/{27_redis_horreum_try.rb → horreum/base_try.rb} +39 -14
- data/try/horreum/class_methods_try.rb +41 -0
- data/try/horreum/commands_try.rb +49 -0
- data/try/{29_redis_horreum_initialization_try.rb → horreum/initialization_try.rb} +9 -7
- data/try/horreum/relations_try.rb +146 -0
- data/try/{28_redis_horreum_serialization_try.rb → horreum/serialization_try.rb} +13 -11
- data/try/horreum/settings_try.rb +43 -0
- data/try/integration/cross_component_try.rb +46 -0
- data/try/{41_customer_safedump_try.rb → models/customer_safe_dump_try.rb} +9 -7
- data/try/{40_customer_try.rb → models/customer_try.rb} +20 -17
- data/try/models/datatype_base_try.rb +101 -0
- data/try/{30_familia_object_try.rb → models/familia_object_try.rb} +18 -16
- data/try/performance/benchmarks_try.rb +55 -0
- data/try/pooling/README.md +20 -0
- data/try/pooling/configurable_stress_test_try.rb +435 -0
- data/try/pooling/connection_pool_test_try.rb +273 -0
- data/try/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +192 -0
- data/try/pooling/lib/connection_pool_metrics.rb +372 -0
- data/try/pooling/lib/connection_pool_stress_test.rb +959 -0
- data/try/pooling/lib/connection_pool_threading_models.rb +421 -0
- data/try/pooling/lib/visualize_stress_results.rb +434 -0
- data/try/pooling/pool_siege_try.rb +509 -0
- data/try/pooling/run_stress_tests_try.rb +482 -0
- data/try/prototypes/atomic_saves_v1_context_proxy.rb +121 -0
- data/try/prototypes/atomic_saves_v2_connection_switching.rb +161 -0
- data/try/prototypes/atomic_saves_v3_connection_pool.rb +189 -0
- data/try/prototypes/atomic_saves_v4.rb +105 -0
- data/try/prototypes/lib/atomic_saves_v2_connection_switching_helpers.rb +124 -0
- data/try/prototypes/lib/atomic_saves_v3_connection_pool_helpers.rb +192 -0
- metadata +140 -43
- data/.github/workflows/ruby.yml +0 -71
- data/VERSION.yml +0 -4
- data/lib/familia/redistype/commands.rb +0 -59
- data/lib/familia/redistype.rb +0 -228
- data/lib/familia/tools.rb +0 -68
- data/lib/redis_middleware.rb +0 -109
- data/try/20_redis_type_try.rb +0 -70
- data/try/91_json_bug_try.rb +0 -86
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92ee81bd30cdbcb84de0e72a26bde44a170efcd6578d81bdd47458aee37f52be
|
4
|
+
data.tar.gz: 4127847dbc955df3e6a7c7a3dd616dd3438da046f8703a59c734399697cf8903
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87f8ff4b5423771ce6c1c93640cd3e83ea1e9beb023c130896878bed64fd61341ac18b365641bd7c30310fafdcf1b31569ca726dbaedf5c7ec23d308805b3305
|
7
|
+
data.tar.gz: d76036d625a604014380a67e5765263c2ea51bb608da09344a57fb4cf8386ae724499bb27e352c7d7133d15ae16a052dcb27ea262943cb509662666c72983d13
|
@@ -0,0 +1,68 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- main
|
7
|
+
|
8
|
+
pull_request:
|
9
|
+
|
10
|
+
workflow_dispatch:
|
11
|
+
|
12
|
+
permissions:
|
13
|
+
contents: read
|
14
|
+
|
15
|
+
jobs:
|
16
|
+
build:
|
17
|
+
timeout-minutes: 10
|
18
|
+
|
19
|
+
runs-on: ubuntu-24.04
|
20
|
+
|
21
|
+
strategy:
|
22
|
+
fail-fast: true
|
23
|
+
matrix:
|
24
|
+
ruby: ["3.4", "3.5"]
|
25
|
+
continue-on-error: [false]
|
26
|
+
|
27
|
+
services:
|
28
|
+
redis:
|
29
|
+
image: valkey/valkey:8.1-bookworm
|
30
|
+
# Set health checks to wait until database server has started
|
31
|
+
options: >-
|
32
|
+
--health-cmd "redis-cli ping"
|
33
|
+
--health-interval 10s
|
34
|
+
--health-timeout 3s
|
35
|
+
--health-retries 5
|
36
|
+
ports:
|
37
|
+
# https://docs.github.com/en/actions/using-containerized-services/creating-redis-service-containers#running-jobs-in-containers
|
38
|
+
# Maps port 6379 on service container to the host
|
39
|
+
- 6379:6379
|
40
|
+
|
41
|
+
steps:
|
42
|
+
- uses: actions/checkout@v4
|
43
|
+
- name: Set up Ruby
|
44
|
+
uses: ruby/setup-ruby@v1
|
45
|
+
with:
|
46
|
+
ruby-version: ${{ matrix.ruby }}
|
47
|
+
# When the following is true, also run "bundle install",
|
48
|
+
# and cache the result automatically. Ran into an issue
|
49
|
+
# with the caching and multiple ruby versions. Needs
|
50
|
+
# further investigation.
|
51
|
+
bundler-cache: true
|
52
|
+
|
53
|
+
- name: Setup tmate session
|
54
|
+
uses: mxschmitt/action-tmate@7b6a61a73bbb9793cb80ad69b8dd8ac19261834c # v3
|
55
|
+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
|
56
|
+
with:
|
57
|
+
detached: true
|
58
|
+
|
59
|
+
- name: Configure Bundler for secure gem installation
|
60
|
+
run: |
|
61
|
+
bundle config set --local path 'vendor/bundle'
|
62
|
+
bundle config set --local deployment 'false'
|
63
|
+
|
64
|
+
- name: Re-run bundle install
|
65
|
+
run: bundle install
|
66
|
+
|
67
|
+
- name: Run the tryouts
|
68
|
+
run: bundle exec try -vf
|
@@ -0,0 +1,64 @@
|
|
1
|
+
name: Build and Publish YARD Documentation
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- main
|
7
|
+
workflow_dispatch:
|
8
|
+
inputs:
|
9
|
+
reason:
|
10
|
+
description: 'Reason for manual documentation build'
|
11
|
+
required: false
|
12
|
+
default: 'Manual documentation update'
|
13
|
+
|
14
|
+
permissions:
|
15
|
+
contents: read
|
16
|
+
pages: write
|
17
|
+
id-token: write
|
18
|
+
|
19
|
+
concurrency:
|
20
|
+
group: "pages"
|
21
|
+
cancel-in-progress: false
|
22
|
+
|
23
|
+
jobs:
|
24
|
+
build_docs:
|
25
|
+
runs-on: ubuntu-24.04
|
26
|
+
|
27
|
+
steps:
|
28
|
+
- name: Checkout code
|
29
|
+
uses: actions/checkout@v4
|
30
|
+
with:
|
31
|
+
fetch-depth: 0
|
32
|
+
|
33
|
+
- name: Set up Ruby
|
34
|
+
uses: ruby/setup-ruby@v1
|
35
|
+
with:
|
36
|
+
ruby-version: '3.4'
|
37
|
+
bundler-cache: true
|
38
|
+
|
39
|
+
- name: Install dependencies
|
40
|
+
run: bundle install
|
41
|
+
|
42
|
+
- name: Build YARD documentation
|
43
|
+
run: |
|
44
|
+
bundle exec yard doc --output-dir ./doc --readme README.md
|
45
|
+
# Ensure doc directory exists and create .nojekyll file to prevent GitHub Pages Jekyll processing
|
46
|
+
mkdir -p ./doc
|
47
|
+
touch ./doc/.nojekyll
|
48
|
+
|
49
|
+
- name: Upload documentation artifacts
|
50
|
+
uses: actions/upload-pages-artifact@v3
|
51
|
+
with:
|
52
|
+
path: ./doc
|
53
|
+
|
54
|
+
deploy:
|
55
|
+
environment:
|
56
|
+
name: github-pages
|
57
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
58
|
+
runs-on: ubuntu-24.04
|
59
|
+
needs: build_docs
|
60
|
+
|
61
|
+
steps:
|
62
|
+
- name: Deploy to GitHub Pages
|
63
|
+
id: deployment
|
64
|
+
uses: actions/deploy-pages@v4
|
data/.gitignore
CHANGED
data/.pre-commit-config.yaml
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# .rubocop.yml
|
1
2
|
|
2
3
|
##
|
3
4
|
# This is the RuboCop configuration file.
|
@@ -12,9 +13,12 @@
|
|
12
13
|
# as those documented at the top of the todo file). This is
|
13
14
|
# useful for a gradual migration of the codebase.
|
14
15
|
#
|
16
|
+
# How to resolve "RuboCop version incompatibility found":
|
17
|
+
# `rubocop --stop-server`
|
18
|
+
#
|
15
19
|
inherit_from: .rubocop_todo.yml
|
16
20
|
|
17
|
-
|
21
|
+
plugins:
|
18
22
|
- rubocop-performance
|
19
23
|
- rubocop-thread_safety
|
20
24
|
|
@@ -22,13 +26,13 @@ AllCops:
|
|
22
26
|
NewCops: enable
|
23
27
|
UseCache: true
|
24
28
|
MaxFilesInCache: 100
|
25
|
-
TargetRubyVersion: 3.
|
29
|
+
TargetRubyVersion: 3.4
|
26
30
|
Exclude:
|
27
|
-
-
|
28
|
-
-
|
29
|
-
-
|
30
|
-
-
|
31
|
-
-
|
31
|
+
- "migrate/**/*.rb"
|
32
|
+
- "migrate/*.rb"
|
33
|
+
- "try/**/*"
|
34
|
+
- "try/*.rb"
|
35
|
+
- "vendor/**/*"
|
32
36
|
|
33
37
|
Gemspec/DeprecatedAttributeAssignment:
|
34
38
|
Enabled: true
|
@@ -56,12 +60,12 @@ Metrics/CyclomaticComplexity:
|
|
56
60
|
Metrics/MethodLength:
|
57
61
|
Enabled: true
|
58
62
|
Max: 40
|
59
|
-
CountAsOne: [
|
63
|
+
CountAsOne: ["method_call"]
|
60
64
|
|
61
65
|
Metrics/ModuleLength:
|
62
66
|
Enabled: true
|
63
67
|
Max: 250
|
64
|
-
CountAsOne: [
|
68
|
+
CountAsOne: ["method_call"]
|
65
69
|
|
66
70
|
Performance/Size:
|
67
71
|
Enabled: true
|
@@ -73,3 +77,6 @@ Style/NegatedIfElseCondition:
|
|
73
77
|
|
74
78
|
Naming/AsciiIdentifiers:
|
75
79
|
Enabled: false
|
80
|
+
|
81
|
+
Style/FrozenStringLiteralComment:
|
82
|
+
Enabled: false
|
data/.rubocop_todo.yml
CHANGED
@@ -1,63 +1,209 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on
|
3
|
+
# on 2025-07-20 01:49:27 UTC using RuboCop version 1.78.0.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
8
|
|
9
|
+
# Offense count: 2
|
10
|
+
# This cop supports safe autocorrection (--autocorrect).
|
11
|
+
# Configuration parameters: AutoCorrect, AllowBorderComment, AllowMarginComment.
|
12
|
+
Layout/EmptyComment:
|
13
|
+
Exclude:
|
14
|
+
- "lib/familia/base.rb"
|
15
|
+
- "lib/familia/connection.rb"
|
16
|
+
|
17
|
+
# Offense count: 1
|
18
|
+
# This cop supports safe autocorrection (--autocorrect).
|
19
|
+
Layout/EmptyLines:
|
20
|
+
Exclude:
|
21
|
+
- "Gemfile"
|
22
|
+
|
23
|
+
# Offense count: 2
|
24
|
+
# This cop supports safe autocorrection (--autocorrect).
|
25
|
+
# Configuration parameters: EnforcedStyle.
|
26
|
+
# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only
|
27
|
+
Layout/EmptyLinesAroundClassBody:
|
28
|
+
Exclude:
|
29
|
+
- "lib/familia/datatype/types/list.rb"
|
30
|
+
- "lib/familia/datatype/types/unsorted_set.rb"
|
31
|
+
|
9
32
|
# Offense count: 1
|
10
|
-
#
|
11
|
-
|
12
|
-
|
13
|
-
|
33
|
+
# This cop supports safe autocorrection (--autocorrect).
|
34
|
+
Layout/SpaceAfterComma:
|
35
|
+
Exclude:
|
36
|
+
- "lib/familia/datatype/types/hashkey.rb"
|
37
|
+
|
38
|
+
# Offense count: 4
|
39
|
+
# This cop supports safe autocorrection (--autocorrect).
|
40
|
+
# Configuration parameters: AutoCorrect, AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions.
|
41
|
+
# NotImplementedExceptions: NotImplementedError
|
42
|
+
Lint/UnusedMethodArgument:
|
14
43
|
Exclude:
|
15
|
-
-
|
44
|
+
- "lib/familia/base.rb"
|
45
|
+
- "lib/middleware/database_middleware.rb"
|
16
46
|
|
17
47
|
# Offense count: 1
|
18
|
-
# Configuration parameters:
|
19
|
-
#
|
20
|
-
|
48
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
49
|
+
# AllowedMethods: refine
|
50
|
+
Metrics/BlockLength:
|
51
|
+
Max: 28
|
52
|
+
|
53
|
+
# Offense count: 2
|
54
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
55
|
+
Metrics/PerceivedComplexity:
|
56
|
+
Max: 9
|
57
|
+
|
58
|
+
# Offense count: 50
|
59
|
+
# This cop supports safe autocorrection (--autocorrect).
|
60
|
+
# Configuration parameters: EnforcedStyle, BlockForwardingName.
|
61
|
+
# SupportedStyles: anonymous, explicit
|
62
|
+
Naming/BlockForwarding:
|
21
63
|
Exclude:
|
22
|
-
-
|
64
|
+
- "lib/familia/datatype/types/list.rb"
|
65
|
+
- "lib/familia/datatype/types/sorted_set.rb"
|
66
|
+
- "lib/familia/datatype/types/unsorted_set.rb"
|
67
|
+
- "lib/familia/refinements.rb"
|
23
68
|
|
24
|
-
# Offense count:
|
69
|
+
# Offense count: 8
|
25
70
|
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
26
71
|
# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
|
27
72
|
Naming/MethodParameterName:
|
28
73
|
Exclude:
|
29
|
-
-
|
30
|
-
-
|
31
|
-
-
|
32
|
-
-
|
74
|
+
- "lib/familia/core_ext.rb"
|
75
|
+
- "lib/familia/horreum/class_methods.rb"
|
76
|
+
- "lib/familia/datatype/types/sorted_set.rb"
|
77
|
+
- "lib/familia/datatype/types/unsorted_set.rb"
|
78
|
+
|
79
|
+
# Offense count: 1
|
80
|
+
# Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
|
81
|
+
# AllowedMethods: call
|
82
|
+
# WaywardPredicates: nonzero?
|
83
|
+
Naming/PredicateMethod:
|
84
|
+
Exclude:
|
85
|
+
- "lib/familia/horreum/class_methods.rb"
|
33
86
|
|
34
87
|
# Offense count: 1
|
35
|
-
# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros.
|
36
|
-
# NamePrefix: is_, has_, have_
|
37
|
-
# ForbiddenPrefixes: is_, has_, have_
|
88
|
+
# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros, UseSorbetSigs.
|
89
|
+
# NamePrefix: is_, has_, have_, does_
|
90
|
+
# ForbiddenPrefixes: is_, has_, have_, does_
|
38
91
|
# AllowedMethods: is_a?
|
39
92
|
# MethodDefinitionMacros: define_method, define_singleton_method
|
40
|
-
Naming/
|
93
|
+
Naming/PredicatePrefix:
|
41
94
|
Exclude:
|
42
|
-
-
|
43
|
-
-
|
95
|
+
- "spec/**/*"
|
96
|
+
- "lib/familia/horreum/class_methods.rb"
|
44
97
|
|
45
|
-
# Offense count:
|
98
|
+
# Offense count: 54
|
99
|
+
# This cop supports safe autocorrection (--autocorrect).
|
100
|
+
# Configuration parameters: AllowOnlyRestArgument, UseAnonymousForwarding, RedundantRestArgumentNames, RedundantKeywordRestArgumentNames, RedundantBlockArgumentNames.
|
101
|
+
# RedundantRestArgumentNames: args, arguments
|
102
|
+
# RedundantKeywordRestArgumentNames: kwargs, options, opts
|
103
|
+
# RedundantBlockArgumentNames: blk, block, proc
|
104
|
+
Style/ArgumentsForwarding:
|
105
|
+
Exclude:
|
106
|
+
- "lib/familia/horreum/class_methods.rb"
|
107
|
+
- "lib/familia/datatype/types/list.rb"
|
108
|
+
- "lib/familia/datatype/types/sorted_set.rb"
|
109
|
+
- "lib/familia/datatype/types/unsorted_set.rb"
|
110
|
+
- "lib/familia/refinements.rb"
|
111
|
+
|
112
|
+
# Offense count: 11
|
46
113
|
# Configuration parameters: AllowedConstants.
|
47
114
|
Style/Documentation:
|
48
115
|
Exclude:
|
49
|
-
-
|
50
|
-
-
|
51
|
-
-
|
52
|
-
-
|
53
|
-
-
|
54
|
-
-
|
55
|
-
-
|
56
|
-
-
|
116
|
+
- "spec/**/*"
|
117
|
+
- "test/**/*"
|
118
|
+
- "lib/familia/errors.rb"
|
119
|
+
- "lib/familia/horreum/class_methods.rb"
|
120
|
+
- "lib/familia/horreum/related_fields_management.rb"
|
121
|
+
- "lib/familia/datatype/types/hashkey.rb"
|
122
|
+
- "lib/familia/datatype/types/list.rb"
|
123
|
+
- "lib/familia/datatype/types/sorted_set.rb"
|
124
|
+
- "lib/familia/datatype/types/string.rb"
|
125
|
+
- "lib/familia/datatype/types/unsorted_set.rb"
|
126
|
+
- "lib/familia/version.rb"
|
127
|
+
|
128
|
+
# Offense count: 1
|
129
|
+
# This cop supports safe autocorrection (--autocorrect).
|
130
|
+
# Configuration parameters: AutoCorrect, EnforcedStyle, AllowComments.
|
131
|
+
# SupportedStyles: empty, nil, both
|
57
132
|
|
58
133
|
# Offense count: 2
|
59
134
|
# This cop supports safe autocorrection (--autocorrect).
|
60
|
-
# Configuration parameters: MaxUnannotatedPlaceholdersAllowed, AllowedMethods, AllowedPatterns.
|
135
|
+
# Configuration parameters: MaxUnannotatedPlaceholdersAllowed, Mode, AllowedMethods, AllowedPatterns.
|
61
136
|
# SupportedStyles: annotated, template, unannotated
|
62
137
|
Style/FormatStringToken:
|
63
138
|
EnforcedStyle: unannotated
|
139
|
+
|
140
|
+
# Offense count: 1
|
141
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
142
|
+
# Configuration parameters: EnforcedStyle.
|
143
|
+
# SupportedStyles: always, always_true, never
|
144
|
+
Style/FrozenStringLiteralComment:
|
145
|
+
Exclude:
|
146
|
+
- "**/*.arb"
|
147
|
+
- "lib/familia/horreum/related_fields_management.rb"
|
148
|
+
|
149
|
+
# Offense count: 1
|
150
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
151
|
+
Style/HashTransformValues:
|
152
|
+
Exclude:
|
153
|
+
- "lib/familia/datatype/types/hashkey.rb"
|
154
|
+
|
155
|
+
# Offense count: 1
|
156
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
157
|
+
# Configuration parameters: EnforcedStyle, Autocorrect.
|
158
|
+
# SupportedStyles: module_function, extend_self, forbidden
|
159
|
+
|
160
|
+
# Offense count: 1
|
161
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
162
|
+
# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns.
|
163
|
+
# SupportedStyles: predicate, comparison
|
164
|
+
Style/NumericPredicate:
|
165
|
+
Exclude:
|
166
|
+
- "spec/**/*"
|
167
|
+
- "lib/familia/horreum/class_methods.rb"
|
168
|
+
|
169
|
+
# Offense count: 1
|
170
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
171
|
+
|
172
|
+
# Offense count: 1
|
173
|
+
# This cop supports safe autocorrection (--autocorrect).
|
174
|
+
# Configuration parameters: EnforcedStyle.
|
175
|
+
# SupportedStyles: implicit, explicit
|
176
|
+
Style/RescueStandardError:
|
177
|
+
Exclude:
|
178
|
+
- "lib/familia/horreum.rb"
|
179
|
+
|
180
|
+
# Offense count: 1
|
181
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
182
|
+
# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength.
|
183
|
+
# AllowedMethods: present?, blank?, presence, try, try!
|
184
|
+
Style/SafeNavigation:
|
185
|
+
Exclude:
|
186
|
+
- "lib/familia/connection.rb"
|
187
|
+
|
188
|
+
# Offense count: 4
|
189
|
+
# Configuration parameters: ActiveSupportClassAttributeAllowed.
|
190
|
+
ThreadSafety/ClassAndModuleAttributes:
|
191
|
+
Exclude:
|
192
|
+
- "lib/familia/base.rb"
|
193
|
+
- "lib/familia/horreum.rb"
|
194
|
+
- "lib/middleware/database_middleware.rb"
|
195
|
+
|
196
|
+
# Offense count: 29
|
197
|
+
ThreadSafety/ClassInstanceVariable:
|
198
|
+
Exclude:
|
199
|
+
- "lib/familia/base.rb"
|
200
|
+
- "lib/familia/horreum/class_methods.rb"
|
201
|
+
- "lib/familia/version.rb"
|
202
|
+
|
203
|
+
# Offense count: 2
|
204
|
+
# This cop supports unsafe autocorrection (--autocorrect-all).
|
205
|
+
# Configuration parameters: EnforcedStyle.
|
206
|
+
# SupportedStyles: literals, strict
|
207
|
+
ThreadSafety/MutableClassInstanceVariable:
|
208
|
+
Exclude:
|
209
|
+
- "lib/familia/connection.rb"
|
data/.yardopts
ADDED
data/CLAUDE.md
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
# CLAUDE.md
|
2
|
+
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
4
|
+
|
5
|
+
## Development Commands
|
6
|
+
|
7
|
+
### Testing
|
8
|
+
- **Run tests**: `bundle exec tryouts` (uses tryouts testing framework)
|
9
|
+
- **Run specific test file**: `bundle exec tryouts try/specific_test_try.rb`
|
10
|
+
- **Debug mode**: `FAMILIA_DEBUG=1 bundle exec tryouts`
|
11
|
+
- **Trace mode**: `FAMILIA_TRACE=1 bundle exec tryouts` (detailed Redis operation logging)
|
12
|
+
|
13
|
+
### Development Setup
|
14
|
+
- **Install dependencies**: `bundle install`
|
15
|
+
- **Generate documentation**: `bundle exec yard`
|
16
|
+
- **Code linting**: `bundle exec rubocop`
|
17
|
+
|
18
|
+
### Known Issues & Quirks
|
19
|
+
- **Reserved Keywords**: Cannot use `ttl`, `db`, `redis` as field names - use prefixed alternatives
|
20
|
+
- **Empty Identifiers**: Cause stack overflow in key generation - validate before operations
|
21
|
+
- **Connection Pool Race Conditions**: Thread safety issues under high concurrency
|
22
|
+
- **Manual Key Sync**: `key` field doesn't auto-sync with identifier changes
|
23
|
+
- **RedisType Redis Parameter**: `:redis` parameter silently ignored (missing setter)
|
24
|
+
|
25
|
+
### Debugging
|
26
|
+
- **Database command logging**: `tail plop.log` - Real-time Database command monitoring
|
27
|
+
- Shows all Database operations with timestamps, database numbers, and full commands
|
28
|
+
- Updates live as tests run or code executes
|
29
|
+
- Essential for debugging Familia ORM Database interactions
|
30
|
+
|
31
|
+
### Testing Framework
|
32
|
+
This project uses `tryouts` instead of RSpec/Minitest. Test files are located in the `try/` directory and follow the pattern `*_try.rb`.
|
33
|
+
|
34
|
+
## Architecture Overview
|
35
|
+
|
36
|
+
### Core Components
|
37
|
+
|
38
|
+
**Familia**: A Valkey-compatible ORM library that provides Ruby object storage with advanced features like expiration, safe dumping, and quantization.
|
39
|
+
|
40
|
+
#### Primary Classes
|
41
|
+
1. **`Familia::Horreum`** - Base class for Valkey-backed objects (like ActiveRecord models)
|
42
|
+
- Located in `lib/familia/horreum.rb`
|
43
|
+
- Provides field definitions, data type relationships, and object lifecycle management
|
44
|
+
- Supports multiple identifier strategies: symbols, procs, arrays
|
45
|
+
|
46
|
+
2. **`Familia::DataType`** - Base class for Valkey data type wrappers
|
47
|
+
- Located in `lib/familia/datatype.rb`
|
48
|
+
- Provides String, List, Set, SortedSet, HashKey implementations
|
49
|
+
- Each type has its own class in `lib/familia/datatype/types/`
|
50
|
+
|
51
|
+
3. **`Familia::Base`** - Common module for both Horreum and DataType
|
52
|
+
- Located in `lib/familia/base.rb`
|
53
|
+
- Provides shared functionality and feature system
|
54
|
+
|
55
|
+
#### Feature System
|
56
|
+
Familia uses a modular feature system where features are mixed into classes:
|
57
|
+
- **Expiration** (`lib/familia/features/expiration.rb`) - TTL management with cascading
|
58
|
+
- **SafeDump** (`lib/familia/features/safe_dump.rb`) - API-safe object serialization
|
59
|
+
- **Quantization** (`lib/familia/features/quantization.rb`) - Time-based data bucketing
|
60
|
+
|
61
|
+
#### Key Architectural Patterns
|
62
|
+
|
63
|
+
**Inheritance Chain**: `MyClass < Familia::Horreum` automatically extends `ClassMethods` and `Features`
|
64
|
+
|
65
|
+
**DataType Definition**: Use class methods to define keystore database-backed attributes:
|
66
|
+
```ruby
|
67
|
+
class User < Familia::Horreum
|
68
|
+
field :email # Simple field
|
69
|
+
list :sessions # Valkey/Redis list
|
70
|
+
set :tags # Valkey/Redis set
|
71
|
+
zset :metrics # Valkey/Redis sorted set
|
72
|
+
hashkey :settings # Valkey/Redis hash
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
**Identifier Resolution**: Multiple strategies for object identification:
|
77
|
+
- Symbol: `identifier :email`
|
78
|
+
- Proc: `identifier ->(user) { "user:#{user.email}" }`
|
79
|
+
- Array: `identifier [:type, :email]`
|
80
|
+
|
81
|
+
### Directory Structure
|
82
|
+
|
83
|
+
- `lib/familia.rb` - Main entry point and module definition
|
84
|
+
- `lib/familia/horreum/` - Horreum class implementation (class_methods, commands, serialization, etc.)
|
85
|
+
- `lib/familia/datatype/` - Valkey/Redis type implementations and commands
|
86
|
+
- `lib/familia/features/` - Modular feature implementations
|
87
|
+
- `try/` - Test files using tryouts framework
|
88
|
+
- `try/test_helpers.rb` - Shared test utilities and sample classes
|
89
|
+
|
90
|
+
### Database Connection Management
|
91
|
+
- Connection handling in `lib/familia/connection.rb`
|
92
|
+
- Settings management in `lib/familia/settings.rb`
|
93
|
+
- Database selection via `logical_database` class method
|
94
|
+
- URI-based configuration support
|
95
|
+
|
96
|
+
### Important Implementation Notes
|
97
|
+
|
98
|
+
**Field Initialization**: Objects can be initialized with positional args (brittle) or keyword args (robust). Keyword args are recommended.
|
99
|
+
|
100
|
+
**Serialization**: Uses JSON by default but supports custom `serialize_value`/`deserialize_value` methods.
|
101
|
+
|
102
|
+
**Database Key Generation**: Automatic key generation using class name, identifier, and field/type names (aka dbkey). Pattern: `classname:identifier:fieldname`
|
103
|
+
|
104
|
+
**Memory Efficiency**: Only non-nil values are stored in keystore database to optimize memory usage.
|
105
|
+
|
106
|
+
**Thread Safety**: Data types are frozen after instantiation to ensure immutability.
|
107
|
+
|
108
|
+
## Common Patterns
|
109
|
+
|
110
|
+
### Defining a Horreum Class
|
111
|
+
```ruby
|
112
|
+
class Customer < Familia::Horreum
|
113
|
+
feature :safe_dump
|
114
|
+
feature :expiration
|
115
|
+
|
116
|
+
identifier_field :custid
|
117
|
+
default_expiration 5.years
|
118
|
+
|
119
|
+
field :custid
|
120
|
+
field :email
|
121
|
+
list :sessions
|
122
|
+
hashkey :settings
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
### Using Features
|
127
|
+
```ruby
|
128
|
+
# Safe dump for API responses
|
129
|
+
customer.safe_dump # Returns only whitelisted fields
|
130
|
+
|
131
|
+
# Expiration management
|
132
|
+
customer.update_expiration(default_expiration: 1.hour)
|
133
|
+
```
|
134
|
+
|
135
|
+
### Transaction Support
|
136
|
+
```ruby
|
137
|
+
customer.transaction do |conn|
|
138
|
+
conn.set("key1", "value1")
|
139
|
+
conn.zadd("key2", score, member)
|
140
|
+
end
|
141
|
+
```
|
data/Gemfile
CHANGED
@@ -1,15 +1,28 @@
|
|
1
|
-
#
|
1
|
+
# Gemfile
|
2
2
|
|
3
3
|
source 'https://rubygems.org'
|
4
4
|
|
5
5
|
gemspec
|
6
6
|
|
7
|
+
group :test do
|
8
|
+
if ENV['LOCAL_DEV']
|
9
|
+
gem 'tryouts', path: '../../d/tryouts'
|
10
|
+
else
|
11
|
+
gem 'tryouts', '~> 3.1.1', require: false
|
12
|
+
end
|
13
|
+
gem 'concurrent-ruby', '~> 1.3.5', require: false
|
14
|
+
gem 'ruby-prof'
|
15
|
+
gem 'stackprof'
|
16
|
+
end
|
17
|
+
|
18
|
+
|
7
19
|
group :development, :test do
|
8
20
|
# byebug only works with MRI
|
9
21
|
gem 'byebug', '~> 11.0', require: false if RUBY_ENGINE == 'ruby'
|
22
|
+
gem 'kramdown', require: false # Required for YARD markdown processing
|
10
23
|
gem 'pry-byebug', '~> 3.10.1', require: false if RUBY_ENGINE == 'ruby'
|
11
24
|
gem 'rubocop', require: false
|
12
25
|
gem 'rubocop-performance', require: false
|
13
26
|
gem 'rubocop-thread_safety', require: false
|
14
|
-
gem '
|
27
|
+
gem 'yard', '~> 0.9', require: false
|
15
28
|
end
|