├── .air.toml ├── .dockerignore ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── general.md │ ├── port_command_to_ironhawk.md │ ├── report_bug_as_maintainers.md │ ├── report_command_bug.md │ └── write_integration_tests_for_cmd.md └── workflows │ ├── cve-scan.yml │ ├── dockerhub.yml │ └── linter.yml ├── .gitignore ├── .gitmodules ├── .golangci.yaml ├── .goreleaser.yaml ├── .pre-commit-config.yaml ├── .vscode ├── launch.json └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING ├── README.md ├── development-setup.md ├── docs.md ├── git.md ├── go.md └── logging.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── VERSION ├── add_license_notice.sh ├── bin └── .gitkeep ├── build_protos.sh ├── cmd ├── init_config.go ├── root.go └── version.go ├── config ├── config.go ├── constants.go ├── constants_darwin.go └── constants_linux.go ├── docs ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc.mjs ├── .vscode │ ├── extensions.json │ ├── launch.json │ └── settings.json ├── CONTRIBUTING.md ├── astro.config.mjs ├── command_docs_template.md ├── eslint.config.js ├── netlify.toml ├── package-lock.json ├── package.json ├── public │ ├── .well-known │ │ └── funding-manifest-urls │ ├── dicedb-logo-dark.png │ ├── dicedb-logo-light.png │ ├── favicon.ico │ ├── favicon.png │ ├── funding.json │ ├── icon.png │ ├── img │ │ ├── general-cover.png │ │ └── hero-video.png │ ├── logo.png │ ├── robots.txt │ ├── site.webmanifest │ └── vercel.json ├── sample_command_docs.md ├── src │ ├── _skipped_commands │ │ ├── APPEND.md │ │ ├── AUTH.md │ │ ├── BF.ADD.md │ │ ├── BF.EXISTS.md │ │ ├── BF.RESERVE.md │ │ ├── BITCOUNT.md │ │ ├── BITFIELD.md │ │ ├── BITFIELD_RO.md │ │ ├── BITPOS.md │ │ ├── CLIENT.md │ │ ├── COMMAND COUNT.md │ │ ├── COMMAND GETKEYS.md │ │ ├── COMMAND HELP.md │ │ ├── COMMAND INFO.md │ │ ├── COMMAND LIST.md │ │ ├── COMMAND.md │ │ ├── COPY.md │ │ ├── DBSIZE.md │ │ ├── GEOADD.md │ │ ├── GEODIST.md │ │ ├── GEOHASH.md │ │ ├── GEOPOS.md │ │ ├── GETBIT.md │ │ ├── GETRANGE.md │ │ ├── GETSET.md │ │ ├── GETUNWATCH.md │ │ ├── HDEL.md │ │ ├── HELLO.md │ │ ├── HEXISTS.md │ │ ├── HGET.md │ │ ├── HGETALL.md │ │ ├── HINCRBY.md │ │ ├── HINCRBYFLOAT.md │ │ ├── HKEYS.md │ │ ├── HLEN.md │ │ ├── HMGET.md │ │ ├── HMSET.md │ │ ├── HRANDFIELD.md │ │ ├── HSCAN.md │ │ ├── HSET.md │ │ ├── HSETNX.md │ │ ├── HSTRLEN.md │ │ ├── HVALS.md │ │ ├── INCRBYFLOAT.md │ │ ├── JSON.ARRAPPEND.md │ │ ├── JSON.ARRINDEX.md │ │ ├── JSON.ARRINSERT.md │ │ ├── JSON.ARRLEN.md │ │ ├── JSON.ARRPOP.md │ │ ├── JSON.ARRTRIM.md │ │ ├── JSON.CLEAR.md │ │ ├── JSON.DEBUG.md │ │ ├── JSON.DEL.md │ │ ├── JSON.FORGET.md │ │ ├── JSON.GET.md │ │ ├── JSON.MGET.md │ │ ├── JSON.MSET.md │ │ ├── JSON.NUMINCRBY.md │ │ ├── JSON.OBJKEYS.md │ │ ├── JSON.OBJLEN.md │ │ ├── JSON.RESP.md │ │ ├── JSON.SET.md │ │ ├── JSON.STRLEN.md │ │ ├── JSON.TOGGLE.md │ │ ├── JSON.TYPE.md │ │ ├── KEYS.md │ │ ├── LATENCY.md │ │ ├── LINSERT.md │ │ ├── LLEN.md │ │ ├── LPOP.md │ │ ├── LPUSH.md │ │ ├── LRANGE.md │ │ ├── MGET.md │ │ ├── MSET.md │ │ ├── OBJECT.md │ │ ├── PERSIST.md │ │ ├── PFADD.md │ │ ├── PFCOUNT.md │ │ ├── PFCOUNTUNWATCH.md │ │ ├── PFCOUNTWATCH.md │ │ ├── PFMERGE.md │ │ ├── PTTL.md │ │ ├── RENAME.md │ │ ├── RPOP.md │ │ ├── RPUSH.md │ │ ├── SADD.md │ │ ├── SCARD.md │ │ ├── SDIFF.md │ │ ├── SETBIT.md │ │ ├── SETEX.md │ │ ├── SINTER.md │ │ ├── SLEEP.md │ │ ├── SMEMBERS.md │ │ ├── SREM.md │ │ ├── TOUCH.md │ │ ├── ZADD.md │ │ ├── ZCARD.md │ │ ├── ZCOUNT.md │ │ ├── ZPOPMAX.md │ │ ├── ZPOPMIN.md │ │ ├── ZRANGE.md │ │ ├── ZRANGEUNWATCH.md │ │ ├── ZRANGEWATCH.md │ │ ├── ZRANK.md │ │ └── ZREM.md │ ├── assets │ │ └── .gitkeep │ ├── components │ │ ├── AboutMeVertical.astro │ │ ├── BlogCard.astro │ │ ├── Dice.astro │ │ ├── Footer.astro │ │ ├── Hero.astro │ │ ├── KeyFeatures.astro │ │ ├── Nav.astro │ │ ├── RecentBlogs.astro │ │ ├── RecentReleases.astro │ │ ├── Seo.astro │ │ ├── SocialHandles.astro │ │ ├── SocialHandlesIcons.astro │ │ └── UserSocialHandles.astro │ ├── content │ │ ├── authors │ │ │ └── arpit.json │ │ ├── blog │ │ │ ├── dicedb-is-open-source.md │ │ │ └── hello-world.md │ │ ├── config.ts │ │ ├── docs │ │ │ ├── QWATCH.md │ │ │ ├── commands │ │ │ │ ├── DECR.md │ │ │ │ ├── DECRBY.md │ │ │ │ ├── DEL.md │ │ │ │ ├── ECHO.md │ │ │ │ ├── EXISTS.md │ │ │ │ ├── EXPIRE.md │ │ │ │ ├── EXPIREAT.md │ │ │ │ ├── EXPIRETIME.md │ │ │ │ ├── FLUSHDB.md │ │ │ │ ├── GET.WATCH.md │ │ │ │ ├── GET.md │ │ │ │ ├── GETDEL.md │ │ │ │ ├── GETEX.md │ │ │ │ ├── GETSET.md │ │ │ │ ├── HANDSHAKE.md │ │ │ │ ├── HGET.WATCH.md │ │ │ │ ├── HGET.md │ │ │ │ ├── HGETALL.WATCH.md │ │ │ │ ├── HGETALL.md │ │ │ │ ├── HSET.md │ │ │ │ ├── INCR.md │ │ │ │ ├── INCRBY.md │ │ │ │ ├── KEYS.md │ │ │ │ ├── PING.md │ │ │ │ ├── SET.md │ │ │ │ ├── TTL.md │ │ │ │ ├── TYPE.md │ │ │ │ ├── UNWATCH.md │ │ │ │ ├── ZADD.md │ │ │ │ ├── ZCARD.WATCH.md │ │ │ │ ├── ZCARD.md │ │ │ │ ├── ZCOUNT.WATCH.md │ │ │ │ ├── ZCOUNT.md │ │ │ │ ├── ZPOPMAX.md │ │ │ │ ├── ZPOPMIN.md │ │ │ │ ├── ZRANGE.WATCH.md │ │ │ │ ├── ZRANGE.md │ │ │ │ ├── ZRANK.WATCH.md │ │ │ │ ├── ZRANK.md │ │ │ │ └── ZREM.md │ │ │ ├── get-started │ │ │ │ ├── hello-world-reactive.mdx │ │ │ │ ├── hello-world.mdx │ │ │ │ └── installation.mdx │ │ │ ├── index.mdx │ │ │ ├── protocols │ │ │ │ ├── http.mdx │ │ │ │ ├── supported-protocols.mdx │ │ │ │ └── websockets.mdx │ │ │ ├── sdk │ │ │ │ └── go.mdx │ │ │ └── tutorials │ │ │ │ ├── realtime-leaderboard.mdx │ │ │ │ └── url-shortener.md │ │ ├── team │ │ │ ├── apoorv.json │ │ │ ├── arpit.json │ │ │ ├── ashwin.json │ │ │ ├── jyotinder.json │ │ │ ├── prashant.json │ │ │ ├── prateek.json │ │ │ └── soumya.json │ │ └── updates │ │ │ ├── 2024-07-18.md │ │ │ ├── 2024-08-01.md │ │ │ ├── 2024-08-08.md │ │ │ ├── 2024-08-15.md │ │ │ ├── 2024-08-19.md │ │ │ ├── 2024-08-22.md │ │ │ ├── 2024-08-29.md │ │ │ ├── 2024-09-05.md │ │ │ ├── 2024-09-12.md │ │ │ ├── 2024-09-19.md │ │ │ ├── 2024-09-26.md │ │ │ ├── 2024-10-03.md │ │ │ ├── 2024-10-10.md │ │ │ ├── 2024-10-17.md │ │ │ ├── 2024-10-24.md │ │ │ ├── 2024-11-07.md │ │ │ ├── 2024-11-14.md │ │ │ ├── 2024-11-21.md │ │ │ ├── 2024-11-28.md │ │ │ ├── 2024-12-05.md │ │ │ └── 2024-12-19.md │ ├── data │ │ ├── benchmarks.mdx │ │ ├── reactivity.md │ │ ├── roadmap.md │ │ └── site.json │ ├── env.d.ts │ ├── layouts │ │ ├── BlogLayout.astro │ │ ├── Head.astro │ │ ├── Layout.astro │ │ └── LayoutNarrow.astro │ ├── pages │ │ ├── about-us.astro │ │ ├── benchmarks.astro │ │ ├── blog │ │ │ ├── [slug].astro │ │ │ └── index.astro │ │ ├── community │ │ │ └── index.astro │ │ ├── index.astro │ │ ├── reactivity.astro │ │ ├── releases │ │ │ ├── [slug].astro │ │ │ └── index.astro │ │ ├── roadmap.astro │ │ ├── team.astro │ │ └── updates │ │ │ └── [slug].astro │ ├── styles │ │ ├── docs.css │ │ └── main.scss │ └── utils │ │ └── github.ts └── tsconfig.json ├── examples ├── chatroom-go │ ├── README.md │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── svc │ │ └── main.go ├── hello-world-go │ ├── README.md │ ├── go.mod │ ├── go.sum │ └── main.go └── leaderboard-go │ ├── README.md │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── svc │ └── main.go ├── go.mod ├── go.sum ├── internal ├── auth │ ├── session.go │ └── session_test.go ├── cmd │ ├── cmd_decr.go │ ├── cmd_decrby.go │ ├── cmd_del.go │ ├── cmd_echo.go │ ├── cmd_exists.go │ ├── cmd_expire.go │ ├── cmd_expireat.go │ ├── cmd_expiretime.go │ ├── cmd_flushdb.go │ ├── cmd_get.go │ ├── cmd_get_watch.go │ ├── cmd_getdel.go │ ├── cmd_getex.go │ ├── cmd_getset.go │ ├── cmd_handshake.go │ ├── cmd_hget.go │ ├── cmd_hget_watch.go │ ├── cmd_hgetall.go │ ├── cmd_hgetall_watch.go │ ├── cmd_hset.go │ ├── cmd_incr.go │ ├── cmd_incrby.go │ ├── cmd_keys.go │ ├── cmd_ping.go │ ├── cmd_set.go │ ├── cmd_ttl.go │ ├── cmd_type.go │ ├── cmd_unwatch.go │ ├── cmd_zadd.go │ ├── cmd_zcard.go │ ├── cmd_zcard_watch.go │ ├── cmd_zcount.go │ ├── cmd_zcount_watch.go │ ├── cmd_zpopmax.go │ ├── cmd_zpopmin.go │ ├── cmd_zrange.go │ ├── cmd_zrange_watch.go │ ├── cmd_zrank.go │ ├── cmd_zrank_watch.go │ ├── cmd_zrem.go │ └── cmds.go ├── comm │ └── client.go ├── common │ ├── map.go │ └── regmap.go ├── dencoding │ ├── dencoding_benchmark_test.go │ ├── int.go │ └── int_test.go ├── errors │ └── errors.go ├── eval │ ├── bitpos.go │ ├── bloom_test.go │ ├── bloom_utils.go │ ├── bytearray.go │ ├── bytearray_test.go │ ├── bytelist.go │ ├── bytelist_test.go │ ├── commands.go │ ├── constants.go │ ├── countminsketch.go │ ├── countminsketch_test.go │ ├── deque.go │ ├── deque_test.go │ ├── dump_restore.go │ ├── eval.go │ ├── eval_test.go │ ├── execute.go │ ├── geo │ │ └── geo.go │ ├── hmap.go │ ├── hmap_test.go │ ├── main_test.go │ ├── sortedset │ │ └── sorted_set.go │ ├── store_eval.go │ ├── type_asserts.go │ ├── type_bloomfilter.go │ ├── type_string.go │ └── type_string_test.go ├── id │ ├── id.go │ └── id_test.go ├── iomultiplexer │ ├── constants.go │ ├── epoll_linux.go │ ├── errors.go │ ├── interface.go │ ├── kqueue_darwin.go │ ├── types.go │ ├── types_darwin.go │ └── types_linux.go ├── logger │ ├── logger.go │ └── zerolog.go ├── object │ ├── deep_copy.go │ ├── object.go │ └── typeencoding.go ├── observability │ ├── constants.go │ ├── hardware.go │ └── instance.go ├── ops │ └── store_op.go ├── regex │ ├── regex.go │ └── regex_test.go ├── server │ ├── ironhawk │ │ ├── iothread.go │ │ ├── iothread_manager.go │ │ ├── main.go │ │ └── watch_manager.go │ └── utils │ │ ├── array.go │ │ ├── bitfield.go │ │ ├── boolToInt.go │ │ ├── constants.go │ │ ├── floatToInt.go │ │ ├── json.go │ │ ├── jsontype.go │ │ ├── jsontype_test.go │ │ └── round.go ├── shard │ └── main.go ├── shardmanager │ └── main.go ├── shardthread │ └── main.go ├── store │ ├── aof.go │ ├── aof_test.go │ ├── batchevictionlru.go │ ├── constants.go │ ├── eviction.go │ ├── expire.go │ ├── store.go │ └── store_options.go ├── types │ ├── params.go │ └── sortedset.go ├── wal │ ├── wal.go │ └── wal_forge.go └── watchmanager │ └── watch_manager.go ├── main.go ├── scripts ├── generate-docs │ ├── doc.tmpl │ └── main.go └── test-docs │ └── main.go ├── server └── main.go ├── tests └── commands │ └── ironhawk │ ├── decr_test.go │ ├── decrby_test.go │ ├── del_test.go │ ├── echo_test.go │ ├── exists_test.go │ ├── expire_test.go │ ├── expireat_test.go │ ├── expiretime_test.go │ ├── flushdb_test.go │ ├── get_test.go │ ├── get_watch_test.go │ ├── getdel_test.go │ ├── getex_test.go │ ├── getset_test.go │ ├── hget_test.go │ ├── hget_watch_test.go │ ├── hgetall_test.go │ ├── hgetall_watch_test.go │ ├── hset_test.go │ ├── incr_test.go │ ├── incrby_test.go │ ├── keys_test.go │ ├── main_test.go │ ├── ping_test.go │ ├── set_test.go │ ├── setup.go │ ├── ttl_test.go │ ├── type_test.go │ ├── zadd_test.go │ ├── zcard_test.go │ ├── zcard_watch_test.go │ ├── zcount_test.go │ ├── zcount_watch_test.go │ ├── zpopmax_test.go │ ├── zpopmin_test.go │ ├── zrange_test.go │ ├── zrange_watch_test.go │ ├── zrank_test.go │ ├── zrank_watch_test.go │ └── zrem_test.go ├── tests0 ├── append_test.go ├── bit_test.go ├── bloom_test.go ├── command_count_test.go ├── command_default_test.go ├── command_docs_test.go ├── command_getkeys_test.go ├── command_info_test.go ├── command_list_test.go ├── command_rename_test.go ├── copy_test.go ├── countminsketch_test.go ├── dbsize_test.go ├── deque_test.go ├── dump_test.go ├── geo_test.go ├── getrange_test.go ├── hdel_test.go ├── hello_test.go ├── hincrby_test.go ├── hincrbyfloat_test.go ├── hkeys_test.go ├── hlen_test.go ├── hmget_test.go ├── hmset_test.go ├── hrandfield_test.go ├── hscan_test.go ├── hset_test.go ├── hsetnx_test.go ├── hstrlen_test.go ├── hvals_test.go ├── hyperloglog_test.go ├── incr_by_float_test.go ├── json_test.go ├── jsondebug_test.go ├── jsonresp_test.go ├── keys_test.go ├── mget_test.go ├── mset_test.go ├── object_test.go ├── pfcountwatch_test.go ├── set_data_cmd_test.go ├── touch_test.go ├── zrangewatch_test.go └── zset_test.go └── testutils ├── json.go ├── parsecommand.go └── slices.go /.air.toml: -------------------------------------------------------------------------------- 1 | root = "." 2 | tmp_dir = "tmp" 3 | 4 | [build] 5 | bin = "./dicedb" 6 | cmd = "go build -o ./dicedb" 7 | delay = 1000 8 | exclude_dir = ["assets", "tmp", "vendor"] 9 | exclude_file = [] 10 | exclude_regex = [] 11 | exclude_unchanged = false 12 | follow_symlink = false 13 | full_bin = "GO_ENV=development ./dicedb --engine ironhawk" 14 | include_dir = [] 15 | include_ext = ["go", "tpl", "tmpl", "yaml", "env"] 16 | kill_delay = "1s" 17 | log = "build-errors.log" 18 | send_interrupt = true 19 | stop_on_error = true 20 | 21 | [color] 22 | app = "" 23 | build = "yellow" 24 | main = "magenta" 25 | runner = "green" 26 | watcher = "cyan" 27 | 28 | [log] 29 | time = false 30 | 31 | [misc] 32 | clean_on_exit = true 33 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | dicedb 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: ['arpitbbhayani'] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue with Base Instructions 3 | about: This template is supposed to be used by maintainers to create issue 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | > Issue details go here ... 10 | 11 | ## Setup Instructions 12 | 13 | 1. setup DiceDB server locally from the source - [instructions](https://github.com/dicedb/dice) 14 | 2. setup DiceDB Go SDK locally from the source - [instructions](https://github.com/dicedb/dicedb-go) 15 | 3. setup DiceDB CLI locally from the source - [instructions](https://github.com/dicedb/dicedb-cli) 16 | 4. refer to the `Pointing to local checked-out `dicedb-go` section in `README`. 17 | 18 | ### Start the DiceDB server 19 | 20 | ``` 21 | $ go run main.go --log-level debug 22 | ``` 23 | 24 | ## Follow the contribution guidelines 25 | 26 | These are general guidelines to follow before you submit a patch. Please mark them as done once you complete them 27 | 28 | - [ ] please go through the [CONTRIBUTING](https://github.com/DiceDB/dice/tree/master/CONTRIBUTING) guide 29 | - [ ] follow [LOGGING best practices](https://github.com/DiceDB/dice/blob/master/CONTRIBUTING/logging.md) 30 | - [ ] follow [Golang best practices](https://github.com/DiceDB/dice/blob/master/CONTRIBUTING/go.md) 31 | - [ ] run `make lint` on your local copy of the codebase 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/report_bug_as_maintainers.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Report a bug [maintainers only] 3 | about: This template is supposed to be used by maintainers to report a bug 4 | title: 'Bug: ' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | > Pick this issue only after #{PR_NUM} is merged. 10 | 11 | {details of the issue} 12 | 13 | ## Steps to patch 14 | 15 | 1. setup DiceDB server locally from source - [instructions](https://github.com/dicedb/dice) 16 | 2. setup DiceDB CLI locally from source - [instructions](https://github.com/dicedb/dice) 17 | 18 | ## Follow the contribution guidelines 19 | 20 | These are general guidelines to follow before you submit a patch. Please mark them as done 21 | once you complete them 22 | 23 | - [ ] please go through the [CONTRIBUTING](https://github.com/DiceDB/dice/tree/master/CONTRIBUTING) guide 24 | - [ ] follow [LOGGING best practices](https://github.com/DiceDB/dice/blob/master/CONTRIBUTING/logging.md) 25 | - [ ] follow [Golang best practices](https://github.com/DiceDB/dice/blob/master/CONTRIBUTING/go.md) 26 | - [ ] run `make lint` on your local copy of the codebase 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/report_command_bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug in DiceDB command 3 | about: Use this template to report bug in any command behaviour 4 | title: 'Inconsistent `{CMD}`: ' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Steps to reproduce 11 | 12 | {steps_to_reproduce} 13 | 14 | ## Expected output 15 | 16 | The expected output when the above set of commands 17 | 18 | ``` 19 | {expected_output} 20 | ``` 21 | 22 | ## Observed output 23 | 24 | The observed output when the above set of commands when run on DiceDB 25 | 26 | ``` 27 | {observed_output} 28 | ``` 29 | -------------------------------------------------------------------------------- /.github/workflows/cve-scan.yml: -------------------------------------------------------------------------------- 1 | name: Weekly Trivy Scan 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * 1' # Run every Monday at midnight 6 | workflow_dispatch: 7 | 8 | jobs: 9 | trivy_scan: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v4 14 | 15 | - name: Install Trivy 16 | run: | 17 | curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin v0.56.2 18 | 19 | - name: Run Trivy scan 20 | run: | 21 | trivy fs --security-checks vuln . -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | name: linter 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | paths: 7 | - '**/*.go' 8 | 9 | pull_request: 10 | branches: [master] 11 | paths: 12 | - '**/*.go' 13 | 14 | permissions: 15 | contents: read 16 | pull-requests: read 17 | 18 | jobs: 19 | golangci: 20 | name: lint 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - uses: actions/setup-go@v5 25 | with: 26 | go-version: stable 27 | - name: golangci-lint 28 | uses: golangci/golangci-lint-action@v6 29 | with: 30 | version: v1.64.6 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/dice 2 | *.aof 3 | *.out 4 | *.prof 5 | dice-server 6 | dicedb 7 | venv 8 | __pycache__ 9 | .idea/ 10 | ./dice 11 | *.rdb 12 | dice 13 | main 14 | tmp/ 15 | vendor/ 16 | 17 | # build output 18 | dist/ 19 | # generated types 20 | .astro/ 21 | 22 | # dependencies 23 | node_modules/ 24 | 25 | # logs 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | pnpm-debug.log* 30 | 31 | 32 | # environment variables 33 | .env 34 | .env.production 35 | 36 | # macOS-specific files 37 | .DS_Store 38 | dicedb.yaml 39 | dicedb.conf 40 | logs/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiceDB/dice/ebad5d913c27aa7bb716fb84555e36b94456e99a/.gitmodules -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | before: 2 | hooks: 3 | - go mod tidy 4 | builds: 5 | - env: 6 | - CGO_ENABLED=0 7 | goos: 8 | - linux 9 | - darwin 10 | goarch: 11 | - amd64 12 | ignore: 13 | - goarch: arm 14 | archives: 15 | - replacements: 16 | darwin: Darwin 17 | linux: Linux 18 | 386: i386 19 | amd64: x86_64 20 | checksum: 21 | name_template: 'checksums.txt' 22 | snapshot: 23 | name_template: "{{ incpatch .Version }}-next" 24 | changelog: 25 | sort: asc 26 | filters: 27 | exclude: 28 | - '^docs:' 29 | - '^test:' 30 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.6.0 4 | hooks: 5 | - id: trailing-whitespace 6 | - id: end-of-file-fixer 7 | - id: check-added-large-files 8 | 9 | - repo: https://github.com/dnephin/pre-commit-golang 10 | rev: v0.5.1 11 | hooks: 12 | - id: go-fmt 13 | - id: golangci-lint 14 | - id: go-mod-tidy 15 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Server with Watch", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "main.go", 13 | "args": ["--enable-watch", "--log-level", "debug", "--engine", "ironhawk", "--enable-wal"] 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[python]": { 3 | "editor.detectIndentation" : false, 4 | "editor.insertSpaces": true, 5 | "editor.tabSize": 4 6 | }, 7 | "[astro]": { 8 | "editor.detectIndentation" : false, 9 | "editor.insertSpaces": true, 10 | "editor.tabSize": 2 11 | }, 12 | "[scss]": { 13 | "editor.detectIndentation" : false, 14 | "editor.insertSpaces": true, 15 | "editor.tabSize": 2 16 | } 17 | } -------------------------------------------------------------------------------- /CONTRIBUTING/docs.md: -------------------------------------------------------------------------------- 1 | # Development Setup for Docs 2 | 3 | We use [Astro](https://astro.build/) framework to power the [dicedb.io website](https://dicedb.io) and [Starlight](https://starlight.astro.build/) to power the docs. Once you have NodeJS installed, fire the following commands to get your local version of [dicedb.io](https://dicedb.io) running. 4 | 5 | ```bash 6 | $ cd docs 7 | $ npm install 8 | $ npm run dev 9 | ``` 10 | 11 | Once the server starts, visit http://localhost:4321/ in your favourite browser. This runs with a hot reload which means any changes you make in the website and the documentation can be instantly viewed on the browser. 12 | 13 | ### Docs directory structure 14 | 15 | 1. `docs/src/content/docs/commands` is where all the commands are documented 16 | 2. `docs/src/content/docs/tutorials` is where all the tutorials are documented 17 | -------------------------------------------------------------------------------- /CONTRIBUTING/go.md: -------------------------------------------------------------------------------- 1 | # Go Best Practices 2 | 3 | ## Language Specifics 4 | 5 | 1. Functions that return something are given noun-like names 6 | 7 | ```go 8 | func (c *Config) GetJobName(key string) (value string, ok bool) // not okay 9 | func (c *Config) JobName(key string) (value string, ok bool) // okay 10 | ``` 11 | 12 | 2. Functions that do something are given verb-like names 13 | 14 | ```go 15 | func (c *Config) WriteDetail(w io.Writer) (int64, error) // okay 16 | ``` 17 | 18 | 3. Identical functions that differ only by the types involved include the name of the type at the end of the name. 19 | 20 | ```go 21 | func ParseInt(input string) (int, error) // okay 22 | func ParseInt64(input string) (int64, error) // okay 23 | func AppendInt(buf []byte, value int) []byte // okay 24 | func AppendInt64(buf []byte, value int64) []byte // okay 25 | ``` 26 | 27 | 4. If there is a clear “primary” version, the type can be omitted from the name for that version: 28 | 29 | ```go 30 | func (c *Config) Marshal() ([]byte, error) // okay 31 | func (c *Config) MarshalText() (string, error) // okay 32 | ``` 33 | 34 | ## Formatting and Linting 35 | 36 | Please complete the [development setup](https://github.com/DiceDB/dice/blob/master/CONTRIBUTING/development-setup.md) and run `make lint`. This command lints the code and formats it according to best practices. 37 | -------------------------------------------------------------------------------- /CONTRIBUTING/logging.md: -------------------------------------------------------------------------------- 1 | # Logging Best Practices 2 | 3 | 1. Use lowercase for log messages, except for proper nouns 4 | 5 | ```go 6 | slog.Info("Starting DiceDB", slog.String("version", config.DiceDBVersion)) // not okay 7 | slog.Info("starting DiceDB", slog.String("version", config.DiceDBVersion)) // okay 8 | ``` 9 | 10 | 2. Be concise, yet informative 11 | 12 | ```go 13 | slog.Info("DiceDB is starting, initialization in progress", slog.String("version", config.DiceDBVersion)) // not okay 14 | slog.Info("starting DiceDB", slog.String("version", config.DiceDBVersion)) // okay 15 | ``` 16 | 17 | 3. Use structured logging with key-value pairs 18 | 19 | ```go 20 | slog.Info("running on port", config.Port) // not okay 21 | slog.Info("running with", slog.Int("port", config.Port)) // okay 22 | ``` 23 | 24 | 4. Avoid logging redundant information 25 | 26 | ```go 27 | slog.Info("running in multi-threaded mode with", slog.String("mode", "multi-threaded"), slog.Int("num-shards", numShards)) // not okay 28 | slog.Info("running with", slog.String("mode", "multi-threaded"), slog.Int("num-shards", numShards)) // okay 29 | ``` 30 | 31 | 5. Use Boolean values effectively 32 | 33 | ```go 34 | slog.Info("enable-watch is set to true", slog.Bool("enable-watch", true)) // not okay 35 | slog.Info("running with", slog.Bool("enable-watch", config.EnableWatch)) // okay 36 | ``` 37 | 38 | 6. Log specific details over general statements 39 | 40 | ```go 41 | slog.Info("server is running") // not okay 42 | slog.Info("running with", slog.Int("port", config.Port)) // okay 43 | ``` 44 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Start from a slim alpine image 2 | FROM golang:1.24.2-alpine AS builder 3 | WORKDIR /src 4 | COPY . . 5 | 6 | # Install musl-dev to make sure we get the required libraries 7 | RUN apk add --no-cache gcc musl-dev libc6-compat make 8 | RUN make build 9 | 10 | FROM alpine 11 | WORKDIR /src 12 | 13 | # Copy the Go binary from the builder stage 14 | COPY --from=builder /usr/local/go /usr/local/go 15 | ENV PATH="/usr/local/go/bin:${PATH}" 16 | 17 | COPY --from=builder /src/dicedb /src/VERSION /src/ 18 | 19 | EXPOSE 7379 20 | 21 | ENTRYPOINT ["/src/dicedb"] 22 | CMD [] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022-present, DiceDB contributors 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | v1.0.10 -------------------------------------------------------------------------------- /bin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiceDB/dice/ebad5d913c27aa7bb716fb84555e36b94456e99a/bin/.gitkeep -------------------------------------------------------------------------------- /build_protos.sh: -------------------------------------------------------------------------------- 1 | protoc --go_out=. ./internal/wal/wal.proto -------------------------------------------------------------------------------- /cmd/init_config.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package cmd 5 | 6 | import ( 7 | "github.com/dicedb/dice/config" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var initConfigCmd = &cobra.Command{ 12 | Use: "config-init", 13 | Short: "creates a config file with default values", 14 | Run: func(cmd *cobra.Command, args []string) { 15 | config.InitConfig(cmd.Flags()) 16 | }, 17 | } 18 | 19 | func init() { 20 | initConfigCmd.Flags().BoolP("overwrite", "", false, "overwrite the existing config") 21 | rootCmd.AddCommand(initConfigCmd) 22 | } 23 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package cmd 5 | 6 | import ( 7 | "fmt" 8 | "log/slog" 9 | "os" 10 | "reflect" 11 | "strconv" 12 | 13 | "github.com/dicedb/dice/config" 14 | "github.com/dicedb/dice/internal/logger" 15 | "github.com/dicedb/dice/server" 16 | "github.com/spf13/cobra" 17 | ) 18 | 19 | func init() { 20 | flags := rootCmd.PersistentFlags() 21 | 22 | c := config.DiceDBConfig{} 23 | _type := reflect.TypeOf(c) 24 | for i := 0; i < _type.NumField(); i++ { 25 | field := _type.Field(i) 26 | yamlTag := field.Tag.Get("mapstructure") 27 | descriptionTag := field.Tag.Get("description") 28 | defaultTag := field.Tag.Get("default") 29 | 30 | switch field.Type.Kind() { 31 | case reflect.String: 32 | flags.String(yamlTag, defaultTag, descriptionTag) 33 | case reflect.Int: 34 | val, _ := strconv.Atoi(defaultTag) 35 | flags.Int(yamlTag, val, descriptionTag) 36 | case reflect.Bool: 37 | val, _ := strconv.ParseBool(defaultTag) 38 | flags.Bool(yamlTag, val, descriptionTag) 39 | } 40 | } 41 | } 42 | 43 | var rootCmd = &cobra.Command{ 44 | Use: "dicedb", 45 | Short: "an in-memory database;", 46 | Run: func(cmd *cobra.Command, args []string) { 47 | config.Load(cmd.Flags()) 48 | slog.SetDefault(logger.New()) 49 | server.Start() 50 | }, 51 | } 52 | 53 | func Execute() { 54 | if err := rootCmd.Execute(); err != nil { 55 | fmt.Fprintln(os.Stderr, err) 56 | os.Exit(1) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package cmd 5 | 6 | import ( 7 | "fmt" 8 | 9 | "github.com/dicedb/dice/config" 10 | "github.com/spf13/cobra" 11 | ) 12 | 13 | var versionCmd = &cobra.Command{ 14 | Use: "version", 15 | Short: "print the version of DiceDB", 16 | Run: func(cmd *cobra.Command, args []string) { 17 | fmt.Println(config.DiceDBVersion) 18 | }, 19 | } 20 | 21 | func init() { 22 | rootCmd.AddCommand(versionCmd) 23 | } 24 | -------------------------------------------------------------------------------- /config/constants.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package config 5 | 6 | import "time" 7 | 8 | const ( 9 | EvictionRatio float64 = 0.9 10 | DefaultKeysLimit int = 200000000 11 | ShardCronFrequency time.Duration = 1 * time.Second 12 | EnableProfile bool = false 13 | 14 | KeepAlive int32 = 300 15 | Timeout int32 = 300 16 | 17 | DefaultConnBacklogSize = 128 18 | 19 | MaxRequestSize = 32 * 1024 * 1024 // 32 MB 20 | IoBufferSize = 16 * 1024 // 16 KB 21 | ) 22 | -------------------------------------------------------------------------------- /config/constants_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | //go:build darwin 5 | 6 | package config 7 | 8 | var MetadataDir = "/usr/local/etc/dicedb/" 9 | -------------------------------------------------------------------------------- /config/constants_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | //go:build linux 5 | 6 | package config 7 | 8 | var MetadataDir = "/etc/dicedb/" 9 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | # generated types 4 | .astro/ 5 | 6 | # dependencies 7 | node_modules/ 8 | 9 | # logs 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | 16 | # environment variables 17 | .env 18 | .env.production 19 | 20 | # macOS-specific files 21 | .DS_Store 22 | -------------------------------------------------------------------------------- /docs/.nvmrc: -------------------------------------------------------------------------------- 1 | 20.18 -------------------------------------------------------------------------------- /docs/.prettierignore: -------------------------------------------------------------------------------- 1 | src/content/docs/commands/* -------------------------------------------------------------------------------- /docs/.prettierrc.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import("prettier").Config} */ 2 | export default { 3 | plugins: ["prettier-plugin-astro"], 4 | overrides: [ 5 | { 6 | files: "*.astro", 7 | options: { 8 | parser: "astro", 9 | }, 10 | }, 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /docs/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["astro-build.astro-vscode"], 3 | "unwantedRecommendations": [] 4 | } 5 | -------------------------------------------------------------------------------- /docs/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "./node_modules/.bin/astro dev", 6 | "name": "Development server", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /docs/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2 3 | } 4 | -------------------------------------------------------------------------------- /docs/eslint.config.js: -------------------------------------------------------------------------------- 1 | import eslintPluginAstro from "eslint-plugin-astro"; 2 | export default [ 3 | // add more generic rule sets here, such as: 4 | // js.configs.recommended, 5 | ...eslintPluginAstro.configs.recommended, 6 | { 7 | rules: { 8 | // override/add rules settings here, such as: 9 | // "astro/no-set-html-directive": "error" 10 | }, 11 | }, 12 | ]; 13 | -------------------------------------------------------------------------------- /docs/netlify.toml: -------------------------------------------------------------------------------- 1 | [[redirects]] 2 | from = "https://dicedb-docs.netlify.app/" 3 | to = "https://dicedb.io" 4 | status = 301 5 | force = true 6 | 7 | [[redirects]] 8 | from = "/docs" 9 | to = "/get-started/installation/" 10 | status = 301 11 | force = true 12 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DiceDB", 3 | "type": "module", 4 | "version": "0.0.1", 5 | "scripts": { 6 | "dev": "astro dev", 7 | "start": "astro dev", 8 | "build": "astro build", 9 | "preview": "astro preview", 10 | "astro": "astro", 11 | "lint": "prettier . --write && eslint \"src/**/*.{js,astro}\"" 12 | }, 13 | "dependencies": { 14 | "@astrojs/sitemap": "^3.3.0", 15 | "@astrojs/starlight": "^0.34.0", 16 | "astro-analytics": "^2.7.0", 17 | "astro-embed": "^0.9.0", 18 | "bulma": "^0.9.4", 19 | "lucide-astro": "^0.438.0", 20 | "sass": "^1.62.1", 21 | "sharp": "^0.32.5" 22 | }, 23 | "devDependencies": { 24 | "astro": "^5.7.2", 25 | "eslint": "^9.11.0", 26 | "eslint-plugin-astro": "^1.2.4", 27 | "prettier": "^3.3.3", 28 | "prettier-plugin-astro": "^0.14.1", 29 | "sass-embedded": "^1.78.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /docs/public/.well-known/funding-manifest-urls: -------------------------------------------------------------------------------- 1 | https://dicedb.io/funding.json -------------------------------------------------------------------------------- /docs/public/dicedb-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiceDB/dice/ebad5d913c27aa7bb716fb84555e36b94456e99a/docs/public/dicedb-logo-dark.png -------------------------------------------------------------------------------- /docs/public/dicedb-logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiceDB/dice/ebad5d913c27aa7bb716fb84555e36b94456e99a/docs/public/dicedb-logo-light.png -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiceDB/dice/ebad5d913c27aa7bb716fb84555e36b94456e99a/docs/public/favicon.ico -------------------------------------------------------------------------------- /docs/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiceDB/dice/ebad5d913c27aa7bb716fb84555e36b94456e99a/docs/public/favicon.png -------------------------------------------------------------------------------- /docs/public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiceDB/dice/ebad5d913c27aa7bb716fb84555e36b94456e99a/docs/public/icon.png -------------------------------------------------------------------------------- /docs/public/img/general-cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiceDB/dice/ebad5d913c27aa7bb716fb84555e36b94456e99a/docs/public/img/general-cover.png -------------------------------------------------------------------------------- /docs/public/img/hero-video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiceDB/dice/ebad5d913c27aa7bb716fb84555e36b94456e99a/docs/public/img/hero-video.png -------------------------------------------------------------------------------- /docs/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiceDB/dice/ebad5d913c27aa7bb716fb84555e36b94456e99a/docs/public/logo.png -------------------------------------------------------------------------------- /docs/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | 4 | Sitemap: https://arpitbhayani.me/sitemap-index.xml 5 | -------------------------------------------------------------------------------- /docs/public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /docs/public/vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "redirects": [] 3 | } 4 | -------------------------------------------------------------------------------- /docs/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiceDB/dice/ebad5d913c27aa7bb716fb84555e36b94456e99a/docs/src/assets/.gitkeep -------------------------------------------------------------------------------- /docs/src/components/AboutMeVertical.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import SocialHandlesIcons from "./SocialHandlesIcons.astro"; 3 | --- 4 | 5 |
6 |
7 |
8 |
9 |
10 | -------------------------------------------------------------------------------- /docs/src/components/BlogCard.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { blog } = Astro.props; 3 | --- 4 | 5 |
6 |
7 | {blog.data.title} 10 |
11 |
12 | -------------------------------------------------------------------------------- /docs/src/components/Dice.astro: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | --- 4 | 5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /docs/src/components/KeyFeatures.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { ArrowDownLeft, Cpu, Waves } from "lucide-astro"; 3 | --- 4 | 5 |
6 |
7 |
8 |
9 |

12 | 13 | Reactive 14 |

15 |

16 | instead of polling the database for changes, DiceDB can push the 17 | resultset if you subscribe to it. 18 |

19 |
20 |
21 |
22 |
23 |

26 | 27 | Fast 28 |

29 |

30 | higher throughput and lower median latencies, making it ideal for 31 | modern workloads. 32 |

33 |
34 |
35 |
36 |
37 |

40 | 41 | For Modern Hardware 42 |

43 |

44 | fully utilizes underlying cores to get higher throughput and better 45 | hardware utilization. 46 |

47 |
48 |
49 |
50 |
51 | -------------------------------------------------------------------------------- /docs/src/components/RecentBlogs.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { blogs } = Astro.props; 3 | --- 4 | 5 |
6 |
7 |
    8 | { 9 | blogs.map((blog) => ( 10 |
  • 11 | 12 | {blog.data.published_at.toLocaleString("en-us", { 13 | day: "2-digit", 14 | month: "short", 15 | year: "numeric", 16 | })} 17 | : 18 | 19 | 20 | {blog.data.title} 21 | 22 |
  • 23 | )) 24 | } 25 |
26 |
27 |
28 | -------------------------------------------------------------------------------- /docs/src/components/RecentReleases.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { releases } = Astro.props; 3 | --- 4 | 5 |
6 |
7 |
    8 | { 9 | releases.map((release) => ( 10 |
  • 11 | 12 | {release.data.published_at.toLocaleString("en-us", { 13 | day: "2-digit", 14 | month: "short", 15 | year: "numeric", 16 | })} 17 | : 18 | 19 | 20 | {release.data.title} 21 | 22 |
  • 23 | )) 24 | } 25 |
26 |
27 |
28 | -------------------------------------------------------------------------------- /docs/src/components/Seo.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import siteData from "../data/site.json"; 3 | 4 | const { title, description, img, video, blog, session, JSONLD } = Astro.props; 5 | --- 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | { 33 | JSONLD && ( 34 | ${JSON.stringify( 36 | JSONLD, 37 | )}`} 38 | /> 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /docs/src/components/SocialHandles.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Twitter, Github, UsersRound } from "lucide-astro"; 3 | --- 4 | 5 | 34 | -------------------------------------------------------------------------------- /docs/src/components/SocialHandlesIcons.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Twitter, Github, UsersRound } from "lucide-astro"; 3 | --- 4 | 5 | 23 | -------------------------------------------------------------------------------- /docs/src/components/UserSocialHandles.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Twitter, Github, Linkedin, Globe } from "lucide-astro"; 3 | const { x, github, linkedin, website } = Astro.props; 4 | --- 5 | 6 | 64 | -------------------------------------------------------------------------------- /docs/src/content/authors/arpit.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Arpit Bhayani", 3 | "bio": "creator DiceDB, Staff Engg at Google Ads and GCP Dataproc", 4 | "avatar_url": "https://edge.arpitbhayani.me/img/arpit-5.jpg", 5 | "url": "https://arpitbhayani.me/" 6 | } 7 | -------------------------------------------------------------------------------- /docs/src/content/config.ts: -------------------------------------------------------------------------------- 1 | import { defineCollection, z, reference } from "astro:content"; 2 | import { docsSchema } from "@astrojs/starlight/schema"; 3 | 4 | const blog = defineCollection({ 5 | type: "content", 6 | schema: z.object({ 7 | title: z.string(), 8 | description: z.string(), 9 | published_at: z.coerce.date(), 10 | author: reference("authors"), 11 | }), 12 | }); 13 | 14 | const authors = defineCollection({ 15 | type: "data", 16 | schema: z.object({ 17 | name: z.string(), 18 | bio: z.string(), 19 | avatar_url: z.string(), 20 | url: z.string(), 21 | }), 22 | }); 23 | 24 | const releases = defineCollection({ 25 | type: "content", 26 | schema: z.object({ 27 | title: z.string(), 28 | description: z.string(), 29 | published_at: z.coerce.date(), 30 | author: reference("authors"), 31 | }), 32 | }); 33 | 34 | const updates = defineCollection({ 35 | type: "content", 36 | schema: z.object({}), 37 | }); 38 | 39 | const team = defineCollection({ 40 | type: "data", 41 | schema: z.object({ 42 | name: z.string(), 43 | avatar_url: z.string(), 44 | roles: z.array(z.string()), 45 | x: z.string(), 46 | linkedin: z.string(), 47 | github: z.string(), 48 | website: z.string(), 49 | }), 50 | }); 51 | 52 | export const collections = { 53 | blog, 54 | authors, 55 | releases, 56 | team, 57 | updates, 58 | docs: defineCollection({ schema: docsSchema() }), 59 | }; 60 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/DECR.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DECR 3 | description: DECR decrements the value of the specified key in args by 1 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | DECR key 15 | ``` 16 | 17 | 18 | DECR command decrements the integer at 'key' by one. Creates 'key' as -1 if absent. 19 | The command raises an error if the value is a non-integer. 20 | 21 | Returns the new value of 'key' on success. 22 | 23 | 24 | #### Examples 25 | 26 | ``` 27 | 28 | localhost:7379> SET k 43 29 | OK 30 | localhost:7379> DECR k 31 | OK 42 32 | localhost:7379> DECR k1 33 | OK -1 34 | localhost:7379> SET k2 v 35 | OK 36 | localhost:7379> DECR k2 37 | ERR wrongtype operation against a key holding the wrong kind of value 38 | 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/DECRBY.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DECRBY 3 | description: DECRBY decrements the specified key by the specified delta 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | DECRBY key delta 15 | ``` 16 | 17 | 18 | DECRBY command decrements the integer at 'key' by the delta specified. Creates 'key' with value (-delta) if absent. 19 | The command raises an error if the value is a non-integer. 20 | 21 | Returns the new value of 'key' on success. 22 | 23 | 24 | #### Examples 25 | 26 | ``` 27 | 28 | localhost:7379> SET k 43 29 | OK 30 | localhost:7379> DECRBY k 10 31 | OK 33 32 | localhost:7379> DECRBY k2 50 33 | OK -50 34 | localhost:7379> GET k2 35 | OK "-50" 36 | 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/DEL.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DEL 3 | description: DEL deletes all the specified keys and returns the number of keys deleted on success. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | DEL key [key ...] 15 | ``` 16 | 17 | DEL deletes all the specified keys and returns the number of keys deleted on success. 18 | 19 | If the key does not exist, it is ignored. The command returns the number of keys successfully deleted. 20 | 21 | #### Examples 22 | 23 | ``` 24 | 25 | localhost:7379> SET k1 v1 26 | OK 27 | localhost:7379> SET k2 v2 28 | OK 29 | localhost:7379> DEL k1 k2 k3 30 | OK 2 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ECHO.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ECHO 3 | description: ECHO returns the message passed to it 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ECHO message 15 | ``` 16 | 17 | ECHO returns the message passed to it. 18 | 19 | #### Examples 20 | 21 | ``` 22 | 23 | localhost:7379> ECHO dicedb 24 | OK dicedb 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/EXISTS.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: EXISTS 3 | description: EXISTS returns the count of keys that exist among the given 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | EXISTS key [key ...] 15 | ``` 16 | 17 | EXISTS command returns the count of keys that exist among the given arguments without modifying them. 18 | 19 | #### Examples 20 | 21 | ``` 22 | 23 | localhost:7379> SET k1 v1 24 | OK 25 | localhost:7379> SET k2 v2 26 | OK 27 | localhost:7379> EXISTS k1 k2 k3 28 | OK 2 29 | 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/EXPIRE.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: EXPIRE 3 | description: EXPIRE sets an expiry (in seconds) on a specified key 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | EXPIRE key seconds [NX | XX] 15 | ``` 16 | 17 | 18 | EXPIRE sets an expiry (in seconds) on a specified key. After the expiry time has elapsed, the key will be automatically deleted. 19 | 20 | > If you want to delete the expiration time on the key, you can use the PERSIST command. 21 | 22 | The command returns true if the expiry was set (changed), and false if the expiry could not be set (changed) due to key 23 | not being present or due to the provided sub-command conditions not being met. The command 24 | supports the following options: 25 | 26 | - NX: Set the expiration only if the key does not already have an expiration time. 27 | - XX: Set the expiration only if the key already has an expiration time. 28 | 29 | 30 | #### Examples 31 | 32 | ``` 33 | 34 | localhost:7379> SET k1 v1 35 | OK 36 | localhost:7379> EXPIRE k1 10 37 | OK true 38 | localhost:7379> SET k2 v2 39 | OK 40 | localhost:7379> EXPIRE k2 10 NX 41 | OK true 42 | localhost:7379> EXPIRE k2 20 XX 43 | OK true 44 | localhost:7379> EXPIRE k2 20 NX 45 | OK false 46 | 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/EXPIREAT.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: EXPIREAT 3 | description: EXPIREAT sets the expiration time of a key as an absolute Unix timestamp (in seconds) 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | EXPIREAT key timestamp [NX | XX | GT | LT] 15 | ``` 16 | 17 | 18 | EXPIREAT sets the expiration time of a key as an absolute Unix timestamp (in seconds). 19 | After the expiry time has elapsed, the key will be automatically deleted. 20 | 21 | > If you want to delete the expiration time on the key, you can use the PERSIST command. 22 | 23 | The command returns true if the expiry was set (changed), and false if the expiry could not be set (changed) due to key 24 | not being present or due to the provided sub-command conditions not being met. The command 25 | supports the following options: 26 | 27 | - NX: Set the expiration only if the key does not already have an expiration time. 28 | - XX: Set the expiration only if the key already has an expiration time. 29 | 30 | 31 | #### Examples 32 | 33 | ``` 34 | 35 | localhost:7379> SET k1 v1 36 | OK 37 | localhost:7379> EXPIREAT k1 1740829942 38 | OK true 39 | localhost:7379> EXPIREAT k1 1740829942 NX 40 | OK false 41 | localhost:7379> EXPIREAT k1 1740829942 XX 42 | OK false 43 | 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/EXPIRETIME.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: EXPIRETIME 3 | description: EXPIRETIME returns the absolute Unix timestamp in seconds at which the given key will expire 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | EXPIRETIME key 15 | ``` 16 | 17 | 18 | EXPIRETIME returns the absolute timestamp in Unix seconds at which the given key will expire. 19 | 20 | The command returns -1 if the key exists but has no associated expiration time. 21 | The command returns -2 if the key does not exist. 22 | 23 | 24 | #### Examples 25 | 26 | ``` 27 | 28 | localhost:7379> SET k1 v1 29 | OK 30 | localhost:7379> EXPIRE k1 10 31 | OK true 32 | localhost:7379> EXPIRETIME k1 33 | OK 1744451192 34 | 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/FLUSHDB.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FLUSHDB 3 | description: FLUSHDB deletes all keys. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | FLUSHDB 15 | ``` 16 | 17 | 18 | FLUSHDB deletes all keys present in the database. 19 | 20 | 21 | #### Examples 22 | 23 | ``` 24 | 25 | localhost:7379> SET k1 v1 26 | OK 27 | localhost:7379> SET k2 v2 28 | OK 29 | localhost:7379> FLUSHDB 30 | OK 31 | localhost:7379> GET k1 32 | OK "" 33 | localhost:7379> GET k2 34 | OK "" 35 | 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/GET.WATCH.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: GET.WATCH 3 | description: GET.WATCH creates a query subscription over the GET command 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | GET.WATCH key 15 | ``` 16 | 17 | 18 | GET.WATCH creates a query subscription over the GET command. The client invoking the command 19 | will receive the output of the GET command (not just the notification) whenever the value against 20 | the key is updated. 21 | 22 | You can update the key in any other client. The GET.WATCH client will receive the updated value. 23 | 24 | 25 | #### Examples 26 | 27 | ``` 28 | 29 | client1:7379> SET k1 v1 30 | OK 31 | client1:7379> GET.WATCH k1 32 | entered the watch mode for GET.WATCH k1 33 | 34 | 35 | client2:7379> SET k1 v2 36 | OK 37 | 38 | 39 | client1:7379> ... 40 | entered the watch mode for GET.WATCH k1 41 | OK [fingerprint=2356444921] "v2" 42 | 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/GET.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: GET 3 | description: GET returns the value as a string for the key in args 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | GET key 15 | ``` 16 | 17 | 18 | GET returns the value as a string for the key in args. 19 | 20 | The command returns an empty string if the key does not exist. 21 | 22 | 23 | #### Examples 24 | 25 | ``` 26 | 27 | localhost:7379> SET k1 v1 28 | OK 29 | localhost:7379> GET k1 30 | OK "v1" 31 | localhost:7379> GET k2 32 | OK "" 33 | 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/GETDEL.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: GETDEL 3 | description: GETDEL returns the value of the key and then deletes the key. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | GETDEL key 15 | ``` 16 | 17 | 18 | GETDEL returns the value of the key and then deletes the key. 19 | 20 | The command returns (nil) if the key does not exist. 21 | 22 | 23 | #### Examples 24 | 25 | ``` 26 | 27 | localhost:7379> SET k v 28 | OK 29 | localhost:7379> GETDEL k 30 | OK "v" 31 | localhost:7379> GET k 32 | OK "" 33 | 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/GETEX.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: GETEX 3 | description: GETEX gets the value of key and optionally set its expiration. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | GETEX key [EX seconds | PX milliseconds] [EXAT timestamp-seconds | PXAT timestamp-milliseconds] [PERSIST] 15 | ``` 16 | 17 | 18 | GETEX gets the value of key and optionally set its expiration. The behavior of the command 19 | is similar to the GET command with the addition of the ability to set an expiration on the key. 20 | 21 | The command returns (nil) if the key does not exist. The command supports the following options: 22 | 23 | - EX seconds: Set the expiration to seconds from now. 24 | - PX milliseconds: Set the expiration to milliseconds from now. 25 | - EXAT timestamp: Set the expiration to a Unix timestamp. 26 | - PXAT timestamp: Set the expiration to a Unix timestamp in milliseconds. 27 | - PERSIST: Remove the expiration from the key. 28 | 29 | 30 | #### Examples 31 | 32 | ``` 33 | 34 | localhost:7379> SET k v 35 | OK 36 | localhost:7379> GETEX k EX 1000 37 | OK "v" 38 | localhost:7379> TTL k 39 | OK 996 40 | localhost:7379> GETEX k PX 200000 41 | OK "v" 42 | localhost:7379> GETEX k EXAT 1772377267 43 | OK "v" 44 | localhost:7379> GETEX k PXAT 1772377267000 45 | OK "v" 46 | localhost:7379> GETEX k PERSIST 47 | OK "v" 48 | localhost:7379> EXPIRETIME k 49 | OK -1 50 | 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/GETSET.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: GETSET 3 | description: GETSET sets the value for the key and returns the old value 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | GETSET key value 15 | ``` 16 | 17 | 18 | GETSET sets the value for the key and returns the old value. 19 | 20 | The command returns "" if the key does not exist. 21 | 22 | 23 | #### Examples 24 | 25 | ``` 26 | 27 | localhost:7379> SET k1 v1 28 | OK 29 | localhost:7379> GETSET k1 v2 30 | OK "v1" 31 | localhost:7379> GET k1 32 | OK "v2" 33 | 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/HANDSHAKE.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: HANDSHAKE 3 | description: HANDSHAKE tells the server the purpose of the connection 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | HANDSHAKE client_id execution_mode 15 | ``` 16 | 17 | 18 | HANDSHAKE is used to tell the DiceDB server the purpose of the connection. It 19 | registers the client_id and execution_mode. 20 | 21 | The client_id is a unique identifier for the client. It can be any string, typically 22 | a UUID. 23 | 24 | The execution_mode is the mode of the connection, it can be one of the following: 25 | 26 | 1. "command" - The client will send commands to the server and receive responses. 27 | 2. "watch" - The connection in the watch mode will be used to receive the responses of query subscriptions. 28 | 29 | If you use DiceDB SDK or CLI then this HANDSHAKE command is automatically sent when the connection is established 30 | or when you establish a subscription. 31 | 32 | 33 | #### Examples 34 | 35 | ``` 36 | 37 | localhost:7379> HANDSHAKE 4c9d0411-6b28-4ee5-b78a-e7e258afa52f command 38 | OK 39 | 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/HGET.WATCH.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: HGET.WATCH 3 | description: HGET.WATCH creates a query subscription over the HGET command 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | HGET.WATCH key field 15 | ``` 16 | 17 | 18 | HGET.WATCH creates a query subscription over the HGET command. The client invoking the command 19 | will receive the output of the HGET command (not just the notification) whenever the value against 20 | the key and field is updated. 21 | 22 | You can update the key in any other client. The HGET.WATCH client will receive the updated value. 23 | 24 | 25 | #### Examples 26 | 27 | ``` 28 | 29 | client1:7379> HSET k1 f1 v1 30 | OK 1 31 | client1:7379> HGET.WATCH k1 f1 32 | entered the watch mode for HGET.WATCH k1 f1 33 | 34 | 35 | client2:7379> HSET k1 f1 v2 36 | OK 0 37 | 38 | 39 | client1:7379> ... 40 | entered the watch mode for HGET.WATCH k1 f1 41 | OK [fingerprint=3432795955] "v2" 42 | 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/HGET.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: HGET 3 | description: HGET returns the value of field present in the string-string map held at key. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | HGET key field 15 | ``` 16 | 17 | 18 | HGET returns the value of field present in the string-string map held at key. 19 | 20 | The command returns empty string "" if the key or field does not exist. 21 | 22 | 23 | #### Examples 24 | 25 | ``` 26 | 27 | localhost:7379> HSET k1 f1 v1 28 | OK 1 29 | localhost:7379> HGET k1 f1 30 | OK "v1" 31 | localhost:7379> HGET k2 f1 32 | OK "" 33 | localhost:7379> HGET k1 f2 34 | OK "" 35 | 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/HGETALL.WATCH.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: HGETALL.WATCH 3 | description: HGETALL.WATCH creates a query subscription over the HGETALL command 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | HGETALL.WATCH key 15 | ``` 16 | 17 | 18 | HGETALL.WATCH creates a query subscription over the HGETALL command. The client invoking the command 19 | will receive the output of the HGETALL command (not just the notification) whenever the value against 20 | the key is updated. 21 | 22 | You can update the key in any other client. The HGETALL.WATCH client will receive the updated value. 23 | 24 | 25 | #### Examples 26 | 27 | ``` 28 | 29 | client1:7379> HSET k f1 v1 30 | OK 1 31 | client1:7379> HGETALL.WATCH k 32 | entered the watch mode for HGETALL.WATCH k 33 | 34 | 35 | client2:7379> HSET k f2 v2 36 | OK 1 37 | 38 | 39 | client1:7379> ... 40 | entered the watch mode for HGETALL.WATCH k 41 | OK [fingerprint=4237011426] 42 | 0) f1="v1" 43 | 1) f2="v2" 44 | 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/HGETALL.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: HGETALL 3 | description: HGETALL returns all the field-value pairs from the string-string map stored at key 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | HGETALL key 15 | ``` 16 | 17 | 18 | HGETALL returns all the field-value pairs (we call it HElements) from the string-string map stored at key. 19 | 20 | The command returns empty list if the key does not exist or the map is empty. Note that the order of the elements is not guaranteed. 21 | 22 | 23 | #### Examples 24 | 25 | ``` 26 | 27 | localhost:7379> HSET k1 f1 v1 f2 v2 f3 v3 28 | OK 3 29 | localhost:7379> HGETALL k1 30 | OK 31 | 0) f1="v1" 32 | 1) f2="v2" 33 | 2) f3="v3" 34 | localhost:7379> HGETALL k2 35 | OK 36 | 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/HSET.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: HSET 3 | description: HSET sets field value in the string-string map stored at key 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | HSET key field value [field value ...] 15 | ``` 16 | 17 | 18 | HSET sets the field and value for the key in the string-string map. 19 | 20 | The command returns the number of fields that were added. 21 | 22 | 23 | #### Examples 24 | 25 | ``` 26 | 27 | localhost:7379> HSET k1 f1 v1 28 | OK 1 29 | localhost:7379> HSET k1 f1 v1 f2 v2 f3 v3 30 | OK 2 31 | 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/INCR.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: INCR 3 | description: INCR increments the value of the specified key in args by 1 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | INCR key 15 | ``` 16 | 17 | 18 | INCR increments the integer at 'key' by one. Creates 'key' as 1 if absent. 19 | The command raises an error if the value is a non-integer. 20 | 21 | Returns the new value of 'key' on success. 22 | 23 | 24 | #### Examples 25 | 26 | ``` 27 | 28 | localhost:7379> SET k 43 29 | OK 30 | localhost:7379> INCR k 31 | OK 44 32 | localhost:7379> INCR k2 33 | OK 1 34 | localhost:7379> GET k2 35 | OK "1" 36 | 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/INCRBY.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: INCRBY 3 | description: INCRBY increments the specified key by the specified delta 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | INCRBY key delta 15 | ``` 16 | 17 | 18 | INCRBY command increments the integer at 'key' by the delta specified. Creates 'key' with value (delta) if absent. 19 | The command raises an error if the value is a non-integer. 20 | 21 | Returns the new value of 'key' on success. 22 | 23 | 24 | #### Examples 25 | 26 | ``` 27 | 28 | localhost:7379> SET k 43 29 | OK 30 | localhost:7379> INCRBY k 10 31 | OK 53 32 | localhost:7379> INCRBY k2 50 33 | OK 50 34 | localhost:7379> GET k2 35 | OK "50" 36 | 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/KEYS.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: KEYS 3 | description: KEYS returns all keys matching the pattern 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | KEYS pattern 15 | ``` 16 | 17 | 18 | KEYS returns all keys matching the pattern. 19 | 20 | The pattern can contain the following special characters to match multiple keys. 21 | Supports glob-style patterns: 22 | - *: matches any sequence of characters 23 | - ?: matches any single character 24 | 25 | #### Examples 26 | 27 | ``` 28 | 29 | localhost:7379> SET k1 v1 30 | OK 31 | localhost:7379> SET k2 v2 32 | OK 33 | localhost:7379> SET k33 v33 34 | OK 35 | localhost:7379> KEYS k? 36 | OK 37 | 0) k1 38 | 1) k2 39 | localhost:7379> KEYS k* 40 | OK 41 | 0) k1 42 | 1) k2 43 | 2) k33 44 | localhost:7379> KEYS * 45 | OK 46 | 0) k1 47 | 1) k2 48 | 2) k33 49 | 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/PING.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: PING 3 | description: PING returns PONG if no argument is provided, otherwise it returns PONG with the message. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | PING 15 | ``` 16 | 17 | 18 | PING returns PONG if no argument is provided, otherwise it returns PONG with the message argument. 19 | 20 | 21 | #### Examples 22 | 23 | ``` 24 | 25 | localhost:7379> PING 26 | OK "PONG" 27 | localhost:7379> PING dicedb 28 | OK "PONG dicedb" 29 | 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/SET.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SET 3 | description: SET puts or updates an existing value for a key 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | SET key value [EX seconds | PX milliseconds] [EXAT timestamp | PXAT timestamp] [XX | NX] [KEEPTTL] 15 | ``` 16 | 17 | 18 | SET puts or updates an existing value for a key. 19 | 20 | SET stores the value as its native type - be it int or string. SET supports the following options: 21 | 22 | - EX seconds: set the expiration time in seconds 23 | - PX milliseconds: set the expiration time in milliseconds 24 | - EXAT timestamp: set the expiration time in seconds since epoch 25 | - PXAT timestamp: set the expiration time in milliseconds since epoch 26 | - XX: only set the key if it already exists 27 | - NX: only set the key if it does not already exist 28 | - KEEPTTL: keep the existing TTL of the key even if some expiration param like EX, etc is provided 29 | 30 | Returns "OK" if the SET operation was successful. 31 | 32 | 33 | #### Examples 34 | 35 | ``` 36 | 37 | localhost:7379> SET k 43 38 | OK 39 | localhost:7379> SET k 43 EX 10 40 | OK 41 | localhost:7379> SET k 43 PX 10000 42 | OK 43 | localhost:7379> SET k 43 EXAT 1772377267 44 | OK 45 | localhost:7379> SET k 43 PXAT 1772377267000 46 | OK 47 | localhost:7379> SET k 43 XX 48 | OK 49 | localhost:7379> SET k 43 NX 50 | OK 51 | localhost:7379> SET k 43 KEEPTTL 52 | OK 53 | 54 | ``` 55 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/TTL.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: TTL 3 | description: TTL returns the remaining time to live in seconds 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | TTL key 15 | ``` 16 | 17 | 18 | TTL returns the remaining time to live (in seconds) of a key that has an expiration set. 19 | 20 | - Returns -1 if the key has no expiration. 21 | - Returns -2 if the key does not exist. 22 | 23 | 24 | #### Examples 25 | 26 | ``` 27 | 28 | localhost:7379> SET k 43 29 | OK 30 | localhost:7379> TTL k 31 | OK -1 32 | localhost:7379> SET k 43 EX 10 33 | OK 34 | localhost:7379> TTL k 35 | OK 8 36 | localhost:7379> TTL kn 37 | OK -2 38 | 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/TYPE.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: TYPE 3 | description: TYPE returns the type of the value stored at a specified key 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | TYPE key 15 | ``` 16 | 17 | 18 | TYPE returns the type of the value stored at a specified key. The type can be one of the following: 19 | 20 | - string 21 | - int 22 | 23 | Returns "none" if the key does not exist. 24 | 25 | 26 | #### Examples 27 | 28 | ``` 29 | 30 | localhost:7379> SET k 43 31 | OK 32 | localhost:7379> TYPE k 33 | OK int 34 | localhost:7379> TYPE kn 35 | OK none 36 | 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/UNWATCH.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: UNWATCH 3 | description: UNWATCH removes the previously created query subscription 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | UNWATCH 15 | ``` 16 | 17 | 18 | WATCH command creates a subscription to the key and returns a fingerprint. Use this fingerprint to UNWATCH the subscription. 19 | After running the UNWATCH command, the subscription will be removed and the data changes will no longer be sent to the client. 20 | 21 | Note: If you are using the DiceDB CLI, then you need not run this command given the REPL will implicitly run this command when 22 | you exit the watch mode. 23 | 24 | 25 | #### Examples 26 | 27 | ``` 28 | 29 | localhost:7379> UNWATCH 2356444921 30 | OK 31 | 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZADD.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZADD 3 | description: ZADD adds all the specified members with the specified scores to the sorted set stored at key 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member...] 15 | ``` 16 | 17 | 18 | ZADD adds all the specified members with the specified scores to the sorted set stored at key. 19 | 20 | The score of the member should be an integer and two members can have the same score. Here are the options supported by the command: 21 | 22 | - NX: Only add new elements and do not update existing elements 23 | - XX: Only update existing elements and do not add new elements 24 | - GT: Only add new elements if the score is greater than the existing score 25 | - LT: Only add new elements if the score is less than the existing score 26 | - CH: Modify the return value from the number of new elements added to the total number of elements changed 27 | - INCR: When this option is specified, the scores provided are treated as increments to the score of the existing elements 28 | 29 | The command by default returns the number of elements added to the sorted set. 30 | 31 | 32 | #### Examples 33 | 34 | ``` 35 | 36 | localhost:7379> ZADD users 10 u1 37 | OK 1 38 | localhost:7379> ZADD users 5 u2 39 | OK 1 40 | localhost:7379> ZADD users 15 u3 41 | OK 1 42 | localhost:7379> ZADD users 12 u4 43 | OK 1 44 | localhost:7379> ZADD users 10 u1 45 | OK 0 46 | localhost:7379> ZADD users CH 11 u1 47 | OK 1 48 | 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZCARD.WATCH.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZCARD.WATCH 3 | description: ZCARD.WATCH creates a query subscription over the ZCARD command 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZCARD.WATCH key 15 | ``` 16 | 17 | 18 | ZCARD.WATCH creates a query subscription over the ZCARD command. The client invoking the command 19 | will receive the output of the ZCARD command (not just the notification) whenever the value against 20 | the key is updated. 21 | 22 | You can update the key in any other client. The ZCARD.WATCH client will receive the updated value. 23 | 24 | 25 | #### Examples 26 | 27 | ``` 28 | 29 | client1:7379> ZADD users 1 alice 2 bob 3 charlie 30 | OK 3 31 | client1:7379> ZCARD.WATCH users 32 | entered the watch mode for ZCARD.WATCH users 33 | 34 | 35 | client2:7379> ZADD users 4 daniel 36 | OK 1 37 | 38 | 39 | client1:7379> ... 40 | entered the watch mode for ZCARD.WATCH users 41 | OK [fingerprint=8372868704969517043] 4 42 | 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZCARD.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZCARD 3 | description: ZCARD returns the cardinality of the sorted set stored at key. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZCARD key 15 | ``` 16 | 17 | 18 | ZCARD returns the cardinality of the sorted set stored at key. 19 | 20 | The command returns 0 if key does not exist. 21 | 22 | 23 | #### Examples 24 | 25 | ``` 26 | 27 | locahost:7379> ZADD users 1 alice 2 bob 3 charlie 28 | OK 3 29 | locahost:7379> ZCARD users 30 | OK 3 31 | localhost:7379> ZCARD nonexistent_key 32 | OK 0 33 | 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZCOUNT.WATCH.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZCOUNT.WATCH 3 | description: ZCOUNT.WATCH creates a query subscription over the ZCOUNT command 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZCOUNT.WATCH key min max 15 | ``` 16 | 17 | 18 | ZCOUNT.WATCH creates a query subscription over the ZCOUNT command. The client invoking the command 19 | will receive the output of the ZCOUNT command (not just the notification) whenever the value against 20 | the key is updated. 21 | 22 | You can update the key in any other client. The ZCOUNT.WATCH client will receive the updated value. 23 | 24 | 25 | #### Examples 26 | 27 | ``` 28 | 29 | client1:7379> ZADD users 1 alice 2 bob 3 charlie 30 | OK 3 31 | client1:7379> ZCOUNT.WATCH users 1 5 32 | entered the watch mode for ZCOUNT.WATCH users 33 | 34 | 35 | client2:7379> ZADD users 4 daniel 36 | OK 1 37 | 38 | 39 | client1:7379> ... 40 | entered the watch mode for ZCOUNT.WATCH users 41 | OK [fingerprint=7042915837159566899] 4 42 | 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZCOUNT.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZCOUNT 3 | description: ZCOUNT counts the number of members in a sorted set between min and max (both inclusive) 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZCOUNT key min max 15 | ``` 16 | 17 | 18 | ZCOUNT counts the number of members in a sorted set between min and max (both inclusive) 19 | 20 | If you want to use unbounded ranges, use -inf and +inf for min and max respectively. 21 | The command returns the count of members in a sorted set between min and max (both inclusive). Returns 0 if the key does not exist. 22 | 23 | 24 | #### Examples 25 | 26 | ``` 27 | 28 | localhost:7379> ZADD k 10 k1 29 | OK 1 30 | localhost:7379> ZADD k 20 k2 31 | OK 1 32 | localhost:7379> ZADD k 30 k3 33 | OK 1 34 | localhost:7379> ZCOUNT k 10 20 35 | OK 2 36 | localhost:7379> ZCOUNT k 10 30 37 | OK 3 38 | localhost:7379> ZCOUNT k 10 40 39 | OK 3 40 | localhost:7379> ZCOUNT k 1 2 41 | OK 0 42 | localhost:7379> ZCOUNT k -inf +inf 43 | OK 3 44 | localhost:7379> ZCOUNT k 10 10 45 | OK 1 46 | 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZPOPMAX.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZPOPMAX 3 | description: ZPOPMAX removes and returns the member with the highest score from the sorted set at the specified key. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZPOPMAX key [count] 15 | ``` 16 | 17 | 18 | ZPOPMAX removes and returns the member with the highest score from the sorted set at the specified key. 19 | 20 | If the key does not exist, the command returns empty list. An optional "count" argument can be provided 21 | to remove and return multiple members (up to the number specified). 22 | 23 | When popped, the elements are returned in descending order of score and you get the rank of the element in the sorted set. 24 | The rank is 1-based, which means that the first element is at rank 1 and not rank 0. 25 | The 1), 2), 3), ... is the rank of the element in the sorted set. 26 | 27 | 28 | #### Examples 29 | 30 | ``` 31 | 32 | localhost:7379> ZADD users 10 alice 20 bob 30 charlie 33 | OK 3 34 | localhost:7379> ZPOPMAX users 35 | OK 36 | 3) 30, charlie 37 | localhost:7379> ZPOPMAX users 10 38 | OK 39 | 2) 20, bob 40 | 1) 10, alice 41 | 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZPOPMIN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZPOPMIN 3 | description: ZPOPMIN removes and returns the member with the lowest score from the sorted set at the specified key. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZPOPMIN key [count] 15 | ``` 16 | 17 | 18 | ZPOPMIN removes and returns the member with the lowest score from the sorted set at the specified key. 19 | 20 | If the key does not exist, the command returns empty list. An optional "count" argument can be provided 21 | to remove and return multiple members (up to the number specified). 22 | 23 | When popped, the elements are returned in ascending order of score and you get the rank of the element in the sorted set. 24 | The rank is 1-based, which means that the first element is at rank 1 and not rank 0. 25 | The 1), 2), 3), ... is the rank of the element in the sorted set. 26 | 27 | 28 | #### Examples 29 | 30 | ``` 31 | 32 | localhost:7379> ZADD users 10 alice 20 bob 30 charlie 33 | OK 3 34 | localhost:7379> ZPOPMIN users 35 | OK 36 | 1) 10, alice 37 | localhost:7379> ZPOPMIN users 10 38 | OK 39 | 1) 20, bob 40 | 2) 30, charlie 41 | 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZRANGE.WATCH.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZRANGE.WATCH 3 | description: ZRANGE.WATCH creates a query subscription over the ZRANGE command 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZRANGE.WATCH key start stop [BYSCORE | BYRANK] 15 | ``` 16 | 17 | 18 | ZRANGE.WATCH creates a query subscription over the ZRANGE command. The client invoking the command 19 | will receive the output of the ZRANGE command (not just the notification) whenever the value against 20 | the key is updated. 21 | 22 | You can update the key in any other client. The ZRANGE.WATCH client will receive the updated value. 23 | 24 | 25 | #### Examples 26 | 27 | ``` 28 | 29 | client1:7379> ZADD users 10 alice 20 bob 30 charlie 30 | OK 3 31 | client1:7379> ZRANGE.WATCH users 1 5 32 | entered the watch mode for ZRANGE.WATCH users 33 | 34 | 35 | client2:7379> ZADD users 40 daniel 36 | OK 1 37 | 38 | 39 | client1:7379> ... 40 | entered the watch mode for ZRANGE.WATCH users 41 | OK [fingerprint=1007898011883907067] 42 | 1) 10, alice 43 | 2) 20, bob 44 | 3) 30, charlie 45 | 4) 40, daniel 46 | 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZRANGE.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZRANGE 3 | description: ZRANGE returns the range of elements from the sorted set stored at key. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZRANGE key start stop [BYSCORE | BYRANK] 15 | ``` 16 | 17 | 18 | ZRANGE returns the range of elements from the sorted set stored at key. 19 | 20 | The default range is by rank "BYRANK" and this can be changed to "BYSCORE" if you want to range by score spanning the start and stop values. 21 | The rank is 1-based, which means that the first element is at rank 1 and not rank 0. 22 | The 1), 2), 3), ... is the rank of the element in the sorted set. 23 | 24 | Both the start and stop values are inclusive and hence the elements having either of the values will be included. The 25 | elements are considered to be ordered from the lowest to the highest. If you want reverse order, consider 26 | storing score with flipped sign. 27 | 28 | #### Examples 29 | 30 | ``` 31 | 32 | localhost:7379> ZADD s 10 a 20 b 30 c 40 d 50 e 33 | OK 5 34 | localhost:7379> ZRANGE s 1 3 35 | OK 36 | 1) 10, a 37 | 2) 20, b 38 | 3) 30, c 39 | localhost:7379> ZRANGE s 1 4 BYRANK 40 | OK 41 | 1) 10, a 42 | 2) 20, b 43 | 3) 30, c 44 | 4) 40, d 45 | localhost:7379> ZRANGE s 1 3 BYSCORE 46 | OK 47 | localhost:7379> ZRANGE s 30 100 BYSCORE 48 | OK 49 | 3) 30, c 50 | 4) 40, d 51 | 5) 50, e 52 | 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZRANK.WATCH.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZRANK.WATCH 3 | description: ZRANK.WATCH creates a query subscription over the ZRANK command 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZRANK.WATCH key 15 | ``` 16 | 17 | 18 | ZRANK.WATCH creates a query subscription over the ZRANK command. The client invoking the command 19 | will receive the output of the ZRANK command (not just the notification) whenever the value against 20 | the key is updated. 21 | 22 | You can update the key in any other client. The ZRANK.WATCH client will receive the updated value. 23 | 24 | 25 | #### Examples 26 | 27 | ``` 28 | 29 | client1:7379> ZADD users 10 alice 20 bob 30 charlie 30 | OK 3 31 | client1:7379> ZRANK.WATCH users bob 32 | entered the watch mode for ZRANK.WATCH users 33 | 34 | 35 | client2:7379> ZADD users 10 bob 36 | OK 0 37 | client2:7379> ZADD users 100 alice 38 | OK 0 39 | 40 | 41 | client1:7379> ... 42 | entered the watch mode for ZRANK.WATCH users 43 | OK [fingerprint=3262833422269415227] 2) 10, bob 44 | OK [fingerprint=3262833422269415227] 1) 10, bob 45 | 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZRANK.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZRANK 3 | description: ZRANK returns the rank of a member in a sorted set, ordered from low to high scores. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZRANK key member 15 | ``` 16 | 17 | 18 | ZRANK returns the rank of a member in a sorted set, ordered from low to high scores. 19 | 20 | The rank is 1-based which means that the member with the lowest score has rank 1, the next highest has rank 2, and so on. 21 | The command returns the element - rank, score, and memeber. 22 | 23 | Thus, 1), 2), 3) are the rank of the element in the sorted set, followed by the score and the member. 24 | 25 | The the member passed as the second argument is not a member of the sorted set, the command returns a 26 | valid response with a rank of 0 and score of 0. If the key does not exist, the command returns a 27 | valid response with a rank of 0, score of 0, and the member as "". 28 | 29 | 30 | #### Examples 31 | 32 | ``` 33 | 34 | localhost:7379> ZADD users 10 alice 20 bob 30 charlie 35 | OK 3 36 | localhost:7379> ZRANK users bob 37 | OK 2) 20, bob 38 | localhost:7379> ZRANK users charlie 39 | OK 3) 30, charlie 40 | localhost:7379> ZRANK users daniel 41 | OK 0) 0, daniel 42 | 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/src/content/docs/commands/ZREM.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ZREM 3 | description: Removes the specified members by key from the sorted set. 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | ZREM key member [member ...] 15 | ``` 16 | 17 | 18 | Removes the specified members by key from the sorted set. Non existing members are ignored. 19 | 20 | Returns the number of members removed from the sorted set. 21 | 22 | 23 | #### Examples 24 | 25 | ``` 26 | 27 | localhost:7379> ZADD users 10 alice 20 bob 30 charlie 28 | OK 3 29 | localhost:7379> ZRANGE users 0 60 BYSCORE 30 | OK 31 | 1) 10, alice 32 | 2) 20, bob 33 | 3) 30, charlie 34 | localhost:7379> ZREM users alice bob 35 | OK 2 36 | localhost:7379> ZRANGE users 0 60 BYSCORE 37 | OK 38 | 1) 30, charlie 39 | 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/src/content/docs/get-started/installation.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | description: Steps to install DiceDB and get started with it. 4 | sidebar: 5 | order: 1 6 | --- 7 | 8 | ### What is DiceDB? 9 | 10 | DiceDB is an open-source, fast, reactive, in-memory database optimized for modern hardware. 11 | Commonly used as a cache, it offers a familiar interface while enabling real-time data 12 | updates through query subscriptions. It delivers higher throughput and lower median latencies, 13 | making it ideal for modern workloads. 14 | 15 | We support multiple ways to install DiceDB, one of which is using Docker and the other is building from source. 16 | Both of these methods can be found [here](https://github.com/DiceDB/dice/blob/master/README.md). 17 | 18 | To work with DiceDB from a command line interface, you can use the [DiceDB CLI](https://github.com/DiceDB/dicedb-cli) 19 | and the installation instructions can be found [here](https://github.com/DiceDB/dicedb-cli/blob/master/README.md). 20 | 21 | Once everything is installed, you are all set for a [Hello, World example](/get-started/hello-world/). 22 | -------------------------------------------------------------------------------- /docs/src/content/docs/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: DiceDB 3 | description: DiceDB is an open source, reactive, scalable, highly available, unified cache optimized for modern hardware. 4 | template: splash 5 | hero: 6 | tagline: an open source, reactive, scalable, highly available, unified cache optimized for modern hardware. 7 | image: 8 | file: ../../../public/icon.png 9 | actions: 10 | - text: Get started 11 | link: /get-started/installation 12 | icon: right-arrow 13 | variant: primary 14 | --- 15 | -------------------------------------------------------------------------------- /docs/src/content/docs/sdk/go.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Go 3 | description: A Golang SDK for DiceDB 4 | --- 5 | 6 | The [DiceDB Go SDK](https://github.com/dicedb/dicedb-go) is the official Go client for DiceDB. 7 | 8 | > Make sure that the DiceDB server is running before you start using the SDK 9 | > and following this guide. 10 | 11 | ## Installation 12 | 13 | To install the DiceDB Go SDK, use `go get`: 14 | 15 | ```bash 16 | go get github.com/dicedb/dicedb-go@v1.0.9 17 | ``` 18 | 19 | ## Hello World 20 | 21 | A simple "Hello, World!" example to get you started with the DiceDB Go SDK, 22 | can be found in the [examples/hello-world-go](https://github.com/dicedb/dice/tree/master/examples/hello-world-go) directory. 23 | 24 | Follow the instructions in the README to run the example. 25 | -------------------------------------------------------------------------------- /docs/src/content/team/apoorv.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Apoorv Yadav", 3 | "avatar_url": "https://avatars.githubusercontent.com/u/32174554?v=4", 4 | "url": "", 5 | "x": "", 6 | "linkedin": "https://www.linkedin.com/in/yadavapoorv/", 7 | "github": "https://github.com/apoorvyadav1111", 8 | "website": "", 9 | "roles": ["committer"] 10 | } 11 | -------------------------------------------------------------------------------- /docs/src/content/team/arpit.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Arpit Bhayani", 3 | "avatar_url": "https://edge.arpitbhayani.me/img/arpit-2.png", 4 | "url": "https://arpitbhayani.me/", 5 | "x": "https://x.com/arpit_bhayani", 6 | "linkedin": "https://linkedin.com/in/arpitbhayani", 7 | "github": "https://github.com/arpitbbhayani", 8 | "website": "https://arpitbhayani.me/", 9 | "roles": ["pmc"] 10 | } 11 | -------------------------------------------------------------------------------- /docs/src/content/team/ashwin.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Ashwin Kulkarni", 3 | "avatar_url": "https://avatars.githubusercontent.com/u/19169648?v=4", 4 | "url": "", 5 | "x": "https://x.com/ashwinkulkarni4", 6 | "linkedin": "https://www.linkedin.com/in/iashwin28/", 7 | "github": "https://github.com/AshwinKul28", 8 | "website": "", 9 | "roles": ["pmc"] 10 | } 11 | -------------------------------------------------------------------------------- /docs/src/content/team/jyotinder.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Jyotinder Singh", 3 | "avatar_url": "https://avatars.githubusercontent.com/u/33001894?v=4", 4 | "url": "https://jyotindersingh.com/", 5 | "x": "https://x.com/Jyotinder_Singh", 6 | "linkedin": "https://linkedin.com/in/jyotinder-singh", 7 | "github": "https://github.com/JyotinderSingh", 8 | "website": "https://jyotindersingh.com/", 9 | "roles": ["pmc"] 10 | } 11 | -------------------------------------------------------------------------------- /docs/src/content/team/prashant.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Prashant Shubham", 3 | "avatar_url": "https://avatars.githubusercontent.com/u/13472823?v=4", 4 | "url": "https://prasha.me", 5 | "x": "https://x.com/prashacr7", 6 | "linkedin": "https://www.linkedin.com/in/prashant-shubham07", 7 | "github": "https://github.com/lucifercr07", 8 | "website": "https://prasha.me", 9 | "roles": ["pmc"] 10 | } 11 | -------------------------------------------------------------------------------- /docs/src/content/team/prateek.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Prateek Rathore", 3 | "avatar_url": "https://avatars.githubusercontent.com/u/25244718?v=4", 4 | "url": "", 5 | "x": "https://twitter.com/psrvere", 6 | "linkedin": "https://www.linkedin.com/in/prateek-singh-rathore/", 7 | "github": "https://github.com/psrvere", 8 | "website": "", 9 | "roles": ["committer"] 10 | } 11 | -------------------------------------------------------------------------------- /docs/src/content/team/soumya.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Soumya Panigrahi", 3 | "avatar_url": "https://avatars.githubusercontent.com/u/151079203?v=4", 4 | "url": "", 5 | "x": "https://x.com/soumyapanigrahi", 6 | "linkedin": "https://www.linkedin.com/in/soumya-panigrahi-8038118/", 7 | "github": "https://github.com/soumya-codes", 8 | "website": "", 9 | "roles": ["pmc"] 10 | } 11 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-07-18.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | Agenda: 5 | 6 | - First community call 🎉 7 | - The documentation website is up: [https://dicedb-docs.netlify.app/](https://dicedb-docs.netlify.app/) 8 | - Aim to support a basic, foundational feature set 9 | - Plans for real-time reactivity: 10 | - Support for JSON 11 | - Filtering on JSON fields 12 | - Optimizations for DSQL query executor: 13 | - Instead of re.match use a specific regex matcher for better performance. 14 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-08-01.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | Agenda: 5 | 6 | - Updates from Arpit 7 | - Design discussion around multi-threaded architecture for Dice being implemented by Yash 8 | - JSON integration with QWATCH 9 | - Add JSON support to the executor to filter on JSON fields using JSONPath syntax. 10 | - JSON-to-JSON comparisons in WHERE clause? 11 | - Research from Cockroach labs on Json libs \- [https://www.cockroachlabs.com/blog/high-performance-json-parsing/](https://www.cockroachlabs.com/blog/high-performance-json-parsing/) 12 | 13 | ## Jul 25, 2024 | [DiceDB Weekly Community Call](https://www.google.com/calendar/event?eid=M2Judmhnb2E0YnFsY2d0NWUwMDBhdnZjbmUgYXJwaXQubWFzdGVyY2xhc3NAbQ) 14 | 15 | Agenda: 16 | 17 | - Jyotinder to check for absolute essentials for Realtime Reactivity 18 | - Crips documentation around the DSQL capabilities as of today 19 | - JSON support for JSONPath and partial updates 20 | - Yash to discuss multi-threaded implementation 21 | - ByteArray divergence \- BITX commands for ByteArray type 22 | - String and ByteArray implementation will have different performance 23 | - Make sure this is documented 24 | - Arpit to write documentation around \`SET\` and \`GET\` command in docs repository. 25 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-08-08.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | Shipped 🚀 5 | 6 | - Command Enhancements: 7 | - KEYS command implementation 8 | - SET command enhancements 9 | - COMMAND GETKEYS command added 10 | - MSET command implementation 11 | - JSON Support: 12 | - JSON.SET and JSON.GET commands 13 | - JSONPath support for querying JSON data 14 | - AUTH command 15 | - BIT commands 16 | - Performance and Stability: 17 | - Fixed server reconnection issues 18 | - Key Expiry fixes 19 | - Executor Benchmarks added 20 | - Thread safety improvements for dencoding 21 | - Data Handling: 22 | - RESP parsing fix for handling RESP_NIL in BulkString 23 | - Signed integer dencoding support 24 | - Development and Testing: 25 | - Test improvements 26 | - Live Reloading on dev server 27 | 28 | Agenda: 29 | 30 | - soumya: Do we need to support range queries? 31 | - gaurav897: _Do we have a good monitoring/metrics/logging story around DiceDB? Given that we are early in the project, should we start proactively on this?_ 32 | - Prometheus 33 | - opentelemetry 34 | - Executor performance 35 | - [https://discord.com/channels/1034342738960855120/1264145943884992595/1269314643298488370](https://discord.com/channels/1034342738960855120/1264145943884992595/1269314643298488370) 36 | - Integration test setup? 37 | 38 | Action Items 39 | 40 | - Memtier 41 | - SQL equivalence 42 | - JSON where clause support 43 | - dice-cli stability with QWATCH 44 | - Python-sdk 45 | - Java-sdk 46 | - Js-sdk 47 | - Stripped locking 48 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-08-15.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | Shipped 5 | 6 | - Commands: 7 | - TOUCH and OBJECT IDLETIME 8 | - KEEPTTL option for SET command 9 | - COPY command 10 | - PTTL command 11 | - GETEX command 12 | - GETDEL command 13 | - RENAME command 14 | - MGET command 15 | - DECRBY command 16 | - EXISTS command 17 | - DECR command 18 | - Fixes 19 | - Fixed atomicity issue in GetAll() function 20 | - Improved atomicity of Get() function 21 | - Simplified AUTH flow 22 | - Fixed failing TestJSONSetWithInvalidJSON 23 | - Fixed issue with emitting watchEvent from DelByPointer 24 | - Testing and code quality: 25 | - Added script to plot executor benchmark results 26 | - Added various new test cases: 27 | - For DEL command 28 | - For DISCARD command 29 | - For expired keys in StackRef.Pop() method 30 | - Additional unit tests for eval.go file 31 | - Introduced golangci linter to improve code quality 32 | - Improved queueref benchmark 33 | 34 | ## Discussion 35 | 36 | - Consensus on consistency - Do we need locks, readers-writers block, etc. 37 | - Blocking operations 38 | - Gaurav and Soumya to explain their reasoning 39 | 40 | ## Action Items 41 | 42 | - New In memory shard for serving watch queries. 43 | - Make target for linting 44 | - Sleep Timer stub 45 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-08-19.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | Discussed: 5 | 6 | Separation of Concerns: 7 | 8 | - Commands like MGET/MSET - Key used across shards, 9 | - Similar for Qwatch - when we are watching a pattern, the pattern can exist across multiple shards. 10 | - Transactional commands like MGET/MSET - We need an abstraction layer outside shards that can manage the transaction across teh shards. 11 | 12 | IOLayer - Should it wait for all shards to complete the tasks, proceed only after all shards have responded. 13 | 14 | Keep store dumb. All ops on store as atomic as possible. 15 | . Add complexity to IOLayer / Coordinator in future if optimisation are needed in future. 16 | 17 | Next step task 18 | 19 | - Remove locks and provide atomic operations. 20 | - Address review comments and merge Store abstraction refactor Yash 21 | - Watch to move out of store / Or implement a scan operator in store Jyotinder 22 | - Limit Store operations to Put / Get / Delete & Scan Pratik 23 | - We are using unsafe pointer, should we move to empty struct ot interface. Move to generics. Ashwin Kulkarni 24 | - Removing all Mutex from Store after the shards and channels are created for multi threads. soumya 25 | - Skeleton for multithreaded mode Yash 26 | - Extract Coordinator from IO Tasks. Gaurav 27 | - Qwatch: each io thread launches a qwatch command, this fans out to every shard. Each shard now maintains records for which io threads are listening to which queries . Jyotinder 28 | - moar thoughts - the watchlist can be maintained at the said coordinator level 29 | - Fanout commands that require consistency soumya 30 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-08-22.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | ## Changelog 5 | 6 | ### New Commands 7 | 8 | - Support for JSON.TYPE command 9 | - Support for EXPIREAT command 10 | - Support for DBSIZE command 11 | - Support for EXPIRETIME command 12 | - Deque implementation for LPUSH, RPUSH, LPOP, and RPOP commands 13 | - JSON support in WHERE clause for queries 14 | 15 | ### Performance 16 | 17 | - Improved performance of JSON WHERE clause evaluation 18 | - Refactored store abstraction as a prerequisite for multi-threading 19 | 20 | ### Bug Fixes 21 | 22 | - Type deduction logic for integers and related fixes 23 | - RENAME command now fetches the key before renaming 24 | - Fixed QWATCH response format and executor type inference logic 25 | - Fixed type casting logic for SET and GET commands 26 | - Corrected INCR/DECR logic and added tests 27 | - Fixed incorrect benchmark iterations for QueueRef 28 | - Corrected the JSON.SET command Arity 29 | - Standardized error messages across codebase 30 | - Updated AUTH error message to be consistent 31 | - Keep JSON.TYPE consistent 32 | - Fixed flaky tests due to JSON ordering 33 | 34 | ### Testing 35 | 36 | - Added unit and integration tests for EXPIRE and EXPIRETIME commands 37 | - Added stubbed time for tests 38 | - Run complete test suite on PRs 39 | 40 | ### Developer Workflow 41 | 42 | - Added make target for linter 43 | - Updated linter.yml 44 | 45 | ## Discussions 46 | 47 | - [https://github.com/DiceDB/dice/issues/386\#issuecomment-2303968575](https://github.com/DiceDB/dice/issues/386#issuecomment-2303968575) 48 | - Discuss on the current implementation of Keypool and its necessity. 49 | - [https://github.com/DiceDB/dice/issues/386](https://github.com/DiceDB/dice/issues/386) 50 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-08-29.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | ## Changelog 5 | 6 | ### New Commands 7 | 8 | - Implement \`HSET\` command 9 | - Add support for options for EXPIRE and EXPIREAT 10 | - Add support for command \`JSON.CLEAR\` 11 | - Added \`SADD\`, \`SREM\`, \`MEMBERS\`, \`SCARD\`, \`SINTER\`, \`SDIFF\` commands 12 | - Implement \`GETSET\` command 13 | - Added support for \`FLUSHDB\` command 14 | - Add support for \`BITPOS\` command 15 | - Added support for \`QUNWATCH\` command 16 | 17 | ### Bug Fixes 18 | 19 | - Fix: \`STACKREFLEN\` and \`QUEUEREFLEN\` are not aware of the deletion of key 20 | 21 | ### Testing 22 | 23 | - Add asserts checking non-set commands: addresses \#411 24 | - Adds memtier benchmark and load tests preset 25 | 26 | ### General Improvements 27 | 28 | - Move QWATCH logic to QueryWatcher 29 | - Reorganize async server code 30 | - Moved from unsafe pointer to string type for the store 31 | 32 | ## Action Items 33 | 34 | - Hacktoberfest focus 35 | - Docs: Inaccuracies, fixes. 36 | - Testing 37 | - Dice-cli 38 | - Language-specific SDKs 39 | - Windows Support 40 | - Report command inconsistencies 41 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-09-05.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | ## Changelog 5 | 6 | ### New Commands 7 | 8 | 1. Added support for JSON.DEL command 9 | 2. Implemented PFADD/PFCOUNT commands 10 | 3. Added COMMAND LIST command 11 | 4. Added support for HGETALL command 12 | 13 | ### Features 14 | 15 | 1. Implemented caching for QWATCH queries to improve performance 16 | 2. Added JSON support to ORDER BY clause for DSQL queries 17 | 3. Added ShardThread and ShardManager for improved concurrency 18 | 4. Switched the store to use SwissTable instead of HashTable for better performance 19 | 5. Migrated set data structure from built-in go map to swissTable 20 | 21 | ### Bug Fixes 22 | 23 | 1. Fixed integer type handling inconsistencies in SQL executor 24 | 2. Fixed SETBIT command for encoding 25 | 3. Fixed benchmark issue in BenchmarkEvalMSET by resetting store for each iteration 26 | 27 | ### Testing 28 | 29 | 1. Added integration tests for JSON.CLEAR and JSON.DEL commands 30 | 2. Temporarily reverted TCL tests integration in Dice 31 | 32 | ### Other 33 | 34 | 1. Removed query-watcher dependency from store 35 | 2. Updated tests to use new Map implementation 36 | 3. Fixed linting errors in SwissTable implementation 37 | 38 | ## Action Items 39 | 40 | - Allow people to run queries without using cache 41 | - Move set back to hashmap 42 | - Set up a temporary issue for the qwatch leaderboard impl. 43 | - Improve qwatch testing, chaos testing, try to break it. 44 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-09-12.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | ## Changelog 5 | 6 | ### New Commands 7 | 8 | 1. Added support for `JSON.ARRLEN` command 9 | 2. Implemented `HGET` command 10 | 3. Added support for `COMMAND` command 11 | 12 | ### Features 13 | 14 | 1. Improved `ORDER BY` clause handling in SQL parser 15 | 2. Added support for `LIKE` and `NOT LIKE` to the SQL Executor 16 | 3. Added retry with exponential backoff for QWATCH writes 17 | 4. Added support for common cache per fingerprint in QWATCH 18 | 5. Deprecated `FROM` clause in DSQL and moved key filtering to `WHERE` 19 | 6. Added realtime leaderboard demo using QWATCH 20 | 21 | ### Bug Fixes 22 | 23 | 1. Fixed hyperloglog type assertion check 24 | 2. Fixed inconsistent `EXPIRE` with conflicting options: `LT` `GT` 25 | 3. Fixed data race occurring when emitting a WatchEvent 26 | 4. Fixed inconsistent `EXPIRE` when ran with flags `XX`, `LT`\-`XX` and `GT` on a key without ttl 27 | 5. Fixed bitmap commands deviation 28 | 6. Optimized type error return 29 | 30 | ### Testing 31 | 32 | 1. Added TestEnvEnabled config and avoiding AOF dump for test env 33 | 2. Added unit and integration tests for `HGET` command 34 | 35 | ### Other 36 | 37 | 1. Version bump 38 | 2. Notifies Query Manager of key changes asynchronously 39 | 3. Removed locking structures for store 40 | 4. Refactored constants from constants package 41 | 5. Refactored the codebase and moved packages to internal 42 | 6. Removed keypool and related structures from the store 43 | 7. Reverted set data structure to map 44 | 8. Updated README with Leaderboard example 45 | 46 | ## Discussion 47 | 48 | - Stability \+ latencies 49 | - DiceDB exporter, node exporter, prometheus 50 | - TCL test documentation 51 | - Multi-threading progress 52 | - New query fingerprinting logic 53 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-11-07.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | ## DB 5 | 6 | ### New Features 7 | 8 | - Migrate commands `SADD`, `SREM`, `SCARD`, `SMEMBERS` to store_eval. (@sahoss) (\#1020) 9 | - Add support for commands `LINSERT` and `LRANGE`. (@ParvBudh28) (\#659) 10 | - Add integration tests for commands `HSET`, `HGET`, `HDEL`. (@c-harish) (\#1021) 11 | - Migrate `GETEX` and `GETDEL` commands. (@Ehijoe) (\#1061) 12 | - Migrated commands `EXPIRE`, `EXPIREAT`, `EXPIRETIME`, `TTL`, `PTTL`. (@SyedMa3) (\#1149) 13 | - Added `GET.UNWATCH` command support and fixed related issues. (@psr) (\#998) 14 | 15 | ### Enhancements 16 | 17 | - ZPOPMIN command tests enhanced to check outputs with ZCOUNT command. (@teja8551) (\#1225) 18 | - Moved HExists, HKeys, HVals commands in commands folder. (@apoorvyadav1111) (\#1229) 19 | 20 | ### Fixes 21 | 22 | - Fix typo in documentation. (@vinitparekh1742) (\#1240) 23 | - Fix `validateCmdMeta` to handle Unwatch commands. (@jyotindrsingh) 24 | 25 | ### Documentation Updates 26 | 27 | - Revamped documentation with separate sections for Blog, Benchmarks, and Roadmap. (@arpitbhayani) (\#1236) 28 | - Add support for command SELECT documentation. (@vanshavenger) (\#820) 29 | - Add documentation for `LINSERT` and `LRANGE` commands. (@ParvBudh28) (\#1040) 30 | - Release page added with blogs and release notes on the homepage. (@arpitbhayani) 31 | - Lint across docs codebase. (@arpitbhayani) 32 | - Removed memtier benchmark from Docs. (@arpitbhayani) 33 | - Updated benchmark numbers. (@arpitbhayani) 34 | - Made landing page simpler and denser. (@arpitbhayani) 35 | - Code documentation fixes. (@aadi-1024) (\#1232) 36 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-11-14.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | ## DB 5 | 6 | ### New Features 7 | 8 | - Migrated JSON.RESP & JSON.DEBUG commands. (@c-harish) (\#1030) 9 | - Migrated LPUSH, RPUSH, LPOP, RPOP, LLEN commands. (@Aditya-Chowdhary) (\#1019) 10 | - Implemented ZADD options: XX, NX, CH, INCR, LT, GT according (@rushabhk04) (\#761) 11 | - Migrate commands SETBIT, GETBIT, BITCOUNT, BITPOS, BITFIELD, BITFIELD_RO. (@vishnuchandrashekar) (\#1017) 12 | - Added support for PFCOUNT.WATCH command. (@saubhikpandey) (\#1133) 13 | - Command migration for single shard, multi-shard, and custom commands. (@ashwin-kulkarni128, @apoorvyadav1111) (\#1276) 14 | - Refactored eviction framework with Basic LRU-based batch eviction. (@soumya-codes) (\#1268) 15 | - Default WAL set to Null with WAL implementation added. (@arpitbhayani) 16 | 17 | ### Bug Fixes 18 | 19 | - Fixed RESP parser to parse strings with multiple `\r`. (@c-harish) (\#1245) 20 | - Fix LPOP to support multiple arguments. (@tren03) (\#1100) 21 | - Added command metadata for LRANGE. (@shashi-sah2003) (\#1272) 22 | - Enhanced GETRANGE to support byte array. (@c-harish) (\#1194) 23 | - Added type check for string compatibility in evalAPPEND function. (@shashi-sah2003) (\#1193) 24 | 25 | ### Documentation Updates 26 | 27 | - Reactive value proposition added to documentation. (@arpitbhayani) (\#1256) 28 | - Releases page with blogs and release notes on the homepage. (@arpitbhayani) 29 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-12-05.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | ### New Features 5 | 6 | - Bloom Filter and Type Standardization: This PR introduces bloom filter and type standardization to improve performance (@arpitbbhayani) (\#1357) 7 | - Add documentation for SETEX command: Added documentation for the SETEX command, making it easier for users to understand its usage (@tarun-29) (\#1350) 8 | 9 | ### Bug Fixes 10 | 11 | - Fixed build error in bytearray.go: This PR fixes a build error that occurred when building the bytearray package (@piyushhhxyz) (\#1351) 12 | - fix: modify the config default value keep consistency: This PR standardizes the default values of configuration options across the codebase, ensuring consistency and preventing potential issues (@jujiale) (\#1352) 13 | 14 | ### Documentation 15 | 16 | - Add documentation for JSON.OBJLEN command: Created a new page in the documentation for the JSON.OBJLEN command, while also fixing typos on the JSON.OBJKEYS page (@paulwalrath) (\#1345) 17 | - Remove \--enable-multithreading flag usage in README: Removed the reference to the deprecated \`--enable-multithreading\` flag from the README, as it is no longer supported (@rahul-mallick-15) (\#1349) 18 | 19 | ### General Enhancements 20 | 21 | - Remove encoding and supporting only Type: This PR removes unused encoding code and supports only type (@arpitbbhayani) (\#1341) 22 | -------------------------------------------------------------------------------- /docs/src/content/updates/2024-12-19.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | ## New Features: 5 | 6 | - Added test cases for zset data type (@pankajjs) (#1366): This PR adds test cases to verify the support for zset data type in type command. 7 | - Improves SET command implementation (@JyotinderSingh) (#1371): Enhances the implementation of the SET command. 8 | 9 | ## Bug Fixes: 10 | 11 | - Fixing lint errors of funding.json (@arpitbbhayani) (#1381): Resolves lint errors in the funding.json file. 12 | - Updating OG Image (@arpitbbhayani) (#1375): Updates the Open Graph image to fix any issues. 13 | 14 | ## Documentation: 15 | 16 | - Community and Team (@arpitbbhayani) (#1370): Adds a section for community and team information. 17 | - Publishing DiceDB is now open source blog (@arpitbbhayani) (#1373): Publishes a blog post announcing that DiceDB is now open-source. 18 | 19 | **General Enhancements:** 20 | 21 | - Switches license to BSD 3-Clause License. 22 | - Editing blog to keep things consistent (@arpitbbhayani) (#1376): Makes edits to the blog post for consistency. 23 | - Updating OG Image (@arpitbbhayani) (#1375): Updates the Open Graph image to improve user experience. 24 | - [CLEANUP] remove sql and query_manager (@apoorvyadav1111) (#1369): Removes unnecessary code in the sql package and `watchmanager.go`. 25 | - Playground link added to nav and stats updated (@arpitbbhayani) (#1379): Adds a link to the playground in the navigation menu and updates statistics. 26 | -------------------------------------------------------------------------------- /docs/src/data/roadmap.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | We track DiceDB's Roadmap in a simple [Google Spreadsheet](https://docs.google.com/spreadsheets/d/1bcf-NOVcKESG4L0QL8jhZuetIeDTzoVngf-0HbzIdO8/edit?usp=sharing). 4 | -------------------------------------------------------------------------------- /docs/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /docs/src/layouts/Head.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Seo from "../components/Seo.astro"; 3 | const { title, description, img, blog, video, session, JSONLD } = Astro.props; 4 | --- 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {title} 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/src/layouts/Layout.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import "../styles/main.scss"; 3 | 4 | import Nav from "../components/Nav.astro"; 5 | import Footer from "../components/Footer.astro"; 6 | import Head from "./Head.astro"; 7 | 8 | import { GoogleAnalytics } from "astro-analytics"; 9 | 10 | const { title, description, img, blog, session, video, JSONLD } = Astro.props; 11 | --- 12 | 13 | 14 | 15 | 16 | 17 |
18 |
25 |
29 |
30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/src/layouts/LayoutNarrow.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from "./Layout.astro"; 3 | const { title, description, img } = Astro.props; 4 | --- 5 | 6 | 7 |
8 |
9 | 10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /docs/src/pages/about-us.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from "../layouts/Layout.astro"; 3 | import site from "../data/site.json"; 4 | 5 | const title = "About Us"; 6 | const description = ""; 7 | --- 8 | 9 | 10 |
11 |
12 |
13 |
14 |
15 | DiceDB Logo 16 |
17 |

About Us

18 |
19 |
20 |
21 | { 22 | site.aboutDiceDB.map((s) => ( 23 |
24 |
25 |

{s.title}

26 |

{s.description}

27 |
28 |
29 | )) 30 | } 31 |
32 |
33 |
34 |
35 |
36 |
37 | -------------------------------------------------------------------------------- /docs/src/pages/benchmarks.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from "../layouts/Layout.astro"; 3 | import BenchmarkContent from "../data/benchmarks.mdx"; 4 | 5 | const title = "DiceDB Benchmarks"; 6 | const description = ""; 7 | --- 8 | 9 | 10 |
11 |
12 |
13 | 14 |
15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /docs/src/pages/blog/[slug].astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { getCollection } from "astro:content"; 3 | import BlogLayout from "../../layouts/BlogLayout.astro"; 4 | export async function getStaticPaths() { 5 | const blogs = (await getCollection("blog")).sort( 6 | (a, b) => b.data.published_at.getTime() - a.data.published_at.getTime(), 7 | ); 8 | return blogs.map((blog) => ({ 9 | params: { slug: blog.slug }, 10 | props: { blog }, 11 | })); 12 | } 13 | 14 | const { blog } = Astro.props; 15 | const { Content } = await blog.render(); 16 | --- 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/src/pages/blog/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { getCollection } from "astro:content"; 3 | 4 | import Layout from "../../layouts/Layout.astro"; 5 | import RecentBlogs from "../../components/RecentBlogs.astro"; 6 | const blogs = (await getCollection("blog")).sort( 7 | (a, b) => b.data.published_at.getTime() - a.data.published_at.getTime(), 8 | ); 9 | const title = "DiceDB Blog"; 10 | const description = ""; 11 | --- 12 | 13 | 14 |
15 |
16 |
17 |
18 |

Blogs

19 |
20 |
21 |
22 |
23 | { 24 | ( 25 |
26 | 27 |
28 | ) 29 | } 30 |
31 |
32 |
33 | -------------------------------------------------------------------------------- /docs/src/pages/reactivity.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from "../layouts/Layout.astro"; 3 | import Content from "../data/reactivity.md"; 4 | 5 | const title = "Reactivity in DiceDB"; 6 | const description = ""; 7 | --- 8 | 9 | 10 |
11 |
12 |
13 | 14 |
15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /docs/src/pages/releases/[slug].astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { getCollection } from "astro:content"; 3 | import BlogLayout from "../../layouts/BlogLayout.astro"; 4 | export async function getStaticPaths() { 5 | const releases = (await getCollection("releases")).sort( 6 | (a, b) => b.data.published_at.getTime() - a.data.published_at.getTime(), 7 | ); 8 | return releases.map((release) => ({ 9 | params: { slug: release.slug }, 10 | props: { release }, 11 | })); 12 | } 13 | 14 | const { release } = Astro.props; 15 | const { Content } = await release.render(); 16 | --- 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/src/pages/releases/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { getCollection } from "astro:content"; 3 | 4 | import Layout from "../../layouts/Layout.astro"; 5 | import RecentReleases from "../../components/RecentReleases.astro"; 6 | const releases = (await getCollection("releases")).sort( 7 | (a, b) => b.data.published_at.getTime() - a.data.published_at.getTime(), 8 | ); 9 | const title = "DiceDB Releases"; 10 | const description = ""; 11 | --- 12 | 13 | 14 |
15 |
16 |
17 |
18 |

19 | Releases 20 |

21 |
22 |
23 |
24 |
25 | { 26 | ( 27 |
28 | 29 |
30 | ) 31 | } 32 |
33 |
34 |
35 | -------------------------------------------------------------------------------- /docs/src/pages/roadmap.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from "../layouts/Layout.astro"; 3 | import Content from "../data/roadmap.md"; 4 | 5 | const title = "DiceDB Roadmap"; 6 | const description = ""; 7 | --- 8 | 9 | 10 |
11 |
12 |
13 | 14 |
15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /docs/src/pages/updates/[slug].astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { getCollection } from "astro:content"; 3 | import BlogLayout from "../../layouts/BlogLayout.astro"; 4 | export async function getStaticPaths() { 5 | const updates = (await getCollection("updates")).sort( 6 | (a, b) => new Date(b.slug).getTime() - new Date(a.slug).getTime(), 7 | ); 8 | return updates.map((update) => ({ 9 | params: { slug: update.slug }, 10 | props: { update }, 11 | })); 12 | } 13 | 14 | const { update } = Astro.props; 15 | const { Content } = await update.render(); 16 | --- 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/src/styles/docs.css: -------------------------------------------------------------------------------- 1 | /* Dark mode colors. */ 2 | :root { 3 | --sl-color-accent-low: #2b1212; 4 | --sl-color-accent: #ff4444; 5 | --sl-color-accent-high: #ffb3b3; 6 | --sl-color-white: #ffffff; 7 | --sl-color-gray-1: #eceef2; 8 | --sl-color-gray-2: #c0c2c7; 9 | --sl-color-gray-3: #888b96; 10 | --sl-color-gray-4: #545861; 11 | --sl-color-gray-5: #353841; 12 | --sl-color-gray-6: #242424; 13 | --sl-color-black: #1a1a1a; 14 | --sl-color-text-link: #66b3ff; 15 | } 16 | 17 | :root[data-theme="light"] { 18 | --sl-color-accent-low: #ffe6e6; 19 | --sl-color-accent: #ff4444; 20 | --sl-color-accent-high: #800000; 21 | --sl-color-white: #17181c; 22 | --sl-color-gray-1: #24272f; 23 | --sl-color-gray-2: #353841; 24 | --sl-color-gray-3: #545861; 25 | --sl-color-gray-4: #888b96; 26 | --sl-color-gray-5: #c0c2c7; 27 | --sl-color-gray-6: #eceef2; 28 | --sl-color-gray-7: #f5f6f8; 29 | --sl-color-black: #ffffff; 30 | --sl-color-text-link: #66b3ff; 31 | } 32 | -------------------------------------------------------------------------------- /docs/src/utils/github.ts: -------------------------------------------------------------------------------- 1 | export async function fetchRepoDetails() { 2 | try { 3 | const response = await fetch("https://api.github.com/repos/DiceDB/dice"); 4 | if (!response.ok) { 5 | throw new Error( 6 | `GitHub API request failed with status ${response.status}`, 7 | ); 8 | } 9 | 10 | const data = await response.json(); 11 | 12 | const formattedStars = 13 | data?.stargazers_count >= 1000 14 | ? (data?.stargazers_count / 1000).toFixed(1) + "k+" 15 | : data?.stargazers_count.toString(); 16 | 17 | return { 18 | name: data.name, 19 | stars: formattedStars, 20 | forks: data.forks_count, 21 | watchers: data.watchers_count, 22 | openIssues: data.open_issues_count, 23 | url: data.html_url, 24 | }; 25 | } catch (error) { 26 | console.error("🚨 GitHub API Error:", error); 27 | throw new Error("❌ Failed to fetch GitHub repository data. Build halted."); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strict" 3 | } 4 | -------------------------------------------------------------------------------- /examples/chatroom-go/README.md: -------------------------------------------------------------------------------- 1 | Chatroom 2 | === 3 | 4 | ```sh 5 | $ go run main.go 6 | ``` 7 | -------------------------------------------------------------------------------- /examples/chatroom-go/go.mod: -------------------------------------------------------------------------------- 1 | module chatroom-go 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/charmbracelet/bubbles v0.20.0 7 | github.com/charmbracelet/bubbletea v1.2.4 8 | github.com/charmbracelet/lipgloss v1.0.0 9 | github.com/dicedb/dicedb-go v1.0.8 10 | ) 11 | 12 | require ( 13 | github.com/atotto/clipboard v0.1.4 // indirect 14 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 15 | github.com/charmbracelet/x/ansi v0.4.5 // indirect 16 | github.com/charmbracelet/x/term v0.2.1 // indirect 17 | github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect 18 | github.com/google/uuid v1.6.0 // indirect 19 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 20 | github.com/mattn/go-isatty v0.0.20 // indirect 21 | github.com/mattn/go-localereader v0.0.1 // indirect 22 | github.com/mattn/go-runewidth v0.0.16 // indirect 23 | github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect 24 | github.com/muesli/cancelreader v0.2.2 // indirect 25 | github.com/muesli/termenv v0.15.2 // indirect 26 | github.com/rivo/uniseg v0.4.7 // indirect 27 | golang.org/x/sync v0.9.0 // indirect 28 | golang.org/x/sys v0.27.0 // indirect 29 | golang.org/x/text v0.3.8 // indirect 30 | google.golang.org/protobuf v1.36.5 // indirect 31 | ) 32 | -------------------------------------------------------------------------------- /examples/chatroom-go/svc/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package svc 5 | 6 | import ( 7 | "fmt" 8 | 9 | "github.com/dicedb/dicedb-go" 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | var ( 14 | client *dicedb.Client 15 | ) 16 | 17 | func init() { 18 | var err error 19 | client, err = dicedb.NewClient("localhost", 7379) 20 | if err != nil { 21 | panic(err) 22 | } 23 | } 24 | 25 | func SendMessage(username, message string) { 26 | resp := client.Fire(&wire.Command{ 27 | Cmd: "SET", 28 | Args: []string{"last_message", fmt.Sprintf("%s:%s", username, message)}, 29 | }) 30 | if resp.Status == wire.Status_ERR { 31 | fmt.Println("error sending message:", resp.Message) 32 | } 33 | } 34 | 35 | func Subscribe() { 36 | resp := client.Fire(&wire.Command{ 37 | Cmd: "GET.WATCH", 38 | Args: []string{"last_message"}, 39 | }) 40 | if resp.Status == wire.Status_ERR { 41 | fmt.Println("error subscribing:", resp.Message) 42 | } 43 | } 44 | 45 | func ListenForMessages(onMessage func(result *wire.Result)) { 46 | ch, err := client.WatchCh() 47 | if err != nil { 48 | panic(err) 49 | } 50 | for resp := range ch { 51 | if resp.Status == wire.Status_ERR { 52 | fmt.Println("error listening for messages:", resp.Message) 53 | } else { 54 | onMessage(resp) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /examples/hello-world-go/README.md: -------------------------------------------------------------------------------- 1 | Hello, World - DiceDB + Go 2 | === 3 | 4 | This is a simple Hello, World application with DiceDB using Go SDK. 5 | The example, sets a key `k1` with value `v1` and then fetches 6 | the key `k1` to get the value `v1`. 7 | 8 | Before you run this example, please make sure you have installed 9 | DiceDB and are running it locally. 10 | 11 | > If not, you can change the connection parameters in the code 12 | > and make your code point to some remote running instance of 13 | > DiceDB 14 | 15 | To run the example, execute the following command from this directory 16 | 17 | ```bash 18 | $ go run main.go 19 | ``` 20 | -------------------------------------------------------------------------------- /examples/hello-world-go/go.mod: -------------------------------------------------------------------------------- 1 | module hello-world-go 2 | 3 | go 1.24.0 4 | 5 | require github.com/dicedb/dicedb-go v1.0.9 6 | 7 | require ( 8 | github.com/google/uuid v1.6.0 // indirect 9 | google.golang.org/protobuf v1.36.6 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /examples/hello-world-go/go.sum: -------------------------------------------------------------------------------- 1 | github.com/dicedb/dicedb-go v1.0.9 h1:WtXtX6Bu/KFjhnOIlnoo9Z1hbmOtL2tMrUmS6793/Pw= 2 | github.com/dicedb/dicedb-go v1.0.9/go.mod h1:V1fiCJnPfSObKWrOJ/zrhHEGlLwT9k3pKCto3sz1oW8= 3 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 4 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 5 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 6 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 7 | go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs= 8 | go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= 9 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 10 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 11 | google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= 12 | google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 13 | -------------------------------------------------------------------------------- /examples/hello-world-go/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | 9 | "github.com/dicedb/dicedb-go" 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | func main() { 14 | // create a new DiceDB client and connect to the server 15 | client, err := dicedb.NewClient("localhost", 7379) 16 | if err != nil { 17 | panic(err) 18 | } 19 | defer client.Close() 20 | 21 | // define a key and value 22 | key := "k1" 23 | value := "v1" 24 | 25 | // set the key and value 26 | resp := client.Fire(&wire.Command{ 27 | Cmd: "SET", 28 | Args: []string{key, value}, 29 | }) 30 | if resp.Status == wire.Status_ERR { 31 | fmt.Println("error setting key:", resp.Message) 32 | return 33 | } 34 | fmt.Printf("successfully set key %s=%s\n", key, value) 35 | 36 | // get the key and value 37 | resp = client.Fire(&wire.Command{ 38 | Cmd: "GET", 39 | Args: []string{key}, 40 | }) 41 | if resp.Status == wire.Status_ERR { 42 | fmt.Println("error getting key:", resp.Message) 43 | return 44 | } 45 | 46 | fmt.Printf("successfully got key %s=%s\n", key, resp.GetGETRes().Value) 47 | } 48 | -------------------------------------------------------------------------------- /examples/leaderboard-go/README.md: -------------------------------------------------------------------------------- 1 | Leaderboard 2 | === 3 | 4 | 1. start the DiceDB server 5 | 2. run the following command from one terminal session 6 | 7 | ```sh 8 | $ go run main.go mock 9 | ``` 10 | 11 | 3. run the following command from 3 other terminal sessions 12 | 13 | ```sh 14 | $ go run main.go 15 | ``` 16 | -------------------------------------------------------------------------------- /examples/leaderboard-go/go.mod: -------------------------------------------------------------------------------- 1 | module leaderboard-go 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/charmbracelet/bubbles v0.20.0 7 | github.com/charmbracelet/lipgloss v1.0.0 8 | github.com/dicedb/dicedb-go v1.0.9 9 | ) 10 | 11 | require ( 12 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 13 | github.com/charmbracelet/bubbletea v1.2.4 // indirect 14 | github.com/charmbracelet/x/ansi v0.4.5 // indirect 15 | github.com/charmbracelet/x/term v0.2.1 // indirect 16 | github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect 17 | github.com/google/uuid v1.6.0 // indirect 18 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 19 | github.com/mattn/go-isatty v0.0.20 // indirect 20 | github.com/mattn/go-localereader v0.0.1 // indirect 21 | github.com/mattn/go-runewidth v0.0.16 // indirect 22 | github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect 23 | github.com/muesli/cancelreader v0.2.2 // indirect 24 | github.com/muesli/termenv v0.15.2 // indirect 25 | github.com/rivo/uniseg v0.4.7 // indirect 26 | golang.org/x/sync v0.9.0 // indirect 27 | golang.org/x/sys v0.27.0 // indirect 28 | golang.org/x/text v0.3.8 // indirect 29 | google.golang.org/protobuf v1.36.5 // indirect 30 | ) 31 | -------------------------------------------------------------------------------- /examples/leaderboard-go/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "leaderboard-go/svc" 9 | "math/rand" 10 | "os" 11 | "os/signal" 12 | "syscall" 13 | "time" 14 | 15 | "github.com/dicedb/dicedb-go/wire" 16 | ) 17 | 18 | var players = []string{"Alice", "Bob", "Charlie", "Dora", "Evan", "Fay", "Gina"} 19 | 20 | func main() { 21 | if len(os.Args) > 1 && os.Args[1] == "mock" { 22 | for { 23 | player := players[rand.Intn(len(players))] 24 | score := rand.Intn(100) 25 | svc.UpdateScore(player, score) 26 | fmt.Println("updated game:scores for", player, "with score", score) 27 | time.Sleep(time.Millisecond * 500) 28 | } 29 | } 30 | 31 | // Set up signal handling for graceful shutdown 32 | sigChan := make(chan os.Signal, 1) 33 | signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) 34 | 35 | // Subscribe to leaderboard updates 36 | svc.Subscribe() 37 | 38 | // Start listening for messages 39 | go svc.ListenForMessages(func(result *wire.Result) { 40 | displayLeaderboard(result.GetZRANGERes().Elements) 41 | }) 42 | 43 | // Wait for interrupt signal 44 | <-sigChan 45 | fmt.Println("\nShutting down...") 46 | } 47 | 48 | func displayLeaderboard(leaderboard []*wire.ZElement) { 49 | // Clear the screen 50 | fmt.Print("\033[H\033[2J") 51 | 52 | fmt.Println("Rank Score Player") 53 | fmt.Println("------------------") 54 | 55 | for _, element := range leaderboard { 56 | fmt.Printf("%2d. %4d %s\n", element.Rank, element.Score, element.Member) 57 | } 58 | 59 | fmt.Println("------------------") 60 | fmt.Println("Press Ctrl+C to exit") 61 | } 62 | -------------------------------------------------------------------------------- /examples/leaderboard-go/svc/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package svc 5 | 6 | import ( 7 | "fmt" 8 | "strconv" 9 | 10 | "github.com/dicedb/dicedb-go" 11 | "github.com/dicedb/dicedb-go/wire" 12 | ) 13 | 14 | var ( 15 | client *dicedb.Client 16 | ) 17 | 18 | func init() { 19 | var err error 20 | client, err = dicedb.NewClient("localhost", 7379) 21 | if err != nil { 22 | panic(err) 23 | } 24 | } 25 | 26 | func UpdateScore(player string, score int) { 27 | resp := client.Fire(&wire.Command{ 28 | Cmd: "ZADD", 29 | Args: []string{"game:scores", strconv.Itoa(score), player}, 30 | }) 31 | if resp.Status == wire.Status_ERR { 32 | fmt.Println("error updating score:", resp.Message) 33 | } 34 | } 35 | 36 | func Subscribe() { 37 | resp := client.Fire(&wire.Command{ 38 | Cmd: "ZRANGE.WATCH", 39 | Args: []string{"game:scores", "1", "5", "BYRANK"}, 40 | }) 41 | if resp.Status == wire.Status_ERR { 42 | fmt.Println("error subscribing:", resp.Message) 43 | } 44 | } 45 | 46 | func ListenForMessages(onMessage func(result *wire.Result)) { 47 | ch, err := client.WatchCh() 48 | if err != nil { 49 | panic(err) 50 | } 51 | for resp := range ch { 52 | if resp.Status == wire.Status_ERR { 53 | fmt.Println("error listening for messages:", resp.Message) 54 | } else { 55 | onMessage(resp) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /internal/cmd/cmd_echo.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package cmd 5 | 6 | import ( 7 | "github.com/dicedb/dice/internal/errors" 8 | "github.com/dicedb/dice/internal/shardmanager" 9 | dstore "github.com/dicedb/dice/internal/store" 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | var cECHO = &CommandMeta{ 14 | Name: "ECHO", 15 | Syntax: "ECHO message", 16 | HelpShort: "ECHO returns the message passed to it", 17 | HelpLong: `ECHO returns the message passed to it.`, 18 | Examples: ` 19 | localhost:7379> ECHO dicedb 20 | OK dicedb`, 21 | Eval: evalECHO, 22 | Execute: executeECHO, 23 | } 24 | 25 | func init() { 26 | CommandRegistry.AddCommand(cECHO) 27 | } 28 | 29 | func newECHORes(message string) *CmdRes { 30 | return &CmdRes{ 31 | Rs: &wire.Result{ 32 | Message: "OK", 33 | Status: wire.Status_OK, 34 | Response: &wire.Result_ECHORes{ 35 | ECHORes: &wire.ECHORes{ 36 | Message: message, 37 | }, 38 | }, 39 | }, 40 | } 41 | } 42 | 43 | func evalECHO(c *Cmd, s *dstore.Store) (*CmdRes, error) { 44 | if len(c.C.Args) != 1 { 45 | return newECHORes(""), errors.ErrWrongArgumentCount("ECHO") 46 | } 47 | 48 | return newECHORes(c.C.Args[0]), nil 49 | } 50 | 51 | func executeECHO(c *Cmd, sm *shardmanager.ShardManager) (*CmdRes, error) { 52 | shard := sm.GetShardForKey("-") 53 | return evalECHO(c, shard.Thread.Store()) 54 | } 55 | -------------------------------------------------------------------------------- /internal/cmd/cmd_ping.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package cmd 5 | 6 | import ( 7 | "github.com/dicedb/dice/internal/errors" 8 | "github.com/dicedb/dice/internal/shardmanager" 9 | dstore "github.com/dicedb/dice/internal/store" 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | var cPING = &CommandMeta{ 14 | Name: "PING", 15 | Syntax: "PING", 16 | HelpShort: "PING returns PONG if no argument is provided, otherwise it returns PONG with the message.", 17 | HelpLong: ` 18 | PING returns PONG if no argument is provided, otherwise it returns PONG with the message argument. 19 | `, 20 | Examples: ` 21 | localhost:7379> PING 22 | OK "PONG" 23 | localhost:7379> PING dicedb 24 | OK "PONG dicedb" 25 | `, 26 | Eval: evalPING, 27 | Execute: executePING, 28 | } 29 | 30 | func init() { 31 | CommandRegistry.AddCommand(cPING) 32 | } 33 | 34 | func newPINGRes(v string) *CmdRes { 35 | return &CmdRes{ 36 | Rs: &wire.Result{ 37 | Message: "OK", 38 | Status: wire.Status_OK, 39 | Response: &wire.Result_PINGRes{ 40 | PINGRes: &wire.PINGRes{ 41 | Message: v, 42 | }, 43 | }, 44 | }, 45 | } 46 | } 47 | 48 | var PINGResNilRes = newPINGRes("") 49 | 50 | func evalPING(c *Cmd, s *dstore.Store) (*CmdRes, error) { 51 | if len(c.C.Args) >= 2 { 52 | return PINGResNilRes, errors.ErrWrongArgumentCount("PING") 53 | } 54 | if len(c.C.Args) == 0 { 55 | return newPINGRes("PONG"), nil 56 | } 57 | return newPINGRes("PONG " + c.C.Args[0]), nil 58 | } 59 | 60 | func executePING(c *Cmd, sm *shardmanager.ShardManager) (*CmdRes, error) { 61 | shard := sm.GetShardForKey("-") 62 | return evalPING(c, shard.Thread.Store()) 63 | } 64 | -------------------------------------------------------------------------------- /internal/common/map.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package common 5 | 6 | type ITable[K comparable, V any] interface { 7 | Put(key K, value V) 8 | Get(key K) (V, bool) 9 | Delete(key K) 10 | Len() int 11 | All(func(k K, obj V) bool) 12 | } 13 | -------------------------------------------------------------------------------- /internal/common/regmap.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package common 5 | 6 | import ( 7 | "sync" 8 | "sync/atomic" 9 | ) 10 | 11 | type RegMap[K comparable, V any] struct { 12 | DefaultV V 13 | M sync.Map 14 | count atomic.Int64 15 | } 16 | 17 | func (t *RegMap[K, V]) Put(key K, value V) { 18 | t.M.Store(key, value) 19 | t.count.Add(1) 20 | } 21 | 22 | func (t *RegMap[K, V]) Get(key K) (V, bool) { 23 | value, ok := t.M.Load(key) 24 | if !ok { 25 | return t.DefaultV, false 26 | } 27 | return value.(V), true 28 | } 29 | 30 | func (t *RegMap[K, V]) Delete(key K) { 31 | t.M.Delete(key) 32 | t.count.Add(-1) 33 | } 34 | 35 | func (t *RegMap[K, V]) Len() int { 36 | return int(t.count.Load()) 37 | } 38 | 39 | func (t *RegMap[K, V]) All(f func(k K, obj V) bool) { 40 | t.M.Range(func(key, value any) bool { 41 | return f(key.(K), value.(V)) 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /internal/eval/bloom_utils.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package eval 5 | 6 | // setBit sets the bit at index `b` to "1" in `buf`. 7 | func setBit(buf []byte, b uint64) { 8 | idx, offset := b/8, 7-b%8 9 | if idx >= uint64(len(buf)) { 10 | return 11 | } 12 | 13 | buf[idx] |= 1 << offset 14 | } 15 | 16 | // isBitSet checks if the bit at index `b` is set to "1" or not in `buf`. 17 | func isBitSet(buf []byte, b uint64) bool { 18 | idx, offset := b/8, 7-b%8 19 | if idx >= uint64(len(buf)) { 20 | return false 21 | } 22 | 23 | if buf[idx]&(1<>counterBits]) << counterBits 26 | return _id 27 | } 28 | 29 | // NextID returns a new unique ID 30 | // TODO: Persisting the cycle on disk and reloading it when we start the server 31 | func NextID() uint32 { 32 | mu.Lock() 33 | defer mu.Unlock() 34 | counter = (counter + 1) & ((1 << counterBits) - 1) 35 | if counter == 0 { 36 | cycle++ 37 | turn = (turn + 1) & ((1 << turnBits) - 1) 38 | cycleMap[turn] = cycle 39 | } 40 | return (turn << counterBits) | counter 41 | } 42 | -------------------------------------------------------------------------------- /internal/id/id_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package id 5 | 6 | import ( 7 | "testing" 8 | ) 9 | 10 | func BenchmarkNextID(b *testing.B) { 11 | for i := 0; i < b.N; i++ { 12 | ExpandID(NextID()) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /internal/iomultiplexer/constants.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package iomultiplexer 5 | 6 | const ( 7 | // OpRead represents the read operation 8 | OpRead Operations = 1 << iota 9 | // OpWrite represents the write operation 10 | OpWrite 11 | ) 12 | -------------------------------------------------------------------------------- /internal/iomultiplexer/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package iomultiplexer 5 | 6 | import "errors" 7 | 8 | var ( 9 | // ErrInvalidMaxClients is returned when the maxClients is less than 0 10 | ErrInvalidMaxClients = errors.New("invalid max clients") 11 | ) 12 | -------------------------------------------------------------------------------- /internal/iomultiplexer/interface.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package iomultiplexer 5 | 6 | import "time" 7 | 8 | // IOMultiplexer defines a generic interface for platform-specific 9 | // I/O multiplexer implementations 10 | type IOMultiplexer interface { 11 | // Subscribe subscribes to the given event 12 | // When the event is triggered, the Poll method will return it 13 | Subscribe(event Event) error 14 | 15 | // Poll polls for all the subscribed events simultaneously 16 | // and returns all the events that were triggered 17 | // It blocks until at least one event is triggered or the timeout is reached 18 | Poll(timeout time.Duration) ([]Event, error) 19 | 20 | // Close closes the IOMultiplexer instance 21 | Close() error 22 | } 23 | -------------------------------------------------------------------------------- /internal/iomultiplexer/types.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package iomultiplexer 5 | 6 | // Event is a platform independent representation of a subscribe event 7 | // For linux platform, this is translated to syscall.EpollEvent 8 | // For darwin platform, this is translated to syscall.Kevent_t 9 | type Event struct { 10 | // Fd denotes the file descriptor 11 | Fd int 12 | // Op denotes the operations on file descriptor that are to be monitored 13 | Op Operations 14 | } 15 | 16 | // Operations is a platform independent representation of the operations 17 | // that need to be monitored on a file descriptor 18 | type Operations uint32 19 | -------------------------------------------------------------------------------- /internal/iomultiplexer/types_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package iomultiplexer 5 | 6 | import ( 7 | "syscall" 8 | "time" 9 | ) 10 | 11 | // newTime converts the given time.Duration to Darwin's timespec struct 12 | func newTime(t time.Duration) *syscall.Timespec { 13 | if t < 0 { 14 | return nil 15 | } 16 | 17 | return &syscall.Timespec{ 18 | Nsec: int64(t), 19 | } 20 | } 21 | 22 | // toNative converts the given generic Event to Darwin's Kevent_t struct 23 | func (e Event) toNative(flags uint16) syscall.Kevent_t { 24 | return syscall.Kevent_t{ 25 | Ident: uint64(e.Fd), 26 | Filter: e.Op.toNative(), 27 | Flags: flags, 28 | } 29 | } 30 | 31 | // newEvent converts the given Darwin's Kevent_t struct to the generic Event type 32 | func newEvent(kEvent syscall.Kevent_t) Event { 33 | return Event{ 34 | Fd: int(kEvent.Ident), 35 | Op: newOperations(kEvent.Filter), 36 | } 37 | } 38 | 39 | // toNative converts the given generic Operations to Darwin's filter type 40 | func (op Operations) toNative() int16 { 41 | native := int16(0) 42 | 43 | if op&OpRead != 0 { 44 | native |= syscall.EVFILT_READ 45 | } 46 | if op&OpWrite != 0 { 47 | native |= syscall.EVFILT_WRITE 48 | } 49 | 50 | return native 51 | } 52 | 53 | // newOperations converts the given Darwin's filter type to the generic Operations type 54 | func newOperations(filter int16) Operations { 55 | op := Operations(0) 56 | 57 | if filter&syscall.EVFILT_READ != 0 { 58 | op |= OpRead 59 | } 60 | if filter&syscall.EVFILT_WRITE != 0 { 61 | op |= OpWrite 62 | } 63 | 64 | return op 65 | } 66 | -------------------------------------------------------------------------------- /internal/iomultiplexer/types_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package iomultiplexer 5 | 6 | import ( 7 | "syscall" 8 | "time" 9 | ) 10 | 11 | // newTime converts the given time.Duration to Linux's ms in int 12 | func newTime(t time.Duration) int { 13 | if t < 0 { 14 | return -1 15 | } 16 | 17 | return int(t / time.Millisecond) 18 | } 19 | 20 | // toNative converts the given generic Event to Linux's EpollEvent struct 21 | func (e Event) toNative() syscall.EpollEvent { 22 | return syscall.EpollEvent{ 23 | Fd: int32(e.Fd), 24 | Events: e.Op.toNative(), 25 | } 26 | } 27 | 28 | // newEvent converts the given Linux's EpollEvent struct to the generic Event type 29 | func newEvent(ePEvent syscall.EpollEvent) Event { 30 | return Event{ 31 | Fd: int(ePEvent.Fd), 32 | Op: newOperations(ePEvent.Events), 33 | } 34 | } 35 | 36 | // toNative converts the given generic Operations to Linux's EpollEvent type 37 | func (op Operations) toNative() uint32 { 38 | native := uint32(0) 39 | 40 | if op&OpRead != 0 { 41 | native |= syscall.EPOLLIN 42 | } 43 | if op&OpWrite != 0 { 44 | native |= syscall.EPOLLOUT 45 | } 46 | 47 | return native 48 | } 49 | 50 | // newOperations converts the given Linux's EpollEvent type to the generic Operations type 51 | func newOperations(events uint32) Operations { 52 | op := Operations(0) 53 | 54 | if events&syscall.EPOLLIN != 0 { 55 | op |= OpRead 56 | } 57 | if events&syscall.EPOLLOUT != 0 { 58 | op |= OpWrite 59 | } 60 | 61 | return op 62 | } 63 | -------------------------------------------------------------------------------- /internal/logger/logger.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package logger 5 | 6 | import ( 7 | "log/slog" 8 | "os" 9 | "time" 10 | 11 | "github.com/dicedb/dice/config" 12 | "github.com/rs/zerolog" 13 | ) 14 | 15 | func getSLogLevel() slog.Level { 16 | switch config.Config.LogLevel { 17 | case "debug": 18 | return slog.LevelDebug 19 | case "info": 20 | return slog.LevelInfo 21 | default: 22 | return slog.LevelInfo 23 | } 24 | } 25 | 26 | func New() *slog.Logger { 27 | zerolog.TimeFieldFormat = zerolog.TimeFormatUnix 28 | zerologLogger := zerolog.New(zerolog.ConsoleWriter{ 29 | Out: os.Stderr, 30 | NoColor: false, 31 | TimeFormat: time.RFC3339, 32 | }).Level(toZerologLevel(getSLogLevel())).With().Timestamp().Logger() 33 | return slog.New(newZerologHandler(&zerologLogger)) 34 | } 35 | -------------------------------------------------------------------------------- /internal/object/deep_copy.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package object 5 | 6 | import ( 7 | "github.com/bytedance/sonic" 8 | ) 9 | 10 | type DeepCopyable interface { 11 | DeepCopy() interface{} 12 | } 13 | 14 | func (obj *Obj) DeepCopy() *Obj { 15 | newObj := &Obj{ 16 | Type: obj.Type, 17 | LastAccessedAt: obj.LastAccessedAt, 18 | } 19 | 20 | // Use the DeepCopyable interface to deep copy the value 21 | if copier, ok := obj.Value.(DeepCopyable); ok { 22 | newObj.Value = copier.DeepCopy() 23 | } else { 24 | // Handle types that are not DeepCopyable 25 | sourceType := obj.Type 26 | switch sourceType { 27 | case ObjTypeString: 28 | sourceValue := obj.Value.(string) 29 | newObj.Value = sourceValue 30 | 31 | case ObjTypeJSON: 32 | sourceValue := obj.Value 33 | jsonStr, err := sonic.MarshalString(sourceValue) 34 | if err != nil { 35 | return nil 36 | } 37 | var value interface{} 38 | err = sonic.UnmarshalString(jsonStr, &value) 39 | if err != nil { 40 | return nil 41 | } 42 | newObj.Value = value 43 | 44 | default: 45 | return nil 46 | } 47 | } 48 | 49 | return newObj 50 | } 51 | -------------------------------------------------------------------------------- /internal/object/typeencoding.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package object 5 | 6 | import ( 7 | "errors" 8 | 9 | diceerrors "github.com/dicedb/dice/internal/errors" 10 | ) 11 | 12 | func AssertTypeWithError(te, t ObjectType) error { 13 | if te != t { 14 | return errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") 15 | } 16 | return nil 17 | } 18 | 19 | func AssertType(_type, expectedType ObjectType) []byte { 20 | if err := AssertTypeWithError(_type, expectedType); err != nil { 21 | return diceerrors.NewErrWithMessage(diceerrors.WrongKeyTypeErr) 22 | } 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /internal/observability/constants.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package observability 5 | 6 | const linux = "linux" 7 | const darwin = "darwin" 8 | const windows = "windows" 9 | -------------------------------------------------------------------------------- /internal/observability/instance.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package observability 5 | 6 | import ( 7 | "log/slog" 8 | "os" 9 | "path/filepath" 10 | 11 | "github.com/google/uuid" 12 | ) 13 | 14 | // GetOrCreateInstanceID creates a file named dicedb.iid in a temp directory with a unique UUID v6. 15 | // If the file exists, it reads the value and returns it. Otherwise, it creates the file and writes a new UUID v6 to it. 16 | func GetOrCreateInstanceID() string { 17 | tempDir := os.TempDir() 18 | filePath := filepath.Join(tempDir, "dicedb.iid") 19 | 20 | if _, err := os.Stat(filePath); os.IsNotExist(err) { 21 | id := uuid.New().String() 22 | if err := os.WriteFile(filePath, []byte(id), 0600); err != nil { 23 | slog.Error("unable to create dicedb.iid hence running anon", slog.Any("error", err)) 24 | return "" 25 | } 26 | return id 27 | } 28 | 29 | data, err := os.ReadFile(filePath) 30 | if err != nil { 31 | slog.Error("unable to read dicedb.iid hence running anon", slog.Any("error", err)) 32 | return "" 33 | } 34 | 35 | return string(data) 36 | } 37 | -------------------------------------------------------------------------------- /internal/regex/regex.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package regex 5 | 6 | // WildCardMatch checks if the key matches the pattern using * and ? as wildcards using two pointer approach 7 | func WildCardMatch(pattern, key string) bool { 8 | patternLen := len(pattern) 9 | keyLen := len(key) 10 | patternIndex := 0 11 | keyIndex := 0 12 | starIndex := -1 13 | kIndex := -1 14 | 15 | for keyIndex < keyLen { 16 | if patternIndex < patternLen && (pattern[patternIndex] == '?' || pattern[patternIndex] == key[keyIndex]) { 17 | patternIndex++ 18 | keyIndex++ 19 | } else if patternIndex < patternLen && pattern[patternIndex] == '*' { 20 | starIndex = patternIndex 21 | kIndex = keyIndex 22 | patternIndex++ 23 | } else if starIndex != -1 { 24 | patternIndex = starIndex + 1 25 | kIndex++ 26 | keyIndex = kIndex 27 | } else { 28 | return false 29 | } 30 | } 31 | 32 | for patternIndex < patternLen && pattern[patternIndex] == '*' { 33 | patternIndex++ 34 | } 35 | 36 | return patternIndex == patternLen 37 | } 38 | -------------------------------------------------------------------------------- /internal/server/ironhawk/iothread_manager.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "sync" 9 | "sync/atomic" 10 | 11 | "github.com/dicedb/dice/config" 12 | ) 13 | 14 | type IOThreadManager struct { 15 | connectedClients sync.Map 16 | numIOThreads atomic.Uint32 17 | mu sync.Mutex 18 | } 19 | 20 | var ( 21 | ErrMaxClientsReached = errors.New("maximum number of clients reached") 22 | ErrIOThreadNotFound = errors.New("io-thread not found") 23 | ) 24 | 25 | func NewIOThreadManager() *IOThreadManager { 26 | return &IOThreadManager{} 27 | } 28 | 29 | func (m *IOThreadManager) RegisterIOThread(ioThread *IOThread) error { 30 | m.mu.Lock() 31 | defer m.mu.Unlock() 32 | 33 | if m.IOThreadCount() >= uint32(config.Config.MaxClients) { 34 | return ErrMaxClientsReached 35 | } 36 | 37 | m.connectedClients.Store(ioThread.ClientID, ioThread) 38 | m.numIOThreads.Add(1) 39 | return nil 40 | } 41 | 42 | func (m *IOThreadManager) IOThreadCount() uint32 { 43 | return m.numIOThreads.Load() 44 | } 45 | 46 | func (m *IOThreadManager) UnregisterIOThread(id string) error { 47 | if client, loaded := m.connectedClients.LoadAndDelete(id); loaded { 48 | w := client.(*IOThread) 49 | if err := w.Stop(); err != nil { 50 | return err 51 | } 52 | } else { 53 | return ErrIOThreadNotFound 54 | } 55 | 56 | m.numIOThreads.Add(^uint32(0)) 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /internal/server/utils/array.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package utils 5 | 6 | import "reflect" 7 | 8 | func IsArray(data any) bool { 9 | kind := reflect.TypeOf(data).Kind() 10 | return kind == reflect.Array || kind == reflect.Slice 11 | } 12 | -------------------------------------------------------------------------------- /internal/server/utils/boolToInt.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package utils 5 | 6 | func BoolToInt(b bool) int { 7 | if b { 8 | return 1 9 | } 10 | return 0 11 | } 12 | -------------------------------------------------------------------------------- /internal/server/utils/constants.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package utils 5 | 6 | const ( 7 | EmptyStr = "" 8 | 9 | ObjectType string = "object" 10 | ArrayType string = "array" 11 | StringType string = "string" 12 | IntegerType string = "integer" 13 | NumberType string = "number" 14 | BooleanType string = "boolean" 15 | NullType string = "null" 16 | UnknownType string = "unknown" 17 | NumberZeroValue int = 0 18 | JSONIngest string = "JSON.INGEST" 19 | 20 | GET string = "GET" 21 | SET string = "SET" 22 | INCRBY string = "INCRBY" 23 | OVERFLOW string = "OVERFLOW" 24 | WRAP string = "WRAP" 25 | SAT string = "SAT" 26 | FAIL string = "FAIL" 27 | SIGNED string = "SIGNED" 28 | UNSIGNED string = "UNSIGNED" 29 | ) 30 | -------------------------------------------------------------------------------- /internal/server/utils/floatToInt.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package utils 5 | 6 | func IsFloatToIntPossible(value float64) (int, bool) { 7 | intValue := int64(value) 8 | if value == float64(intValue) { 9 | return int(intValue), true 10 | } 11 | return 0, false 12 | } 13 | -------------------------------------------------------------------------------- /internal/server/utils/json.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package utils 5 | 6 | // This method returns the path, and a boolean value telling if the path provided follows Legacy Path Syntax or JSONPath syntax. 7 | // JSON knows which syntax to use depending on the first character of the path query. 8 | // If the query starts with the character $, it uses JSONPath syntax. Otherwise, it defaults to the legacy path syntax. 9 | // A JSONPath query can resolve to several locations in a JSON document. 10 | // In this case, the JSON commands apply the operation to every possible location. This is a major improvement over legacy path queries, which only operate on the first path. 11 | func ParseInputJSONPath(path string) (string, bool) { 12 | isLegacyPath := path[0] != '$' 13 | 14 | // Handle . path error 15 | if len(path) == 1 && path[0] == '.' { 16 | path = "$" 17 | } 18 | return path, isLegacyPath 19 | } 20 | -------------------------------------------------------------------------------- /internal/server/utils/jsontype.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package utils 5 | 6 | func GetJSONFieldType(v interface{}) string { 7 | switch v.(type) { 8 | case map[string]interface{}: 9 | return ObjectType 10 | case []interface{}: 11 | return ArrayType 12 | case string: 13 | return StringType 14 | case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: 15 | return IntegerType 16 | case float32, float64: 17 | return NumberType 18 | case bool: 19 | return BooleanType 20 | case nil: 21 | return NullType 22 | default: 23 | return UnknownType 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /internal/server/utils/jsontype_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package utils 5 | 6 | import ( 7 | "github.com/stretchr/testify/assert" 8 | "testing" 9 | ) 10 | 11 | func TestGetJsonFieldType(t *testing.T) { 12 | tests := []struct { 13 | name string 14 | input interface{} 15 | wantType string 16 | }{ 17 | { 18 | name: "string test", 19 | input: "123", 20 | wantType: "string", 21 | }, 22 | { 23 | name: "integer test", 24 | input: 1, 25 | wantType: "integer", 26 | }, 27 | { 28 | name: "float test", 29 | input: 1.1, 30 | wantType: "number", 31 | }, 32 | { 33 | name: "boolean test", 34 | input: true, 35 | wantType: "boolean", 36 | }, 37 | { 38 | name: "nil test", 39 | input: nil, 40 | wantType: "null", 41 | }, 42 | { 43 | name: "array test", 44 | input: []interface{}{"string"}, 45 | wantType: "array", 46 | }, 47 | { 48 | name: "object test", 49 | input: map[string]interface{}{}, 50 | wantType: "object", 51 | }, 52 | { 53 | name: "unknown test", 54 | input: struct{}{}, 55 | wantType: "unknown", 56 | }, 57 | } 58 | 59 | for _, tt := range tests { 60 | t.Run(tt.name, func(t *testing.T) { 61 | result := GetJSONFieldType(tt.input) 62 | assert.Equal(t, tt.wantType, result) 63 | }) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /internal/server/utils/round.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package utils 5 | 6 | import "math" 7 | 8 | // RoundToDecimals rounds a float64 or float32 to a specified number of decimal places. 9 | func RoundToDecimals[T float32 | float64](num T, decimals int) T { 10 | pow := math.Pow(10, float64(decimals)) 11 | return T(math.Round(float64(num)*pow) / pow) 12 | } 13 | -------------------------------------------------------------------------------- /internal/shard/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package shard 5 | 6 | import "github.com/dicedb/dice/internal/shardthread" 7 | 8 | type Shard struct { 9 | ID int 10 | Thread *shardthread.ShardThread 11 | } 12 | -------------------------------------------------------------------------------- /internal/store/aof.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package store 5 | 6 | import ( 7 | "bufio" 8 | "io/fs" 9 | "os" 10 | "sync" 11 | ) 12 | 13 | type AOF struct { 14 | file *os.File 15 | writer *bufio.Writer 16 | mutex sync.Mutex 17 | path string 18 | } 19 | 20 | const ( 21 | FileMode int = 0644 22 | ) 23 | 24 | func NewAOF(path string) (*AOF, error) { 25 | f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, fs.FileMode(FileMode)) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | return &AOF{ 31 | file: f, 32 | writer: bufio.NewWriter(f), 33 | path: path, 34 | }, nil 35 | } 36 | 37 | func (a *AOF) Write(operation string) error { 38 | a.mutex.Lock() 39 | defer a.mutex.Unlock() 40 | 41 | if _, err := a.writer.WriteString(operation + "\n"); err != nil { 42 | return err 43 | } 44 | if err := a.writer.Flush(); err != nil { 45 | return err 46 | } 47 | return a.file.Sync() 48 | } 49 | 50 | func (a *AOF) Close() error { 51 | a.mutex.Lock() 52 | defer a.mutex.Unlock() 53 | 54 | if err := a.writer.Flush(); err != nil { 55 | return err 56 | } 57 | return a.file.Close() 58 | } 59 | 60 | func (a *AOF) Load() ([]string, error) { 61 | f, err := os.Open(a.path) 62 | if err != nil { 63 | return nil, err 64 | } 65 | defer f.Close() 66 | 67 | var operations []string 68 | scanner := bufio.NewScanner(f) 69 | for scanner.Scan() { 70 | operations = append(operations, scanner.Text()) 71 | } 72 | 73 | if err := scanner.Err(); err != nil { 74 | return nil, err 75 | } 76 | 77 | return operations, nil 78 | } 79 | -------------------------------------------------------------------------------- /internal/store/constants.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package store 5 | 6 | const ( 7 | Set string = "SET" 8 | Del string = "DEL" 9 | Get string = "GET" 10 | Rename string = "RENAME" 11 | ZAdd string = "ZADD" 12 | ZRange string = "ZRANGE" 13 | Replace string = "REPLACE" 14 | Smembers string = "SMEMBERS" 15 | JSONGet string = "JSON.GET" 16 | PFADD string = "PFADD" 17 | PFCOUNT string = "PFCOUNT" 18 | PFMERGE string = "PFMERGE" 19 | KEYSPERSHARD string = "KEYSPERSHARD" 20 | Evict string = "EVICT" 21 | SingleShardSize string = "SINGLEDBSIZE" 22 | SingleShardTouch string = "SINGLETOUCH" 23 | SingleShardKeys string = "SINGLEKEYS" 24 | FlushDB string = "FLUSHDB" 25 | ) 26 | -------------------------------------------------------------------------------- /internal/store/store_options.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package store 5 | 6 | type PutOptions struct { 7 | KeepTTL bool 8 | PutCmd string 9 | } 10 | 11 | func getDefaultPutOptions() *PutOptions { 12 | return &PutOptions{ 13 | KeepTTL: false, 14 | PutCmd: Set, 15 | } 16 | } 17 | 18 | type PutOption func(*PutOptions) 19 | 20 | func WithKeepTTL(value bool) PutOption { 21 | return func(po *PutOptions) { 22 | po.KeepTTL = value 23 | } 24 | } 25 | 26 | func WithPutCmd(cmd string) PutOption { 27 | return func(po *PutOptions) { 28 | po.PutCmd = cmd 29 | } 30 | } 31 | 32 | type DelOptions struct { 33 | DelCmd string 34 | } 35 | 36 | func getDefaultDelOptions() *DelOptions { 37 | return &DelOptions{ 38 | DelCmd: Del, 39 | } 40 | } 41 | 42 | type DelOption func(*DelOptions) 43 | 44 | func WithDelCmd(cmd string) DelOption { 45 | return func(po *DelOptions) { 46 | po.DelCmd = cmd 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /internal/types/params.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package types 5 | 6 | type Param string 7 | 8 | const ( 9 | CH Param = "CH" 10 | INCR Param = "INCR" 11 | GT Param = "GT" 12 | LT Param = "LT" 13 | 14 | EX Param = "EX" 15 | PX Param = "PX" 16 | EXAT Param = "EXAT" 17 | PXAT Param = "PXAT" 18 | XX Param = "XX" 19 | NX Param = "NX" 20 | KEEPTTL Param = "KEEPTTL" 21 | 22 | PERSIST Param = "PERSIST" 23 | ) 24 | -------------------------------------------------------------------------------- /internal/wal/wal.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package wal 5 | 6 | import ( 7 | "log/slog" 8 | 9 | "github.com/dicedb/dice/config" 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | type WAL interface { 14 | // Init initializes the WAL. 15 | // The WAL implementation should start all the background jobs and initialize the WAL. 16 | Init() error 17 | // Stop stops the WAL. 18 | // The WAL implementation should stop all the background jobs and close the WAL. 19 | Stop() 20 | // LogCommand logs a command to the WAL. 21 | LogCommand(c *wire.Command) error 22 | // Replay replays the command from the WAL. 23 | ReplayCommand(cb func(c *wire.Command) error) error 24 | } 25 | 26 | var DefaultWAL WAL 27 | var ( 28 | stopCh chan struct{} 29 | ) 30 | 31 | func init() { 32 | stopCh = make(chan struct{}) 33 | } 34 | 35 | // TeardownWAL stops the WAL and closes the WAL instance. 36 | func TeardownWAL() { 37 | close(stopCh) 38 | } 39 | 40 | // SetupWAL initializes the WAL based on the configuration. 41 | // It creates a new WAL instance based on the WAL variant and initializes it. 42 | // If the initialization fails, it panics. 43 | func SetupWAL() { 44 | switch config.Config.WALVariant { 45 | case "forge": 46 | DefaultWAL = newWalForge() 47 | default: 48 | return 49 | } 50 | 51 | if err := DefaultWAL.Init(); err != nil { 52 | slog.Error("could not initialize WAL", slog.Any("error", err)) 53 | panic(err) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package main 5 | 6 | import "github.com/dicedb/dice/cmd" 7 | 8 | func main() { 9 | cmd.Execute() 10 | } 11 | -------------------------------------------------------------------------------- /scripts/generate-docs/doc.tmpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: {{ .Name }} 3 | description: {{ .HelpShort }} 4 | --- 5 | 6 | 10 | 11 | #### Syntax 12 | 13 | ``` 14 | {{ .Syntax }} 15 | ``` 16 | 17 | {{ .HelpLong }} 18 | 19 | #### Examples 20 | 21 | ``` 22 | {{ .Examples }} 23 | ``` 24 | -------------------------------------------------------------------------------- /scripts/generate-docs/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "os" 9 | "text/template" 10 | 11 | "github.com/dicedb/dice/internal/cmd" 12 | ) 13 | 14 | const DocsCommandsDirectory = "docs/src/content/docs/commands" 15 | 16 | func generateDocs(tmpl *template.Template, c *cmd.CommandMeta) { 17 | docFile, err := os.Create(fmt.Sprintf("%s/%s.md", DocsCommandsDirectory, c.Name)) 18 | if err != nil { 19 | fmt.Printf("ERR: error creating file: %v\n", err) 20 | } 21 | defer docFile.Close() 22 | 23 | err = tmpl.Execute(docFile, c) 24 | if err != nil { 25 | fmt.Printf("ERR: error executing template: %v\n", err) 26 | } 27 | } 28 | 29 | func main() { 30 | tmpl := template.Must(template.ParseFiles("scripts/generate-docs/doc.tmpl")) 31 | for _, c := range cmd.CommandRegistry.CommandMetas { 32 | if c.HelpLong == "" { 33 | continue 34 | } 35 | 36 | generateDocs(tmpl, c) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /scripts/test-docs/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "strings" 9 | 10 | "github.com/dicedb/dice/internal/cmd" 11 | "github.com/dicedb/dicedb-go" 12 | "github.com/dicedb/dicedb-go/wire" 13 | ) 14 | 15 | func main() { 16 | for _, c := range cmd.CommandRegistry.CommandMetas { 17 | if strings.Contains(c.Examples, "WATCH") { 18 | continue 19 | } 20 | for _, linesStr := range strings.Split(c.Examples, "localhost:7379>") { 21 | lines := strings.Split(linesStr, "\n") 22 | command := strings.TrimSpace(lines[0]) 23 | if command == "" { 24 | continue 25 | } 26 | output := strings.TrimSpace(strings.Join(lines[1:], "\n")) 27 | fmt.Println("cmd", command) 28 | fmt.Println("output", output) 29 | 30 | client, err := dicedb.NewClient("localhost", 7379) 31 | if err != nil { 32 | fmt.Println("error", err) 33 | continue 34 | } 35 | 36 | res := client.Fire(&wire.Command{ 37 | Cmd: strings.Split(command, " ")[0], 38 | Args: strings.Split(command, " ")[1:], 39 | }) 40 | 41 | // TODO: Write a function to compare the output 42 | // to the expected output 43 | // The idea is to test the documentation examples and making sure 44 | // what we ship in the docs is working as expected. 45 | fmt.Println("res", res) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/decr_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/dicedb/dicedb-go/wire" 10 | ) 11 | 12 | func extractValueDECR(result *wire.Result) interface{} { 13 | return result.GetDECRRes().GetValue() 14 | } 15 | 16 | func TestDECR(t *testing.T) { 17 | client := getLocalConnection() 18 | defer client.Close() 19 | 20 | // TODO: Add test cases for DECR with non-integer values 21 | // TODO: Add test cases for non existent key 22 | // TODO: Add test cases for DECR with negative values 23 | // TODO: Add test cases for DECR with min and max int64 values 24 | testCases := []TestCase{ 25 | { 26 | name: "DECR", 27 | commands: []string{"SET key1 2", "DECR key1", "DECR key1", "DECR key1"}, 28 | expected: []interface{}{"OK", 1, 0, -1}, 29 | valueExtractor: []ValueExtractorFn{extractValueSET, extractValueDECR, extractValueDECR, extractValueDECR}, 30 | }, 31 | } 32 | runTestcases(t, client, testCases) 33 | } 34 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/decrby_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/dicedb/dicedb-go/wire" 10 | ) 11 | 12 | func extractValueDECRBY(result *wire.Result) interface{} { 13 | return result.GetDECRBYRes().GetValue() 14 | } 15 | 16 | func TestDECRBY(t *testing.T) { 17 | client := getLocalConnection() 18 | defer client.Close() 19 | 20 | // TODO: Add test cases for DECRBY with non-integer values 21 | // TODO: Add test cases for non existent key 22 | // TODO: Add test cases for DECR with negative values 23 | // TODO: Add test cases for DECR with min and max int64 values 24 | testCases := []TestCase{ 25 | { 26 | name: "DECRBY", 27 | commands: []string{ 28 | "SET key1 5", 29 | "DECRBY key1 2", 30 | "DECRBY key1 2", 31 | "DECRBY key1 1", 32 | "DECRBY key1 1", 33 | }, 34 | expected: []interface{}{"OK", 3, 1, 0, -1}, 35 | valueExtractor: []ValueExtractorFn{extractValueSET, extractValueDECRBY, extractValueDECRBY, extractValueDECRBY, extractValueDECRBY}, 36 | }, 37 | } 38 | runTestcases(t, client, testCases) 39 | } 40 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/del_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/dicedb/dicedb-go/wire" 10 | ) 11 | 12 | func extractValueDEL(result *wire.Result) interface{} { 13 | return result.GetDELRes().GetCount() 14 | } 15 | 16 | func TestDEL(t *testing.T) { 17 | client := getLocalConnection() 18 | defer client.Close() 19 | 20 | testCases := []TestCase{ 21 | { 22 | name: "DEL with set key", 23 | commands: []string{"SET k1 v1", "DEL k1", "GET k1"}, 24 | expected: []interface{}{"OK", 1, ""}, 25 | valueExtractor: []ValueExtractorFn{extractValueSET, extractValueDEL, extractValueGET}, 26 | }, 27 | { 28 | name: "DEL multiple keys", 29 | commands: []string{"SET k1 v1", "SET k2 v2", "DEL k1 k2", "GET k1", "GET k2"}, 30 | expected: []interface{}{"OK", "OK", 2, "", ""}, 31 | valueExtractor: []ValueExtractorFn{extractValueSET, extractValueSET, extractValueDEL, extractValueGET, extractValueGET}, 32 | }, 33 | { 34 | name: "DEL with key not set", 35 | commands: []string{"GET k3", "DEL k3"}, 36 | expected: []interface{}{"", 0}, 37 | valueExtractor: []ValueExtractorFn{extractValueGET, extractValueDEL}, 38 | }, 39 | { 40 | name: "DEL with no keys or arguments", 41 | commands: []string{"DEL"}, 42 | expected: []interface{}{0}, 43 | valueExtractor: []ValueExtractorFn{extractValueDEL}, 44 | }, 45 | } 46 | runTestcases(t, client, testCases) 47 | } 48 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/echo_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | func extractValueECHO(result *wire.Result) interface{} { 14 | return result.GetECHORes().GetMessage() 15 | } 16 | 17 | func TestEcho(t *testing.T) { 18 | client := getLocalConnection() 19 | defer client.Close() 20 | 21 | // TODO: Add tests where argument is a string with special characters and spaces etc 22 | testCases := []TestCase{ 23 | { 24 | name: "ECHO with invalid number of arguments", 25 | commands: []string{"ECHO"}, 26 | expected: []interface{}{ 27 | errors.New("wrong number of arguments for 'ECHO' command"), 28 | }, 29 | valueExtractor: []ValueExtractorFn{extractValueECHO}, 30 | }, 31 | { 32 | name: "ECHO with one argument", 33 | commands: []string{"ECHO hello"}, 34 | expected: []interface{}{"hello"}, 35 | valueExtractor: []ValueExtractorFn{extractValueECHO}, 36 | }, 37 | } 38 | runTestcases(t, client, testCases) 39 | } 40 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/flushdb_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/dicedb/dicedb-go/wire" 10 | ) 11 | 12 | func extractValueFLUSHDB(result *wire.Result) interface{} { 13 | return result.GetMessage() 14 | } 15 | 16 | func TestFLUSHDB(t *testing.T) { 17 | client := getLocalConnection() 18 | defer client.Close() 19 | 20 | testCases := []TestCase{ 21 | { 22 | name: "FLUSHDB", 23 | commands: []string{ 24 | "SET k1 v1", 25 | "SET k2 v2", 26 | "SET k3 v3", 27 | "FLUSHDB", 28 | "GET k1", 29 | "GET k2", 30 | "GET k3", 31 | }, 32 | expected: []interface{}{"OK", "OK", "OK", "OK", "", "", ""}, 33 | valueExtractor: []ValueExtractorFn{extractValueSET, extractValueSET, extractValueSET, extractValueFLUSHDB, extractValueGET, extractValueGET, extractValueGET}, 34 | }, 35 | } 36 | 37 | runTestcases(t, client, testCases) 38 | } 39 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/get_watch_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | ) 10 | 11 | func TestGETWATCH(t *testing.T) { 12 | client := getLocalConnection() 13 | defer client.Close() 14 | 15 | testCases := []TestCase{ 16 | { 17 | name: "Get watch subscription without key arg", 18 | commands: []string{"GET.WATCH"}, 19 | expected: []interface{}{ 20 | errors.New("wrong number of arguments for 'GET.WATCH' command"), 21 | }, 22 | valueExtractor: []ValueExtractorFn{nil}, 23 | }, 24 | } 25 | 26 | runTestcases(t, client, testCases) 27 | } 28 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/hget_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | func extractValueHGET(res *wire.Result) interface{} { 14 | return res.GetHGETRes().Value 15 | } 16 | 17 | func TestHGET(t *testing.T) { 18 | client := getLocalConnection() 19 | defer client.Close() 20 | 21 | testCases := []TestCase{ 22 | { 23 | name: "Get Value for Field stored at Hash Key", 24 | commands: []string{"HSET k f 1", "HGET k f"}, 25 | expected: []interface{}{1, "1"}, 26 | valueExtractor: []ValueExtractorFn{extractValueHSET, extractValueHGET}, 27 | }, 28 | { 29 | name: "Get Hash Field on non-hash Key", 30 | commands: []string{"SET key f", "HGET key f"}, 31 | expected: []interface{}{"OK", 32 | errors.New("wrongtype operation against a key holding the wrong kind of value"), 33 | }, 34 | valueExtractor: []ValueExtractorFn{extractValueSET, nil}, 35 | }, 36 | { 37 | name: "Get Hash Key with no Field argument", 38 | commands: []string{"HGET k"}, 39 | expected: []interface{}{ 40 | errors.New("wrong number of arguments for 'HGET' command"), 41 | }, 42 | valueExtractor: []ValueExtractorFn{nil, nil}, 43 | }, 44 | } 45 | runTestcases(t, client, testCases) 46 | } 47 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/hget_watch_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | func extractValueHGETWATCH(res *wire.Result) interface{} { 14 | return res.Message 15 | } 16 | 17 | func TestHGETWATCH(t *testing.T) { 18 | client := getLocalConnection() 19 | defer client.Close() 20 | 21 | testCases := []TestCase{ 22 | { 23 | name: "HGet watch subscription without key arg", 24 | commands: []string{"HGET.WATCH"}, 25 | expected: []interface{}{ 26 | errors.New("wrong number of arguments for 'HGET.WATCH' command"), 27 | }, 28 | valueExtractor: []ValueExtractorFn{nil}, 29 | }, 30 | { 31 | name: "HGet watch subscription without field arg", 32 | commands: []string{"HGET.WATCH k1"}, 33 | expected: []interface{}{ 34 | errors.New("wrong number of arguments for 'HGET.WATCH' command"), 35 | }, 36 | valueExtractor: []ValueExtractorFn{nil}, 37 | }, 38 | { 39 | name: "HGet watch subscription with key and field arg", 40 | commands: []string{"HGET.WATCH k1 f1"}, 41 | expected: []interface{}{"OK"}, 42 | valueExtractor: []ValueExtractorFn{extractValueHGETWATCH}, 43 | }, 44 | } 45 | 46 | runTestcases(t, client, testCases) 47 | } 48 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/hgetall_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "sort" 10 | "testing" 11 | 12 | "github.com/dicedb/dicedb-go/wire" 13 | ) 14 | 15 | func extractValueHGETALL(res *wire.Result) interface{} { 16 | elements := res.GetHGETALLRes().Elements 17 | sort.Slice(elements, func(i, j int) bool { 18 | return elements[i].Key < elements[j].Key 19 | }) 20 | 21 | str := "" 22 | for _, element := range elements { 23 | str += fmt.Sprintf("%s: %s\n", element.Key, element.Value) 24 | } 25 | return str 26 | } 27 | 28 | func TestHGETALL(t *testing.T) { 29 | client := getLocalConnection() 30 | defer client.Close() 31 | 32 | testCases := []TestCase{ 33 | { 34 | name: "Get Value for Field stored at Hash Key", 35 | commands: []string{"HSET k f1 v1 f2 v2", "HGETALL k"}, 36 | expected: []interface{}{2, "f1: v1\nf2: v2\n"}, 37 | valueExtractor: []ValueExtractorFn{extractValueHSET, extractValueHGETALL}, 38 | }, 39 | { 40 | name: "HGETALL with no key argument", 41 | commands: []string{"HGETALL"}, 42 | expected: []interface{}{ 43 | errors.New("wrong number of arguments for 'HGETALL' command"), 44 | }, 45 | valueExtractor: []ValueExtractorFn{nil}, 46 | }, 47 | { 48 | name: "HGETALL with non hash key", 49 | commands: []string{"SET key 5", "HGETALL key"}, 50 | expected: []interface{}{"OK", 51 | errors.New("wrongtype operation against a key holding the wrong kind of value"), 52 | }, 53 | valueExtractor: []ValueExtractorFn{extractValueSET, nil}, 54 | }, 55 | } 56 | runTestcases(t, client, testCases) 57 | } 58 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/hgetall_watch_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | func extractValueHGETALLWATCH(res *wire.Result) interface{} { 14 | return res.Message 15 | } 16 | 17 | func TestHGETALLWATCH(t *testing.T) { 18 | client := getLocalConnection() 19 | defer client.Close() 20 | 21 | testCases := []TestCase{ 22 | { 23 | name: "HGetAll watch subscription without key arg", 24 | commands: []string{"HGETALL.WATCH"}, 25 | expected: []interface{}{ 26 | errors.New("wrong number of arguments for 'HGETALL.WATCH' command"), 27 | }, 28 | valueExtractor: []ValueExtractorFn{nil}, 29 | }, 30 | { 31 | name: "HGetAll watch subscription without field arg", 32 | commands: []string{"HGETALL.WATCH k1"}, 33 | expected: []interface{}{ 34 | "OK", 35 | }, 36 | valueExtractor: []ValueExtractorFn{extractValueHGETALLWATCH}, 37 | }, 38 | } 39 | 40 | runTestcases(t, client, testCases) 41 | } 42 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/hset_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | func extractValueHSET(res *wire.Result) interface{} { 14 | return res.GetHSETRes().Count 15 | } 16 | 17 | func TestHSET(t *testing.T) { 18 | client := getLocalConnection() 19 | defer client.Close() 20 | 21 | testCases := []TestCase{ 22 | { 23 | name: "Set Field Value at Key stored in Hash", 24 | commands: []string{"HSET k f v"}, 25 | expected: []interface{}{1}, 26 | valueExtractor: []ValueExtractorFn{extractValueHSET}, 27 | }, 28 | { 29 | name: "Set Hash on non-hash Key", 30 | commands: []string{"SET key f", "HSET key f v"}, 31 | expected: []interface{}{"OK", 32 | errors.New("wrongtype operation against a key holding the wrong kind of value"), 33 | }, 34 | valueExtractor: []ValueExtractorFn{extractValueSET, nil}, 35 | }, 36 | { 37 | name: "Set Hash with no Field and Value", 38 | commands: []string{"HSET k"}, 39 | expected: []interface{}{ 40 | errors.New("wrong number of arguments for 'HSET' command"), 41 | }, 42 | valueExtractor: []ValueExtractorFn{nil, nil}, 43 | }, 44 | } 45 | runTestcases(t, client, testCases) 46 | } 47 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/keys_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/dicedb/dicedb-go/wire" 10 | ) 11 | 12 | func extractValueKEYS(res *wire.Result) interface{} { 13 | return res.GetKEYSRes().Keys 14 | } 15 | 16 | func TestKEYS(t *testing.T) { 17 | client := getLocalConnection() 18 | defer client.Close() 19 | 20 | testCases := []TestCase{ 21 | { 22 | name: "KEYS with more than one matching key", 23 | commands: []string{"SET k v", "SET k1 v1", "KEYS k*"}, 24 | expected: []interface{}{"OK", "OK", []string{"k", "k1"}}, 25 | valueExtractor: []ValueExtractorFn{extractValueSET, extractValueSET, extractValueKEYS}, 26 | }, 27 | { 28 | name: "KEYS with no matching keys", 29 | commands: []string{"KEYS a*"}, 30 | expected: []interface{}{[]string{}}, 31 | valueExtractor: []ValueExtractorFn{extractValueKEYS}, 32 | }, 33 | { 34 | name: "KEYS with single character wildcard", 35 | commands: []string{"SET k1 v1", "SET k2 v2", "SET ka va", "KEYS k?"}, 36 | expected: []interface{}{"OK", "OK", "OK", []string{"k1", "k2", "ka"}}, 37 | valueExtractor: []ValueExtractorFn{extractValueSET, extractValueSET, extractValueSET, extractValueKEYS}, 38 | }, 39 | { 40 | name: "KEYS with single matching key", 41 | commands: []string{"SET unique_key value", "KEYS unique*"}, 42 | expected: []interface{}{"OK", []string{"unique_key"}}, 43 | valueExtractor: []ValueExtractorFn{extractValueSET, extractValueKEYS}, 44 | }, 45 | } 46 | 47 | runTestcases(t, client, testCases) 48 | } 49 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/ping_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | func extractValuePING(res *wire.Result) interface{} { 14 | return res.GetPINGRes().Message 15 | } 16 | 17 | func TestPING(t *testing.T) { 18 | client := getLocalConnection() 19 | defer client.Close() 20 | 21 | testCases := []TestCase{ 22 | { 23 | name: "PING no arguments", 24 | commands: []string{"PING"}, 25 | expected: []interface{}{"PONG"}, 26 | valueExtractor: []ValueExtractorFn{extractValuePING}, 27 | }, 28 | { 29 | name: "PING with one argument", 30 | commands: []string{"PING hello"}, 31 | expected: []interface{}{"PONG hello"}, 32 | valueExtractor: []ValueExtractorFn{extractValuePING}, 33 | }, 34 | { 35 | name: "PING with two arguments", 36 | commands: []string{"PING hello world"}, 37 | expected: []interface{}{ 38 | errors.New("wrong number of arguments for 'PING' command"), 39 | }, 40 | valueExtractor: []ValueExtractorFn{nil}, 41 | }, 42 | } 43 | runTestcases(t, client, testCases) 44 | } 45 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/type_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | 10 | "github.com/dicedb/dicedb-go/wire" 11 | ) 12 | 13 | func extractValueTYPE(res *wire.Result) interface{} { 14 | return res.GetTYPERes().Type 15 | } 16 | 17 | func TestTYPE(t *testing.T) { 18 | client := getLocalConnection() 19 | defer client.Close() 20 | 21 | testCases := []TestCase{ 22 | { 23 | name: "TYPE with invalid number of arguments", 24 | commands: []string{"TYPE"}, 25 | expected: []interface{}{ 26 | errors.New("wrong number of arguments for 'TYPE' command"), 27 | }, 28 | valueExtractor: []ValueExtractorFn{nil}, 29 | }, 30 | { 31 | name: "TYPE for non-existent key", 32 | commands: []string{"TYPE k1"}, 33 | expected: []interface{}{"none"}, 34 | valueExtractor: []ValueExtractorFn{extractValueTYPE}, 35 | }, 36 | { 37 | name: "TYPE for key with String value", 38 | commands: []string{"SET k1 v1", "TYPE k1"}, 39 | expected: []interface{}{"OK", "string"}, 40 | valueExtractor: []ValueExtractorFn{extractValueSET, extractValueTYPE}, 41 | }, 42 | } 43 | 44 | runTestcases(t, client, testCases) 45 | } 46 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/zcard_watch_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | ) 10 | 11 | func TestZCARDWATCH(t *testing.T) { 12 | client := getLocalConnection() 13 | defer client.Close() 14 | 15 | testCases := []TestCase{ 16 | { 17 | name: "Get watch subscription without key arg", 18 | commands: []string{"ZCARD.WATCH"}, 19 | expected: []interface{}{ 20 | errors.New("wrong number of arguments for 'ZCARD.WATCH' command"), 21 | }, 22 | valueExtractor: []ValueExtractorFn{nil}, 23 | }, 24 | } 25 | 26 | runTestcases(t, client, testCases) 27 | } 28 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/zcount_watch_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | ) 10 | 11 | func TestZCOUNTWATCH(t *testing.T) { 12 | client := getLocalConnection() 13 | defer client.Close() 14 | 15 | testCases := []TestCase{ 16 | { 17 | name: "Get watch subscription without key arg", 18 | commands: []string{"ZCOUNT.WATCH", "ZCOUNT.WATCH users", "ZCOUNT.WATCH users 1"}, 19 | expected: []interface{}{ 20 | errors.New("wrong number of arguments for 'ZCOUNT.WATCH' command"), 21 | errors.New("wrong number of arguments for 'ZCOUNT.WATCH' command"), 22 | errors.New("wrong number of arguments for 'ZCOUNT.WATCH' command"), 23 | }, 24 | valueExtractor: []ValueExtractorFn{nil, nil, nil}, 25 | }, 26 | } 27 | 28 | runTestcases(t, client, testCases) 29 | } 30 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/zrange_watch_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | ) 10 | 11 | func TestZRANGEWATCH(t *testing.T) { 12 | client := getLocalConnection() 13 | defer client.Close() 14 | 15 | testCases := []TestCase{ 16 | { 17 | name: "Get watch subscription without key arg", 18 | commands: []string{"ZRANGE.WATCH", "ZRANGE.WATCH users", "ZRANGE.WATCH users 1"}, 19 | expected: []interface{}{ 20 | errors.New("wrong number of arguments for 'ZRANGE.WATCH' command"), 21 | errors.New("wrong number of arguments for 'ZRANGE.WATCH' command"), 22 | errors.New("wrong number of arguments for 'ZRANGE.WATCH' command"), 23 | }, 24 | valueExtractor: []ValueExtractorFn{nil, nil, nil}, 25 | }, 26 | } 27 | 28 | runTestcases(t, client, testCases) 29 | } 30 | -------------------------------------------------------------------------------- /tests/commands/ironhawk/zrank_watch_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | ) 10 | 11 | func TestZRANKWATCH(t *testing.T) { 12 | client := getLocalConnection() 13 | defer client.Close() 14 | 15 | testCases := []TestCase{ 16 | { 17 | name: "Get watch subscription without key arg", 18 | commands: []string{"ZRANK.WATCH", "ZRANK.WATCH users"}, 19 | expected: []interface{}{ 20 | errors.New("wrong number of arguments for 'ZRANK.WATCH' command"), 21 | errors.New("wrong number of arguments for 'ZRANK.WATCH' command"), 22 | }, 23 | valueExtractor: []ValueExtractorFn{nil, nil}, 24 | }, 25 | } 26 | 27 | runTestcases(t, client, testCases) 28 | } 29 | -------------------------------------------------------------------------------- /tests0/command_count_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | "github.com/dicedb/dicedb-go" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func TestCommandCount(t *testing.T) { 15 | client := getLocalConnection() 16 | defer client.Close() 17 | 18 | t.Run("Command count should be positive", func(t *testing.T) { 19 | commandCount := getCommandCount(client) 20 | assert.True(t, commandCount > 0, 21 | fmt.Sprintf("Unexpected number of CLI commands found. expected greater than 0, %d found", commandCount)) 22 | }) 23 | } 24 | 25 | func getCommandCount(client *dicedb.Client) int64 { 26 | responseValue := client.FireString("COMMAND COUNT") 27 | if responseValue == nil { 28 | return -1 29 | } 30 | return responseValue.GetVInt() 31 | } 32 | 33 | func BenchmarkCountCommand(b *testing.B) { 34 | client := getLocalConnection() 35 | defer client.Close() 36 | 37 | b.ResetTimer() 38 | for n := 0; n < b.N; n++ { 39 | commandCount := getCommandCount(client) 40 | if commandCount <= 0 { 41 | b.Fail() 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests0/command_default_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | "github.com/dicedb/dice/internal/eval" 11 | "github.com/dicedb/dicedb-go" 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | func TestCommandDefault(t *testing.T) { 16 | client := getLocalConnection() 17 | defer client.Close() 18 | 19 | commands := getCommandDefault(client) 20 | t.Run("Command should not be empty", func(t *testing.T) { 21 | assert.True(t, len(commands) > 0, 22 | fmt.Sprintf("Unexpected number of CLI commands found. expected greater than 0, %d found", len(commands))) 23 | }) 24 | 25 | t.Run("Command count matches", func(t *testing.T) { 26 | assert.True(t, len(commands) == len(eval.DiceCmds), 27 | fmt.Sprintf("Unexpected number of CLI commands found. expected %d, %d found", len(eval.DiceCmds), len(commands))) 28 | }) 29 | } 30 | 31 | func getCommandDefault(client *dicedb.Client) []interface{} { 32 | resp := client.FireString("COMMAND") 33 | if resp == nil { 34 | return nil 35 | } 36 | var cmds []interface{} 37 | cmds = append(cmds, resp.GetVStr()) 38 | return cmds 39 | } 40 | 41 | func BenchmarkCommandDefault(b *testing.B) { 42 | client := getLocalConnection() 43 | defer client.Close() 44 | 45 | b.ResetTimer() 46 | for n := 0; n < b.N; n++ { 47 | commands := getCommandDefault(client) 48 | if len(commands) <= 0 { 49 | b.Fail() 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests0/command_list_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | "github.com/dicedb/dicedb-go" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func TestCommandList(t *testing.T) { 15 | client := getLocalConnection() 16 | defer client.Close() 17 | 18 | t.Run("Command list should not be empty", func(t *testing.T) { 19 | commandList := getCommandList(client) 20 | assert.True(t, len(commandList) > 0, 21 | fmt.Sprintf("Unexpected number of CLI commands found. expected greater than 0, %d found", len(commandList))) 22 | }) 23 | } 24 | 25 | func getCommandList(client *dicedb.Client) []string { 26 | resp := client.FireString("COMMAND LIST") 27 | if resp == nil { 28 | return nil 29 | } 30 | 31 | var cmds []string 32 | for _, v := range resp.GetVStr() { 33 | cmds = append(cmds, string(v)) 34 | } 35 | return cmds 36 | } 37 | 38 | func BenchmarkCommandList(b *testing.B) { 39 | client := getLocalConnection() 40 | defer client.Close() 41 | 42 | b.ResetTimer() 43 | for n := 0; n < b.N; n++ { 44 | commandList := getCommandList(client) 45 | if len(commandList) <= 0 { 46 | b.Fail() 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests0/hdel_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestHDEL(t *testing.T) { 13 | client := getLocalConnection() 14 | defer client.Close() 15 | 16 | testCases := []TestCase{ 17 | { 18 | commands: []string{"HSET key field value", "HDEL key field"}, 19 | expected: []interface{}{ONE, ONE}, 20 | }, 21 | { 22 | commands: []string{"HSET key field1 value1", "HDEL key field1"}, 23 | expected: []interface{}{ONE, ONE}, 24 | }, 25 | { 26 | commands: []string{"HSET key field2 value2 field3 value3", "HDEL key field2 field3"}, 27 | expected: []interface{}{TWO, TWO}, 28 | }, 29 | { 30 | commands: []string{"HSET key_new field value", "HDEL key_new field", "HDEL key_new"}, 31 | expected: []interface{}{ONE, ONE, "ERR wrong number of arguments for 'hdel' command"}, 32 | }, 33 | { 34 | commands: []string{"SET k v", "HDEL k f"}, 35 | expected: []interface{}{"OK", "WRONGTYPE Operation against a key holding the wrong kind of value"}, 36 | }, 37 | } 38 | 39 | for _, tc := range testCases { 40 | for i, cmd := range tc.commands { 41 | result := client.FireString(cmd) 42 | assert.Equal(t, tc.expected[i], result) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests0/hello_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | "github.com/dicedb/dice/config" 11 | ) 12 | 13 | func TestHello(t *testing.T) { 14 | client := getLocalConnection() 15 | defer client.Close() 16 | 17 | runTestcases(t, client, []TestCase{ 18 | { 19 | name: "Hello", 20 | commands: []string{"HELLO"}, 21 | expected: []interface{}{ 22 | "proto", int64(2), 23 | "id", fmt.Sprintf("%s:%d", config.Config.Host, config.Config.Port), 24 | "mode", "standalone", 25 | "role", "master", 26 | "modules", []interface{}{}, 27 | }, 28 | }, 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /tests0/hmset_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestHMSET(t *testing.T) { 13 | client := getLocalConnection() 14 | defer client.Close() 15 | defer client.FireString("DEL key key_new key2") 16 | 17 | testCases := []TestCase{ 18 | { 19 | commands: []string{"HMSET key field value field2 value2", "HGET key field", 20 | "HGET key field2", "HMSET key field3 value_new field value4", "HGET key field3", "HGET key field2", 21 | "HGET key field"}, 22 | expected: []interface{}{"OK", "value", "value2", "OK", "value_new", "value2", "value4"}, 23 | }, 24 | { 25 | commands: []string{"HMSET key2 field1 value1", "HGET key2 xxxx", "HGET key2 field1"}, 26 | expected: []interface{}{"OK", "(nil)", "value1"}, 27 | }, 28 | { 29 | commands: []string{"HMSET key field2 value2 field3 value3"}, 30 | expected: []interface{}{"OK"}, 31 | }, 32 | { 33 | commands: []string{"HMSET key_new field value field2 value2", "HMSET key_new field new_value", "HMSET key_new", 34 | "HGET key_new field", "HGET key_new field2"}, 35 | expected: []interface{}{"OK", "OK", "ERR wrong number of arguments for 'hmset' command", "new_value", "value2"}, 36 | }, 37 | { 38 | commands: []string{"SET k v", "HMSET k f v"}, 39 | expected: []interface{}{"OK", "WRONGTYPE Operation against a key holding the wrong kind of value"}, 40 | }, 41 | } 42 | 43 | for _, tc := range testCases { 44 | for i, cmd := range tc.commands { 45 | result := client.FireString(cmd) 46 | assert.Equal(t, tc.expected[i], result) 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests0/hset_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | var ZERO int64 = 0 13 | var ONE int64 = 1 14 | var TWO int64 = 2 15 | 16 | func TestHSET(t *testing.T) { 17 | client := getLocalConnection() 18 | defer client.Close() 19 | 20 | testCases := []TestCase{ 21 | { 22 | commands: []string{"HSET key field value", "HSET key field value_new"}, 23 | expected: []interface{}{ONE, ZERO}, 24 | }, 25 | { 26 | commands: []string{"HSET key field1 value1"}, 27 | expected: []interface{}{ONE}, 28 | }, 29 | { 30 | commands: []string{"HSET key field2 value2 field3 value3"}, 31 | expected: []interface{}{TWO}, 32 | }, 33 | { 34 | commands: []string{"HSET key_new field value", "HSET key_new field new_value", "HSET key_new"}, 35 | expected: []interface{}{ONE, ZERO, "ERR wrong number of arguments for 'hset' command"}, 36 | }, 37 | { 38 | commands: []string{"SET k v", "HSET k f v"}, 39 | expected: []interface{}{"OK", "WRONGTYPE Operation against a key holding the wrong kind of value"}, 40 | }, 41 | } 42 | 43 | for _, tc := range testCases { 44 | for i, cmd := range tc.commands { 45 | result := client.FireString(cmd) 46 | assert.Equal(t, tc.expected[i], result) 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests0/hsetnx_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestHSETNX(t *testing.T) { 13 | client := getLocalConnection() 14 | defer client.Close() 15 | 16 | testCases := []TestCase{ 17 | { 18 | commands: []string{"HSETNX key_nx_t1 field value", "HSET key_nx_t1 field value_new"}, 19 | expected: []interface{}{ONE, ZERO}, 20 | }, 21 | { 22 | commands: []string{"HSETNX key_nx_t2 field1 value1"}, 23 | expected: []interface{}{ONE}, 24 | }, 25 | { 26 | commands: []string{"HSETNX key_nx_t3 field value", "HSETNX key_nx_t3 field new_value", "HSETNX key_nx_t3"}, 27 | expected: []interface{}{ONE, ZERO, "ERR wrong number of arguments for 'hsetnx' command"}, 28 | }, 29 | { 30 | commands: []string{"SET key_nx_t4 v", "HSETNX key_nx_t4 f v"}, 31 | expected: []interface{}{"OK", "WRONGTYPE Operation against a key holding the wrong kind of value"}, 32 | }, 33 | } 34 | 35 | for _, tc := range testCases { 36 | for i, cmd := range tc.commands { 37 | result := client.FireString(cmd) 38 | assert.Equal(t, tc.expected[i], result) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests0/jsonresp_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestJSONRESP(t *testing.T) { 13 | client := getLocalConnection() 14 | defer client.Close() 15 | 16 | client.FireString("DEL k1 k2 k3") 17 | 18 | testCases := []struct { 19 | name string 20 | commands []string 21 | expected []interface{} 22 | }{ 23 | { 24 | name: "jsonresp on array with mixed types", 25 | commands: []string{ 26 | `JSON.SET k1 $ ["dice",10,10.5,true,null]`, 27 | "JSON.RESP k1 $", 28 | }, 29 | expected: []interface{}{"OK", []interface{}([]interface{}{"[", "dice", int64(10), "10.5", "true", "(nil)"})}, 30 | }, 31 | { 32 | name: "jsonresp on nested array with mixed types", 33 | commands: []string{ 34 | `JSON.SET k2 $ {"b":["dice",10,10.5,true,null]}`, 35 | "JSON.RESP k2 $.b", 36 | }, 37 | expected: []interface{}{"OK", []interface{}([]interface{}{[]interface{}{"[", "dice", int64(10), "10.5", "true", "(nil)"}})}, 38 | }, 39 | { 40 | name: "jsonresp on object at root path", 41 | commands: []string{ 42 | `JSON.SET k3 $ {"b":["dice",10,10.5,true,null]}`, 43 | "JSON.RESP k3", 44 | }, 45 | expected: []interface{}{"OK", []interface{}([]interface{}{"{", "b", []interface{}{"[", "dice", int64(10), "10.5", "true", "(nil)"}})}, 46 | }, 47 | } 48 | 49 | for _, tc := range testCases { 50 | t.Run(tc.name, func(t *testing.T) { 51 | for i, cmd := range tc.commands { 52 | result := client.FireString(cmd) 53 | assert.Equal(t, tc.expected[i], result) 54 | } 55 | }) 56 | } 57 | client.FireString("FLUSHDB") 58 | } 59 | -------------------------------------------------------------------------------- /tests0/touch_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package ironhawk 5 | 6 | import ( 7 | "testing" 8 | "time" 9 | ) 10 | 11 | func TestTouch(t *testing.T) { 12 | client := getLocalConnection() 13 | defer client.Close() 14 | 15 | testCases := []TestCase{ 16 | { 17 | name: "Touch Simple Value", 18 | commands: []string{"SET foo bar", "OBJECT IDLETIME foo", "TOUCH foo", "OBJECT IDLETIME foo"}, 19 | expected: []interface{}{"OK", int64(2), int64(1), int64(0)}, 20 | delay: []time.Duration{0, 2 * time.Second, 0, 0}, 21 | }, 22 | { 23 | name: "Touch Multiple Existing Keys", 24 | commands: []string{"SET foo bar", "SET foo1 bar", "TOUCH foo foo1"}, 25 | expected: []interface{}{"OK", "OK", int64(2)}, 26 | }, 27 | { 28 | name: "Touch Multiple Existing and Non-Existing Keys", 29 | commands: []string{"SET foo bar", "TOUCH foo foo1"}, 30 | expected: []interface{}{"OK", int64(1)}, 31 | }, 32 | } 33 | 34 | runTestcases(t, client, testCases) 35 | } 36 | -------------------------------------------------------------------------------- /testutils/parsecommand.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package testutils 5 | 6 | import ( 7 | "strings" 8 | "unicode/utf8" 9 | ) 10 | 11 | func ParseCommand(cmd string) []string { 12 | var args []string 13 | var builder strings.Builder 14 | var inQuotes bool 15 | 16 | flushBuilder := func() { 17 | if builder.Len() > 0 { 18 | args = append(args, builder.String()) 19 | builder.Reset() 20 | } 21 | } 22 | 23 | for cmd != "" { 24 | r, size := utf8.DecodeRuneInString(cmd) 25 | switch { 26 | case r == utf8.RuneError && size == 1: 27 | // Invalid UTF-8 sequence, treat each byte as a separate character 28 | builder.WriteByte(cmd[0]) 29 | cmd = cmd[1:] 30 | case r == ' ' && !inQuotes: 31 | flushBuilder() 32 | cmd = cmd[size:] 33 | case r == '"': 34 | inQuotes = !inQuotes 35 | builder.WriteRune(r) 36 | cmd = cmd[size:] 37 | default: 38 | builder.WriteString(cmd[:size]) 39 | cmd = cmd[size:] 40 | } 41 | } 42 | 43 | flushBuilder() 44 | 45 | // Remove quotes from each argument 46 | for i, arg := range args { 47 | args[i] = trimQuotes(arg) 48 | } 49 | 50 | return args 51 | } 52 | 53 | func trimQuotes(s string) string { 54 | if len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' { 55 | return s[1 : len(s)-1] 56 | } 57 | return s 58 | } 59 | -------------------------------------------------------------------------------- /testutils/slices.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-present, DiceDB contributors 2 | // All rights reserved. Licensed under the BSD 3-Clause License. See LICENSE file in the project root for full license information. 3 | 4 | package testutils 5 | 6 | // UnorderedEqual compares two slices of interfaces and returns true if they 7 | // contain the same elements, regardless of order. 8 | func UnorderedEqual(expected, actual interface{}) bool { 9 | expectedSlice, ok := expected.([]interface{}) 10 | if !ok { 11 | return false 12 | } 13 | 14 | actualSlice, ok := actual.([]interface{}) 15 | if !ok { 16 | return false 17 | } 18 | 19 | if len(expectedSlice) != len(actualSlice) { 20 | return false 21 | } 22 | 23 | for _, e := range expectedSlice { 24 | found := false 25 | for _, a := range actualSlice { 26 | if e == a { 27 | found = true 28 | break 29 | } 30 | } 31 | if !found { 32 | return false 33 | } 34 | } 35 | 36 | return true 37 | } 38 | 39 | // EqualByteSlice compares two byte slices and returns true if they are equal. 40 | func EqualByteSlice(a, b []byte) bool { 41 | if len(a) != len(b) { 42 | return false 43 | } 44 | 45 | for i := 0; i < len(a); i++ { 46 | if a[i] != b[i] { 47 | return false 48 | } 49 | } 50 | 51 | return true 52 | } 53 | 54 | // EqualInt64Slice compares two int64 slices and returns true if they are equal. 55 | func EqualInt64Slice(a, b []int64) bool { 56 | if len(a) != len(b) { 57 | return false 58 | } 59 | 60 | for i := 0; i < len(a); i++ { 61 | if a[i] != b[i] { 62 | return false 63 | } 64 | } 65 | 66 | return true 67 | } 68 | --------------------------------------------------------------------------------