pqt

package module
v0.21.0 Latest Latest
Warning

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

Go to latest
Published: Sep 25, 2017 License: MIT Imports: 4 Imported by: 0

README

pqt GoDoc Build Status codecov.io

This package is a toolbox for postgres driven applications. It provides multiple tools to help to work with postgres efficiently. In comparison to other currently available libraries instead of pushing struct tags into anti pattern or parsing SQL, it allows to define schema programmatically.

Features:

  • query builder:
    • Composer - builder like object that keeps buffer and arguments but also tracks positional parameters.
  • array support
    • JSONArrayInt64 - wrapper for []int64, it generates JSONB compatible array [] instead of {}
    • JSONArrayFloat64 - wrapper for []float64, it generates JSONB compatible array [] instead of {}
    • JSONArrayString - wrapper for []string, it generates JSONB compatible array [] instead of {}
  • sql generation
  • go generation - it includes:
    • <table-name>Entity - struct that reflects single row within the database
    • <table-name>Criteria - object that can be passed to the Find method, it allows to create complex queries
      • <table-name>Or - utility function that joins Criteria using logical OR operator
      • <table-name>And - utility function that joins Criteria using logical AND operator
    • <table-name>Patch - structure used by UpdateOneBy<primary-key> methods to modify existing cri
    • <table-name>Iterator - interface used by FindIter methods as a result, implementation is <table-name>Rows - it wraps sql.Rows
    • constants:
      • complete names
      • column names
      • constraints - library generates exact names of each constraint and corresponding constant that allow to easily handle query errors using ErrorConstraint helper function
    • <table-name>Repository - data access layer that expose API to manipulate entities:
      • Count - returns number of entities for given cri
      • Find - returns collection of entities that match given cri
      • FindIter - works like Find but returns iterator
      • Insert - saves given cri into the database
      • FindOneBy<primary-key> - retrieves single cri, search by primary key
      • FindOneBy<unique-key> - retrieves single cri, search by unique key
      • UpdateOneBy<primary-key> - modifies single cri, search by primary key
      • UpdateOneBy<unique-key> - modifies single cri, search by unique key
      • DeleteOneBy<primary-key> - modifies single cri, search by primary key
    • func Scan<Entity>Rows(rows *sql.Rows) ([]*<cri>Entity, error) { helper function
  • schema definition - allow to programmatically define database schema, that includes:
    • schemas
    • tables
    • columns
    • constraints
    • relationships
  • helper functions
    • ErrorConstraint - if possible extracts constraint from pq.Error so it's easy to build switch statements using generated constraints.

Documentation

Plugins

pqtgo supports plugins over the interface.

Example

Package itself do not provide any command line application that would generate output out of given input. Instead it encourage to write local generation application next to the proper package. Good example how such application could be structured can be found in examples.

By default example is trying to connect to local test database on default port. To run it simply call:

$ make gen // not necessary, since generated code is already part of the repo
$ make run

Contribution

Very welcome in general. Especially in fields like:

TODO

  • Change <entity-name>FindExpr.OrderBy to slice.
  • Postgres types better support.
  • Support for functions.
  • Selective go/sql generation.
  • Logical operations (AND, OR)
  • Refactor WithXXX functions to be prefixed by the type they return for example TableWithIfNotExists or ColumnWithNotNull.
  • Constraint.
    • Index
    • Unique
    • Primary Key
    • Foreign Key
    • Check
    • Exclusion

Documentation

Index

Constants

View Source
const (
	// RelationshipTypeOneToOne is a relationship that each row in one database table is linked to 1 and only 1 other row in another table.
	// In a one-to-one relationship between Table A and Table B, each row in Table A is linked to another row in Table B.
	// The number of rows in Table A must equal the number of rows in Table B
	RelationshipTypeOneToOne RelationshipType = iota
	// RelationshipTypeOneToMany is a relationship that each row in the related to table can be related to many rows in the relating table.
	// This allows frequently used information to be saved only once in a table and referenced many times in all other tables.
	RelationshipTypeOneToMany
	// RelationshipTypeManyToOne works like one to many, but it points to another owner.
	RelationshipTypeManyToOne

	// RelationshipTypeManyToMany is combination of two many to one relationships.
	// Needs proxy table.
	RelationshipTypeManyToMany

	// NoAction produce an error indicating that the deletion or update would create a foreign key constraint violation.
	// If the constraint is deferred, this error will be produced at constraint check time if there still exist any referencing rows.
	// This is the default action.
	NoAction int32 = iota
	// Restrict produce an error indicating that the deletion or update would create a foreign key constraint violation.
	// This is the same as NO ACTION except that the check is not deferrable.
	Restrict
	// Cascade delete any rows referencing the deleted row,
	// or update the values of the referencing column(s) to the new values of the referenced columns, respectively.
	Cascade
	// SetNull set the referencing column(s) to null
	SetNull
	// SetDefault set the referencing column(s) to their default values.
	// (There must be a row in the referenced table matching the default values, if they are not null, or the operation will fail
	SetDefault
)

Variables

This section is empty.

Functions

func IsCheck

func IsCheck(c string) bool

IsCheck returns true if string has suffix "_check".

func IsForeignKey

func IsForeignKey(c string) bool

IsForeignKey returns true if string has suffix "_fkey".

func IsIndex

func IsIndex(c string) bool

IsIndex returns true if string has suffix "_idx".

func IsPrimaryKey

func IsPrimaryKey(c string) bool

IsPrimaryKey returns true if string has suffix "_pkey".

func IsUnique

func IsUnique(c string) bool

IsUnique returns true if string has suffix "_key".

func JoinColumns

func JoinColumns(columns Columns, sep string) string

JoinColumns ...

Types

type Attribute

type Attribute struct {
	Name, Collate, Default, Check string
	NotNull, Unique, PrimaryKey   bool
	Schema                        *Schema
	Type                          Type
}

Attribute ...

func (*Attribute) Constraint

func (a *Attribute) Constraint() (*Constraint, bool)

Constraint ...

type BaseType

type BaseType struct {
	// contains filtered or unexported fields
}

BaseType ...

func TypeBool

func TypeBool() BaseType

TypeBool is a state of true or false.

func TypeBytea

func TypeBytea() BaseType

TypeBytea ...

func TypeCharacter

func TypeCharacter(l int) BaseType

TypeCharacter is physically padded with spaces to the specified width n, and are stored and displayed that way.

func TypeDecimal

func TypeDecimal(precision, scale int) BaseType

TypeDecimal ...

func TypeDoubleArray

func TypeDoubleArray(l int) BaseType

TypeDoubleArray ...

func TypeDoublePrecision

func TypeDoublePrecision() BaseType

TypeDoublePrecision is a numeric type with 15 decimal digits precision.

func TypeInteger

func TypeInteger() BaseType

TypeInteger is the common choice, as it offers the best balance between range, storage size, and performance.

func TypeIntegerArray

func TypeIntegerArray(l int) BaseType

TypeIntegerArray ...

func TypeIntegerBig

func TypeIntegerBig() BaseType

TypeIntegerBig is designed to be used when the range of the TypeInteger is insufficient.

func TypeIntegerBigArray

func TypeIntegerBigArray(l int) BaseType

TypeIntegerBigArray ...

func TypeIntegerSmall

func TypeIntegerSmall() BaseType

TypeIntegerSmall is generally only used if disk space is at a premium.

func TypeIntegerSmallArray

func TypeIntegerSmallArray(l int) BaseType

TypeIntegerSmallArray ...

func TypeJSON

func TypeJSON() BaseType

TypeJSON is for storing JSON (JavaScript Object Notation) data, as specified in RFC 7159. Such data can also be stored as text, but the JSON data types have the advantage of enforcing that each stored value is valid according to the JSON rules.

func TypeJSONB

func TypeJSONB() BaseType

TypeJSONB in compare to TypeJSON is stored in a decomposed binary format that makes it slightly slower to input due to added conversion overhead, but significantly faster to process, since no reparsing is needed. JSONB also supports indexing, which can be a significant advantage.

func TypeNumeric

func TypeNumeric(precision, scale int) BaseType

TypeNumeric can store numbers with a very large number of digits. It is especially recommended for storing monetary amounts and other quantities where exactness is required. Calculations with numeric values yield exact results where possible, e.g. addition, subtraction, multiplication. However, calculations on numeric values are very slow compared to the integer types, or to the floating-point types described in the next section.

func TypeReal

func TypeReal() BaseType

TypeReal ...

func TypeSerial

func TypeSerial() BaseType

TypeSerial ...

func TypeSerialBig

func TypeSerialBig() BaseType

TypeSerialBig ...

func TypeSerialSmall

func TypeSerialSmall() BaseType

TypeSerialSmall ...

func TypeText

func TypeText() BaseType

TypeText is variable-length character string.

func TypeTextArray

func TypeTextArray(l int) BaseType

TypeTextArray ...

func TypeTimestamp

func TypeTimestamp() BaseType

TypeTimestamp is a date and time (no time zone).

func TypeTimestampTZ

func TypeTimestampTZ() BaseType

TypeTimestampTZ is a date and time, including time zone

func TypeUUID

func TypeUUID() BaseType

TypeUUID stores Universally Unique Identifiers (UUID) as defined by RFC 4122, ISO/IEC 9834-8:2005, and related standards. (Some systems refer to this data type as a globally unique identifier, or GUID, instead.) This identifier is a 128-bit quantity that is generated by an algorithm chosen to make it very unlikely that the same identifier will be generated by anyone else in the known universe using the same algorithm. Therefore, for distributed systems, these identifiers provide a better uniqueness guarantee than sequence generators, which are only unique within a single database.

func TypeVarchar

func TypeVarchar(l int) BaseType

TypeVarchar ...

func (BaseType) Fingerprint

func (bt BaseType) Fingerprint() string

Fingerprint implements Type interface.

func (BaseType) String

func (bt BaseType) String() string

String implements Stringer interface.

type Column

type Column struct {
	Name, ShortName, Collate, Check                                      string
	Default                                                              map[Event]string
	NotNull, Unique, PrimaryKey, Index                                   bool
	Type                                                                 Type
	Table                                                                *Table
	Reference                                                            *Column
	ReferenceOptions                                                     []RelationshipOption
	Match, OnDelete, OnUpdate                                            int32
	NoInherit, DeferrableInitiallyDeferred, DeferrableInitiallyImmediate bool
	// Dynamic
	IsDynamic bool
	Func      *Function
	Columns   Columns
}

Column ...

func NewColumn

func NewColumn(n string, t Type, opts ...ColumnOption) *Column

NewColumn ...

func NewDynamicColumn added in v0.13.0

func NewDynamicColumn(n string, f *Function, cs ...*Column) *Column

NewDynamicColumn ...

func (*Column) Constraints

func (c *Column) Constraints() []*Constraint

Constraints ...

func (Column) DefaultOn

func (c Column) DefaultOn(e ...Event) (string, bool)

DefaultOn ...

type ColumnOption

type ColumnOption func(*Column)

ColumnOption configures how we set up the column.

func WithCheck

func WithCheck(ch string) ColumnOption

WithCheck ...

func WithCollate

func WithCollate(cl string) ColumnOption

WithCollate ...

func WithColumnShortName added in v0.3.0

func WithColumnShortName(s string) ColumnOption

WithColumnShortName ...

func WithDefault

func WithDefault(d string, e ...Event) ColumnOption

WithDefault ...

func WithIndex added in v0.15.0

func WithIndex() ColumnOption

WithIndex ...

func WithNotNull

func WithNotNull() ColumnOption

WithNotNull ...

func WithOnDelete

func WithOnDelete(on int32) ColumnOption

WithOnDelete add ON DELETE clause that specifies the action to perform when a referenced row in the referenced table is being deleted

func WithOnUpdate

func WithOnUpdate(on int32) ColumnOption

WithOnUpdate add ON UPDATE clause that specifies the action to perform when a referenced column in the referenced table is being updated to a new value.

func WithPrimaryKey

func WithPrimaryKey() ColumnOption

WithPrimaryKey ...

func WithReference

func WithReference(r *Column, opts ...RelationshipOption) ColumnOption

WithReference ...

func WithTypeMapping

func WithTypeMapping(t Type) ColumnOption

WithTypeMapping ...

func WithUnique

func WithUnique() ColumnOption

WithUnique ...

type Columns

type Columns []*Column

Columns is a slice of columns that implements few handy methods.

func (Columns) Len

func (c Columns) Len() int

Len implements sort.Interface interface.

func (Columns) Less

func (c Columns) Less(i, j int) bool

Less implements sort.Interface interface.

func (Columns) String

func (c Columns) String() string

String implements Stringer interface.

func (Columns) Swap

func (c Columns) Swap(i, j int)

Swap implements sort.Interface interface.

type CompositeType

type CompositeType struct {
	Attributes []*Attribute
	// contains filtered or unexported fields
}

CompositeType represents the structure of a row or record. It is essentially just a list of field names and their data types. PostgreSQL allows composite types to be used in many of the same ways that simple types can be used. For example, a column of a table can be declared to be of a composite type. EXPERIMENTAL

func TypeComposite

func TypeComposite(name string, attributes ...*Attribute) CompositeType

TypeComposite allocates CompositeType with given name and attributes.

func (CompositeType) Fingerprint

func (ct CompositeType) Fingerprint() string

Fingerprint implements Type interface.

func (CompositeType) String

func (ct CompositeType) String() string

String implements Stringer interface.

type Constraint

type Constraint struct {
	Type                                                                 ConstraintType
	Where, Check                                                         string
	PrimaryTable, Table                                                  *Table
	PrimaryColumns, Columns                                              Columns
	Attribute                                                            []*Attribute
	Match, OnDelete, OnUpdate                                            int32
	NoInherit, DeferrableInitiallyDeferred, DeferrableInitiallyImmediate bool
}

Constraint ...

func Check

func Check(table *Table, check string, columns ...*Column) *Constraint

Check ...

func ForeignKey

func ForeignKey(primaryColumns, referenceColumns Columns, opts ...ConstraintOption) *Constraint

ForeignKey constraint specifies that the values in a column (or a group of columns) must match the values appearing in some row of another table. We say this maintains the referential integrity between two related tables.

func Index

func Index(table *Table, columns ...*Column) *Constraint

Index ...

func PrimaryKey

func PrimaryKey(table *Table, columns ...*Column) *Constraint

PrimaryKey constraint is simply a combination of a unique constraint and a not-null constraint.

func Unique

func Unique(table *Table, columns ...*Column) *Constraint

Unique constraint ensure that the data contained in a column or a group of columns is unique with respect to all the rows in the table.

func (*Constraint) Name

func (c *Constraint) Name() string

Name ...

func (*Constraint) String

func (c *Constraint) String() string

String implements Stringer interface.

type ConstraintOption

type ConstraintOption func(*Constraint)

ConstraintOption ...

type ConstraintType added in v0.15.0

type ConstraintType string
const (
	// ConstraintTypeUnknown ...
	ConstraintTypeUnknown ConstraintType = "unknown"
	// ConstraintTypePrimaryKey ...
	ConstraintTypePrimaryKey ConstraintType = "pkey"
	// ConstraintTypeCheck ...
	ConstraintTypeCheck ConstraintType = "check"
	// ConstraintTypeUnique ...
	ConstraintTypeUnique ConstraintType = "key"
	// ConstraintTypeIndex ...
	ConstraintTypeIndex ConstraintType = "idx"
	// ConstraintTypeForeignKey ...
	ConstraintTypeForeignKey ConstraintType = "fkey"
	// ConstraintTypeExclusion ...
	ConstraintTypeExclusion ConstraintType = "excl"
)

type Constraints added in v0.15.0

type Constraints []*Constraint

func (Constraints) CountOf added in v0.15.0

func (c Constraints) CountOf(types ...ConstraintType) int

CountOf returns number of constraints of given type. If nothing is given return length of entire slice.

type EnumeratedType

type EnumeratedType struct {
	Enums []string
	// contains filtered or unexported fields
}

EnumeratedType ... EXPERIMENTAL

func TypeEnumerated

func TypeEnumerated(name string, enums ...string) EnumeratedType

TypeEnumerated ...

func (EnumeratedType) Fingerprint

func (et EnumeratedType) Fingerprint() string

Fingerprint implements Type interface.

func (EnumeratedType) String

func (et EnumeratedType) String() string

String implements Stringer interface.

type Event

type Event string

Event ...

const (
	// EventInsert ...
	EventInsert Event = "INSERT"
	// EventUpdate ...
	EventUpdate Event = "UPDATE"
)

type Function

type Function struct {
	Name      string
	BuiltIn   bool
	Type      Type
	Body      string
	Behaviour FunctionBehaviour
	Args      []*FunctionArg
}

Function ...

func FunctionNow

func FunctionNow() *Function

FunctionNow ...

type FunctionArg added in v0.13.0

type FunctionArg struct {
	Name string
	Type Type
}

FunctionArg ...

type FunctionBehaviour added in v0.13.0

type FunctionBehaviour int
const (
	// FunctionBehaviourVolatile indicates that the function value can change even within a single table scan,
	// so no optimizations can be made.
	// Relatively few database functions are volatile in this sense; some examples are random(), currval(), timeofday().
	// But note that any function that has side-effects must be classified volatile, even if its result is quite predictable,
	// to prevent calls from being optimized away; an example is setval().
	FunctionBehaviourVolatile FunctionBehaviour = iota
	// FunctionBehaviourImmutable indicates that the function cannot modify the database and always returns the same result when given the same argument values;
	// that is, it does not do database lookups or otherwise use information not directly present in its argument list.
	// If this option is given, any call of the function with all-constant arguments can be immediately replaced with the function value.
	FunctionBehaviourImmutable
	// FunctionBehaviourStable indicates that the function cannot modify the database,
	// and that within a single table scan it will consistently return the same result for the same argument values,
	// but that its result could change across SQL statements.
	// This is the appropriate selection for functions whose results depend on database lookups,
	// parameter variables (such as the current time zone), etc.
	// (It is inappropriate for AFTER triggers that wish to query rows modified by the current command.)
	// Also note that the current_timestamp family of functions qualify as stable, since their values do not change within a transaction.
	FunctionBehaviourStable
)

type MappableType

type MappableType struct {
	From    Type
	Mapping []Type
}

MappableType ...

func TypeMappable

func TypeMappable(from Type, mapping ...Type) MappableType

TypeMappable ...

func (MappableType) Fingerprint

func (mt MappableType) Fingerprint() string

Fingerprint implements Type interface.

func (MappableType) String

func (mt MappableType) String() string

String implements Stringer interface.

type PseudoType

type PseudoType struct {
	// contains filtered or unexported fields
}

PseudoType ... EXPERIMENTAL

func TypePseudo

func TypePseudo(name string) PseudoType

TypePseudo ...

func (PseudoType) Fingerprint

func (pt PseudoType) Fingerprint() string

Fingerprint implements Type interface.

func (PseudoType) String

func (pt PseudoType) String() string

String implements Stringer interface.

type Reference

type Reference struct {
	From, To *Column
}

Reference ...

type Relationship

type Relationship struct {
	Bidirectional                           bool
	Type                                    RelationshipType
	OwnerName, InversedName                 string
	OwnerTable, InversedTable, ThroughTable *Table
	OwnerForeignKey, InversedForeignKey     *Constraint
	OwnerColumns, InversedColumns           Columns
	ColumnName                              string
	OnDelete, OnUpdate                      int32
}

Relationship ...

func ManyToMany

func ManyToMany(t1 *Table, t2 *Table, opts ...RelationshipOption) *Relationship

ManyToMany ...

func ManyToOne

func ManyToOne(t *Table, opts ...RelationshipOption) *Relationship

ManyToOne ...

func OneToMany

func OneToMany(t *Table, opts ...RelationshipOption) *Relationship

OneToMany ...

func OneToOne

func OneToOne(t *Table, opts ...RelationshipOption) *Relationship

OneToOne ...

type RelationshipOption

type RelationshipOption func(*Relationship)

RelationshipOption configures how we set up the relationship.

func WithBidirectional

func WithBidirectional() RelationshipOption

WithBidirectional ...

func WithColumnName

func WithColumnName(n string) RelationshipOption

WithColumnName ...

func WithForeignKey added in v0.18.0

func WithForeignKey(primaryColumns, referenceColumns Columns, opts ...ConstraintOption) RelationshipOption

WithForeignKey ...

func WithInversedForeignKey

func WithInversedForeignKey(primaryColumns, referenceColumns Columns, opts ...ConstraintOption) RelationshipOption

WithInversedForeignKey ...

func WithInversedName

func WithInversedName(s string) RelationshipOption

WithInversedName ...

func WithOwnerForeignKey

func WithOwnerForeignKey(primaryColumns, referenceColumns Columns, opts ...ConstraintOption) RelationshipOption

WithOwnerForeignKey ...

func WithOwnerName

func WithOwnerName(s string) RelationshipOption

WithOwnerName ...

type RelationshipType

type RelationshipType int

RelationshipType ...

type Schema

type Schema struct {
	Name        string
	IfNotExists bool
	Tables      []*Table
	Functions   []*Function
	Types       []Type
}

Schema ...

func NewSchema

func NewSchema(name string, opts ...SchemaOption) *Schema

NewSchema ...

func (*Schema) AddFunction added in v0.13.0

func (s *Schema) AddFunction(f *Function) *Schema

func (*Schema) AddTable

func (s *Schema) AddTable(t *Table) *Schema

AddTable ...

type SchemaOption added in v0.4.0

type SchemaOption func(*Schema)

SchemaOption configures how we set up a schema.

func WithSchemaIfNotExists added in v0.4.0

func WithSchemaIfNotExists() SchemaOption

WithSchemaIfNotExists is schema option that sets IfNotExists flag to true.

type Table

type Table struct {
	Name, ShortName, Collate, TableSpace string
	IfNotExists, Temporary               bool
	Schema                               *Schema
	Columns                              Columns
	Constraints                          Constraints
	OwnedRelationships                   []*Relationship
	InversedRelationships                []*Relationship
	ManyToManyRelationships              []*Relationship
	// contains filtered or unexported fields
}

Table is partially implemented postgres table synopsis.

func NewTable

func NewTable(name string, opts ...TableOption) *Table

NewTable allocates new table using given name and options.

func SelfReference

func SelfReference() *Table

SelfReference returns almost empty table that express self reference. Should be used with relationships.

func (*Table) AddCheck

func (t *Table) AddCheck(check string, columns ...*Column) *Table

AddCheck adds check constraint to the table.

func (*Table) AddColumn

func (t *Table) AddColumn(c *Column) *Table

AddColumn adds column to the table.

func (*Table) AddConstraint

func (t *Table) AddConstraint(c *Constraint) *Table

AddConstraint adds constraint to the table.

func (*Table) AddIndex added in v0.15.0

func (t *Table) AddIndex(columns ...*Column) *Table

AddIndex adds index to the table.

func (*Table) AddRelationship

func (t *Table) AddRelationship(r *Relationship, opts ...ColumnOption) *Table

AddRelationship adds relationship to the table.

func (*Table) AddUnique

func (t *Table) AddUnique(columns ...*Column) *Table

AddUnique adds unique constraint to the table.

func (*Table) FullName

func (t *Table) FullName() string

FullName if schema is defined returns name in format <schema>.<name> or just <name> if not set.

func (*Table) PrimaryKey

func (t *Table) PrimaryKey() (*Column, bool)

PrimaryKey returns column that is primary key, or false if none.

func (*Table) SetIfNotExists

func (t *Table) SetIfNotExists(ine bool) *Table

SetIfNotExists sets IfNotExists flag.

func (*Table) SetSchema

func (t *Table) SetSchema(s *Schema) *Table

SetSchema sets schema name table belongs to.

type TableOption

type TableOption func(*Table)

TableOption configures how we set up the table.

func WithTableIfNotExists added in v0.4.0

func WithTableIfNotExists() TableOption

WithTableIfNotExists is table option that sets IfNotExists flag to true.

func WithTableShortName added in v0.3.0

func WithTableShortName(s string) TableOption

WithTableShortName ...

func WithTableSpace

func WithTableSpace(s string) TableOption

WithTableSpace pass the name of the tablespace in which the new table is to be created. If not specified, default_tablespace is consulted, or temp_tablespaces if the table is temporary.

func WithTemporary

func WithTemporary() TableOption

WithTemporary specified, the table is created as a temporary table. Temporary tables are automatically dropped at the end of a session, or optionally at the end of the current transaction (see ON COMMIT below). Existing permanent tables with the same name are not visible to the current session while the temporary table exists, unless they are referenced with schema-qualified names. Any indexes created on a temporary table are automatically temporary as well.

type Type

type Type interface {
	fmt.Stringer
	// Fingerprint returns unique identifier of the type. Two different types can have same SQL representation.
	Fingerprint() string
}

Type ...

Directories

Path Synopsis
example
app
app/internal/model
Code generated by pqt.
Code generated by pqt.

Jump to

Keyboard shortcuts

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