Skip to content

Commit bb2f630

Browse files
committed
feat(go): embed the specification's example extensions
The specification's example extension and type YAML under `site/examples` are the only worked examples of large parts of the simple-extension schema — parameterized user-defined types, NSTRUCT structures, variadic and optional parameters, lambda signatures, metadata and deprecation markers — which makes them useful fixtures for the typed parsing that lives downstream in substrait-go. Vendor them alongside the extension, text and test-case data and expose them through a separate `GetSubstraitExamplesFS`. Keeping them in their own directory and their own `embed.FS` is deliberate: they are documentation illustrations, not entries in the Substrait extension catalog, so a consumer walking the extensions FS must not encounter them. `TestExamplesAreNotEmbeddedAsExtensions` asserts that, and fails if a future change flattens the copy. The plan examples in `site/examples/proto-textformat` are not vendored: they are protobuf text format rather than simple-extension YAML, so they belong with the protobuf modules.
1 parent 4141326 commit bb2f630

5 files changed

Lines changed: 64 additions & 2 deletions

File tree

go/substrait-extensions/README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# substrait-extensions (Go)
22

3-
Go access to the [Substrait](https://substrait.io/) specification's extension definitions, text schemas and function test cases, bundled via [`embed.FS`](https://pkg.go.dev/embed).
3+
Go access to the [Substrait](https://substrait.io/) specification's extension definitions, text schemas, function test cases and documentation examples, bundled via [`embed.FS`](https://pkg.go.dev/embed).
44

55
This module ships the raw spec **data only** — it does not generate Go types from the extension schema. Unlike the Python and Rust extensions packages (which generate types with datamodel-code-generator and typify), Go has no canonical JSON-schema code generator, and the extension schema's polymorphic function definitions do not map cleanly onto Go's type system. The typed parsing therefore lives downstream (e.g. in [substrait-go](https://github.com/substrait-io/substrait-go)). This mirrors the Java extensions artifact, which also bundles the data as resources without generating types.
66

77
It is a drop-in replacement for the legacy `embed.FS` module that lived at the root of the substrait specification repository (`github.com/substrait-io/substrait`): the package is named `substrait` and exposes the same accessors, so consumers only change the import path.
88

9-
The data is sourced from [extensions](https://github.com/substrait-io/substrait/tree/main/extensions), [text](https://github.com/substrait-io/substrait/tree/main/text) and [tests/cases](https://github.com/substrait-io/substrait/tree/main/tests/cases) in the substrait repository. Versions of this module correspond to Substrait [releases](https://github.com/substrait-io/substrait/releases).
9+
The data is sourced from [extensions](https://github.com/substrait-io/substrait/tree/main/extensions), [text](https://github.com/substrait-io/substrait/tree/main/text), [tests/cases](https://github.com/substrait-io/substrait/tree/main/tests/cases) and [site/examples](https://github.com/substrait-io/substrait/tree/main/site/examples) in the substrait repository. Versions of this module correspond to Substrait [releases](https://github.com/substrait-io/substrait/releases).
1010

1111
## Module Usage
1212

@@ -17,16 +17,20 @@ func example() {
1717
extFS := substrait.GetSubstraitExtensionsFS() // extensions/*.yaml
1818
textFS := substrait.GetSubstraitTextFS() // text/*.yaml
1919
testsFS := substrait.GetSubstraitTestsFS() // tests/cases/**/*.test
20+
exFS := substrait.GetSubstraitExamplesFS() // examples/{extensions,types}/*.yaml
2021
_ = extFS
2122
_ = textFS
2223
_ = testsFS
24+
_ = exFS
2325
}
2426
```
2527

2628
```sh
2729
go get github.com/substrait-io/substrait-packaging/go/substrait-extensions@vx.y.z
2830
```
2931

32+
The examples returned by `GetSubstraitExamplesFS` are **not** catalog entries: their URNs use an example owner rather than `extension:io.substrait:`, they are deliberately absent from the FS returned by `GetSubstraitExtensionsFS`, and their contents and URNs may change without a deprecation cycle. They ship as fixtures for exercising an extension parser against the corners of the simple-extension schema.
33+
3034
## Generation and Publishing
3135

3236
Code generation and publishing is handled in the [substrait-packaging](https://github.com/substrait-io/substrait-packaging) repository.

go/substrait-extensions/embed.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ var textFS embed.FS
2020
//go:embed tests/cases
2121
var testsFS embed.FS
2222

23+
//go:embed examples
24+
var examplesFS embed.FS
25+
2326
// GetSubstraitFS returns an embed.FS containing the Substrait extension
2427
// definition YAML files under the "extensions" directory.
2528
//
@@ -38,3 +41,13 @@ func GetSubstraitTextFS() embed.FS { return textFS }
3841
// GetSubstraitTestsFS returns an embed.FS containing the Substrait function
3942
// test case files under the "tests/cases" directory.
4043
func GetSubstraitTestsFS() embed.FS { return testsFS }
44+
45+
// GetSubstraitExamplesFS returns an embed.FS containing the example extension
46+
// and type YAML files from the specification's documentation, under the
47+
// "examples/extensions" and "examples/types" directories.
48+
//
49+
// These are illustrations of the simple-extension format, not entries in the
50+
// Substrait extension catalog: they are deliberately absent from the FS returned
51+
// by GetSubstraitExtensionsFS, and their contents and URNs may change without a
52+
// deprecation cycle. They are useful as fixtures for testing an extension parser.
53+
func GetSubstraitExamplesFS() embed.FS { return examplesFS }

go/substrait-extensions/embed_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,37 @@ func TestEmbeddedTests(t *testing.T) {
4545
t.Fatal("no embedded test case files found under tests/cases/")
4646
}
4747
}
48+
49+
func TestEmbeddedExamples(t *testing.T) {
50+
for _, dir := range []string{"examples/extensions", "examples/types"} {
51+
entries, err := GetSubstraitExamplesFS().ReadDir(dir)
52+
if err != nil {
53+
t.Fatal(err)
54+
}
55+
if len(entries) == 0 {
56+
t.Fatalf("no embedded example files found under %s/", dir)
57+
}
58+
}
59+
}
60+
61+
func TestExamplesAreNotEmbeddedAsExtensions(t *testing.T) {
62+
// The examples are illustrations, not catalog entries: code that walks the
63+
// extensions FS must not reach them. Guards against a future change that
64+
// flattens the copy into extensions/.
65+
err := fs.WalkDir(GetSubstraitExtensionsFS(), "extensions", func(path string, d fs.DirEntry, err error) error {
66+
if err != nil {
67+
return err
68+
}
69+
if d.IsDir() && path != "extensions" {
70+
t.Errorf("unexpected subdirectory %s in the extensions FS", path)
71+
}
72+
return nil
73+
})
74+
if err != nil {
75+
t.Fatal(err)
76+
}
77+
78+
if _, err := GetSubstraitExtensionsFS().ReadDir("examples"); err == nil {
79+
t.Fatal("examples/ is reachable from the extensions FS")
80+
}
81+
}

go/substrait-extensions/examples/.gitkeep

Whitespace-only changes.

go/substrait-extensions/generate_extensions.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ SUBSTRAIT_HOME="${SUBSTRAIT_HOME:-../../substrait}"
66
EXTENSIONS_DIR="$SUBSTRAIT_HOME/extensions"
77
TEXT_DIR="$SUBSTRAIT_HOME/text"
88
TESTCASES_DIR="$SUBSTRAIT_HOME/tests/cases"
9+
EXAMPLES_DIR="$SUBSTRAIT_HOME/site/examples"
910

1011
echo "Vendoring Substrait extension files from $SUBSTRAIT_HOME"
1112

@@ -27,3 +28,13 @@ cp "$TEXT_DIR"/*.yaml text/
2728
rm -rf tests/cases
2829
mkdir -p tests/cases
2930
cp -r "$TESTCASES_DIR"/. tests/cases/
31+
32+
# Example extension and type YAML files (embedded via //go:embed examples). These
33+
# are documentation illustrations rather than catalog entries, so they are kept in
34+
# their own directory and their own embed.FS: a consumer walking the extensions FS
35+
# must not encounter them. The plan examples in site/examples/proto-textformat are
36+
# protobuf, not simple-extension YAML, and are not vendored here.
37+
rm -rf examples
38+
mkdir -p examples
39+
cp -r "$EXAMPLES_DIR/extensions" examples/
40+
cp -r "$EXAMPLES_DIR/types" examples/

0 commit comments

Comments
 (0)