typed.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package db
  7. import (
  8. "database/sql"
  9. "encoding/binary"
  10. "errors"
  11. "time"
  12. )
  13. // Typed is a simple key-value store using a specific namespace within a
  14. // lower level KV.
  15. type Typed struct {
  16. db KV
  17. prefix string
  18. }
  19. func NewMiscDB(db KV) *Typed {
  20. return NewTyped(db, "misc")
  21. }
  22. // NewTyped returns a new typed key-value store that lives in the namespace
  23. // specified by the prefix.
  24. func NewTyped(db KV, prefix string) *Typed {
  25. return &Typed{
  26. db: db,
  27. prefix: prefix,
  28. }
  29. }
  30. // PutInt64 stores a new int64. Any existing value (even if of another type)
  31. // is overwritten.
  32. func (n *Typed) PutInt64(key string, val int64) error {
  33. var valBs [8]byte
  34. binary.BigEndian.PutUint64(valBs[:], uint64(val)) //nolint:gosec
  35. return n.db.PutKV(n.prefixedKey(key), valBs[:])
  36. }
  37. // Int64 returns the stored value interpreted as an int64 and a boolean that
  38. // is false if no value was stored at the key.
  39. func (n *Typed) Int64(key string) (int64, bool, error) {
  40. valBs, err := n.db.GetKV(n.prefixedKey(key))
  41. if err != nil {
  42. return 0, false, filterNotFound(err)
  43. }
  44. val := binary.BigEndian.Uint64(valBs)
  45. return int64(val), true, nil //nolint:gosec
  46. }
  47. // PutTime stores a new time.Time. Any existing value (even if of another
  48. // type) is overwritten.
  49. func (n *Typed) PutTime(key string, val time.Time) error {
  50. valBs, _ := val.MarshalBinary() // never returns an error
  51. return n.db.PutKV(n.prefixedKey(key), valBs)
  52. }
  53. // Time returns the stored value interpreted as a time.Time and a boolean
  54. // that is false if no value was stored at the key.
  55. func (n *Typed) Time(key string) (time.Time, bool, error) {
  56. var t time.Time
  57. valBs, err := n.db.GetKV(n.prefixedKey(key))
  58. if err != nil {
  59. return t, false, filterNotFound(err)
  60. }
  61. err = t.UnmarshalBinary(valBs)
  62. return t, err == nil, err
  63. }
  64. // PutString stores a new string. Any existing value (even if of another type)
  65. // is overwritten.
  66. func (n *Typed) PutString(key, val string) error {
  67. return n.db.PutKV(n.prefixedKey(key), []byte(val))
  68. }
  69. // String returns the stored value interpreted as a string and a boolean that
  70. // is false if no value was stored at the key.
  71. func (n *Typed) String(key string) (string, bool, error) {
  72. valBs, err := n.db.GetKV(n.prefixedKey(key))
  73. if err != nil {
  74. return "", false, filterNotFound(err)
  75. }
  76. return string(valBs), true, nil
  77. }
  78. // PutBytes stores a new byte slice. Any existing value (even if of another type)
  79. // is overwritten.
  80. func (n *Typed) PutBytes(key string, val []byte) error {
  81. return n.db.PutKV(n.prefixedKey(key), val)
  82. }
  83. // Bytes returns the stored value as a raw byte slice and a boolean that
  84. // is false if no value was stored at the key.
  85. func (n *Typed) Bytes(key string) ([]byte, bool, error) {
  86. valBs, err := n.db.GetKV(n.prefixedKey(key))
  87. if err != nil {
  88. return nil, false, filterNotFound(err)
  89. }
  90. return valBs, true, nil
  91. }
  92. // PutBool stores a new boolean. Any existing value (even if of another type)
  93. // is overwritten.
  94. func (n *Typed) PutBool(key string, val bool) error {
  95. if val {
  96. return n.db.PutKV(n.prefixedKey(key), []byte{0x0})
  97. }
  98. return n.db.PutKV(n.prefixedKey(key), []byte{0x1})
  99. }
  100. // Bool returns the stored value as a boolean and a boolean that
  101. // is false if no value was stored at the key.
  102. func (n *Typed) Bool(key string) (bool, bool, error) {
  103. valBs, err := n.db.GetKV(n.prefixedKey(key))
  104. if err != nil {
  105. return false, false, filterNotFound(err)
  106. }
  107. return valBs[0] == 0x0, true, nil
  108. }
  109. // Delete deletes the specified key. It is allowed to delete a nonexistent
  110. // key.
  111. func (n *Typed) Delete(key string) error {
  112. return n.db.DeleteKV(n.prefixedKey(key))
  113. }
  114. func (n *Typed) prefixedKey(key string) string {
  115. return n.prefix + "/" + key
  116. }
  117. func filterNotFound(err error) error {
  118. if errors.Is(err, sql.ErrNoRows) {
  119. return nil
  120. }
  121. return err
  122. }