include

package
v0.3.11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 4, 2023 License: MIT Imports: 5 Imported by: 0

README

pggen/include

The include package provides a way to specify a tree of descendant objects to be loaded from the postgres database by the FillIncludes generated method. For more details on the specifics of include specs, see the package godoc.

Documentation

Overview

package include defines include specs, which represent a subset of the object graph in the database. They can be used to instruct the code generated by pggen to load child entities attached to a given entity by a 1-1, 1-* or *-* relationship in an efficient way that avoids N+1 queries.

In order to make defining include specs more convenient, they have a simple textual syntax for describing them. The syntax for include specs is reminiscent of dot access syntax, except that multiple tables can be accessed at once. For example, if you had an `foos` table that had a 1-* relationship with a `bars` table, you could use the following to produce an `include.Spec` to efficiently load all the bars attached to a foo:

```go spec := include.Must(include.Parse("foos.bars")) ```

Dot access syntax works well enough when a table has just a single relationship, but it doesn't handle relationships with multiple tables, so include spec syntax allows you to write a list of sub-specs separated by commas and enclosed in a set of curly braces.

For example, if the `foos` table also had a `bazes` attached to it with a 1-* relationship and the `bars` table had a `quxes` table attached to it in the same way, you could use to following to create a spec for loading all the objects attached to a given foo, even transitively.

```go spec := include.Must(include.Parse("foos.{bars.quxes, bazes}")) ```

In order to match the semantics of SQL, include specs allow quoted identifiers, so the spec `"space table".{"how odd", "right?"}` is a valid include spec. Just like in SQL, you can escape a `"` in a quoted identifier with `""`.

If a parent table uses a name besides the name of a child table to refer to it, the include spec must include this information somehow. In order to do this, include specs have rename expressions, which consist of the name used by the parent the '->' operator and the name of the child table. For example if the `sales` table referred to the users table with the name `customer`, an include spec for pulling customer data would look like `sales.customer->users`.

More formally, the grammar for include specs is:

spec ::= id

| id '.' inner_spec
| id '.' '{' spec_list '}'

inner_spec ::= id

| rename_or_id '.' inner_spec
| rename_or_id '.' '{' spec_list '}'

rename_or_id ::= id '->' id

| id

spec_list ::= inner_spec

| inner_spec ',' inner_spec

Cyclic Include Specs:

The object graph in a database schema might have cyclic references, which don't map the most obviously to the hierarchical representation used by include specs, especially in their textual form. Include specs can still be used to describe cycles though. Each cycle in an include spec has a root node, which is the one closest to the root node of the include spec. Cycles are expressed as the path from the root node back to itself.

For example, if the table `foo` referenced the table `bar` which contained a reference back to `foo`, the include spec `foo.bar.foo` could be used to capture that cycle.

Filling in Parent References:

SQL references are bidirectional, and pggen preserves those semantics in generated code by emitting pointers back to parent records in the model structs that it generates. These can be filled in using include specs, just like ordinary references, and doing so will not hit the database again if the parent record had already been loaded into memory. You do still need to explicitly tell pggen to fill in these references for you, which you can do by adding a sub-spec pointing to the parent. For example if the `bar` table refers to the `foo` table with a foreign key, we would usually think of the `foo` table as the parent and the `bar` table as the child. We have already seen that the include spec `foo.bar` would fill in the references in the generated `Foo` struct with generated `Bar` structs, but that won't fill in the references back to the parent from the `Bar` children. To do that we would need to use an include spec of `foo.bar.foo`.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Spec

type Spec struct {
	// The name of the table that this is a spec for filling in
	TableName string
	// All the child tables to fill in
	Includes map[string]*Spec
}

Spec is the parsed form of an include spec. Specs can be constructed directly, or parsed from a terse string format using the Parse routine.

func Must

func Must(spec *Spec, err error) *Spec

Must can be used to turn an error from `include.Parse` into a panic

func Parse

func Parse(src string) (spec *Spec, err error)

Parse an Spec from the given source string or an error on failure

func (*Spec) String

func (s *Spec) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL