@chrismo/superkit 1.0.0
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.
- package/LICENSE.txt +29 -0
- package/README.md +26 -0
- package/dist/cli/pager.d.ts +6 -0
- package/dist/cli/pager.d.ts.map +1 -0
- package/dist/cli/pager.js +21 -0
- package/dist/cli/pager.js.map +1 -0
- package/dist/cli/skdoc.d.ts +3 -0
- package/dist/cli/skdoc.d.ts.map +1 -0
- package/dist/cli/skdoc.js +42 -0
- package/dist/cli/skdoc.js.map +1 -0
- package/dist/cli/skgrok.d.ts +3 -0
- package/dist/cli/skgrok.d.ts.map +1 -0
- package/dist/cli/skgrok.js +21 -0
- package/dist/cli/skgrok.js.map +1 -0
- package/dist/cli/skops.d.ts +3 -0
- package/dist/cli/skops.d.ts.map +1 -0
- package/dist/cli/skops.js +32 -0
- package/dist/cli/skops.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/docs.d.ts +11 -0
- package/dist/lib/docs.d.ts.map +1 -0
- package/dist/lib/docs.js +29 -0
- package/dist/lib/docs.js.map +1 -0
- package/dist/lib/expert-sections.d.ts +32 -0
- package/dist/lib/expert-sections.d.ts.map +1 -0
- package/dist/lib/expert-sections.js +130 -0
- package/dist/lib/expert-sections.js.map +1 -0
- package/dist/lib/grok.d.ts +15 -0
- package/dist/lib/grok.d.ts.map +1 -0
- package/dist/lib/grok.js +57 -0
- package/dist/lib/grok.js.map +1 -0
- package/dist/lib/help.d.ts +20 -0
- package/dist/lib/help.d.ts.map +1 -0
- package/dist/lib/help.js +163 -0
- package/dist/lib/help.js.map +1 -0
- package/dist/lib/recipes.d.ts +29 -0
- package/dist/lib/recipes.d.ts.map +1 -0
- package/dist/lib/recipes.js +133 -0
- package/dist/lib/recipes.js.map +1 -0
- package/dist/superkit.tar.gz +0 -0
- package/docs/grok-patterns.sup +89 -0
- package/docs/recipes/array.md +66 -0
- package/docs/recipes/array.spq +31 -0
- package/docs/recipes/character.md +110 -0
- package/docs/recipes/character.spq +57 -0
- package/docs/recipes/escape.md +159 -0
- package/docs/recipes/escape.spq +102 -0
- package/docs/recipes/format.md +51 -0
- package/docs/recipes/format.spq +24 -0
- package/docs/recipes/index.md +23 -0
- package/docs/recipes/integer.md +101 -0
- package/docs/recipes/integer.spq +53 -0
- package/docs/recipes/records.md +84 -0
- package/docs/recipes/records.spq +61 -0
- package/docs/recipes/string.md +177 -0
- package/docs/recipes/string.spq +105 -0
- package/docs/superdb-expert.md +929 -0
- package/docs/tutorials/bash_to_sup.md +123 -0
- package/docs/tutorials/chess-tiebreaks.md +233 -0
- package/docs/tutorials/debug.md +439 -0
- package/docs/tutorials/fork_for_window.md +296 -0
- package/docs/tutorials/grok.md +166 -0
- package/docs/tutorials/index.md +10 -0
- package/docs/tutorials/joins.md +79 -0
- package/docs/tutorials/moar_subqueries.md +35 -0
- package/docs/tutorials/subqueries.md +236 -0
- package/docs/tutorials/sup_to_bash.md +164 -0
- package/docs/tutorials/super_db_update.md +34 -0
- package/docs/tutorials/unnest.md +113 -0
- package/docs/zq-to-super-upgrades.md +549 -0
- package/package.json +46 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
-- sk_include string.spq
|
|
2
|
+
|
|
3
|
+
op skdoc_seq: (
|
|
4
|
+
cast(
|
|
5
|
+
{name:"sk_seq",
|
|
6
|
+
type:"op",
|
|
7
|
+
desc:"Generates a sequence 0..n-1 (like generate_series).",
|
|
8
|
+
args:[{name:"n",desc:"Number of elements to generate"}],
|
|
9
|
+
examples:[{i:"sk_seq(3)",o:"0, 1, 2"}] }, <skdoc>)
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
op sk_seq(n): (
|
|
13
|
+
split(sk_pad_left('', '0', n), '')
|
|
14
|
+
| unnest this
|
|
15
|
+
| count
|
|
16
|
+
| values count - 1
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
fn skdoc_hex_digits(): (
|
|
20
|
+
cast(
|
|
21
|
+
{name:"sk_hex_digits",
|
|
22
|
+
type:"func",
|
|
23
|
+
desc:"Returns the 16 hex digit characters as an array.",
|
|
24
|
+
args:[],
|
|
25
|
+
examples:[] }, <skdoc>)
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
fn sk_hex_digits(): (
|
|
29
|
+
split("0123456789abcdef", "")
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
fn skdoc_chr(): (
|
|
33
|
+
cast(
|
|
34
|
+
{name:"sk_chr",
|
|
35
|
+
type:"func",
|
|
36
|
+
desc:"Converts an integer (0-127) to its ASCII character.",
|
|
37
|
+
args:[{name:"code",desc:"ASCII code (0-127)"}],
|
|
38
|
+
examples:[{i:"sk_chr(65)",o:"'A'"}] }, <skdoc>)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
fn sk_chr(code): (
|
|
42
|
+
let d = sk_hex_digits() |
|
|
43
|
+
hex(f'{d[code/16]}{d[code%16]}')::string
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
fn skdoc_alpha(): (
|
|
47
|
+
cast(
|
|
48
|
+
{name:"sk_alpha",
|
|
49
|
+
type:"func",
|
|
50
|
+
desc:"Converts 1-26 to A-Z.",
|
|
51
|
+
args:[{name:"n",desc:"Number 1-26"}],
|
|
52
|
+
examples:[{i:"sk_alpha(3)",o:"'C'"}] }, <skdoc>)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
fn sk_alpha(n): (
|
|
56
|
+
sk_chr(64 + n)
|
|
57
|
+
)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Escape
|
|
3
|
+
layout: default
|
|
4
|
+
nav_order: 7
|
|
5
|
+
parent: Recipes
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Escape Recipes
|
|
9
|
+
|
|
10
|
+
Source: `escape.spq`
|
|
11
|
+
|
|
12
|
+
Functions for safely escaping values for CSV, TSV, and shell contexts, plus
|
|
13
|
+
patterns for safe text ingestion from shell pipelines.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## sk_csv_field
|
|
18
|
+
|
|
19
|
+
Escapes a string for use as a CSV field per RFC 4180. Wraps in double quotes
|
|
20
|
+
and doubles internal quotes when the value contains commas, quotes, or
|
|
21
|
+
newlines. Plain values pass through unchanged.
|
|
22
|
+
|
|
23
|
+
**Type:** function
|
|
24
|
+
|
|
25
|
+
| Argument | Description |
|
|
26
|
+
|----------|-------------|
|
|
27
|
+
| `s` | The string to escape |
|
|
28
|
+
|
|
29
|
+
```supersql
|
|
30
|
+
sk_csv_field('plain')
|
|
31
|
+
-- => 'plain'
|
|
32
|
+
|
|
33
|
+
sk_csv_field('hello, world')
|
|
34
|
+
-- => quoted and wrapped
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Implementation:**
|
|
38
|
+
|
|
39
|
+
```supersql
|
|
40
|
+
fn sk_csv_field(s): (
|
|
41
|
+
grep("[,\"\n]", s)
|
|
42
|
+
? f"\"{replace(s, "\"", "\"\"")}\""
|
|
43
|
+
: s
|
|
44
|
+
)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## sk_csv_row
|
|
50
|
+
|
|
51
|
+
Builds a CSV row from an array of values. Each element is cast to string and
|
|
52
|
+
escaped with sk_csv_field, then joined with commas.
|
|
53
|
+
|
|
54
|
+
**Type:** function
|
|
55
|
+
|
|
56
|
+
| Argument | Description |
|
|
57
|
+
|----------|-------------|
|
|
58
|
+
| `arr` | Array of values to format as a CSV row |
|
|
59
|
+
|
|
60
|
+
**Implementation:**
|
|
61
|
+
|
|
62
|
+
```supersql
|
|
63
|
+
fn sk_csv_row(arr): (
|
|
64
|
+
join([unnest arr | values sk_csv_field(cast(this, <string>))], ",")
|
|
65
|
+
)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## sk_shell_quote
|
|
71
|
+
|
|
72
|
+
Wraps a string in POSIX shell single quotes. Internal single quotes are escaped
|
|
73
|
+
so the result is safe for shell interpolation. Protects against injection of `$`,
|
|
74
|
+
backticks, and other shell metacharacters.
|
|
75
|
+
|
|
76
|
+
**Type:** function
|
|
77
|
+
|
|
78
|
+
| Argument | Description |
|
|
79
|
+
|----------|-------------|
|
|
80
|
+
| `s` | The string to quote |
|
|
81
|
+
|
|
82
|
+
```supersql
|
|
83
|
+
sk_shell_quote('hello world')
|
|
84
|
+
-- => single-quoted string
|
|
85
|
+
|
|
86
|
+
sk_shell_quote('has $var')
|
|
87
|
+
-- => single-quoted, $ not expanded
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Implementation:**
|
|
91
|
+
|
|
92
|
+
```supersql
|
|
93
|
+
fn sk_shell_quote(s): (
|
|
94
|
+
f"'{replace(s, "'", "'\\''")}'"
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## sk_tsv_field
|
|
101
|
+
|
|
102
|
+
Escapes a value for use in a TSV field. Casts to string, then replaces literal
|
|
103
|
+
tab and newline characters with their backslash-escaped forms.
|
|
104
|
+
|
|
105
|
+
**Type:** function
|
|
106
|
+
|
|
107
|
+
| Argument | Description |
|
|
108
|
+
|----------|-------------|
|
|
109
|
+
| `s` | The value to escape |
|
|
110
|
+
|
|
111
|
+
**Implementation:**
|
|
112
|
+
|
|
113
|
+
```supersql
|
|
114
|
+
fn sk_tsv_field(s): (
|
|
115
|
+
replace(replace(cast(s, <string>), "\t", "\\t"), "\n", "\\n")
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Shell Patterns for Safe Text Ingestion
|
|
122
|
+
|
|
123
|
+
The key insight: never interpolate untrusted text into a SuperQL string literal.
|
|
124
|
+
Pipe raw text through `super` with `-i line` and let the serializer handle
|
|
125
|
+
escaping. These patterns work from any language that can spawn a subprocess.
|
|
126
|
+
|
|
127
|
+
### safe_text_to_record
|
|
128
|
+
|
|
129
|
+
Pipe raw text into super to build a record without string interpolation.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
echo "$text" | super -s -i line -c "values {body: this}" -
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### safe_text_to_string
|
|
136
|
+
|
|
137
|
+
Pipe raw text through super to get a properly escaped SUP string literal.
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
echo "$text" | super -s -i line -c "values this" -
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### safe_multiline_to_record
|
|
144
|
+
|
|
145
|
+
Collapse multiline text into a single record field.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
echo "$text" | super -s -i line \
|
|
149
|
+
-c 'aggregate s:=collect(this) | values {body: join(s, "\n")}' -
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### safe_append_to_sup_file
|
|
153
|
+
|
|
154
|
+
Append a timestamped record with raw text to a `.sup` file.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
echo "$text" | super -s -i line \
|
|
158
|
+
-c "values {ts: now(), body: this}" - >> data.sup
|
|
159
|
+
```
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
fn skdoc_csv_field(): (
|
|
2
|
+
cast(
|
|
3
|
+
{name:"sk_csv_field",
|
|
4
|
+
type:"func",
|
|
5
|
+
desc:"Escapes a string for use as a CSV field per RFC 4180. Wraps in double quotes and doubles internal quotes when the value contains commas, quotes, or newlines. Plain values pass through unchanged.",
|
|
6
|
+
args:[{name:"s",desc:"The string to escape"}],
|
|
7
|
+
examples:[{i:"sk_csv_field('plain')",o:"'plain'"}
|
|
8
|
+
{i:"sk_csv_field('hello, world')",o:"quoted and wrapped"}
|
|
9
|
+
{i:"sk_csv_field('has newline')",o:"quoted and wrapped"}] }, <skdoc>)
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
fn sk_csv_field(s): (
|
|
13
|
+
grep("[,\"\n]", s)
|
|
14
|
+
? f"\"{replace(s, "\"", "\"\"")}\""
|
|
15
|
+
: s
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
fn skdoc_csv_row(): (
|
|
19
|
+
cast(
|
|
20
|
+
{name:"sk_csv_row",
|
|
21
|
+
type:"func",
|
|
22
|
+
desc:"Builds a CSV row from an array of values. Each element is cast to string and escaped with sk_csv_field, then joined with commas.",
|
|
23
|
+
args:[{name:"arr",desc:"Array of values to format as a CSV row"}],
|
|
24
|
+
examples:[{i:"sk_csv_row(arr) where arr has commas",o:"fields with commas get quoted"}] }, <skdoc>)
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
fn sk_csv_row(arr): (
|
|
28
|
+
join([unnest arr | values sk_csv_field(cast(this, <string>))], ",")
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
fn skdoc_shell_quote(): (
|
|
32
|
+
cast(
|
|
33
|
+
{name:"sk_shell_quote",
|
|
34
|
+
type:"func",
|
|
35
|
+
desc:"Wraps a string in POSIX shell single quotes. Internal single quotes are escaped so the result is safe for shell interpolation. Protects against injection of $, backticks, and other shell metacharacters.",
|
|
36
|
+
args:[{name:"s",desc:"The string to quote"}],
|
|
37
|
+
examples:[{i:"sk_shell_quote('hello world')",o:"single-quoted string"}
|
|
38
|
+
{i:"sk_shell_quote('has $var')",o:"single-quoted, $ not expanded"}] }, <skdoc>)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
fn sk_shell_quote(s): (
|
|
42
|
+
f"'{replace(s, "'", "'\\'')}'"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
fn skdoc_tsv_field(): (
|
|
46
|
+
cast(
|
|
47
|
+
{name:"sk_tsv_field",
|
|
48
|
+
type:"func",
|
|
49
|
+
desc:"Escapes a value for use in a TSV field. Casts to string, then replaces literal tab and newline characters with their backslash-escaped forms.",
|
|
50
|
+
args:[{name:"s",desc:"The value to escape"}],
|
|
51
|
+
examples:[{i:"sk_tsv_field('col1\\tcol2')",o:"tabs replaced with literal \\t"}
|
|
52
|
+
{i:"sk_tsv_field('line1\\nline2')",o:"newlines replaced with literal \\n"}] }, <skdoc>)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
fn sk_tsv_field(s): (
|
|
56
|
+
replace(replace(cast(s, <string>), "\t", "\\t"), "\n", "\\n")
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
-- Shell patterns for safe text ingestion
|
|
60
|
+
-- The key insight: never interpolate untrusted text into a SuperQL string literal.
|
|
61
|
+
-- Pipe raw text through super with -i line and let the serializer handle escaping.
|
|
62
|
+
-- These patterns work from any language that can spawn a subprocess.
|
|
63
|
+
|
|
64
|
+
fn skdoc_safe_text_to_record(): (
|
|
65
|
+
cast(
|
|
66
|
+
{name:"safe_text_to_record",
|
|
67
|
+
type:"shell",
|
|
68
|
+
desc:"Pipe raw text into super to build a record without string interpolation. The text never passes through shell expansion or manual escaping. Works from any language via subprocess.",
|
|
69
|
+
args:[],
|
|
70
|
+
snippet:'echo "$text" | super -s -i line -c "values {body: this}" -',
|
|
71
|
+
examples:[{i:"text with quotes and $pecial chars",o:"safely embedded in a .sup record"}] }, <skdoc>)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
fn skdoc_safe_text_to_string(): (
|
|
75
|
+
cast(
|
|
76
|
+
{name:"safe_text_to_string",
|
|
77
|
+
type:"shell",
|
|
78
|
+
desc:"Pipe raw text through super to get a properly escaped SUP string literal. Useful when you need the escaped value for embedding in other SUP data.",
|
|
79
|
+
args:[],
|
|
80
|
+
snippet:'echo "$text" | super -s -i line -c "values this" -',
|
|
81
|
+
examples:[{i:"She said hello and backslash",o:"properly escaped SUP string"}] }, <skdoc>)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
fn skdoc_safe_multiline_to_record(): (
|
|
85
|
+
cast(
|
|
86
|
+
{name:"safe_multiline_to_record",
|
|
87
|
+
type:"shell",
|
|
88
|
+
desc:"Collapse multiline text into a single record field. Each line is collected then joined with newline characters. The text is never interpolated through the shell.",
|
|
89
|
+
args:[],
|
|
90
|
+
snippet:'echo "$text" | super -s -i line -c "aggregate s:=collect(this) | values {body: join(s, \"\\n\")}" -',
|
|
91
|
+
examples:[{i:"multi-line text with special chars",o:"single record with embedded newlines"}] }, <skdoc>)
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
fn skdoc_safe_append_to_sup_file(): (
|
|
95
|
+
cast(
|
|
96
|
+
{name:"safe_append_to_sup_file",
|
|
97
|
+
type:"shell",
|
|
98
|
+
desc:"Append a timestamped record with raw text to a .sup file. Common pattern for scripts that log or accumulate structured data from unstructured input.",
|
|
99
|
+
args:[],
|
|
100
|
+
snippet:'echo "$text" | super -s -i line -c "values {ts: now(), body: this}" - >> data.sup',
|
|
101
|
+
examples:[{i:"arbitrary user input",o:"appended as timestamped record to .sup file"}] }, <skdoc>)
|
|
102
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Format
|
|
3
|
+
layout: default
|
|
4
|
+
nav_order: 5
|
|
5
|
+
parent: Recipes
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Format Recipes
|
|
9
|
+
|
|
10
|
+
Source: `format.spq`
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## sk_format_bytes
|
|
15
|
+
|
|
16
|
+
Returns the size in bytes in human readable format.
|
|
17
|
+
|
|
18
|
+
**Type:** function
|
|
19
|
+
|
|
20
|
+
| Argument | Description |
|
|
21
|
+
|----------|-------------|
|
|
22
|
+
| `value` | Must be castable to uint64 |
|
|
23
|
+
|
|
24
|
+
```supersql
|
|
25
|
+
sk_format_bytes(1048576)
|
|
26
|
+
-- => '1 MB'
|
|
27
|
+
|
|
28
|
+
sk_format_bytes(0)
|
|
29
|
+
-- => '0 B'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Supports units up to EB (exabytes). The full unit list: B, KB, MB, GB, TB, PB, EB.
|
|
33
|
+
|
|
34
|
+
**Implementation:**
|
|
35
|
+
|
|
36
|
+
```supersql
|
|
37
|
+
const sk_bytes_units=["B", "KB", "MB", "GB", "TB", "PB", "EB"]
|
|
38
|
+
const sk_bytes_divisor=1024
|
|
39
|
+
|
|
40
|
+
fn _sk_bytes_unit_index(value): (
|
|
41
|
+
floor(log(value) / log(sk_bytes_divisor))::uint64
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
fn _sk_format_nonzero_bytes(value): (
|
|
45
|
+
f"{(value / pow(sk_bytes_divisor, _sk_bytes_unit_index(value)))::uint64} {sk_bytes_units[_sk_bytes_unit_index(value)]}"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
fn sk_format_bytes(value): (
|
|
49
|
+
(value == 0) ? "0 B" : _sk_format_nonzero_bytes(value)
|
|
50
|
+
)
|
|
51
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- cannot get above EB with uint64 - sorry "ZB" & "YB" and beyond...
|
|
2
|
+
const sk_bytes_units=["B", "KB", "MB", "GB", "TB", "PB", "EB"]
|
|
3
|
+
const sk_bytes_divisor=1024
|
|
4
|
+
|
|
5
|
+
fn _sk_bytes_unit_index(value): (
|
|
6
|
+
floor(log(value) / log(sk_bytes_divisor))::uint64
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
fn _sk_format_nonzero_bytes(value): (
|
|
10
|
+
f"{(value / pow(sk_bytes_divisor, _sk_bytes_unit_index(value)))::uint64} {sk_bytes_units[_sk_bytes_unit_index(value)]}"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
fn skdoc_format_bytes(): (
|
|
14
|
+
cast(
|
|
15
|
+
{name:"sk_format_bytes",
|
|
16
|
+
type:"func",
|
|
17
|
+
desc:"Returns the size in bytes in human readable format.",
|
|
18
|
+
args:[{name:"value",desc:"Must be castable to uint64"}],
|
|
19
|
+
examples:[{i:"sk_format_bytes(1048576)",o:"'1 MB'"}] }, <skdoc>)
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
fn sk_format_bytes(value): (
|
|
23
|
+
(value == 0) ? "0 B" : _sk_format_nonzero_bytes(value)
|
|
24
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Recipes
|
|
3
|
+
layout: default
|
|
4
|
+
has_children: true
|
|
5
|
+
nav_order: 5
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Recipes
|
|
9
|
+
|
|
10
|
+
Reusable SuperSQL functions and operators for common tasks. Include them in your
|
|
11
|
+
queries with `from` or `-I`:
|
|
12
|
+
|
|
13
|
+
```supersql
|
|
14
|
+
from 'string.spq' | values sk_capitalize('hello')
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
super -I string.spq -c "values sk_capitalize('hello')"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Recipe source files are available in the
|
|
22
|
+
[superkit](https://github.com/chrismo/superkit/tree/main/docs/recipes)
|
|
23
|
+
repository.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Integer
|
|
3
|
+
layout: default
|
|
4
|
+
nav_order: 3
|
|
5
|
+
parent: Recipes
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Integer Recipes
|
|
9
|
+
|
|
10
|
+
Source: `integer.spq`
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## sk_clamp
|
|
15
|
+
|
|
16
|
+
Clamps a value between min and max.
|
|
17
|
+
|
|
18
|
+
**Type:** function
|
|
19
|
+
|
|
20
|
+
| Argument | Description |
|
|
21
|
+
|----------|-------------|
|
|
22
|
+
| `i` | The value to clamp. |
|
|
23
|
+
| `min` | The minimum value. |
|
|
24
|
+
| `max` | The maximum value. |
|
|
25
|
+
|
|
26
|
+
```supersql
|
|
27
|
+
sk_clamp(1, 2, 3)
|
|
28
|
+
-- => 2
|
|
29
|
+
|
|
30
|
+
sk_clamp(4, 2, 3)
|
|
31
|
+
-- => 3
|
|
32
|
+
|
|
33
|
+
sk_clamp(2, 2, 3)
|
|
34
|
+
-- => 2
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Implementation:**
|
|
38
|
+
|
|
39
|
+
```supersql
|
|
40
|
+
fn sk_clamp(i, min, max): (
|
|
41
|
+
i < min ? min : i > max ? max : i
|
|
42
|
+
)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## sk_min
|
|
48
|
+
|
|
49
|
+
Returns the minimum of two values.
|
|
50
|
+
|
|
51
|
+
**Type:** function
|
|
52
|
+
|
|
53
|
+
| Argument | Description |
|
|
54
|
+
|----------|-------------|
|
|
55
|
+
| `a` | The first value. |
|
|
56
|
+
| `b` | The second value. |
|
|
57
|
+
|
|
58
|
+
```supersql
|
|
59
|
+
sk_min(1, 2)
|
|
60
|
+
-- => 1
|
|
61
|
+
|
|
62
|
+
sk_min(3, 2)
|
|
63
|
+
-- => 2
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Implementation:**
|
|
67
|
+
|
|
68
|
+
```supersql
|
|
69
|
+
fn sk_min(a, b): (
|
|
70
|
+
a < b ? a : b
|
|
71
|
+
)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## sk_max
|
|
77
|
+
|
|
78
|
+
Returns the maximum of two values.
|
|
79
|
+
|
|
80
|
+
**Type:** function
|
|
81
|
+
|
|
82
|
+
| Argument | Description |
|
|
83
|
+
|----------|-------------|
|
|
84
|
+
| `a` | The first value. |
|
|
85
|
+
| `b` | The second value. |
|
|
86
|
+
|
|
87
|
+
```supersql
|
|
88
|
+
sk_max(1, 2)
|
|
89
|
+
-- => 2
|
|
90
|
+
|
|
91
|
+
sk_max(3, 2)
|
|
92
|
+
-- => 3
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Implementation:**
|
|
96
|
+
|
|
97
|
+
```supersql
|
|
98
|
+
fn sk_max(a, b): (
|
|
99
|
+
a > b ? a : b
|
|
100
|
+
)
|
|
101
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
-- TODO: this doesn't cause any problems yet because we're not recursively
|
|
2
|
+
-- scanning sk_include files for _their_ sk_includes.
|
|
3
|
+
|
|
4
|
+
-- sk_include string.spq -- test circular dependencies
|
|
5
|
+
|
|
6
|
+
op skdoc_clamp: (
|
|
7
|
+
cast(
|
|
8
|
+
{name:"sk_clamp",
|
|
9
|
+
type:"func",
|
|
10
|
+
desc:"Clamps a value between min and max.",
|
|
11
|
+
args:[{name:"i",desc:"The value to clamp."}
|
|
12
|
+
{name:"min",desc:"The minimum value."}
|
|
13
|
+
{name:"max",desc:"The maximum value."}],
|
|
14
|
+
examples:[{i:"sk_clamp(1, 2, 3)",o:"2"}
|
|
15
|
+
{i:"sk_clamp(4, 2, 3)",o:"3"}
|
|
16
|
+
{i:"sk_clamp(2, 2, 3)",o:"2"}]}, <skdoc>)
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
fn sk_clamp(i, min, max): (
|
|
20
|
+
i < min ? min : i > max ? max : i
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
fn skdoc_min(): (
|
|
24
|
+
cast(
|
|
25
|
+
{name:"sk_min",
|
|
26
|
+
type:"func",
|
|
27
|
+
desc:"Returns the minimum of two values.",
|
|
28
|
+
args:[{name:"a",desc:"The first value."}
|
|
29
|
+
{name:"b",desc:"The second value."}],
|
|
30
|
+
examples:[{i:"sk_min(1, 2)",o:"1"}
|
|
31
|
+
{i:"sk_min(3, 2)",o:"2"}
|
|
32
|
+
{i:"sk_min(2, 2)",o:"2"}]}, <skdoc>)
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
fn sk_min(a, b): (
|
|
36
|
+
a < b ? a : b
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
fn skdoc_max(): (
|
|
40
|
+
cast(
|
|
41
|
+
{name:"sk_max",
|
|
42
|
+
type:"func",
|
|
43
|
+
desc:"Returns the maximum of two values.",
|
|
44
|
+
args:[{name:"a",desc:"The first value."}
|
|
45
|
+
{name:"b",desc:"The second value."}],
|
|
46
|
+
examples:[{i:"sk_max(1, 2)",o:"2"}
|
|
47
|
+
{i:"sk_max(3, 2)",o:"3"}
|
|
48
|
+
{i:"sk_max(2, 2)",o:"2"}]}, <skdoc>)
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
fn sk_max(a, b): (
|
|
52
|
+
a > b ? a : b
|
|
53
|
+
)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Records
|
|
3
|
+
layout: default
|
|
4
|
+
nav_order: 6
|
|
5
|
+
parent: Recipes
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Record Recipes
|
|
9
|
+
|
|
10
|
+
Source: `records.spq` (includes `array.spq`)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## sk_keys
|
|
15
|
+
|
|
16
|
+
Returns the keys of the top-level fields in a record. This does not go deep
|
|
17
|
+
into nested records.
|
|
18
|
+
|
|
19
|
+
**Type:** operator
|
|
20
|
+
|
|
21
|
+
```supersql
|
|
22
|
+
{a:1,b:{c:333}} | sk_keys
|
|
23
|
+
-- => ['a','b']
|
|
24
|
+
|
|
25
|
+
{x:10,y:20,z:30} | sk_keys
|
|
26
|
+
-- => ['x','y','z']
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Implementation:**
|
|
30
|
+
|
|
31
|
+
```supersql
|
|
32
|
+
op sk_keys: (
|
|
33
|
+
fields(this) | unnest this | values this[0] | uniq | collect(this)
|
|
34
|
+
)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## sk_merge_records
|
|
40
|
+
|
|
41
|
+
Merges an array of records into a single record by combining the fields. If
|
|
42
|
+
there are duplicate keys, the last one wins.
|
|
43
|
+
|
|
44
|
+
**Type:** operator
|
|
45
|
+
|
|
46
|
+
```supersql
|
|
47
|
+
[{a:1},{b:{c:333}}] | sk_merge_records
|
|
48
|
+
-- => {a:1,b:{c:333}}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Implementation:**
|
|
52
|
+
|
|
53
|
+
```supersql
|
|
54
|
+
op sk_merge_records: (
|
|
55
|
+
this::string
|
|
56
|
+
| replace(this, "},{",",")
|
|
57
|
+
| parse_sup(this[1:-1])
|
|
58
|
+
)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## sk_add_ids
|
|
64
|
+
|
|
65
|
+
Prepends an incrementing id field to each record. Always returns an array.
|
|
66
|
+
|
|
67
|
+
**Type:** operator
|
|
68
|
+
|
|
69
|
+
```supersql
|
|
70
|
+
[{a:3},{b:4}] | sk_add_ids
|
|
71
|
+
-- => [{id:1,a:3},{id:2,b:4}]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Implementation:**
|
|
75
|
+
|
|
76
|
+
```supersql
|
|
77
|
+
op sk_add_ids: (
|
|
78
|
+
sk_in_array(this)
|
|
79
|
+
| unnest this
|
|
80
|
+
| count
|
|
81
|
+
| values {id:count,...that}
|
|
82
|
+
| collect(this)
|
|
83
|
+
)
|
|
84
|
+
```
|