fix(aof): do not override context database when conn is nil (AOF replay fix)

This commit is contained in:
AI Engineer 2026-06-28 10:18:30 +08:00
commit 7c11581e11
329 changed files with 94488 additions and 0 deletions

80
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,80 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project
and our community a harassment-free experience for everyone, regardless
of age, body size, disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic
status, nationality, personal appearance, race, religion, or sexual
identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual
attention or advances
- Trolling, insulting/derogatory comments, and personal or political
attacks
- Public or private harassment
- Publishing others' private information, such as a physical or
electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in
a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of
acceptable behavior and are expected to take appropriate and fair
corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit,
or reject comments, commits, code, wiki edits, issues, and other
contributions that are not aligned to this Code of Conduct, or to ban
temporarily or permanently any contributor for other behaviors that they
deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also
applies when an individual is representing the project or its community
in public spaces. Examples of representing a project or community
include using an official project e-mail address, posting via an
official social media account, or acting as an appointed representative
at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may
be reported by contacting the project team at <kelvin@echovault.io>.
All complaints will be reviewed and investigated and will result in a
response that is deemed necessary and appropriate to the circumstances.
The project team is obligated to maintain confidentiality with regard to
the reporter of an incident. Further details of specific enforcement
policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in
good faith may face temporary or permanent repercussions as determined
by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor
Covenant](https://www.contributor-covenant.org), version 1.4, available
at
<https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>
For answers to common questions about this code of conduct, see
<https://www.contributor-covenant.org/faq>

65
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,65 @@
# Contributing
## Issues
Issues are very valuable to this project.
- Ideas are a valuable source of contributions others can make
- Problems show where this project is lacking
- With a question you show where contributors can improve the user
experience
Thank you for creating them.
## Pull Requests
Pull requests are a great way to get your ideas into this repository.
Before opening a pull request, reach out to one of the organization
members or state your intent in the [discord server](https://discord.com/invite/JrG4kPrF8v). This prevents you
from potentially doing redundant or low-priority work.
When deciding if I merge in a pull request I look at the following
things:
### Does it state intent
You should be clear which problem you're trying to solve with your
contribution.
For example:
> Add link to code of conduct in README.md
Doesn't tell me anything about why you're doing that
> Add link to code of conduct in README.md because users don't always
> look in the CONTRIBUTING.md
Tells me the problem that you have found, and the pull request shows me
the action you have taken to solve it.
### Is it of good quality
- There are no spelling mistakes
- It reads well
- For english language contributions: Has a good score on
[Grammarly](https://www.grammarly.com) or [Hemingway
App](https://www.hemingwayapp.com/)
### Does it move this repository closer to my vision for the repository
The aim of this repository is:
- To provide a distributed (primarily) in-memory data cache that is
embeddable in Go and compatible with RESP.
- Foster a culture of respect and gratitude in the open source
community.
### Does it follow the contributor covenant
This repository has a [code of conduct](CODE_OF_CONDUCT.md), I will
remove things that do not respect it.
If all the above conditions are met, feel free to fork the project
and open a pull request.

62
Dockerfile.dev Normal file
View File

@ -0,0 +1,62 @@
FROM --platform=linux/amd64 golang:alpine AS build
RUN apk add --no-cache gcc musl-dev
WORKDIR /build
COPY . ./
ENV CGO_ENABLED=1 CC=gcc GOOS=linux GOARCH=amd64
ENV DEST=volumes/modules
RUN CGO_ENABLED=$CGO_ENABLED CC=$CC GOOS=$GOOS GOARCH=$GOARCH go build -buildmode=plugin -o $DEST/module_set/module_set.so ./internal/volumes/modules/go/module_set/module_set.go
RUN CGO_ENABLED=$CGO_ENABLED CC=$CC GOOS=$GOOS GOARCH=$GOARCH go build -buildmode=plugin -o $DEST/module_get/module_get.so ./internal/volumes/modules/go/module_get/module_get.go
ENV DEST=bin
RUN CGO_ENABLED=$CGO_ENABLED CC=$CC GOOS=$GOOS GOARCH=$GOARCH go build -o $DEST/server ./cmd/...
FROM --platform=linux/amd64 alpine:latest AS server
RUN mkdir -p /usr/sugardb/bin/modules
RUN mkdir -p /etc/ssl/certs/sugardb/server
RUN mkdir -p /etc/ssl/certs/sugardb/client
COPY --from=build /build/volumes/modules /usr/sugardb/bin/modules
COPY --from=build /build/bin/server /usr/sugardb/bin
COPY ./openssl/server /etc/ssl/certs/sugardb/server
COPY ./openssl/client /etc/ssl/certs/sugardb/client
WORKDIR /usr/sugardb/bin
CMD "./server" \
"--bind-addr" "${BIND_ADDR}" \
"--port" "${PORT}" \
"--discovery-port" "${DISCOVERY_PORT}" \
"--server-id" "${SERVER_ID}" \
"--join-addr" "${JOIN_ADDR}" \
"--data-dir" "${DATA_DIR}" \
"--snapshot-threshold" "${SNAPSHOT_THRESHOLD}" \
"--snapshot-interval" "${SNAPSHOT_INTERVAL}" \
"--max-memory" "${MAX_MEMORY}" \
"--eviction-policy" "${EVICTION_POLICY}" \
"--eviction-sample" "${EVICTION_SAMPLE}" \
"--eviction-interval" "${EVICTION_INTERVAL}" \
"--tls=${TLS}" \
"--mtls=${MTLS}" \
"--bootstrap-cluster=${BOOTSTRAP_CLUSTER}" \
"--acl-config=${ACL_CONFIG}" \
"--require-pass=${REQUIRE_PASS}" \
"--password=${PASSWORD}" \
"--forward-commands=${FORWARD_COMMAND}" \
"--restore-snapshot=${RESTORE_SNAPSHOT}" \
"--restore-aof=${RESTORE_AOF}" \
"--aof-sync-strategy=${AOF_SYNC_STRATEGY}" \
# List of sugardb cert/key pairs
"--cert-key-pair=${CERT_KEY_PAIR_1}" \
"--cert-key-pair=${CERT_KEY_PAIR_2}" \
# List of client certs
"--client-ca=${CLIENT_CA_1}" \
# List of plugins to load on startup
"--loadmodule=${MODULE_1}" \
"--loadmodule=${MODULE_2}" \

11
Dockerfile.prod Normal file
View File

@ -0,0 +1,11 @@
FROM --platform=linux/amd64 golang:alpine AS build
RUN apk add --no-cache gcc musl-dev
WORKDIR /build
COPY . ./
RUN CGO_ENABLED=1 CC=gcc GOOS=linux GOARCH=amd64 go build -o bin/server ./cmd/...
FROM --platform=linux/amd64 alpine:latest AS server
RUN mkdir -p /usr/sugardb/bin
COPY --from=build /build/bin/server /usr/sugardb/bin
WORKDIR /usr/sugardb/bin
ENTRYPOINT ["./server"]

51
LICENSE.md Normal file
View File

@ -0,0 +1,51 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of this License; and
You must cause any modified files to carry prominent notices stating that You changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

41
Makefile Normal file
View File

@ -0,0 +1,41 @@
run:
docker-compose up --build
build-local:
CGO_ENABLED=1 go build -buildmode=plugin -o ./bin/modules/module_set/module_set.so ./internal/volumes/modules/go/module_set/module_set.go && \
CGO_ENABLED=1 go build -buildmode=plugin -o ./bin/modules/module_get/module_get.so ./internal/volumes/modules/go/module_get/module_get.go && \
CGO_ENABLED=1 go build -o ./bin ./...
build-modules-test:
CGO_ENABLED=1 go build --race=$(RACE) -buildmode=plugin -o $(OUT)/modules/module_set/module_set.so ./internal/volumes/modules/go/module_set/module_set.go && \
CGO_ENABLED=1 go build --race=$(RACE) -buildmode=plugin -o $(OUT)/modules/module_get/module_get.so ./internal/volumes/modules/go/module_get/module_get.go
test:
env RACE=false OUT=internal/modules/admin/testdata make build-modules-test && \
env RACE=false OUT=sugardb/testdata make build-modules-test && \
CGO_ENABLED=1 go test ./... -coverprofile coverage/coverage.out
test-race:
env RACE=true OUT=internal/modules/admin/testdata make build-modules-test && \
env RACE=true OUT=sugardb/testdata make build-modules-test && \
CGO_ENABLED=1 go test ./... --race
testenv-run:
docker-compose -f test_env/run/docker-compose.yaml build
docker-compose -f test_env/run/docker-compose.yaml run projenv
testenv-test:
docker-compose -f test_env/test/docker-compose.yaml up --build
testenv-test-race:
docker-compose -f test_env/test_race/docker-compose.yaml up --build
testenv-all:
docker-compose -f test_env/all/docker-compose.yaml up --build
cover:
go tool cover -html=./coverage/coverage.out
benchmark:
go run redis_benchmark.go $(if $(commands),-commands="$(commands)") $(if $(use_local_server),-use_local_server)

341
README.md Normal file
View File

@ -0,0 +1,341 @@
[![Go](https://github.com/EchoVault/SugarDB/workflows/Go/badge.svg)]()
[![Go Report Card](https://goreportcard.com/badge/github.com/echovault/echovault)](https://goreportcard.com/report/github.com/echovault/echovault)
[![codecov](https://codecov.io/gh/EchoVault/SugarDB/graph/badge.svg?token=CHWTW0IUNV)](https://codecov.io/gh/EchoVault/SugarDB)
<br/>
[![Go Reference](https://pkg.go.dev/badge/github.com/echovault/echovault.svg)](https://pkg.go.dev/github.com/echovault/sugardb)
[![GitHub Release](https://img.shields.io/github/v/release/EchoVault/SugarDB)]()
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
<br/>
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)
[![Discord](https://img.shields.io/discord/1211815152291414037?label=Discord&labelColor=%237289da)](https://discord.com/invite/JrG4kPrF8v)
<br/>
<hr/>
# Table of Contents
1. [What is SugarDB](#what-is-sugardb)
2. [Features](#features)
3. [Usage (Embedded)](#usage-embedded)
4. [Usage (Client-Server)](#usage-client-server)
1. [Homebrew](#usage-homebrew)
2. [Docker](#usage-docker)
3. [GitHub Container Registry](#usage-container-registry)
4. [Binaries](#usage-binaries)
5. [Clients](#clients)
6. [Benchmarks](#benchmarks)
7. [Commands](#commands)
1. [ACL](#commands-acl)
2. [ADMIN](#commands-admin)
3. [CONNECTION](#commands-connection)
4. [GENERIC](#commands-generic)
5. [HASH](#commands-hash)
6. [LIST](#commands-list)
7. [PUBSUB](#commands-pubsub)
8. [SET](#commands-set)
9. [SORTED SET](#commands-sortedset)
10. [STRING](#commands-string)
<a name="what-is-sugardb"></a>
# What is SugarDB?
SugarDB is a highly configurable, distributed, in-memory data store and cache implemented in Go.
It can be imported as a Go library or run as an independent service.
SugarDB aims to provide a rich set of data structures and functions for
manipulating data in memory. These data structures include, but are not limited to:
Lists, Sets, Sorted Sets, Hashes, and much more to come soon.
SugarDB provides a persistence layer for increased reliability. Both Append-Only files
and snapshots can be used to persist data in the disk for recovery in case of unexpected shutdowns.
Replication is a core feature of SugarDB and is implemented using the RAFT algorithm,
allowing you to create a fault-tolerant cluster of SugarDB nodes to improve reliability.
If you do not need a replication cluster, you can always run SugarDB
in standalone mode and have a fully capable single node.
SugarDB aims to not only be a server but to be importable to existing
projects to enhance them with SugarDB features, this
capability is always being worked on and improved.
<a name="features"></a>
# Features
Features offered by SugarDB include:
1) TLS and mTLS support for multiple server and client RootCAs.
2) Replication cluster support using the RAFT algorithm.
3) ACL Layer for user Authentication and Authorization.
4) Distributed Pub/Sub functionality.
5) Sets, Sorted Sets, Hashes, Lists and more.
6) Persistence layer with Snapshots and Append-Only files.
7) Key Eviction Policies.
8) Command extension via shared object files.
9) Command extension via embedded API.
10) Command extension via Lua Modules.
11) Command extension via JavaScript Modules.
12) Multi-database support for key namespacing.
We are working hard to add more features to SugarDB to make it
much more powerful. Features in the roadmap include:
1) Sharding
2) Streams
3) Transactions
4) Bitmap
5) HyperLogLog
6) JSON
7) Improved Observability
<a name="usage-embedded"></a>
# Usage (Embedded)
Install SugarDB with: `go get github.com/echovault/sugardb`.
Here's an example of using SugarDB as an embedded library.
You can access all of SugarDB's commands using an ergonomic API.
```go
func main() {
server, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
_, _, _ = server.Set("key", "Hello, SugarDB!", sugardb.SETOptions{})
v, _ := server.Get("key")
fmt.Println(v) // Hello, SugarDB!
// (Optional): Listen for TCP connections on this SugarDB instance.
server.Start()
}
```
An embedded SugarDB instance can still be part of a cluster, and the changes triggered
from the API will be consistent across the cluster.
<a name="usage-client-server"></a>
# Usage (Client-Server)
<a name="usage-homebrew"></a>
### Homebrew
To install via homebrew, run:
1) `brew tap echovault/sugardb`
2) `brew install echovault/echovault/sugardb`
Once installed, you can run the server with the following command:
`sugardb --bind-addr=localhost --data-dir="path/to/persistence/directory"`
<a name="usage-docker"></a>
### Docker
`docker pull echovault/sugardb`
The full list of tags can be found [here](https://hub.docker.com/r/echovault/sugardb/tags).
<a name="usage-container-registry"></a>
### Container Registry
`docker pull ghcr.io/echovault/sugardb`
The full list of tags can be found [here](https://github.com/EchoVault/SugarDB/pkgs/container/sugardb).
<a name="usage-binaries"></a>
### Binaries
You can download the binaries by clicking on a release tag and downloading
the binary for your system.
<a name="clients"></a>
# Clients
SugarDB uses RESP, which makes it compatible with existing
Redis clients.
<a name="benchmarks"></a>
# Benchmarks
To compare command performance with Redis, benchmarks can be run with:
`make benchmark`
Prerequisites:
- `brew install redis` to run the Redis server and benchmark script
- `brew tap echovault/sugardb` & `brew install echovault/echovault/sugardb` to run the SugarDB Client-Server
Benchmark script options:
- `make benchmark use_local_server=true` runs on your local SugarDB Client-Server
- `make benchmark commands=ping,set,get...` runs the benchmark script on the specified commands
<a name="commands"></a>
# Supported Commands
<a name="commands-acl"></a>
## ACL
* [ACL CAT](https://sugardb.io/docs/commands/acl/acl_cat)
* [ACL DELUSER](https://sugardb.io/docs/commands/acl/acl_deluser)
* [ACL GETUSER](https://sugardb.io/docs/commands/acl/acl_getuser)
* [ACL LIST](https://sugardb.io/docs/commands/acl/acl_list)
* [ACL LOAD](https://sugardb.io/docs/commands/acl/acl_load)
* [ACL SAVE](https://sugardb.io/docs/commands/acl/acl_save)
* [ACL SETUSER](https://sugardb.io/docs/commands/acl/acl_setuser)
* [ACL USERS](https://sugardb.io/docs/commands/acl/acl_users)
* [ACL WHOAMI](https://sugardb.io/docs/commands/acl/acl_whoami)
<a name="commands-admin"></a>
## ADMIN
* [COMMAND COUNT](https://sugardb.io/docs/commands/admin/command_count)
* [COMMAND LIST](https://sugardb.io/docs/commands/admin/command_list)
* [COMMANDS](https://sugardb.io/docs/commands/admin/commands)
* [LASTSAVE](https://sugardb.io/docs/commands/admin/lastsave)
* [MODULE LIST](https://sugardb.io/docs/commands/admin/module_list)
* [MODULE LOAD](https://sugardb.io/docs/commands/admin/module_load)
* [MODULE UNLOAD](https://sugardb.io/docs/commands/admin/module_unload)
* [REWRITEAOF](https://sugardb.io/docs/commands/admin/rewriteaof)
* [SAVE](https://sugardb.io/docs/commands/admin/save)
<a name="commands-connection"></a>
## CONNECTION
* [AUTH](https://sugardb.io/docs/commands/connection/auth)
* [ECHO](https://sugardb.io/docs/commands/connection/echo)
* [HELLO](https://sugardb.io/docs/commands/connection/hello)
* [PING](https://sugardb.io/docs/commands/connection/ping)
* [SELECT](https://sugardb.io/docs/commands/connection/select)
* [SWAPDB](https://sugardb.io/docs/commands/connection/swapdb)
<a name="commands-generic"></a>
## GENERIC
* [COPY](https://sugardb.io/docs/commands/generic/copy)
* [DBSIZE](https://sugardb.io/docs/commands/generic/dbsize)
* [DECR](https://sugardb.io/docs/commands/generic/decr)
* [DECRBY](https://sugardb.io/docs/commands/generic/decrby)
* [DEL](https://sugardb.io/docs/commands/generic/del)
* [EXISTS](https://sugardb.io/docs/commands/generic/exists)
* [EXPIRE](https://sugardb.io/docs/commands/generic/expire)
* [EXPIRETIME](https://sugardb.io/docs/commands/generic/expiretime)
* [FLUSHALL](https://sugardb.io/docs/commands/generic/flushall)
* [FLUSHDB](https://sugardb.io/docs/commands/generic/flushdb)
* [GET](https://sugardb.io/docs/commands/generic/get)
* [GETDEL](https://sugardb.io/docs/commands/generic/getdel)
* [GETEX](https://sugardb.io/docs/commands/generic/get)
* [INCR](https://sugardb.io/docs/commands/generic/incr)
* [INCRBY](https://sugardb.io/docs/commands/generic/incrby)
* [INCRBYFLOAT](https://sugardb.io/docs/commands/generic/incrbyfloat)
* [MGET](https://sugardb.io/docs/commands/generic/mget)
* [MOVE](https://sugardb.io/docs/commands/generic/move)
* [MSET](https://sugardb.io/docs/commands/generic/mset)
* [OBJECTFREQ](https://sugardb.io/docs/commands/generic/objectfreq)
* [OBJECTIDLETIME](https://sugardb.io/docs/commands/generic/objectidletime)
* [PERSIST](https://sugardb.io/docs/commands/generic/persist)
* [PEXPIRE](https://sugardb.io/docs/commands/generic/pexpire)
* [PEXPIREAT](https://sugardb.io/docs/commands/generic/pexpireat)
* [PEXPIRETIME](https://sugardb.io/docs/commands/generic/pexpiretime)
* [PTTL](https://sugardb.io/docs/commands/generic/pttl)
* [RANDOMKEY](https://sugardb.io/docs/commands/generic/randomkey)
* [RENAME](https://sugardb.io/docs/commands/generic/rename)
* [SET](https://sugardb.io/docs/commands/generic/set)
* [TTL](https://sugardb.io/docs/commands/generic/ttl)
* [TYPE](https://sugardb.io/docs/commands/generic/type)
<a name="commands-hash"></a>
## HASH
* [HDEL](https://sugardb.io/docs/commands/hash/hdel)
* [HEXISTS](https://sugardb.io/docs/commands/hash/hexists)
* [HEXPIRE](https://sugardb.io/docs/commands/hash/hexpire)
* [HGET](https://sugardb.io/docs/commands/hash/hget)
* [HGETALL](https://sugardb.io/docs/commands/hash/hgetall)
* [HINCRBY](https://sugardb.io/docs/commands/hash/hincrby)
* [HINCRBYFLOAT](https://sugardb.io/docs/commands/hash/hincrbyfloat)
* [HKEYS](https://sugardb.io/docs/commands/hash/hkeys)
* [HLEN](https://sugardb.io/docs/commands/hash/hlen)
* [HMGET](https://sugardb.io/docs/commands/hash/hmget)
* [HRANDFIELD](https://sugardb.io/docs/commands/hash/hrandfield)
* [HSET](https://sugardb.io/docs/commands/hash/hset)
* [HSETNX](https://sugardb.io/docs/commands/hash/hsetnx)
* [HSTRLEN](https://sugardb.io/docs/commands/hash/hstrlen)
* [HTTL](https://sugardb.io/docs/commands/hash/httl)
* [HVALS](https://sugardb.io/docs/commands/hash/hvals)
<a name="commands-list"></a>
## LIST
* [LINDEX](https://sugardb.io/docs/commands/list/lindex)
* [LLEN](https://sugardb.io/docs/commands/list/llen)
* [LMOVE](https://sugardb.io/docs/commands/list/lmove)
* [LPOP](https://sugardb.io/docs/commands/list/lpop)
* [LPUSH](https://sugardb.io/docs/commands/list/lpush)
* [LPUSHX](https://sugardb.io/docs/commands/list/lpushx)
* [LRANGE](https://sugardb.io/docs/commands/list/lrange)
* [LREM](https://sugardb.io/docs/commands/list/lrem)
* [LSET](https://sugardb.io/docs/commands/list/lset)
* [LTRIM](https://sugardb.io/docs/commands/list/ltrim)
* [RPOP](https://sugardb.io/docs/commands/list/rpop)
* [RPUSH](https://sugardb.io/docs/commands/list/rpush)
* [RPUSHX](https://sugardb.io/docs/commands/list/rpushx)
<a name="commands-pubsub"></a>
## PUBSUB
* [PSUBSCRIBE](https://sugardb.io/docs/commands/pubsub/psubscribe)
* [PUBLISH](https://sugardb.io/docs/commands/pubsub/publish)
* [PUBSUB CHANNELS](https://sugardb.io/docs/commands/pubsub/pubsub_channels)
* [PUBSUB NUMPAT](https://sugardb.io/docs/commands/pubsub/pubsub_numpat)
* [PUBSUB NUMSUB](https://sugardb.io/docs/commands/pubsub/pubsub_numsub)
* [PUNSUBSCRIBE](https://sugardb.io/docs/commands/pubsub/punsubscribe)
* [SUBSCRIBE](https://sugardb.io/docs/commands/pubsub/subscribe)
* [UNSUBSCRIBE](https://sugardb.io/docs/commands/pubsub/unsubscribe)
<a name="commands-set"></a>
## SET
* [SADD](https://sugardb.io/docs/commands/set/sadd)
* [SCARD](https://sugardb.io/docs/commands/set/scard)
* [SDIFF](https://sugardb.io/docs/commands/set/sdiff)
* [SDIFFSTORE](https://sugardb.io/docs/commands/set/sdiffstore)
* [SINTER](https://sugardb.io/docs/commands/set/sinter)
* [SINTERCARD](https://sugardb.io/docs/commands/set/sintercard)
* [SINTERSTORE](https://sugardb.io/docs/commands/set/sinterstore)
* [SISMEMBER](https://sugardb.io/docs/commands/set/sismember)
* [SMEMBERS](https://sugardb.io/docs/commands/set/smembers)
* [SMISMEMBER](https://sugardb.io/docs/commands/set/smismember)
* [SMOVE](https://sugardb.io/docs/commands/set/smove)
* [SPOP](https://sugardb.io/docs/commands/set/spop)
* [SRANDMEMBER](https://sugardb.io/docs/commands/set/srandmember)
* [SREM](https://sugardb.io/docs/commands/set/srem)
* [SUNION](https://sugardb.io/docs/commands/set/sunion)
* [SUNIONSTORE](https://sugardb.io/docs/commands/set/sunionstore)
<a name="commands-sortedset"></a>
## SORTED SET
* [ZADD](https://sugardb.io/docs/commands/sorted_set/zadd)
* [ZCARD](https://sugardb.io/docs/commands/sorted_set/zcard)
* [ZCOUNT](https://sugardb.io/docs/commands/sorted_set/zcount)
* [ZDIFF](https://sugardb.io/docs/commands/sorted_set/zdiff)
* [ZDIFFSTORE](https://sugardb.io/docs/commands/sorted_set/zdiffstore)
* [ZINCRBY](https://sugardb.io/docs/commands/sorted_set/zincrby)
* [ZINTER](https://sugardb.io/docs/commands/sorted_set/zinter)
* [ZINTERSTORE](https://sugardb.io/docs/commands/sorted_set/zinterstore)
* [ZLEXCOUNT](https://sugardb.io/docs/commands/sorted_set/zlexcount)
* [ZMPOP](https://sugardb.io/docs/commands/sorted_set/zmpop)
* [ZMSCORE](https://sugardb.io/docs/commands/sorted_set/zmscore)
* [ZPOPMAX](https://sugardb.io/docs/commands/sorted_set/zpopmax)
* [ZPOPMIN](https://sugardb.io/docs/commands/sorted_set/zpopmin)
* [ZRANDMEMBER](https://sugardb.io/docs/commands/sorted_set/zrandmember)
* [ZRANGE](https://sugardb.io/docs/commands/sorted_set/zrange)
* [ZRANGESTORE](https://sugardb.io/docs/commands/sorted_set/zrangestore)
* [ZRANK](https://sugardb.io/docs/commands/sorted_set/zrank)
* [ZREM](https://sugardb.io/docs/commands/sorted_set/zrem)
* [ZREMRANGEBYLEX](https://sugardb.io/docs/commands/sorted_set/zremrangebylex)
* [ZREMRANGEBYRANK](https://sugardb.io/docs/commands/sorted_set/zremrangebyrank)
* [ZREMRANGEBYSCORE](https://sugardb.io/docs/commands/sorted_set/zremrangebyscore)
* [ZREVRANK](https://sugardb.io/docs/commands/sorted_set/zrevrank)
* [ZSCORE](https://sugardb.io/docs/commands/sorted_set/zscore)
* [ZUNION](https://sugardb.io/docs/commands/sorted_set/zunion)
* [ZUNIONSTORE](https://sugardb.io/docs/commands/sorted_set/zunionstore)
<a name="commands-string"></a>
## STRING
* [APPEND](https://sugardb.io/docs/commands/string/append)
* [GETRANGE](https://sugardb.io/docs/commands/string/getrange)
* [SETRANGE](https://sugardb.io/docs/commands/string/setrange)
* [STRLEN](https://sugardb.io/docs/commands/string/strlen)
* [SUBSTR](https://sugardb.io/docs/commands/string/substr)

53
cmd/main.go Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2024 Kelvin Clement Mwinuka
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"context"
"apigo.cc/go/sugardb/internal"
"apigo.cc/go/sugardb/internal/config"
"apigo.cc/go/sugardb/sugardb"
"log"
"os"
"os/signal"
"syscall"
)
func main() {
conf, err := config.GetConfig()
if err != nil {
log.Fatal(err)
}
ctx := context.WithValue(context.Background(), internal.ContextServerID("ServerID"), conf.ServerID)
cancelCh := make(chan os.Signal, 1)
signal.Notify(cancelCh, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
server, err := sugardb.NewSugarDB(
sugardb.WithContext(ctx),
sugardb.WithConfig(conf),
)
if err != nil {
log.Fatal(err)
}
go server.Start()
<-cancelCh
server.ShutDown()
}

10378
coverage/coverage.out Normal file

File diff suppressed because it is too large Load Diff

281
docker-compose.yaml Normal file
View File

@ -0,0 +1,281 @@
networks:
testnet:
driver: bridge
services:
standalone_node:
container_name: standalone_node
build:
context: .
dockerfile: Dockerfile.dev
environment:
- BIND_ADDR=0.0.0.0
- PORT=7480
- DISCOVERY_PORT=7946
- SERVER_ID=1
- PLUGIN_DIR=/usr/local/lib/sugardb
- DATA_DIR=/var/lib/sugardb
- TLS=false
- MTLS=false
- BOOTSTRAP_CLUSTER=false
- ACL_CONFIG=/etc/sugardb/config/acl.yml
- REQUIRE_PASS=false
- PASSWORD=password1
- FORWARD_COMMAND=false
- SNAPSHOT_THRESHOLD=1000
- SNAPSHOT_INTERVAL=5m30s
- RESTORE_SNAPSHOT=true
- RESTORE_AOF=false
- AOF_SYNC_STRATEGY=everysec
- MAX_MEMORY=2000kb
- EVICTION_POLICY=noeviction
- EVICTION_SAMPLE=20
- EVICTION_INTERVAL=100ms
# List of sugardb cert/key pairs
- CERT_KEY_PAIR_1=/etc/ssl/certs/sugardb/server/server1.crt,/etc/ssl/certs/sugardb/server/server1.key
- CERT_KEY_PAIR_2=/etc/ssl/certs/sugardb/server/server2.crt,/etc/ssl/certs/sugardb/server/server2.key
# List of client certificate authorities
- CLIENT_CA_1=/etc/ssl/certs/sugardb/client/rootCA.crt
# List of shared object plugins to load on startup
- MODULE_1=./modules/module_set/module_set.so
- MODULE_2=./modules/module_get/module_get.so
ports:
- "7480:7480"
- "7946:7946"
volumes:
- ./internal/volumes/config:/etc/sugardb/config
- ./internal/volumes/nodes/standalone_node:/var/lib/sugardb
- ./internal/volumes/modules/lua:/var/lib/sugardb/scripts/lua
- ./internal/volumes/modules/js:/var/lib/sugardb/scripts/js
networks:
- testnet
cluster_node_1:
container_name: cluster_node_1
build:
context: .
dockerfile: Dockerfile.dev
environment:
- BIND_ADDR=0.0.0.0
- PORT=7480
- DISCOVERY_PORT=7946
- SERVER_ID=1
- JOIN_ADDR=2/cluster_node_2:7946
- DATA_DIR=/var/lib/sugardb
- TLS=false
- MTLS=false
- BOOTSTRAP_CLUSTER=true
- ACL_CONFIG=/etc/sugardb/config/acl.yml
- REQUIRE_PASS=false
- FORWARD_COMMAND=true
- SNAPSHOT_THRESHOLD=1000
- SNAPSHOT_INTERVAL=5m30s
- RESTORE_SNAPSHOT=false
- RESTORE_AOF=false
- AOF_SYNC_STRATEGY=everysec
- MAX_MEMORY=100mb
- EVICTION_POLICY=noeviction
- EVICTION_SAMPLE=20
- EVICTION_INTERVAL=100ms
# List of sugardb cert/key pairs
- CERT_KEY_PAIR_1=/etc/ssl/certs/sugardb/server/server1.crt,/etc/ssl/certs/sugardb/server/server1.key
- CERT_KEY_PAIR_2=/etc/ssl/certs/sugardb/server/server2.crt,/etc/ssl/certs/sugardb/server/server2.key
# List of client certificate authorities
- CLIENT_CA_1=/etc/ssl/certs/sugardb/client/rootCA.crt
# List of shared object plugins to load on startup
- MODULE_1=./modules/module_set/module_set.so
- MODULE_2=./modules/module_get/module_get.so
ports:
- "7481:7480"
- "7945:7946"
volumes:
- ./internal/volumes/config:/etc/sugardb/config
- ./internal/volumes/nodes/cluster_node_1:/var/lib/sugardb
- ./internal/volumes/modules/lua:/var/lib/sugardb/scripts/lua
- ./internal/volumes/modules/js:/var/lib/sugardb/scripts/js
networks:
- testnet
cluster_node_2:
container_name: cluster_node_2
build:
context: .
dockerfile: Dockerfile.dev
environment:
- BIND_ADDR=0.0.0.0
- PORT=7480
- DISCOVERY_PORT=7946
- SERVER_ID=2
- JOIN_ADDR=3/cluster_node_3:7946
- DATA_DIR=/var/lib/sugardb
- TLS=false
- MTLS=false
- BOOTSTRAP_CLUSTER=false
- ACL_CONFIG=/etc/sugardb/config/acl.yml
- REQUIRE_PASS=false
- FORWARD_COMMAND=true
- SNAPSHOT_THRESHOLD=1000
- SNAPSHOT_INTERVAL=5m30s
- RESTORE_SNAPSHOT=false
- RESTORE_AOF=false
- AOF_SYNC_STRATEGY=everysec
- MAX_MEMORY=100mb
- EVICTION_POLICY=noeviction
- EVICTION_SAMPLE=20
- EVICTION_INTERVAL=100ms
# List of sugardb cert/key pairs
- CERT_KEY_PAIR_1=/etc/ssl/certs/sugardb/server/server1.crt,/etc/ssl/certs/sugardb/server/server1.key
- CERT_KEY_PAIR_2=/etc/ssl/certs/sugardb/server/server2.crt,/etc/ssl/certs/sugardb/server/server2.key
# List of client certificate authorities
- CLIENT_CA_1=/etc/ssl/certs/sugardb/client/rootCA.crt
# List of shared object plugins to load on startup
- MODULE_1=./modules/module_set/module_set.so
- MODULE_2=./modules/module_get/module_get.so
ports:
- "7482:7480"
- "7947:7946"
volumes:
- ./internal/volumes/config:/etc/sugardb/config
- ./internal/volumes/nodes/cluster_node_2:/var/lib/sugardb
- ./internal/volumes/modules/lua:/var/lib/sugardb/scripts/lua
- ./internal/volumes/modules/js:/var/lib/sugardb/scripts/js
networks:
- testnet
cluster_node_3:
container_name: cluster_node_3
build:
context: .
dockerfile: Dockerfile.dev
environment:
- BIND_ADDR=0.0.0.0
- PORT=7480
- DISCOVERY_PORT=7946
- SERVER_ID=3
- JOIN_ADDR=4/cluster_node_4:7946
- DATA_DIR=/var/lib/sugardb
- TLS=false
- MTLS=false
- BOOTSTRAP_CLUSTER=false
- ACL_CONFIG=/etc/sugardb/config/acl.yml
- REQUIRE_PASS=false
- FORWARD_COMMAND=true
- SNAPSHOT_THRESHOLD=1000
- SNAPSHOT_INTERVAL=5m30s
- RESTORE_SNAPSHOT=false
- RESTORE_AOF=false
- AOF_SYNC_STRATEGY=everysec
- MAX_MEMORY=100mb
- EVICTION_POLICY=noeviction
- EVICTION_SAMPLE=20
- EVICTION_INTERVAL=100ms
# List of sugardb cert/key pairs
- CERT_KEY_PAIR_1=/etc/ssl/certs/sugardb/server/server1.crt,/etc/ssl/certs/sugardb/server/server1.key
- CERT_KEY_PAIR_2=/etc/ssl/certs/sugardb/server/server2.crt,/etc/ssl/certs/sugardb/server/server2.key
# List of client certificate authorities
- CLIENT_CA_1=/etc/ssl/certs/sugardb/client/rootCA.crt
# List of shared object plugins to load on startup
- MODULE_1=./modules/module_set/module_set.so
- MODULE_2=./modules/module_get/module_get.so
ports:
- "7483:7480"
- "7948:7946"
volumes:
- ./internal/volumes/config:/etc/sugardb/config
- ./internal/volumes/nodes/cluster_node_3:/var/lib/sugardb
- ./internal/volumes/modules/lua:/var/lib/sugardb/scripts/lua
- ./internal/volumes/modules/js:/var/lib/sugardb/scripts/js
networks:
- testnet
cluster_node_4:
container_name: cluster_node_4
build:
context: .
dockerfile: Dockerfile.dev
environment:
- BIND_ADDR=0.0.0.0
- PORT=7480
- DISCOVERY_PORT=7946
- SERVER_ID=4
- JOIN_ADDR=5/cluster_node_5:7946
- DATA_DIR=/var/lib/sugardb
- TLS=false
- MTLS=false
- BOOTSTRAP_CLUSTER=false
- ACL_CONFIG=/etc/sugardb/config/acl.yml
- REQUIRE_PASS=false
- FORWARD_COMMAND=true
- SNAPSHOT_THRESHOLD=1000
- SNAPSHOT_INTERVAL=5m30s
- RESTORE_SNAPSHOT=false
- RESTORE_AOF=false
- AOF_SYNC_STRATEGY=everysec
- MAX_MEMORY=100mb
- EVICTION_POLICY=noeviction
- EVICTION_SAMPLE=20
- EVICTION_INTERVAL=100ms
# List of sugardb cert/key pairs
- CERT_KEY_PAIR_1=/etc/ssl/certs/sugardb/server/server1.crt,/etc/ssl/certs/sugardb/server/server1.key
- CERT_KEY_PAIR_2=/etc/ssl/certs/sugardb/server/server2.crt,/etc/ssl/certs/sugardb/server/server2.key
# List of client certificate authorities
- CLIENT_CA_1=/etc/ssl/certs/sugardb/client/rootCA.crt
# List of shared object plugins to load on startup
- MODULE_1=./modules/module_set/module_set.so
- MODULE_2=./modules/module_get/module_get.so
ports:
- "7484:7480"
- "7949:7946"
volumes:
- ./internal/volumes/config:/etc/sugardb/config
- ./internal/volumes/nodes/cluster_node_4:/var/lib/sugardb
- ./internal/volumes/modules/lua:/var/lib/sugardb/scripts/lua
- ./internal/volumes/modules/js:/var/lib/sugardb/scripts/js
networks:
- testnet
cluster_node_5:
container_name: cluster_node_5
build:
context: .
dockerfile: Dockerfile.dev
environment:
- BIND_ADDR=0.0.0.0
- PORT=7480
- DISCOVERY_PORT=7946
- SERVER_ID=5
- JOIN_ADDR=1/cluster_node_1:7946
- DATA_DIR=/var/lib/sugardb
- TLS=false
- MTLS=false
- BOOTSTRAP_CLUSTER=false
- ACL_CONFIG=/etc/sugardb/config/acl.yml
- REQUIRE_PASS=false
- FORWARD_COMMAND=true
- SNAPSHOT_THRESHOLD=1000
- SNAPSHOT_INTERVAL=5m30s
- RESTORE_SNAPSHOT=false
- RESTORE_AOF=false
- AOF_SYNC_STRATEGY=everysec
- MAX_MEMORY=100mb
- EVICTION_POLICY=noeviction
- EVICTION_SAMPLE=20
- EVICTION_INTERVAL=100ms
# List of sugardb cert/key pairs
- CERT_KEY_PAIR_1=/etc/ssl/certs/sugardb/server/server1.crt,/etc/ssl/certs/sugardb/server/server1.key
- CERT_KEY_PAIR_2=/etc/ssl/certs/sugardb/server/server2.crt,/etc/ssl/certs/sugardb/server/server2.key
# List of client certificate authorities
- CLIENT_CA_1=/etc/ssl/certs/sugardb/client/rootCA.crt
# List of shared object plugins to load on startup
- MODULE_1=./modules/module_set/module_set.so
- MODULE_2=./modules/module_get/module_get.so
ports:
- "7485:7480"
- "7950:7946"
volumes:
- ./internal/volumes/config:/etc/sugardb/config
- ./internal/volumes/nodes/cluster_node_5:/var/lib/sugardb
- ./internal/volumes/modules/lua:/var/lib/sugardb/scripts/lua
- ./internal/volumes/modules/js:/var/lib/sugardb/scripts/js
networks:
- testnet

22
docs/.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
# Dependencies
/node_modules
# Production
/build
# Generated files
.docusaurus
.cache-loader
.next
package-lock.json
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

1
docs/CNAME Normal file
View File

@ -0,0 +1 @@
.io

3
docs/babel.config.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};

5
docs/blog/authors.yml Normal file
View File

@ -0,0 +1,5 @@
kelvinmwinuka:
name: Kelvin Clement Mwinuka
title: EchoVault Maintainer
url: https://kelvinmwinuka.com
image_url: https://github.com/kelvinmwinuka.png

199
docs/docs/acl.md Normal file
View File

@ -0,0 +1,199 @@
---
sidebar_position: 7
---
# Access Control List
Access Control Lists enable you to add a layer of security to the SugarDB server or cluster. You can create users with associated rules and require clients to authorize before executing commands on the server.
SugarDB creates a default user upon startup. You can see this user by executing the following command:
```
> ACL LIST
1) "default on +@all +all %RW~* +&*"
```
The default user is enabled, and has access to all categories, commands, keys and pub/sub channels. Connections are associated with user by default.
You can configure the default user to require a passwords by using the following configuration options:
- `--require-pass` forces the SugarDB server to require a user to authenticate itself using a password and/or username.
- `--password` attaches the provided password to the default user.
## Authorization
The TCP client can authenticate itself using the `AUTH` command:
`AUTH <username> <password>` tries to authenticate the TCP connection with the provided username and password.
`AUTH <password>` tries to authenticate the TCP connection with the default user and the provided passsword.
Authorization is not supported in embedded mode. When an SugarDB instance is embedded, it autimatically has access to all the commands exposed by the API.
## Configuration files
You can configure ACL Rules by passing the path to the config file to the `--acl-config=<path/to/config/file>` flag. The configuration file can be either a YAML or JSON file.
### YAML Config example
```yaml
- Username: "user1"
Enabled: true
NoPassword: false
NoKeys: false
Passwords:
- PasswordType: "plaintext"
PasswordValue: "password1"
- PasswordType: "SHA256"
PasswordValue: "6cf615d5bcaac778352a8f1f3360d23f02f34ec182e259897fd6ce485d7870d4"
IncludedCategories: ["*"]
ExcludedCategories: []
IncludedReadKeys: ["*"]
IncludedWriteKeys: ["*"]
IncludedPubSubChannels: ["*"]
ExcludedPubSubChannels: []
- Username: "user2"
Enabled: true
NoPassword: false
NoKeys: false
Passwords:
- PasswordType: "plaintext"
PasswordValue: "password4"
- PasswordType: "SHA256"
PasswordValue: "8b2c86ea9cf2ea4eb517fd1e06b74f399e7fec0fef92e3b482a6cf2e2b092023"
IncludedCategories: ["hash", "set", "sortedset", "list", "generic"]
ExcludedCategories: []
IncludedReadKeys: ["*"]
IncludedWriteKeys: ["*"]
IncludedPubSubChannels: ["user:channel:*"]
ExcludedPubSubChannels: ["admin:channel:*"]
```
### JSON Config example
```json
[
{
"Username": "user1",
"Enabled": true,
"NoPassword": false,
"NoKeys": false,
"Passwords": [
{
"PasswordType": "plaintext",
"PasswordValue": "password1"
},
{
"PasswordType": "SHA256",
"PasswordValue": "6cf615d5bcaac778352a8f1f3360d23f02f34ec182e259897fd6ce485d7870d4"
}
],
"IncludedCategories": ["*"],
"ExcludedCategories": [],
"IncludedReadKeys": ["*"],
"IncludedWriteKeys": ["*"],
"IncludedPubSubChannels": ["*"],
"ExcludedPubSubChannels": []
},
{
"Username": "user2",
"Enabled": true,
"NoPassword": false,
"NoKeys": false,
"Passwords": [
{
"PasswordType": "plaintext",
"PasswordValue": "password4"
},
{
"PasswordType": "SHA256",
"PasswordValue": "8b2c86ea9cf2ea4eb517fd1e06b74f399e7fec0fef92e3b482a6cf2e2b092023"
}
],
"IncludedCategories": ["hash", "set", "sortedset", "list", "generic"],
"ExcludedCategories": [],
"IncludedReadKeys": ["*"],
"IncludedWriteKeys": ["*"],
"IncludedPubSubChannels": ["user:channel:*"],
"ExcludedPubSubChannels": ["admin:channel:*"]
}
]
```
## ACL rules
ACL rules allow you to add new user profiles and set fine-grained rules that determine what clients can do on the server.
The default user's rules are very permissive so if you want to restrict access, you will have to explicitly configure ACL rules. The default user can be configured too.
### Enable and disable users
- `on` - Enable this user. A TCP connection can authenticate as this user.
- `off` - Disable this user. It's impossible to authenticate as thsi user.
### Allow and disallow categories
- `+@all` - Allow this user to access all categories (aliased by `allCategories` and `+@*`). This overrides all other category access rules.
- `-@all` - Block this user from accessing any categories (aliased by `-@*`, and `nocommands`). This overrides all other category access rules.
- `+@<category>` - Allow this user to access the specified category. If updating an existing user, then this category will be added to the list of categories they are allowed to access.
- `-@<category>` - Block the user from accessing this specific category. If updating an existing user, then this category is removed from the list of categories the user is allowed to access.
If both `+@all` and `-@all` are specified, whichever one is specified last will take effect.
The `nocommands` flag will apply the `-@all` rule.
### Allow and disallow commands
- `+all` - Allow this user to execute all commands (aliased by `allCommands`). This overrides all other command access rules.
- `-all` - Block this user from executing any commands. This overrides all other command access rules.
- `+<command>` - Allow the user to access the specified command. In order to allow the user to access only a specific subcommand, you can use `+<command>|<subcommand>`.
- `-<command>` - Block this user from executing any commands. In order to allow the user to access only a specific subscommand, you can user `-<command>|<subcommand>`.
If both `+all` and `-all` are specified, whichever one is specified last will take effect.
The `nocommands` flag will apply the `-all` rule.
### Allow and disallow access to keys
By default, SugarDB allows each user to read and write to all keys. If you'd like to control what keys users have access to and what they can do with those keys, you can make use of the following options:
- `%RW~*` - Allow this user to read and write all keys on the SugarDB instance (aliased by `allKeys`).
- `%RW~<key>` - Allow this user to read and write to the specified key. This option accepts a glob pattern for the key which allows you to restrict certain key patterns.
- `%W~*` - Allow the user to write to all keys.
- `%W~<key>` - Block the user from writing to any keys except the one specified. A glob pattern can be used in place of the key.
- `%R~*` - Allow the user to read from all the keys.
- `%R~<key>` - Block the user from reading any keys except the one specified. A glob pattern can be used in place of the key.
### Allow and disallow Pub/Sub channels
- `+&*` - Allow this user to access all pub/sub channels (aliased by `allChannels`).
- `-&*` - Block this user from accessing any of the pub/sub channels.
- `+&<channel>` - Allow this user to access the specied channel. This rule accepts a glob pattern (e.g. "channel\*").
- `-&<channel>` - Block this user from accessing the specied channel. This rule accepts a glob pattern (e.g. "channel\*").
If both `+&*` and `-&*` are specified, the one specified last will take effect.
### Add and remove passwords
By default users have no password and require no password to authenticate against them except when the `--require-pass` configuration is `true`. You can add and remove passwords associated with a user using the following options:
- `><password>` - Adds the plaintext password to the list of passwords associated with the user.
- `<<password>` - Removes the plaintext password from the list of passwords associated with the user.
- `#<hash>` - Adds the hash to the list of passwords associated with the user. The hash must be a SHA256 hash. When the user is being authenticated, they provide a plaintext passwords and the passwords will be compared with the user's plaintext passwords. If no match is found, the password's SHA256 hash is compared with the list of password hashes associated with the user.
- `!<hash>` - Removes the SHA256 hash from the list of passwords hashes associated with the user.
### Reset the user
You can pass certain flags to make sweeping updates to a user's ACL rules. These flags often reset the granular rules specified above.
- `nopass` - Deletes all the user's associated passwords. Future TCP connections will not need to provide a password to authenticate against this user.
- `resetpass` - Deletes all the user's associated passwords, but does not set the `nopass` flag to true.
- `nocommands` - Blocks the user from executing any commands.
- `resetkeys` - Blocks the user from accesssing any keys for both reads and writes (aliased by `nokeys`).
- `resetchannels` - Allows the user to access all pub/sub channels.
## Examples
For examples on how to create and update ACL users and their rules, checkout out the `ACL SETUSER` command documentation.

View File

@ -0,0 +1,11 @@
---
sidebar_position: 6
---
# Architecture
SugarDB can be run in the following modes:
- Standalone mode - Where only one instance runs in isolation.
- Replication cluster - Strongly consistent RAFT cluster.
- Sharding - To be implemented.

View File

@ -0,0 +1,59 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# ACL CAT
### Syntax
```
ACL CAT [category]
```
### Module
<span className="acl-category">acl</span>
### Categories
<span className="acl-category">slow</span>
### Description
Lists all the categories. If the optional category is provided, lists all the commands in the category.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
List all categories:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
categories, err := db.ACLCat()
```
List all commands/subcommands in pubsub module:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
commands, err := db.ACLCat("pubsub")
```
</TabItem>
<TabItem value="cli">
List all categories:
```
> ACL CAT
```
List all commands/subcommands in pubsub module:
```
> ACL CAT pubsub
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# ACL DELUSER
### Syntax
```
ACL DELUSER username [username ...]
```
### Module
<span className="acl-category">acl</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">slow</span>
### Description
Deletes users and terminates their connections. This command cannot delete the default user.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Delete users:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.ACLDelUser("username1", "username2")
```
</TabItem>
<TabItem value="cli">
Delete users:
```
> ACL DELUSER username1 username2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,77 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# ACL GETUSER
### Syntax
```
ACL GETUSER username
```
### Module
<span className="acl-category">acl</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">slow</span>
### Description
List the ACL rules of a user.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Retrieve user:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
rules, err := db.ACLGetUser("username")
```
Returns a map[string][]string map where each key is the rule category and each value is a string slice of relevant values.
The map returned has the following structure:
- "username" - string slice containing the user's username.
- "flags" - string slices containing the following values: "on" if the user is enabled, otherwise "off",
- "nokeys" if the user is not allowed to access any keys (and NoKeys is true),
- "nopass" if the user has no passwords (and NoPass is true).
- "categories" - string slice af ACL command categories associated with the user.
If the user is allowed to access all categories, it will contain "+@*".
For each category the user is allowed to access, the slice will contain "+@\<category\>".
If the user is not allowed to access any categories, it will contain "-@*".
For each category the user is not allowed to access, the slice will contain "-@\<category\>".
- "commands" - string slice af commands associated with the user.
If the user is allowed to execute all commands, it will contain "+all".
For each command the user is allowed to execute, the slice will contain "+\<command\>".
If the user is not allowed to execute any commands, it will contain "-all".
For each command the user is not allowed to execute, the slice will contain "-\<category\>".
- "keys" - string slice af keys associated with the user.
If the user is allowed read/write access all keys, the slice will contain "%RW~*".
For each key glob pattern the user has read/write access to, the slice will contain "%RW~\<pattern\>".
If the user is allowed read access to all keys, the slice will contain "%R~*".
For each key glob pattern the user has read access to, the slice will contain "%R~\<pattern\>".
If the user is allowed write access to all keys, the slice will contain "%W~*".
For each key glob pattern the user has write access to, the slice will contain "%W~\<pattern\>".
- "channels" - string slice af pubsub channels associated with the user.
If the user is allowed to access all channels, the slice will contain "+&*".
For each channel the user is allowed to access, the slice will contain "+&\<channel\>".
If the user is not allowed to access any channels, the slice will contain "-&*".
For each channel the user is not allowed to access, the slice will contain "-&\<channel\>".
</TabItem>
<TabItem value="cli">
Retrieve user:
```
> ACL GETUSER username
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# ACL LIST
### Syntax
```
ACL LIST
```
### Module
<span className="acl-category">acl</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">slow</span>
### Description
Dumps effective acl rules in ACL DSL format.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
List ACL rules:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
rules, err := db.ACLList()
```
</TabItem>
<TabItem value="cli">
List ACL rules:
```
> ACL LIST
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,58 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# ACL LOAD
### Syntax
```
ACL LOAD <MERGE | REPLACE>
```
### Module
<span className="acl-category">acl</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">slow</span>
### Description
Reloads the rules from the configured ACL config file.
When 'MERGE' is passed, users from config file who share a username with users in memory will be merged.
When 'REPLACE' is passed, users from config file who share a username with users in memory will replace the user in memory.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Load ACL config:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
// Load config and merge with currently loaded ACL config
ok, err := db.ACLLoad(sugardb.ACLLoadOptions{Merge: true})
// Load config and replace currently loaded ACL config
ok, err := db.ACLLoad(sugardb.ACLLoadOptions{Replace: true})`
```
</TabItem>
<TabItem value="cli">
Load ACL config file and merge it with currently loaded config:
```
> ACL LOAD MERGE
```
Load ACL config file and replace the currently loaded config:
```
> ACL LOAD REPLACE
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,49 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# ACL SAVE
### Syntax
```
ACL SAVE
```
### Module
<span className="acl-category">acl</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">slow</span>
### Description
Saves the effective ACL rules the configured ACL config file.
The save command overwrites the current ACL config file entirely and using the current
in-memory ACL configuration.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Save ACL rules:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := server.ACLSave()
```
</TabItem>
<TabItem value="cli">
Save ACL rules:
```
> ACL SAVE
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,123 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# ACL SETUSER
### Syntax
```
ACL SAVE
```
### Module
<span className="acl-category">acl</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">slow</span>
### Description
Configure a new or existing user.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Save user:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
user := sugardb.User{}
ok, err := server.ACLSetUser(user)
```
The User struct takes the following shape:
```go
type User struct {
// Username - string - the user's username.
Username string
// Enabled - bool - whether the user should be enabled (i.e connections can authenticate with this user).
Enabled bool
// NoPassword - bool - if true, this user can be authenticated against without a password.
NoPassword bool
// NoKeys - bool - if true, this user will not be allowed to access any keys.
NoKeys bool
// NoCommands - bool - if true, this user will not be allowed to execute any commands.
NoCommands bool
// ResetPass - bool - if true, all the user's configured passwords are removed and NoPassword is set to false.
ResetPass bool
// ResetKeys - bool - if true, the user's NoKeys flag is set to true and all their currently accessible keys are cleared.
ResetKeys bool
// ResetChannels - bool - if true, the user will be allowed to access all PubSub channels.
ResetChannels bool
// AddPlainPasswords - []string - the list of plaintext passwords to add to the user's passwords.
AddPlainPasswords []string
// RemovePlainPasswords - []string - the list of plaintext passwords to remove from the user's passwords.
RemovePlainPasswords []string
// AddHashPasswords - []string - the list of SHA256 password hashes to add to the user's passwords.
AddHashPasswords []string
// RemoveHashPasswords - []string - the list of SHA256 password hashes to add to the user's passwords.
RemoveHashPasswords []string
// IncludeCategories - []string - the list of ACL command categories to allow this user to access, default is all.
IncludeCategories []string
// ExcludeCategories - []string - the list of ACL command categories to bar the user from accessing. The default is none.
ExcludeCategories []string
// IncludeCommands - []string - the list of commands to allow the user to execute. The default is none. If you want to
// specify a subcommand, use the format "command|subcommand".
IncludeCommands []string
// ExcludeCommands - []string - the list of commands to bar the user from executing.
// The default is none. If you want to specify a subcommand, use the format "command|subcommand".
ExcludeCommands []string
// IncludeReadWriteKeys - []string - the list of keys the user is allowed read and write access to. The default is all.
// This field accepts glob pattern strings.
IncludeReadWriteKeys []string
// IncludeReadKeys - []string - the list of keys the user is allowed read access to. The default is all.
// This field accepts glob pattern strings.
IncludeReadKeys []string
// IncludeWriteKeys - []string - the list of keys the user is allowed write access to. The default is all.
// This field accepts glob pattern strings.
IncludeWriteKeys []string
// IncludeChannels - []string - the list of PubSub channels the user is allowed to access ("Subscribe" and "Publish").
// This field accepts glob pattern strings.
IncludeChannels []string
// ExcludeChannels - []string - the list of PubSub channels the user cannot access ("Subscribe" and "Publish").
// This field accepts glob pattern strings.
ExcludeChannels []string
}
```
</TabItem>
<TabItem value="cli">
Checkout the <a href="/docs/acl">Access Control List documentation</a> for the list of rules.
```
> ACL SETUSER username
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# ACL USERS
### Syntax
```
ACL USERS
```
### Module
<span className="acl-category">acl</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">slow</span>
### Description
Lists all usernames of the configured ACL users.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
List ACL usernames:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
users, err := db.ACLUsers()
```
</TabItem>
<TabItem value="cli">
List ACL usersnames:
```
> ACL USERS
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,38 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# ACL WHOAMI
### Syntax
```
ACL WHOAMI
```
### Module
<span className="acl-category">acl</span>
### Categories
<span className="acl-category">fast</span>
### Description
Returns the authenticated user of the current connection.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Not available in embedded mode.
</TabItem>
<TabItem value="cli">
Get the username of the user associated with the current connection:
```
> ACL WHOAMI
```
</TabItem>
</Tabs>

View File

@ -0,0 +1 @@
# ACL

View File

@ -0,0 +1,46 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# COMMAND COUNT
### Syntax
```
COMMAND COUNT
```
### Module
<span className="acl-category">admin</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">slow</span>
### Description
Get the number of commands in the SugarDB instance.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get server command count:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
count, err := db.CommandCount()
```
</TabItem>
<TabItem value="cli">
Get server command count:
```
> COMMAND COUNT
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,94 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# COMMAND LIST
### Syntax
```
COMMAND LIST [FILTERBY <ACLCAT category | PATTERN pattern | MODULE module>]
```
### Module
<span className="acl-category">admin</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">slow</span>
### Description
Get the list of command names. Allows for filtering by ACL category or glob pattern.
### Options
FILTERBY - An optional condition used to filter the response. ACLCAT filters by the provided acl
category string. PATTERN filters the response by the provided glob pattern.
MODULE filters the response by the provided SugarDB module.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get a list of all the loaded commands:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
commands, err := db.CommandList(sugardb.CommandListOptions{})
```
Get a list of all commands with the \"fast\" ACL category:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
commands, err := db.CommandList(sugardb.CommandListOptions{ACLCAT: "fast"})
```
Get a list of all commands which satisfy the \"z*\" glob pattern:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
commands, err := db.CommandList(sugardb.CommandListOptions{PATTERN: "z*"})
```
Get a list of all the commands in the \"set\" module:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
commands, err := db.CommandList(sugardb.CommandListOptions{MODULE: "set"})
```
</TabItem>
<TabItem value="cli">
Get a list of all the loaded commands:
```
> COMMAND LIST
```
Get a list of all commands with the "fast" ACL category:
```
> COMMAND LIST FILTERBY ACLCAT fast
```
Get a list of all commands which satisfy the "z*" glob pattern:
```
> COMMAND LIST FILTERBY PATTERN z*
```
Get a list of all the commands in the "set" module:
```
> COMMAND LIST FILTERBY MODULE set
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,40 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# COMMANDS
### Syntax
```
COMMANDS
```
### Module
<span className="acl-category">admin</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">slow</span>
### Description
Get a list of all the commands in available on the SugarDB instance with categories and descriptions.
Sub-commands are formatted as "command|subcommand".
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Make use of the <a href="/docs/commands/admin/command_list">CommandList method</a>.
</TabItem>
<TabItem value="cli">
Get List of commands:
```
> COMMAND
```
</TabItem>
</Tabs>

View File

@ -0,0 +1 @@
# Admin

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# LASTSAVE
### Syntax
```
LASTSAVE
```
### Module
<span className="acl-category">admin</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">fast</span>
### Description
Get unix timestamp for the latest snapshot in milliseconds.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get last snapshot timestamp:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
count, err := db.LastSave()
```
</TabItem>
<TabItem value="cli">
Get last snapshot timestamp:
```
> LASTSAVE
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# MODULE LIST
### Syntax
```
MODULE LIST
```
### Module
<span className="acl-category">admin</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">fast</span>
### Description
List all the modules that are currently loaded in the server/instance.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
List all the modules that are currently loaded in the instance:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
modules := db.ListModules()
```
</TabItem>
<TabItem value="cli">
List all the modules that are currently loaded in the server:
```
> MODULE LIST
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,63 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# MODULE LOAD
### Syntax
```
MODULE LOAD path [arg [arg ...]]
```
### Module
<span className="acl-category">admin</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">fast</span>
### Description
Load a module from a dynamic library at runtime.
The path should be the full path to the module, including the .so filename. Any args will be passed unmodified to the
module's key extraction and handler functions.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Load a modules with no args:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
err := server.LoadModule("/path/to/module.so")
```
Load a module with a few args:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
err := server.LoadModule("/path/to/module.so", "arg1", "arg2", "arg3")
```
</TabItem>
<TabItem value="cli">
Load a module with no args:
```
> MODULE LOAD path/to/module.so
```
Load a module with a few args:
```
> MODULE LOAD path/to/module.so arg1 arg2 arg3
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# MODULE UNLOAD
### Syntax
```
MODULE UNLOAD name
```
### Module
<span className="acl-category">admin</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">fast</span>
### Description
Unloads a module based on the its name as displayed by the MODULE LIST command.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Unload a module:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
err := server.UnloadModule("module-name")
```
</TabItem>
<TabItem value="cli">
Unload a module:
```
> MODULE UNLOAD module-name
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# REWRITEAOF
### Syntax
```
REWRITEAOF
```
### Module
<span className="acl-category">admin</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">fast</span>
### Description
Trigger re-writing of append process.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Trigger re-writing of append process:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
count, err := db.RewriteAOF()
```
</TabItem>
<TabItem value="cli">
Trigger re-writing of append process:
```
> REWRITEAOF
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# SAVE
### Syntax
```
SAVE
```
### Module
<span className="acl-category">admin</span>
### Categories
<span className="acl-category">admin</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">fast</span>
### Description
Trigger a snapshot save.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Trigger a snapshot save:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
count, err := db.Save()
```
</TabItem>
<TabItem value="cli">
Trigger a snapshot save:
```
> SAVE
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,46 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# AUTH
### Syntax
```
AUTH [username] password
```
### Module
<span className="acl-category">connection</span>
### Categories
<span className="acl-category">connection</span>
<span className="acl-category">slow</span>
### Description
Authenticates the connection. If the username is not provided, the connection will be authenticated against the
default ACL user. Otherwise, it is authenticated against the ACL user with the provided username.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
```go
// Not available in embedded mode.
```
</TabItem>
<TabItem value="cli">
Authenticate against the default user:
```
> AUTH password
```
Authenticate against a specific user:
```
> AUTH username password
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,42 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# ECHO
### Syntax
```
ECHO [message]
```
### Module
<span className="acl-category">connection</span>
### Categories
<span className="acl-category">connection</span>
<span className="acl-category">fast</span>
### Description
Sends a message to the SugarDB server and it returns the same message back.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
```go
// Not available in embedded mode.
```
</TabItem>
<TabItem value="cli">
Echo with message:
```
> ECHO "Hello, World!"
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,86 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HELLO
### Syntax
```
HELLO [protover [AUTH username password] [SETNAME clientname]]
```
### Module
<span className="acl-category">connection</span>
### Categories
<span className="acl-category">connection</span>
<span className="acl-category">fast</span>
### Description
Switch to a different protocol, optionally authenticating and setting the connection's name.
This command returns a contextual client report.
### Options
- `protover` - The protocol version to switch to. The default is 2.
- `AUTH username password` - Authenticate with the server using the specified username and password.
- `SETNAME clientname` - Set the connection's name to the specified clientname.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
When using the embedded API, there's no need to authenticate the API caller or set an alias for the caller.
Therefore, only the set protocol functionality is available in embedded mode. You can set the protocol using
the SetProtocol method:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
err := db.SetProtocol(2)
```
The method above changes the protocol to version 3. This is relevant when executing commands using the
`ExecuteCommand` method. Since this methods returns a raw RESP response. It will not affect any other methods'
return types as they return native go types.
`SetProtocol` return an error if the protocol version is not supported (i.e. not 2 or 3).
</TabItem>
<TabItem value="cli">
Only fetch client report:
```
> HELLO
```
Authenticate and set the connection's name:
```
> HELLO 2 AUTH myuser mypass SETNAME myclient
```
Authenticate only:
```
> HELLO 2 AUTH myuser mypass
```
Set the connection's name only:
```
> HELLO 2 SETNAME myclient
```
Switch to protocol version 3:
```
> HELLO 3
```
Authenticate and switch to protocol version 3:
```
> HELLO 3 AUTH myuser mypass
```
</TabItem>
</Tabs>

View File

@ -0,0 +1 @@
# Connection

View File

@ -0,0 +1,46 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# PING
### Syntax
```
PING [message]
```
### Module
<span className="acl-category">connection</span>
### Categories
<span className="acl-category">connection</span>
<span className="acl-category">fast</span>
### Description
Ping the SugarDB server. If a message is provided, the message will be echoed back to the client.
Otherwise, the server will return "PONG".
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
```go
// Not available in embedded mode.
```
</TabItem>
<TabItem value="cli">
Ping without message (returns PONG):
```
> PING
```
Ping with message (returns "Hello, world!"):
```
> PING "Hello, world!"
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,50 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# SELECT
### Syntax
```
SELECT index
```
### Module
<span className="acl-category">connection</span>
### Categories
<span className="acl-category">connection</span>
<span className="acl-category">fast</span>
### Description
Change the logical database that the current connection is operating from.
If the database does not exist, it will be created.
When this command is executed in a RAFT cluster, the database will be created in all the nodes of the cluster.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Select the database that the embedded instance is operating from:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
err := db.SelectDB(2)
```
After successfully calling this method, all subsequent commands executed on that instance
will be executed on the selected database. So you should to be careful when doing this in a multi-threaded environment.
</TabItem>
<TabItem value="cli">
Select the database with index 1:
```
> SELECT 1
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,52 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# SWAPDB
### Syntax
```
SWAPDB index1 index2
```
### Module
<span className="acl-category">connection</span>
### Categories
<span className="acl-category">connection</span>
<span className="acl-category">dangerous</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">slow</span>
### Description
This command swaps two databases,
so that immediately all the clients connected to a given database will see the data of the other database,
and the other way around. If either one of the databases does not exist, it will be created.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Swap the databases with indexes 1 and 2:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
err := db.SwapDBs(1, 2)
```
The method above only switches the databases for the currently active TCP connections.
To switch the database for the embedded instance, use the `SelectDB` method.
</TabItem>
<TabItem value="cli">
Swap the databases with indexes 1 and 2:
```
> SWAPDB 1 2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,85 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# COPY
### Syntax
```
COPY source destination [DB destination-db] [REPLACE]
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">slow</span>
<span className="acl-category">write</span>
<span className="acl-category">keyspace</span>
### Description
Copies the value stored at the source key to the destination key.
Returns 1 if copied and 0 if not copied.
Also returns 0 if the destination key already exists in the database and the REPLACE option is not set.
### Options
- `DB destination-db`: the destination database to copy the key to
- `REPLACE`: replace the destination key if it already exists
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
The API provides a struct called COPYOptions that wraps these options in a convenient object.
```go
type COPYOptions struct {
Database string
Replace bool
}
```
Copy the value stored at key 'hello' to the new key 'bye'
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
db.Set("hello", "world")
key = db.Copy("hello", "bye")
```
Copy the value stored at key 'hello' in database 0 and replace the value at key 'bye' in database 1
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
err := db.SelectDB(1)
ok, err := db.Set("bye", "goodbye")
err := db.SelectDB(0)
ok, err := db.Set("hello", "world")
ret, err = db.Copy("hello", "bye", db.COPYOptions{Database: "1", Replace: true})
```
</TabItem>
<TabItem value="cli">
Copy the value stored at key 'hello' to the key 'bye'
```
> SET "hello" "world"
> COPY "hello" "bye"
```
Copy the value stored at key 'hello' in database 0 and replace the value at key 'bye' in database 1
```
> SELECT 1
> SET "bye" "goodbye"
> SELECT 0
> SET "hello" "world"
> COPY "hello" "bye" DB 1 REPLACE
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# DBSIZE
### Syntax
```
DBSIZE
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">read</span>
<span className="acl-category">keyspace</span>
### Description
Return the number of keys in the currently-selected database.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get the number of keys in the database:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
key, err := db.DBSize()
```
</TabItem>
<TabItem value="cli">
Get the number of keys in the database:
```
> DBSIZE
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,50 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# DECR
### Syntax
```
DECR key
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">write</span>
### Description
Decrements the number stored at key by one.
If the key does not exist, it is set to 0 before performing the operation.
An error is returned if the key contains a value of the wrong type or contains a string that cannot be represented as integer.
This operation is limited to 64 bit signed integers.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Decrement the value of the key `mykey`:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
value, err := db.Decr("mykey")
```
</TabItem>
<TabItem value="cli">
Decrement the value of the key `mykey`:
```
> DECR mykey
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# DECRBY
### Syntax
```
DECRBY key decrement
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">write</span>
### Description
The DECRBY command reduces the value stored at the specified key by the specified decrement.
If the key does not exist, it is initialized with a value of 0 before performing the operation.
If the key's value is not of the correct type or cannot be represented as an integer, an error is returned.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Decrement the value of the key `mykey` by 5:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
value, err := db.DecrBy("mykey 5")
```
</TabItem>
<TabItem value="cli">
Decrement the value of the key `mykey` by 5:
```
> DECRBY mykey 5
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,61 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# DEL
### Syntax
```
DEL key [key ...]
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">write</span>
### Description
Removes one or more keys from the store.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Delete a single key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
noOfDeletedKeys, err = db.Del("key1")
```
Delete multiple keys:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
noOfDeletedKeys, err = db.Del("key1", "key2", "key3")
```
</TabItem>
<TabItem value="cli">
Delete a single key:
```
> DEL key
```
Delete multiple keys:
```
> DEL key1 key2 key3
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# EXISTS
### Syntax
```
EXISTS
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">read</span>
<span className="acl-category">keyspace</span>
### Description
Returns the number of keys that exists from the provided list of keys. Note: If duplicate keys are provided, each one is counted separately.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Return the number of keys that exists:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
key, err := db.Exists("key1")
```
</TabItem>
<TabItem value="cli">
Return the number of keys that exists:
```
> EXISTS key1 key2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,106 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# EXPIRE
### Syntax
```
EXPIRE key seconds [NX | XX | GT | LT]
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">write</span>
### Description
Expire the key in the specified number of seconds. This commands turns a key into a volatile one.
### Options
- `NX` - Only set the expiry time if the key has no associated expiry.
- `XX` - Only set the expiry time if the key already has an expiry time.
- `GT` - Only set the expiry time if the new expiry time is greater than the current one.
- `LT` - Only set the expiry time if the new expiry time is less than the current one.
<br></br>
NX, GT, and LT are mutually exclusive. XX can additionally be passed in with either GT or LT.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
The embedded API utilizes the ExpireOptions interface, which acts as a wrapper for the various expiry options.
<br></br>
ExpireOptions include the following constants:
- `NX` - Only set the expiry time if the key has no associated expiry.
- `XX` - Only set the expiry time if the key already has an expiry time.
- `GT` - Only set the expiry time if the new expiry time is greater than the current one.
- `LT` - Only set the expiry time if the new expiry time is less than the current one.
<br></br>
Add an expiration to a key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 10, nil)
```
Add an expiration to a key only if it does not have one already:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 10, sugardb.NX)
```
Add an expiration to a key only if it has one already:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 10, sugardb.XX)
```
Add an expiration to a key only if it already has one that is less than the current expiry:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 10, sugardb.XX, sugardb.LT)
```
</TabItem>
<TabItem value="cli">
Add an expiration to a key:
```
> EXPIRE key 10
```
Add an expiration to a key only if it does not have one already:
```
> EXPIRE key 10 NX
```
Add an expiration to a key only if it has one already:
```
> EXPIRE key 10 XX
```
Add an expiration to a key only if it already has one that is less than the current expiry:
```
> EXPIRE key 10 XX LT
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,106 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# EXPIREAT
### Syntax
```
EXPIREAT key unix-time-seconds [NX | XX | GT | LT]
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">write</span>
### Description
Expire the key at the provided unix-time. This commands turns a key into a volatile one.
### Options
- `NX` - Only set the expiry time if the key has no associated expiry.
- `XX` - Only set the expiry time if the key already has an expiry time.
- `GT` - Only set the expiry time if the new expiry time is greater than the current one.
- `LT` - Only set the expiry time if the new expiry time is less than the current one.
<br></br>
NX, GT, and LT are mutually exclusive. XX can additionally be passed in with either GT or LT.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
The embedded API utilizes the ExpireOptions interface, which acts as a wrapper for the various expiry options.
<br></br>
ExpireOptions include the following constants:
- `NX` - Only set the expiry time if the key has no associated expiry.
- `XX` - Only set the expiry time if the key already has an expiry time.
- `GT` - Only set the expiry time if the new expiry time is greater than the current one.
- `LT` - Only set the expiry time if the new expiry time is less than the current one.
<br></br>
Add an expiration to a key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 1767160800, nil)
```
Add an expiration to a key only if it does not have one already:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 1767160800, sugardb.NX)
```
Add an expiration to a key only if it has one already:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 1767160800, sugardb.XX)
```
Add an expiration to a key only if it already has one that is less than the current expiry:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 1767160800, sugardb.XX, sugardb.LT)
```
</TabItem>
<TabItem value="cli">
Add an expiration to a key:
```
> EXPIRE key 1767160800
```
Add an expiration to a key only if it does not have one already:
```
> EXPIRE key 1767160800 NX
```
Add an expiration to a key only if it has one already:
```
> EXPIRE key 1767160800 XX
```
Add an expiration to a key only if it already has one that is less than the current expiry:
```
> EXPIRE key 1767160800 XX LT
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# EXPIRETIME
### Syntax
```
EXPIRETIME key
```
### Module
<span className="acl-category">generic</span>
### categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">read</span>
### Description
Returns the absolute unix time in seconds when the key will expire.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get the expiration time of a key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
expireTime, err := db.ExpireTime("key")
```
</TabItem>
<TabItem value="cli">
Get the expiration time of a key:
```
> EXPIRETIME key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# FLUSHALL
### Syntax
```
FLUSHALL
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">dangerous</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">slow</span>
<span className="acl-category">write</span>
### Description
Delete all the keys in all the existing databases. This command is always synchronous.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
In order to delete all the keys in all the databases, you need to pass -1 to the `Flush` method:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
db.Flush(-1)
```
</TabItem>
<TabItem value="cli">
Flush all the databases:
```
> FLUSHALL
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# FLUSHDB
### Syntax
```
FLUSHDB
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">dangerous</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">slow</span>
<span className="acl-category">write</span>
### Description
Delete all the keys in the currently selected database. This command is always synchronous.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
For the embedded instance, you need to pass the database index to the `Flush` method:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
db.Flush(0)
```
</TabItem>
<TabItem value="cli">
Flush the database that the current connection is operating from:
```
FLUSHDB
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# GET
### Syntax
```
GET key
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">read</span>
### Description
Get the value at the specified key.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get the value at the specified key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
value, err := db.Get("key")
```
</TabItem>
<TabItem value="cli">
Get the value at the specified key:
```
> GET key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,46 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# GETDEL
### Syntax
```
GETDEL key
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">write</span>
### Description
Get the value of key and delete the key. This command is similar to [GET], but deletes key on success.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get the value at the specified key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
value, err := db.GetDel("key")
```
</TabItem>
<TabItem value="cli">
Get the value at the specified key:
```
> GETDEL key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,65 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# GETEX
### Syntax
```
GETEX key [EX | PX | EXAT | PXAT | PERSIST]
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">write</span>
### Description
Get the value of key and optionally set its expiration. GETEX is similar to [GET], but is a write command with additional options.
### Options
- `EX` - Set the specified expire time, in seconds.
- `PX` - Set the specified expire time, in milliseconds.
- `EXAT` - Set the specified Unix time at which the key will expire, in seconds.
- `PXAT` - Set the specified Unix time at which the key will expire, in milliseconds.
- `PERSIST` - Remove the time to live associated with the key.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
The embedded API utilizes the GetExOption interface, which acts as a wrapper for the various expiry options of the GETEX command.
<br></br>
GetExOption includes the following constants:
- `EX` - Set the specified expire time, in seconds.
- `PX` - Set the specified expire time, in milliseconds.
- `EXAT` - Set the specified Unix time at which the key will expire, in seconds.
- `PXAT` - Set the specified Unix time at which the key will expire, in milliseconds.
- `PERSIST` - Remove the time to live associated with the key.
<br></br>
Get the value at the specified key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
value, err := db.GetEx("key", nil, 0)
// optionally set expiry
value, err = db.GetEx("key", sugardb.EX, 10)
```
</TabItem>
<TabItem value="cli">
Get the value at the specified key and set the expiry:
```
> GETEX key EX 10
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# INCR
### Syntax
```
INCR key
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">write</span>
### Description
Increments the number stored at key by one. If the key does not exist, it is set to 0 before performing the operation.
An error is returned if the key contains a value of the wrong type or contains a string that cannot be represented as integer.
This operation is limited to 64 bit signed integers.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Increment the value of the key `mykey`:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
value, err := db.Incr("mykey")
```
</TabItem>
<TabItem value="cli">
Increment the value of the key `mykey`:
```
> INCR mykey
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,50 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# INCRBY
### Syntax
```
INCRBY key increment
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">write</span>
### Description
Increments the number stored at key by increment. If the key does not exist, it is set to 0 before performing
the operation. An error is returned if the key contains a value of the wrong type or contains a string
that can not be represented as integer.
### Options
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Increment the value of the key `mykey` by 5:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
value, err := db.IncrBy("mykey", "5")
```
</TabItem>
<TabItem value="cli">
Increment the value of the key `mykey` by 5:
```
> INCRBY mykey 5
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,50 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# INCRBYFLOAT
### Syntax
```
INCRBYFLOAT key increment
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">write</span>
### Description
Increments the floating point number stored at key by increment. If the key does not exist, it is set to 0 before performing
the operation. An error is returned if the key contains a value of the wrong type or contains a string
that can not be represented as a floating point number.
### Options
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Increment the value of the key `mykey` by 10.33:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
value, err := db.IncrByFloat("mykey", "10.33")
```
</TabItem>
<TabItem value="cli">
Increment the value of the key `mykey` by 10.33:
```
> INCRBYFLOAT mykey 10.33
```
</TabItem>
</Tabs>

View File

@ -0,0 +1 @@
# Generic

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# MGET
### Syntax
```
MGET key [key ...]
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">read</span>
### Description
Get multiple values from the specified keys.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get the values at the specified keys:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
values, err := db.MGet("key1", "key2", "key3")
```
</TabItem>
<TabItem value="cli">
Get the values at the specified keys:
```
> MGET key1 key2 key3
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# MOVE
### Syntax
```
MOVE key database
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">write</span>
### Description
Move key from currently selected database to specified destination database. Returns 1 if successful, if
key already exists in the destination database, or key does not exist in the source database, it does nothing and returns 0.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Move the key to database 1:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
value, err := db.Move("key", 1)
```
</TabItem>
<TabItem value="cli">
Move the key to database 1:
```
> MOVE key 1
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,46 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# MSET
### Syntax
```
MSET key value [key value ...]
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">write</span>
<span className="acl-category">slow</span>
### Description
Set or modify multiple key/value pairs at once.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Set multiple key/value pairs:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.MSet(map[string]string{"key1": "value1", "key2": "value2", "key3": "value3"})
```
</TabItem>
<TabItem value="cli">
Set multiple key/value pairs:
```
> MSET key1 value1 key2 value2 key3 value3
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,49 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# OBJECTFREQ
### Syntax
```
OBJECTFREQ keys
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">keyspace</span>
<span className="acl-category">read</span>
<span className="acl-category">slow</span>
### Description
Get the time in seconds since the last access to the value stored at the key.
The command is only available when the maxmemory-policy configuration directive is set to one of the LRU policies.
This command returns an integer representing the access frequency. If the key doesn't exist -1 and an error is returned.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get a key's access frequency:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
freq, err := db.ObjectFreq("key")
```
</TabItem>
<TabItem value="cli">
Get the access frequency of a key:
```
> OBJECTFREQ key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,50 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# OBJECTIDLETIME
### Syntax
```
OBJECTIDLETIME key
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">keyspace</span>
<span className="acl-category">read</span>
<span className="acl-category">slow</span>
### Description
Get the time in seconds since the last access to the value stored at the key.
The command is only available when the maxmemory-policy configuration directive is set to one of the LRU policies.
This commands returns a float representing the seconds since the key was last accessed. If the key doesn't exist -1
and an error is returned.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get a key's idle time:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
idletime, err := db.ObjectIdleTime("key")
```
</TabItem>
<TabItem value="cli">
Get the idle time of a key:
```
> OBJECTIDLETIME key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# PERSIST
### Syntax
```
PERSIST key
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">write</span>
### Description
Removes the TTl associated with a key, turning it from a volatile key to a persistent key.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Remove the TTL associated with a key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Persist("key")
```
</TabItem>
<TabItem value="cli">
Remove the TTL associated with a key:
```
> PERSIST key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,103 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# PEXPIRE
### Syntax
```
PEXPIRE key seconds [NX | XX | GT | LT]
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">write</span>
### Description
Expire the key in the specified number of milliseconds. This commands turns a key into a volatile one.
## Options
- `NX` - Only set the expiry time if the key has no associated expiry.
- `XX` - Only set the expiry time if the key already has an expiry time.
- `GT` - Only set the expiry time if the new expiry time is greater than the current one.
- `LT` - Only set the expiry time if the new expiry time is less than the current one.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
The embedded API utilizes the ExpireOptions interface, which acts as a wrapper for the various expiry options.
<br></br>
ExpireOptions include the following constants:
- `NX` - Only set the expiry time if the key has no associated expiry.
- `XX` - Only set the expiry time if the key already has an expiry time.
- `GT` - Only set the expiry time if the new expiry time is greater than the current one.
- `LT` - Only set the expiry time if the new expiry time is less than the current one.
<br></br>
Add an expiration to a key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
updated, err := db.PExpire("key", 10000, nil)
```
Add an expiration to a key only if it does not have one already:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
updated, err := db.PExpire("key", 10000, db.NX)
```
Add an expiration to a key only if it has one already:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
updated, err := db.PExpire("key", 10000, db.XX)
```
Add an expiration to a key only if it already has one that is less than the current expiry:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
updated, err := db.PExpire("key", 10000, db.XX, db.LT)
```
</TabItem>
<TabItem value="cli">
Add an expiration to a key:
```
> PEXPIRE key 10000
```
Add an expiration to a key only if it does not have one already:
```
> PEXPIRE key 10000 NX
```
Add an expiration to a key only if it has one already:
```
> PEXPIRE key 10000 XX
```
Add an expiration to a key only if it already has one that is less than the current expiry:
```
> PEXPIRE key 10000 XX LT
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,106 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# PEXPIREAT
### Syntax
```
PEXPIREAT key unix-time-milliseconds [NX | XX | GT | LT]
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">write</span>
### Description
Expire the key at the provided unix-time. This commands turns a key into a volatile one.
### Options
- `NX` - Only set the expiry time if the key has no associated expiry.
- `XX` - Only set the expiry time if the key already has an expiry time.
- `GT` - Only set the expiry time if the new expiry time is greater than the current one.
- `LT` - Only set the expiry time if the new expiry time is less than the current one.
<br></br>
NX, GT, and LT are mutually exclusive. XX can additionally be passed in with either GT or LT.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
The embedded API utilizes the ExpireOptions interface, which acts as a wrapper for the various expiry options.
<br></br>
ExpireOptions include the following constants:
- `NX` - Only set the expiry time if the key has no associated expiry.
- `XX` - Only set the expiry time if the key already has an expiry time.
- `GT` - Only set the expiry time if the new expiry time is greater than the current one.
- `LT` - Only set the expiry time if the new expiry time is less than the current one.
<br></br>
Add an expiration to a key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 1767160800000, nil)
```
Add an expiration to a key only if it does not have one already:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 1767160800000, db.NX)
```
Add an expiration to a key only if it has one already:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 1767160800000, db.XX)
```
Add an expiration to a key only if it already has one that is less than the current expiry:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Expire("key", 1767160800000, db.XX, db.LT)
```
</TabItem>
<TabItem value="cli">
Add an expiration to a key:
```
> EXPIRE key 1767160800000
```
Add an expiration to a key only if it does not have one already:
```
> EXPIRE key 1767160800000 NX
```
Add an expiration to a key only if it has one already:
```
> EXPIRE key 1767160800000 XX
```
Add an expiration to a key only if it already has one that is less than the current expiry:
```
> EXPIRE key 1767160800000 XX LT
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,50 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# PEXPIRETIME
### Syntax
```
PEXPIRETIME key
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">read</span>
### Description
Returns the absolute unix time in milliseconds when the key will expire.
Returns -1 if the key exists but has no associated expiry time.
Returns -2 if the key does not exist.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Retrieve the expiration time of a key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
pexpireTime, err := db.PExpireTime("key")
```
</TabItem>
<TabItem value="cli">
Retrieve the expiration time of a key:
```
> PEXPIRETIME key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,49 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# PTTL
### Syntax
```
PTTL key
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">read</span>
### Description
Returns the remaining time to live for a key that has an expiry time in milliseconds.
If the key exists but does not have an associated expiry time, -1 is returned.
If the key does not exist, -2 is returned.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Retrieve the expiration time of a key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ttl, err := db.PTTL("key")
```
</TabItem>
<TabItem value="cli">
Retrieve the expiration time of a key:
```
> PTTL key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# RANDOMKEY
### Syntax
```
RANDOMKEY
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">slow</span>
<span className="acl-category">read</span>
<span className="acl-category">keyspace</span>
### Description
Returns a random key from the currently selected database. If no keys are available, an empty string is returned.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get a random key from the database:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
key, err := db.RandomKey()
```
</TabItem>
<TabItem value="cli">
Get a random key from the database:
```
> RANDOMKEY
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,46 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# RENAME
### Syntax
```
RENAME key newkey
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">write</span>
### Description
Renames key to newkey. If newkey already exists, it is overwritten. If key does not exist, an error is returned.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Rename the key `mykey` to `newkey`:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
err = db.Rename("mykey", "newkey")
```
</TabItem>
<TabItem value="cli">
Rename the key `mykey` to `newkey`:
```
> RENAME mykey newkey
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# RENAMENX
### Syntax
```
RENAMENX key newkey
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">write</span>
### Description
Renames the specified key with the new name only if the new name does not already exist.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Rename the key `mykey` to `newkey`:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
err = db.RenameNX("mykey", "newkey")
```
</TabItem>
<TabItem value="cli">
Rename the key `mykey` to `newkey`:
```
> RENAMENX mykey newkey
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,121 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# SET
### Syntax
```
SET key value [NX | XX] [GET] [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds]
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">slow</span>
<span className="acl-category">write</span>
### Description
Set the value of a key, considering the value's type. If the key already exists, it is overwritten.
### Options
- `NX` - Only set if the key does not exist.
- `XX` - Only set if the key exists.
- `GET` - Return the old value stored at key, or nil if the value does not exist.
- `EX` - Expire the key after the specified number of seconds (positive integer).
- `PX` - Expire the key after the specified number of milliseconds (positive integer).
- `EXAT` - Expire at the exact time in unix seconds (positive integer).
- `PXAT` - Expire at the exat time in unix milliseconds (positive integer).
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
The embedded API organizes the SET command options into constants wrapped in interfaces.
<br></br>
SetWriteOption
- `SETNX` - Only set if the key does not exist.
- `SETXX` - Only set if the key exists.
<br></br>
SetExOption
- `SETEX` - Expire the key after the specified number of seconds.
- `SETPX` - Expire the key after the specified number of milliseconds.
- `SETEXAT` - Expire at the exact time in unix seconds.
- `SETPXAT` - Expire at the exact time in unix milliseconds.
<br></br>
The API provides a struct called SETOptions that wraps these options in a convenient object.
```go
type SETOptions struct {
WriteOpt SetWriteOption
ExpireOpt SetExOption
ExpireTime int
Get bool
}
```
<br></br>
Set a value at a key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Set("name", "SugarDB", db.SETOptions{})
```
Set a value only if the key does not exist:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.Set("name", "SugarDB", db.SETOptions{WriteOpt: db.SETNX})
```
Set a value if key already exists and get the previous value:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
previousValue, err := db.Set("name", "SugarDB", db.SetOptions{WriteOpt: db.SETXX, Get: true})
```
Set a value if the key already exists, return the previous value, and expire after 10 seconds:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
previousValue, err := db.Set("name", "SugarDB", db.SetOptions{WriteOpt: db.SETXX, ExpireOpt: db.SETEX, ExpireTime 10, Get: true})
```
</TabItem>
<TabItem value="cli">
Set a value at a key:
```
> SET name SugarDB
```
Set a value only if the key does not exist:
```
> SET name SugarDB NX
```
Set a value if key already exists and get the previous value:
```
> SET name SugarDB XX GET
```
Set a value if the key already exists, return the previous value, and expire after 10 seconds:
```
> SET name SugarDB XX GET EX 10
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,62 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# TOUCH
### Syntax
```
TOUCH keys [key ...]
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">keyspace</span>
<span className="acl-category">read</span>
<span className="acl-category">fast</span>
### Description
Alters the last access time or access count of the key(s) depending on whether LFU or LRU strategy was used.
A key is ignored if it does not exist. This commands returns the number of keys that were touched.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Touch a key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
touched, err := db.Touch("key1")
```
Touch multiple keys:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
touched, err := db.Touch("key1", "key2", "key3")
```
</TabItem>
<TabItem value="cli">
Touch a key:
```
> TOUCH key1
```
Touch multiple keys:
```
> TOUCH key1 key2 key3
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,49 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# TTL
### Syntax
```
TTL key
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">read</span>
### Description
Returns the remaining time to live for a key that has an expiry time in milliseconds.
If the key exists but does not have an associated expiry time, -1 is returned.
If the key does not exist, -2 is returned.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Retrieve the expiration time of a key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ttl, err := db.TTL("key")
```
</TabItem>
<TabItem value="cli">
Retrieve the expiration time of a key:
```
> TTL key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# TYPE
### Syntax
```
TYPE key
```
### Module
<span className="acl-category">generic</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">keyspace</span>
<span className="acl-category">read</span>
### Description
Returns the string representation of the value type stored at the key.
The types that can be returned are string, integer, float, list, set, set, and hash.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Retrieve the type of the value stored at key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
type, err := db.Type("key")
```
</TabItem>
<TabItem value="cli">
Retrieve the type of the value stored at key:
```
> TYPE key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HDEL
### Syntax
```
HDEL key field [field ...]
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">write</span>
### Description
Deletes the specified fields from the hash.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Delete fields from a hash:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
deletedCount, err := db.HDel("key", "field1", "field2")
```
</TabItem>
<TabItem value="cli">
Delete fields from a hash:
```
> HDEL key field1 field2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HEXISTS
### Syntax
```
HEXISTS key field
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">read</span>
### Description
Returns if field is an existing field in the hash.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Returns if field exists in a hash:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
exists, err := db.HExists ("key", "field1")
```
</TabItem>
<TabItem value="cli">
Returns if field exists in a hash:
```
> HEXISTS key field1
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HEXPIRE
### Syntax
```
HEXPIRE key seconds [NX | XX | GT | LT] FIELDS numfields field [field...]
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">write</span>
### Description
Set an expiration (TTL or time to live) in seconds on one or more fields of a given hash key.
You must specify at least one field. Field(s) will automatically be deleted from the hash key when their TTLs expire.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Set the expiration in seconds for fields in the hash:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
respArray, err := db.HExpire("key", 500, nil, field1, field2)
```
</TabItem>
<TabItem value="cli">
Set the expiration in seconds for fields in the hash:
```
> HEXPIRE key 500 FIELDS 2 field1 field2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HGET
### Syntax
```
HGET key field [field ...]
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">read</span>
### Description
Retrieve the value of each of the listed fields from the hash.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Retrieve values from a hash:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
values, err := db.HGet("key", "field1", "field2", "field3")
```
</TabItem>
<TabItem value="cli">
Retrieve values from a hash:
```
> HGET key field1 field2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HGETALL
### Syntax
```
HGETALL key
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">hash</span>
<span className="acl-category">read</span>
<span className="acl-category">slow</span>
### Description
Get all fields and values of a hash.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get all fields and values of a hash:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
result, err := db.HGetAll("key")
```
</TabItem>
<TabItem value="cli">
Get all fields and values of a hash:
```
> HGETALL key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HINCRBY
### Syntax
```
HINCRBY key field increment
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">write</span>
### Description
Increment the hash value by the integer increment.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Increment the hash value by the integer increment:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
newValue, err := db.HIncrBy("key", "field", 7)
```
</TabItem>
<TabItem value="cli">
Increment the hash value by the integer increment:
```
> HINCRBY key field 7
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HINCRBYFLOAT
### Syntax
```
HINCRBYFLOAT key field increment
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">write</span>
### Description
Increment the hash value by the float increment.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Increment the hash value by the float increment:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
newValue, err := db.HIncrByFloat("key", "field", 7.75)
```
</TabItem>
<TabItem value="cli">
Increment the hash value by the float increment:
```
> HINCRBYFLOAT key field 7.75
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HKEYS
### Syntax
```
HKEYS key
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">hash</span>
<span className="acl-category">read</span>
<span className="acl-category">slow</span>
### Description
Returns all the fields in a hash.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Retrieve all fields from a hash:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
keys, err := db.HKeys("key")
```
</TabItem>
<TabItem value="cli">
Retrieve all fields from a hash:
```
> HKEYS key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HLEN
### Syntax
```
HLEN key
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">read</span>
### Description
Returns the number of fields in the hash.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Retrieve the number of fields in the hash:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
length, err := db.HLen("key")
```
</TabItem>
<TabItem value="cli">
Retrieve the number of fields in the hash:
```
> HLEN key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HMGET
### Syntax
```
HMGET key field [field ...]
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">read</span>
### Description
Retrieves the value of each of the listed fields from the hash.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Retrieve values from a hash:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
values, err := db.HMGet("key", "field1", "field2", "field3")
```
</TabItem>
<TabItem value="cli">
Retrieve values from a hash:
```
> HMGET key field1 field2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,51 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HRANDFIELD
### Syntax
```
HRANDFIELD key [count [WITHVALUES]]
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">hash</span>
<span className="acl-category">read</span>
<span className="acl-category">slow</span>
### Description
Returns one or more random fields from the hash.
## Options
- `WITHVALUES` - When provided, the return value will contain the field and its value.
Otherwise, only the field is returned.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Returns one or more random fields from the hash:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
fields, err := db.HRandField("key", db.HRandFieldOptions{})
```
</TabItem>
<TabItem value="cli">
Returns one or more random fields from the hash:
```
> HRANDFIELD key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HSET
### Syntax
```
HSET key field value [field value ...]
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">write</span>
### Description
Update each field of the hash with the corresponding value.
If the field does not exist, it is created.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Update each field of the hash with the corresponding value:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
noOfUpdatedFields, err := db.HSet("key", map[string]string{"field1": "value1", "field2": "value2"})
```
</TabItem>
<TabItem value="cli">
Update each field of the hash with the corresponding value:
```
> HSET key field1 value1 field2 value2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HSETNX
### Syntax
```
HSETNX key field value [field value ...]
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">write</span>
### Description
Set hash field value only if the field does not exist.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Set hash field value:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
noOfUpdatedFields, err := db.HSetNX("key", map[string]string{"field1": "value1", "field2": "value2"})
```
</TabItem>
<TabItem value="cli">
Set hash field value:
```
> HSETNX key field1 value1 field2 value2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HSTRLEN
### Syntax
```
HSTRLEN key field [field ...]
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">read</span>
### Description
Return the string length of the values stored at the specified fields.
Returns 0 if the value does not exist.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Return the string length of the values stored at the specified fields:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
lengths, err := db.HStrLen("key", "field1", "field2", "field3")
```
</TabItem>
<TabItem value="cli">
Return the string length of the values stored at the specified fields:
```
> HSTRLEN key field1 field2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HTTL
### Syntax
```
HTTL key FIELDS numfields field [field...]
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">hash</span>
<span className="acl-category">read</span>
### Description
Returns the remaining TTL (time to live) of a hash key's field(s) that have a set expiration.
This introspection capability allows you to check how many seconds a given hash field will continue to be part of the hash key.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Get the expiration time in seconds for fields in the hash:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
TTLArray, err := db.HTTL("key", field1, field2)
```
</TabItem>
<TabItem value="cli">
Get the expiration time in seconds for fields in the hash:
```
> HTTL key FIELDS 2 field1 field2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# HVALS
### Syntax
```
HVALS key
```
### Module
<span className="acl-category">hash</span>
### Categories
<span className="acl-category">hash</span>
<span className="acl-category">read</span>
<span className="acl-category">slow</span>
### Description
Returns all the values of the hash at key.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Returns all the values of the hash at key:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
values, err := db.HVals("key")
```
</TabItem>
<TabItem value="cli">
Returns all the values of the hash at key:
```
> HVALS key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1 @@
# Hash

View File

@ -0,0 +1,5 @@
---
sidebar_position: 8
---
# Commands

View File

@ -0,0 +1 @@
# List

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# LINDEX
### Syntax
```
LINDEX key index
```
### Module
<span className="acl-category">list</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">list</span>
<span className="acl-category">read</span>
### Description
Returns the list element at the given index.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Returns the list element at the given index:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
element, err := db.LIndex("key", 2)
```
</TabItem>
<TabItem value="cli">
Returns the list element at the given index:
```
> LINDEX key 2
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,47 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# LLEN
### Syntax
```
LLEN key
```
### Module
<span className="acl-category">list</span>
### Categories
<span className="acl-category">fast</span>
<span className="acl-category">list</span>
<span className="acl-category">read</span>
### Description
Returns the length of a list.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Returns the length of a list:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
length, err := db.LLen("key")
```
</TabItem>
<TabItem value="cli">
Returns the length of a list:
```
> LLEN key
```
</TabItem>
</Tabs>

View File

@ -0,0 +1,48 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# LMOVE
### Syntax
```
LMOVE source destination <LEFT | RIGHT> <LEFT | RIGHT>
```
### Module
<span className="acl-category">list</span>
### Categories
<span className="acl-category">list</span>
<span className="acl-category">slow</span>
<span className="acl-category">write</span>
### Description
Move element from one list to the other specifying left/right for both lists.
LEFT represents the start of a list. RIGHT represents the end of a list.
### Examples
<Tabs
defaultValue="go"
values={[
{ label: 'Go (Embedded)', value: 'go', },
{ label: 'CLI', value: 'cli', },
]}
>
<TabItem value="go">
Move an element from the beginning of the source list to the end of the destination list:
```go
db, err := sugardb.NewSugarDB()
if err != nil {
log.Fatal(err)
}
ok, err := db.LMove("source", "destination", "LEFT", "RIGHT")
```
</TabItem>
<TabItem value="cli">
Move an element from the beginning of the source list to the end of the destination list:
```
> LMOVE source destination LEFT RIGHT
```
</TabItem>
</Tabs>

Some files were not shown because too many files have changed in this diff Show More