Skip to content

Commit

Permalink
Added data encoding & big int.
Browse files Browse the repository at this point in the history
  • Loading branch information
janderland committed Mar 13, 2024
1 parent dda168d commit b67b329
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 41 deletions.
2 changes: 2 additions & 0 deletions syntax.ebnf
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ float = int '.' number

scientific = ( int | float ) 'e' int

bigint = '#' int

string = '"' { text | '\"' } '"'

uuid = ( 8 * hexDigit ) '-' ( 4 * hexDigit ) '-' ( 4 * hexDigit ) '-' ( 4 * hexDigit ) '-' ( 12 * hexDigit )
Expand Down
117 changes: 76 additions & 41 deletions vision.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
# Foundation QL Vision
# Foundation QL Handbook

Foundation QL is a query language for Foundation DB. FQL
aims to make FDB's semantics feel natural and intuitive.
Common patterns like index indirection and chunked range
reads are first class citizens.

> __NOTE:__ This document expects the reader to have a basic
> knowledge of FDB, and it's tuple & directory layers.
FQL may also be used as a [Go API](#language-integration)
which is structurally equivalent to the query language.
which is structurally equivalent to the query language.

FQL is a work in-progress: the features mentioned in
this document are not all implemented. Unimplemented
features will be marked as such with a callout.

This document expects the reader to have a basic
understanding of Foundation DB, and it's directory &
tuple layers.

## Query Basics
## Basics

An FQL query looks like a key-value. Queries include
a directory, tuple, and value. FQL can only access keys
encoded by the directory & tuples layers.
sections for a directory, tuple, and value. FQL can only
access keys encoded by the directory & tuples layers.

```fql
/my/directory("my","tuple")=4000
Expand All @@ -29,26 +34,31 @@ from the database.
/my/directory("my","tuple")=<>
```

The query above has a variable (`<>`) in its value section
and will read a single key from the database.
The query above has a variable `<>` in its value section
and will read a single key-value from the database, if the
key exists.

FQL queries can also perform range reads by including
a variable in the tuple section.
FQL queries can also perform range reads by including a
variable in the tuple section.

```fql
/my/directory(<>,"tuple")=<>
```

The query above will range read all key-values which
conform to the schema defined by the query. For instance,
the key-value `/my/directory("my","tuple")=nil` conforms
and would be returned.

All key-values with a certain prefix can be range read by
ending the tuple with `...`.

```fql
/my/directory("my","tuple",...)=<>
```

Including a variable in the directory section tells FQL to
perform the read on all directory paths matching the
pattern.
Including a variable in the directory tells FQL to perform
the read on all directory paths matching the schema.

```fql
/<>/directory("my","tuple")=<>
Expand All @@ -64,10 +74,10 @@ identical to the one above.

## Data Elements

In an FQL query, the directory, tuple, and value
contain instances of data elements. FQL utilizes the
same types of elements as the tuple layer. Example
instances of these types can be seen below.
In an FQL query, the directory, tuple, and value contain
instances of data elements. FQL utilizes the same types of
elements as the tuple layer. Example instances of these
types can be seen below.

| Type | Example |
|:---------|:---------------------------------------|
Expand All @@ -76,23 +86,43 @@ instances of these types can be seen below.
| `uint` | `7` |
| `bool` | `true` |
| `float` | `33.4` |
| `bigint` | `#35299340192843523485929848293291842` |
| `string` | `"string"` |
| `bytes` | `0xa2bff2438312aac032` |
| `uuid` | `5a5ebefd-2193-47e2-8def-f464fc698e31` |
| `tuple` | `("hello",27.4,nil)` |

> __NOTE:__ FDB tuples can also include variable length
> integers (bigint). While these are not currently
> supported by FQL, they will be in the future.
> __NOTE:__ `bigint` support is not yet implemented.
The directory may only contain strings. Directory strings
don't need to be quoted if they only contain
alphanumerics, `.`, or `_`. The tuple & value may
contain any of the data elements.
don't need to be quoted if they only contain alphanumerics,
`.`, or `_`. The tuple & value may contain any of the data
elements.

For the precise syntax definitions of each data type, see
the [syntax document](syntax.ebnf).

## Data Encoding

TODO: Finish section.
The directory and tuple layers are responsible for
encoding the data elements in the key section. As for the
value section, FDB doesn't provide a standard encoding.

The table below outlines how data elements are encoded
when present in the value section.

| Type | Encoding |
|:---------|:--------------------------------|
| `nil` | empty value |
| `int` | 64-bit, 1's compliment |
| `uint` | 64-bit |
| `bool` | single byte, `0x00` means false |
| `float` | IEEE 754 |
| `bigint` | not implemented yet |
| `string` | ASCII |
| `bytes` | as provided |
| `uuid` | RFC 4122 |
| `tuple` | tuple layer |

## Variables

Expand All @@ -119,10 +149,6 @@ In the query above, the 2nd element of the key's tuple must
be either an integer or string. Likewise, the value must be
a tuple.

> __NOTE:__ FQL does not currently provide a way to
> constrain a variable to range of values, though this could
> be added in the future.
## Index Indirection

TODO: Finish section.
Expand Down Expand Up @@ -170,11 +196,7 @@ import (

func _() {
fdb.MustAPIVersion(620)
eg := engine.New(facade.NewTransactor(
fdb.MustOpenDefault(),
// Choose a global directory root for all queries.
directory.Root(),
))
eg := engine.New(facade.NewTransactor(fdb.MustOpenDefault(), directory.Root()))

// /user/entry(22573,"Goodwin","Samuels")=nil
query := kv.KeyValue{
Expand All @@ -192,6 +214,7 @@ func _() {
Value: kv.Nil{},
}

// Perform the write.
err := eg.Set(query);
if err != nil {
panic(err)
Expand All @@ -202,25 +225,37 @@ func _() {
Code generation tooling could be provided to lessen the
verbosity of the host language's syntax.

> __NOTE:__ This code generation is not currently
> implemented.
```go
package example

// Generate a function which binds args to the query.
import (
"github.com/apple/foundationdb/bindings/go/src/fdb"
"github.com/apple/foundationdb/bindings/go/src/fdb/directory"

"github.com/janderland/fdbq/engine"
"github.com/janderland/fdbq/engine/facade"
kv "github.com/janderland/fdbq/keyval"
)

// Generate a function `getFullName` which binds args to the query.
//go:generate fql --gen getFullName '/user/entry(?,<string>,<string>)'

func _() {
fdb.MustAPIVersion(620)
eg := engine.New(facade.NewTransactor(
fdb.MustOpenDefault(),
// Choose a global directory root for all queries.
directory.Root(),
))
eg := engine.New(facade.NewTransactor(fdb.MustOpenDefault(), directory.Root()))

const userID = 22573
// Call the generated function which creates the query.
query := getFullName(userID)
res, err := eg.SingleRead(query)
if err != nil {
panic(err)
}

firstName := res.Key.Tuple[1].(string)
LastName := res.Key.Tuple[2].(string)
}
```

0 comments on commit b67b329

Please sign in to comment.