diff --git a/docker/Dockerfile b/docker/Dockerfile index f078685d..8de97938 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,12 +1,17 @@ # 'builder' includes all build & testing dependencies. FROM debian:12 AS builder +# hadolint ignore=DL3008 RUN apt-get update &&\ apt-get install --no-install-recommends -y \ build-essential=12.9 \ ca-certificates=20230311 \ - git=1:2.39.5-0+deb12u1 \ - curl=7.88.1-10+deb12u7 &&\ + # git=1:2.39.5-0+deb12u1 \ + # curl=7.88.1-10+deb12u7 &&\ + # Specific versions of git/curl break every + # couple weeks. + # TODO: Find a better way to pin versions. + git curl &&\ apt-get clean &&\ rm -rf /var/lib/apt/lists/* diff --git a/docs/css/style.css b/docs/css/style.css index f44ceac2..045e4e50 100644 --- a/docs/css/style.css +++ b/docs/css/style.css @@ -135,6 +135,10 @@ pre { } } +.lang-go, .language-go { + font-size: 0.85rem; +} + pre.query, pre.lang-go { code { padding: 1.5rem 1rem 0.5rem 1rem; diff --git a/docs/index.html b/docs/index.html index a48f0281..dd6f4eec 100644 --- a/docs/index.html +++ b/docs/index.html @@ -32,12 +32,13 @@
FQL is specified as a context-free - grammar. The queries look like key-values encoded using the - directory & tuple layers.
+FQL is specified as a context-free grammar. + The queries look like key-values encoded using the directory & + tuple layers.
/my/directory("my","tuple")=4000
FQL queries may define a single key-value to be written, as shown above, or may define a set of key-values to be read, as shown @@ -74,9 +75,7 @@
/my/directory("my","tuple")=4000
The query above has a variable <int>
as its
value. Variables act as placeholders for any of the supported data elements. In this case, the variable
- also tells FQL how to decode the value’s bytes. This query will return
- a single key-value from the database, if such a key exists.
FQL queries can also perform range reads & filtering by including a variable in the key’s tuple. The query below will return all key-values which conform to the schema defined by the query.
@@ -111,7 +110,7 @@An FQL query contains instances of data elements. These mirror the types of elements found in the tuple - layer. Descriptions of these elements can be seen below.
+ layer.bool |
Boolean | -true |
+ true
+ false |
int |
Signed Integer | --14 |
+ -14 3033 |
num |
Floating Point | -33.4 |
+ 33.4
+ -3.2e5 |
str |
Unicode String | -"string" |
+ "happy😁"
+ "\"quoted\"" |
uuid |
@@ -166,44 +168,47 @@
The nil
type allows for a single value which is also
- nil
. The tuple layer supports a unique encoding for
- nil
. As a value, nil
is equivalent to an
- empty byte array, so the following queries are semantically
- equivalent:
/entry(537856)=nil
-/entry(537856)=0x
- The int
type allows for arbitrarily large integers.
- The num
type allows for 64-bit floating-point numbers.
- For now, the num
type does not support arbitrary
- precision because the tuple layer advises
- against using it’s abitrarily-sized decimal encoding. Support for
- arbitrarily-sized floating-point numbers will be revisited in the
- future.
The str
type supports unicode strings, including
- unicode escape sequences. FQL has not chosen a unicode escape syntax,
- but it will be similar to what is found in other programming
- languages.
Strings are the only data element allowed in directories. If a - directory string only contains alphanumericals, underscores, dashes, - and periods then the quotes don’t need to be included.
+The nil
type may only be instantiated as the element
+ nil
. The int
type may be instantiated as any
+ arbitrarily large integer.
/int(9223372036854775808)=nil
+ The num
type may be instantiated as any real number
+ between -1.18e4932
and 1.18e4932
, and may
+ use scientific notation. The type may also be instantiated as the
+ tokens -inf
, inf
, -nan
, or
+ nan
. The element is represented as an 80-bit extended
+ double floating-point
+ and will snap to the nearest representable number.
/float(-inf,nan)=1.234e4732
+ The str
type is the only element type allowed in
+ directory paths. If a directory string only contains alphanumericals,
+ underscores, dashes, and periods then the quotes may not be
+ included.
/quoteless-string_in.dir(true)=false
/"other ch@r@cters must be quoted!"(20)=32.3
Quoted strings may contain quotes via backslash escapes.
-/my/dir("I said \"hello\"")=nil
- The ‘tup’ type may contain any of the data elements, including - sub-tuples. Like tuples, a query’s value may contain any of the data - elements.
-/region/north_america(22.3,-8)=("rain","fog")
-/region/east_asia("japan",("sub",nil))=0xff
- The directory and tuple layers are responsible for encoding the - data elements in the key. As for the value, FDB doesn’t provide a - standard encoding.
-FQL provides default value encoding for each of the data elements, - as show below. The upcoming “options” syntax will allow queries to - specify alternative encodings for each data element.
+/escape("I said \"hello\"")=nil
+ The hexidecimal numbers of the uuid
and
+ bytes
types may be upper, lower, or mixed case.
/hex(fC2Af671-a248-4AD6-ad57-219cd8a9f734)=0x3b42ADED28b9
+ The tup
type may contain any of the data elements,
+ including sub-tuples. Like tuples, a query’s value may contain any of
+ the data elements.
/sub/tuple("japan",("sub",nil))=0xff
+/tuple/value(22.3,-8)=("rain","fog")
+ For data elements in the key, the directory and tuple layers are + responsible for data encoding. In the value, the tuple layer may be + used, but FQL supports other encodings known as “raw values”.
+/tuple_value()={4000}
+/raw_value()=4000
+ As a raw value, the int
type doesn’t support an
+ encoding for arbitrarily large integers. As a value, you’ll need to
+ encode such integers using the tuple layer.
/int()={9223372036854775808}
+ Below, you can see the default encodings of each type when used as + a raw value.
nil |
- empty value | +empty byte array |
bool |
@@ -224,15 +229,15 @@ ||
int |
- 64-bit, 1’s compliment | +64-bit, 1’s compliment, big endian |
num |
- IEEE 754 | +64-bit, IEEE 754, big endian |
str |
- Unicode | +UTF-8 |
uuid |
@@ -249,19 +254,125 @@
Variables allow FQL to describe key-value schemas. Any data element may be represented with a
- variable. Variables are specified as a list of element types,
- separated by |
, wrapped in angled braces.
<uint|str|uuid|bytes>
+ The tuple layer supports a unique encoding for nil
,
+ but as a raw value nil
is equivalent to an empty byte
+ array. This makes the following two queries equivalent.
/entry(537856)=nil
+/entry(537856)=0x
+ Whether encoded using the tuple layer or as a raw value, the
+ int
and num
types support several different
+ encodings. A non-default encoding may be specified using the options syntax. Options are specified in a braced
+ list after the element. If the element’s value cannot be represented
+ by specified encoding then the query is invalid.
/numbers(362342[i16])=32.55[f32]
+ By default, variables will + decode any encoding for its types. Options can be applied to a + variable’s types to limit which encoding will match the schema.
+/numbers(<int[i16,big]>)=<num[f32]>
+ The tables below shows which options are supported for the
+ int
and num
types.
Int Option | +Description | +
---|---|
big |
+ Big endian | +
lil |
+ Little Endian | +
u8 |
+ Unsigned 8-bit | +
u16 |
+ Unsigned 16-bit | +
u32 |
+ Unsigned 32-bit | +
u64 |
+ Unsigned 64-bit | +
i8 |
+ Signed 8-bit | +
i16 |
+ Signed 16-bit | +
i32 |
+ Signed 32-bit | +
i64 |
+ Signed 64-bit | +
Num Options | +Description | +
---|---|
big |
+ Big endian | +
lil |
+ Little Endian | +
f32 |
+ 32-bit | +
f64 |
+ 64-bit | +
f80 |
+ 80-bit | +
A hole is any of the following syntax constructs: variables,
+ references, and the ...
token. Holes are used to define a
+ key-value schema by acting as placeholders for one or more data
+ elements.
A single data element may be
+ represented with a variable. Variables are specified as a list of
+ element types, separated by |
, wrapped in angled
+ braces.
<int|str|uuid|bytes>
The variable’s type list describes which data elements are allowed at the variable’s position. A variable may be empty, including no element types, meaning it represents all element types.
/user(<int>,<str>,<>)=<>
/user(0,"jon",0xffab0c)=nil
/user(20,"roger",22.3)=0xff
-/user(21,"",nil)="nothing"
+/user(21,"",nil)=nil
Before the type list, a variable can be given a name. This name is used to reference the variable in subsequent queries, allowing for index indirection.
@@ -270,34 +381,73 @@/user(33,"mazda")=nil
/user(320,"ford")=nil
/user(411,"chevy")=nil
+ Named variables must include at least one type. To allow named
+ variables to match any element type, use the any
+ type.
/stuff(<thing:any>)
+/count(:thing,<int>)
+ /count("cat",10)
+/count(42,1)
+/count(0x5fae,3)
+ The ...
token represents any number of data elements
+ of any type.
/tuples(0x00,...)
+ /tuples(0x00,"something")=nil
+/tuples(0x00,42,43,44)=0xabcf
+/tuples(0x00)=nil
+ +❓ Currently, the
+...
token is only allowed as the + last element of a tuple. This will be revisited in the future.
Whitespace and newlines are allowed within a tuple, between its elements.
/account/private(
- <uint>,
- <uint>,
+ <int>,
+ <int>,
<str>,
)=<int>
Comments start with a %
and continue until the end of
the line. They can be used to describe a tuple’s elements.
% private account balances
/account/private(
- <uint>, % user ID
- <uint>, % group ID
+ <int>, % group ID
+ <int>, % account ID
<str>, % account name
)=<int> % balance in USD
+ Options provide a way to modify the default behavior of data + elements, variable types, and queries. Options are specified as a + comma separated list wrapped in braces.
+For instance, to specify that an int
should be encoded
+ as a little-endian unsigned 8-bit integer, the following options would
+ be included after the number.
3548[u8,lil]
+ Similarly, if a variable should only match against a big-endian
+ 32-bit float then the following option would be included after the
+ num
type.
<num[f32,big]>
+ Query options are specified on the line before the query. For + instance, to specify that a range-read query should read in reverse + and only read 5 items, the following options would be included before + the query.
+[reverse,limit:5]
+/my/integers(<int>)=nil
+ Notice that the limit
option includes an argument
+ after the colon. Some options include a single argument to further
+ specify the option’s behavior.
FQL queries can write/clear a single key-value, read one or more +
FQL queries can mutate a single key-value, read one or more key-values, or list directories. Throughout this section, snippets of - Go code are included to show how the queries interact with the FDB - API.
+ Go code are included which approximate how the queries interact with + the Foundation DB API.Queries lacking variables and the
- ...
token perform mutations on the database by either
- writing or clearing a key-value.
Queries lacking holes perform + mutations on the database by either writing or clearing a + key-value.
-Queries lacking a value altogether imply an empty variable as the value and should not be +
❗ Queries lacking a value altogether imply an empty variable as the value and should not be confused with mutation queries.
Mutation queries with a data element @@ -332,16 +482,13 @@
Queries containing a variable or
- the ...
token read one or more key-values. The query
- defines a schema which the returned key-values must conform to.
If the variable or ...
token only appears in the
- query’s value, then it returns a single key-value, if one matching the
- schema exists.
Queries containing holes read one or + more key-values. If the holes only appears in the value, then a single + key-value is returned, if one matching the schema exists.
-Queries lacking a value altogether imply an empty variable as the value, and are therefore - read queries.
+❗ Queries lacking a value altogether imply an empty variable as the value which makes them read + queries.
/my/dir(99.8,7dfb10d1-2493-4fb5-928e-889fdc6a7136)=<int|str>
db.ReadTransact(func(tr fdb.ReadTransaction) (interface{}, error) {
@@ -387,9 +534,9 @@ Reads
// No value decoding...
return tr.MustGet(dir.Pack(tuple.Tuple{10139})), nil
})
- Queries with variables or the
- ...
token in their key (and optionally in their value)
- result in a range of key-values being read.
Queries with variables in their key + (and optionally in their value) result in a range of key-values being + read.
/people("coders",...)
db.ReadTransact(func(tr fdb.ReadTransaction) (interface{}, error) {
dir, err := directory.Open(tr, []string{"people"}, nil)
@@ -532,10 +679,8 @@ Filtering
return results, nil
})
Besides basic CRUD - operations, FQL is capable of performing indirection and aggregation - queries.
+Besides basic CRUD operations, FQL is capable of performing + indirection and aggregation queries.
🚧 Indirection is still being implemented.
@@ -579,10 +724,11 @@Aggregation
Aggregation queries read multiple key-values and combine them into a single output key-value.
-Foundation DB performs best when key-values are kept small. When storing large - blobs, the blobs are usually split into 10 kB chunks and stored as - values. The respective keys contain the byte offset of the chunks.
+Foundation DB performs best when key-values are kept small. When + storing large blobs, the + blobs are usually split into 10 kB chunks and stored as values. The + respective keys contain the byte offset of the chunks.
/blob(
"audio.wav", % The identifier of the blob.
<offset:int>, % The byte offset within the blob.
@@ -639,7 +785,7 @@ Using FQL
exploring the data, similar to psql
for Postgres. This
libraries powering this application are exposed as a Go API, allowing
FQL to be used as a Foundation DB layer.
+ href="https://apple.github.io/foundationdb/layer-concept.html">layer;
Command Line
Headless
@@ -770,15 +916,11 @@ Roadmap
By summer of 2025, I’d like to have the following items
completed:
- Indirection & aggregation queries implemented as described
- in this document.
+ Implement all features described in this document.
Design and document the syntax for doing the following
features.
Separating queries into multiple transactions.
- Set options at both the query & transaction level. Options
- control things like range-read direction & limits, endianness of
- values, and whether write queries are allowed.
Meta language for aliasing queries or parts of queries. This
language would provide type-safe templating with the goal of reducing
repetition in a query file.
diff --git a/docs/index.md b/docs/index.md
index abadad99..6496dc40 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -24,11 +24,12 @@ include-before: |
# Overview
-FQL is specified as a [context-free
-grammar](https://github.com/janderland/fql/blob/main/syntax.ebnf).
-The queries look like key-values encoded using the directory
+FQL is specified as a context-free [grammar][]. The
+queries look like key-values encoded using the directory
& tuple layers.
+[grammar]: https://github.com/janderland/fql/blob/main/syntax.ebnf
+
```language-fql {.query}
/my/directory("my","tuple")=4000
```
@@ -47,10 +48,7 @@ as shown below.
The query above has a variable `` as its value.
Variables act as placeholders for any of the supported [data
-elements](#data-elements). In this case, the variable also
-tells FQL how to decode the value's bytes. This query will
-return a single key-value from the database, if such a key
-exists.
+elements](#data-elements).
FQL queries can also perform range reads & filtering by
including a variable in the key's tuple. The query below
@@ -126,53 +124,50 @@ a directory path.
# Data Elements
An FQL query contains instances of data elements. These
-mirror the types of elements found in the [tuple
-layer](https://github.com/apple/foundationdb/blob/main/design/tuple.md).
-Descriptions of these elements can be seen below.
+mirror the types of elements found in the [tuple layer][].
+
+[tuple layer]: https://github.com/apple/foundationdb/blob/main/design/tuple.md
| Type | Description | Example |
|:--------|:---------------|:---------------------------------------|
| `nil` | Empty Type | `nil` |
-| `bool` | Boolean | `true` |
-| `int` | Signed Integer | `-14` |
-| `num` | Floating Point | `33.4` |
-| `str` | Unicode String | `"string"` |
+| `bool` | Boolean | `true` `false` |
+| `int` | Signed Integer | `-14` `3033` |
+| `num` | Floating Point | `33.4` `-3.2e5` |
+| `str` | Unicode String | `"happy😁"` `"\"quoted\""` |
| `uuid` | UUID | `5a5ebefd-2193-47e2-8def-f464fc698e31` |
| `bytes` | Byte String | `0xa2bff2438312aac032` |
| `tup` | Tuple | `("hello",27.4,nil)` |
-The `nil` type allows for a single value which is also
-`nil`. The tuple layer supports a unique encoding for `nil`.
-As a value, `nil` is equivalent to an empty byte array, so
-the following queries are semantically equivalent:
+The `nil` type may only be instantiated as the element
+`nil`. The `int` type may be instantiated as any arbitrarily
+large integer.
-```language-fql {.query}
-/entry(537856)=nil
-/entry(537856)=0x
+```
+/int(9223372036854775808)=nil
```
-The `int` type allows for arbitrarily large integers. The
-`num` type allows for 64-bit floating-point numbers. For
-now, the `num` type does not support arbitrary precision
-because the tuple layer [advises
-against](https://github.com/apple/foundationdb/blob/main/design/tuple.md#arbitrary-precision-decimal)
-using it's abitrarily-sized decimal encoding. Support for
-arbitrarily-sized floating-point numbers will
-be revisited in the future.
+The `num` type may be instantiated as any real number
+between `-1.18e4932` and `1.18e4932`, and may use scientific
+notation. The type may also be instantiated as the tokens
+`-inf`, `inf`, `-nan`, or `nan`. The element is represented
+as an 80-bit extended double [floating-point][] and will
+snap to the nearest representable number.
-The `str` type supports unicode strings, including unicode
-escape sequences. FQL has not chosen a unicode escape
-syntax, but it will be similar to what is found in other
-programming languages.
+[floating-point]: https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format
-Strings are the only data element allowed in directories. If
-a directory string only contains alphanumericals,
-underscores, dashes, and periods then the quotes don't need
-to be included.
+```language-fql {.query}
+/float(-inf,nan)=1.234e4732
+```
+
+The `str` type is the only element type allowed in directory
+paths. If a directory string only contains alphanumericals,
+underscores, dashes, and periods then the quotes may not be
+included.
```language-fql {.query}
/quoteless-string_in.dir(true)=false
@@ -182,53 +177,137 @@ to be included.
Quoted strings may contain quotes via backslash escapes.
```language-fql {.query}
-/my/dir("I said \"hello\"")=nil
+/escape("I said \"hello\"")=nil
```
-The 'tup' type may contain any of the data elements,
+The hexidecimal numbers of the `uuid` and `bytes` types may
+be upper, lower, or mixed case.
+
+```language-fql {.query}
+/hex(fC2Af671-a248-4AD6-ad57-219cd8a9f734)=0x3b42ADED28b9
+```
+
+The `tup` type may contain any of the data elements,
including sub-tuples. Like tuples, a query's value may
contain any of the data elements.
```language-fql {.query}
-/region/north_america(22.3,-8)=("rain","fog")
-/region/east_asia("japan",("sub",nil))=0xff
+/sub/tuple("japan",("sub",nil))=0xff
+/tuple/value(22.3,-8)=("rain","fog")
+```
+
+# Element Encoding
+
+For data elements in the key, the directory and tuple layers
+are responsible for data encoding. In the value, the tuple
+layer may be used, but FQL supports other encodings known as
+"raw values".
+
+```
+/tuple_value()={4000}
+/raw_value()=4000
```
-# Value Encoding
+As a raw value, the `int` type doesn't support an encoding
+for arbitrarily large integers. As a value, you'll need to
+encode such integers using the tuple layer.
-The directory and tuple layers are responsible for encoding
-the data elements in the key. As for the value, FDB doesn't
-provide a standard encoding.
+```language-fql {.query}
+/int()={9223372036854775808}
+```
-FQL provides default value encoding for each of the data
-elements, as show below. The upcoming "options" syntax will
-allow queries to specify alternative encodings for each data
-element.
+Below, you can see the default encodings of each type when
+used as a raw value.
-| Type | Encoding |
-|:--------|:--------------------------------|
-| `nil` | empty value |
-| `bool` | single byte, `0x00` means false |
-| `int` | 64-bit, 1's compliment |
-| `num` | IEEE 754 |
-| `str` | Unicode |
-| `uuid` | RFC 4122 |
-| `bytes` | as provided |
-| `tup` | tuple layer |
+| Type | Encoding |
+|:--------|:-----------------------------------|
+| `nil` | empty byte array |
+| `bool` | single byte, `0x00` means false |
+| `int` | 64-bit, 1's compliment, big endian |
+| `num` | 64-bit, IEEE 754, big endian |
+| `str` | UTF-8 |
+| `uuid` | RFC 4122 |
+| `bytes` | as provided |
+| `tup` | tuple layer |
-# Variables & Schemas
+The tuple layer supports a unique encoding for `nil`, but as
+a raw value `nil` is equivalent to an empty byte array. This
+makes the following two queries equivalent.
+
+```language-fql {.query}
+/entry(537856)=nil
+/entry(537856)=0x
+```
+
+Whether encoded using the tuple layer or as a raw value, the
+`int` and `num` types support several different encodings.
+A non-default encoding may be specified using the
+[options](#options) syntax. Options are specified in
+a braced list after the element. If the element's value
+cannot be represented by specified encoding then the query
+is invalid.
+
+```language-fql {.query}
+/numbers(362342[i16])=32.55[f32]
+```
+
+By default, [variables](#holes-&-schemas) will decode any
+encoding for its types. Options can be applied to
+a variable's types to limit which encoding will match the
+schema.
+
+```language-fql {.query}
+/numbers()=
+```
+
+The tables below shows which options are supported for the
+`int` and `num` types.
+
+
+
+| Int Option | Description |
+|:-----------|:----------------|
+| `big` | Big endian |
+| `lil` | Little Endian |
+| `u8` | Unsigned 8-bit |
+| `u16` | Unsigned 16-bit |
+| `u32` | Unsigned 32-bit |
+| `u64` | Unsigned 64-bit |
+| `i8` | Signed 8-bit |
+| `i16` | Signed 16-bit |
+| `i32` | Signed 32-bit |
+| `i64` | Signed 64-bit |
+
+
+
-Variables allow FQL to describe key-value schemas. Any [data
-element](#data-elements) may be represented with a variable.
-Variables are specified as a list of element types,
-separated by `|`, wrapped in angled braces.
+| Num Options | Description |
+|:------------|:--------------|
+| `big` | Big endian |
+| `lil` | Little Endian |
+| `f32` | 32-bit |
+| `f64` | 64-bit |
+| `f80` | 80-bit |
+
+
+
+# Holes & Schemas
+
+A hole is any of the following syntax constructs: variables,
+references, and the `...` token. Holes are used to define
+a key-value schema by acting as placeholders for one or more
+data elements.
+
+A single [data element](#data-elements) may be represented
+with a variable. Variables are specified as a list of
+element types, separated by `|`, wrapped in angled braces.
```language-fql
-
+
```
The variable's type list describes which data elements are
@@ -243,7 +322,7 @@ element types.
```language-fql {.result}
/user(0,"jon",0xffab0c)=nil
/user(20,"roger",22.3)=0xff
-/user(21,"",nil)="nothing"
+/user(21,"",nil)=nil
```
Before the type list, a variable can be given a name. This
@@ -261,6 +340,37 @@ queries, allowing for [index indirection](#indirection).
/user(411,"chevy")=nil
```
+Named variables must include at least one type. To allow
+named variables to match any element type, use the `any`
+type.
+
+```language-fql
+/stuff()
+/count(:thing,)
+```
+
+```language-fql {.result}
+/count("cat",10)
+/count(42,1)
+/count(0x5fae,3)
+```
+
+The `...` token represents any number of data elements of
+any type.
+
+```language-fql
+/tuples(0x00,...)
+```
+
+```language-fql {.result}
+/tuples(0x00,"something")=nil
+/tuples(0x00,42,43,44)=0xabcf
+/tuples(0x00)=nil
+```
+
+> ❓ Currently, the `...` token is only allowed as the last
+> element of a tuple. This will be revisited in the future.
+
# Space & Comments
Whitespace and newlines are allowed within a tuple, between
@@ -268,8 +378,8 @@ its elements.
```language-fql {.query}
/account/private(
- ,
- ,
+ ,
+ ,
,
)=
```
@@ -280,28 +390,63 @@ line. They can be used to describe a tuple's elements.
```language-fql
% private account balances
/account/private(
- , % user ID
- , % group ID
+ , % group ID
+ , % account ID
, % account name
)= % balance in USD
```
+# Options
+
+Options provide a way to modify the default behavior of data
+elements, variable types, and queries. Options are specified
+as a comma separated list wrapped in braces.
+
+For instance, to specify that an `int` should be encoded as
+a little-endian unsigned 8-bit integer, the following
+options would be included after the number.
+
+```language-fql
+3548[u8,lil]
+```
+
+Similarly, if a variable should only match against
+a big-endian 32-bit float then the following option would be
+included after the `num` type.
+
+```language-fql
+
+```
+
+Query options are specified on the line before the query.
+For instance, to specify that a range-read query should read
+in reverse and only read 5 items, the following options
+would be included before the query.
+
+```language-fql {.query}
+[reverse,limit:5]
+/my/integers()=nil
+```
+
+Notice that the `limit` option includes an argument after
+the colon. Some options include a single argument to further
+specify the option's behavior.
+
# Basic Queries
-FQL queries can write/clear a single key-value, read one or
-more key-values, or list directories. Throughout this
-section, snippets of Go code are included to show how the
-queries interact with the FDB API.
+FQL queries can mutate a single key-value, read one or more
+key-values, or list directories. Throughout this section,
+snippets of Go code are included which approximate how the
+queries interact with the Foundation DB API.
## Mutations
-Queries lacking [variables](#variables-schemas) and the
-`...` token perform mutations on the database by either
-writing or clearing a key-value.
+Queries lacking [holes](#holes-schemas) perform mutations on
+the database by either writing or clearing a key-value.
-> Queries lacking a value altogether imply an empty
-> [variable](#variables-schemas) as the value and should not
-> be confused with mutation queries.
+> ❗ Queries lacking a value altogether imply an empty
+> [variable](#holes-schemas) as the value and should not be
+> confused with mutation queries.
Mutation queries with a [data element](#data-elements) as
their value perform a write operation.
@@ -350,17 +495,14 @@ db.Transact(func(tr fdb.Transaction) (interface{}, error) {
## Reads
-Queries containing a [variable](#variables-schemas) or the
-`...` token read one or more key-values. The query defines
-a schema which the returned key-values must conform to.
-
-If the variable or `...` token only appears in the query's
-value, then it returns a single key-value, if one matching
-the schema exists.
+Queries containing [holes](#holes-schemas) read one or more
+key-values. If the holes only appears in the value, then
+a single key-value is returned, if one matching the schema
+exists.
-> Queries lacking a value altogether imply an empty
-> [variable](#variables-schemas) as the value, and are
-> therefore read queries.
+> ❗ Queries lacking a value altogether imply an empty
+> [variable](#holes-schemas) as the value which makes them
+> read queries.
```language-fql {.query}
/my/dir(99.8,7dfb10d1-2493-4fb5-928e-889fdc6a7136)=
@@ -420,9 +562,9 @@ db.ReadTransact(func(tr fdb.ReadTransaction) (interface{}, error) {
})
```
-Queries with [variables](#variables-schemas) or the `...`
-token in their key (and optionally in their value) result in
-a range of key-values being read.
+Queries with [variables](#holes-schemas) in their key (and
+optionally in their value) result in a range of key-values
+being read.
```language-fql {.query}
/people("coders",...)
@@ -600,10 +742,8 @@ db.ReadTransact(func(tr fdb.ReadTransaction) (interface{}, error) {
# Advanced Queries
-Besides basic
-[CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete)
-operations, FQL is capable of performing indirection and
-aggregation queries.
+Besides basic CRUD operations, FQL is capable of performing
+indirection and aggregation queries.
## Indirection
@@ -674,11 +814,11 @@ Aggregation queries read multiple key-values and combine
them into a single output key-value.
Foundation DB performs best when key-values are kept small.
-When [storing large
-blobs](https://apple.github.io/foundationdb/blob.html), the
-blobs are usually split into 10 kB chunks and stored as
-values. The respective keys contain the byte offset of the
-chunks.
+When storing large [blobs][], the blobs are usually split
+into 10 kB chunks and stored as values. The respective keys
+contain the byte offset of the chunks.
+
+[blobs]: https://apple.github.io/foundationdb/blob.html
```language-fql {.query}
/blob(
@@ -732,8 +872,9 @@ The FQL project provides an application for executing
queries and exploring the data, similar to `psql` for
Postgres. This libraries powering this application are
exposed as a Go API, allowing FQL to be used as a Foundation
-DB
-[layer](https://apple.github.io/foundationdb/layer-concept.html).
+DB [layer][];
+
+[layer]: https://apple.github.io/foundationdb/layer-concept.html
## Command Line
@@ -896,19 +1037,13 @@ func _() {
By summer of 2025, I'd like to have the following items
completed:
-- Indirection & aggregation queries implemented as described
- in this document.
+- Implement all features described in this document.
- Design and document the syntax for doing the following
features.
- Separating queries into multiple transactions.
- - Set options at both the query & transaction level.
- Options control things like range-read direction
- & limits, endianness of values, and whether write
- queries are allowed.
-
- Meta language for aliasing queries or parts of queries.
This language would provide type-safe templating with
the goal of reducing repetition in a query file.
diff --git a/docs/js/fql.js b/docs/js/fql.js
index 082dac27..7b568191 100644
--- a/docs/js/fql.js
+++ b/docs/js/fql.js
@@ -15,12 +15,16 @@
/\d+/,
/\.?/,
/\d*/,
+ /e?/,
+ /\d*/,
],
beginScope: {
1: 'accent',
2: 'number',
3: 'accent',
4: 'number',
+ 5: 'accent',
+ 6: 'number',
},
};
@@ -71,7 +75,7 @@
const DSTRING = {
scope: 'section',
- begin: /[\w\.]/,
+ begin: /[\w\.\-]/,
};
const KEYWORD = {
@@ -79,11 +83,14 @@
beginKeywords: [
'true',
'false',
+ '-inf',
+ 'inf',
+ '-nan',
+ 'nan',
'clear',
'nil',
'any',
'int',
- 'uint',
'bool',
'num',
'bint',
@@ -94,9 +101,62 @@
'append',
'sum',
'count',
+ 'big',
+ 'lil',
+ 'i8',
+ 'i16',
+ 'i32',
+ 'i64',
+ 'u8',
+ 'u16',
+ 'u32',
+ 'u64',
+ 'f32',
+ 'f64',
+ 'f80',
+ 'reverse',
+ 'limit',
].join(' '),
};
+ const OPTIONS = {
+ scope: 'options',
+ begin: /\[/,
+ end: /]/,
+ keywords: {
+ $$pattern: /[^,:]+/,
+ keyword: [
+ 'big',
+ 'lil',
+ 'i8',
+ 'i16',
+ 'i32',
+ 'i64',
+ 'u8',
+ 'u16',
+ 'u32',
+ 'u64',
+ 'f32',
+ 'f64',
+ 'f80',
+ 'reverse',
+ 'limit',
+ ],
+ },
+ contains: [
+ {
+ begin: [
+ /:/,
+ /[^,\]]/
+ ],
+ beginScope: {
+ 1: 'option',
+ 2: 'number',
+ },
+ },
+ ],
+ };
+
const VARIABLE = {
scope: 'variable',
begin: /,
@@ -106,7 +166,6 @@
keyword: [
'any',
'int',
- 'uint',
'bool',
'num',
'bint',
@@ -119,6 +178,9 @@
'count',
],
},
+ contains: [
+ OPTIONS,
+ ],
};
const REFERENCE = {
@@ -157,6 +219,7 @@
UUID,
BYTES,
NUMBER,
+ OPTIONS,
],
};
@@ -173,6 +236,7 @@
UUID,
BYTES,
NUMBER,
+ OPTIONS,
],
};
@@ -184,6 +248,7 @@
reference: 'variable',
escape: 'subst',
accent: 'title',
+ options: 'title',
},
contains: [
COMMENT,
@@ -197,6 +262,7 @@
UUID,
BYTES,
NUMBER,
+ OPTIONS,
{ // Highlight lone bar for inline text.
scope: 'variable',
begin: /\|/,