diff --git a/Makefile b/Makefile index 61b39bc..7b76abb 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ build: run: make build && docker-compose up --build -test: +test-normal: go clean -testcache && go test ./... -coverprofile coverage/coverage.out test-race: diff --git a/coverage/coverage.out b/coverage/coverage.out index ec87e68..5f02b11 100644 --- a/coverage/coverage.out +++ b/coverage/coverage.out @@ -1,3139 +1 @@ mode: set -github.com/echovault/echovault/pkg/modules/acl/commands.go:34.108,35.34 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:35.34,37.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:38.2,39.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:39.9,41.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:42.2,42.67 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:42.67,44.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:45.2,45.42 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:48.106,49.19 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:49.19,51.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:53.2,54.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:54.9,56.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:58.2,60.30 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:60.30,61.27 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:61.27,64.9 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:68.2,68.16 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:68.16,70.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:73.2,77.18 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:77.18,79.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:79.8,81.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:82.2,82.21 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:82.21,84.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:85.2,85.17 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:85.17,87.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:89.2,90.29 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:90.29,92.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:95.2,96.51 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:96.51,97.22 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:97.22,99.12 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:101.3,101.49 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:103.2,103.51 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:103.51,104.22 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:104.22,106.12 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:108.3,108.49 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:112.2,113.48 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:113.48,114.21 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:114.21,116.12 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:118.3,118.47 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:120.2,120.48 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:120.48,121.21 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:121.21,123.12 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:125.3,125.47 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:129.2,130.79 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:130.79,131.37 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:131.37,133.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:135.2,136.30 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:136.30,137.10 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:138.100,140.53 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:141.53,143.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:144.52,146.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:151.2,153.54 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:153.54,155.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:156.2,156.54 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:156.54,158.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:160.2,162.25 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:165.102,166.18 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:166.18,168.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:170.2,174.35 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:174.35,175.36 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:175.36,176.48 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:176.48,178.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:179.4,179.12 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:181.3,181.50 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:181.50,182.51 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:182.51,185.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:189.2,189.19 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:189.19,192.34 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:192.34,195.4 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:196.3,197.28 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:197.28,199.24 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:199.24,201.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:203.3,203.26 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:206.2,206.19 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:206.19,208.46 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:208.46,209.43 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:209.43,211.38 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:211.38,213.30 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:213.30,215.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:217.5,217.28 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:222.2,222.74 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:225.102,227.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:227.9,229.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:230.2,231.33 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:231.33,233.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:234.2,235.25 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:238.106,240.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:240.9,242.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:243.2,243.45 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:243.45,245.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:246.2,246.42 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:249.108,250.18 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:250.18,252.3 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:253.2,254.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:254.9,256.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:257.2,257.53 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:257.53,259.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:260.2,260.42 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:263.106,265.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:265.9,267.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:268.2,269.74 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:272.103,273.18 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:273.18,275.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:276.2,277.9 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:277.9,279.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:280.2,282.33 3 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:282.33,285.19 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:285.19,287.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:287.9,289.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:291.3,291.22 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:291.22,293.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:295.3,295.18 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:295.18,297.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:299.3,299.43 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:299.43,300.61 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:300.61,302.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:303.4,303.58 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:303.58,305.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:308.3,308.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:308.52,309.23 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:309.23,311.13 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:313.4,313.39 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:316.3,316.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:316.52,317.23 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:317.23,319.13 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:321.4,321.39 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:324.3,324.49 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:324.49,325.22 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:325.22,327.13 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:329.4,329.37 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:332.3,332.49 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:332.49,333.22 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:333.22,335.13 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:337.4,337.37 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:340.3,340.45 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:340.45,341.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:341.52,343.13 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:345.4,345.41 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:348.3,348.45 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:348.45,349.52 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:349.52,351.5 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:354.3,354.55 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:354.55,356.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:358.3,358.55 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:358.55,360.4 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:361.3,361.54 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:364.2,365.25 2 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:368.103,369.19 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:369.19,371.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:373.2,374.9 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:374.9,376.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:378.2,382.16 4 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:382.16,384.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:386.2,386.15 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:386.15,387.35 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:387.35,389.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:392.2,396.20 3 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:396.20,397.59 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:397.59,399.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:402.2,402.37 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:402.37,403.59 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:403.59,405.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:409.2,409.29 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:409.29,413.31 3 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:413.31,414.35 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:414.35,417.43 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:417.43,419.6 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:419.11,422.6 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:423.5,423.10 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:427.3,427.17 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:427.17,429.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:432.2,432.42 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:435.103,436.18 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:436.18,438.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:440.2,441.9 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:441.9,443.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:445.2,449.16 4 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:449.16,451.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:453.2,453.15 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:453.15,454.35 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:454.35,456.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:459.2,461.20 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:461.20,464.17 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:464.17,466.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:467.3,468.17 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:468.17,470.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:473.2,473.37 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:473.37,476.17 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:476.17,478.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:479.3,480.17 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:480.17,482.4 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:485.2,486.16 2 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:486.16,488.3 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:490.2,490.42 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:493.33,501.68 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:501.68,507.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:516.68,522.5 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:531.70,537.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:546.70,552.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:561.70,567.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:576.70,582.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:591.70,597.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:606.70,612.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:621.70,627.7 1 1 -github.com/echovault/echovault/pkg/modules/acl/commands.go:639.70,645.7 1 0 -github.com/echovault/echovault/pkg/modules/acl/commands.go:654.70,660.7 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:30.105,32.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:32.16,34.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:36.2,38.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:38.33,41.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:43.2,43.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:43.52,45.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:46.2,48.63 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:48.63,50.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:52.2,52.57 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:55.107,57.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:57.16,59.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:61.2,64.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:64.9,66.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:68.2,68.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:68.33,70.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:72.2,72.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:72.52,74.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:75.2,78.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:78.9,80.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:82.2,82.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:82.40,84.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:86.2,86.57 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:89.107,91.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:91.16,93.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:95.2,99.24 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:99.24,101.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:103.2,103.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:103.33,105.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:107.2,107.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:107.52,109.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:110.2,113.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:113.9,115.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:118.2,118.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:118.40,120.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:123.2,123.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:123.51,125.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:127.2,130.15 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:130.15,132.43 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:132.43,135.4 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:136.3,136.20 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:140.2,140.18 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:140.18,142.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:147.2,151.17 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:151.17,153.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:155.2,155.13 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:155.13,158.18 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:158.18,160.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:160.9,162.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:165.2,165.19 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:168.105,170.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:170.16,172.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:174.2,177.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:177.9,179.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:181.2,181.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:181.33,183.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:185.2,185.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:185.51,187.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:188.2,191.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:191.9,193.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:195.2,195.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:195.40,197.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:199.2,200.55 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:200.55,202.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:204.2,204.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:207.106,209.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:209.16,211.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:213.2,217.24 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:217.24,219.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:221.2,221.30 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:221.30,223.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:225.2,225.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:225.33,227.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:229.2,229.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:229.51,231.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:232.2,235.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:235.9,237.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:239.2,239.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:239.40,241.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:243.2,243.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:243.34,244.64 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:244.64,246.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:247.3,247.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:250.2,250.66 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:250.66,252.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:253.2,253.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:256.105,258.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:258.16,260.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:262.2,266.9 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:266.9,268.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:270.2,272.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:272.33,274.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:276.2,276.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:276.51,278.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:279.2,282.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:282.9,284.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:286.2,286.9 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:287.10,287.10 0 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:289.17,291.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:291.34,292.26 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:292.26,293.10 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:295.4,295.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:295.43,298.5 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:300.17,302.39 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:302.39,303.26 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:303.26,304.10 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:306.4,306.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:306.43,309.5 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:313.2,313.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:313.61,315.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:317.2,317.55 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:317.55,319.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:321.2,321.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:324.106,326.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:326.16,328.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:330.2,334.116 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:334.116,336.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:338.2,338.75 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:338.75,340.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:342.2,342.54 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:342.54,344.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:345.2,348.16 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:348.16,350.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:351.2,356.33 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:356.33,358.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:360.2,360.19 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:361.14,363.24 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:363.24,365.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:365.9,365.32 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:365.32,367.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:368.15,370.24 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:370.24,372.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:372.9,372.32 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:372.32,374.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:377.2,377.16 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:377.16,379.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:381.2,381.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:384.106,386.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:386.16,388.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:390.2,392.31 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:392.31,394.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:396.2,398.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:398.33,399.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:400.17,401.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:402.11,403.62 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:403.62,405.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:406.4,406.68 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:406.68,408.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:410.8,411.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:411.52,413.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:415.2,420.9 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:420.9,422.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:424.2,424.73 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:424.73,426.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:427.2,427.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:430.106,432.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:432.16,434.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:436.2,440.31 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:440.31,442.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:444.2,444.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:444.33,445.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:446.17,447.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:448.11,449.62 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:449.62,451.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:452.4,453.68 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:453.68,455.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:457.8,458.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:458.52,460.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:461.3,461.35 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:464.2,468.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:468.9,470.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:472.2,472.73 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:472.73,474.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:475.2,475.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:478.104,480.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:480.16,482.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:484.2,486.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:486.33,488.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:490.2,490.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:490.51,492.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:493.2,496.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:496.9,498.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:500.2,500.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:501.10,502.60 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:502.60,504.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:505.3,505.54 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:506.14,507.70 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:507.70,509.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:510.3,510.64 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:514.33,634.2 1 0 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:23.59,24.18 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:24.18,26.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:27.2,31.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:34.57,35.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:35.19,37.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:38.2,42.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:45.58,46.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:46.19,48.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:49.2,53.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:56.60,57.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:57.19,59.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:60.2,64.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:67.60,68.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:68.19,70.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:71.2,75.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:78.58,79.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:79.19,81.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:82.2,86.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:89.59,90.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:90.19,92.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:93.2,97.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:100.58,101.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:101.19,103.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:104.2,108.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:111.59,112.18 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:112.18,114.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:115.2,119.8 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:122.59,123.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:123.19,125.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:126.2,130.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:36.104,38.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:38.16,40.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:42.2,48.16 6 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:48.16,50.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:54.2,54.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:54.16,55.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:55.34,57.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:57.9,59.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:62.2,62.44 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:62.44,64.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:64.34,66.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:67.3,67.36 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:68.8,68.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:68.51,70.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:70.33,72.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:73.3,73.45 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:74.8,76.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:76.34,79.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:79.9,82.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:84.2,84.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:84.16,86.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:87.2,89.76 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:89.76,91.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:94.2,94.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:94.28,96.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:98.2,98.17 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:101.105,103.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:103.16,105.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:107.2,110.15 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:110.15,111.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:111.29,112.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:112.16,118.5 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:123.2,123.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:123.30,124.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:124.15,129.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:134.2,134.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:134.28,135.31 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:135.31,136.52 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:136.52,138.5 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:139.4,140.12 2 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:142.3,142.60 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:142.60,144.4 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:145.3,145.55 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:149.2,149.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:149.28,150.58 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:150.58,152.4 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:155.2,155.42 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:158.104,160.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:160.16,162.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:163.2,165.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:165.33,167.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:169.2,170.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:170.16,172.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:173.2,177.51 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:180.105,182.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:182.16,184.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:186.2,189.36 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:189.36,190.31 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:190.31,192.12 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:194.3,194.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:194.33,196.18 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:196.18,198.5 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:199.4,200.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:202.3,202.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:204.2,204.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:204.15,205.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:205.34,206.14 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:206.14,209.5 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:213.2,213.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:213.28,215.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:217.2,219.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:219.30,220.24 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:220.24,222.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:224.3,224.96 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:227.2,227.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:230.104,232.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:232.16,234.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:235.2,236.37 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:236.37,238.17 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:238.17,240.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:242.3,242.13 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:244.2,244.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:247.108,249.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:249.16,251.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:253.2,255.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:255.33,257.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:259.2,259.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:259.51,261.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:262.2,265.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:265.31,267.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:269.2,271.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:274.111,276.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:276.16,278.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:280.2,282.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:282.33,284.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:286.2,286.52 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:286.52,288.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:289.2,293.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:293.31,295.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:297.2,298.46 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:298.46,300.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:302.2,302.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:305.104,307.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:307.16,309.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:311.2,315.33 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:315.33,317.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:319.2,319.52 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:319.52,321.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:322.2,326.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:326.31,328.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:330.2,331.39 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:331.39,333.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:335.2,335.12 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:335.12,337.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:339.2,339.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:342.107,344.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:344.16,346.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:348.2,352.16 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:352.16,354.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:355.2,356.42 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:356.42,358.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:360.2,360.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:360.33,362.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:364.2,364.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:364.51,366.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:367.2,369.19 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:369.19,372.3 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:374.2,376.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:377.12,378.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:378.39,380.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:381.3,381.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:382.12,383.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:383.39,385.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:386.3,386.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:387.12,388.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:388.39,390.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:391.3,391.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:391.39,393.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:394.3,394.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:395.12,396.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:396.39,397.40 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:397.40,399.5 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:400.4,400.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:402.3,402.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:403.10,404.71 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:407.2,407.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:410.109,412.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:412.16,414.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:416.2,420.16 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:420.16,422.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:423.2,424.44 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:424.44,426.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:428.2,428.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:428.33,430.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:432.2,432.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:432.51,434.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:435.2,437.19 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:437.19,440.3 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:442.2,444.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:445.12,446.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:446.39,448.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:449.3,449.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:450.12,451.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:451.39,453.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:454.3,454.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:455.12,456.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:456.39,458.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:459.3,459.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:459.39,461.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:462.3,462.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:463.12,464.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:464.39,465.40 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:465.40,467.5 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:468.4,468.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:470.3,470.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:471.10,472.71 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:475.2,475.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:478.33,647.2 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:23.57,24.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:24.34,26.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:27.2,31.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:34.58,35.25 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:35.25,37.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:38.2,39.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:39.30,40.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:40.15,42.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:44.2,48.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:51.57,52.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:52.19,54.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:55.2,59.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:62.58,63.18 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:63.18,65.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:66.2,70.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:73.57,74.18 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:74.18,76.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:77.2,81.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:84.61,85.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:85.19,87.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:88.2,92.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:95.64,96.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:96.19,98.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:99.2,103.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:106.57,107.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:107.19,109.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:110.2,114.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:117.60,118.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:118.34,120.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:121.2,125.8 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:128.62,129.34 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:129.34,131.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:132.2,136.8 1 0 -github.com/echovault/echovault/pkg/modules/generic/utils.go:32.96,33.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:33.19,35.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:36.2,36.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:37.13,39.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:41.12,42.26 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:42.26,44.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:45.3,46.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:48.12,49.26 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:49.26,51.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:52.3,53.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:55.12,56.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:56.19,58.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:59.3,59.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:59.29,61.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:62.3,64.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:64.17,66.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:67.3,68.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:70.12,71.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:71.19,73.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:74.3,74.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:74.29,76.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:77.3,79.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:79.17,81.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:82.3,83.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:85.14,86.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:86.19,88.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:89.3,89.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:89.29,91.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:92.3,94.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:94.17,96.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:97.3,98.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:100.14,101.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:101.19,103.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:104.3,104.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:104.29,106.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:107.3,109.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:109.17,111.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:112.3,113.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:115.10,116.95 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:31.105,33.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:33.16,35.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:37.2,40.25 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:40.25,42.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:44.2,44.38 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:44.38,46.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:48.2,48.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:48.33,50.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:50.17,52.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:53.3,54.59 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:54.59,56.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:57.3,57.59 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:60.2,60.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:60.51,62.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:63.2,66.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:66.9,68.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:70.2,71.36 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:71.36,72.42 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:72.42,73.26 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:73.26,76.5 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:77.4,77.12 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:79.3,80.13 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:82.2,82.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:82.55,84.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:86.2,86.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:89.105,91.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:91.16,93.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:95.2,98.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:98.33,100.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:102.2,102.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:102.52,104.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:105.2,108.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:108.9,110.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:112.2,115.31 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:115.31,117.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:117.19,119.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:121.3,121.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:121.34,123.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:125.3,125.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:125.31,127.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:129.3,129.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:129.35,132.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:134.3,134.32 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:137.2,137.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:140.108,142.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:142.16,144.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:146.2,149.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:149.33,151.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:153.2,153.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:153.52,155.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:156.2,159.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:159.9,161.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:163.2,166.31 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:166.31,168.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:168.19,170.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:172.3,172.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:172.34,174.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:176.3,176.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:176.35,179.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:181.3,181.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:181.31,183.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:185.3,185.18 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:188.2,188.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:191.106,193.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:193.16,195.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:197.2,199.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:199.33,201.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:203.2,203.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:203.52,205.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:206.2,209.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:209.9,211.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:213.2,214.27 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:214.27,215.32 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:215.32,217.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:219.3,219.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:219.33,222.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:224.3,224.29 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:224.29,226.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:229.2,229.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:232.111,234.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:234.16,236.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:238.2,241.19 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:241.19,243.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:243.17,245.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:246.3,246.13 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:246.13,248.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:249.3,249.12 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:252.2,253.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:253.19,254.46 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:254.46,256.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:256.9,258.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:261.2,261.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:261.33,263.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:265.2,265.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:265.52,267.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:268.2,271.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:271.9,273.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:276.2,276.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:276.24,278.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:278.17,280.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:281.3,281.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:281.34,283.18 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:283.18,284.36 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:284.36,286.14 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:288.5,288.37 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:288.37,291.14 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:293.5,293.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:293.33,295.14 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:299.3,299.26 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:303.2,304.29 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:304.29,306.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:309.2,311.46 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:311.46,315.16 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:315.16,316.59 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:316.59,318.5 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:322.2,323.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:323.16,325.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:326.2,326.38 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:326.38,328.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:328.17,329.41 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:329.41,331.13 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:333.4,333.42 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:333.42,336.13 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:338.4,338.38 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:338.38,340.13 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:345.2,345.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:348.105,350.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:350.16,352.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:354.2,356.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:356.33,358.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:360.2,360.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:360.52,362.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:363.2,366.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:366.9,368.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:370.2,370.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:373.106,375.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:375.16,377.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:379.2,381.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:381.33,383.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:385.2,385.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:385.52,387.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:388.2,391.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:391.9,393.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:395.2,396.29 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:396.29,398.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:400.2,400.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:403.108,405.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:405.16,407.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:409.2,415.47 5 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:415.47,417.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:417.17,419.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:420.3,420.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:421.8,423.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:423.17,425.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:426.3,426.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:429.2,429.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:429.33,430.62 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:430.62,432.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:433.3,435.48 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:435.48,437.57 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:437.57,439.5 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:440.4,440.96 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:441.9,443.57 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:443.57,445.5 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:446.4,446.60 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:450.2,450.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:450.52,452.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:453.2,456.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:456.9,458.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:460.2,460.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:460.24,462.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:464.2,464.28 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:465.10,466.69 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:467.11,469.48 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:469.48,471.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:471.9,473.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:474.15,476.48 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:476.48,478.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:478.9,480.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:483.2,483.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:483.55,485.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:487.2,487.40 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:487.40,489.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:491.2,492.47 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:495.108,497.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:497.16,499.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:501.2,503.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:503.33,505.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:507.2,507.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:507.52,509.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:510.2,513.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:513.9,515.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:517.2,518.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:518.33,520.34 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:520.34,522.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:523.3,523.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:523.35,526.4 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:527.3,527.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:527.31,529.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:532.2,532.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:535.108,537.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:537.16,539.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:541.2,544.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:544.33,546.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:548.2,548.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:548.52,550.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:551.2,554.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:554.9,556.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:558.2,558.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:558.24,560.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:562.2,562.30 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:565.105,567.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:567.16,569.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:571.2,574.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:574.33,576.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:578.2,578.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:578.51,580.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:581.2,584.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:584.9,586.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:588.2,590.31 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:590.31,591.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:591.25,594.4 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:597.2,597.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:597.55,599.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:601.2,601.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:604.33,725.2 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:23.58,24.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:24.18,26.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:27.2,31.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:34.60,35.18 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:35.18,37.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:38.2,42.8 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:45.58,46.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:46.18,48.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:49.2,53.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:56.61,57.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:57.18,59.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:60.2,64.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:67.59,68.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:68.19,70.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:71.2,75.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:78.64,79.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:79.34,81.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:82.2,82.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:82.19,88.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:89.2,93.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:96.58,97.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:97.19,99.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:100.2,104.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:107.59,108.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:108.19,110.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:111.2,115.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:118.61,119.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:119.19,121.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:122.2,126.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:129.61,130.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:130.19,132.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:133.2,137.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:140.61,141.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:141.19,143.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:144.2,148.8 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:151.58,152.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:152.18,154.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:155.2,159.8 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.68 1 0 -github.com/echovault/echovault/pkg/modules/connection/commands.go:45.68,51.5 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:125.72,127.23 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:127.23,129.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:130.2,131.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:131.16,133.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:134.2,134.45 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:138.56,140.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:140.16,142.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:143.2,143.45 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:154.65,157.18 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:157.18,159.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:159.8,161.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:163.2,163.21 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:163.21,165.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:167.2,167.17 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:167.17,169.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:171.2,171.21 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:171.21,173.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:175.2,175.20 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:175.20,177.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:179.2,179.20 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:179.20,181.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:183.2,183.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:183.24,185.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:187.2,187.50 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:187.50,189.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:191.2,191.53 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:191.53,193.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:195.2,195.49 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:195.49,197.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:199.2,199.52 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:199.52,201.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:203.2,203.50 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:203.50,205.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:207.2,207.50 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:207.50,209.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:211.2,211.47 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:211.47,213.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:215.2,215.47 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:215.47,217.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:219.2,219.48 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:219.48,221.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:223.2,223.43 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:223.43,225.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:227.2,227.44 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:227.44,229.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:231.2,231.47 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:231.47,233.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:235.2,235.47 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:235.47,237.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:239.2,240.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:240.16,242.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:244.2,244.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:291.84,293.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:293.16,295.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:297.2,299.16 3 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:299.16,301.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:303.2,306.35 3 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:306.35,312.35 4 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:312.35,314.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:317.2,317.20 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:327.75,330.16 3 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:330.16,332.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:333.2,333.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:337.55,339.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:339.16,341.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:342.2,342.45 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:353.75,355.9 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:356.21,357.29 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:358.23,359.31 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:360.10,361.31 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:364.2,365.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:365.16,367.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:369.2,369.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:375.53,377.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:377.16,379.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_acl.go:380.2,380.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:39.85,42.9 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:43.28,44.71 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:45.29,46.73 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:47.28,48.71 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:51.2,52.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:52.16,54.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:56.2,56.45 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:62.55,64.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:64.16,66.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:67.2,67.41 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:71.49,73.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:73.16,75.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:76.2,76.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:80.50,82.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:82.16,84.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:85.2,85.41 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:89.55,91.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:91.16,93.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_admin.go:94.2,94.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:87.85,90.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:91.18,92.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:93.18,94.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:97.2,97.9 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:98.23,99.65 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:100.23,101.65 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:102.25,103.69 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:104.25,105.69 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:108.2,108.17 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:108.17,110.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:112.2,113.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:113.16,115.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:117.2,117.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:132.74,135.28 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:135.28,137.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:139.2,140.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:140.16,142.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:144.2,144.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:155.58,157.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:157.16,159.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:160.2,160.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:171.65,173.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:173.16,175.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:176.2,176.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:186.59,188.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:188.16,190.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:191.2,191.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:202.60,204.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:204.16,206.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:207.2,207.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:217.62,219.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:219.16,221.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:222.2,222.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:232.63,234.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:234.16,236.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:237.2,237.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:247.55,249.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:249.16,251.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:252.2,252.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:262.56,264.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:264.16,266.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:267.2,267.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:282.94,285.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:286.18,287.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:288.18,289.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:290.18,291.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:292.18,293.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:296.2,297.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:297.16,299.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:301.2,301.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:316.101,319.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:320.18,321.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:322.18,323.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:324.18,325.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:326.18,327.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:330.2,331.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:331.16,333.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:335.2,335.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:350.102,353.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:354.18,355.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:356.18,357.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:358.18,359.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:360.18,361.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:364.2,365.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:365.16,367.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:369.2,369.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:384.109,387.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:388.18,389.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:390.18,391.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:392.18,393.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:394.18,395.26 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:398.2,399.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_generic.go:399.16,401.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_generic.go:403.2,403.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:46.91,49.36 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:49.36,51.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:53.2,54.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:54.16,56.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:58.2,58.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:76.93,79.36 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:79.36,81.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:83.2,84.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:84.16,86.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_hash.go:88.2,88.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:105.79,109.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:109.16,111.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:113.2,113.46 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:127.62,129.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:129.16,131.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:132.2,132.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:148.94,151.24 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:151.24,153.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:153.8,155.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:157.2,157.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:157.24,159.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:161.2,162.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:162.16,164.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:166.2,166.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:180.56,182.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:182.16,184.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:185.2,185.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:199.62,201.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:201.16,203.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:204.2,204.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:223.85,225.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:225.16,227.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:228.2,228.39 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:232.94,234.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:234.16,236.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_hash.go:237.2,237.39 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:252.64,254.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:254.16,256.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:257.2,257.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:273.67,275.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:275.16,277.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:278.2,278.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:294.74,297.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:297.16,299.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_hash.go:300.2,300.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:34.56,37.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:37.16,39.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:40.2,40.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:63.79,65.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:65.16,67.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:68.2,68.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:86.73,88.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:88.16,90.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:91.2,91.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:111.84,113.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:113.16,115.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:116.2,116.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:121.80,123.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:123.16,125.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:126.2,126.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:144.84,146.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:146.16,148.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:149.2,149.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:173.96,175.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:175.16,177.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:178.2,178.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:192.59,194.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:194.16,196.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:197.2,197.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:211.59,213.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:213.16,215.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:216.2,216.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:233.78,236.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:236.16,238.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_list.go:239.2,239.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:255.79,258.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:258.16,260.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:261.2,261.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:278.78,281.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:281.16,283.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_list.go:284.2,284.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:300.79,303.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:303.16,305.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_list.go:306.2,306.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:49.86,51.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:51.24,53.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:56.2,58.36 3 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:58.36,64.3 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:67.2,68.12 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:68.12,70.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:72.2,72.25 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:72.25,77.33 4 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:77.33,79.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:81.3,81.13 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:92.70,93.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:93.24,95.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:97.2,97.36 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:97.36,99.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:101.2,102.115 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:115.87,117.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:117.24,119.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:122.2,124.36 3 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:124.36,130.3 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:133.2,134.12 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:134.12,136.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:138.2,138.25 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:138.25,143.33 4 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:143.33,145.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:147.3,147.13 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:158.71,159.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:159.24,161.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:163.2,163.36 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:163.36,165.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:167.2,168.115 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:181.75,183.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:183.16,185.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:186.2,186.40 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:196.76,198.19 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:198.19,200.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:201.2,202.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:202.16,204.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:205.2,205.45 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:211.55,213.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:213.16,215.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:216.2,216.41 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:226.84,230.16 3 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:230.16,232.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:234.2,236.16 3 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:236.16,238.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:240.2,243.28 3 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:243.28,246.3 2 0 -github.com/echovault/echovault/pkg/echovault/api_pubsub.go:248.2,248.20 1 0 -github.com/echovault/echovault/pkg/echovault/api_set.go:36.75,39.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:39.16,41.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:42.2,42.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:56.57,58.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:58.16,60.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:61.2,61.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:78.66,81.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:81.16,83.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:84.2,84.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:89.86,92.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:92.16,94.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:95.2,95.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:112.67,115.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:115.16,117.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:118.2,118.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:136.77,138.15 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:138.15,140.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:141.2,142.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:142.16,144.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:145.2,145.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:150.87,153.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:153.16,155.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:156.2,156.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:172.70,174.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:174.16,176.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:177.2,177.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:191.65,193.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:193.16,195.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:196.2,196.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:213.84,216.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:216.16,218.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:219.2,219.46 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:241.82,243.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:243.16,245.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:246.2,246.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:262.73,264.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:264.16,266.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:267.2,267.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:284.79,286.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:286.16,288.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:289.2,289.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:305.75,308.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:308.16,310.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:311.2,311.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:326.67,329.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:329.16,331.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:332.2,332.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:337.87,340.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:340.16,342.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_set.go:343.2,343.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:102.87,104.28 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:104.28,105.17 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:105.17,107.18 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:107.18,109.5 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:110.4,111.12 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:113.3,113.23 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:115.2,115.20 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:118.85,120.28 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:120.28,122.17 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:122.17,124.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:125.3,126.17 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:126.17,128.18 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:128.18,130.5 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:131.4,131.24 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:134.2,134.20 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:158.105,161.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:162.18,163.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:164.18,165.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:168.2,168.9 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:169.18,170.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:171.18,172.26 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:175.2,175.16 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:175.16,177.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:179.2,179.18 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:179.18,181.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:183.2,183.37 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:183.37,185.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:187.2,188.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:188.16,190.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:192.2,192.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:206.57,208.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:208.16,210.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:211.2,211.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:229.76,237.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:237.16,239.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:240.2,240.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:258.93,260.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:260.16,262.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:263.2,264.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:264.16,266.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:268.2,269.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:269.16,271.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:273.2,273.45 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:290.86,293.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:293.16,295.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:296.2,296.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:313.99,316.30 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:316.30,318.45 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:318.45,320.4 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:323.2,323.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:323.29,325.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:327.2,327.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:327.24,329.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:331.2,332.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:332.16,334.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:336.2,337.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:337.16,339.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:341.2,341.53 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:360.114,363.30 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:363.30,365.42 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:365.42,367.4 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:370.2,370.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:370.29,372.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:374.2,374.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:374.24,376.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:378.2,379.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:379.16,381.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:383.2,383.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:400.99,403.30 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:403.30,405.42 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:405.42,407.4 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:410.2,410.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:410.29,412.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:414.2,414.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:414.24,416.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:418.2,419.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:419.16,421.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:423.2,424.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:424.16,426.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:428.2,428.53 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:447.114,450.30 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:450.30,452.42 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:452.42,454.4 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:457.2,457.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:457.29,459.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:461.2,461.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:461.24,463.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:465.2,466.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:466.16,468.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:470.2,470.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:489.97,492.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:492.16,494.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:495.2,496.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:496.16,498.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:499.2,499.15 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:516.89,519.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:520.19,521.27 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:522.19,523.27 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:524.10,525.27 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:528.2,528.9 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:529.26,530.76 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:531.10,532.59 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:535.2,536.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:536.16,538.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:540.2,540.51 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:558.88,560.33 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:560.33,562.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:564.2,565.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:565.16,567.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:569.2,570.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:570.16,572.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:574.2,575.24 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:575.24,576.14 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:576.14,578.12 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:580.3,581.17 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:581.17,583.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:584.3,584.20 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:587.2,587.20 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:607.71,610.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:610.16,612.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:613.2,613.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:632.78,634.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:634.16,636.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:637.2,637.51 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:656.78,658.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:658.16,660.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:661.2,661.51 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:685.98,687.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:687.16,689.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:690.2,690.16 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:690.16,692.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:694.2,695.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:695.16,697.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:699.2,699.51 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:720.101,722.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:722.16,724.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:726.2,727.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:727.16,729.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:731.2,733.19 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:733.19,735.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:737.2,738.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:738.16,740.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:742.2,744.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:744.16,746.17 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:746.17,748.4 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:749.3,749.13 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:752.2,752.17 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:757.104,759.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:759.16,761.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:763.2,764.16 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:764.16,766.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:768.2,770.46 2 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:787.81,790.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:790.16,792.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:794.2,795.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:795.16,797.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:799.2,799.11 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:799.11,801.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:803.2,804.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:804.16,806.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:808.2,808.19 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:824.75,826.33 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:826.33,828.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:829.2,830.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:830.16,832.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:833.2,833.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:851.94,860.16 3 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:860.16,862.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:864.2,864.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:884.109,887.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:888.23,889.31 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:890.21,891.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:892.10,893.31 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:896.2,896.24 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:896.24,898.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:900.2,900.47 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:900.47,902.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:904.2,905.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:905.16,907.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:909.2,910.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:910.16,912.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:914.2,914.53 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:936.120,939.9 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:940.23,941.31 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:942.21,943.29 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:944.10,945.31 1 0 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:948.2,948.47 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:948.47,950.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:952.2,953.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:953.16,955.3 1 1 -github.com/echovault/echovault/pkg/echovault/api_sorted_set.go:957.2,957.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:30.84,32.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:32.16,34.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_string.go:35.2,35.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:45.58,47.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:47.16,49.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_string.go:50.2,50.41 1 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:63.77,65.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:65.16,67.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_string.go:68.2,68.40 1 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:72.79,74.16 2 1 -github.com/echovault/echovault/pkg/echovault/api_string.go:74.16,76.3 1 0 -github.com/echovault/echovault/pkg/echovault/api_string.go:77.2,77.40 1 1 -github.com/echovault/echovault/pkg/echovault/cluster.go:25.45,27.2 1 1 -github.com/echovault/echovault/pkg/echovault/cluster.go:29.84,40.16 4 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:40.16,42.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:44.2,46.43 2 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:46.43,48.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:50.2,52.9 2 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:52.9,54.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:56.2,56.20 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:56.20,58.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:60.2,60.12 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:63.94,75.16 5 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:75.16,77.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:79.2,81.43 2 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:81.43,83.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:85.2,87.9 2 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:87.9,89.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:91.2,91.20 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:91.20,93.3 1 0 -github.com/echovault/echovault/pkg/echovault/cluster.go:95.2,95.24 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:99.66,100.36 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:100.36,102.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:108.66,109.36 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:109.36,111.3 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:117.72,118.36 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:118.36,120.3 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:125.78,136.33 2 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:136.33,138.3 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:140.2,151.29 4 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:151.29,160.49 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:160.49,162.44 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:162.44,163.46 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:163.46,165.7 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:167.5,167.17 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:170.3,178.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:179.8,190.65 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:190.65,192.44 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:192.44,193.46 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:193.46,195.7 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:197.5,197.17 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:199.72,201.67 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:201.67,203.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:204.5,204.68 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:204.68,206.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:207.5,208.34 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:212.3,218.60 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:218.60,220.44 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:220.44,221.46 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:221.46,223.7 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:225.5,225.17 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:227.68,229.67 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:229.67,231.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:232.5,232.69 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:232.69,234.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:235.5,236.34 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:238.51,240.19 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:240.19,242.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:248.2,248.61 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:248.61,249.13 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:249.13,250.8 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:250.8,252.83 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:252.83,254.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:259.2,259.69 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:259.69,261.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:263.2,263.29 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:263.29,267.36 3 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:267.36,269.4 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:272.2,272.30 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:272.30,275.34 2 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:275.34,277.18 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:277.18,279.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:283.3,283.71 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:283.71,285.18 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:285.18,287.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:291.2,291.23 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:294.37,303.16 4 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:303.16,305.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:307.2,307.15 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:307.15,310.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:312.2,312.27 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:312.27,314.15 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:314.15,316.4 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:316.9,318.4 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:320.3,321.49 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:321.49,323.18 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:323.18,325.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:326.4,326.42 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:329.3,332.16 3 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:332.16,334.37 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:334.37,336.19 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:336.19,338.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:339.5,340.19 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:340.19,342.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:343.5,343.61 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:343.61,345.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:349.3,353.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:357.2,357.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:357.6,359.17 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:359.17,361.12 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:364.3,364.35 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:368.58,370.23 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:370.23,372.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:374.2,380.6 4 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:380.6,383.43 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:383.43,386.9 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:389.3,389.17 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:389.17,391.9 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:394.3,396.43 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:396.43,397.9 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:400.3,400.17 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:400.17,401.87 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:401.87,403.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:404.4,404.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:407.3,410.20 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:410.20,411.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:414.3,414.28 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:414.28,416.12 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:420.3,421.7 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:421.7,423.41 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:423.41,425.19 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:425.19,427.6 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:428.5,428.10 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:430.4,431.21 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:431.21,432.10 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:434.4,434.27 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:438.2,438.37 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:438.37,440.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:448.34,450.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:453.47,454.38 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:454.38,456.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:458.2,458.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:458.12,459.27 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:459.27,461.53 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:461.53,463.5 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:464.4,464.10 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:467.3,467.62 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:467.62,469.4 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:472.2,472.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:476.49,478.2 1 1 -github.com/echovault/echovault/pkg/echovault/echovault.go:480.42,482.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:484.43,486.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:488.56,490.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:493.56,495.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:497.44,499.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:501.45,503.2 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:506.45,507.40 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:507.40,509.3 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:510.2,510.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:510.12,511.55 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:511.55,513.4 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:515.2,515.12 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:520.37,521.26 1 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:521.26,524.3 2 0 -github.com/echovault/echovault/pkg/echovault/echovault.go:527.45,544.2 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:37.81,40.34 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:40.34,43.3 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:45.2,45.6 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:45.6,46.10 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:47.11,48.35 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:48.35,50.5 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:51.4,52.10 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:52.10,54.5 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:55.21,56.36 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:65.67,66.39 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:66.39,68.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:76.82,79.34 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:79.34,82.3 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:84.2,84.6 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:84.6,85.10 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:86.11,87.35 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:87.35,89.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:90.4,91.10 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:91.10,93.5 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:94.21,95.36 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:104.68,105.39 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:105.39,107.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:115.74,117.9 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:117.9,119.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:121.2,121.82 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:121.82,122.28 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:122.28,125.18 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:125.18,127.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:128.9,128.64 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:128.64,131.18 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:131.18,133.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:134.9,134.65 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:134.65,139.4 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:141.3,141.15 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:144.2,144.13 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:152.90,153.115 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:153.115,155.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:157.2,160.33 3 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:160.33,171.3 5 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:173.2,173.33 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:178.80,179.58 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:179.58,181.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:182.2,182.32 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:189.93,190.115 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:190.115,192.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:194.2,200.16 3 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:200.16,202.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:204.2,204.27 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:204.27,206.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:208.2,208.12 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:213.79,214.58 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:214.58,216.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:217.2,217.35 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:226.101,234.55 3 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:234.55,236.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:237.2,240.11 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:240.11,242.17 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:242.17,244.4 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:250.51,259.97 4 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:259.97,261.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:269.60,271.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:271.6,272.83 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:272.83,274.9 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:277.2,278.33 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:278.33,280.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:281.2,282.13 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:289.75,290.52 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:290.52,292.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:295.2,302.9 4 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:303.108,304.36 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:305.108,306.36 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:309.2,311.12 2 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:316.82,318.83 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:318.83,320.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:322.2,322.34 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:322.34,324.3 1 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:325.2,325.55 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:326.28,329.36 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:330.28,333.36 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:334.29,337.50 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:337.50,339.4 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:340.29,343.50 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:343.50,345.4 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:347.2,347.54 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:347.54,349.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:350.2,350.12 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:354.71,356.34 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:356.34,358.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:361.2,364.50 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:364.50,366.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:368.2,370.50 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:370.50,372.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:376.2,376.9 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:377.125,382.7 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:382.7,384.40 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:384.40,386.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:388.4,389.29 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:389.29,391.54 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:391.54,393.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:394.10,394.65 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:394.65,396.63 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:396.63,398.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:402.4,405.52 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:405.52,407.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:409.125,414.7 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:414.7,416.40 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:416.40,418.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:420.4,421.29 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:421.29,423.54 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:423.54,425.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:426.10,426.65 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:426.65,429.63 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:429.63,431.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:435.4,438.52 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:438.52,440.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:442.105,445.7 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:445.7,447.33 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:447.33,450.5 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:452.4,453.40 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:453.40,454.17 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:454.17,455.31 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:455.31,457.56 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:457.56,459.8 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:460.12,460.67 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:460.67,461.65 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:461.65,463.8 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:466.6,469.54 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:469.54,471.7 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:473.5,473.10 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:476.106,479.7 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:479.7,486.29 5 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:486.29,488.54 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:488.54,490.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:491.10,491.65 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:491.65,492.63 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:492.63,494.6 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:498.4,501.52 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:501.52,503.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:505.10,506.13 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:515.77,517.57 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:517.57,519.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:521.2,526.50 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:526.50,528.3 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:529.2,536.33 6 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:536.33,537.7 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:537.7,541.35 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:541.35,543.10 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:547.2,550.25 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:550.25,551.52 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:551.52,552.12 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:556.3,556.57 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:556.57,558.12 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:562.3,564.28 3 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:564.28,565.51 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:565.51,567.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:568.9,568.64 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:568.64,569.60 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:569.60,571.5 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:576.2,576.21 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:576.21,579.3 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:581.2,584.58 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:584.58,588.3 2 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:590.2,590.12 1 0 -github.com/echovault/echovault/pkg/echovault/keyspace.go:593.68,597.2 3 1 -github.com/echovault/echovault/pkg/echovault/keyspace.go:599.74,604.2 4 1 -github.com/echovault/echovault/pkg/echovault/modules.go:28.59,30.2 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:32.47,34.2 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:36.50,38.2 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:40.72,41.42 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:41.42,42.46 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:42.46,44.4 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:46.2,46.69 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:49.137,51.16 2 1 -github.com/echovault/echovault/pkg/echovault/modules.go:51.16,53.3 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:55.2,56.16 2 1 -github.com/echovault/echovault/pkg/echovault/modules.go:56.16,58.3 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:60.2,64.8 4 1 -github.com/echovault/echovault/pkg/echovault/modules.go:64.8,67.3 2 0 -github.com/echovault/echovault/pkg/echovault/modules.go:69.2,69.51 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:69.51,72.87 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:72.87,74.4 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:78.2,78.50 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:78.50,79.7 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:79.7,80.42 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:80.42,82.10 2 1 -github.com/echovault/echovault/pkg/echovault/modules.go:87.2,87.43 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:87.43,89.17 2 1 -github.com/echovault/echovault/pkg/echovault/modules.go:89.17,91.4 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:93.3,93.62 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:93.62,95.4 1 1 -github.com/echovault/echovault/pkg/echovault/modules.go:97.3,99.18 2 1 -github.com/echovault/echovault/pkg/echovault/modules.go:103.2,103.32 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:103.32,106.17 3 0 -github.com/echovault/echovault/pkg/echovault/modules.go:106.17,108.4 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:109.3,109.18 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:113.2,113.34 1 0 -github.com/echovault/echovault/pkg/echovault/modules.go:113.34,116.3 2 0 -github.com/echovault/echovault/pkg/echovault/modules.go:118.2,118.72 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:29.111,35.29 4 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:35.29,36.54 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:36.54,42.42 4 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:42.42,44.5 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:46.4,49.12 3 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:52.3,52.36 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:52.36,59.43 5 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:59.43,61.5 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:63.4,65.21 2 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:69.2,71.25 2 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:74.109,78.35 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:78.35,79.65 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:79.65,80.41 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:80.41,82.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:83.4,83.12 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:85.3,85.13 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:88.2,88.51 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:91.110,92.18 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:93.9,98.36 4 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:98.36,99.66 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:99.66,100.52 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:100.52,104.6 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:105.5,105.13 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:107.4,108.14 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:110.3,111.26 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:113.9,117.45 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:117.45,119.4 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:120.3,120.42 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:120.42,124.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:124.37,125.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:125.67,126.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:126.53,127.59 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:127.59,131.8 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:133.6,133.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:135.5,135.54 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:135.54,138.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:140.9,140.50 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:140.50,144.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:144.37,145.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:145.67,146.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:146.53,148.24 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:148.24,151.8 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:153.6,153.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:155.5,155.33 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:155.33,158.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:160.9,160.49 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:160.49,164.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:164.37,165.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:165.67,166.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:166.53,167.55 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:167.55,171.8 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:173.6,173.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:175.5,175.50 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:175.50,178.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:180.9,182.4 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:183.3,184.26 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:185.10,186.54 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:190.103,192.2 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:194.33,202.68 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:202.68,208.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:217.68,223.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:231.70,237.7 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:246.70,252.7 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:262.70,268.7 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:279.68,285.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:286.113,287.49 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:287.49,289.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:290.5,290.45 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:299.68,305.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:306.113,308.18 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:308.18,310.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:311.5,311.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:320.68,326.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:327.113,328.47 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:328.47,330.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:331.5,331.45 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:28.113,30.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:30.9,32.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:34.2,36.24 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:36.24,38.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:40.2,43.17 3 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:46.115,48.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:48.9,50.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:52.2,56.66 3 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:59.108,61.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:61.9,63.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:64.2,64.19 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:64.19,66.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:67.2,68.42 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:71.113,72.18 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:72.18,74.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:76.2,77.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:77.9,79.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:81.2,82.19 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:82.19,84.3 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:86.2,86.38 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:89.109,91.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:91.9,93.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:94.2,95.49 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:98.112,100.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:100.9,102.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:103.2,103.36 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:106.33,114.68 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:114.68,116.21 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:116.21,118.6 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:119.5,123.11 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:133.68,135.21 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:135.21,137.6 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:138.5,142.11 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:152.68,154.22 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:154.22,156.6 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:157.5,161.11 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:173.68,180.5 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:191.68,197.5 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:206.68,212.5 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:213.101,215.5 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:225.70,231.7 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:240.70,246.7 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:256.70,262.7 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:30.105,32.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:32.16,34.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:36.2,40.33 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:40.33,42.70 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:42.70,44.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:45.3,45.55 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:45.55,47.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:48.3,49.59 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:52.2,52.51 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:52.51,54.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:55.2,58.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:58.9,60.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:62.2,64.51 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:67.106,69.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:69.16,71.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:73.2,75.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:75.33,77.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:79.2,79.52 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:79.52,81.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:82.2,85.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:85.9,87.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:89.2,91.57 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:94.106,96.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:96.16,98.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:101.2,101.46 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:101.46,103.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:104.2,104.65 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:104.65,106.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:107.2,109.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:109.9,111.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:113.2,114.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:114.15,115.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:115.34,116.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:116.14,118.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:122.2,122.40 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:122.40,123.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:123.34,124.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:126.3,126.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:126.53,127.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:129.3,129.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:132.2,133.30 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:133.30,135.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:135.10,136.12 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:138.3,138.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:141.2,145.26 4 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:145.26,147.24 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:147.24,149.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:152.2,152.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:155.111,157.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:157.16,159.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:161.2,164.46 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:164.46,166.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:167.2,167.66 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:167.66,169.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:170.2,172.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:172.9,174.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:176.2,177.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:177.15,178.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:178.34,179.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:179.14,181.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:185.2,185.40 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:185.40,186.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:186.34,187.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:189.3,189.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:189.53,190.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:192.3,192.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:195.2,196.40 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:196.40,198.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:198.10,199.12 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:201.3,201.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:204.2,209.40 4 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:209.40,210.60 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:210.60,212.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:213.3,213.64 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:213.64,215.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:216.3,217.26 2 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:220.2,220.68 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:220.68,222.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:223.2,223.63 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:223.63,225.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:226.2,228.25 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:231.107,233.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:233.16,235.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:237.2,238.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:238.15,239.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:239.34,240.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:240.14,242.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:246.2,246.36 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:246.36,247.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:247.34,250.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:251.3,251.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:251.53,253.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:254.3,254.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:257.2,259.28 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:259.28,261.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:261.10,264.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:265.3,265.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:268.2,268.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:268.20,270.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:272.2,276.26 4 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:276.26,278.24 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:278.24,280.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:283.2,283.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:286.111,288.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:288.16,290.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:293.2,294.56 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:294.56,296.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:297.2,297.35 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:297.35,299.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:300.2,300.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:300.20,302.27 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:302.27,304.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:306.3,306.60 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:306.60,308.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:308.9,310.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:313.2,314.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:314.15,315.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:315.34,316.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:316.14,318.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:322.2,322.36 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:322.36,323.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:323.34,326.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:327.3,327.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:327.53,329.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:330.3,330.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:333.2,335.28 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:335.28,337.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:337.10,340.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:341.3,341.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:344.2,344.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:344.20,346.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:348.2,350.69 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:353.112,355.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:355.16,357.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:359.2,360.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:360.15,361.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:361.34,362.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:362.14,364.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:368.2,368.36 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:368.36,369.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:369.34,372.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:373.3,373.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:373.53,375.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:376.3,376.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:379.2,381.28 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:381.28,383.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:383.10,386.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:387.3,387.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:390.2,393.40 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:393.40,394.60 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:394.60,396.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:397.8,398.69 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:398.69,400.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:403.2,403.68 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:403.68,405.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:406.2,408.69 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:411.110,413.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:413.16,415.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:417.2,419.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:419.33,421.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:423.2,423.52 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:423.52,425.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:426.2,429.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:429.9,431.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:433.2,433.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:433.27,435.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:437.2,437.30 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:440.109,442.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:442.16,444.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:446.2,448.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:448.33,450.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:452.2,452.52 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:452.52,454.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:455.2,458.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:458.9,460.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:462.2,465.26 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:465.26,467.24 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:467.24,469.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:472.2,472.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:475.111,477.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:477.16,479.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:481.2,484.33 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:484.33,486.29 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:486.29,488.27 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:488.27,490.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:492.3,492.26 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:495.2,495.52 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:495.52,497.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:498.2,501.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:501.9,503.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:505.2,506.36 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:506.36,507.31 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:507.31,509.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:509.9,511.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:513.2,515.25 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:518.106,520.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:520.16,522.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:524.2,527.36 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:527.36,529.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:531.2,531.54 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:531.54,533.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:534.2,537.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:537.9,539.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:541.2,543.41 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:543.41,545.69 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:545.69,547.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:548.3,550.74 3 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:550.74,552.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:553.8,555.61 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:555.61,557.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:558.3,560.10 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:560.10,562.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:563.3,563.22 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:566.2,568.49 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:571.105,573.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:573.16,575.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:577.2,580.19 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:580.19,582.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:582.10,584.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:585.3,585.12 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:588.2,588.33 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:588.33,590.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:592.2,592.51 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:592.51,594.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:595.2,598.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:598.9,600.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:602.2,605.28 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:605.28,607.26 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:607.26,609.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:612.2,612.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:615.112,617.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:617.16,619.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:621.2,624.19 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:624.19,626.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:626.10,628.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:629.3,629.12 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:632.2,632.33 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:632.33,634.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:636.2,636.51 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:636.51,638.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:639.2,642.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:642.9,644.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:646.2,649.28 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:649.28,651.26 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:651.26,653.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:656.2,656.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:659.105,661.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:661.16,663.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:665.2,668.33 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:668.33,670.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:672.2,672.51 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:672.51,674.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:675.2,678.9 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:678.9,680.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:682.2,684.51 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:687.107,689.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:689.16,691.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:693.2,694.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:694.15,695.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:695.34,696.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:696.14,698.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:702.2,702.36 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:702.36,703.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:703.34,704.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:706.3,706.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:706.53,708.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:709.3,709.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:712.2,714.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:714.33,715.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:715.14,716.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:718.3,719.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:719.10,721.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:722.3,722.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:725.2,728.35 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:728.35,730.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:730.33,732.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:735.2,735.25 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:738.112,740.16 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:740.16,742.3 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:744.2,745.15 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:745.15,746.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:746.34,747.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:747.14,749.5 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:753.2,753.36 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:753.36,754.34 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:754.34,755.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:757.3,757.53 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:757.53,759.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:760.3,760.20 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:763.2,765.33 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:765.33,766.14 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:766.14,767.12 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:769.3,770.10 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:770.10,772.4 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:773.3,773.27 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:776.2,780.40 3 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:780.40,781.60 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:781.60,783.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:784.8,785.69 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:785.69,787.4 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:789.2,791.64 2 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:791.64,793.3 1 0 -github.com/echovault/echovault/pkg/modules/set/commands.go:794.2,794.65 1 1 -github.com/echovault/echovault/pkg/modules/set/commands.go:797.33,948.2 1 0 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:25.58,26.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:26.18,28.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:29.2,33.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:36.59,37.19 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:37.19,39.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:40.2,44.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:47.59,48.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:48.18,50.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:51.2,55.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:58.64,59.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:59.18,61.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:62.2,66.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:69.60,70.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:70.18,72.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:73.2,77.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:80.64,81.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:81.18,83.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:85.2,85.56 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:85.56,87.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:89.2,89.20 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:89.20,95.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:97.2,101.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:104.65,105.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:105.18,107.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:108.2,112.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:115.63,116.19 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:116.19,118.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:119.2,123.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:126.62,127.19 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:127.19,129.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:130.2,134.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:137.64,138.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:138.18,140.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:141.2,145.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:148.59,149.19 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:149.19,151.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:152.2,156.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:159.58,160.34 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:160.34,162.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:163.2,167.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:170.65,171.34 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:171.34,173.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:174.2,178.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:181.58,182.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:182.18,184.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:185.2,189.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:192.60,193.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:193.18,195.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:196.2,200.8 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:203.65,204.18 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:204.18,206.3 1 1 -github.com/echovault/echovault/pkg/modules/set/key_funcs.go:207.2,211.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:33.105,35.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:35.16,37.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:39.2,48.32 7 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:48.32,49.29 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:49.29,50.9 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:52.3,52.44 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:53.15,54.74 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:54.74,56.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:57.16,58.25 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:59.12,60.25 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:64.2,64.66 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:64.66,66.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:68.2,70.52 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:70.52,71.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:71.15,72.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:74.3,75.23 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:76.11,77.64 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:78.15,80.49 2 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:80.49,86.5 2 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:87.4,87.49 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:87.49,93.5 2 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:94.16,99.6 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:100.12,105.6 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:110.2,110.27 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:110.27,112.34 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:112.34,113.70 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:113.70,116.61 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:116.61,118.6 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:119.5,119.13 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:121.4,121.70 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:121.70,125.36 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:125.36,127.6 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:128.5,128.13 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:130.4,130.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:130.39,132.13 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:134.4,134.41 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:134.41,137.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:137.25,139.6 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:140.5,140.13 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:142.4,142.55 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:146.2,146.32 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:146.32,149.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:149.17,151.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:152.3,154.10 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:154.10,156.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:157.3,158.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:158.17,160.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:162.3,162.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:162.18,165.4 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:167.3,167.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:171.2,171.60 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:171.60,173.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:174.2,177.54 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:177.54,179.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:181.2,181.63 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:184.106,186.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:186.16,188.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:189.2,191.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:191.33,193.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:195.2,195.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:195.52,197.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:198.2,201.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:201.9,203.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:205.2,205.63 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:208.107,210.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:210.16,212.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:214.2,217.43 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:218.10,219.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:220.14,221.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:221.40,223.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:223.9,225.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:226.15,228.32 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:229.11,231.32 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:234.2,235.43 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:236.10,237.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:238.14,239.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:239.40,241.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:241.9,243.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:244.15,246.32 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:247.11,249.32 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:252.2,252.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:252.33,254.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:256.2,256.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:256.52,258.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:259.2,262.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:262.9,264.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:266.2,267.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:267.33,268.47 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:268.47,270.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:273.2,273.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:276.110,278.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:278.16,280.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:282.2,286.33 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:286.33,288.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:290.2,290.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:290.52,292.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:293.2,296.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:296.9,298.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:300.2,303.38 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:303.38,304.45 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:304.45,306.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:309.2,311.28 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:311.28,313.81 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:313.81,315.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:318.2,318.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:321.106,323.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:323.16,325.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:327.2,327.63 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:327.63,329.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:330.2,330.49 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:330.49,332.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:334.2,335.15 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:335.15,336.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:336.34,337.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:337.14,339.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:344.2,344.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:344.46,347.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:348.2,348.65 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:348.65,350.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:351.2,353.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:353.9,355.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:358.2,360.42 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:360.42,361.47 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:361.47,362.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:364.3,365.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:365.17,367.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:368.3,370.10 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:370.10,372.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:373.3,373.27 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:376.2,381.34 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:381.34,382.20 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:382.20,384.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:384.9,386.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:389.2,391.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:394.111,396.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:396.16,398.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:400.2,403.15 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:403.15,404.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:404.34,405.14 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:405.14,407.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:412.2,412.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:412.46,415.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:416.2,416.65 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:416.65,418.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:419.2,421.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:421.9,423.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:425.2,427.42 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:427.42,428.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:428.46,429.67 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:429.67,431.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:432.4,433.11 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:433.11,435.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:436.4,436.28 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:440.2,442.40 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:442.40,443.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:443.60,445.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:446.8,447.69 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:447.69,449.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:451.2,453.63 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:453.63,455.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:457.2,457.64 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:460.108,462.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:462.16,464.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:466.2,470.43 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:471.10,472.55 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:473.14,474.57 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:474.57,476.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:476.9,476.64 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:476.64,478.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:478.9,480.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:481.15,483.34 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:484.11,486.34 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:489.2,489.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:489.33,492.61 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:492.61,494.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:495.3,499.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:499.17,501.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:502.3,503.99 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:506.2,506.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:506.51,508.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:509.2,511.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:511.9,513.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:514.2,520.23 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:520.23,522.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:523.2,524.74 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:527.107,529.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:529.16,531.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:533.2,534.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:534.16,536.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:538.2,539.15 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:539.15,540.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:540.34,541.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:541.14,543.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:547.2,549.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:549.33,550.38 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:550.38,553.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:554.3,554.57 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:554.57,556.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:557.3,559.10 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:559.10,561.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:562.3,565.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:568.2,572.33 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:572.33,573.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:573.40,574.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:574.18,576.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:576.10,578.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:582.2,584.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:587.112,589.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:589.16,591.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:593.2,596.51 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:596.51,598.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:600.2,601.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:601.16,603.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:605.2,606.15 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:606.15,607.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:607.34,608.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:608.14,610.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:614.2,616.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:616.33,617.38 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:617.38,619.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:620.3,620.57 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:620.57,622.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:623.3,625.10 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:625.10,627.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:628.3,631.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:634.2,636.71 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:636.71,637.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:637.60,639.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:640.8,640.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:640.40,641.69 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:641.69,643.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:645.2,647.68 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:647.68,649.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:651.2,651.69 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:654.106,656.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:656.16,658.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:660.2,665.56 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:665.56,667.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:668.2,668.20 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:668.20,669.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:669.19,671.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:672.3,672.29 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:672.29,674.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:675.3,676.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:676.17,678.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:679.3,679.13 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:679.13,681.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:682.3,683.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:687.2,687.57 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:687.57,689.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:690.2,690.21 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:690.21,691.20 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:691.20,693.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:694.3,695.53 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:695.53,697.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:700.2,700.43 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:700.43,701.47 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:701.47,702.67 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:702.67,703.13 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:705.4,706.35 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:706.35,708.13 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:710.4,711.18 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:711.18,714.5 2 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:715.4,719.38 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:719.38,721.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:723.4,725.27 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:729.2,729.30 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:732.105,734.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:734.16,736.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:738.2,742.42 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:742.42,744.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:746.2,746.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:746.19,748.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:748.17,750.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:751.3,751.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:751.12,753.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:756.2,756.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:756.33,758.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:760.2,760.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:760.51,762.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:763.2,766.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:766.9,768.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:770.2,771.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:771.16,773.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:775.2,776.36 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:776.36,778.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:780.2,782.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:785.108,787.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:787.16,789.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:791.2,793.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:793.33,795.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:797.2,797.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:797.52,799.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:800.2,803.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:803.9,805.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:807.2,813.36 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:813.36,815.21 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:815.21,817.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:817.9,819.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:822.2,824.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:827.112,829.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:829.16,831.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:833.2,836.19 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:836.19,838.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:838.17,840.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:841.3,841.13 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:841.13,843.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:846.2,847.19 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:847.19,848.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:848.46,850.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:850.9,852.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:855.2,855.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:855.33,857.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:859.2,859.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:859.52,861.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:862.2,865.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:865.9,867.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:869.2,872.28 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:872.28,873.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:873.17,875.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:875.9,877.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:880.2,882.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:885.106,887.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:887.16,889.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:891.2,895.62 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:895.62,897.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:899.2,899.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:899.33,901.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:903.2,903.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:903.52,905.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:906.2,909.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:909.9,911.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:913.2,914.65 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:914.65,915.44 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:915.44,917.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:918.3,918.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:921.2,921.36 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:921.36,922.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:922.51,923.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:923.18,926.5 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:926.10,928.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:932.2,932.31 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:935.105,937.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:937.16,939.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:941.2,943.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:943.33,945.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:947.2,947.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:947.51,949.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:950.2,953.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:953.9,955.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:957.2,958.28 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:958.28,959.38 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:959.38,961.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:964.2,964.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:967.107,969.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:969.16,971.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:973.2,975.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:975.33,977.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:978.2,978.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:978.52,980.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:981.2,983.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:983.9,985.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:986.2,987.20 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:987.20,989.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:991.2,993.69 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:996.117,998.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:998.16,1000.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1002.2,1007.16 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1007.16,1009.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1011.2,1012.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1012.16,1014.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1016.2,1016.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1016.33,1018.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1020.2,1020.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1020.51,1022.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1023.2,1026.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1026.9,1028.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1030.2,1030.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1030.33,1031.83 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1031.83,1034.4 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1037.2,1037.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1040.116,1042.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1042.16,1044.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1046.2,1049.16 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1049.16,1051.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1053.2,1054.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1054.16,1056.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1058.2,1058.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1058.33,1060.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1062.2,1062.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1062.51,1064.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1065.2,1068.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1068.9,1070.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1072.2,1072.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1072.15,1074.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1075.2,1075.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1075.14,1077.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1079.2,1079.88 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1079.88,1081.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1083.2,1084.65 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1084.65,1086.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1088.2,1090.18 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1090.18,1091.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1091.34,1094.4 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1095.8,1096.34 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1096.34,1099.4 2 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1102.2,1102.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1105.115,1107.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1107.16,1109.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1111.2,1115.33 4 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1115.33,1117.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1119.2,1119.51 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1119.51,1121.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1122.2,1125.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1125.9,1127.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1129.2,1132.38 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1132.38,1133.45 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1133.45,1135.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1138.2,1141.28 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1141.28,1143.81 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1143.81,1146.4 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1149.2,1149.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1152.107,1154.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1154.16,1156.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1158.2,1167.65 9 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1167.65,1169.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1171.2,1171.62 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1171.62,1173.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1175.2,1175.54 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1175.54,1177.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1177.5,1179.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1179.8,1182.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1182.17,1184.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1185.3,1186.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1186.17,1188.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1191.2,1191.54 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1191.54,1193.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1193.5,1194.61 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1194.61,1196.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1197.3,1197.50 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1197.50,1199.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1200.3,1201.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1201.17,1203.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1204.3,1204.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1204.17,1206.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1207.3,1208.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1208.17,1210.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1213.2,1213.33 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1213.33,1215.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1217.2,1217.52 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1217.52,1219.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1220.2,1223.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1223.9,1225.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1227.2,1227.32 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1227.32,1229.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1230.2,1230.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1230.15,1232.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1234.2,1235.42 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1235.42,1236.66 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1236.66,1238.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1238.15,1240.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1241.4,1241.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1244.2,1244.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1244.40,1246.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1246.39,1247.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1247.46,1249.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1251.3,1251.66 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1251.66,1252.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1252.15,1254.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1255.4,1255.64 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1259.2,1261.35 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1261.35,1262.24 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1262.24,1263.9 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1265.3,1265.43 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1265.43,1266.107 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1266.107,1268.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1269.4,1269.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1271.3,1272.90 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1272.90,1274.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1277.2,1279.34 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1279.34,1280.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1280.17,1282.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1282.9,1284.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1287.2,1289.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1292.112,1294.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1294.16,1296.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1298.2,1308.62 10 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1308.62,1310.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1312.2,1312.54 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1312.54,1314.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1314.5,1316.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1316.8,1319.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1319.17,1321.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1322.3,1323.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1323.17,1325.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1328.2,1328.54 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1328.54,1330.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1330.5,1331.61 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1331.61,1333.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1334.3,1334.50 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1334.50,1336.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1337.3,1338.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1338.17,1340.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1341.3,1341.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1341.17,1343.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1344.3,1345.17 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1345.17,1347.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1350.2,1350.36 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1350.36,1352.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1354.2,1354.55 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1354.55,1356.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1357.2,1360.9 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1360.9,1362.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1364.2,1364.32 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1364.32,1366.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1367.2,1367.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1367.15,1369.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1371.2,1372.42 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1372.42,1373.66 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1373.66,1375.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1375.15,1377.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1378.4,1378.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1381.2,1381.40 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1381.40,1383.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1383.39,1384.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1384.46,1386.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1388.3,1388.66 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1388.66,1389.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1389.15,1391.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1392.4,1392.64 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1396.2,1398.35 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1398.35,1399.24 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1399.24,1400.9 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1402.3,1402.43 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1402.43,1403.107 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1403.107,1405.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1406.4,1406.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1408.3,1409.90 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1409.90,1411.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1414.2,1416.40 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1416.40,1417.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1417.60,1419.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1420.8,1421.69 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1421.69,1423.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1425.2,1427.71 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1427.71,1429.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1431.2,1431.72 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1434.107,1435.46 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1435.46,1437.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1439.2,1440.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1440.16,1442.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1444.2,1445.15 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1445.15,1446.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1446.34,1447.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1447.14,1449.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1453.2,1455.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1455.33,1456.37 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1456.37,1457.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1457.58,1459.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1460.4,1462.11 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1462.11,1464.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1465.4,1468.6 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1472.2,1475.35 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1475.35,1476.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1476.17,1478.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1478.9,1480.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1483.2,1485.25 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1488.112,1490.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1490.16,1492.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1494.2,1497.51 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1497.51,1499.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1501.2,1502.16 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1502.16,1504.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1506.2,1507.15 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1507.15,1508.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1508.34,1509.14 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1509.14,1511.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1515.2,1517.33 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1517.33,1518.37 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1518.37,1519.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1519.58,1521.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1522.4,1524.11 3 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1524.11,1526.5 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1527.4,1530.6 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1534.2,1536.40 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1536.40,1537.60 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1537.60,1539.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1540.8,1541.69 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1541.69,1543.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1545.2,1547.64 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1547.64,1549.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1551.2,1551.65 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/commands.go:1554.33,1826.2 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:25.58,26.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:26.18,28.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:29.2,33.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:36.59,37.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:37.19,39.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:40.2,44.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:47.60,48.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:48.19,50.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:51.2,55.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:58.59,59.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:59.18,61.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:63.2,63.63 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:63.63,65.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:67.2,67.27 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:67.27,73.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:75.2,79.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:82.64,83.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:83.18,85.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:86.2,90.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:93.61,94.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:94.19,96.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:97.2,101.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:104.60,105.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:105.18,107.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:108.2,108.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:108.58,111.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:111.39,113.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:114.3,114.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:116.2,116.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:116.18,122.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:123.2,123.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:123.17,129.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:130.2,130.68 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:133.65,134.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:134.18,136.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:137.2,137.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:137.58,140.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:140.39,142.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:143.3,143.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:145.2,145.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:145.18,151.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:152.2,152.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:152.17,158.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:159.2,159.68 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:162.59,163.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:163.18,165.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:166.2,166.54 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:166.54,168.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:169.2,169.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:169.18,175.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:176.2,176.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:176.17,182.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:183.2,183.68 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:186.61,187.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:187.18,189.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:190.2,194.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:197.58,198.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:198.34,200.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:201.2,205.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:208.65,209.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:209.34,211.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:212.2,216.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:219.59,220.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:220.34,222.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:223.2,227.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:230.58,231.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:231.18,233.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:234.2,238.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:241.62,242.18 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:242.18,244.3 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:245.2,249.8 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:252.60,253.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:253.19,255.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:256.2,260.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:263.68,264.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:264.19,266.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:267.2,271.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:274.69,275.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:275.19,277.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:278.2,282.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:285.70,286.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:286.19,288.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:289.2,293.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:296.63,297.19 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:297.19,299.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:300.2,304.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:307.61,308.35 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:308.35,310.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:311.2,315.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:318.65,319.35 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:319.35,321.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:322.2,326.8 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:329.60,330.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:330.18,332.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:333.2,333.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:333.58,336.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:336.39,338.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:339.3,339.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:341.2,341.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:341.18,347.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:348.2,348.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:348.17,354.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:355.2,355.68 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:358.65,359.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:359.18,361.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:362.2,362.58 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:362.58,365.39 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:365.39,367.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:368.3,368.15 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:370.2,370.18 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:370.18,376.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:377.2,377.17 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:377.17,383.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/key_funcs.go:384.2,384.68 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:24.97,26.60 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:26.60,28.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:29.2,29.24 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:29.24,30.48 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:30.48,31.85 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:31.85,32.10 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:34.4,35.18 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:35.18,37.5 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:38.4,38.32 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:42.2,43.62 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:43.62,45.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:46.2,46.26 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:46.26,47.94 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:47.94,49.4 1 0 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:50.3,50.53 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:53.2,54.63 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:54.63,56.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:57.2,57.27 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:57.27,59.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:62.2,63.85 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:63.85,64.26 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:64.26,65.12 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:67.3,67.31 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:67.31,69.12 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:71.3,71.41 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:71.41,73.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:76.2,77.30 2 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:77.30,79.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:79.8,81.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:83.2,83.55 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:83.55,85.3 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:85.8,85.31 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:85.31,86.34 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:86.34,88.4 1 1 -github.com/echovault/echovault/pkg/modules/sorted_set/utils.go:91.2,91.50 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:27.109,29.16 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:29.16,31.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:33.2,36.9 3 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:36.9,38.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:40.2,42.33 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:42.33,43.61 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:43.61,45.4 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:46.3,46.58 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:46.58,48.4 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:49.3,50.58 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:53.2,53.52 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:53.52,55.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:56.2,59.9 3 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:59.9,61.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:64.2,64.24 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:64.24,66.58 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:66.58,68.4 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:69.3,69.58 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:73.2,73.16 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:73.16,75.58 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:75.58,77.4 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:78.3,78.58 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:81.2,83.35 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:83.35,85.24 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:85.24,88.12 3 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:91.3,92.8 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:95.2,95.67 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:95.67,97.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:99.2,99.59 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:102.110,104.16 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:104.16,106.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:108.2,110.33 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:110.33,112.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:114.2,114.53 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:114.53,116.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:117.2,121.9 3 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:121.9,123.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:125.2,125.56 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:128.107,130.16 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:130.16,132.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:134.2,140.24 5 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:140.24,142.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:144.2,144.33 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:144.33,146.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:148.2,148.52 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:148.52,150.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:151.2,154.9 3 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:154.9,156.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:158.2,158.15 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:158.15,160.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:161.2,161.13 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:161.13,163.3 1 0 -github.com/echovault/echovault/pkg/modules/string/commands.go:165.2,165.30 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:165.30,167.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:169.2,169.22 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:169.22,171.3 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:173.2,173.17 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:173.17,176.3 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:178.2,180.14 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:180.14,182.38 2 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:182.38,184.4 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:185.3,185.12 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:188.2,188.65 1 1 -github.com/echovault/echovault/pkg/modules/string/commands.go:191.33,231.2 1 0 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:23.62,24.19 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:24.19,26.3 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:27.2,31.8 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:34.60,35.19 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:35.19,37.3 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:38.2,42.8 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:45.60,46.19 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:46.19,48.3 1 1 -github.com/echovault/echovault/pkg/modules/string/key_funcs.go:49.2,53.8 1 1 diff --git a/internal/raft/fsm.go b/internal/raft/fsm.go index 7619dee..2de04d8 100644 --- a/internal/raft/fsm.go +++ b/internal/raft/fsm.go @@ -24,6 +24,7 @@ import ( "github.com/hashicorp/raft" "io" "log" + "net" "strings" ) @@ -36,6 +37,7 @@ type FSMOpts struct { StartSnapshot func() FinishSnapshot func() SetLatestSnapshotTime func(msec int64) + GetHandlerFuncParams func(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams } type FSM struct { @@ -86,34 +88,33 @@ func (fsm *FSM) Apply(log *raft.Log) interface{} { } case "command": - // TODO: Re-Implement Command handling with dependency injection // Handle command - // command, err := fsm.options.GetCommand(request.CMD[0]) - // if err != nil { - // return internal.ApplyResponse{ - // Error: err, - // Response: nil, - // } - // } - // - // handler := command.HandlerFunc - // - // subCommand, ok := internal.GetSubCommand(command, request.CMD).(types.SubCommand) - // if ok { - // handler = subCommand.HandlerFunc - // } - // - // if res, err := handler(ctx, request.CMD, fsm.options.EchoVault, nil); err != nil { - // return internal.ApplyResponse{ - // Error: err, - // Response: nil, - // } - // } else { - // return internal.ApplyResponse{ - // Error: nil, - // Response: res, - // } - // } + command, err := fsm.options.GetCommand(request.CMD[0]) + if err != nil { + return internal.ApplyResponse{ + Error: err, + Response: nil, + } + } + + handler := command.HandlerFunc + + subCommand, ok := internal.GetSubCommand(command, request.CMD).(types.SubCommand) + if ok { + handler = subCommand.HandlerFunc + } + + if res, err := handler(fsm.options.GetHandlerFuncParams(ctx, request.CMD, nil)); err != nil { + return internal.ApplyResponse{ + Error: err, + Response: nil, + } + } else { + return internal.ApplyResponse{ + Error: nil, + Response: res, + } + } } } diff --git a/internal/raft/raft.go b/internal/raft/raft.go index 3a11354..a6abbc6 100644 --- a/internal/raft/raft.go +++ b/internal/raft/raft.go @@ -41,6 +41,7 @@ type Opts struct { StartSnapshot func() FinishSnapshot func() SetLatestSnapshotTime func(msec int64) + GetHandlerFuncParams func(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams } type Raft struct { @@ -120,6 +121,7 @@ func (r *Raft) RaftInit(ctx context.Context) { StartSnapshot: r.options.StartSnapshot, FinishSnapshot: r.options.FinishSnapshot, SetLatestSnapshotTime: r.options.SetLatestSnapshotTime, + GetHandlerFuncParams: r.options.GetHandlerFuncParams, }), logStore, stableStore, diff --git a/pkg/echovault/echovault.go b/pkg/echovault/echovault.go index b56b742..70e69bf 100644 --- a/pkg/echovault/echovault.go +++ b/pkg/echovault/echovault.go @@ -157,6 +157,7 @@ func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) { StartSnapshot: echovault.startSnapshot, FinishSnapshot: echovault.finishSnapshot, SetLatestSnapshotTime: echovault.setLatestSnapshot, + GetHandlerFuncParams: echovault.getHandlerFuncParams, GetState: func() map[string]internal.KeyData { state := make(map[string]internal.KeyData) for k, v := range echovault.getState() { diff --git a/pkg/echovault/modules.go b/pkg/echovault/modules.go index 0f02e3e..9f8e44f 100644 --- a/pkg/echovault/modules.go +++ b/pkg/echovault/modules.go @@ -48,7 +48,6 @@ func (server *EchoVault) getCommand(cmd string) (types.Command, error) { func (server *EchoVault) getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { return types.HandlerFuncParams{ - // TODO: Add all the required methods here Context: ctx, Command: cmd, Connection: conn, @@ -60,6 +59,13 @@ func (server *EchoVault) getHandlerFuncParams(ctx context.Context, cmd []string, KeyRUnlock: server.KeyRUnlock, GetValue: server.GetValue, SetValue: server.SetValue, + GetClock: server.GetClock, + GetExpiry: server.GetExpiry, + SetExpiry: server.SetExpiry, + DeleteKey: server.DeleteKey, + GetPubSub: server.GetPubSub, + GetACL: server.GetACL, + GetAllCommands: server.GetAllCommands, } } diff --git a/pkg/modules/acl/commands.go b/pkg/modules/acl/commands.go index 2392cb8..68e05ba 100644 --- a/pkg/modules/acl/commands.go +++ b/pkg/modules/acl/commands.go @@ -15,7 +15,6 @@ package acl import ( - "context" "encoding/json" "errors" "fmt" @@ -24,33 +23,32 @@ import ( "github.com/echovault/echovault/pkg/types" "gopkg.in/yaml.v3" "log" - "net" "os" "path" "slices" "strings" ) -func handleAuth(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - if len(cmd) < 2 || len(cmd) > 3 { +func handleAuth(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) < 2 || len(params.Command) > 3 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } - if err := acl.AuthenticateConnection(ctx, conn, cmd); err != nil { + if err := acl.AuthenticateConnection(params.Context, params.Connection, params.Command); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleGetUser(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) != 3 { +func handleGetUser(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) != 3 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -58,7 +56,7 @@ func handleGetUser(_ context.Context, cmd []string, server types.EchoVault, _ *n var user *internal_acl.User userFound := false for _, u := range acl.Users { - if u.Username == cmd[2] { + if u.Username == params.Command[2] { user = u userFound = true break @@ -162,14 +160,14 @@ func handleGetUser(_ context.Context, cmd []string, server types.EchoVault, _ *n return []byte(res), nil } -func handleCat(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) > 3 { +func handleCat(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) > 3 { return nil, errors.New(constants.WrongArgsResponse) } categories := make(map[string][]string) - commands := server.GetAllCommands() + commands := params.GetAllCommands() for _, command := range commands { if len(command.SubCommands) == 0 { @@ -186,7 +184,7 @@ func handleCat(_ context.Context, cmd []string, server types.EchoVault, _ *net.C } } - if len(cmd) == 2 { + if len(params.Command) == 2 { var cats []string length := 0 for key, _ := range categories { @@ -203,10 +201,10 @@ func handleCat(_ context.Context, cmd []string, server types.EchoVault, _ *net.C return []byte(res), nil } - if len(cmd) == 3 { + if len(params.Command) == 3 { var res string for category, commands := range categories { - if strings.EqualFold(category, cmd[2]) { + if strings.EqualFold(category, params.Command[2]) { res = fmt.Sprintf("*%d", len(commands)) for i, command := range commands { res = fmt.Sprintf("%s\r\n+%s", res, command) @@ -219,11 +217,11 @@ func handleCat(_ context.Context, cmd []string, server types.EchoVault, _ *net.C } } - return nil, fmt.Errorf("category %s not found", strings.ToUpper(cmd[2])) + return nil, fmt.Errorf("category %s not found", strings.ToUpper(params.Command[2])) } -func handleUsers(_ context.Context, _ []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - acl, ok := server.GetACL().(*internal_acl.ACL) +func handleUsers(params types.HandlerFuncParams) ([]byte, error) { + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -235,45 +233,45 @@ func handleUsers(_ context.Context, _ []string, server types.EchoVault, _ *net.C return []byte(res), nil } -func handleSetUser(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - acl, ok := server.GetACL().(*internal_acl.ACL) +func handleSetUser(params types.HandlerFuncParams) ([]byte, error) { + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } - if err := acl.SetUser(cmd[2:]); err != nil { + if err := acl.SetUser(params.Command[2:]); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleDelUser(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) < 3 { +func handleDelUser(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) < 3 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } - if err := acl.DeleteUser(ctx, cmd[2:]); err != nil { + if err := acl.DeleteUser(params.Context, params.Command[2:]); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleWhoAmI(_ context.Context, _ []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - acl, ok := server.GetACL().(*internal_acl.ACL) +func handleWhoAmI(params types.HandlerFuncParams) ([]byte, error) { + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } - connectionInfo := acl.Connections[conn] + connectionInfo := acl.Connections[params.Connection] return []byte(fmt.Sprintf("+%s\r\n", connectionInfo.User.Username)), nil } -func handleList(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) > 2 { +func handleList(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) > 2 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -365,12 +363,12 @@ func handleList(_ context.Context, cmd []string, server types.EchoVault, _ *net. return []byte(res), nil } -func handleLoad(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) != 3 { +func handleLoad(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) != 3 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } @@ -414,7 +412,7 @@ func handleLoad(_ context.Context, cmd []string, server types.EchoVault, _ *net. if u.Username == user.Username { userFound = true // If we have a user with the current username and are in merge mode, merge the two users. - if strings.EqualFold(cmd[2], "merge") { + if strings.EqualFold(params.Command[2], "merge") { u.Merge(user) } else { // If we have a user with the current username and are in replace mode, merge the two users. @@ -432,12 +430,12 @@ func handleLoad(_ context.Context, cmd []string, server types.EchoVault, _ *net. return []byte(constants.OkResponse), nil } -func handleSave(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) > 2 { +func handleSave(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) > 2 { return nil, errors.New(constants.WrongArgsResponse) } - acl, ok := server.GetACL().(*internal_acl.ACL) + acl, ok := params.GetACL().(*internal_acl.ACL) if !ok { return nil, errors.New("could not load ACL") } diff --git a/pkg/modules/admin/commands.go b/pkg/modules/admin/commands.go index b1edf83..0ea5f15 100644 --- a/pkg/modules/admin/commands.go +++ b/pkg/modules/admin/commands.go @@ -15,19 +15,17 @@ package admin import ( - "context" "errors" "fmt" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "github.com/gobwas/glob" - "net" "slices" "strings" ) -func handleGetAllCommands(_ context.Context, _ []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - commands := server.GetAllCommands() +func handleGetAllCommands(params types.HandlerFuncParams) ([]byte, error) { + commands := params.GetAllCommands() res := "" commandCount := 0 @@ -71,10 +69,10 @@ func handleGetAllCommands(_ context.Context, _ []string, server types.EchoVault, return []byte(res), nil } -func handleCommandCount(_ context.Context, _ []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { +func handleCommandCount(params types.HandlerFuncParams) ([]byte, error) { var count int - commands := server.GetAllCommands() + commands := params.GetAllCommands() for _, command := range commands { if command.SubCommands != nil && len(command.SubCommands) > 0 { for _, _ = range command.SubCommands { @@ -88,13 +86,13 @@ func handleCommandCount(_ context.Context, _ []string, server types.EchoVault, _ return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - switch len(cmd) { +func handleCommandList(params types.HandlerFuncParams) ([]byte, error) { + switch len(params.Command) { case 2: // Command is COMMAND LIST var count int var res string - commands := server.GetAllCommands() + commands := params.GetAllCommands() for _, command := range commands { if command.SubCommands != nil && len(command.SubCommands) > 0 { for _, subcommand := range command.SubCommands { @@ -114,13 +112,13 @@ func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, var count int var res string // Command has filter - if !strings.EqualFold("FILTERBY", cmd[2]) { - return nil, fmt.Errorf("expected FILTERBY, got %s", strings.ToUpper(cmd[2])) + if !strings.EqualFold("FILTERBY", params.Command[2]) { + return nil, fmt.Errorf("expected FILTERBY, got %s", strings.ToUpper(params.Command[2])) } - if strings.EqualFold("ACLCAT", cmd[3]) { + if strings.EqualFold("ACLCAT", params.Command[3]) { // ACL Category filter - commands := server.GetAllCommands() - category := strings.ToLower(cmd[4]) + commands := params.GetAllCommands() + category := strings.ToLower(params.Command[4]) for _, command := range commands { if command.SubCommands != nil && len(command.SubCommands) > 0 { for _, subcommand := range command.SubCommands { @@ -137,10 +135,10 @@ func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, count += 1 } } - } else if strings.EqualFold("PATTERN", cmd[3]) { + } else if strings.EqualFold("PATTERN", params.Command[3]) { // Pattern filter - commands := server.GetAllCommands() - g := glob.MustCompile(cmd[4]) + commands := params.GetAllCommands() + g := glob.MustCompile(params.Command[4]) for _, command := range commands { if command.SubCommands != nil && len(command.SubCommands) > 0 { for _, subcommand := range command.SubCommands { @@ -157,10 +155,10 @@ func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, count += 1 } } - } else if strings.EqualFold("MODULE", cmd[3]) { + } else if strings.EqualFold("MODULE", params.Command[3]) { // Module filter - commands := server.GetAllCommands() - module := strings.ToLower(cmd[4]) + commands := params.GetAllCommands() + module := strings.ToLower(params.Command[4]) for _, command := range commands { if command.SubCommands != nil && len(command.SubCommands) > 0 { for _, subcommand := range command.SubCommands { @@ -178,7 +176,7 @@ func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, } } } else { - return nil, fmt.Errorf("expected filter to be ACLCAT or PATTERN, got %s", strings.ToUpper(cmd[3])) + return nil, fmt.Errorf("expected filter to be ACLCAT or PATTERN, got %s", strings.ToUpper(params.Command[3])) } res = fmt.Sprintf("*%d\r\n%s", count, res) return []byte(res), nil @@ -187,7 +185,7 @@ func handleCommandList(_ context.Context, cmd []string, server types.EchoVault, } } -func handleCommandDocs(_ context.Context, _ []string, _ types.EchoVault, _ *net.Conn) ([]byte, error) { +func handleCommandDocs(params types.HandlerFuncParams) ([]byte, error) { return []byte("*0\r\n"), nil } @@ -283,8 +281,8 @@ Allows for filtering by ACL category or glob pattern.`, WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - if err := server.TakeSnapshot(); err != nil { + HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) { + if err := params.TakeSnapshot(); err != nil { return nil, err } return []byte(constants.OkResponse), nil @@ -303,8 +301,8 @@ Allows for filtering by ACL category or glob pattern.`, WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - msec := server.GetLatestSnapshotTime() + HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) { + msec := params.GetLatestSnapshotTime() if msec == 0 { return nil, errors.New("no snapshot") } @@ -324,8 +322,8 @@ Allows for filtering by ACL category or glob pattern.`, WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - if err := server.RewriteAOF(); err != nil { + HandlerFunc: func(params types.HandlerFuncParams) ([]byte, error) { + if err := params.RewriteAOF(); err != nil { return nil, err } return []byte(constants.OkResponse), nil diff --git a/pkg/modules/connection/commands.go b/pkg/modules/connection/commands.go index f9eac58..1cfb887 100644 --- a/pkg/modules/connection/commands.go +++ b/pkg/modules/connection/commands.go @@ -15,29 +15,27 @@ package connection import ( - "context" "errors" "fmt" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" - "net" ) -func handlePing(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - switch len(cmd) { +func handlePing(params types.HandlerFuncParams) ([]byte, error) { + switch len(params.Command) { default: return nil, errors.New(constants.WrongArgsResponse) case 1: return []byte("+PONG\r\n"), nil case 2: - return []byte(fmt.Sprintf("$%d\r\n%s\r\n", len(cmd[1]), cmd[1])), nil + return []byte(fmt.Sprintf("$%d\r\n%s\r\n", len(params.Command[1]), params.Command[1])), nil } } func Commands() []types.Command { return []types.Command{ { - Command: "connection", + Command: "ping", Module: constants.ConnectionModule, Categories: []string{constants.FastCategory, constants.ConnectionCategory}, Description: "(PING [value]) Ping the echovault. If a value is provided, the value will be echoed.", diff --git a/pkg/modules/generic/commands.go b/pkg/modules/generic/commands.go index a9e454d..6db861e 100644 --- a/pkg/modules/generic/commands.go +++ b/pkg/modules/generic/commands.go @@ -15,14 +15,12 @@ package generic import ( - "context" "errors" "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "log" - "net" "strconv" "strings" "time" @@ -33,73 +31,73 @@ type KeyObject struct { locked bool } -func handleSet(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := setKeyFunc(cmd) +func handleSet(params types.HandlerFuncParams) ([]byte, error) { + keys, err := setKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - value := cmd[2] + value := params.Command[2] res := []byte(constants.OkResponse) - clock := server.GetClock() + clock := params.GetClock() - params, err := getSetCommandParams(clock, cmd[3:], SetParams{}) + options, err := getSetCommandOptions(clock, params.Command[3:], SetOptions{}) if err != nil { return nil, err } // If GET is provided, the response should be the current stored value. // If there's no current value, then the response should be nil. - if params.get { - if !server.KeyExists(ctx, key) { + if options.get { + if !params.KeyExists(params.Context, key) { res = []byte("$-1\r\n") } else { - res = []byte(fmt.Sprintf("+%v\r\n", server.GetValue(ctx, key))) + res = []byte(fmt.Sprintf("+%v\r\n", params.GetValue(params.Context, key))) } } - if "xx" == strings.ToLower(params.exists) { + if "xx" == strings.ToLower(options.exists) { // If XX is specified, make sure the key exists. - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, fmt.Errorf("key %s does not exist", key) } - _, err = server.KeyLock(ctx, key) - } else if "nx" == strings.ToLower(params.exists) { + _, err = params.KeyLock(params.Context, key) + } else if "nx" == strings.ToLower(options.exists) { // If NX is specified, make sure that the key does not currently exist. - if server.KeyExists(ctx, key) { + if params.KeyExists(params.Context, key) { return nil, fmt.Errorf("key %s already exists", key) } - _, err = server.CreateKeyAndLock(ctx, key) + _, err = params.CreateKeyAndLock(params.Context, key) } else { // Neither XX not NX are specified, lock or create the lock - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // Key does not exist, create it - _, err = server.CreateKeyAndLock(ctx, key) + _, err = params.CreateKeyAndLock(params.Context, key) } else { // Key exists, acquire the lock - _, err = server.KeyLock(ctx, key) + _, err = params.KeyLock(params.Context, key) } } if err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - if err = server.SetValue(ctx, key, internal.AdaptType(value)); err != nil { + if err = params.SetValue(params.Context, key, internal.AdaptType(value)); err != nil { return nil, err } // If expiresAt is set, set the key's expiry time as well - if params.expireAt != nil { - server.SetExpiry(ctx, key, params.expireAt.(time.Time), false) + if options.expireAt != nil { + params.SetExpiry(params.Context, key, options.expireAt.(time.Time), false) } return res, nil } -func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - _, err := msetKeyFunc(cmd) +func handleMSet(params types.HandlerFuncParams) ([]byte, error) { + _, err := msetKeyFunc(params.Command) if err != nil { return nil, err } @@ -110,7 +108,7 @@ func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne defer func() { for k, v := range entries { if v.locked { - server.KeyUnlock(ctx, k) + params.KeyUnlock(params.Context, k) entries[k] = KeyObject{ value: v.value, locked: false, @@ -120,10 +118,10 @@ func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne }() // Extract all the key/value pairs - for i, key := range cmd[1:] { + for i, key := range params.Command[1:] { if i%2 == 0 { entries[key] = KeyObject{ - value: internal.AdaptType(cmd[1:][i+1]), + value: internal.AdaptType(params.Command[1:][i+1]), locked: false, } } @@ -132,14 +130,14 @@ func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne // Acquire all the locks for each key first // If any key cannot be acquired, abandon transaction and release all currently held keys for k, v := range entries { - if server.KeyExists(ctx, k) { - if _, err := server.KeyLock(ctx, k); err != nil { + if params.KeyExists(params.Context, k) { + if _, err := params.KeyLock(params.Context, k); err != nil { return nil, err } entries[k] = KeyObject{value: v.value, locked: true} continue } - if _, err := server.CreateKeyAndLock(ctx, k); err != nil { + if _, err := params.CreateKeyAndLock(params.Context, k); err != nil { return nil, err } entries[k] = KeyObject{value: v.value, locked: true} @@ -147,7 +145,7 @@ func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne // Set all the values for k, v := range entries { - if err := server.SetValue(ctx, k, v.value); err != nil { + if err := params.SetValue(params.Context, k, v.value); err != nil { return nil, err } } @@ -155,30 +153,30 @@ func handleMSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(constants.OkResponse), nil } -func handleGet(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := getKeyFunc(cmd) +func handleGet(params types.HandlerFuncParams) ([]byte, error) { + keys, err := getKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - _, err = server.KeyRLock(ctx, key) + _, err = params.KeyRLock(params.Context, key) if err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - value := server.GetValue(ctx, key) + value := params.GetValue(params.Context, key) return []byte(fmt.Sprintf("+%v\r\n", value)), nil } -func handleMGet(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := mgetKeyFunc(cmd) +func handleMGet(params types.HandlerFuncParams) ([]byte, error) { + keys, err := mgetKeyFunc(params.Command) if err != nil { return nil, err } @@ -191,8 +189,8 @@ func handleMGet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne // Skip if we have already locked this key continue } - if server.KeyExists(ctx, key) { - _, err = server.KeyRLock(ctx, key) + if params.KeyExists(params.Context, key) { + _, err = params.KeyRLock(params.Context, key) if err != nil { return nil, fmt.Errorf("could not obtain lock for %s key", key) } @@ -204,19 +202,19 @@ func handleMGet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) locks[key] = false } } }() for key, _ := range locks { - values[key] = fmt.Sprintf("%v", server.GetValue(ctx, key)) + values[key] = fmt.Sprintf("%v", params.GetValue(params.Context, key)) } - bytes := []byte(fmt.Sprintf("*%d\r\n", len(cmd[1:]))) + bytes := []byte(fmt.Sprintf("*%d\r\n", len(params.Command[1:]))) - for _, key := range cmd[1:] { + for _, key := range params.Command[1:] { if values[key] == "" { bytes = append(bytes, []byte("$-1\r\n")...) continue @@ -227,14 +225,14 @@ func handleMGet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return bytes, nil } -func handleDel(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := delKeyFunc(cmd) +func handleDel(params types.HandlerFuncParams) ([]byte, error) { + keys, err := delKeyFunc(params.Command) if err != nil { return nil, err } count := 0 for _, key := range keys.WriteKeys { - err = server.DeleteKey(ctx, key) + err = params.DeleteKey(params.Context, key) if err != nil { log.Printf("could not delete key %s due to error: %+v\n", key, err) continue @@ -244,91 +242,91 @@ func handleDel(ctx context.Context, cmd []string, server types.EchoVault, _ *net return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handlePersist(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := persistKeyFunc(cmd) +func handlePersist(params types.HandlerFuncParams) ([]byte, error) { + keys, err := persistKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - expireAt := server.GetExpiry(ctx, key) + expireAt := params.GetExpiry(params.Context, key) if expireAt == (time.Time{}) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, time.Time{}, false) + params.SetExpiry(params.Context, key, time.Time{}, false) return []byte(":1\r\n"), nil } -func handleExpireTime(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := expireTimeKeyFunc(cmd) +func handleExpireTime(params types.HandlerFuncParams) ([]byte, error) { + keys, err := expireTimeKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":-2\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - expireAt := server.GetExpiry(ctx, key) + expireAt := params.GetExpiry(params.Context, key) if expireAt == (time.Time{}) { return []byte(":-1\r\n"), nil } t := expireAt.Unix() - if strings.ToLower(cmd[0]) == "pexpiretime" { + if strings.ToLower(params.Command[0]) == "pexpiretime" { t = expireAt.UnixMilli() } return []byte(fmt.Sprintf(":%d\r\n", t)), nil } -func handleTTL(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := ttlKeyFunc(cmd) +func handleTTL(params types.HandlerFuncParams) ([]byte, error) { + keys, err := ttlKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - clock := server.GetClock() + clock := params.GetClock() - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":-2\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - expireAt := server.GetExpiry(ctx, key) + expireAt := params.GetExpiry(params.Context, key) if expireAt == (time.Time{}) { return []byte(":-1\r\n"), nil } t := expireAt.Unix() - clock.Now().Unix() - if strings.ToLower(cmd[0]) == "pttl" { + if strings.ToLower(params.Command[0]) == "pttl" { t = expireAt.UnixMilli() - clock.Now().UnixMilli() } @@ -339,8 +337,8 @@ func handleTTL(ctx context.Context, cmd []string, server types.EchoVault, _ *net return []byte(fmt.Sprintf(":%d\r\n", t)), nil } -func handleExpire(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := expireKeyFunc(cmd) +func handleExpire(params types.HandlerFuncParams) ([]byte, error) { + keys, err := expireKeyFunc(params.Command) if err != nil { return nil, err } @@ -348,42 +346,42 @@ func handleExpire(ctx context.Context, cmd []string, server types.EchoVault, _ * key := keys.WriteKeys[0] // Extract time - n, err := strconv.ParseInt(cmd[2], 10, 64) + n, err := strconv.ParseInt(params.Command[2], 10, 64) if err != nil { return nil, errors.New("expire time must be integer") } - expireAt := server.GetClock().Now().Add(time.Duration(n) * time.Second) - if strings.ToLower(cmd[0]) == "pexpire" { - expireAt = server.GetClock().Now().Add(time.Duration(n) * time.Millisecond) + expireAt := params.GetClock().Now().Add(time.Duration(n) * time.Second) + if strings.ToLower(params.Command[0]) == "pexpire" { + expireAt = params.GetClock().Now().Add(time.Duration(n) * time.Millisecond) } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - if len(cmd) == 3 { - server.SetExpiry(ctx, key, expireAt, true) + if len(params.Command) == 3 { + params.SetExpiry(params.Context, key, expireAt, true) return []byte(":1\r\n"), nil } - currentExpireAt := server.GetExpiry(ctx, key) + currentExpireAt := params.GetExpiry(params.Context, key) - switch strings.ToLower(cmd[3]) { + switch strings.ToLower(params.Command[3]) { case "nx": if currentExpireAt != (time.Time{}) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "xx": if currentExpireAt == (time.Time{}) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "gt": if currentExpireAt == (time.Time{}) { return []byte(":0\r\n"), nil @@ -391,24 +389,24 @@ func handleExpire(ctx context.Context, cmd []string, server types.EchoVault, _ * if expireAt.Before(currentExpireAt) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "lt": if currentExpireAt != (time.Time{}) { if currentExpireAt.Before(expireAt) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) default: - return nil, fmt.Errorf("unknown option %s", strings.ToUpper(cmd[3])) + return nil, fmt.Errorf("unknown option %s", strings.ToUpper(params.Command[3])) } return []byte(":1\r\n"), nil } -func handleExpireAt(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := expireKeyFunc(cmd) +func handleExpireAt(params types.HandlerFuncParams) ([]byte, error) { + keys, err := expireKeyFunc(params.Command) if err != nil { return nil, err } @@ -416,42 +414,42 @@ func handleExpireAt(ctx context.Context, cmd []string, server types.EchoVault, _ key := keys.WriteKeys[0] // Extract time - n, err := strconv.ParseInt(cmd[2], 10, 64) + n, err := strconv.ParseInt(params.Command[2], 10, 64) if err != nil { return nil, errors.New("expire time must be integer") } expireAt := time.Unix(n, 0) - if strings.ToLower(cmd[0]) == "pexpireat" { + if strings.ToLower(params.Command[0]) == "pexpireat" { expireAt = time.UnixMilli(n) } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - if len(cmd) == 3 { - server.SetExpiry(ctx, key, expireAt, true) + if len(params.Command) == 3 { + params.SetExpiry(params.Context, key, expireAt, true) return []byte(":1\r\n"), nil } - currentExpireAt := server.GetExpiry(ctx, key) + currentExpireAt := params.GetExpiry(params.Context, key) - switch strings.ToLower(cmd[3]) { + switch strings.ToLower(params.Command[3]) { case "nx": if currentExpireAt != (time.Time{}) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "xx": if currentExpireAt == (time.Time{}) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "gt": if currentExpireAt == (time.Time{}) { return []byte(":0\r\n"), nil @@ -459,17 +457,17 @@ func handleExpireAt(ctx context.Context, cmd []string, server types.EchoVault, _ if expireAt.Before(currentExpireAt) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) case "lt": if currentExpireAt != (time.Time{}) { if currentExpireAt.Before(expireAt) { return []byte(":0\r\n"), nil } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) } - server.SetExpiry(ctx, key, expireAt, false) + params.SetExpiry(params.Context, key, expireAt, false) default: - return nil, fmt.Errorf("unknown option %s", strings.ToUpper(cmd[3])) + return nil, fmt.Errorf("unknown option %s", strings.ToUpper(params.Command[3])) } return []byte(":1\r\n"), nil diff --git a/pkg/modules/generic/utils.go b/pkg/modules/generic/utils.go index 17a3f5d..3e5b215 100644 --- a/pkg/modules/generic/utils.go +++ b/pkg/modules/generic/utils.go @@ -23,96 +23,96 @@ import ( "time" ) -type SetParams struct { +type SetOptions struct { exists string get bool expireAt interface{} // Exact expireAt time un unix milliseconds } -func getSetCommandParams(clock clock.Clock, cmd []string, params SetParams) (SetParams, error) { +func getSetCommandOptions(clock clock.Clock, cmd []string, options SetOptions) (SetOptions, error) { if len(cmd) == 0 { - return params, nil + return options, nil } switch strings.ToLower(cmd[0]) { case "get": - params.get = true - return getSetCommandParams(clock, cmd[1:], params) + options.get = true + return getSetCommandOptions(clock, cmd[1:], options) case "nx": - if params.exists != "" { - return SetParams{}, fmt.Errorf("cannot specify NX when %s is already specified", strings.ToUpper(params.exists)) + if options.exists != "" { + return SetOptions{}, fmt.Errorf("cannot specify NX when %s is already specified", strings.ToUpper(options.exists)) } - params.exists = "NX" - return getSetCommandParams(clock, cmd[1:], params) + options.exists = "NX" + return getSetCommandOptions(clock, cmd[1:], options) case "xx": - if params.exists != "" { - return SetParams{}, fmt.Errorf("cannot specify XX when %s is already specified", strings.ToUpper(params.exists)) + if options.exists != "" { + return SetOptions{}, fmt.Errorf("cannot specify XX when %s is already specified", strings.ToUpper(options.exists)) } - params.exists = "XX" - return getSetCommandParams(clock, cmd[1:], params) + options.exists = "XX" + return getSetCommandOptions(clock, cmd[1:], options) case "ex": if len(cmd) < 2 { - return SetParams{}, errors.New("seconds value required after EX") + return SetOptions{}, errors.New("seconds value required after EX") } - if params.expireAt != nil { - return SetParams{}, errors.New("cannot specify EX when expiry time is already set") + if options.expireAt != nil { + return SetOptions{}, errors.New("cannot specify EX when expiry time is already set") } secondsStr := cmd[1] seconds, err := strconv.ParseInt(secondsStr, 10, 64) if err != nil { - return SetParams{}, errors.New("seconds value should be an integer") + return SetOptions{}, errors.New("seconds value should be an integer") } - params.expireAt = clock.Now().Add(time.Duration(seconds) * time.Second) - return getSetCommandParams(clock, cmd[2:], params) + options.expireAt = clock.Now().Add(time.Duration(seconds) * time.Second) + return getSetCommandOptions(clock, cmd[2:], options) case "px": if len(cmd) < 2 { - return SetParams{}, errors.New("milliseconds value required after PX") + return SetOptions{}, errors.New("milliseconds value required after PX") } - if params.expireAt != nil { - return SetParams{}, errors.New("cannot specify PX when expiry time is already set") + if options.expireAt != nil { + return SetOptions{}, errors.New("cannot specify PX when expiry time is already set") } millisecondsStr := cmd[1] milliseconds, err := strconv.ParseInt(millisecondsStr, 10, 64) if err != nil { - return SetParams{}, errors.New("milliseconds value should be an integer") + return SetOptions{}, errors.New("milliseconds value should be an integer") } - params.expireAt = clock.Now().Add(time.Duration(milliseconds) * time.Millisecond) - return getSetCommandParams(clock, cmd[2:], params) + options.expireAt = clock.Now().Add(time.Duration(milliseconds) * time.Millisecond) + return getSetCommandOptions(clock, cmd[2:], options) case "exat": if len(cmd) < 2 { - return SetParams{}, errors.New("seconds value required after EXAT") + return SetOptions{}, errors.New("seconds value required after EXAT") } - if params.expireAt != nil { - return SetParams{}, errors.New("cannot specify EXAT when expiry time is already set") + if options.expireAt != nil { + return SetOptions{}, errors.New("cannot specify EXAT when expiry time is already set") } secondsStr := cmd[1] seconds, err := strconv.ParseInt(secondsStr, 10, 64) if err != nil { - return SetParams{}, errors.New("seconds value should be an integer") + return SetOptions{}, errors.New("seconds value should be an integer") } - params.expireAt = time.Unix(seconds, 0) - return getSetCommandParams(clock, cmd[2:], params) + options.expireAt = time.Unix(seconds, 0) + return getSetCommandOptions(clock, cmd[2:], options) case "pxat": if len(cmd) < 2 { - return SetParams{}, errors.New("milliseconds value required after PXAT") + return SetOptions{}, errors.New("milliseconds value required after PXAT") } - if params.expireAt != nil { - return SetParams{}, errors.New("cannot specify PXAT when expiry time is already set") + if options.expireAt != nil { + return SetOptions{}, errors.New("cannot specify PXAT when expiry time is already set") } millisecondsStr := cmd[1] milliseconds, err := strconv.ParseInt(millisecondsStr, 10, 64) if err != nil { - return SetParams{}, errors.New("milliseconds value should be an integer") + return SetOptions{}, errors.New("milliseconds value should be an integer") } - params.expireAt = time.UnixMilli(milliseconds) - return getSetCommandParams(clock, cmd[2:], params) + options.expireAt = time.UnixMilli(milliseconds) + return getSetCommandOptions(clock, cmd[2:], options) default: - return SetParams{}, fmt.Errorf("unknown option %s for set command", strings.ToUpper(cmd[0])) + return SetOptions{}, fmt.Errorf("unknown option %s for set command", strings.ToUpper(cmd[0])) } } diff --git a/pkg/modules/hash/commands.go b/pkg/modules/hash/commands.go index 3399db3..c8b74b3 100644 --- a/pkg/modules/hash/commands.go +++ b/pkg/modules/hash/commands.go @@ -15,21 +15,19 @@ package hash import ( - "context" "errors" "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "math/rand" - "net" "slices" "strconv" "strings" ) -func handleHSET(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hsetKeyFunc(cmd) +func handleHSET(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hsetKeyFunc(params.Command) if err != nil { return nil, err } @@ -37,39 +35,39 @@ func handleHSET(ctx context.Context, cmd []string, server types.EchoVault, _ *ne key := keys.WriteKeys[0] entries := make(map[string]interface{}) - if len(cmd[2:])%2 != 0 { + if len(params.Command[2:])%2 != 0 { return nil, errors.New("each field must have a corresponding value") } - for i := 2; i <= len(cmd)-2; i += 2 { - entries[cmd[i]] = internal.AdaptType(cmd[i+1]) + for i := 2; i <= len(params.Command)-2; i += 2 { + entries[params.Command[i]] = internal.AdaptType(params.Command[i+1]) } - if !server.KeyExists(ctx, key) { - _, err = server.CreateKeyAndLock(ctx, key) + if !params.KeyExists(params.Context, key) { + _, err = params.CreateKeyAndLock(params.Context, key) if err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) - if err = server.SetValue(ctx, key, entries); err != nil { + defer params.KeyUnlock(params.Context, key) + if err = params.SetValue(params.Context, key, entries); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", len(entries))), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } count := 0 for field, value := range entries { - if strings.EqualFold(cmd[0], "hsetnx") { + if strings.EqualFold(params.Command[0], "hsetnx") { if hash[field] == nil { hash[field] = value count += 1 @@ -79,32 +77,32 @@ func handleHSET(ctx context.Context, cmd []string, server types.EchoVault, _ *ne hash[field] = value count += 1 } - if err = server.SetValue(ctx, key, hash); err != nil { + if err = params.SetValue(params.Context, key, hash); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleHGET(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hgetKeyFunc(cmd) +func handleHGET(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hgetKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - fields := cmd[2:] + fields := params.Command[2:] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -137,25 +135,25 @@ func handleHGET(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(res), nil } -func handleHSTRLEN(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hstrlenKeyFunc(cmd) +func handleHSTRLEN(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hstrlenKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - fields := cmd[2:] + fields := params.Command[2:] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -188,24 +186,24 @@ func handleHSTRLEN(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(res), nil } -func handleHVALS(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hvalsKeyFunc(cmd) +func handleHVALS(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hvalsKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -229,8 +227,8 @@ func handleHVALS(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(res), nil } -func handleHRANDFIELD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hrandfieldKeyFunc(cmd) +func handleHRANDFIELD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hrandfieldKeyFunc(params.Command) if err != nil { return nil, err } @@ -238,8 +236,8 @@ func handleHRANDFIELD(ctx context.Context, cmd []string, server types.EchoVault, key := keys.ReadKeys[0] count := 1 - if len(cmd) >= 3 { - c, err := strconv.Atoi(cmd[2]) + if len(params.Command) >= 3 { + c, err := strconv.Atoi(params.Command[2]) if err != nil { return nil, errors.New("count must be an integer") } @@ -250,24 +248,24 @@ func handleHRANDFIELD(ctx context.Context, cmd []string, server types.EchoVault, } withvalues := false - if len(cmd) == 4 { - if strings.EqualFold(cmd[3], "withvalues") { + if len(params.Command) == 4 { + if strings.EqualFold(params.Command[3], "withvalues") { withvalues = true } else { return nil, errors.New("result modifier must be withvalues") } } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -345,24 +343,24 @@ func handleHRANDFIELD(ctx context.Context, cmd []string, server types.EchoVault, return []byte(res), nil } -func handleHLEN(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hlenKeyFunc(cmd) +func handleHLEN(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hlenKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -370,24 +368,24 @@ func handleHLEN(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(fmt.Sprintf(":%d\r\n", len(hash))), nil } -func handleHKEYS(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hkeysKeyFunc(cmd) +func handleHKEYS(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hkeysKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -400,59 +398,59 @@ func handleHKEYS(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(res), nil } -func handleHINCRBY(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hincrbyKeyFunc(cmd) +func handleHINCRBY(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hincrbyKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - field := cmd[2] + field := params.Command[2] var intIncrement int var floatIncrement float64 - if strings.EqualFold(cmd[0], "hincrbyfloat") { - f, err := strconv.ParseFloat(cmd[3], 64) + if strings.EqualFold(params.Command[0], "hincrbyfloat") { + f, err := strconv.ParseFloat(params.Command[3], 64) if err != nil { return nil, errors.New("increment must be a float") } floatIncrement = f } else { - i, err := strconv.Atoi(cmd[3]) + i, err := strconv.Atoi(params.Command[3]) if err != nil { return nil, errors.New("increment must be an integer") } intIncrement = i } - if !server.KeyExists(ctx, key) { - if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + if !params.KeyExists(params.Context, key) { + if _, err := params.CreateKeyAndLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) hash := make(map[string]interface{}) - if strings.EqualFold(cmd[0], "hincrbyfloat") { + if strings.EqualFold(params.Command[0], "hincrbyfloat") { hash[field] = floatIncrement - if err = server.SetValue(ctx, key, hash); err != nil { + if err = params.SetValue(params.Context, key, hash); err != nil { return nil, err } return []byte(fmt.Sprintf("+%s\r\n", strconv.FormatFloat(floatIncrement, 'f', -1, 64))), nil } else { hash[field] = intIncrement - if err = server.SetValue(ctx, key, hash); err != nil { + if err = params.SetValue(params.Context, key, hash); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", intIncrement)), nil } } - if _, err := server.KeyLock(ctx, key); err != nil { + if _, err := params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -466,21 +464,21 @@ func handleHINCRBY(ctx context.Context, cmd []string, server types.EchoVault, _ return nil, fmt.Errorf("value at field %s is not a number", field) case int: i, _ := hash[field].(int) - if strings.EqualFold(cmd[0], "hincrbyfloat") { + if strings.EqualFold(params.Command[0], "hincrbyfloat") { hash[field] = float64(i) + floatIncrement } else { hash[field] = i + intIncrement } case float64: f, _ := hash[field].(float64) - if strings.EqualFold(cmd[0], "hincrbyfloat") { + if strings.EqualFold(params.Command[0], "hincrbyfloat") { hash[field] = f + floatIncrement } else { hash[field] = f + float64(intIncrement) } } - if err = server.SetValue(ctx, key, hash); err != nil { + if err = params.SetValue(params.Context, key, hash); err != nil { return nil, err } @@ -492,24 +490,24 @@ func handleHINCRBY(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(fmt.Sprintf(":%d\r\n", i)), nil } -func handleHGETALL(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hgetallKeyFunc(cmd) +func handleHGETALL(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hgetallKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -532,25 +530,25 @@ func handleHGETALL(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(res), nil } -func handleHEXISTS(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hexistsKeyFunc(cmd) +func handleHEXISTS(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hexistsKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - field := cmd[2] + field := params.Command[2] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -562,25 +560,25 @@ func handleHEXISTS(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(":0\r\n"), nil } -func handleHDEL(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := hdelKeyFunc(cmd) +func handleHDEL(params types.HandlerFuncParams) ([]byte, error) { + keys, err := hdelKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - fields := cmd[2:] + fields := params.Command[2:] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - hash, ok := server.GetValue(ctx, key).(map[string]interface{}) + hash, ok := params.GetValue(params.Context, key).(map[string]interface{}) if !ok { return nil, fmt.Errorf("value at %s is not a hash", key) } @@ -594,7 +592,7 @@ func handleHDEL(ctx context.Context, cmd []string, server types.EchoVault, _ *ne } } - if err = server.SetValue(ctx, key, hash); err != nil { + if err = params.SetValue(params.Context, key, hash); err != nil { return nil, err } diff --git a/pkg/modules/list/commands.go b/pkg/modules/list/commands.go index 145dc1c..0d3bf1e 100644 --- a/pkg/modules/list/commands.go +++ b/pkg/modules/list/commands.go @@ -15,65 +15,63 @@ package list import ( - "context" "errors" "fmt" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "math" - "net" "slices" "strings" ) -func handleLLen(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := llenKeyFunc(cmd) +func handleLLen(params types.HandlerFuncParams) ([]byte, error) { + keys, err := llenKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // If key does not exist, return 0 return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - if list, ok := server.GetValue(ctx, key).([]interface{}); ok { + if list, ok := params.GetValue(params.Context, key).([]interface{}); ok { return []byte(fmt.Sprintf(":%d\r\n", len(list))), nil } return nil, errors.New("LLEN command on non-list item") } -func handleLIndex(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lindexKeyFunc(cmd) +func handleLIndex(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lindexKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - index, ok := internal.AdaptType(cmd[2]).(int) + index, ok := internal.AdaptType(params.Command[2]).(int) if !ok { return nil, errors.New("index must be an integer") } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, errors.New("LINDEX command on non-list item") } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - list, ok := server.GetValue(ctx, key).([]interface{}) - server.KeyRUnlock(ctx, key) + list, ok := params.GetValue(params.Context, key).([]interface{}) + params.KeyRUnlock(params.Context, key) if !ok { return nil, errors.New("LINDEX command on non-list item") @@ -86,30 +84,30 @@ func handleLIndex(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(fmt.Sprintf("+%s\r\n", list[index])), nil } -func handleLRange(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lrangeKeyFunc(cmd) +func handleLRange(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lrangeKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - start, startOk := internal.AdaptType(cmd[2]).(int) - end, endOk := internal.AdaptType(cmd[3]).(int) + start, startOk := internal.AdaptType(params.Command[2]).(int) + end, endOk := internal.AdaptType(params.Command[3]).(int) if !startOk || !endOk { return nil, errors.New("start and end indices must be integers") } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, errors.New("LRANGE command on non-list item") } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - list, ok := server.GetValue(ctx, key).([]interface{}) + list, ok := params.GetValue(params.Context, key).([]interface{}) if !ok { return nil, errors.New("LRANGE command on non-list item") } @@ -165,29 +163,29 @@ func handleLRange(ctx context.Context, cmd []string, server types.EchoVault, _ * return bytes, nil } -func handleLSet(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lsetKeyFunc(cmd) +func handleLSet(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lsetKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - index, ok := internal.AdaptType(cmd[2]).(int) + index, ok := internal.AdaptType(params.Command[2]).(int) if !ok { return nil, errors.New("index must be an integer") } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, errors.New("LSET command on non-list item") } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - list, ok := server.GetValue(ctx, key).([]interface{}) + list, ok := params.GetValue(params.Context, key).([]interface{}) if !ok { return nil, errors.New("LSET command on non-list item") } @@ -196,23 +194,23 @@ func handleLSet(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return nil, errors.New("index must be within list range") } - list[index] = internal.AdaptType(cmd[3]) - if err = server.SetValue(ctx, key, list); err != nil { + list[index] = internal.AdaptType(params.Command[3]) + if err = params.SetValue(params.Context, key, list); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleLTrim(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := ltrimKeyFunc(cmd) +func handleLTrim(params types.HandlerFuncParams) ([]byte, error) { + keys, err := ltrimKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - start, startOk := internal.AdaptType(cmd[2]).(int) - end, endOk := internal.AdaptType(cmd[3]).(int) + start, startOk := internal.AdaptType(params.Command[2]).(int) + end, endOk := internal.AdaptType(params.Command[3]).(int) if !startOk || !endOk { return nil, errors.New("start and end indices must be integers") @@ -222,16 +220,16 @@ func handleLTrim(ctx context.Context, cmd []string, server types.EchoVault, _ *n return nil, errors.New("end index must be greater than start index or -1") } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, errors.New("LTRIM command on non-list item") } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - list, ok := server.GetValue(ctx, key).([]interface{}) + list, ok := params.GetValue(params.Context, key).([]interface{}) if !ok { return nil, errors.New("LTRIM command on non-list item") } @@ -241,44 +239,44 @@ func handleLTrim(ctx context.Context, cmd []string, server types.EchoVault, _ *n } if end == -1 || end > len(list) { - if err = server.SetValue(ctx, key, list[start:]); err != nil { + if err = params.SetValue(params.Context, key, list[start:]); err != nil { return nil, err } return []byte(constants.OkResponse), nil } - if err = server.SetValue(ctx, key, list[start:end]); err != nil { + if err = params.SetValue(params.Context, key, list[start:end]); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleLRem(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lremKeyFunc(cmd) +func handleLRem(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lremKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - value := cmd[3] + value := params.Command[3] - count, ok := internal.AdaptType(cmd[2]).(int) + count, ok := internal.AdaptType(params.Command[2]).(int) if !ok { return nil, errors.New("count must be an integer") } absoluteCount := internal.AbsInt(count) - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return nil, errors.New("LREM command on non-list item") } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - list, ok := server.GetValue(ctx, key).([]interface{}) + list, ok := params.GetValue(params.Context, key).([]interface{}) if !ok { return nil, errors.New("LREM command on non-list item") } @@ -314,44 +312,44 @@ func handleLRem(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return elem == nil }) - if err = server.SetValue(ctx, key, list); err != nil { + if err = params.SetValue(params.Context, key, list); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleLMove(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lmoveKeyFunc(cmd) +func handleLMove(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lmoveKeyFunc(params.Command) if err != nil { return nil, err } source, destination := keys.WriteKeys[0], keys.WriteKeys[1] - whereFrom := strings.ToLower(cmd[3]) - whereTo := strings.ToLower(cmd[4]) + whereFrom := strings.ToLower(params.Command[3]) + whereTo := strings.ToLower(params.Command[4]) if !slices.Contains([]string{"left", "right"}, whereFrom) || !slices.Contains([]string{"left", "right"}, whereTo) { return nil, errors.New("wherefrom and whereto arguments must be either LEFT or RIGHT") } - if !server.KeyExists(ctx, source) || !server.KeyExists(ctx, destination) { + if !params.KeyExists(params.Context, source) || !params.KeyExists(params.Context, destination) { return nil, errors.New("both source and destination must be lists") } - if _, err = server.KeyLock(ctx, source); err != nil { + if _, err = params.KeyLock(params.Context, source); err != nil { return nil, err } - defer server.KeyUnlock(ctx, source) + defer params.KeyUnlock(params.Context, source) - _, err = server.KeyLock(ctx, destination) + _, err = params.KeyLock(params.Context, destination) if err != nil { return nil, err } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - sourceList, sourceOk := server.GetValue(ctx, source).([]interface{}) - destinationList, destinationOk := server.GetValue(ctx, destination).([]interface{}) + sourceList, sourceOk := params.GetValue(params.Context, source).([]interface{}) + destinationList, destinationOk := params.GetValue(params.Context, destination).([]interface{}) if !sourceOk || !destinationOk { return nil, errors.New("both source and destination must be lists") @@ -359,18 +357,18 @@ func handleLMove(ctx context.Context, cmd []string, server types.EchoVault, _ *n switch whereFrom { case "left": - err = server.SetValue(ctx, source, append([]interface{}{}, sourceList[1:]...)) + err = params.SetValue(params.Context, source, append([]interface{}{}, sourceList[1:]...)) if whereTo == "left" { - err = server.SetValue(ctx, destination, append(sourceList[0:1], destinationList...)) + err = params.SetValue(params.Context, destination, append(sourceList[0:1], destinationList...)) } else if whereTo == "right" { - err = server.SetValue(ctx, destination, append(destinationList, sourceList[0])) + err = params.SetValue(params.Context, destination, append(destinationList, sourceList[0])) } case "right": - err = server.SetValue(ctx, source, append([]interface{}{}, sourceList[:len(sourceList)-1]...)) + err = params.SetValue(params.Context, source, append([]interface{}{}, sourceList[:len(sourceList)-1]...)) if whereTo == "left" { - err = server.SetValue(ctx, destination, append(sourceList[len(sourceList)-1:], destinationList...)) + err = params.SetValue(params.Context, destination, append(sourceList[len(sourceList)-1:], destinationList...)) } else if whereTo == "right" { - err = server.SetValue(ctx, destination, append(destinationList, sourceList[len(sourceList)-1])) + err = params.SetValue(params.Context, destination, append(destinationList, sourceList[len(sourceList)-1])) } } @@ -381,54 +379,54 @@ func handleLMove(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(constants.OkResponse), nil } -func handleLPush(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := lpushKeyFunc(cmd) +func handleLPush(params types.HandlerFuncParams) ([]byte, error) { + keys, err := lpushKeyFunc(params.Command) if err != nil { return nil, err } var newElems []interface{} - for _, elem := range cmd[2:] { + for _, elem := range params.Command[2:] { newElems = append(newElems, internal.AdaptType(elem)) } key := keys.WriteKeys[0] - if !server.KeyExists(ctx, key) { - switch strings.ToLower(cmd[0]) { + if !params.KeyExists(params.Context, key) { + switch strings.ToLower(params.Command[0]) { case "lpushx": return nil, errors.New("LPUSHX command on non-list item") default: - if _, err = server.CreateKeyAndLock(ctx, key); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, key); err != nil { return nil, err } - if err = server.SetValue(ctx, key, []interface{}{}); err != nil { + if err = params.SetValue(params.Context, key, []interface{}{}); err != nil { return nil, err } } } else { - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - currentList := server.GetValue(ctx, key) + currentList := params.GetValue(params.Context, key) l, ok := currentList.([]interface{}) if !ok { return nil, errors.New("LPUSH command on non-list item") } - if err = server.SetValue(ctx, key, append(newElems, l...)); err != nil { + if err = params.SetValue(params.Context, key, append(newElems, l...)); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handleRPush(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := rpushKeyFunc(cmd) +func handleRPush(params types.HandlerFuncParams) ([]byte, error) { + keys, err := rpushKeyFunc(params.Command) if err != nil { return nil, err } @@ -437,31 +435,31 @@ func handleRPush(ctx context.Context, cmd []string, server types.EchoVault, _ *n var newElems []interface{} - for _, elem := range cmd[2:] { + for _, elem := range params.Command[2:] { newElems = append(newElems, internal.AdaptType(elem)) } - if !server.KeyExists(ctx, key) { - switch strings.ToLower(cmd[0]) { + if !params.KeyExists(params.Context, key) { + switch strings.ToLower(params.Command[0]) { case "rpushx": return nil, errors.New("RPUSHX command on non-list item") default: - if _, err = server.CreateKeyAndLock(ctx, key); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) - if err = server.SetValue(ctx, key, []interface{}{}); err != nil { + defer params.KeyUnlock(params.Context, key) + if err = params.SetValue(params.Context, key, []interface{}{}); err != nil { return nil, err } } } else { - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) } - currentList := server.GetValue(ctx, key) + currentList := params.GetValue(params.Context, key) l, ok := currentList.([]interface{}) @@ -469,42 +467,42 @@ func handleRPush(ctx context.Context, cmd []string, server types.EchoVault, _ *n return nil, errors.New("RPUSH command on non-list item") } - if err = server.SetValue(ctx, key, append(l, newElems...)); err != nil { + if err = params.SetValue(params.Context, key, append(l, newElems...)); err != nil { return nil, err } return []byte(constants.OkResponse), nil } -func handlePop(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := popKeyFunc(cmd) +func handlePop(params types.HandlerFuncParams) ([]byte, error) { + keys, err := popKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - if !server.KeyExists(ctx, key) { - return nil, fmt.Errorf("%s command on non-list item", strings.ToUpper(cmd[0])) + if !params.KeyExists(params.Context, key) { + return nil, fmt.Errorf("%s command on non-list item", strings.ToUpper(params.Command[0])) } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - list, ok := server.GetValue(ctx, key).([]interface{}) + list, ok := params.GetValue(params.Context, key).([]interface{}) if !ok { - return nil, fmt.Errorf("%s command on non-list item", strings.ToUpper(cmd[0])) + return nil, fmt.Errorf("%s command on non-list item", strings.ToUpper(params.Command[0])) } - switch strings.ToLower(cmd[0]) { + switch strings.ToLower(params.Command[0]) { default: - if err = server.SetValue(ctx, key, list[1:]); err != nil { + if err = params.SetValue(params.Context, key, list[1:]); err != nil { return nil, err } return []byte(fmt.Sprintf("+%v\r\n", list[0])), nil case "rpop": - if err = server.SetValue(ctx, key, list[:len(list)-1]); err != nil { + if err = params.SetValue(params.Context, key, list[:len(list)-1]); err != nil { return nil, err } return []byte(fmt.Sprintf("+%v\r\n", list[len(list)-1])), nil diff --git a/pkg/modules/pubsub/commands.go b/pkg/modules/pubsub/commands.go index 6fe9fab..e8c0f79 100644 --- a/pkg/modules/pubsub/commands.go +++ b/pkg/modules/pubsub/commands.go @@ -15,79 +15,77 @@ package pubsub import ( - "context" "errors" "fmt" internal_pubsub "github.com/echovault/echovault/internal/pubsub" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" - "net" "strings" ) -func handleSubscribe(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) +func handleSubscribe(params types.HandlerFuncParams) ([]byte, error) { + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } - channels := cmd[1:] + channels := params.Command[1:] if len(channels) == 0 { return nil, errors.New(constants.WrongArgsResponse) } - withPattern := strings.EqualFold(cmd[0], "psubscribe") - pubsub.Subscribe(ctx, conn, channels, withPattern) + withPattern := strings.EqualFold(params.Command[0], "psubscribe") + pubsub.Subscribe(params.Context, params.Connection, channels, withPattern) return nil, nil } -func handleUnsubscribe(ctx context.Context, cmd []string, server types.EchoVault, conn *net.Conn) ([]byte, error) { - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) +func handleUnsubscribe(params types.HandlerFuncParams) ([]byte, error) { + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } - channels := cmd[1:] + channels := params.Command[1:] - withPattern := strings.EqualFold(cmd[0], "punsubscribe") + withPattern := strings.EqualFold(params.Command[0], "punsubscribe") - return pubsub.Unsubscribe(ctx, conn, channels, withPattern), nil + return pubsub.Unsubscribe(params.Context, params.Connection, channels, withPattern), nil } -func handlePublish(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) +func handlePublish(params types.HandlerFuncParams) ([]byte, error) { + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } - if len(cmd) != 3 { + if len(params.Command) != 3 { return nil, errors.New(constants.WrongArgsResponse) } - pubsub.Publish(ctx, cmd[2], cmd[1]) + pubsub.Publish(params.Context, params.Command[2], params.Command[1]) return []byte(constants.OkResponse), nil } -func handlePubSubChannels(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if len(cmd) > 3 { +func handlePubSubChannels(params types.HandlerFuncParams) ([]byte, error) { + if len(params.Command) > 3 { return nil, errors.New(constants.WrongArgsResponse) } - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } pattern := "" - if len(cmd) == 3 { - pattern = cmd[2] + if len(params.Command) == 3 { + pattern = params.Command[2] } return pubsub.Channels(pattern), nil } -func handlePubSubNumPat(_ context.Context, _ []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) +func handlePubSubNumPat(params types.HandlerFuncParams) ([]byte, error) { + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } @@ -95,12 +93,12 @@ func handlePubSubNumPat(_ context.Context, _ []string, server types.EchoVault, _ return []byte(fmt.Sprintf(":%d\r\n", num)), nil } -func handlePubSubNumSubs(_ context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - pubsub, ok := server.GetPubSub().(*internal_pubsub.PubSub) +func handlePubSubNumSubs(params types.HandlerFuncParams) ([]byte, error) { + pubsub, ok := params.GetPubSub().(*internal_pubsub.PubSub) if !ok { return nil, errors.New("could not load pubsub module") } - return pubsub.NumSub(cmd[2:]), nil + return pubsub.NumSub(params.Command[2:]), nil } func Commands() []types.Command { @@ -210,7 +208,7 @@ it's currently subscribe to.`, WriteKeys: make([]string, 0), }, nil }, - HandlerFunc: func(_ context.Context, _ []string, _ types.EchoVault, _ *net.Conn) ([]byte, error) { + HandlerFunc: func(_ types.HandlerFuncParams) ([]byte, error) { return nil, errors.New("provide CHANNELS, NUMPAT, or NUMSUB subcommand") }, SubCommands: []types.SubCommand{ diff --git a/pkg/modules/set/commands.go b/pkg/modules/set/commands.go index f258283..f7f4c72 100644 --- a/pkg/modules/set/commands.go +++ b/pkg/modules/set/commands.go @@ -15,20 +15,18 @@ package set import ( - "context" "errors" "fmt" "github.com/echovault/echovault/internal" internal_set "github.com/echovault/echovault/internal/set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" - "net" "slices" "strings" ) -func handleSADD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := saddKeyFunc(cmd) +func handleSADD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := saddKeyFunc(params.Command) if err != nil { return nil, err } @@ -37,51 +35,51 @@ func handleSADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne var set *internal_set.Set - if !server.KeyExists(ctx, key) { - set = internal_set.NewSet(cmd[2:]) - if ok, err := server.CreateKeyAndLock(ctx, key); !ok && err != nil { + if !params.KeyExists(params.Context, key) { + set = internal_set.NewSet(params.Command[2:]) + if ok, err := params.CreateKeyAndLock(params.Context, key); !ok && err != nil { return nil, err } - if err = server.SetValue(ctx, key, set); err != nil { + if err = params.SetValue(params.Context, key, set); err != nil { return nil, err } - server.KeyUnlock(ctx, key) - return []byte(fmt.Sprintf(":%d\r\n", len(cmd[2:]))), nil + params.KeyUnlock(params.Context, key) + return []byte(fmt.Sprintf(":%d\r\n", len(params.Command[2:]))), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } - count := set.Add(cmd[2:]) + count := set.Add(params.Command[2:]) return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleSCARD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := scardKeyFunc(cmd) +func handleSCARD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := scardKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(fmt.Sprintf(":0\r\n")), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -91,21 +89,21 @@ func handleSCARD(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(fmt.Sprintf(":%d\r\n", cardinality)), nil } -func handleSDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sdiffKeyFunc(cmd) +func handleSDIFF(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sdiffKeyFunc(params.Command) if err != nil { return nil, err } // Extract base set first - if !server.KeyExists(ctx, keys.ReadKeys[0]) { + if !params.KeyExists(params.Context, keys.ReadKeys[0]) { return nil, fmt.Errorf("key for base set \"%s\" does not exist", keys.ReadKeys[0]) } - if _, err = server.KeyRLock(ctx, keys.ReadKeys[0]); err != nil { + if _, err = params.KeyRLock(params.Context, keys.ReadKeys[0]); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, keys.ReadKeys[0]) - baseSet, ok := server.GetValue(ctx, keys.ReadKeys[0]).(*internal_set.Set) + defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) + baseSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", keys.ReadKeys[0]) } @@ -114,24 +112,24 @@ func handleSDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *n defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys[1:] { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { continue } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { continue } locks[key] = true } var sets []*internal_set.Set - for _, key := range cmd[2:] { - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + for _, key := range params.Command[2:] { + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { continue } @@ -152,8 +150,8 @@ func handleSDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(res), nil } -func handleSDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sdiffstoreKeyFunc(cmd) +func handleSDIFFSTORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sdiffstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -161,14 +159,14 @@ func handleSDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, destination := keys.WriteKeys[0] // Extract base set first - if !server.KeyExists(ctx, keys.ReadKeys[0]) { + if !params.KeyExists(params.Context, keys.ReadKeys[0]) { return nil, fmt.Errorf("key for base set \"%s\" does not exist", keys.ReadKeys[0]) } - if _, err := server.KeyRLock(ctx, keys.ReadKeys[0]); err != nil { + if _, err := params.KeyRLock(params.Context, keys.ReadKeys[0]); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, keys.ReadKeys[0]) - baseSet, ok := server.GetValue(ctx, keys.ReadKeys[0]).(*internal_set.Set) + defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) + baseSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", keys.ReadKeys[0]) } @@ -177,16 +175,16 @@ func handleSDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys[1:] { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { continue } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { continue } locks[key] = true @@ -194,7 +192,7 @@ func handleSDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, var sets []*internal_set.Set for _, key := range keys.ReadKeys[1:] { - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { continue } @@ -206,30 +204,30 @@ func handleSDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, res := fmt.Sprintf(":%d\r\n", len(elems)) - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } - if err = server.SetValue(ctx, destination, diff); err != nil { + if err = params.SetValue(params.Context, destination, diff); err != nil { return nil, err } - server.KeyUnlock(ctx, destination) + params.KeyUnlock(params.Context, destination) return []byte(res), nil } - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } - if err = server.SetValue(ctx, destination, diff); err != nil { + if err = params.SetValue(params.Context, destination, diff); err != nil { return nil, err } - server.KeyUnlock(ctx, destination) + params.KeyUnlock(params.Context, destination) return []byte(res), nil } -func handleSINTER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sinterKeyFunc(cmd) +func handleSINTER(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sinterKeyFunc(params.Command) if err != nil { return nil, err } @@ -238,17 +236,17 @@ func handleSINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // If key does not exist, then there is no intersection return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } locks[key] = true @@ -257,7 +255,7 @@ func handleSINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * var sets []*internal_set.Set for key, _ := range locks { - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { // If the value at the key is not a set, return error return nil, fmt.Errorf("value at key %s is not a set", key) @@ -283,15 +281,15 @@ func handleSINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(res), nil } -func handleSINTERCARD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sintercardKeyFunc(cmd) +func handleSINTERCARD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sintercardKeyFunc(params.Command) if err != nil { return nil, err } // Extract the limit from the command var limit int - limitIdx := slices.IndexFunc(cmd, func(s string) bool { + limitIdx := slices.IndexFunc(params.Command, func(s string) bool { return strings.EqualFold(s, "limit") }) if limitIdx >= 0 && limitIdx < 2 { @@ -299,11 +297,11 @@ func handleSINTERCARD(ctx context.Context, cmd []string, server types.EchoVault, } if limitIdx != -1 { limitIdx += 1 - if limitIdx >= len(cmd) { + if limitIdx >= len(params.Command) { return nil, errors.New("provide limit after LIMIT keyword") } - if l, ok := internal.AdaptType(cmd[limitIdx]).(int); !ok { + if l, ok := internal.AdaptType(params.Command[limitIdx]).(int); !ok { return nil, errors.New("limit must be an integer") } else { limit = l @@ -314,17 +312,17 @@ func handleSINTERCARD(ctx context.Context, cmd []string, server types.EchoVault, defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // If key does not exist, then there is no intersection return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } locks[key] = true @@ -333,7 +331,7 @@ func handleSINTERCARD(ctx context.Context, cmd []string, server types.EchoVault, var sets []*internal_set.Set for key, _ := range locks { - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { // If the value at the key is not a set, return error return nil, fmt.Errorf("value at key %s is not a set", key) @@ -350,8 +348,8 @@ func handleSINTERCARD(ctx context.Context, cmd []string, server types.EchoVault, return []byte(fmt.Sprintf(":%d\r\n", intersect.Cardinality())), nil } -func handleSINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sinterstoreKeyFunc(cmd) +func handleSINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sinterstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -360,17 +358,17 @@ func handleSINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // If key does not exist, then there is no intersection return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } locks[key] = true @@ -379,7 +377,7 @@ func handleSINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault var sets []*internal_set.Set for key, _ := range locks { - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { // If the value at the key is not a set, return error return nil, fmt.Errorf("value at key %s is not a set", key) @@ -390,71 +388,71 @@ func handleSINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault intersect, _ := internal_set.Intersection(0, sets...) destination := keys.WriteKeys[0] - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - if err = server.SetValue(ctx, destination, intersect); err != nil { + if err = params.SetValue(params.Context, destination, intersect); err != nil { return nil, err } - server.KeyUnlock(ctx, destination) + params.KeyUnlock(params.Context, destination) return []byte(fmt.Sprintf(":%d\r\n", intersect.Cardinality())), nil } -func handleSISMEMBER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sismemberKeyFunc(cmd) +func handleSISMEMBER(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sismemberKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } - if !set.Contains(cmd[2]) { + if !set.Contains(params.Command[2]) { return []byte(":0\r\n"), nil } return []byte(":1\r\n"), nil } -func handleSMEMBERS(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := smembersKeyFunc(cmd) +func handleSMEMBERS(params types.HandlerFuncParams) ([]byte, error) { + keys, err := smembersKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -472,16 +470,16 @@ func handleSMEMBERS(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(res), nil } -func handleSMISMEMBER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := smismemberKeyFunc(cmd) +func handleSMISMEMBER(params types.HandlerFuncParams) ([]byte, error) { + keys, err := smismemberKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - members := cmd[2:] + members := params.Command[2:] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { res := fmt.Sprintf("*%d", len(members)) for i, _ := range members { res = fmt.Sprintf("%s\r\n:0", res) @@ -492,12 +490,12 @@ func handleSMISMEMBER(ctx context.Context, cmd []string, server types.EchoVault, return []byte(res), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -515,48 +513,48 @@ func handleSMISMEMBER(ctx context.Context, cmd []string, server types.EchoVault, return []byte(res), nil } -func handleSMOVE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := smoveKeyFunc(cmd) +func handleSMOVE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := smoveKeyFunc(params.Command) if err != nil { return nil, err } source, destination := keys.WriteKeys[0], keys.WriteKeys[1] - member := cmd[3] + member := params.Command[3] - if !server.KeyExists(ctx, source) { + if !params.KeyExists(params.Context, source) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, source); err != nil { + if _, err = params.KeyLock(params.Context, source); err != nil { return nil, err } - defer server.KeyUnlock(ctx, source) + defer params.KeyUnlock(params.Context, source) - sourceSet, ok := server.GetValue(ctx, source).(*internal_set.Set) + sourceSet, ok := params.GetValue(params.Context, source).(*internal_set.Set) if !ok { return nil, errors.New("source is not a set") } var destinationSet *internal_set.Set - if !server.KeyExists(ctx, destination) { + if !params.KeyExists(params.Context, destination) { // Destination key does not exist - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) destinationSet = internal_set.NewSet([]string{}) - if err = server.SetValue(ctx, destination, destinationSet); err != nil { + if err = params.SetValue(params.Context, destination, destinationSet); err != nil { return nil, err } } else { // Destination key exists - if _, err := server.KeyLock(ctx, destination); err != nil { + if _, err := params.KeyLock(params.Context, destination); err != nil { return nil, err } - defer server.KeyUnlock(ctx, destination) - ds, ok := server.GetValue(ctx, destination).(*internal_set.Set) + defer params.KeyUnlock(params.Context, destination) + ds, ok := params.GetValue(params.Context, destination).(*internal_set.Set) if !ok { return nil, errors.New("destination is not a set") } @@ -568,8 +566,8 @@ func handleSMOVE(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(fmt.Sprintf(":%d\r\n", res)), nil } -func handleSPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := spopKeyFunc(cmd) +func handleSPOP(params types.HandlerFuncParams) ([]byte, error) { + keys, err := spopKeyFunc(params.Command) if err != nil { return nil, err } @@ -577,24 +575,24 @@ func handleSPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *ne key := keys.WriteKeys[0] count := 1 - if len(cmd) == 3 { - c, ok := internal.AdaptType(cmd[2]).(int) + if len(params.Command) == 3 { + c, ok := internal.AdaptType(params.Command[2]).(int) if !ok { return nil, errors.New("count must be an integer") } count = c } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*-1\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at %s is not a set", key) } @@ -612,8 +610,8 @@ func handleSPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(res), nil } -func handleSRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := srandmemberKeyFunc(cmd) +func handleSRANDMEMBER(params types.HandlerFuncParams) ([]byte, error) { + keys, err := srandmemberKeyFunc(params.Command) if err != nil { return nil, err } @@ -621,24 +619,24 @@ func handleSRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault key := keys.ReadKeys[0] count := 1 - if len(cmd) == 3 { - c, ok := internal.AdaptType(cmd[2]).(int) + if len(params.Command) == 3 { + c, ok := internal.AdaptType(params.Command[2]).(int) if !ok { return nil, errors.New("count must be an integer") } count = c } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*-1\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at %s is not a set", key) } @@ -656,25 +654,25 @@ func handleSRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault return []byte(res), nil } -func handleSREM(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sremKeyFunc(cmd) +func handleSREM(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sremKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - members := cmd[2:] + members := params.Command[2:] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -684,8 +682,8 @@ func handleSREM(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleSUNION(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sunionKeyFunc(cmd) +func handleSUNION(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sunionKeyFunc(params.Command) if err != nil { return nil, err } @@ -694,16 +692,16 @@ func handleSUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { continue } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } locks[key] = true @@ -715,7 +713,7 @@ func handleSUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * if !locked { continue } - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -735,8 +733,8 @@ func handleSUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(res), nil } -func handleSUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := sunionstoreKeyFunc(cmd) +func handleSUNIONSTORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := sunionstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -745,16 +743,16 @@ func handleSUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() for _, key := range keys.ReadKeys { - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { continue } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } locks[key] = true @@ -766,7 +764,7 @@ func handleSUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault if !locked { continue } - set, ok := server.GetValue(ctx, key).(*internal_set.Set) + set, ok := params.GetValue(params.Context, key).(*internal_set.Set) if !ok { return nil, fmt.Errorf("value at key %s is not a set", key) } @@ -777,18 +775,18 @@ func handleSUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault destination := keys.WriteKeys[0] - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - if err = server.SetValue(ctx, destination, union); err != nil { + if err = params.SetValue(params.Context, destination, union); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", union.Cardinality())), nil diff --git a/pkg/modules/sorted_set/commands.go b/pkg/modules/sorted_set/commands.go index 325844c..d892fe4 100644 --- a/pkg/modules/sorted_set/commands.go +++ b/pkg/modules/sorted_set/commands.go @@ -16,7 +16,6 @@ package sorted_set import ( "cmp" - "context" "errors" "fmt" "github.com/echovault/echovault/internal" @@ -24,14 +23,13 @@ import ( "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/types" "math" - "net" "slices" "strconv" "strings" ) -func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zaddKeyFunc(cmd) +func handleZADD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zaddKeyFunc(params.Command) if err != nil { return nil, err } @@ -45,13 +43,13 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne // Find the first valid score and this will be the start of the score/member pairs var membersStartIndex int - for i := 0; i < len(cmd); i++ { + for i := 0; i < len(params.Command); i++ { if membersStartIndex != 0 { break } - switch internal.AdaptType(cmd[i]).(type) { + switch internal.AdaptType(params.Command[i]).(type) { case string: - if slices.Contains([]string{"-inf", "+inf"}, strings.ToLower(cmd[i])) { + if slices.Contains([]string{"-inf", "+inf"}, strings.ToLower(params.Command[i])) { membersStartIndex = i } case float64: @@ -61,17 +59,17 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne } } - if membersStartIndex < 2 || len(cmd[membersStartIndex:])%2 != 0 { + if membersStartIndex < 2 || len(params.Command[membersStartIndex:])%2 != 0 { return nil, errors.New("score/member pairs must be float/string") } var members []sorted_set.MemberParam - for i := 0; i < len(cmd[membersStartIndex:]); i++ { + for i := 0; i < len(params.Command[membersStartIndex:]); i++ { if i%2 != 0 { continue } - score := internal.AdaptType(cmd[membersStartIndex:][i]) + score := internal.AdaptType(params.Command[membersStartIndex:][i]) switch score.(type) { default: return nil, errors.New("invalid score in score/member list") @@ -80,27 +78,27 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne if strings.ToLower(score.(string)) == "-inf" { s = math.Inf(-1) members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(cmd[membersStartIndex:][i+1]), + Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), Score: sorted_set.Score(s), }) } if strings.ToLower(score.(string)) == "+inf" { s = math.Inf(1) members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(cmd[membersStartIndex:][i+1]), + Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), Score: sorted_set.Score(s), }) } case float64: s, _ := score.(float64) members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(cmd[membersStartIndex:][i+1]), + Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), Score: sorted_set.Score(s), }) case int: s, _ := score.(int) members = append(members, sorted_set.MemberParam{ - Value: sorted_set.Value(cmd[membersStartIndex:][i+1]), + Value: sorted_set.Value(params.Command[membersStartIndex:][i+1]), Score: sorted_set.Score(s), }) } @@ -108,7 +106,7 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne // Parse options using membersStartIndex as the upper limit if membersStartIndex > 2 { - options := cmd[2:membersStartIndex] + options := params.Command[2:membersStartIndex] for _, option := range options { if slices.Contains([]string{"xx", "nx"}, strings.ToLower(option)) { updatePolicy = option @@ -143,14 +141,14 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne } } - if server.KeyExists(ctx, key) { + if params.KeyExists(params.Context, key) { // Key exists - _, err = server.KeyLock(ctx, key) + _, err = params.KeyLock(params.Context, key) if err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + defer params.KeyUnlock(params.Context, key) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -168,36 +166,36 @@ func handleZADD(ctx context.Context, cmd []string, server types.EchoVault, _ *ne } // Key does not exist - if _, err = server.CreateKeyAndLock(ctx, key); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) set := sorted_set.NewSortedSet(members) - if err = server.SetValue(ctx, key, set); err != nil { + if err = params.SetValue(params.Context, key, set); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", set.Cardinality())), nil } -func handleZCARD(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zcardKeyFunc(cmd) +func handleZCARD(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zcardKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -205,8 +203,8 @@ func handleZCARD(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(fmt.Sprintf(":%d\r\n", set.Cardinality())), nil } -func handleZCOUNT(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zcountKeyFunc(cmd) +func handleZCOUNT(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zcountKeyFunc(params.Command) if err != nil { return nil, err } @@ -214,51 +212,51 @@ func handleZCOUNT(ctx context.Context, cmd []string, server types.EchoVault, _ * key := keys.ReadKeys[0] minimum := sorted_set.Score(math.Inf(-1)) - switch internal.AdaptType(cmd[2]).(type) { + switch internal.AdaptType(params.Command[2]).(type) { default: return nil, errors.New("min constraint must be a double") case string: - if strings.ToLower(cmd[2]) == "+inf" { + if strings.ToLower(params.Command[2]) == "+inf" { minimum = sorted_set.Score(math.Inf(1)) } else { return nil, errors.New("min constraint must be a double") } case float64: - s, _ := internal.AdaptType(cmd[2]).(float64) + s, _ := internal.AdaptType(params.Command[2]).(float64) minimum = sorted_set.Score(s) case int: - s, _ := internal.AdaptType(cmd[2]).(int) + s, _ := internal.AdaptType(params.Command[2]).(int) minimum = sorted_set.Score(s) } maximum := sorted_set.Score(math.Inf(1)) - switch internal.AdaptType(cmd[3]).(type) { + switch internal.AdaptType(params.Command[3]).(type) { default: return nil, errors.New("max constraint must be a double") case string: - if strings.ToLower(cmd[3]) == "-inf" { + if strings.ToLower(params.Command[3]) == "-inf" { maximum = sorted_set.Score(math.Inf(-1)) } else { return nil, errors.New("max constraint must be a double") } case float64: - s, _ := internal.AdaptType(cmd[3]).(float64) + s, _ := internal.AdaptType(params.Command[3]).(float64) maximum = sorted_set.Score(s) case int: - s, _ := internal.AdaptType(cmd[3]).(int) + s, _ := internal.AdaptType(params.Command[3]).(int) maximum = sorted_set.Score(s) } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -273,26 +271,26 @@ func handleZCOUNT(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(fmt.Sprintf(":%d\r\n", len(members))), nil } -func handleZLEXCOUNT(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zlexcountKeyFunc(cmd) +func handleZLEXCOUNT(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zlexcountKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - minimum := cmd[2] - maximum := cmd[3] + minimum := params.Command[2] + maximum := params.Command[3] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -318,13 +316,13 @@ func handleZLEXCOUNT(ctx context.Context, cmd []string, server types.EchoVault, return []byte(fmt.Sprintf(":%d\r\n", count)), nil } -func handleZDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zdiffKeyFunc(cmd) +func handleZDIFF(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zdiffKeyFunc(params.Command) if err != nil { return nil, err } - withscoresIndex := slices.IndexFunc(cmd, func(s string) bool { + withscoresIndex := slices.IndexFunc(params.Command, func(s string) bool { return strings.EqualFold(s, "withscores") }) if withscoresIndex > -1 && withscoresIndex < 2 { @@ -335,21 +333,21 @@ func handleZDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *n defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() // Extract base set - if !server.KeyExists(ctx, keys.ReadKeys[0]) { + if !params.KeyExists(params.Context, keys.ReadKeys[0]) { // If base set does not exist, return an empty array return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, keys.ReadKeys[0]); err != nil { + if _, err = params.KeyRLock(params.Context, keys.ReadKeys[0]); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, keys.ReadKeys[0]) - baseSortedSet, ok := server.GetValue(ctx, keys.ReadKeys[0]).(*sorted_set.SortedSet) + defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) + baseSortedSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[0]) } @@ -358,15 +356,15 @@ func handleZDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *n var sets []*sorted_set.SortedSet for i := 1; i < len(keys.ReadKeys); i++ { - if !server.KeyExists(ctx, keys.ReadKeys[i]) { + if !params.KeyExists(params.Context, keys.ReadKeys[i]) { continue } - locked, err := server.KeyRLock(ctx, keys.ReadKeys[i]) + locked, err := params.KeyRLock(params.Context, keys.ReadKeys[i]) if err != nil { return nil, err } locks[keys.ReadKeys[i]] = locked - set, ok := server.GetValue(ctx, keys.ReadKeys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys.ReadKeys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[i]) } @@ -391,8 +389,8 @@ func handleZDIFF(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte(res), nil } -func handleZDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zdiffstoreKeyFunc(cmd) +func handleZDIFFSTORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zdiffstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -403,21 +401,21 @@ func handleZDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() // Extract base set - if !server.KeyExists(ctx, keys.ReadKeys[0]) { + if !params.KeyExists(params.Context, keys.ReadKeys[0]) { // If base set does not exist, return 0 return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, keys.ReadKeys[0]); err != nil { + if _, err = params.KeyRLock(params.Context, keys.ReadKeys[0]); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, keys.ReadKeys[0]) - baseSortedSet, ok := server.GetValue(ctx, keys.ReadKeys[0]).(*sorted_set.SortedSet) + defer params.KeyRUnlock(params.Context, keys.ReadKeys[0]) + baseSortedSet, ok := params.GetValue(params.Context, keys.ReadKeys[0]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[0]) } @@ -425,11 +423,11 @@ func handleZDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, var sets []*sorted_set.SortedSet for i := 1; i < len(keys.ReadKeys); i++ { - if server.KeyExists(ctx, keys.ReadKeys[i]) { - if _, err = server.KeyRLock(ctx, keys.ReadKeys[i]); err != nil { + if params.KeyExists(params.Context, keys.ReadKeys[i]) { + if _, err = params.KeyRLock(params.Context, keys.ReadKeys[i]); err != nil { return nil, err } - set, ok := server.GetValue(ctx, keys.ReadKeys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys.ReadKeys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys.ReadKeys[i]) } @@ -439,75 +437,75 @@ func handleZDIFFSTORE(ctx context.Context, cmd []string, server types.EchoVault, diff := baseSortedSet.Subtract(sets) - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - if err = server.SetValue(ctx, destination, diff); err != nil { + if err = params.SetValue(params.Context, destination, diff); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", diff.Cardinality())), nil } -func handleZINCRBY(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zincrbyKeyFunc(cmd) +func handleZINCRBY(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zincrbyKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - member := sorted_set.Value(cmd[3]) + member := sorted_set.Value(params.Command[3]) var increment sorted_set.Score - switch internal.AdaptType(cmd[2]).(type) { + switch internal.AdaptType(params.Command[2]).(type) { default: return nil, errors.New("increment must be a double") case string: - if strings.EqualFold("-inf", strings.ToLower(cmd[2])) { + if strings.EqualFold("-inf", strings.ToLower(params.Command[2])) { increment = sorted_set.Score(math.Inf(-1)) - } else if strings.EqualFold("+inf", strings.ToLower(cmd[2])) { + } else if strings.EqualFold("+inf", strings.ToLower(params.Command[2])) { increment = sorted_set.Score(math.Inf(1)) } else { return nil, errors.New("increment must be a double") } case float64: - s, _ := internal.AdaptType(cmd[2]).(float64) + s, _ := internal.AdaptType(params.Command[2]).(float64) increment = sorted_set.Score(s) case int: - s, _ := internal.AdaptType(cmd[2]).(int) + s, _ := internal.AdaptType(params.Command[2]).(int) increment = sorted_set.Score(s) } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { // If the key does not exist, create a new sorted set at the key with // the member and increment as the first value - if _, err = server.CreateKeyAndLock(ctx, key); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, key); err != nil { return nil, err } - if err = server.SetValue( - ctx, + if err = params.SetValue( + params.Context, key, sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: member, Score: increment}}), ); err != nil { return nil, err } - server.KeyUnlock(ctx, key) + params.KeyUnlock(params.Context, key) return []byte(fmt.Sprintf("+%s\r\n", strconv.FormatFloat(float64(increment), 'f', -1, 64))), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + defer params.KeyUnlock(params.Context, key) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -524,13 +522,13 @@ func handleZINCRBY(ctx context.Context, cmd []string, server types.EchoVault, _ strconv.FormatFloat(float64(set.Get(member).Score), 'f', -1, 64))), nil } -func handleZINTER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - _, err := zinterKeyFunc(cmd) +func handleZINTER(params types.HandlerFuncParams) ([]byte, error) { + _, err := zinterKeyFunc(params.Command) if err != nil { return nil, err } - keys, weights, aggregate, withscores, err := extractKeysWeightsAggregateWithScores(cmd) + keys, weights, aggregate, withscores, err := extractKeysWeightsAggregateWithScores(params.Command) if err != nil { return nil, err } @@ -539,7 +537,7 @@ func handleZINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() @@ -547,15 +545,15 @@ func handleZINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * var setParams []sorted_set.SortedSetParam for i := 0; i < len(keys); i++ { - if !server.KeyExists(ctx, keys[i]) { + if !params.KeyExists(params.Context, keys[i]) { // If any of the keys is non-existent, return an empty array as there's no intersect return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, keys[i]); err != nil { + if _, err = params.KeyRLock(params.Context, keys[i]); err != nil { return nil, err } locks[keys[i]] = true - set, ok := server.GetValue(ctx, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } @@ -584,8 +582,8 @@ func handleZINTER(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(res), nil } -func handleZINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - k, err := zinterstoreKeyFunc(cmd) +func handleZINTERSTORE(params types.HandlerFuncParams) ([]byte, error) { + k, err := zinterstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -593,7 +591,7 @@ func handleZINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault destination := k.WriteKeys[0] // Remove the destination keys from the command before parsing it - cmd = slices.DeleteFunc(cmd, func(s string) bool { + cmd := slices.DeleteFunc(params.Command, func(s string) bool { return s == destination }) @@ -606,7 +604,7 @@ func handleZINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() @@ -614,14 +612,14 @@ func handleZINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault var setParams []sorted_set.SortedSetParam for i := 0; i < len(keys); i++ { - if !server.KeyExists(ctx, keys[i]) { + if !params.KeyExists(params.Context, keys[i]) { return []byte(":0\r\n"), nil } - if _, err = server.KeyRLock(ctx, keys[i]); err != nil { + if _, err = params.KeyRLock(params.Context, keys[i]); err != nil { return nil, err } locks[keys[i]] = true - set, ok := server.GetValue(ctx, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } @@ -633,26 +631,26 @@ func handleZINTERSTORE(ctx context.Context, cmd []string, server types.EchoVault intersect := sorted_set.Intersect(aggregate, setParams...) - if server.KeyExists(ctx, destination) && intersect.Cardinality() > 0 { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) && intersect.Cardinality() > 0 { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else if intersect.Cardinality() > 0 { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - if err = server.SetValue(ctx, destination, intersect); err != nil { + if err = params.SetValue(params.Context, destination, intersect); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", intersect.Cardinality())), nil } -func handleZMPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zmpopKeyFunc(cmd) +func handleZMPOP(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zmpopKeyFunc(params.Command) if err != nil { return nil, err } @@ -662,17 +660,17 @@ func handleZMPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *n modifierIdx := -1 // Parse COUNT from command - countIdx := slices.IndexFunc(cmd, func(s string) bool { + countIdx := slices.IndexFunc(params.Command, func(s string) bool { return strings.ToLower(s) == "count" }) if countIdx != -1 { if countIdx < 2 { return nil, errors.New(constants.WrongArgsResponse) } - if countIdx == len(cmd)-1 { + if countIdx == len(params.Command)-1 { return nil, errors.New("count must be a positive integer") } - c, err := strconv.Atoi(cmd[countIdx+1]) + c, err := strconv.Atoi(params.Command[countIdx+1]) if err != nil { return nil, err } @@ -684,35 +682,35 @@ func handleZMPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *n } // Parse MIN/MAX from the command - policyIdx := slices.IndexFunc(cmd, func(s string) bool { + policyIdx := slices.IndexFunc(params.Command, func(s string) bool { return slices.Contains([]string{"min", "max"}, strings.ToLower(s)) }) if policyIdx != -1 { if policyIdx < 2 { return nil, errors.New(constants.WrongArgsResponse) } - policy = strings.ToLower(cmd[policyIdx]) + policy = strings.ToLower(params.Command[policyIdx]) if modifierIdx == -1 || (policyIdx < modifierIdx) { modifierIdx = policyIdx } } for i := 0; i < len(keys.WriteKeys); i++ { - if server.KeyExists(ctx, keys.WriteKeys[i]) { - if _, err = server.KeyLock(ctx, keys.WriteKeys[i]); err != nil { + if params.KeyExists(params.Context, keys.WriteKeys[i]) { + if _, err = params.KeyLock(params.Context, keys.WriteKeys[i]); err != nil { continue } - v, ok := server.GetValue(ctx, keys.WriteKeys[i]).(*sorted_set.SortedSet) + v, ok := params.GetValue(params.Context, keys.WriteKeys[i]).(*sorted_set.SortedSet) if !ok || v.Cardinality() == 0 { - server.KeyUnlock(ctx, keys.WriteKeys[i]) + params.KeyUnlock(params.Context, keys.WriteKeys[i]) continue } popped, err := v.Pop(count, policy) if err != nil { - server.KeyUnlock(ctx, keys.WriteKeys[i]) + params.KeyUnlock(params.Context, keys.WriteKeys[i]) return nil, err } - server.KeyUnlock(ctx, keys.WriteKeys[i]) + params.KeyUnlock(params.Context, keys.WriteKeys[i]) res := fmt.Sprintf("*%d", popped.Cardinality()) @@ -729,8 +727,8 @@ func handleZMPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte("*0\r\n"), nil } -func handleZPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zpopKeyFunc(cmd) +func handleZPOP(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zpopKeyFunc(params.Command) if err != nil { return nil, err } @@ -739,12 +737,12 @@ func handleZPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *ne count := 1 policy := "min" - if strings.EqualFold(cmd[0], "zpopmax") { + if strings.EqualFold(params.Command[0], "zpopmax") { policy = "max" } - if len(cmd) == 3 { - c, err := strconv.Atoi(cmd[2]) + if len(params.Command) == 3 { + c, err := strconv.Atoi(params.Command[2]) if err != nil { return nil, err } @@ -753,16 +751,16 @@ func handleZPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *ne } } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at key %s is not a sorted set", key) } @@ -782,29 +780,29 @@ func handleZPOP(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(res), nil } -func handleZMSCORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zmscoreKeyFunc(cmd) +func handleZMSCORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zmscoreKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } - members := cmd[2:] + members := params.Command[2:] res := fmt.Sprintf("*%d", len(members)) @@ -824,8 +822,8 @@ func handleZMSCORE(ctx context.Context, cmd []string, server types.EchoVault, _ return []byte(res), nil } -func handleZRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zrandmemberKeyFunc(cmd) +func handleZRANDMEMBER(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zrandmemberKeyFunc(params.Command) if err != nil { return nil, err } @@ -833,8 +831,8 @@ func handleZRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault key := keys.ReadKeys[0] count := 1 - if len(cmd) >= 3 { - c, err := strconv.Atoi(cmd[2]) + if len(params.Command) >= 3 { + c, err := strconv.Atoi(params.Command[2]) if err != nil { return nil, errors.New("count must be an integer") } @@ -844,24 +842,24 @@ func handleZRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault } withscores := false - if len(cmd) == 4 { - if strings.EqualFold(cmd[3], "withscores") { + if len(params.Command) == 4 { + if strings.EqualFold(params.Command[3], "withscores") { withscores = true } else { return nil, errors.New("last option must be WITHSCORES") } } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -882,37 +880,37 @@ func handleZRANDMEMBER(ctx context.Context, cmd []string, server types.EchoVault return []byte(res), nil } -func handleZRANK(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zrankKeyFunc(cmd) +func handleZRANK(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zrankKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - member := cmd[2] + member := params.Command[2] withscores := false - if len(cmd) == 4 && strings.EqualFold(cmd[3], "withscores") { + if len(params.Command) == 4 && strings.EqualFold(params.Command[3], "withscores") { withscores = true } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } members := set.GetAll() slices.SortFunc(members, func(a, b sorted_set.MemberParam) int { - if strings.EqualFold(cmd[0], "zrevrank") { + if strings.EqualFold(params.Command[0], "zrevrank") { return cmp.Compare(b.Score, a.Score) } return cmp.Compare(a.Score, b.Score) @@ -932,30 +930,30 @@ func handleZRANK(ctx context.Context, cmd []string, server types.EchoVault, _ *n return []byte("$-1\r\n"), nil } -func handleZREM(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zremKeyFunc(cmd) +func handleZREM(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zremKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } deletedCount := 0 - for _, m := range cmd[2:] { + for _, m := range params.Command[2:] { if set.Remove(sorted_set.Value(m)) { deletedCount += 1 } @@ -964,26 +962,26 @@ func handleZREM(ctx context.Context, cmd []string, server types.EchoVault, _ *ne return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZSCORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zscoreKeyFunc(cmd) +func handleZSCORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zscoreKeyFunc(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("$-1\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + defer params.KeyRUnlock(params.Context, key) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } - member := set.Get(sorted_set.Value(cmd[2])) + member := set.Get(sorted_set.Value(params.Command[2])) if !member.Exists { return []byte("$-1\r\n"), nil } @@ -993,8 +991,8 @@ func handleZSCORE(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(fmt.Sprintf("$%d\r\n%s\r\n", len(score), score)), nil } -func handleZREMRANGEBYSCORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zremrangebyscoreKeyFunc(cmd) +func handleZREMRANGEBYSCORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zremrangebyscoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -1003,26 +1001,26 @@ func handleZREMRANGEBYSCORE(ctx context.Context, cmd []string, server types.Echo deletedCount := 0 - minimum, err := strconv.ParseFloat(cmd[2], 64) + minimum, err := strconv.ParseFloat(params.Command[2], 64) if err != nil { return nil, err } - maximum, err := strconv.ParseFloat(cmd[3], 64) + maximum, err := strconv.ParseFloat(params.Command[3], 64) if err != nil { return nil, err } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -1037,34 +1035,34 @@ func handleZREMRANGEBYSCORE(ctx context.Context, cmd []string, server types.Echo return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZREMRANGEBYRANK(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zremrangebyrankKeyFunc(cmd) +func handleZREMRANGEBYRANK(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zremrangebyrankKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - start, err := strconv.Atoi(cmd[2]) + start, err := strconv.Atoi(params.Command[2]) if err != nil { return nil, err } - stop, err := strconv.Atoi(cmd[3]) + stop, err := strconv.Atoi(params.Command[3]) if err != nil { return nil, err } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -1102,26 +1100,26 @@ func handleZREMRANGEBYRANK(ctx context.Context, cmd []string, server types.EchoV return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZREMRANGEBYLEX(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zremrangebylexKeyFunc(cmd) +func handleZREMRANGEBYLEX(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zremrangebylexKeyFunc(params.Command) if err != nil { return nil, err } key := keys.WriteKeys[0] - minimum := cmd[2] - maximum := cmd[3] + minimum := params.Command[2] + maximum := params.Command[3] - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte(":0\r\n"), nil } - if _, err = server.KeyLock(ctx, key); err != nil { + if _, err = params.KeyLock(params.Context, key); err != nil { return nil, err } - defer server.KeyUnlock(ctx, key) + defer params.KeyUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -1149,77 +1147,77 @@ func handleZREMRANGEBYLEX(ctx context.Context, cmd []string, server types.EchoVa return []byte(fmt.Sprintf(":%d\r\n", deletedCount)), nil } -func handleZRANGE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zrangeKeyCount(cmd) +func handleZRANGE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zrangeKeyCount(params.Command) if err != nil { return nil, err } key := keys.ReadKeys[0] policy := "byscore" - scoreStart := math.Inf(-1) // Lower bound if policy is "byscore" - scoreStop := math.Inf(1) // Upper bound if policy is "byscore" - lexStart := cmd[2] // Lower bound if policy is "bylex" - lexStop := cmd[3] // Upper bound if policy is "bylex" + scoreStart := math.Inf(-1) // Lower bound if policy is "byscore" + scoreStop := math.Inf(1) // Upper bound if policy is "byscore" + lexStart := params.Command[2] // Lower bound if policy is "bylex" + lexStop := params.Command[3] // Upper bound if policy is "bylex" offset := 0 count := -1 - withscores := slices.ContainsFunc(cmd[4:], func(s string) bool { + withscores := slices.ContainsFunc(params.Command[4:], func(s string) bool { return strings.EqualFold(s, "withscores") }) - reverse := slices.ContainsFunc(cmd[4:], func(s string) bool { + reverse := slices.ContainsFunc(params.Command[4:], func(s string) bool { return strings.EqualFold(s, "rev") }) - if slices.ContainsFunc(cmd[4:], func(s string) bool { + if slices.ContainsFunc(params.Command[4:], func(s string) bool { return strings.EqualFold(s, "bylex") }) { policy = "bylex" } else { // policy is "byscore" make sure start and stop are valid float values - scoreStart, err = strconv.ParseFloat(cmd[2], 64) + scoreStart, err = strconv.ParseFloat(params.Command[2], 64) if err != nil { return nil, err } - scoreStop, err = strconv.ParseFloat(cmd[3], 64) + scoreStop, err = strconv.ParseFloat(params.Command[3], 64) if err != nil { return nil, err } } - if slices.ContainsFunc(cmd[4:], func(s string) bool { + if slices.ContainsFunc(params.Command[4:], func(s string) bool { return strings.EqualFold(s, "limit") }) { - limitIdx := slices.IndexFunc(cmd[4:], func(s string) bool { + limitIdx := slices.IndexFunc(params.Command[4:], func(s string) bool { return strings.EqualFold(s, "limit") }) - if limitIdx != -1 && limitIdx > len(cmd[4:])-3 { + if limitIdx != -1 && limitIdx > len(params.Command[4:])-3 { return nil, errors.New("limit should contain offset and count as integers") } - offset, err = strconv.Atoi(cmd[4:][limitIdx+1]) + offset, err = strconv.Atoi(params.Command[4:][limitIdx+1]) if err != nil { return nil, errors.New("limit offset must be integer") } if offset < 0 { return nil, errors.New("limit offset must be >= 0") } - count, err = strconv.Atoi(cmd[4:][limitIdx+2]) + count, err = strconv.Atoi(params.Command[4:][limitIdx+2]) if err != nil { return nil, errors.New("limit count must be integer") } } - if !server.KeyExists(ctx, key) { + if !params.KeyExists(params.Context, key) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, key); err != nil { + if _, err = params.KeyRLock(params.Context, key); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, key) + defer params.KeyRUnlock(params.Context, key) - set, ok := server.GetValue(ctx, key).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, key).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", key) } @@ -1289,8 +1287,8 @@ func handleZRANGE(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(res), nil } -func handleZRANGESTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - keys, err := zrangeStoreKeyFunc(cmd) +func handleZRANGESTORE(params types.HandlerFuncParams) ([]byte, error) { + keys, err := zrangeStoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -1298,65 +1296,65 @@ func handleZRANGESTORE(ctx context.Context, cmd []string, server types.EchoVault destination := keys.WriteKeys[0] source := keys.ReadKeys[0] policy := "byscore" - scoreStart := math.Inf(-1) // Lower bound if policy is "byscore" - scoreStop := math.Inf(1) // Upper bound if policy is "byfloat" - lexStart := cmd[3] // Lower bound if policy is "bylex" - lexStop := cmd[4] // Upper bound if policy is "bylex" + scoreStart := math.Inf(-1) // Lower bound if policy is "byscore" + scoreStop := math.Inf(1) // Upper bound if policy is "byfloat" + lexStart := params.Command[3] // Lower bound if policy is "bylex" + lexStop := params.Command[4] // Upper bound if policy is "bylex" offset := 0 count := -1 - reverse := slices.ContainsFunc(cmd[5:], func(s string) bool { + reverse := slices.ContainsFunc(params.Command[5:], func(s string) bool { return strings.EqualFold(s, "rev") }) - if slices.ContainsFunc(cmd[5:], func(s string) bool { + if slices.ContainsFunc(params.Command[5:], func(s string) bool { return strings.EqualFold(s, "bylex") }) { policy = "bylex" } else { // policy is "byscore" make sure start and stop are valid float values - scoreStart, err = strconv.ParseFloat(cmd[3], 64) + scoreStart, err = strconv.ParseFloat(params.Command[3], 64) if err != nil { return nil, err } - scoreStop, err = strconv.ParseFloat(cmd[4], 64) + scoreStop, err = strconv.ParseFloat(params.Command[4], 64) if err != nil { return nil, err } } - if slices.ContainsFunc(cmd[5:], func(s string) bool { + if slices.ContainsFunc(params.Command[5:], func(s string) bool { return strings.EqualFold(s, "limit") }) { - limitIdx := slices.IndexFunc(cmd[5:], func(s string) bool { + limitIdx := slices.IndexFunc(params.Command[5:], func(s string) bool { return strings.EqualFold(s, "limit") }) - if limitIdx != -1 && limitIdx > len(cmd[5:])-3 { + if limitIdx != -1 && limitIdx > len(params.Command[5:])-3 { return nil, errors.New("limit should contain offset and count as integers") } - offset, err = strconv.Atoi(cmd[5:][limitIdx+1]) + offset, err = strconv.Atoi(params.Command[5:][limitIdx+1]) if err != nil { return nil, errors.New("limit offset must be integer") } if offset < 0 { return nil, errors.New("limit offset must be >= 0") } - count, err = strconv.Atoi(cmd[5:][limitIdx+2]) + count, err = strconv.Atoi(params.Command[5:][limitIdx+2]) if err != nil { return nil, errors.New("limit count must be integer") } } - if !server.KeyExists(ctx, source) { + if !params.KeyExists(params.Context, source) { return []byte("*0\r\n"), nil } - if _, err = server.KeyRLock(ctx, source); err != nil { + if _, err = params.KeyRLock(params.Context, source); err != nil { return nil, err } - defer server.KeyRUnlock(ctx, source) + defer params.KeyRUnlock(params.Context, source) - set, ok := server.GetValue(ctx, source).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, source).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", source) } @@ -1413,30 +1411,30 @@ func handleZRANGESTORE(ctx context.Context, cmd []string, server types.EchoVault newSortedSet := sorted_set.NewSortedSet(resultMembers) - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - if err = server.SetValue(ctx, destination, newSortedSet); err != nil { + if err = params.SetValue(params.Context, destination, newSortedSet); err != nil { return nil, err } return []byte(fmt.Sprintf(":%d\r\n", newSortedSet.Cardinality())), nil } -func handleZUNION(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - if _, err := zunionKeyFunc(cmd); err != nil { +func handleZUNION(params types.HandlerFuncParams) ([]byte, error) { + if _, err := zunionKeyFunc(params.Command); err != nil { return nil, err } - keys, weights, aggregate, withscores, err := extractKeysWeightsAggregateWithScores(cmd) + keys, weights, aggregate, withscores, err := extractKeysWeightsAggregateWithScores(params.Command) if err != nil { return nil, err } @@ -1445,7 +1443,7 @@ func handleZUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() @@ -1453,12 +1451,12 @@ func handleZUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * var setParams []sorted_set.SortedSetParam for i := 0; i < len(keys); i++ { - if server.KeyExists(ctx, keys[i]) { - if _, err = server.KeyRLock(ctx, keys[i]); err != nil { + if params.KeyExists(params.Context, keys[i]) { + if _, err = params.KeyRLock(params.Context, keys[i]); err != nil { return nil, err } locks[keys[i]] = true - set, ok := server.GetValue(ctx, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } @@ -1485,8 +1483,8 @@ func handleZUNION(ctx context.Context, cmd []string, server types.EchoVault, _ * return []byte(res), nil } -func handleZUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault, _ *net.Conn) ([]byte, error) { - k, err := zunionstoreKeyFunc(cmd) +func handleZUNIONSTORE(params types.HandlerFuncParams) ([]byte, error) { + k, err := zunionstoreKeyFunc(params.Command) if err != nil { return nil, err } @@ -1494,11 +1492,11 @@ func handleZUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault destination := k.WriteKeys[0] // Remove destination key from list of keys - cmd = slices.DeleteFunc(cmd, func(s string) bool { + params.Command = slices.DeleteFunc(params.Command, func(s string) bool { return s == destination }) - keys, weights, aggregate, _, err := extractKeysWeightsAggregateWithScores(cmd) + keys, weights, aggregate, _, err := extractKeysWeightsAggregateWithScores(params.Command) if err != nil { return nil, err } @@ -1507,7 +1505,7 @@ func handleZUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault defer func() { for key, locked := range locks { if locked { - server.KeyRUnlock(ctx, key) + params.KeyRUnlock(params.Context, key) } } }() @@ -1515,12 +1513,12 @@ func handleZUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault var setParams []sorted_set.SortedSetParam for i := 0; i < len(keys); i++ { - if server.KeyExists(ctx, keys[i]) { - if _, err = server.KeyRLock(ctx, keys[i]); err != nil { + if params.KeyExists(params.Context, keys[i]) { + if _, err = params.KeyRLock(params.Context, keys[i]); err != nil { return nil, err } locks[keys[i]] = true - set, ok := server.GetValue(ctx, keys[i]).(*sorted_set.SortedSet) + set, ok := params.GetValue(params.Context, keys[i]).(*sorted_set.SortedSet) if !ok { return nil, fmt.Errorf("value at %s is not a sorted set", keys[i]) } @@ -1533,18 +1531,18 @@ func handleZUNIONSTORE(ctx context.Context, cmd []string, server types.EchoVault union := sorted_set.Union(aggregate, setParams...) - if server.KeyExists(ctx, destination) { - if _, err = server.KeyLock(ctx, destination); err != nil { + if params.KeyExists(params.Context, destination) { + if _, err = params.KeyLock(params.Context, destination); err != nil { return nil, err } } else { - if _, err = server.CreateKeyAndLock(ctx, destination); err != nil { + if _, err = params.CreateKeyAndLock(params.Context, destination); err != nil { return nil, err } } - defer server.KeyUnlock(ctx, destination) + defer params.KeyUnlock(params.Context, destination) - if err = server.SetValue(ctx, destination, union); err != nil { + if err = params.SetValue(params.Context, destination, union); err != nil { return nil, err } diff --git a/pkg/echovault/api_acl_test.go b/test/modules/acl/api_acl_test.go similarity index 97% rename from pkg/echovault/api_acl_test.go rename to test/modules/acl/api_acl_test.go index f6598c8..96769fe 100644 --- a/pkg/echovault/api_acl_test.go +++ b/test/modules/acl/api_acl_test.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package acl diff --git a/pkg/modules/acl/commands_test.go b/test/modules/acl/commands_test.go similarity index 99% rename from pkg/modules/acl/commands_test.go rename to test/modules/acl/commands_test.go index da8b557..5c9a81d 100644 --- a/pkg/modules/acl/commands_test.go +++ b/test/modules/acl/commands_test.go @@ -21,6 +21,7 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + acl2 "github.com/echovault/echovault/pkg/modules/acl" "github.com/tidwall/resp" "net" "slices" @@ -60,8 +61,8 @@ func setUpServer(bindAddr string, port uint16, requirePass bool, aclConfig strin } mockServer, _ := echovault.NewEchoVault( + echovault.WithCommands(acl2.Commands()), echovault.WithConfig(conf), - echovault.WithCommands(Commands()), ) // Add the initial test users to the ACL module diff --git a/pkg/echovault/api_admin_test.go b/test/modules/admin/api_admin_test.go similarity index 97% rename from pkg/echovault/api_admin_test.go rename to test/modules/admin/api_admin_test.go index afd234a..d643816 100644 --- a/pkg/echovault/api_admin_test.go +++ b/test/modules/admin/api_admin_test.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package admin diff --git a/pkg/modules/admin/commands_test.go b/test/modules/admin/commands_test.go similarity index 51% rename from pkg/modules/admin/commands_test.go rename to test/modules/admin/commands_test.go index cd558ee..6e1ac3c 100644 --- a/pkg/modules/admin/commands_test.go +++ b/test/modules/admin/commands_test.go @@ -21,20 +21,58 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/admin" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" + "strings" "testing" ) -func Test_CommandsHandler(t *testing.T) { - mockServer, _ := echovault.NewEchoVault( +var mockServer *echovault.EchoVault + +func init() { + mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(admin.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, }), - echovault.WithCommands(Commands()), ) +} - res, err := handleGetAllCommands(context.Background(), []string{"commands"}, mockServer, nil) +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + GetAllCommands: mockServer.GetAllCommands, + } +} + +func Test_CommandsHandler(t *testing.T) { + res, err := getHandler("COMMANDS")(getHandlerFuncParams(context.Background(), []string{"commands"}, nil)) if err != nil { t.Error(err) } diff --git a/pkg/echovault/api_connection_test.go b/test/modules/connection/api_connection_test.go similarity index 96% rename from pkg/echovault/api_connection_test.go rename to test/modules/connection/api_connection_test.go index afd234a..dacccb8 100644 --- a/pkg/echovault/api_connection_test.go +++ b/test/modules/connection/api_connection_test.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package connection diff --git a/pkg/modules/connection/commands_test.go b/test/modules/connection/commands_test.go similarity index 68% rename from pkg/modules/connection/commands_test.go rename to test/modules/connection/commands_test.go index 3d96fa5..675a4e2 100644 --- a/pkg/modules/connection/commands_test.go +++ b/test/modules/connection/commands_test.go @@ -21,7 +21,11 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/connection" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" + "strings" "testing" ) @@ -29,6 +33,7 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(connection.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -36,6 +41,35 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + } +} + func Test_HandlePing(t *testing.T) { ctx := context.Background() @@ -62,7 +96,7 @@ func Test_HandlePing(t *testing.T) { } for _, test := range tests { - res, err := handlePing(ctx, test.command, mockServer, nil) + res, err := getHandler("PING")(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedErr != nil && err != nil { if err.Error() != test.expectedErr.Error() { t.Errorf("expected error %s, got: %s", test.expectedErr.Error(), err.Error()) diff --git a/pkg/echovault/api_generic_test.go b/test/modules/generic/api_generic_test.go similarity index 85% rename from pkg/echovault/api_generic_test.go rename to test/modules/generic/api_generic_test.go index 9ec5b45..d0f6cdc 100644 --- a/pkg/echovault/api_generic_test.go +++ b/test/modules/generic/api_generic_test.go @@ -12,14 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package generic import ( + "context" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/clock" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/pkg/commands" - "github.com/echovault/echovault/pkg/constants" + "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/generic" "reflect" "slices" "strings" @@ -27,13 +28,36 @@ import ( "time" ) -func TestEchoVault_DEL(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(generic.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", }), ) + return ev +} + +func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { + if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + return err + } + if err := server.SetValue(ctx, key, value); err != nil { + return err + } + server.KeyUnlock(ctx, key) + return nil +} + +func presetKeyData(server *echovault.EchoVault, ctx context.Context, key string, data internal.KeyData) { + _, _ = server.CreateKeyAndLock(ctx, key) + defer server.KeyUnlock(ctx, key) + _ = server.SetValue(ctx, key, data.Value) + server.SetExpiry(ctx, key, data.ExpireAt, false) +} + +func TestEchoVault_DEL(t *testing.T) { + server := createEchoVault() tests := []struct { name string @@ -59,7 +83,7 @@ func TestEchoVault_DEL(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } got, err := server.DEL(tt.keys...) @@ -77,12 +101,7 @@ func TestEchoVault_DEL(t *testing.T) { func TestEchoVault_EXPIRE(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -90,8 +109,8 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd string key string time int - expireOpts EXPIREOptions - pexpireOpts PEXPIREOptions + expireOpts echovault.EXPIREOptions + pexpireOpts echovault.PEXPIREOptions want int wantErr bool }{ @@ -100,7 +119,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key1", time: 100, - expireOpts: EXPIREOptions{}, + expireOpts: echovault.EXPIREOptions{}, presetValues: map[string]internal.KeyData{ "key1": {Value: "value1", ExpireAt: time.Time{}}, }, @@ -112,7 +131,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "PEXPIRE", key: "key2", time: 1000, - pexpireOpts: PEXPIREOptions{}, + pexpireOpts: echovault.PEXPIREOptions{}, presetValues: map[string]internal.KeyData{ "key2": {Value: "value2", ExpireAt: time.Time{}}, }, @@ -124,7 +143,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key3", time: 1000, - expireOpts: EXPIREOptions{NX: true}, + expireOpts: echovault.EXPIREOptions{NX: true}, presetValues: map[string]internal.KeyData{ "key3": {Value: "value3", ExpireAt: time.Time{}}, }, @@ -136,7 +155,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key4", time: 1000, - expireOpts: EXPIREOptions{NX: true}, + expireOpts: echovault.EXPIREOptions{NX: true}, presetValues: map[string]internal.KeyData{ "key4": {Value: "value4", ExpireAt: mockClock.Now().Add(1000 * time.Second)}, }, @@ -148,7 +167,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key5", time: 1000, - expireOpts: EXPIREOptions{XX: true}, + expireOpts: echovault.EXPIREOptions{XX: true}, presetValues: map[string]internal.KeyData{ "key5": {Value: "value5", ExpireAt: mockClock.Now().Add(30 * time.Second)}, }, @@ -159,7 +178,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { name: "Return 0 when key does not have an expiry and the XX flag is provided", cmd: "EXPIRE", time: 1000, - expireOpts: EXPIREOptions{XX: true}, + expireOpts: echovault.EXPIREOptions{XX: true}, key: "key6", presetValues: map[string]internal.KeyData{ "key6": {Value: "value6", ExpireAt: time.Time{}}, @@ -172,7 +191,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key7", time: 100000, - expireOpts: EXPIREOptions{GT: true}, + expireOpts: echovault.EXPIREOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key7": {Value: "value7", ExpireAt: mockClock.Now().Add(30 * time.Second)}, }, @@ -184,7 +203,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key8", time: 1000, - expireOpts: EXPIREOptions{GT: true}, + expireOpts: echovault.EXPIREOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key8": {Value: "value8", ExpireAt: mockClock.Now().Add(3000 * time.Second)}, }, @@ -196,7 +215,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key9", time: 1000, - expireOpts: EXPIREOptions{GT: true}, + expireOpts: echovault.EXPIREOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key9": {Value: "value9", ExpireAt: time.Time{}}, }, @@ -208,7 +227,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key10", time: 1000, - expireOpts: EXPIREOptions{LT: true}, + expireOpts: echovault.EXPIREOptions{LT: true}, presetValues: map[string]internal.KeyData{ "key10": {Value: "value10", ExpireAt: mockClock.Now().Add(3000 * time.Second)}, }, @@ -220,7 +239,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { cmd: "EXPIRE", key: "key11", time: 50000, - expireOpts: EXPIREOptions{LT: true}, + expireOpts: echovault.EXPIREOptions{LT: true}, presetValues: map[string]internal.KeyData{ "key11": {Value: "value11", ExpireAt: mockClock.Now().Add(30 * time.Second)}, }, @@ -232,7 +251,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } var got int @@ -256,12 +275,7 @@ func TestEchoVault_EXPIRE(t *testing.T) { func TestEchoVault_EXPIREAT(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -269,8 +283,8 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd string key string time int - expireAtOpts EXPIREATOptions - pexpireAtOpts PEXPIREATOptions + expireAtOpts echovault.EXPIREATOptions + pexpireAtOpts echovault.PEXPIREATOptions want int wantErr bool }{ @@ -278,7 +292,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { name: "Set new expire by unix seconds", cmd: "EXPIREAT", key: "key1", - expireAtOpts: EXPIREATOptions{}, + expireAtOpts: echovault.EXPIREATOptions{}, time: int(mockClock.Now().Add(1000 * time.Second).Unix()), presetValues: map[string]internal.KeyData{ "key1": {Value: "value1", ExpireAt: time.Time{}}, @@ -290,7 +304,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { name: "Set new expire by milliseconds", cmd: "PEXPIREAT", key: "key2", - pexpireAtOpts: PEXPIREATOptions{}, + pexpireAtOpts: echovault.PEXPIREATOptions{}, time: int(mockClock.Now().Add(1000 * time.Second).UnixMilli()), presetValues: map[string]internal.KeyData{ "key2": {Value: "value2", ExpireAt: time.Time{}}, @@ -303,7 +317,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key3", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{NX: true}, + expireAtOpts: echovault.EXPIREATOptions{NX: true}, presetValues: map[string]internal.KeyData{ "key3": {Value: "value3", ExpireAt: time.Time{}}, }, @@ -314,7 +328,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { name: "Return 0, when NX flag is provided and key already has an expiry time", cmd: "EXPIREAT", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{NX: true}, + expireAtOpts: echovault.EXPIREATOptions{NX: true}, key: "key4", presetValues: map[string]internal.KeyData{ "key4": {Value: "value4", ExpireAt: mockClock.Now().Add(1000 * time.Second)}, @@ -327,7 +341,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), key: "key5", - expireAtOpts: EXPIREATOptions{XX: true}, + expireAtOpts: echovault.EXPIREATOptions{XX: true}, presetValues: map[string]internal.KeyData{ "key5": {Value: "value5", ExpireAt: mockClock.Now().Add(30 * time.Second)}, }, @@ -339,7 +353,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key6", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{XX: true}, + expireAtOpts: echovault.EXPIREATOptions{XX: true}, presetValues: map[string]internal.KeyData{ "key6": {Value: "value6", ExpireAt: time.Time{}}, }, @@ -351,7 +365,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key7", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{GT: true}, + expireAtOpts: echovault.EXPIREATOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key7": {Value: "value7", ExpireAt: mockClock.Now().Add(30 * time.Second)}, }, @@ -363,7 +377,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key8", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{GT: true}, + expireAtOpts: echovault.EXPIREATOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key8": {Value: "value8", ExpireAt: mockClock.Now().Add(3000 * time.Second)}, }, @@ -375,7 +389,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key9", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{GT: true}, + expireAtOpts: echovault.EXPIREATOptions{GT: true}, presetValues: map[string]internal.KeyData{ "key9": {Value: "value9", ExpireAt: time.Time{}}, }, @@ -386,7 +400,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key10", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{LT: true}, + expireAtOpts: echovault.EXPIREATOptions{LT: true}, presetValues: map[string]internal.KeyData{ "key10": {Value: "value10", ExpireAt: mockClock.Now().Add(3000 * time.Second)}, }, @@ -398,7 +412,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key11", time: int(mockClock.Now().Add(3000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{LT: true}, + expireAtOpts: echovault.EXPIREATOptions{LT: true}, presetValues: map[string]internal.KeyData{ "key11": {Value: "value11", ExpireAt: mockClock.Now().Add(1000 * time.Second)}, }, @@ -410,7 +424,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { cmd: "EXPIREAT", key: "key12", time: int(mockClock.Now().Add(1000 * time.Second).Unix()), - expireAtOpts: EXPIREATOptions{LT: true}, + expireAtOpts: echovault.EXPIREATOptions{LT: true}, presetValues: map[string]internal.KeyData{ "key12": {Value: "value12", ExpireAt: time.Time{}}, }, @@ -422,7 +436,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } var got int @@ -446,12 +460,7 @@ func TestEchoVault_EXPIREAT(t *testing.T) { func TestEchoVault_EXPIRETIME(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -503,7 +512,7 @@ func TestEchoVault_EXPIRETIME(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } got, err := tt.expiretimeFunc(tt.key) @@ -519,12 +528,7 @@ func TestEchoVault_EXPIRETIME(t *testing.T) { } func TestEchoVault_GET(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -551,7 +555,11 @@ func TestEchoVault_GET(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.GET(tt.key) if (err != nil) != tt.wantErr { @@ -566,12 +574,7 @@ func TestEchoVault_GET(t *testing.T) { } func TestEchoVault_MGET(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -599,7 +602,11 @@ func TestEchoVault_MGET(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.MGET(tt.keys...) @@ -625,19 +632,14 @@ func TestEchoVault_MGET(t *testing.T) { func TestEchoVault_SET(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string presetValues map[string]internal.KeyData key string value string - options SETOptions + options echovault.SETOptions want string wantErr bool }{ @@ -646,7 +648,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key1", value: "value1", - options: SETOptions{}, + options: echovault.SETOptions{}, want: "OK", wantErr: false, }, @@ -655,7 +657,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key2", value: "value2", - options: SETOptions{NX: true}, + options: echovault.SETOptions{NX: true}, want: "OK", wantErr: false, }, @@ -669,7 +671,7 @@ func TestEchoVault_SET(t *testing.T) { }, key: "key3", value: "value3", - options: SETOptions{NX: true}, + options: echovault.SETOptions{NX: true}, want: "", wantErr: true, }, @@ -683,7 +685,7 @@ func TestEchoVault_SET(t *testing.T) { }, key: "key4", value: "value4", - options: SETOptions{XX: true}, + options: echovault.SETOptions{XX: true}, want: "OK", wantErr: false, }, @@ -692,7 +694,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key5", value: "value5", - options: SETOptions{XX: true}, + options: echovault.SETOptions{XX: true}, want: "", wantErr: true, }, @@ -701,7 +703,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key6", value: "value6", - options: SETOptions{EX: 100}, + options: echovault.SETOptions{EX: 100}, want: "OK", wantErr: false, }, @@ -710,7 +712,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key7", value: "value7", - options: SETOptions{PX: 4096}, + options: echovault.SETOptions{PX: 4096}, want: "OK", wantErr: false, }, @@ -719,7 +721,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key8", value: "value8", - options: SETOptions{EXAT: int(mockClock.Now().Add(200 * time.Second).Unix())}, + options: echovault.SETOptions{EXAT: int(mockClock.Now().Add(200 * time.Second).Unix())}, want: "OK", wantErr: false, }, @@ -727,7 +729,7 @@ func TestEchoVault_SET(t *testing.T) { name: "Set exact expiry time in milliseconds from unix epoch", key: "key9", value: "value9", - options: SETOptions{PXAT: int(mockClock.Now().Add(4096 * time.Millisecond).UnixMilli())}, + options: echovault.SETOptions{PXAT: int(mockClock.Now().Add(4096 * time.Millisecond).UnixMilli())}, presetValues: nil, want: "OK", wantErr: false, @@ -742,7 +744,7 @@ func TestEchoVault_SET(t *testing.T) { }, key: "key10", value: "value10", - options: SETOptions{GET: true, EX: 1000}, + options: echovault.SETOptions{GET: true, EX: 1000}, want: "previous-value", wantErr: false, }, @@ -751,7 +753,7 @@ func TestEchoVault_SET(t *testing.T) { presetValues: nil, key: "key11", value: "value11", - options: SETOptions{GET: true, EX: 1000}, + options: echovault.SETOptions{GET: true, EX: 1000}, want: "", wantErr: false, }, @@ -760,7 +762,7 @@ func TestEchoVault_SET(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } got, err := server.SET(tt.key, tt.value, tt.options) @@ -776,12 +778,7 @@ func TestEchoVault_SET(t *testing.T) { } func TestEchoVault_MSET(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -813,12 +810,7 @@ func TestEchoVault_MSET(t *testing.T) { func TestEchoVault_PERSIST(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -857,7 +849,7 @@ func TestEchoVault_PERSIST(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } got, err := server.PERSIST(tt.key) @@ -875,12 +867,7 @@ func TestEchoVault_PERSIST(t *testing.T) { func TestEchoVault_TTL(t *testing.T) { mockClock := clock.NewClock() - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -933,7 +920,7 @@ func TestEchoVault_TTL(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, d := range tt.presetValues { - presetKeyData(server, k, d) + presetKeyData(server, context.Background(), k, d) } } got, err := tt.ttlFunc(tt.key) diff --git a/pkg/modules/generic/commands_test.go b/test/modules/generic/commands_test.go similarity index 92% rename from pkg/modules/generic/commands_test.go rename to test/modules/generic/commands_test.go index fd64081..95f012f 100644 --- a/pkg/modules/generic/commands_test.go +++ b/test/modules/generic/commands_test.go @@ -23,7 +23,11 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/generic" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" + "strings" "testing" "time" ) @@ -41,6 +45,7 @@ func init() { mockClock = clock.NewClock() mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(generic.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -48,6 +53,47 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + GetClock: mockServer.GetClock, + GetExpiry: mockServer.GetExpiry, + SetExpiry: mockServer.SetExpiry, + DeleteKey: mockServer.DeleteKey, + } +} + func Test_HandleSET(t *testing.T) { tests := []struct { name string @@ -372,7 +418,13 @@ func Test_HandleSET(t *testing.T) { } } - res, err := handleSet(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedErr != nil { if err == nil { t.Errorf("expected error \"%s\", got nil", test.expectedErr.Error()) @@ -454,7 +506,14 @@ func Test_HandleMSET(t *testing.T) { for i, test := range tests { t.Run(test.name, func(t *testing.T) { ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("MSET, %d", i)) - res, err := handleMSet(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedErr != nil { if err.Error() != test.expectedErr.Error() { t.Errorf("expected error %s, got %s", test.expectedErr.Error(), err.Error()) @@ -547,7 +606,14 @@ func Test_HandleGET(t *testing.T) { } mockServer.KeyUnlock(ctx, key) - res, err := handleGet(ctx, []string{"GET", key}, mockServer, nil) + handler := getHandler("GET") + if handler == nil { + t.Error("no handler found for command GET") + return + } + + res, err := handler(getHandlerFuncParams(ctx, []string{"GET", key}, nil)) + if err != nil { t.Error(err) } @@ -559,7 +625,7 @@ func Test_HandleGET(t *testing.T) { } // Test get non-existent key - res, err := handleGet(context.Background(), []string{"GET", "test4"}, mockServer, nil) + res, err := getHandler("GET")(getHandlerFuncParams(context.Background(), []string{"GET", "test4"}, nil)) if err != nil { t.Error(err) } @@ -585,7 +651,12 @@ func Test_HandleGET(t *testing.T) { } for _, test := range errorTests { t.Run(test.name, func(t *testing.T) { - res, err = handleGet(context.Background(), test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + res, err = handler(getHandlerFuncParams(context.Background(), test.command, nil)) if res != nil { t.Errorf("expected nil response, got: %+v", res) } @@ -631,21 +702,28 @@ func Test_HandleMGET(t *testing.T) { }, } - for _, test := range tests { + for i, test := range tests { t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("MGET, %d", i)) // Set up the values for i, key := range test.presetKeys { - _, err := mockServer.CreateKeyAndLock(context.Background(), key) + _, err := mockServer.CreateKeyAndLock(ctx, key) if err != nil { t.Error(err) } - if err = mockServer.SetValue(context.Background(), key, test.presetValues[i]); err != nil { + if err = mockServer.SetValue(ctx, key, test.presetValues[i]); err != nil { t.Error(err) } - mockServer.KeyUnlock(context.Background(), key) + mockServer.KeyUnlock(ctx, key) } // Test the command and its results - res, err := handleMGet(context.Background(), test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { // If we expect and error, branch out and check error if err.Error() != test.expectedError.Error() { @@ -734,7 +812,13 @@ func Test_HandleDEL(t *testing.T) { } } - res, err := handleDel(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedErr != nil { if err == nil { t.Errorf("exected error \"%s\", got nil", test.expectedErr.Error()) @@ -844,7 +928,13 @@ func Test_HandlePERSIST(t *testing.T) { } } - res, err := handlePersist(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err == nil { @@ -965,7 +1055,13 @@ func Test_HandleEXPIRETIME(t *testing.T) { } } - res, err := handleExpireTime(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err == nil { @@ -1067,7 +1163,13 @@ func Test_HandleTTL(t *testing.T) { } } - res, err := handleTTL(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err == nil { @@ -1300,7 +1402,13 @@ func Test_HandleEXPIRE(t *testing.T) { } } - res, err := handleExpire(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err == nil { @@ -1576,7 +1684,13 @@ func Test_HandleEXPIREAT(t *testing.T) { } } - res, err := handleExpireAt(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err == nil { diff --git a/pkg/echovault/api_hash_test.go b/test/modules/hash/api_hash_test.go similarity index 87% rename from pkg/echovault/api_hash_test.go rename to test/modules/hash/api_hash_test.go index 0aaf7d9..9ee30f1 100644 --- a/pkg/echovault/api_hash_test.go +++ b/test/modules/hash/api_hash_test.go @@ -12,25 +12,41 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package hash import ( + "context" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/pkg/commands" - "github.com/echovault/echovault/pkg/constants" + "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/hash" "reflect" "slices" "testing" ) -func TestEchoVault_HDEL(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(hash.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", }), ) + return ev +} + +func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { + if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + return err + } + if err := server.SetValue(ctx, key, value); err != nil { + return err + } + server.KeyUnlock(ctx, key) + return nil +} + +func TestEchoVault_HDEL(t *testing.T) { + server := createEchoVault() tests := []struct { name string @@ -76,7 +92,11 @@ func TestEchoVault_HDEL(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HDEL(tt.key, tt.fields...) if (err != nil) != tt.wantErr { @@ -91,13 +111,7 @@ func TestEchoVault_HDEL(t *testing.T) { } func TestEchoVault_HEXISTS(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -135,7 +149,11 @@ func TestEchoVault_HEXISTS(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HEXISTS(tt.key, tt.field) if (err != nil) != tt.wantErr { @@ -150,13 +168,7 @@ func TestEchoVault_HEXISTS(t *testing.T) { } func TestEchoVault_HGETALL(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -190,7 +202,11 @@ func TestEchoVault_HGETALL(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HGETALL(tt.key) if (err != nil) != tt.wantErr { @@ -212,13 +228,7 @@ func TestEchoVault_HGETALL(t *testing.T) { } func TestEchoVault_HINCRBY(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() const ( HINCRBY = "HINCRBY" @@ -300,7 +310,11 @@ func TestEchoVault_HINCRBY(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } var got float64 var err error @@ -326,13 +340,7 @@ func TestEchoVault_HINCRBY(t *testing.T) { } func TestEchoVault_HKEYS(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -366,7 +374,11 @@ func TestEchoVault_HKEYS(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HKEYS(tt.key) if (err != nil) != tt.wantErr { @@ -386,13 +398,7 @@ func TestEchoVault_HKEYS(t *testing.T) { } func TestEchoVault_HLEN(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -426,7 +432,11 @@ func TestEchoVault_HLEN(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HLEN(tt.key) if (err != nil) != tt.wantErr { @@ -441,19 +451,13 @@ func TestEchoVault_HLEN(t *testing.T) { } func TestEchoVault_HRANDFIELD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string presetValue interface{} key string - options HRANDFIELDOptions + options echovault.HRANDFIELDOptions wantCount int want []string wantErr bool @@ -462,7 +466,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { name: "Get a random field", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, key: "key1", - options: HRANDFIELDOptions{Count: 1}, + options: echovault.HRANDFIELDOptions{Count: 1}, wantCount: 1, want: []string{"field1", "field2", "field3"}, wantErr: false, @@ -471,7 +475,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { name: "Get a random field with a value", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, key: "key2", - options: HRANDFIELDOptions{WithValues: true, Count: 1}, + options: echovault.HRANDFIELDOptions{WithValues: true, Count: 1}, wantCount: 2, want: []string{"field1", "value1", "field2", "123456789", "field3", "3.142"}, wantErr: false, @@ -486,7 +490,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { "field5": "value5", }, key: "key3", - options: HRANDFIELDOptions{Count: 3}, + options: echovault.HRANDFIELDOptions{Count: 3}, wantCount: 3, want: []string{"field1", "field2", "field3", "field4", "field5"}, wantErr: false, @@ -501,7 +505,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { "field5": "value5", }, key: "key4", - options: HRANDFIELDOptions{WithValues: true, Count: 3}, + options: echovault.HRANDFIELDOptions{WithValues: true, Count: 3}, wantCount: 6, want: []string{ "field1", "value1", "field2", "123456789", "field3", @@ -519,7 +523,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { "field5": "value5", }, key: "key5", - options: HRANDFIELDOptions{Count: 5}, + options: echovault.HRANDFIELDOptions{Count: 5}, wantCount: 5, want: []string{"field1", "field2", "field3", "field4", "field5"}, wantErr: false, @@ -534,7 +538,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { "field5": "value5", }, key: "key5", - options: HRANDFIELDOptions{WithValues: true, Count: 5}, + options: echovault.HRANDFIELDOptions{WithValues: true, Count: 5}, wantCount: 10, want: []string{ "field1", "value1", "field2", "123456789", "field3", @@ -546,7 +550,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { name: "Trying to get random field on a non hash map returns error", presetValue: "Default value", key: "key12", - options: HRANDFIELDOptions{}, + options: echovault.HRANDFIELDOptions{}, wantCount: 0, want: nil, wantErr: true, @@ -555,7 +559,11 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HRANDFIELD(tt.key, tt.options) if (err != nil) != tt.wantErr { @@ -575,13 +583,7 @@ func TestEchoVault_HRANDFIELD(t *testing.T) { } func TestEchoVault_HSET(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -650,7 +652,11 @@ func TestEchoVault_HSET(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := tt.hsetFunc(tt.key, tt.fieldValuePairs) if (err != nil) != tt.wantErr { @@ -665,13 +671,7 @@ func TestEchoVault_HSET(t *testing.T) { } func TestEchoVault_HSTRLEN(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -719,7 +719,11 @@ func TestEchoVault_HSTRLEN(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HSTRLEN(tt.key, tt.fields...) if (err != nil) != tt.wantErr { @@ -734,13 +738,7 @@ func TestEchoVault_HSTRLEN(t *testing.T) { } func TestEchoVault_HVALS(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -774,7 +772,11 @@ func TestEchoVault_HVALS(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.HVALS(tt.key) if (err != nil) != tt.wantErr { diff --git a/pkg/modules/hash/commands_test.go b/test/modules/hash/commands_test.go similarity index 92% rename from pkg/modules/hash/commands_test.go rename to test/modules/hash/commands_test.go index 1b9e2ac..ba7c7fa 100644 --- a/pkg/modules/hash/commands_test.go +++ b/test/modules/hash/commands_test.go @@ -22,8 +22,12 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/hash" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" "slices" + "strings" "testing" ) @@ -31,6 +35,7 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(hash.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -38,6 +43,43 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + } +} + func Test_HandleHSET(t *testing.T) { // Tests for both HSET and HSETNX tests := []struct { @@ -144,7 +186,14 @@ func Test_HandleHSET(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHSET(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -163,11 +212,11 @@ func Test_HandleHSET(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) + h, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) if !ok { t.Errorf("value at key \"%s\" is not a hash map", test.key) } - for field, value := range hash { + for field, value := range h { if value != test.expectedValue[field] { t.Errorf("expected value \"%+v\" for field \"%+v\", got \"%+v\"", test.expectedValue[field], field, value) } @@ -303,7 +352,14 @@ func Test_HandleHINCRBY(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHINCRBY(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -331,11 +387,11 @@ func Test_HandleHINCRBY(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) + h, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) if !ok { t.Errorf("value at key \"%s\" is not a hash map", test.key) } - for field, value := range hash { + for field, value := range h { if value != test.expectedValue[field] { t.Errorf("expected value \"%+v\" for field \"%+v\", got \"%+v\"", test.expectedValue[field], field, value) } @@ -410,7 +466,14 @@ func Test_HandleHGET(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHGET(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -519,7 +582,14 @@ func Test_HandleHSTRLEN(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHSTRLEN(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -623,7 +693,14 @@ func Test_HandleHVALS(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHVALS(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -831,7 +908,14 @@ func Test_HandleHRANDFIELD(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHRANDFIELD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -954,7 +1038,14 @@ func Test_HandleHLEN(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHLEN(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1053,7 +1144,14 @@ func Test_HandleHKeys(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHKEYS(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1159,7 +1257,14 @@ func Test_HandleHGETALL(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHGETALL(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1276,7 +1381,14 @@ func Test_HandleHEXISTS(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHEXISTS(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1375,7 +1487,14 @@ func Test_HandleHDEL(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleHDEL(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1396,8 +1515,8 @@ func Test_HandleHDEL(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - if hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}); ok { - for field, value := range hash { + if h, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}); ok { + for field, value := range h { if value != test.expectedValue[field] { t.Errorf("expected value \"%+v\", got \"%+v\"", test.expectedValue[field], value) } diff --git a/pkg/echovault/api_list_test.go b/test/modules/list/api_list_test.go similarity index 91% rename from pkg/echovault/api_list_test.go rename to test/modules/list/api_list_test.go index 22ec6fc..4018109 100644 --- a/pkg/echovault/api_list_test.go +++ b/test/modules/list/api_list_test.go @@ -12,24 +12,40 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package list import ( + "context" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/pkg/commands" - "github.com/echovault/echovault/pkg/constants" + "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/list" "reflect" "testing" ) -func TestEchoVault_LLEN(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(list.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", }), ) + return ev +} + +func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { + if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + return err + } + if err := server.SetValue(ctx, key, value); err != nil { + return err + } + server.KeyUnlock(ctx, key) + return nil +} + +func TestEchoVault_LLEN(t *testing.T) { + server := createEchoVault() tests := []struct { preset bool @@ -67,7 +83,11 @@ func TestEchoVault_LLEN(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.LLEN(tt.key) if (err != nil) != tt.wantErr { @@ -82,13 +102,7 @@ func TestEchoVault_LLEN(t *testing.T) { } func TestEchoVault_LINDEX(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { preset bool @@ -156,7 +170,11 @@ func TestEchoVault_LINDEX(t *testing.T) { } for _, tt := range tests { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } t.Run(tt.name, func(t *testing.T) { got, err := server.LINDEX(tt.key, tt.index) @@ -172,13 +190,7 @@ func TestEchoVault_LINDEX(t *testing.T) { } func TestEchoVault_LMOVE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -328,7 +340,11 @@ func TestEchoVault_LMOVE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValue { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.LMOVE(tt.source, tt.destination, tt.whereFrom, tt.whereTo) @@ -344,13 +360,7 @@ func TestEchoVault_LMOVE(t *testing.T) { } func TestEchoVault_POP(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -401,7 +411,11 @@ func TestEchoVault_POP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := tt.popFunc(tt.key) if (err != nil) != tt.wantErr { @@ -416,13 +430,7 @@ func TestEchoVault_POP(t *testing.T) { } func TestEchoVault_LPUSH(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -478,7 +486,11 @@ func TestEchoVault_LPUSH(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := tt.lpushFunc(tt.key, tt.values...) if (err != nil) != tt.wantErr { @@ -493,13 +505,7 @@ func TestEchoVault_LPUSH(t *testing.T) { } func TestEchoVault_RPUSH(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -535,7 +541,11 @@ func TestEchoVault_RPUSH(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := tt.rpushFunc(tt.key, tt.values...) if (err != nil) != tt.wantErr { @@ -550,13 +560,7 @@ func TestEchoVault_RPUSH(t *testing.T) { } func TestEchoVault_LRANGE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -656,7 +660,11 @@ func TestEchoVault_LRANGE(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.LRANGE(tt.key, tt.start, tt.end) if (err != nil) != tt.wantErr { @@ -671,13 +679,7 @@ func TestEchoVault_LRANGE(t *testing.T) { } func TestEchoVault_LREM(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -722,7 +724,11 @@ func TestEchoVault_LREM(t *testing.T) { } for _, tt := range tests { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } t.Run(tt.name, func(t *testing.T) { got, err := server.LREM(tt.key, tt.count, tt.value) @@ -738,13 +744,7 @@ func TestEchoVault_LREM(t *testing.T) { } func TestEchoVault_LSET(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -830,7 +830,11 @@ func TestEchoVault_LSET(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.LSET(tt.key, tt.index, tt.value) if (err != nil) != tt.wantErr { @@ -845,13 +849,7 @@ func TestEchoVault_LSET(t *testing.T) { } func TestEchoVault_LTRIM(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -940,7 +938,11 @@ func TestEchoVault_LTRIM(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.LTRIM(tt.key, tt.start, tt.end) if (err != nil) != tt.wantErr { diff --git a/pkg/modules/list/commands_test.go b/test/modules/list/commands_test.go similarity index 90% rename from pkg/modules/list/commands_test.go rename to test/modules/list/commands_test.go index 94ecab1..1074d1b 100644 --- a/pkg/modules/list/commands_test.go +++ b/test/modules/list/commands_test.go @@ -22,7 +22,11 @@ import ( "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + "github.com/echovault/echovault/pkg/modules/list" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" + "strings" "testing" ) @@ -30,6 +34,7 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(list.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -37,6 +42,43 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + } +} + func Test_HandleLLEN(t *testing.T) { tests := []struct { name string @@ -113,7 +155,14 @@ func Test_HandleLLEN(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLLen(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -258,7 +307,14 @@ func Test_HandleLINDEX(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLIndex(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -426,7 +482,14 @@ func Test_HandleLRANGE(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLRange(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -577,7 +640,14 @@ func Test_HandleLSET(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLSet(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -595,16 +665,16 @@ func Test_HandleLSET(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) @@ -751,7 +821,14 @@ func Test_HandleLTRIM(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLTrim(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -769,16 +846,16 @@ func Test_HandleLTRIM(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) @@ -882,7 +959,14 @@ func Test_HandleLREM(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLRem(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -900,16 +984,16 @@ func Test_HandleLREM(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) @@ -1096,7 +1180,14 @@ func Test_HandleLMOVE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleLMove(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1115,7 +1206,7 @@ func Test_HandleLMOVE(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, key).([]interface{}) + l, ok := mockServer.GetValue(ctx, key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } @@ -1123,12 +1214,12 @@ func Test_HandleLMOVE(t *testing.T) { if !ok { t.Error("expected test value to be list, got another type") } - if len(list) != len(expectedList) { - t.Errorf("expected list length to be %d, got %d", len(expectedList), len(list)) + if len(l) != len(expectedList) { + t.Errorf("expected list length to be %d, got %d", len(expectedList), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != expectedList[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, expectedList[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != expectedList[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, expectedList[i], l[i]) } } mockServer.KeyRUnlock(ctx, key) @@ -1213,7 +1304,14 @@ func Test_HandleLPUSH(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleLPush(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1231,16 +1329,16 @@ func Test_HandleLPUSH(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) @@ -1324,7 +1422,14 @@ func Test_HandleRPUSH(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleRPush(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1342,16 +1447,16 @@ func Test_HandleRPUSH(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) @@ -1445,7 +1550,14 @@ func Test_HandlePOP(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handlePop(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1463,16 +1575,16 @@ func Test_HandlePOP(t *testing.T) { if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + l, ok := mockServer.GetValue(ctx, test.key).([]interface{}) if !ok { t.Error("expected value to be list, got another type") } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + if len(l) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(l)) } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + for i := 0; i < len(l); i++ { + if l[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], l[i]) } } mockServer.KeyRUnlock(ctx, test.key) diff --git a/pkg/echovault/api_pubsub_test.go b/test/modules/pubsub/api_pubsub_test.go similarity index 97% rename from pkg/echovault/api_pubsub_test.go rename to test/modules/pubsub/api_pubsub_test.go index afd234a..5a6d9c1 100644 --- a/pkg/echovault/api_pubsub_test.go +++ b/test/modules/pubsub/api_pubsub_test.go @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package pubsub diff --git a/pkg/modules/pubsub/commands_test.go b/test/modules/pubsub/commands_test.go similarity index 85% rename from pkg/modules/pubsub/commands_test.go rename to test/modules/pubsub/commands_test.go index 03ca8a7..07ea3b2 100644 --- a/pkg/modules/pubsub/commands_test.go +++ b/test/modules/pubsub/commands_test.go @@ -22,9 +22,12 @@ import ( internal_pubsub "github.com/echovault/echovault/internal/pubsub" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + ps "github.com/echovault/echovault/pkg/modules/pubsub" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "net" "slices" + "strings" "sync" "testing" "time" @@ -51,7 +54,7 @@ func init() { func setUpServer(bindAddr string, port uint16) *echovault.EchoVault { server, _ := echovault.NewEchoVault( - echovault.WithCommands(Commands()), + echovault.WithCommands(ps.Commands()), echovault.WithConfig(config.Config{ BindAddr: bindAddr, Port: port, @@ -62,6 +65,36 @@ func setUpServer(bindAddr string, port uint16) *echovault.EchoVault { return server } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn, mockServer *echovault.EchoVault) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + GetPubSub: mockServer.GetPubSub, + } +} + func Test_HandleSubscribe(t *testing.T) { ctx := context.WithValue(context.Background(), "test_name", "SUBSCRIBE/PSUBSCRIBE") @@ -86,7 +119,8 @@ func Test_HandleSubscribe(t *testing.T) { // Test subscribe to channels channels := []string{"sub_channel1", "sub_channel2", "sub_channel3"} for _, conn := range connections { - if _, err := handleSubscribe(ctx, append([]string{"SUBSCRIBE"}, channels...), mockServer, conn); err != nil { + _, err := getHandler("SUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"SUBSCRIBE"}, channels...), conn, mockServer)) + if err != nil { t.Error(err) } } @@ -116,7 +150,8 @@ func Test_HandleSubscribe(t *testing.T) { // Test subscribe to patterns patterns := []string{"psub_channel*"} for _, conn := range connections { - if _, err := handleSubscribe(ctx, append([]string{"PSUBSCRIBE"}, patterns...), mockServer, conn); err != nil { + _, err := getHandler("PSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PSUBSCRIBE"}, patterns...), conn, mockServer)) + if err != nil { t.Error(err) } } @@ -263,24 +298,24 @@ func Test_HandleUnsubscribe(t *testing.T) { // Subscribe all the connections to the channels and patterns for _, conn := range append(test.otherConnections, test.targetConn) { - _, err := handleSubscribe(ctx, append([]string{"SUBSCRIBE"}, test.subChannels...), mockServer, conn) + _, err := getHandler("SUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"SUBSCRIBE"}, test.subChannels...), conn, mockServer)) if err != nil { t.Error(err) } - _, err = handleSubscribe(ctx, append([]string{"PSUBSCRIBE"}, test.subPatterns...), mockServer, conn) + _, err = getHandler("PSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PSUBSCRIBE"}, test.subPatterns...), conn, mockServer)) if err != nil { t.Error(err) } } // Unsubscribe the target connection from the unsub channels and patterns - res, err := handleUnsubscribe(ctx, append([]string{"UNSUBSCRIBE"}, test.unSubChannels...), mockServer, test.targetConn) + res, err := getHandler("UNSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"UNSUBSCRIBE"}, test.unSubChannels...), test.targetConn, mockServer)) if err != nil { t.Error(err) } verifyResponse(res, test.expectedResponses["channel"]) - res, err = handleUnsubscribe(ctx, append([]string{"PUNSUBSCRIBE"}, test.unSubPatterns...), mockServer, test.targetConn) + res, err = getHandler("PUNSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PUNSUBSCRIBE"}, test.unSubPatterns...), test.targetConn, mockServer)) if err != nil { t.Error(err) } @@ -347,7 +382,7 @@ func Test_HandlePublish(t *testing.T) { subscribe := func(ctx context.Context, channels []string, patterns []string, c *net.Conn, r *resp.Conn) { // Subscribe to channels go func() { - _, _ = handleSubscribe(ctx, append([]string{"SUBSCRIBE"}, channels...), mockServer, c) + _, _ = getHandler("SUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"SUBSCRIBE"}, channels...), c, mockServer)) }() // Verify all the responses for each channel subscription for i := 0; i < len(channels); i++ { @@ -355,7 +390,7 @@ func Test_HandlePublish(t *testing.T) { } // Subscribe to all the patterns go func() { - _, _ = handleSubscribe(ctx, append([]string{"PSUBSCRIBE"}, patterns...), mockServer, c) + _, _ = getHandler("PSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PSUBSCRIBE"}, patterns...), c, mockServer)) }() // Verify all the responses for each pattern subscription for i := 0; i < len(patterns); i++ { @@ -518,7 +553,7 @@ func Test_HandlePubSubChannels(t *testing.T) { // Subscribe connections to channels go func() { - _, err := handleSubscribe(ctx, append([]string{"SUBSCRIBE"}, channels...), mockServer, &wConn1) + _, err := getHandler("SUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"SUBSCRIBE"}, channels...), &wConn1, mockServer)) if err != nil { t.Error(err) } @@ -535,7 +570,7 @@ func Test_HandlePubSubChannels(t *testing.T) { } } go func() { - _, err := handleSubscribe(ctx, append([]string{"PSUBSCRIBE"}, patterns...), mockServer, &wConn2) + _, err := getHandler("PSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PSUBSCRIBE"}, patterns...), &wConn2, mockServer)) if err != nil { t.Error(err) } @@ -571,7 +606,7 @@ func Test_HandlePubSubChannels(t *testing.T) { } // Check if all subscriptions are returned - res, err := handlePubSubChannels(ctx, []string{"PUBSUB", "CHANNELS"}, mockServer, nil) + res, err := getHandler("PUBSUB", "CHANNELS")(getHandlerFuncParams(ctx, []string{"PUBSUB", "CHANNELS"}, nil, mockServer)) if err != nil { t.Error(err) } @@ -579,45 +614,45 @@ func Test_HandlePubSubChannels(t *testing.T) { // Unsubscribe from one pattern and one channel before checking against a new slice of // expected channels/patterns in the response of the "PUBSUB CHANNELS" command - _, err = handleUnsubscribe( + _, err = getHandler("UNSUBSCRIBE")(getHandlerFuncParams( ctx, append([]string{"UNSUBSCRIBE"}, []string{"channel_2", "channel_3"}...), - mockServer, &wConn1, - ) + mockServer, + )) if err != nil { t.Error(err) } - _, err = handleUnsubscribe( + _, err = getHandler("UNSUBSCRIBE")(getHandlerFuncParams( ctx, append([]string{"UNSUBSCRIBE"}, "channel_[456]"), - mockServer, &wConn2, - ) + mockServer, + )) if err != nil { t.Error(err) } // Return all the remaining channels - res, err = handlePubSubChannels(ctx, []string{"PUBSUB", "CHANNELS"}, mockServer, nil) + res, err = getHandler("PUBSUB", "CHANNELS")(getHandlerFuncParams(ctx, []string{"PUBSUB", "CHANNELS"}, nil, mockServer)) if err != nil { t.Error(err) } verifyExpectedResponse(res, []string{"channel_1", "channel_[123]"}) // Return only one of the remaining channels when passed a pattern that matches it - res, err = handlePubSubChannels(ctx, []string{"PUBSUB", "CHANNELS", "channel_[189]"}, mockServer, nil) + res, err = getHandler("PUBSUB", "CHANNELS")(getHandlerFuncParams(ctx, []string{"PUBSUB", "CHANNELS", "channel_[189]"}, nil, mockServer)) if err != nil { t.Error(err) } verifyExpectedResponse(res, []string{"channel_1"}) // Return both remaining channels when passed a pattern that matches them - res, err = handlePubSubChannels(ctx, []string{"PUBSUB", "CHANNELS", "channel_[123]"}, mockServer, nil) + res, err = getHandler("PUBSUB", "CHANNELS")(getHandlerFuncParams(ctx, []string{"PUBSUB", "CHANNELS", "channel_[123]"}, nil, mockServer)) if err != nil { t.Error(err) } verifyExpectedResponse(res, []string{"channel_1", "channel_[123]"}) // Return none channels when passed a pattern that does not match either channel - res, err = handlePubSubChannels(ctx, []string{"PUBSUB", "CHANNELS", "channel_[456]"}, mockServer, nil) + res, err = getHandler("PUBSUB", "CHANNELS")(getHandlerFuncParams(ctx, []string{"PUBSUB", "CHANNELS", "channel_[456]"}, nil, mockServer)) if err != nil { t.Error(err) } @@ -655,7 +690,8 @@ func Test_HandleNumPat(t *testing.T) { r *resp.Conn }{w: &w, r: resp.NewConn(r)} go func() { - if _, err := handleSubscribe(ctx, append([]string{"PSUBSCRIBE"}, patterns...), mockServer, &w); err != nil { + _, err := getHandler("PSUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"PSUBSCRIBE"}, patterns...), &w, mockServer)) + if err != nil { t.Error(err) } }() @@ -685,7 +721,7 @@ func Test_HandleNumPat(t *testing.T) { } // Check that we receive all the patterns with NUMPAT commands - res, err := handlePubSubNumPat(ctx, []string{"PUBSUB", "NUMPAT"}, mockServer, nil) + res, err := getHandler("PUBSUB", "NUMPAT")(getHandlerFuncParams(ctx, []string{"PUBSUB", "NUMPAT"}, nil, mockServer)) if err != nil { t.Error(err) } @@ -693,12 +729,12 @@ func Test_HandleNumPat(t *testing.T) { // Unsubscribe from a channel and check if the number of active channels is updated for _, conn := range connections { - _, err = handleUnsubscribe(ctx, []string{"PUNSUBSCRIBE", patterns[0]}, mockServer, conn.w) + _, err = getHandler("PUNSUBSCRIBE")(getHandlerFuncParams(ctx, []string{"PUNSUBSCRIBE", patterns[0]}, conn.w, mockServer)) if err != nil { t.Error(err) } } - res, err = handlePubSubNumPat(ctx, []string{"PUBSUB", "NUMPAT"}, mockServer, nil) + res, err = getHandler("PUBSUB", "NUMPAT")(getHandlerFuncParams(ctx, []string{"PUBSUB", "NUMPAT"}, nil, mockServer)) if err != nil { t.Error(err) } @@ -706,12 +742,12 @@ func Test_HandleNumPat(t *testing.T) { // Unsubscribe from all the channels and check if we get a 0 response for _, conn := range connections { - _, err = handleUnsubscribe(ctx, []string{"PUNSUBSCRIBE"}, mockServer, conn.w) + _, err = getHandler("PUNSUBSCRIBE")(getHandlerFuncParams(ctx, []string{"PUNSUBSCRIBE"}, conn.w, mockServer)) if err != nil { t.Error(err) } } - res, err = handlePubSubNumPat(ctx, []string{"PUBSUB", "NUMPAT"}, mockServer, nil) + res, err = getHandler("PUBSUB", "NUMPAT")(getHandlerFuncParams(ctx, []string{"PUBSUB", "NUMPAT"}, nil, mockServer)) if err != nil { t.Error(err) } @@ -748,7 +784,8 @@ func Test_HandleNumSub(t *testing.T) { r *resp.Conn }{w: &w, r: resp.NewConn(r)} go func() { - if _, err := handleSubscribe(ctx, append([]string{"SUBSCRIBE"}, channels...), mockServer, &w); err != nil { + _, err := getHandler("SUBSCRIBE")(getHandlerFuncParams(ctx, append([]string{"SUBSCRIBE"}, channels...), &w, mockServer)) + if err != nil { t.Error(err) } }() @@ -793,7 +830,7 @@ func Test_HandleNumSub(t *testing.T) { for i, test := range tests { ctx = context.WithValue(ctx, "test_index", i) - res, err := handlePubSubNumSubs(ctx, test.cmd, mockServer, nil) + res, err := getHandler("PUBSUB", "NUMSUB")(getHandlerFuncParams(ctx, test.cmd, nil, mockServer)) if err != nil { t.Error(err) } diff --git a/pkg/echovault/api_set_test.go b/test/modules/set/api_set_test.go similarity index 90% rename from pkg/echovault/api_set_test.go rename to test/modules/set/api_set_test.go index 36f25a1..491eb8b 100644 --- a/pkg/echovault/api_set_test.go +++ b/test/modules/set/api_set_test.go @@ -12,26 +12,42 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package set import ( + "context" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/internal/set" - "github.com/echovault/echovault/pkg/commands" - "github.com/echovault/echovault/pkg/constants" + "github.com/echovault/echovault/pkg/echovault" + s "github.com/echovault/echovault/pkg/modules/set" "reflect" "slices" "testing" ) -func TestEchoVault_SADD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(s.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", }), ) + return ev +} + +func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { + if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + return err + } + if err := server.SetValue(ctx, key, value); err != nil { + return err + } + server.KeyUnlock(ctx, key) + return nil +} + +func TestEchoVault_SADD(t *testing.T) { + server := createEchoVault() tests := []struct { name string @@ -69,7 +85,11 @@ func TestEchoVault_SADD(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SADD(tt.key, tt.members...) if (err != nil) != tt.wantErr { @@ -84,13 +104,7 @@ func TestEchoVault_SADD(t *testing.T) { } func TestEchoVault_SCARD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -124,7 +138,11 @@ func TestEchoVault_SCARD(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SCARD(tt.key) if (err != nil) != tt.wantErr { @@ -139,13 +157,7 @@ func TestEchoVault_SCARD(t *testing.T) { } func TestEchoVault_SDIFF(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -212,7 +224,11 @@ func TestEchoVault_SDIFF(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SDIFF(tt.keys...) @@ -233,13 +249,7 @@ func TestEchoVault_SDIFF(t *testing.T) { } func TestEchoVault_SDIFFSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -312,7 +322,11 @@ func TestEchoVault_SDIFFSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SDIFFSTORE(tt.destination, tt.keys...) @@ -328,13 +342,7 @@ func TestEchoVault_SDIFFSTORE(t *testing.T) { } func TestEchoVault_SINTER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -401,7 +409,11 @@ func TestEchoVault_SINTER(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SINTER(tt.keys...) @@ -422,13 +434,7 @@ func TestEchoVault_SINTER(t *testing.T) { } func TestEchoVault_SINTERCARD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -512,7 +518,11 @@ func TestEchoVault_SINTERCARD(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SINTERCARD(tt.keys, tt.limit) @@ -528,13 +538,7 @@ func TestEchoVault_SINTERCARD(t *testing.T) { } func TestEchoVault_SINTERSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -607,7 +611,11 @@ func TestEchoVault_SINTERSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SINTERSTORE(tt.destination, tt.keys...) @@ -623,13 +631,7 @@ func TestEchoVault_SINTERSTORE(t *testing.T) { } func TestEchoVault_SISMEMBER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -667,7 +669,11 @@ func TestEchoVault_SISMEMBER(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SISMEMBER(tt.key, tt.member) if (err != nil) != tt.wantErr { @@ -682,13 +688,7 @@ func TestEchoVault_SISMEMBER(t *testing.T) { } func TestEchoVault_SMEMBERS(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -722,7 +722,11 @@ func TestEchoVault_SMEMBERS(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SMEMBERS(tt.key) if (err != nil) != tt.wantErr { @@ -742,13 +746,7 @@ func TestEchoVault_SMEMBERS(t *testing.T) { } func TestEchoVault_SMISMEMBER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -805,7 +803,11 @@ func TestEchoVault_SMISMEMBER(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SMISMEMBER(tt.key, tt.members...) if (err != nil) != tt.wantErr { @@ -820,13 +822,7 @@ func TestEchoVault_SMISMEMBER(t *testing.T) { } func TestEchoVault_SMOVE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -890,7 +886,11 @@ func TestEchoVault_SMOVE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SMOVE(tt.source, tt.destination, tt.member) @@ -906,13 +906,7 @@ func TestEchoVault_SMOVE(t *testing.T) { } func TestEchoVault_SPOP(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -942,7 +936,11 @@ func TestEchoVault_SPOP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SPOP(tt.key, tt.count) if (err != nil) != tt.wantErr { @@ -959,13 +957,7 @@ func TestEchoVault_SPOP(t *testing.T) { } func TestEchoVault_SRANDMEMBER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1007,7 +999,11 @@ func TestEchoVault_SRANDMEMBER(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SRANDMEMBER(tt.key, tt.count) if (err != nil) != tt.wantErr { @@ -1028,13 +1024,7 @@ func TestEchoVault_SRANDMEMBER(t *testing.T) { } func TestEchoVault_SREM(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1072,7 +1062,11 @@ func TestEchoVault_SREM(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.presetValue != nil { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.SREM(tt.key, tt.members...) if (err != nil) != tt.wantErr { @@ -1087,13 +1081,7 @@ func TestEchoVault_SREM(t *testing.T) { } func TestEchoVault_SUNION(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1153,7 +1141,11 @@ func TestEchoVault_SUNION(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SUNION(tt.keys...) @@ -1174,13 +1166,7 @@ func TestEchoVault_SUNION(t *testing.T) { } func TestEchoVault_SUNIONSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1230,7 +1216,11 @@ func TestEchoVault_SUNIONSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.presetValues != nil { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.SUNIONSTORE(tt.destination, tt.keys...) diff --git a/pkg/modules/set/commant_test.go b/test/modules/set/commands_test.go similarity index 93% rename from pkg/modules/set/commant_test.go rename to test/modules/set/commands_test.go index fdd35d5..aa716b9 100644 --- a/pkg/modules/set/commant_test.go +++ b/test/modules/set/commands_test.go @@ -23,8 +23,12 @@ import ( "github.com/echovault/echovault/internal/set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + s "github.com/echovault/echovault/pkg/modules/set" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" "slices" + "strings" "testing" ) @@ -32,6 +36,7 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(s.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -39,6 +44,43 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + } +} + func Test_HandleSADD(t *testing.T) { tests := []struct { name string @@ -103,7 +145,15 @@ func Test_HandleSADD(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSADD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -214,7 +264,15 @@ func Test_HandleSCARD(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSCARD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -327,7 +385,15 @@ func Test_HandleSDIFF(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSDIFF(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -454,7 +520,15 @@ func Test_HandleSDIFFSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSDIFFSTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -582,7 +656,15 @@ func Test_HandleSINTER(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSINTER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -709,7 +791,15 @@ func Test_HandleSINTERCARD(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSINTERCARD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -834,7 +924,13 @@ func Test_HandleSINTERSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSINTERSTORE(ctx, test.command, mockServer, nil) + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -939,7 +1035,14 @@ func Test_HandleSISMEMBER(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSISMEMBER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1027,7 +1130,14 @@ func Test_HandleSMEMBERS(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSMEMBERS(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1118,7 +1228,14 @@ func Test_HandleSMISMEMBER(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSMISMEMBER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1160,7 +1277,7 @@ func Test_HandleSMOVE(t *testing.T) { "SmoveSource1": set.NewSet([]string{"one", "two", "three", "four"}), "SmoveDestination1": set.NewSet([]string{"five", "six", "seven", "eight"}), }, - command: []string{"MOVE", "SmoveSource1", "SmoveDestination1", "four"}, + command: []string{"SMOVE", "SmoveSource1", "SmoveDestination1", "four"}, expectedValues: map[string]interface{}{ "SmoveSource1": set.NewSet([]string{"one", "two", "three"}), "SmoveDestination1": set.NewSet([]string{"four", "five", "six", "seven", "eight"}), @@ -1242,7 +1359,14 @@ func Test_HandleSMOVE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSMOVE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1350,7 +1474,14 @@ func Test_HandleSPOP(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSPOP(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1473,7 +1604,14 @@ func Test_HandleSRANDMEMBER(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSRANDMEMBER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1588,7 +1726,14 @@ func Test_HandleSREM(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleSREM(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1708,7 +1853,14 @@ func Test_HandleSUNION(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSUNION(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1811,7 +1963,14 @@ func Test_HandleSUNIONSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleSUNIONSTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) diff --git a/pkg/echovault/api_sorted_set_test.go b/test/modules/sorted_set/api_sorted_set_test.go similarity index 91% rename from pkg/echovault/api_sorted_set_test.go rename to test/modules/sorted_set/api_sorted_set_test.go index 6959877..9c674d6 100644 --- a/pkg/echovault/api_sorted_set_test.go +++ b/test/modules/sorted_set/api_sorted_set_test.go @@ -12,28 +12,44 @@ // See the License for the specific language governing permissions and // limitations under the License. -package echovault +package sorted_set import ( + "context" "github.com/echovault/echovault/internal" "github.com/echovault/echovault/internal/config" "github.com/echovault/echovault/internal/sorted_set" - "github.com/echovault/echovault/pkg/commands" - "github.com/echovault/echovault/pkg/constants" + "github.com/echovault/echovault/pkg/echovault" + ss "github.com/echovault/echovault/pkg/modules/sorted_set" "math" "reflect" "strconv" "testing" ) -func TestEchoVault_ZADD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(ss.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", }), ) + return ev +} + +func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { + if _, err := server.CreateKeyAndLock(ctx, key); err != nil { + return err + } + if err := server.SetValue(ctx, key, value); err != nil { + return err + } + server.KeyUnlock(ctx, key) + return nil +} + +func TestEchoVault_ZADD(t *testing.T) { + server := createEchoVault() tests := []struct { name string @@ -41,7 +57,7 @@ func TestEchoVault_ZADD(t *testing.T) { presetValue *sorted_set.SortedSet key string entries map[string]float64 - options ZADDOptions + options echovault.ZADDOptions want int wantErr bool }{ @@ -57,7 +73,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member4": math.Inf(-1), "member5": math.Inf(1), }, - options: ZADDOptions{}, + options: echovault.ZADDOptions{}, want: 5, wantErr: false, }, @@ -75,7 +91,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member4": 67.77, "member5": 10, }, - options: ZADDOptions{NX: true}, + options: echovault.ZADDOptions{NX: true}, want: 2, wantErr: false, }, @@ -93,7 +109,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member2": 67.77, "member3": 10, }, - options: ZADDOptions{NX: true}, + options: echovault.ZADDOptions{NX: true}, want: 0, wantErr: false, }, @@ -112,7 +128,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member3": 15, "member4": 99.75, }, - options: ZADDOptions{XX: true, CH: true}, + options: echovault.ZADDOptions{XX: true, CH: true}, want: 3, wantErr: false, }, @@ -130,7 +146,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member5": 100.5, "member6": 15, }, - options: ZADDOptions{XX: true}, + options: echovault.ZADDOptions{XX: true}, want: 0, wantErr: false, }, @@ -150,7 +166,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member4": 100.5, "member5": 15, }, - options: ZADDOptions{XX: true, CH: true, GT: true}, + options: echovault.ZADDOptions{XX: true, CH: true, GT: true}, want: 1, wantErr: false, }, @@ -170,7 +186,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member4": 100.5, "member5": 15, }, - options: ZADDOptions{XX: true, LT: true}, + options: echovault.ZADDOptions{XX: true, LT: true}, want: 0, wantErr: false, }, @@ -188,7 +204,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member4": 100.5, "member5": 15, }, - options: ZADDOptions{XX: true, LT: true, CH: true}, + options: echovault.ZADDOptions{XX: true, LT: true, CH: true}, want: 1, wantErr: false, }, @@ -204,7 +220,7 @@ func TestEchoVault_ZADD(t *testing.T) { entries: map[string]float64{ "member3": 5.5, }, - options: ZADDOptions{INCR: true}, + options: echovault.ZADDOptions{INCR: true}, want: 0, wantErr: false, }, @@ -217,7 +233,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member1": 3.5, "member5": 15, }, - options: ZADDOptions{NX: true, LT: true, CH: true}, + options: echovault.ZADDOptions{NX: true, LT: true, CH: true}, want: 0, wantErr: true, }, @@ -230,7 +246,7 @@ func TestEchoVault_ZADD(t *testing.T) { "member1": 10.5, "member2": 12.5, }, - options: ZADDOptions{INCR: true}, + options: echovault.ZADDOptions{INCR: true}, want: 0, wantErr: true, }, @@ -238,7 +254,11 @@ func TestEchoVault_ZADD(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZADD(tt.key, tt.entries, tt.options) if (err != nil) != tt.wantErr { @@ -253,13 +273,7 @@ func TestEchoVault_ZADD(t *testing.T) { } func TestEchoVault_ZCARD(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -301,7 +315,11 @@ func TestEchoVault_ZCARD(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZCARD(tt.key) if (err != nil) != tt.wantErr { @@ -316,13 +334,7 @@ func TestEchoVault_ZCARD(t *testing.T) { } func TestEchoVault_ZCOUNT(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -402,7 +414,11 @@ func TestEchoVault_ZCOUNT(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZCOUNT(tt.key, tt.min, tt.max) if (err != nil) != tt.wantErr { @@ -417,13 +433,7 @@ func TestEchoVault_ZCOUNT(t *testing.T) { } func TestEchoVault_ZDIFF(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -553,7 +563,11 @@ func TestEchoVault_ZDIFF(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZDIFF(tt.withscores, tt.keys...) @@ -569,13 +583,7 @@ func TestEchoVault_ZDIFF(t *testing.T) { } func TestEchoVault_ZDIFFSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -674,7 +682,11 @@ func TestEchoVault_ZDIFFSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZDIFFSTORE(tt.destination, tt.keys...) @@ -690,13 +702,7 @@ func TestEchoVault_ZDIFFSTORE(t *testing.T) { } func TestEchoVault_ZINCRBY(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -825,7 +831,11 @@ func TestEchoVault_ZINCRBY(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZINCRBY(tt.key, tt.increment, tt.member) if (err != nil) != tt.wantErr { @@ -840,20 +850,14 @@ func TestEchoVault_ZINCRBY(t *testing.T) { } func TestEchoVault_ZINTER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string preset bool presetValues map[string]interface{} keys []string - options ZINTEROptions + options echovault.ZINTEROptions want map[string]float64 wantErr bool }{ @@ -873,7 +877,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key1", "key2"}, - options: ZINTEROptions{}, + options: echovault.ZINTEROptions{}, want: map[string]float64{"three": 0, "four": 0, "five": 0}, wantErr: false, }, @@ -901,7 +905,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key3", "key4", "key5"}, - options: ZINTEROptions{WithScores: true}, + options: echovault.ZINTEROptions{WithScores: true}, want: map[string]float64{"one": 3, "eight": 24}, wantErr: false, }, @@ -929,7 +933,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key6", "key7", "key8"}, - options: ZINTEROptions{Aggregate: "MIN", WithScores: true}, + options: echovault.ZINTEROptions{Aggregate: "MIN", WithScores: true}, want: map[string]float64{"one": 1, "eight": 8}, wantErr: false, }, @@ -956,7 +960,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key9", "key10", "key11"}, - options: ZINTEROptions{WithScores: true, Aggregate: "MAX"}, + options: echovault.ZINTEROptions{WithScores: true, Aggregate: "MAX"}, want: map[string]float64{"one": 1000, "eight": 800}, wantErr: false, }, @@ -984,7 +988,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key12", "key13", "key14"}, - options: ZINTEROptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTEROptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 5, 3}}, want: map[string]float64{"one": 3105, "eight": 2808}, wantErr: false, }, @@ -1012,7 +1016,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key15", "key16", "key17"}, - options: ZINTEROptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTEROptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 5, 3}}, want: map[string]float64{"one": 3000, "eight": 2400}, wantErr: false, }, @@ -1040,7 +1044,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"key18", "key19", "key20"}, - options: ZINTEROptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTEROptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 5, 3}}, want: map[string]float64{"one": 5, "eight": 8}, wantErr: false, }, @@ -1057,7 +1061,7 @@ func TestEchoVault_ZINTER(t *testing.T) { "key22": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key21", "key22"}, - options: ZINTEROptions{Weights: []float64{1, 2, 3}}, + options: echovault.ZINTEROptions{Weights: []float64{1, 2, 3}}, want: nil, wantErr: true, }, @@ -1077,7 +1081,7 @@ func TestEchoVault_ZINTER(t *testing.T) { "key25": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key23", "key24", "key25"}, - options: ZINTEROptions{Weights: []float64{5, 4}}, + options: echovault.ZINTEROptions{Weights: []float64{5, 4}}, want: nil, wantErr: true, }, @@ -1090,7 +1094,7 @@ func TestEchoVault_ZINTER(t *testing.T) { "key28": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{}, - options: ZINTEROptions{}, + options: echovault.ZINTEROptions{}, want: nil, wantErr: true, }, @@ -1108,7 +1112,7 @@ func TestEchoVault_ZINTER(t *testing.T) { "key31": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key29", "key30", "key31"}, - options: ZINTEROptions{}, + options: echovault.ZINTEROptions{}, want: nil, wantErr: true, }, @@ -1128,7 +1132,7 @@ func TestEchoVault_ZINTER(t *testing.T) { }), }, keys: []string{"non-existent", "key32", "key33"}, - options: ZINTEROptions{}, + options: echovault.ZINTEROptions{}, want: map[string]float64{}, wantErr: false, }, @@ -1137,7 +1141,11 @@ func TestEchoVault_ZINTER(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZINTER(tt.keys, tt.options) @@ -1153,13 +1161,7 @@ func TestEchoVault_ZINTER(t *testing.T) { } func TestEchoVault_ZINTERSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1167,7 +1169,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { presetValues map[string]interface{} destination string keys []string - options ZINTERSTOREOptions + options echovault.ZINTERSTOREOptions want int wantErr bool }{ @@ -1188,7 +1190,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination1", keys: []string{"key1", "key2"}, - options: ZINTERSTOREOptions{}, + options: echovault.ZINTERSTOREOptions{}, want: 3, wantErr: false, }, @@ -1217,7 +1219,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination2", keys: []string{"key3", "key4", "key5"}, - options: ZINTERSTOREOptions{WithScores: true}, + options: echovault.ZINTERSTOREOptions{WithScores: true}, want: 2, wantErr: false, }, @@ -1246,7 +1248,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination3", keys: []string{"key6", "key7", "key8"}, - options: ZINTERSTOREOptions{WithScores: true, Aggregate: "MIN"}, + options: echovault.ZINTERSTOREOptions{WithScores: true, Aggregate: "MIN"}, want: 2, wantErr: false, }, @@ -1275,7 +1277,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination4", keys: []string{"key9", "key10", "key11"}, - options: ZINTERSTOREOptions{WithScores: true, Aggregate: "MAX"}, + options: echovault.ZINTERSTOREOptions{WithScores: true, Aggregate: "MAX"}, want: 2, wantErr: false, }, @@ -1304,7 +1306,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination5", keys: []string{"key12", "key13", "key14"}, - options: ZINTERSTOREOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTERSTOREOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 5, 3}}, want: 2, wantErr: false, }, @@ -1333,7 +1335,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination6", keys: []string{"key15", "key16", "key17"}, - options: ZINTERSTOREOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTERSTOREOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 5, 3}}, want: 2, wantErr: false, }, @@ -1362,7 +1364,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination7", keys: []string{"key18", "key19", "key20"}, - options: ZINTERSTOREOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 5, 3}}, + options: echovault.ZINTERSTOREOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 5, 3}}, want: 2, wantErr: false, }, @@ -1380,7 +1382,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination8", keys: []string{"key21", "key22"}, - options: ZINTERSTOREOptions{Weights: []float64{1, 2, 3}}, + options: echovault.ZINTERSTOREOptions{Weights: []float64{1, 2, 3}}, want: 0, wantErr: true, }, @@ -1401,7 +1403,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination9", keys: []string{"key23", "key24"}, - options: ZINTERSTOREOptions{Weights: []float64{5}}, + options: echovault.ZINTERSTOREOptions{Weights: []float64{5}}, want: 0, wantErr: true, }, @@ -1415,7 +1417,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination10", keys: []string{}, - options: ZINTERSTOREOptions{Weights: []float64{5, 4}}, + options: echovault.ZINTERSTOREOptions{Weights: []float64{5, 4}}, want: 0, wantErr: true, }, @@ -1434,7 +1436,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination11", keys: []string{"key29", "key30", "key31"}, - options: ZINTERSTOREOptions{}, + options: echovault.ZINTERSTOREOptions{}, want: 0, wantErr: true, }, @@ -1455,7 +1457,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { }, destination: "destination12", keys: []string{"non-existent", "key32", "key33"}, - options: ZINTERSTOREOptions{}, + options: echovault.ZINTERSTOREOptions{}, want: 0, wantErr: false, }, @@ -1464,7 +1466,11 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZINTERSTORE(tt.destination, tt.keys, tt.options) @@ -1480,13 +1486,7 @@ func TestEchoVault_ZINTERSTORE(t *testing.T) { } func TestEchoVault_ZLEXCOUNT(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1558,7 +1558,11 @@ func TestEchoVault_ZLEXCOUNT(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZLEXCOUNT(tt.key, tt.min, tt.max) if (err != nil) != tt.wantErr { @@ -1573,20 +1577,14 @@ func TestEchoVault_ZLEXCOUNT(t *testing.T) { } func TestEchoVault_ZMPOP(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string preset bool presetValues map[string]interface{} keys []string - options ZMPOPOptions + options echovault.ZMPOPOptions want [][]string wantErr bool }{ @@ -1601,7 +1599,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key1"}, - options: ZMPOPOptions{}, + options: echovault.ZMPOPOptions{}, want: [][]string{ {"one", "1"}, }, @@ -1618,7 +1616,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key2"}, - options: ZMPOPOptions{Min: true}, + options: echovault.ZMPOPOptions{Min: true}, want: [][]string{ {"one", "1"}, }, @@ -1635,7 +1633,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key3"}, - options: ZMPOPOptions{Max: true}, + options: echovault.ZMPOPOptions{Max: true}, want: [][]string{ {"five", "5"}, }, @@ -1652,7 +1650,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key4"}, - options: ZMPOPOptions{Min: true, Count: 5}, + options: echovault.ZMPOPOptions{Min: true, Count: 5}, want: [][]string{ {"one", "1"}, {"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, @@ -1670,7 +1668,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key5"}, - options: ZMPOPOptions{Max: true, Count: 5}, + options: echovault.ZMPOPOptions{Max: true, Count: 5}, want: [][]string{{"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, {"six", "6"}}, wantErr: false, }, @@ -1686,7 +1684,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key6", "key7"}, - options: ZMPOPOptions{Max: true, Count: 5}, + options: echovault.ZMPOPOptions{Max: true, Count: 5}, want: [][]string{{"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, {"six", "6"}}, wantErr: false, }, @@ -1704,7 +1702,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { }), }, keys: []string{"key8", "key9", "key10", "key11"}, - options: ZMPOPOptions{Min: true, Count: 5}, + options: echovault.ZMPOPOptions{Min: true, Count: 5}, want: [][]string{{"one", "1"}, {"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}}, wantErr: false, }, @@ -1713,7 +1711,11 @@ func TestEchoVault_ZMPOP(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZMPOP(tt.keys, tt.options) @@ -1729,13 +1731,7 @@ func TestEchoVault_ZMPOP(t *testing.T) { } func TestEchoVault_ZMSCORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1782,7 +1778,11 @@ func TestEchoVault_ZMSCORE(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZMSCORE(tt.key, tt.members...) if (err != nil) != tt.wantErr { @@ -1810,13 +1810,7 @@ func TestEchoVault_ZMSCORE(t *testing.T) { } func TestEchoVault_ZPOP(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1903,7 +1897,11 @@ func TestEchoVault_ZPOP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := tt.popFunc(tt.key, tt.count) if (err != nil) != tt.wantErr { @@ -1918,13 +1916,7 @@ func TestEchoVault_ZPOP(t *testing.T) { } func TestEchoVault_ZRANDMEMBER(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -1979,7 +1971,11 @@ func TestEchoVault_ZRANDMEMBER(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZRANDMEMBER(tt.key, tt.count, tt.withscores) if (err != nil) != tt.wantErr { @@ -1994,13 +1990,7 @@ func TestEchoVault_ZRANDMEMBER(t *testing.T) { } func TestEchoVault_ZRANGE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2009,7 +1999,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key string start string stop string - options ZRANGEOptions + options echovault.ZRANGEOptions want map[string]float64 wantErr bool }{ @@ -2025,7 +2015,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key1", start: "3", stop: "7", - options: ZRANGEOptions{ByScore: true}, + options: echovault.ZRANGEOptions{ByScore: true}, want: map[string]float64{"three": 0, "four": 0, "five": 0, "six": 0, "seven": 0}, wantErr: false, }, @@ -2041,7 +2031,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key2", start: "3", stop: "7", - options: ZRANGEOptions{ByScore: true, WithScores: true}, + options: echovault.ZRANGEOptions{ByScore: true, WithScores: true}, want: map[string]float64{"three": 3, "four": 4, "five": 5, "six": 6, "seven": 7}, wantErr: false, }, @@ -2059,7 +2049,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key3", start: "3", stop: "7", - options: ZRANGEOptions{WithScores: true, ByScore: true, Offset: 2, Count: 4}, + options: echovault.ZRANGEOptions{WithScores: true, ByScore: true, Offset: 2, Count: 4}, want: map[string]float64{"three": 3, "four": 4, "five": 5}, wantErr: false, }, @@ -2075,7 +2065,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key4", start: "c", stop: "g", - options: ZRANGEOptions{ByLex: true}, + options: echovault.ZRANGEOptions{ByLex: true}, want: map[string]float64{"c": 0, "d": 0, "e": 0, "f": 0, "g": 0}, wantErr: false, }, @@ -2091,7 +2081,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key5", start: "a", stop: "f", - options: ZRANGEOptions{ByLex: true, WithScores: true}, + options: echovault.ZRANGEOptions{ByLex: true, WithScores: true}, want: map[string]float64{"a": 1, "b": 1, "c": 1, "d": 1, "e": 1, "f": 1}, wantErr: false, }, @@ -2109,7 +2099,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key6", start: "a", stop: "h", - options: ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: map[string]float64{"c": 1, "d": 1, "e": 1}, wantErr: false, }, @@ -2125,7 +2115,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key7", start: "a", stop: "h", - options: ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: map[string]float64{}, wantErr: false, }, @@ -2136,7 +2126,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { key: "key10", start: "a", stop: "h", - options: ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGEOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: nil, wantErr: true, }, @@ -2144,7 +2134,11 @@ func TestEchoVault_ZRANGE(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZRANGE(tt.key, tt.start, tt.stop, tt.options) if (err != nil) != tt.wantErr { @@ -2159,13 +2153,7 @@ func TestEchoVault_ZRANGE(t *testing.T) { } func TestEchoVault_ZRANGESTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2175,7 +2163,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source string start string stop string - options ZRANGESTOREOptions + options echovault.ZRANGESTOREOptions want int wantErr bool }{ @@ -2194,7 +2182,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key1", start: "3", stop: "7", - options: ZRANGESTOREOptions{ByScore: true}, + options: echovault.ZRANGESTOREOptions{ByScore: true}, want: 5, wantErr: false, }, @@ -2213,7 +2201,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key2", start: "3", stop: "7", - options: ZRANGESTOREOptions{WithScores: true, ByScore: true}, + options: echovault.ZRANGESTOREOptions{WithScores: true, ByScore: true}, want: 5, wantErr: false, }, @@ -2234,7 +2222,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key3", start: "3", stop: "7", - options: ZRANGESTOREOptions{ByScore: true, WithScores: true, Offset: 2, Count: 4}, + options: echovault.ZRANGESTOREOptions{ByScore: true, WithScores: true, Offset: 2, Count: 4}, want: 3, wantErr: false, }, @@ -2253,7 +2241,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key4", start: "c", stop: "g", - options: ZRANGESTOREOptions{ByLex: true}, + options: echovault.ZRANGESTOREOptions{ByLex: true}, want: 5, wantErr: false, }, @@ -2272,7 +2260,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key5", start: "a", stop: "f", - options: ZRANGESTOREOptions{ByLex: true, WithScores: true}, + options: echovault.ZRANGESTOREOptions{ByLex: true, WithScores: true}, want: 6, wantErr: false, }, @@ -2293,7 +2281,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key6", start: "a", stop: "h", - options: ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: 3, wantErr: false, }, @@ -2315,7 +2303,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key7", start: "a", stop: "h", - options: ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: 3, wantErr: false, }, @@ -2334,7 +2322,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key8", start: "a", stop: "h", - options: ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: 0, wantErr: false, }, @@ -2348,7 +2336,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { source: "key9", start: "a", stop: "h", - options: ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, + options: echovault.ZRANGESTOREOptions{WithScores: true, ByLex: true, Offset: 2, Count: 4}, want: 0, wantErr: true, }, @@ -2357,7 +2345,11 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZRANGESTORE(tt.destination, tt.source, tt.start, tt.stop, tt.options) @@ -2373,13 +2365,7 @@ func TestEchoVault_ZRANGESTORE(t *testing.T) { } func TestEchoVault_ZRANK(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2457,7 +2443,11 @@ func TestEchoVault_ZRANK(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZRANK(tt.key, tt.member, tt.withscores) if (err != nil) != tt.wantErr { @@ -2472,13 +2462,7 @@ func TestEchoVault_ZRANK(t *testing.T) { } func TestEchoVault_ZREM(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2528,7 +2512,11 @@ func TestEchoVault_ZREM(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZREM(tt.key, tt.members...) if (err != nil) != tt.wantErr { @@ -2543,13 +2531,7 @@ func TestEchoVault_ZREM(t *testing.T) { } func TestEchoVault_ZREMRANGEBYSCORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2600,7 +2582,11 @@ func TestEchoVault_ZREMRANGEBYSCORE(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZREMRANGEBYSCORE(tt.key, tt.min, tt.max) if (err != nil) != tt.wantErr { @@ -2615,13 +2601,7 @@ func TestEchoVault_ZREMRANGEBYSCORE(t *testing.T) { } func TestEchoVault_ZSCORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -2680,7 +2660,11 @@ func TestEchoVault_ZSCORE(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.preset { - presetValue(server, tt.key, tt.presetValue) + err := presetValue(server, context.Background(), tt.key, tt.presetValue) + if err != nil { + t.Error(err) + return + } } got, err := server.ZSCORE(tt.key, tt.member) if (err != nil) != tt.wantErr { @@ -2695,20 +2679,14 @@ func TestEchoVault_ZSCORE(t *testing.T) { } func TestEchoVault_ZUNION(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string preset bool presetValues map[string]interface{} keys []string - options ZUNIONOptions + options echovault.ZUNIONOptions want map[string]float64 wantErr bool }{ @@ -2728,7 +2706,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key1", "key2"}, - options: ZUNIONOptions{}, + options: echovault.ZUNIONOptions{}, want: map[string]float64{ "one": 0, "two": 0, "three": 0, "four": 0, "five": 0, "six": 0, "seven": 0, "eight": 0, @@ -2759,7 +2737,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key3", "key4", "key5"}, - options: ZUNIONOptions{WithScores: true}, + options: echovault.ZUNIONOptions{WithScores: true}, want: map[string]float64{ "one": 3, "two": 4, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 24, "nine": 9, "ten": 10, "eleven": 11, "twelve": 24, "thirty-six": 72, @@ -2790,7 +2768,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key6", "key7", "key8"}, - options: ZUNIONOptions{WithScores: true, Aggregate: "MIN"}, + options: echovault.ZUNIONOptions{WithScores: true, Aggregate: "MIN"}, want: map[string]float64{ "one": 1, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10, "eleven": 11, "twelve": 12, "thirty-six": 36, @@ -2821,7 +2799,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key9", "key10", "key11"}, - options: ZUNIONOptions{WithScores: true, Aggregate: "MAX"}, + options: echovault.ZUNIONOptions{WithScores: true, Aggregate: "MAX"}, want: map[string]float64{ "one": 1000, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 800, "nine": 9, "ten": 10, "eleven": 11, "twelve": 12, "thirty-six": 72, @@ -2852,7 +2830,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key12", "key13", "key14"}, - options: ZUNIONOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 2, 3}}, want: map[string]float64{ "one": 3102, "two": 6, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 2568, "nine": 27, "ten": 30, "eleven": 22, "twelve": 60, "thirty-six": 72, @@ -2883,7 +2861,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key15", "key16", "key17"}, - options: ZUNIONOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 2, 3}}, want: map[string]float64{ "one": 3000, "two": 4, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 2400, "nine": 27, "ten": 30, "eleven": 22, "twelve": 36, "thirty-six": 72, @@ -2914,7 +2892,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"key18", "key19", "key20"}, - options: ZUNIONOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 2, 3}}, want: map[string]float64{ "one": 2, "two": 2, "three": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 27, "ten": 30, "eleven": 22, "twelve": 24, "thirty-six": 72, @@ -2934,7 +2912,7 @@ func TestEchoVault_ZUNION(t *testing.T) { "key22": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key21", "key22"}, - options: ZUNIONOptions{Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONOptions{Weights: []float64{1, 2, 3}}, want: nil, wantErr: true, }, @@ -2954,7 +2932,7 @@ func TestEchoVault_ZUNION(t *testing.T) { "key25": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key23", "key24", "key25"}, - options: ZUNIONOptions{Weights: []float64{5, 4}}, + options: echovault.ZUNIONOptions{Weights: []float64{5, 4}}, want: nil, wantErr: true, }, @@ -2967,7 +2945,7 @@ func TestEchoVault_ZUNION(t *testing.T) { "key28": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{}, - options: ZUNIONOptions{Weights: []float64{5, 4}}, + options: echovault.ZUNIONOptions{Weights: []float64{5, 4}}, want: nil, wantErr: true, }, @@ -2985,7 +2963,7 @@ func TestEchoVault_ZUNION(t *testing.T) { "key31": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), }, keys: []string{"key29", "key30", "key31"}, - options: ZUNIONOptions{}, + options: echovault.ZUNIONOptions{}, want: nil, wantErr: true, }, @@ -3005,7 +2983,7 @@ func TestEchoVault_ZUNION(t *testing.T) { }), }, keys: []string{"non-existent", "key32", "key33"}, - options: ZUNIONOptions{}, + options: echovault.ZUNIONOptions{}, want: map[string]float64{ "one": 0, "two": 0, "thirty-six": 0, "twelve": 0, "eleven": 0, "seven": 0, "eight": 0, "nine": 0, "ten": 0, @@ -3017,7 +2995,11 @@ func TestEchoVault_ZUNION(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZUNION(tt.keys, tt.options) @@ -3033,13 +3015,7 @@ func TestEchoVault_ZUNION(t *testing.T) { } func TestEchoVault_ZUNIONSTORE(t *testing.T) { - server, _ := NewEchoVault( - WithCommands(commands.All()), - WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -3047,7 +3023,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { presetValues map[string]interface{} destination string keys []string - options ZUNIONSTOREOptions + options echovault.ZUNIONSTOREOptions want int wantErr bool }{ @@ -3068,7 +3044,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination1", keys: []string{"key1", "key2"}, - options: ZUNIONSTOREOptions{}, + options: echovault.ZUNIONSTOREOptions{}, want: 8, wantErr: false, }, @@ -3097,7 +3073,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination2", keys: []string{"key3", "key4", "key5"}, - options: ZUNIONSTOREOptions{WithScores: true}, + options: echovault.ZUNIONSTOREOptions{WithScores: true}, want: 13, wantErr: false, }, @@ -3126,7 +3102,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination3", keys: []string{"key6", "key7", "key8"}, - options: ZUNIONSTOREOptions{WithScores: true, Aggregate: "MIN"}, + options: echovault.ZUNIONSTOREOptions{WithScores: true, Aggregate: "MIN"}, want: 13, wantErr: false, }, @@ -3155,7 +3131,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination4", keys: []string{"key9", "key10", "key11"}, - options: ZUNIONSTOREOptions{WithScores: true, Aggregate: "MAX"}, + options: echovault.ZUNIONSTOREOptions{WithScores: true, Aggregate: "MAX"}, want: 13, wantErr: false, }, @@ -3184,7 +3160,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination5", keys: []string{"key12", "key13", "key14"}, - options: ZUNIONSTOREOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONSTOREOptions{WithScores: true, Aggregate: "SUM", Weights: []float64{1, 2, 3}}, want: 13, wantErr: false, }, @@ -3213,7 +3189,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination6", keys: []string{"key15", "key16", "key17"}, - options: ZUNIONSTOREOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONSTOREOptions{WithScores: true, Aggregate: "MAX", Weights: []float64{1, 2, 3}}, want: 13, wantErr: false, }, @@ -3242,7 +3218,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination7", keys: []string{"destination7", "key18", "key19", "key20"}, - options: ZUNIONSTOREOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONSTOREOptions{WithScores: true, Aggregate: "MIN", Weights: []float64{1, 2, 3}}, want: 13, wantErr: false, }, @@ -3260,7 +3236,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination8", keys: []string{"key21", "key22"}, - options: ZUNIONSTOREOptions{Weights: []float64{1, 2, 3}}, + options: echovault.ZUNIONSTOREOptions{Weights: []float64{1, 2, 3}}, want: 0, wantErr: true, }, @@ -3281,7 +3257,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination9", keys: []string{"key23", "key24", "key25"}, - options: ZUNIONSTOREOptions{Weights: []float64{5, 4}}, + options: echovault.ZUNIONSTOREOptions{Weights: []float64{5, 4}}, want: 0, wantErr: true, }, @@ -3300,7 +3276,7 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { }, destination: "destination11", keys: []string{"key29", "key30", "key31"}, - options: ZUNIONSTOREOptions{}, + options: echovault.ZUNIONSTOREOptions{}, want: 0, wantErr: true, }, @@ -3329,7 +3305,11 @@ func TestEchoVault_ZUNIONSTORE(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.preset { for k, v := range tt.presetValues { - presetValue(server, k, v) + err := presetValue(server, context.Background(), k, v) + if err != nil { + t.Error(err) + return + } } } got, err := server.ZUNIONSTORE(tt.destination, tt.keys, tt.options) diff --git a/pkg/modules/sorted_set/commands_test.go b/test/modules/sorted_set/commands_test.go similarity index 96% rename from pkg/modules/sorted_set/commands_test.go rename to test/modules/sorted_set/commands_test.go index bf8ed36..0810b45 100644 --- a/pkg/modules/sorted_set/commands_test.go +++ b/test/modules/sorted_set/commands_test.go @@ -23,10 +23,14 @@ import ( "github.com/echovault/echovault/internal/sorted_set" "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" + ss "github.com/echovault/echovault/pkg/modules/sorted_set" + "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" "math" + "net" "slices" "strconv" + "strings" "testing" ) @@ -34,6 +38,7 @@ var mockServer *echovault.EchoVault func init() { mockServer, _ = echovault.NewEchoVault( + echovault.WithCommands(ss.Commands()), echovault.WithConfig(config.Config{ DataDir: "", EvictionPolicy: constants.NoEviction, @@ -41,6 +46,43 @@ func init() { ) } +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } + for _, c := range mockServer.GetAllCommands() { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler + return c.HandlerFunc + } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } + } + return nil +} + +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + } +} + func Test_HandleZADD(t *testing.T) { tests := []struct { name string @@ -273,7 +315,15 @@ func Test_HandleZADD(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZADD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -390,7 +440,15 @@ func Test_HandleZCARD(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZCARD(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -542,7 +600,15 @@ func Test_HandleZCOUNT(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZCOUNT(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -666,7 +732,15 @@ func Test_HandleZLEXCOUNT(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZLEXCOUNT(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -830,7 +904,15 @@ func Test_HandleZDIFF(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZDIFF(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1016,7 +1098,15 @@ func Test_HandleZDIFFSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZDIFFSTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1246,7 +1336,15 @@ func Test_HandleZINCRBY(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZINCRBY(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1482,7 +1580,15 @@ func Test_HandleZMPOP(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZMPOP(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1665,7 +1771,15 @@ func Test_HandleZPOP(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZPOP(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1775,7 +1889,15 @@ func Test_HandleZMSCORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZMSCORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -1886,7 +2008,15 @@ func Test_HandleZSCORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZSCORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2012,7 +2142,15 @@ func Test_HandleZRANDMEMBER(t *testing.T) { } mockServer.KeyUnlock(ctx, test.key) } - res, err := handleZRANDMEMBER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2181,7 +2319,15 @@ func Test_HandleZRANK(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZRANK(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2289,7 +2435,15 @@ func Test_HandleZREM(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZREM(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2405,7 +2559,15 @@ func Test_HandleZREMRANGEBYSCORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZREMRANGEBYSCORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2578,7 +2740,15 @@ func Test_HandleZREMRANGEBYRANK(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZREMRANGEBYRANK(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2720,7 +2890,15 @@ func Test_HandleZREMRANGEBYLEX(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZREMRANGEBYLEX(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -2990,7 +3168,15 @@ func Test_HandleZRANGE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZRANGE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -3297,7 +3483,15 @@ func Test_HandleZRANGESTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZRANGESTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -3629,7 +3823,15 @@ func Test_HandleZINTER(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZINTER(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -3992,7 +4194,15 @@ func Test_HandleZINTERSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZINTERSTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -4351,7 +4561,15 @@ func Test_HandleZUNION(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZUNION(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) @@ -4753,7 +4971,15 @@ func Test_HandleZUNIONSTORE(t *testing.T) { mockServer.KeyUnlock(ctx, key) } } - res, err := handleZUNIONSTORE(ctx, test.command, mockServer, nil) + + handler := getHandler(test.command[0]) + if handler == nil { + t.Errorf("no handler found for command %s", test.command[0]) + return + } + + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) + if test.expectedError != nil { if err.Error() != test.expectedError.Error() { t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) diff --git a/test/modules/string/api_string_test.go b/test/modules/string/api_string_test.go index 9526bce..36197c9 100644 --- a/test/modules/string/api_string_test.go +++ b/test/modules/string/api_string_test.go @@ -17,12 +17,21 @@ package str import ( "context" "github.com/echovault/echovault/internal/config" - "github.com/echovault/echovault/pkg/constants" "github.com/echovault/echovault/pkg/echovault" str "github.com/echovault/echovault/pkg/modules/string" "testing" ) +func createEchoVault() *echovault.EchoVault { + ev, _ := echovault.NewEchoVault( + echovault.WithCommands(str.Commands()), + echovault.WithConfig(config.Config{ + DataDir: "", + }), + ) + return ev +} + func presetValue(server *echovault.EchoVault, ctx context.Context, key string, value interface{}) error { if _, err := server.CreateKeyAndLock(ctx, key); err != nil { return err @@ -35,13 +44,7 @@ func presetValue(server *echovault.EchoVault, ctx context.Context, key string, v } func TestEchoVault_SUBSTR(t *testing.T) { - server, _ := echovault.NewEchoVault( - echovault.WithCommands(str.Commands()), - echovault.WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -200,13 +203,7 @@ func TestEchoVault_SUBSTR(t *testing.T) { } func TestEchoVault_SETRANGE(t *testing.T) { - server, _ := echovault.NewEchoVault( - echovault.WithCommands(str.Commands()), - echovault.WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string @@ -294,13 +291,7 @@ func TestEchoVault_SETRANGE(t *testing.T) { } func TestEchoVault_STRLEN(t *testing.T) { - server, _ := echovault.NewEchoVault( - echovault.WithCommands(str.Commands()), - echovault.WithConfig(config.Config{ - DataDir: "", - EvictionPolicy: constants.NoEviction, - }), - ) + server := createEchoVault() tests := []struct { name string diff --git a/test/modules/string/commands_test.go b/test/modules/string/commands_test.go index 22ce517..9497e45 100644 --- a/test/modules/string/commands_test.go +++ b/test/modules/string/commands_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package str_test +package str import ( "bytes" @@ -26,6 +26,7 @@ import ( str "github.com/echovault/echovault/pkg/modules/string" "github.com/echovault/echovault/pkg/types" "github.com/tidwall/resp" + "net" "strconv" "strings" "testing" @@ -43,15 +44,43 @@ func init() { ) } -func getHandler(command string) types.HandlerFunc { +func getHandler(commands ...string) types.HandlerFunc { + if len(commands) == 0 { + return nil + } for _, c := range mockServer.GetAllCommands() { - if strings.EqualFold(command, c.Command) { + if strings.EqualFold(commands[0], c.Command) && len(commands) == 1 { + // Get command handler return c.HandlerFunc } + if strings.EqualFold(commands[0], c.Command) { + // Get sub-command handler + for _, sc := range c.SubCommands { + if strings.EqualFold(commands[1], sc.Command) { + return sc.HandlerFunc + } + } + } } return nil } +func getHandlerFuncParams(ctx context.Context, cmd []string, conn *net.Conn) types.HandlerFuncParams { + return types.HandlerFuncParams{ + Context: ctx, + Command: cmd, + Connection: conn, + KeyExists: mockServer.KeyExists, + CreateKeyAndLock: mockServer.CreateKeyAndLock, + KeyLock: mockServer.KeyLock, + KeyRLock: mockServer.KeyRLock, + KeyUnlock: mockServer.KeyUnlock, + KeyRUnlock: mockServer.KeyRUnlock, + GetValue: mockServer.GetValue, + SetValue: mockServer.SetValue, + } +} + func Test_HandleSetRange(t *testing.T) { tests := []struct { name string @@ -176,17 +205,7 @@ func Test_HandleSetRange(t *testing.T) { return } - res, err := handler(types.HandlerFuncParams{ - Context: ctx, - Command: test.command, - Connection: nil, - KeyExists: mockServer.KeyExists, - CreateKeyAndLock: mockServer.CreateKeyAndLock, - KeyLock: mockServer.KeyLock, - KeyUnlock: mockServer.KeyUnlock, - GetValue: mockServer.GetValue, - SetValue: mockServer.SetValue, - }) + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { @@ -291,16 +310,7 @@ func Test_HandleStrLen(t *testing.T) { return } - res, err := handler(types.HandlerFuncParams{ - Context: ctx, - Command: test.command, - Connection: nil, - KeyExists: mockServer.KeyExists, - KeyRLock: mockServer.KeyRLock, - KeyRUnlock: mockServer.KeyRUnlock, - GetValue: mockServer.GetValue, - SetValue: mockServer.SetValue, - }) + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() { @@ -436,16 +446,7 @@ func Test_HandleSubStr(t *testing.T) { return } - res, err := handler(types.HandlerFuncParams{ - Context: ctx, - Command: test.command, - Connection: nil, - KeyExists: mockServer.KeyExists, - KeyRLock: mockServer.KeyRLock, - KeyRUnlock: mockServer.KeyRUnlock, - GetValue: mockServer.GetValue, - SetValue: mockServer.SetValue, - }) + res, err := handler(getHandlerFuncParams(ctx, test.command, nil)) if test.expectedError != nil { if err.Error() != test.expectedError.Error() {