ndb 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +21 -0
- data/lib/ndb/client.rb +37 -3
- data/lib/ndb/errors.rb +7 -1
- data/lib/ndb/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b4be3ecd3f672ee851429ab1c7c80167be5a7f3d4c40e399eab1d1f301c55f4b
|
|
4
|
+
data.tar.gz: 2601743744f84d4962a395e6168432d60e67d0c557a9da48fa95b245050b4c1d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4b5625d6c7158f777187868a0bb099155916eafc5774e0d275e2513a5adfd868834f5c15403a6501cf4148af1af43d330f8b12ae72d457b387d26351c678fc71
|
|
7
|
+
data.tar.gz: 0a2f5b44deddc4140f4de275a762da655bbb44e4bacb3dd91178f1ba5a5d77f61abc7aebb7b09886ae6eb9d1c0fb3746e16d888b9c3917692bacfc598154626f
|
data/README.md
CHANGED
|
@@ -100,6 +100,26 @@ rescue Ndb::VersionConflict
|
|
|
100
100
|
end
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
+
## Expiry (TTL like Redis)
|
|
104
|
+
|
|
105
|
+
The collection needs `expires_field`.
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
ndb.ensure_collection("sessions", { id: "sid", expires_field: "exp" })
|
|
109
|
+
|
|
110
|
+
ndb.insert("sessions", [{ sid: "s1" }], expire_in: 3600) # seconds, or "1h" / "30m" / "1d"
|
|
111
|
+
ndb.update("sessions", "s1", set: { user: "u" }, expire_in: "30m")
|
|
112
|
+
|
|
113
|
+
ndb.expire("sessions", "s1", in: 1800) # => {"id", "v", "expires_at"}
|
|
114
|
+
ndb.expire("sessions", "s1", at: Time.now + 7200, if_version: 2)
|
|
115
|
+
ndb.ttl("sessions", "s1") # => 7199, -1 (never expires), or nil (missing or expired)
|
|
116
|
+
ndb.persist("sessions", "s1") # => {"id", "v"}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- `expire_in` wins over a value of `expires_field` in the same call. `ttl` rounds up to whole seconds.
|
|
120
|
+
- `expire` and `persist` raise `Ndb::NotFound` for a missing or expired document. `Ndb::TtlNotEnabled` means no `expires_field`; `Ndb::TtlDerived` means the expiry comes from `ttl` + `time`.
|
|
121
|
+
- Disk space of expired documents returns after compaction, and fully only with `wal_retention`; see [Freeing disk](https://github.com/thadeu/ndb/blob/main/docs/dev/configuration.md#freeing-disk).
|
|
122
|
+
|
|
103
123
|
## Find
|
|
104
124
|
|
|
105
125
|
`find` returns a `Ndb::Page` with `rows` (an array of Hash), `next_cursor`, `plan`, `examined` and `total`.
|
|
@@ -264,6 +284,7 @@ All errors inherit from `Ndb::Error`, which has `code` (the daemon code) and `st
|
|
|
264
284
|
| `InvalidCursor` | `cursor_invalid`, `cursor_mismatch`, `cursor_expired` |
|
|
265
285
|
| `WatchLagged` | `watch_lagged` |
|
|
266
286
|
| `HistoryTruncated` | `history_truncated` |
|
|
287
|
+
| `TtlNotEnabled`, `TtlDerived` | `ttl_not_enabled`, `ttl_derived` |
|
|
267
288
|
| `ConnectionError` | cannot reach the daemon. Subclasses: `ConnectError` (nothing was sent), `TimeoutError` |
|
|
268
289
|
|
|
269
290
|
Any other code is a plain `Ndb::Error`. A response that is not a daemon error has the code `http_status`.
|
data/lib/ndb/client.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
4
|
require "uri"
|
|
5
|
+
require "time"
|
|
5
6
|
|
|
6
7
|
module Ndb
|
|
7
8
|
Page = Struct.new(:rows, :next_cursor, :plan, :examined, :total)
|
|
@@ -40,13 +41,19 @@ module Ndb
|
|
|
40
41
|
page(post(coll, "aggregate", Conditions.regexps(body)))
|
|
41
42
|
end
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
# expire_in (seconds, or "30m" / "1h" / "1d") sets the expires_field of
|
|
45
|
+
# every document to now + expire_in, in the same transaction.
|
|
46
|
+
def insert(coll, docs, expire_in: nil)
|
|
47
|
+
body = { insert: docs }
|
|
48
|
+
body[:expire_in] = expire_in if expire_in
|
|
49
|
+
|
|
50
|
+
json(post(coll, "insert", body)).fetch("results")
|
|
45
51
|
end
|
|
46
52
|
|
|
47
|
-
def update(coll, id, set: {}, unset: [], if_version: nil)
|
|
53
|
+
def update(coll, id, set: {}, unset: [], if_version: nil, expire_in: nil)
|
|
48
54
|
change = { id: id, set: set, unset: unset }
|
|
49
55
|
change[:if_version] = if_version if if_version
|
|
56
|
+
change[:expire_in] = expire_in if expire_in
|
|
50
57
|
|
|
51
58
|
json(post(coll, "update", update: change))
|
|
52
59
|
end
|
|
@@ -58,6 +65,33 @@ module Ndb
|
|
|
58
65
|
json(post(coll, "delete", delete: change))
|
|
59
66
|
end
|
|
60
67
|
|
|
68
|
+
# Makes a document expire, like EXPIRE in Redis: in: seconds or "30m", or
|
|
69
|
+
# at: a Time or an RFC 3339 String. Returns {"id", "v", "expires_at"}.
|
|
70
|
+
# Raises NotFound for a missing or expired document, TtlNotEnabled when
|
|
71
|
+
# the collection has no expires_field, TtlDerived when the expiry comes
|
|
72
|
+
# from ttl + time.
|
|
73
|
+
def expire(coll, id, if_version: nil, **time)
|
|
74
|
+
body = { id: id }
|
|
75
|
+
body[:in] = time[:in] if time[:in]
|
|
76
|
+
body[:at] = time[:at].respond_to?(:utc) ? time[:at].utc.iso8601(9) : time[:at] if time[:at]
|
|
77
|
+
body[:if_version] = if_version if if_version
|
|
78
|
+
|
|
79
|
+
json(post(coll, "expire", body))
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Removes the expiry of a document, like PERSIST in Redis.
|
|
83
|
+
def persist(coll, id)
|
|
84
|
+
json(post(coll, "persist", id: id))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# The seconds left of a document (an Integer, rounded up), -1 when it
|
|
88
|
+
# never expires, nil when it is missing or expired.
|
|
89
|
+
def ttl(coll, id)
|
|
90
|
+
json(request("GET", "#{path(coll)}/ttl/#{URI.encode_www_form_component(id).gsub('+', '%20')}", nil)).fetch("ttl")
|
|
91
|
+
rescue NotFound
|
|
92
|
+
nil
|
|
93
|
+
end
|
|
94
|
+
|
|
61
95
|
# Streams the changes of a collection for a named consumer: first the ones
|
|
62
96
|
# after its last ack, then the new ones. Yields one Hash per event (pos,
|
|
63
97
|
# op, id, v, doc). where is the same Hash/Range conditions as find, and
|
data/lib/ndb/errors.rb
CHANGED
|
@@ -33,6 +33,10 @@ module Ndb
|
|
|
33
33
|
class InvalidQuery < Error; end
|
|
34
34
|
class InvalidCursor < Error; end
|
|
35
35
|
|
|
36
|
+
# The collection has no expires_field, or its expiry comes from ttl + time.
|
|
37
|
+
class TtlNotEnabled < Error; end
|
|
38
|
+
class TtlDerived < Error; end
|
|
39
|
+
|
|
36
40
|
# The consumer was too slow: call watch again, it resumes from the last ack.
|
|
37
41
|
class WatchLagged < Error; end
|
|
38
42
|
|
|
@@ -58,7 +62,9 @@ module Ndb
|
|
|
58
62
|
"cursor_mismatch" => InvalidCursor,
|
|
59
63
|
"cursor_expired" => InvalidCursor,
|
|
60
64
|
"watch_lagged" => WatchLagged,
|
|
61
|
-
"history_truncated" => HistoryTruncated
|
|
65
|
+
"history_truncated" => HistoryTruncated,
|
|
66
|
+
"ttl_not_enabled" => TtlNotEnabled,
|
|
67
|
+
"ttl_derived" => TtlDerived
|
|
62
68
|
}.freeze
|
|
63
69
|
|
|
64
70
|
def self.error_for(code, message, status)
|
data/lib/ndb/version.rb
CHANGED