peak-sdk 1.16.1__py3-none-any.whl → 1.18.0__py3-none-any.whl
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.
- peak/_version.py +1 -1
- peak/cli/cli.py +2 -1
- peak/cli/helpers.py +1 -0
- peak/cli/metrics/metrics.py +104 -4
- peak/cli/resources/cache.py +452 -0
- peak/metrics/metrics.py +63 -3
- peak/resources/__init__.py +2 -1
- peak/resources/cache.py +650 -0
- peak/sample_yaml/metrics/publish.yaml +5 -0
- peak/sample_yaml/metrics/update-namespace.yaml +7 -0
- peak/tools/logging/logger.py +13 -6
- {peak_sdk-1.16.1.dist-info → peak_sdk-1.18.0.dist-info}/METADATA +4 -3
- {peak_sdk-1.16.1.dist-info → peak_sdk-1.18.0.dist-info}/RECORD +16 -13
- {peak_sdk-1.16.1.dist-info → peak_sdk-1.18.0.dist-info}/LICENSE +0 -0
- {peak_sdk-1.16.1.dist-info → peak_sdk-1.18.0.dist-info}/WHEEL +0 -0
- {peak_sdk-1.16.1.dist-info → peak_sdk-1.18.0.dist-info}/entry_points.txt +0 -0
peak/_version.py
CHANGED
peak/cli/cli.py
CHANGED
@@ -26,7 +26,7 @@ import typer
|
|
26
26
|
from peak.cli import args, helpers
|
27
27
|
from peak.cli.metrics import metrics
|
28
28
|
from peak.cli.press import apps, blocks, deployments, specs
|
29
|
-
from peak.cli.resources import alerts, artifacts, images, services, tenants, users, webapps, workflows
|
29
|
+
from peak.cli.resources import alerts, artifacts, cache, images, services, tenants, users, webapps, workflows
|
30
30
|
from peak.constants import Sources
|
31
31
|
from peak.output import Writer
|
32
32
|
|
@@ -38,6 +38,7 @@ typer_app.add_typer(images.app, name="images")
|
|
38
38
|
typer_app.add_typer(metrics.app, name="metrics")
|
39
39
|
typer_app.add_typer(alerts.app, name="alerts")
|
40
40
|
typer_app.add_typer(artifacts.app, name="artifacts")
|
41
|
+
typer_app.add_typer(cache.app, name="cache")
|
41
42
|
typer_app.add_typer(workflows.app, name="workflows")
|
42
43
|
typer_app.add_typer(webapps.app, name="webapps")
|
43
44
|
typer_app.add_typer(services.app, name="services")
|
peak/cli/helpers.py
CHANGED
@@ -251,6 +251,7 @@ def get_client(command: str) -> base_client.BaseClient:
|
|
251
251
|
"specs": press.specs,
|
252
252
|
"deployments": press.deployments,
|
253
253
|
"artifacts": resources.artifacts,
|
254
|
+
"cache": resources.cache,
|
254
255
|
"images": resources.images,
|
255
256
|
"workflows": resources.workflows,
|
256
257
|
"services": resources.services,
|
peak/cli/metrics/metrics.py
CHANGED
@@ -50,6 +50,16 @@ _NAMESPACE = typer.Option(
|
|
50
50
|
None,
|
51
51
|
help="The namespace associated with the metrics. If not provided, the default namespace is used.",
|
52
52
|
)
|
53
|
+
|
54
|
+
_NAMESPACE_DESCRIPTION = typer.Option(
|
55
|
+
None,
|
56
|
+
help="A description of the namespace.",
|
57
|
+
)
|
58
|
+
|
59
|
+
_NAMESPACE_METADATA = typer.Option(
|
60
|
+
None,
|
61
|
+
help="Key-value metadata associated with the namespace. Provide them in stringified JSON format.",
|
62
|
+
)
|
53
63
|
_GENERATE_SQL = typer.Option(
|
54
64
|
None,
|
55
65
|
help="Indicates whether to return the SQL query instead of data. If `true`, the response will include the SQL query used to retrieve the metrics. Default is `false`.",
|
@@ -70,6 +80,10 @@ _TIME_DIMENSIONS = typer.Option(
|
|
70
80
|
None,
|
71
81
|
help="An array of time dimensions to include in the query. Time dimensions allow querying over specific time ranges with optional granularity (e.g., day, month, year). Provide them in stringified JSON format.",
|
72
82
|
)
|
83
|
+
_SEARCH_TERM = typer.Option(
|
84
|
+
None,
|
85
|
+
help="A search term to filter the metrics. This can be used to search for specific metrics by name.",
|
86
|
+
)
|
73
87
|
_SEGMENTS = typer.Option(
|
74
88
|
None,
|
75
89
|
help="An array of segments to include in the query. Segments represent pre-defined filters that can be applied to metrics. Provide them in stringified JSON format.",
|
@@ -145,6 +159,7 @@ def publish(
|
|
145
159
|
params_file: str = args.TEMPLATE_PARAMS_FILE,
|
146
160
|
params: List[str] = args.TEMPLATE_PARAMS,
|
147
161
|
namespace: Optional[str] = _PUBLISH_NAMESPACE,
|
162
|
+
namespace_description: Optional[str] = _NAMESPACE_DESCRIPTION,
|
148
163
|
artifact_path: Optional[str] = _ARTIFACT_PATH,
|
149
164
|
collection_id: Optional[str] = _COLLECTION_ID,
|
150
165
|
dry_run: Optional[bool] = DRY_RUN, # noqa: ARG001
|
@@ -156,6 +171,7 @@ def publish(
|
|
156
171
|
The metrics can be published either by passing artifact and namespace,
|
157
172
|
or by passing collection_id and namespace. If both artifact and collection_id
|
158
173
|
are provided, artifact takes priority. If the namespace is not provided, the 'default' namespace is used.
|
174
|
+
Namespace metadata and Namespace description are optional.
|
159
175
|
|
160
176
|
\b
|
161
177
|
🧩 ***Input file schema(yaml):***<br/>
|
@@ -164,6 +180,9 @@ def publish(
|
|
164
180
|
```yaml
|
165
181
|
body (map):
|
166
182
|
namespace (str): The namespace associated with the metrics.
|
183
|
+
namespaceMetadata (map | required: false): Key-value metadata associated with the namespace.
|
184
|
+
namespaceDescription (str | required: false): A description of the namespace.
|
185
|
+
|
167
186
|
artifact (map):
|
168
187
|
path (str): Path to the artifact.
|
169
188
|
```
|
@@ -171,6 +190,9 @@ def publish(
|
|
171
190
|
```yaml
|
172
191
|
body (map):
|
173
192
|
namespace (str): The namespace associated with the metrics.
|
193
|
+
namespaceMetadata (map | required: false): Key-value metadata associated with the namespace.
|
194
|
+
namespaceDescription (str | required: false): A description of the namespace.
|
195
|
+
|
174
196
|
collectionId (str): The ID of the collection to publish the metrics.
|
175
197
|
```
|
176
198
|
|
@@ -186,9 +208,10 @@ def publish(
|
|
186
208
|
📝 ***Example usage without yaml:***
|
187
209
|
```bash
|
188
210
|
# Publish metrics using artifact and namespace
|
189
|
-
peak metrics publish --artifact-path <path> --namespace <namespace>
|
211
|
+
peak metrics publish --artifact-path <path> --namespace <namespace> --namespace-description "Metrics for pricing"
|
212
|
+
|
190
213
|
# Publish metrics using collection id and namespace
|
191
|
-
peak metrics publish --collection-id <collection-id> --namespace <namespace>
|
214
|
+
peak metrics publish --collection-id <collection-id> --namespace <namespace> --namespace-description "Metrics for pricing"
|
192
215
|
```
|
193
216
|
|
194
217
|
\b
|
@@ -208,6 +231,7 @@ def publish(
|
|
208
231
|
|
209
232
|
user_options: Dict[str, Any] = variables_to_dict(
|
210
233
|
namespace,
|
234
|
+
namespace_description,
|
211
235
|
)
|
212
236
|
|
213
237
|
body: Dict[str, Any] = {}
|
@@ -358,7 +382,9 @@ def list_metrics(
|
|
358
382
|
ctx: typer.Context,
|
359
383
|
page_size: Optional[int] = args.PAGE_SIZE,
|
360
384
|
page_number: Optional[int] = args.PAGE_NUMBER,
|
385
|
+
publication_id: Optional[str] = _PUBLICATION_ID,
|
361
386
|
namespace: Optional[str] = _NAMESPACE,
|
387
|
+
search_term: Optional[str] = _SEARCH_TERM,
|
362
388
|
type: Optional[str] = _METRIC_TYPES, # noqa: A002
|
363
389
|
paging: Optional[bool] = PAGING, # noqa: ARG001
|
364
390
|
output_type: Optional[OutputTypes] = OUTPUT_TYPES, # noqa: ARG001
|
@@ -368,7 +394,7 @@ def list_metrics(
|
|
368
394
|
\b
|
369
395
|
📝 ***Example usage:***<br/>
|
370
396
|
```bash
|
371
|
-
peak metrics list --page-size 25 --page-number 1 --namespace <namespace> --type <type>
|
397
|
+
peak metrics list --page-size 25 --page-number 1 --namespace <namespace> --type <type> --search-term <search_term> --publication-id <publication_id>
|
372
398
|
```
|
373
399
|
|
374
400
|
\b
|
@@ -429,11 +455,12 @@ def list_metrics(
|
|
429
455
|
response = metric_client.list(
|
430
456
|
page_size=page_size,
|
431
457
|
page_number=page_number,
|
458
|
+
publication_id=publication_id,
|
432
459
|
namespace=namespace,
|
460
|
+
search_term=search_term,
|
433
461
|
type=type,
|
434
462
|
return_iterator=False,
|
435
463
|
)
|
436
|
-
|
437
464
|
writer.write(response)
|
438
465
|
|
439
466
|
|
@@ -676,6 +703,11 @@ def list_namespaces(
|
|
676
703
|
{
|
677
704
|
"namespaces": [
|
678
705
|
{
|
706
|
+
"description": "Default namespace",
|
707
|
+
"metadata": {
|
708
|
+
"owner": "abc",
|
709
|
+
"environment": "development"
|
710
|
+
},
|
679
711
|
"name": "default",
|
680
712
|
"models": [
|
681
713
|
{
|
@@ -705,3 +737,71 @@ def list_namespaces(
|
|
705
737
|
return_iterator=False,
|
706
738
|
)
|
707
739
|
writer.write(response)
|
740
|
+
|
741
|
+
|
742
|
+
@app.command(short_help="Update a namespace.")
|
743
|
+
def update_namespace(
|
744
|
+
ctx: typer.Context,
|
745
|
+
file: Annotated[
|
746
|
+
Optional[str],
|
747
|
+
typer.Argument(
|
748
|
+
...,
|
749
|
+
help="Path to the file that defines the body for this operation, supports both `yaml` file or a `jinja` template.",
|
750
|
+
),
|
751
|
+
] = None,
|
752
|
+
params_file: Optional[str] = args.TEMPLATE_PARAMS_FILE,
|
753
|
+
params: Optional[List[str]] = args.TEMPLATE_PARAMS,
|
754
|
+
namespace: Optional[str] = typer.Option(None, help="The name of the namespace to update."),
|
755
|
+
description: Optional[str] = _NAMESPACE_DESCRIPTION,
|
756
|
+
dry_run: Optional[bool] = DRY_RUN, # noqa: ARG001
|
757
|
+
output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
|
758
|
+
) -> None:
|
759
|
+
"""***Update*** a namespace with a new description and metadata.
|
760
|
+
|
761
|
+
\b
|
762
|
+
📝 ***Example usage:***
|
763
|
+
```bash
|
764
|
+
peak metrics update-namespace update-namespace.yaml --namespace new_namespace --description "Updated description"
|
765
|
+
```
|
766
|
+
|
767
|
+
\b
|
768
|
+
🆗 ***Response:***
|
769
|
+
```json
|
770
|
+
{
|
771
|
+
"namespace": "new_namespace",
|
772
|
+
"description": "Updated description",
|
773
|
+
"message": "Updated namespace new_namespace",
|
774
|
+
"metadata": {
|
775
|
+
"key": "value"
|
776
|
+
}
|
777
|
+
}
|
778
|
+
```
|
779
|
+
"""
|
780
|
+
metrics_client: Metric = ctx.obj["client"]
|
781
|
+
writer: Writer = ctx.obj["writer"]
|
782
|
+
|
783
|
+
body: Dict[str, Any] = {}
|
784
|
+
if file:
|
785
|
+
body = helpers.template_handler(file=file, params_file=params_file, params=params)
|
786
|
+
|
787
|
+
cli_options: Dict[str, Any] = variables_to_dict(
|
788
|
+
namespace,
|
789
|
+
description,
|
790
|
+
)
|
791
|
+
|
792
|
+
updated_body = combine_dictionaries(body or {}, cli_options)
|
793
|
+
|
794
|
+
if not updated_body.get("namespace") and not namespace:
|
795
|
+
error_message = "Namespace must be provided either through file or CLI option."
|
796
|
+
raise typer.BadParameter(error_message)
|
797
|
+
|
798
|
+
final_namespace = updated_body.pop("namespace", namespace)
|
799
|
+
metadata = updated_body.get("metadata")
|
800
|
+
|
801
|
+
with writer.pager():
|
802
|
+
response = metrics_client.update_namespace(
|
803
|
+
namespace=final_namespace,
|
804
|
+
description=updated_body.get("description"),
|
805
|
+
metadata=metadata,
|
806
|
+
)
|
807
|
+
writer.write(response)
|
@@ -0,0 +1,452 @@
|
|
1
|
+
#
|
2
|
+
# # Copyright © 2025 Peak AI Limited. or its affiliates. All Rights Reserved.
|
3
|
+
# #
|
4
|
+
# # Licensed under the Apache License, Version 2.0 (the "License"). You
|
5
|
+
# # may not use this file except in compliance with the License. A copy of
|
6
|
+
# # the License is located at:
|
7
|
+
# #
|
8
|
+
# # https://github.com/PeakBI/peak-sdk/blob/main/LICENSE
|
9
|
+
# #
|
10
|
+
# # or in the "license" file accompanying this file. This file is
|
11
|
+
# # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
12
|
+
# # ANY KIND, either express or implied. See the License for the specific
|
13
|
+
# # language governing permissions and limitations under the License.
|
14
|
+
# #
|
15
|
+
# # This file is part of the peak-sdk.
|
16
|
+
# # see (https://github.com/PeakBI/peak-sdk)
|
17
|
+
# #
|
18
|
+
# # You should have received a copy of the APACHE LICENSE, VERSION 2.0
|
19
|
+
# # along with this program. If not, see <https://apache.org/licenses/LICENSE-2.0>
|
20
|
+
#
|
21
|
+
"""Peak Cache commands."""
|
22
|
+
import json
|
23
|
+
from typing import Any, Dict, Optional
|
24
|
+
|
25
|
+
import typer
|
26
|
+
from peak.cli.args import OUTPUT_TYPES, PAGING
|
27
|
+
from peak.constants import OutputTypes, OutputTypesNoTable
|
28
|
+
from peak.output import Writer
|
29
|
+
from peak.resources.cache import CacheClient
|
30
|
+
|
31
|
+
app = typer.Typer(
|
32
|
+
help="Cache operations for storing and retrieving data.",
|
33
|
+
short_help="Manage Cache Operations.",
|
34
|
+
)
|
35
|
+
|
36
|
+
_KEY = typer.Option(..., help="The cache key to operate on.")
|
37
|
+
_VALUE = typer.Option(..., help="The value to store in the cache.")
|
38
|
+
_TTL = typer.Option(None, help="Time to live in seconds for the cache entry.")
|
39
|
+
_DEFAULT = typer.Option(None, help="Default value to return if key doesn't exist.")
|
40
|
+
_KEYS = typer.Option(..., help="Comma-separated list of keys to operate on.")
|
41
|
+
_MAPPING = typer.Option(..., help="JSON mapping of key-value pairs to store.")
|
42
|
+
_PATTERN = typer.Option(..., help="Pattern to match keys for deletion.")
|
43
|
+
_DEBUG = typer.Option(False, help="Enable debug logging.")
|
44
|
+
_PREFIX = typer.Option(None, help="Additional prefix for cache keys.")
|
45
|
+
|
46
|
+
|
47
|
+
def _parse_json_mapping(mapping: str) -> Dict[str, Any]:
|
48
|
+
"""Parse and validate JSON mapping for mset command.
|
49
|
+
|
50
|
+
Args:
|
51
|
+
mapping: JSON string to parse
|
52
|
+
|
53
|
+
Returns:
|
54
|
+
Parsed dictionary
|
55
|
+
|
56
|
+
Raises:
|
57
|
+
typer.BadParameter: If mapping is invalid
|
58
|
+
TypeError: If mapping is not a JSON object
|
59
|
+
"""
|
60
|
+
parsed_mapping = json.loads(mapping)
|
61
|
+
if not isinstance(parsed_mapping, dict):
|
62
|
+
msg = "Mapping must be a JSON object"
|
63
|
+
raise TypeError(msg)
|
64
|
+
return parsed_mapping
|
65
|
+
|
66
|
+
|
67
|
+
@app.command("set", short_help="Store a value in the cache.")
|
68
|
+
def set_value(
|
69
|
+
ctx: typer.Context,
|
70
|
+
key: str = _KEY,
|
71
|
+
value: str = _VALUE,
|
72
|
+
ttl: Optional[int] = _TTL,
|
73
|
+
_debug: bool = _DEBUG,
|
74
|
+
prefix: Optional[str] = _PREFIX,
|
75
|
+
_paging: Optional[bool] = PAGING,
|
76
|
+
_output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,
|
77
|
+
) -> None:
|
78
|
+
"""Store a value in the cache with an optional TTL.
|
79
|
+
|
80
|
+
\b
|
81
|
+
📝 ***Example usage:***
|
82
|
+
```bash
|
83
|
+
peak cache set --key "user:123" --value "John Doe"
|
84
|
+
peak cache set --key "config" --value '{"timeout": 30}' --ttl 3600
|
85
|
+
```
|
86
|
+
|
87
|
+
\b
|
88
|
+
🆗 ***Response:***
|
89
|
+
True if the value was stored successfully, False otherwise.
|
90
|
+
"""
|
91
|
+
client: CacheClient = ctx.obj["client"]
|
92
|
+
writer: Writer = ctx.obj["writer"]
|
93
|
+
|
94
|
+
if prefix:
|
95
|
+
client.set_additional_prefix(prefix)
|
96
|
+
|
97
|
+
try:
|
98
|
+
parsed_value = json.loads(value)
|
99
|
+
except json.JSONDecodeError:
|
100
|
+
parsed_value = value
|
101
|
+
|
102
|
+
with writer.pager():
|
103
|
+
result = client.set(key, parsed_value, ttl=ttl)
|
104
|
+
writer.write(result, output_type=OutputTypes.json)
|
105
|
+
|
106
|
+
|
107
|
+
@app.command(short_help="Retrieve a value from the cache.")
|
108
|
+
def get(
|
109
|
+
ctx: typer.Context,
|
110
|
+
key: str = _KEY,
|
111
|
+
default: Optional[str] = _DEFAULT,
|
112
|
+
_debug: bool = _DEBUG,
|
113
|
+
prefix: Optional[str] = _PREFIX,
|
114
|
+
_paging: Optional[bool] = PAGING,
|
115
|
+
_output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,
|
116
|
+
) -> None:
|
117
|
+
"""Retrieve a value from the cache.
|
118
|
+
|
119
|
+
\b
|
120
|
+
📝 ***Example usage:***
|
121
|
+
```bash
|
122
|
+
peak cache get --key "user:123"
|
123
|
+
peak cache get --key "missing" --default "not found"
|
124
|
+
```
|
125
|
+
|
126
|
+
\b
|
127
|
+
🆗 ***Response:***
|
128
|
+
The cached value or the default value if the key doesn't exist.
|
129
|
+
"""
|
130
|
+
client: CacheClient = ctx.obj["client"]
|
131
|
+
writer: Writer = ctx.obj["writer"]
|
132
|
+
|
133
|
+
if prefix:
|
134
|
+
client.set_additional_prefix(prefix)
|
135
|
+
|
136
|
+
parsed_default = None
|
137
|
+
if default is not None:
|
138
|
+
try:
|
139
|
+
parsed_default = json.loads(default)
|
140
|
+
except json.JSONDecodeError:
|
141
|
+
parsed_default = default
|
142
|
+
|
143
|
+
with writer.pager():
|
144
|
+
result = client.get(key, default=parsed_default)
|
145
|
+
writer.write(result, output_type=OutputTypes.json)
|
146
|
+
|
147
|
+
|
148
|
+
@app.command(short_help="Retrieve multiple values from the cache.")
|
149
|
+
def mget(
|
150
|
+
ctx: typer.Context,
|
151
|
+
keys: str = _KEYS,
|
152
|
+
_debug: bool = _DEBUG,
|
153
|
+
prefix: Optional[str] = _PREFIX,
|
154
|
+
_paging: Optional[bool] = PAGING,
|
155
|
+
_output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,
|
156
|
+
) -> None:
|
157
|
+
"""Retrieve multiple values from the cache.
|
158
|
+
|
159
|
+
\b
|
160
|
+
📝 ***Example usage:***
|
161
|
+
```bash
|
162
|
+
peak cache mget --keys "user:123,user:456,config"
|
163
|
+
peak cache mget --keys "session:abc,session:def"
|
164
|
+
```
|
165
|
+
|
166
|
+
\b
|
167
|
+
🆗 ***Response:***
|
168
|
+
List of values corresponding to the keys (null for non-existent keys).
|
169
|
+
"""
|
170
|
+
client: CacheClient = ctx.obj["client"]
|
171
|
+
writer: Writer = ctx.obj["writer"]
|
172
|
+
|
173
|
+
if prefix:
|
174
|
+
client.set_additional_prefix(prefix)
|
175
|
+
|
176
|
+
key_list = [key.strip() for key in keys.split(",")]
|
177
|
+
|
178
|
+
with writer.pager():
|
179
|
+
result = client.mget(*key_list)
|
180
|
+
writer.write(result, output_type=OutputTypes.json)
|
181
|
+
|
182
|
+
|
183
|
+
@app.command(short_help="Store multiple key-value pairs in the cache.")
|
184
|
+
def mset(
|
185
|
+
ctx: typer.Context,
|
186
|
+
mapping: str = _MAPPING,
|
187
|
+
ttl: Optional[int] = _TTL,
|
188
|
+
_debug: bool = _DEBUG,
|
189
|
+
prefix: Optional[str] = _PREFIX,
|
190
|
+
_paging: Optional[bool] = PAGING,
|
191
|
+
_output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,
|
192
|
+
) -> None:
|
193
|
+
"""Store multiple key-value pairs in the cache.
|
194
|
+
|
195
|
+
\b
|
196
|
+
📝 ***Example usage:***
|
197
|
+
```bash
|
198
|
+
peak cache mset --mapping '{"user:123": "John", "user:456": "Jane"}'
|
199
|
+
peak cache mset --mapping '{"config:timeout": 30, "config:retries": 3}' --ttl 3600
|
200
|
+
```
|
201
|
+
|
202
|
+
\b
|
203
|
+
🆗 ***Response:***
|
204
|
+
True if all values were stored successfully, False otherwise.
|
205
|
+
"""
|
206
|
+
client: CacheClient = ctx.obj["client"]
|
207
|
+
writer: Writer = ctx.obj["writer"]
|
208
|
+
|
209
|
+
if prefix:
|
210
|
+
client.set_additional_prefix(prefix)
|
211
|
+
|
212
|
+
try:
|
213
|
+
parsed_mapping = _parse_json_mapping(mapping)
|
214
|
+
except (json.JSONDecodeError, ValueError, TypeError) as e:
|
215
|
+
msg = f"Invalid JSON mapping: {e}"
|
216
|
+
raise typer.BadParameter(msg) from e
|
217
|
+
|
218
|
+
with writer.pager():
|
219
|
+
result = client.mset(parsed_mapping, ttl=ttl)
|
220
|
+
writer.write(result, output_type=OutputTypes.json)
|
221
|
+
|
222
|
+
|
223
|
+
@app.command(short_help="Delete one or more keys from the cache.")
|
224
|
+
def delete(
|
225
|
+
ctx: typer.Context,
|
226
|
+
keys: str = _KEYS,
|
227
|
+
_debug: bool = _DEBUG,
|
228
|
+
prefix: Optional[str] = _PREFIX,
|
229
|
+
_paging: Optional[bool] = PAGING,
|
230
|
+
_output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,
|
231
|
+
) -> None:
|
232
|
+
"""Delete one or more keys from the cache.
|
233
|
+
|
234
|
+
\b
|
235
|
+
📝 ***Example usage:***
|
236
|
+
```bash
|
237
|
+
peak cache delete --keys "user:123"
|
238
|
+
peak cache delete --keys "user:123,user:456,config"
|
239
|
+
```
|
240
|
+
|
241
|
+
\b
|
242
|
+
🆗 ***Response:***
|
243
|
+
Number of keys that were deleted.
|
244
|
+
"""
|
245
|
+
client: CacheClient = ctx.obj["client"]
|
246
|
+
writer: Writer = ctx.obj["writer"]
|
247
|
+
|
248
|
+
if prefix:
|
249
|
+
client.set_additional_prefix(prefix)
|
250
|
+
|
251
|
+
key_list = [key.strip() for key in keys.split(",")]
|
252
|
+
|
253
|
+
with writer.pager():
|
254
|
+
result = client.delete(*key_list)
|
255
|
+
writer.write(result, output_type=OutputTypes.json)
|
256
|
+
|
257
|
+
|
258
|
+
@app.command(short_help="Check if one or more keys exist in the cache.")
|
259
|
+
def exists(
|
260
|
+
ctx: typer.Context,
|
261
|
+
keys: str = _KEYS,
|
262
|
+
_debug: bool = _DEBUG,
|
263
|
+
prefix: Optional[str] = _PREFIX,
|
264
|
+
_paging: Optional[bool] = PAGING,
|
265
|
+
_output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,
|
266
|
+
) -> None:
|
267
|
+
"""Check if one or more keys exist in the cache.
|
268
|
+
|
269
|
+
\b
|
270
|
+
📝 ***Example usage:***
|
271
|
+
```bash
|
272
|
+
peak cache exists --keys "user:123"
|
273
|
+
peak cache exists --keys "user:123,user:456"
|
274
|
+
```
|
275
|
+
|
276
|
+
\b
|
277
|
+
🆗 ***Response:***
|
278
|
+
Number of keys that exist in the cache.
|
279
|
+
"""
|
280
|
+
client: CacheClient = ctx.obj["client"]
|
281
|
+
writer: Writer = ctx.obj["writer"]
|
282
|
+
|
283
|
+
if prefix:
|
284
|
+
client.set_additional_prefix(prefix)
|
285
|
+
|
286
|
+
key_list = [key.strip() for key in keys.split(",")]
|
287
|
+
|
288
|
+
with writer.pager():
|
289
|
+
result = client.exists(*key_list)
|
290
|
+
writer.write(result, output_type=OutputTypes.json)
|
291
|
+
|
292
|
+
|
293
|
+
@app.command(short_help="Set expiration time for a key.")
|
294
|
+
def expire(
|
295
|
+
ctx: typer.Context,
|
296
|
+
key: str = _KEY,
|
297
|
+
ttl: int = typer.Option(..., help="Time to live in seconds."),
|
298
|
+
_debug: bool = _DEBUG,
|
299
|
+
prefix: Optional[str] = _PREFIX,
|
300
|
+
_paging: Optional[bool] = PAGING,
|
301
|
+
_output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,
|
302
|
+
) -> None:
|
303
|
+
"""Set expiration time for a key.
|
304
|
+
|
305
|
+
\b
|
306
|
+
📝 ***Example usage:***
|
307
|
+
```bash
|
308
|
+
peak cache expire --key "user:123" --ttl 3600
|
309
|
+
peak cache expire --key "session:abc" --ttl 1800
|
310
|
+
```
|
311
|
+
|
312
|
+
\b
|
313
|
+
🆗 ***Response:***
|
314
|
+
True if the expiration was set, False if the key doesn't exist.
|
315
|
+
"""
|
316
|
+
client: CacheClient = ctx.obj["client"]
|
317
|
+
writer: Writer = ctx.obj["writer"]
|
318
|
+
|
319
|
+
if prefix:
|
320
|
+
client.set_additional_prefix(prefix)
|
321
|
+
|
322
|
+
with writer.pager():
|
323
|
+
result = client.expire(key, ttl)
|
324
|
+
writer.write(result, output_type=OutputTypes.json)
|
325
|
+
|
326
|
+
|
327
|
+
@app.command(short_help="Get the remaining time to live for a key.")
|
328
|
+
def ttl(
|
329
|
+
ctx: typer.Context,
|
330
|
+
key: str = _KEY,
|
331
|
+
_debug: bool = _DEBUG,
|
332
|
+
prefix: Optional[str] = _PREFIX,
|
333
|
+
_paging: Optional[bool] = PAGING,
|
334
|
+
_output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,
|
335
|
+
) -> None:
|
336
|
+
"""Get the remaining time to live for a key.
|
337
|
+
|
338
|
+
\b
|
339
|
+
📝 ***Example usage:***
|
340
|
+
```bash
|
341
|
+
peak cache ttl --key "user:123"
|
342
|
+
peak cache ttl --key "session:abc"
|
343
|
+
```
|
344
|
+
|
345
|
+
\b
|
346
|
+
🆗 ***Response:***
|
347
|
+
Remaining TTL in seconds (-1 if no expiration, -2 if key doesn't exist).
|
348
|
+
"""
|
349
|
+
client: CacheClient = ctx.obj["client"]
|
350
|
+
writer: Writer = ctx.obj["writer"]
|
351
|
+
|
352
|
+
if prefix:
|
353
|
+
client.set_additional_prefix(prefix)
|
354
|
+
|
355
|
+
with writer.pager():
|
356
|
+
result = client.ttl(key)
|
357
|
+
writer.write(result, output_type=OutputTypes.json)
|
358
|
+
|
359
|
+
|
360
|
+
@app.command(short_help="Test cache connection.")
|
361
|
+
def ping(
|
362
|
+
ctx: typer.Context,
|
363
|
+
_debug: bool = _DEBUG,
|
364
|
+
prefix: Optional[str] = _PREFIX,
|
365
|
+
_paging: Optional[bool] = PAGING,
|
366
|
+
_output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,
|
367
|
+
) -> None:
|
368
|
+
"""Test cache connection.
|
369
|
+
|
370
|
+
\b
|
371
|
+
📝 ***Example usage:***
|
372
|
+
```bash
|
373
|
+
peak cache ping
|
374
|
+
```
|
375
|
+
|
376
|
+
\b
|
377
|
+
🆗 ***Response:***
|
378
|
+
True if the connection is successful, False otherwise.
|
379
|
+
"""
|
380
|
+
client: CacheClient = ctx.obj["client"]
|
381
|
+
writer: Writer = ctx.obj["writer"]
|
382
|
+
|
383
|
+
if prefix:
|
384
|
+
client.set_additional_prefix(prefix)
|
385
|
+
|
386
|
+
with writer.pager():
|
387
|
+
result = client.ping()
|
388
|
+
writer.write(result, output_type=OutputTypes.json)
|
389
|
+
|
390
|
+
|
391
|
+
@app.command(short_help="Delete all keys matching a pattern.")
|
392
|
+
def flush_pattern(
|
393
|
+
ctx: typer.Context,
|
394
|
+
pattern: str = _PATTERN,
|
395
|
+
_debug: bool = _DEBUG,
|
396
|
+
prefix: Optional[str] = _PREFIX,
|
397
|
+
_paging: Optional[bool] = PAGING,
|
398
|
+
_output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,
|
399
|
+
) -> None:
|
400
|
+
"""Delete all keys matching a pattern within the tenant namespace.
|
401
|
+
|
402
|
+
\b
|
403
|
+
📝 ***Example usage:***
|
404
|
+
```bash
|
405
|
+
peak cache flush-pattern --pattern "user:*"
|
406
|
+
peak cache flush-pattern --pattern "session:*"
|
407
|
+
```
|
408
|
+
|
409
|
+
\b
|
410
|
+
🆗 ***Response:***
|
411
|
+
Number of keys that were deleted.
|
412
|
+
"""
|
413
|
+
client: CacheClient = ctx.obj["client"]
|
414
|
+
writer: Writer = ctx.obj["writer"]
|
415
|
+
|
416
|
+
if prefix:
|
417
|
+
client.set_additional_prefix(prefix)
|
418
|
+
|
419
|
+
with writer.pager():
|
420
|
+
result = client.flush_by_pattern(pattern)
|
421
|
+
writer.write(result, output_type=OutputTypes.json)
|
422
|
+
|
423
|
+
|
424
|
+
@app.command(short_help="Delete all keys for the current tenant.")
|
425
|
+
def flush_tenant(
|
426
|
+
ctx: typer.Context,
|
427
|
+
_debug: bool = _DEBUG,
|
428
|
+
prefix: Optional[str] = _PREFIX,
|
429
|
+
_paging: Optional[bool] = PAGING,
|
430
|
+
_output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES,
|
431
|
+
) -> None:
|
432
|
+
"""Delete all keys for the current tenant.
|
433
|
+
|
434
|
+
\b
|
435
|
+
📝 ***Example usage:***
|
436
|
+
```bash
|
437
|
+
peak cache flush-tenant
|
438
|
+
```
|
439
|
+
|
440
|
+
\b
|
441
|
+
🆗 ***Response:***
|
442
|
+
Number of keys that were deleted.
|
443
|
+
"""
|
444
|
+
client: CacheClient = ctx.obj["client"]
|
445
|
+
writer: Writer = ctx.obj["writer"]
|
446
|
+
|
447
|
+
if prefix:
|
448
|
+
client.set_additional_prefix(prefix)
|
449
|
+
|
450
|
+
with writer.pager():
|
451
|
+
result = client.flush_tenant()
|
452
|
+
writer.write(result, output_type=OutputTypes.json)
|