{{/* Copyright 2019-present Facebook Inc. All rights reserved. This source code is licensed under the Apache 2.0 license found in the LICENSE file in the root directory of this source tree. */}} {{ define "dialect/sql/query" }} {{ $pkg := $.Scope.Package }} {{ $builder := pascal $.Scope.Builder }} {{ $receiver := receiver $builder }} func ({{ $receiver }} *{{ $builder }}) sqlAll(ctx context.Context) ([]*{{ $.Name }}, error) { rows := &sql.Rows{} selector := {{ $receiver }}.sqlQuery() if unique := {{ $receiver }}.unique; len(unique) == 0 { selector.Distinct() } query, args := selector.Query() if err := {{ $receiver }}.driver.Query(ctx, query, args, rows); err != nil { return nil, err } defer rows.Close() {{- $ret := plural $.Receiver }} var {{ $ret }} {{ plural $.Name }} if err := {{ $ret }}.FromRows(rows); err != nil { return nil, err } {{ $ret }}.config({{ $receiver }}.config) return {{ $ret }}, nil } func ({{ $receiver }} *{{ $builder }}) sqlCount(ctx context.Context) (int, error) { rows := &sql.Rows{} selector := {{ $receiver }}.sqlQuery() unique := []string{ {{ $.Package }}.{{ $.ID.Constant }} } if len({{ $receiver }}.unique) > 0 { unique = {{ $receiver }}.unique } selector.Count(sql.Distinct(selector.Columns(unique...)...)) query, args := selector.Query() if err := {{ $receiver }}.driver.Query(ctx, query, args, rows); err != nil { return 0, err } defer rows.Close() if !rows.Next() { return 0, errors.New("{{ $pkg }}: no rows found") } var n int if err := rows.Scan(&n); err != nil { return 0, fmt.Errorf("{{ $pkg }}: failed reading count: %v", err) } return n, nil } func ({{ $receiver }} *{{ $builder }}) sqlExist(ctx context.Context) (bool, error) { n, err := {{ $receiver }}.sqlCount(ctx) if err != nil { return false, fmt.Errorf("{{ $pkg }}: check existence: %v", err) } return n > 0, nil } func ({{ $receiver }} *{{ $builder }}) sqlIDs(ctx context.Context) ([]{{ $.ID.Type }}, error) { vs, err := {{ $receiver }}.sqlAll(ctx) if err != nil { return nil, err } var ids []{{ $.ID.Type }} for _, v := range vs { ids = append(ids, v.ID) } return ids, nil } func ({{ $receiver }} *{{ $builder }}) sqlQuery() *sql.Selector { t1 := sql.Table({{ $.Package }}.Table) selector := sql.Select(t1.Columns({{ $.Package }}.Columns...)...).From(t1) if {{ $receiver }}.sql != nil { selector = {{ $receiver }}.sql selector.Select(selector.Columns({{ $.Package }}.Columns...)...) } for _, p := range {{ $receiver }}.predicates { p(selector) } for _, p := range {{ $receiver }}.order { p(selector) } if offset := {{ $receiver }}.offset; offset != nil { // limit is mandatory for offset clause. We start // with default value, and override it below if needed. selector.Offset(*offset).Limit(math.MaxInt32) } if limit := {{ $receiver }}.limit; limit != nil { selector.Limit(*limit) } return selector } {{ end }} {{/* query/path defines the query generation for path of a given edge. */}} {{ define "dialect/sql/query/path" }} {{- $e := $.Scope.Edge }} {{/* the edge we need to genegrate the path to. */}} {{- $receiver := $.Scope.Receiver }} {{- if $e.M2M }} {{ $i := 1 }}{{ $j := 0 }}{{- if $e.IsInverse }}{{ $i = 0 }}{{ $j = 1 }}{{ end -}} t1 := sql.Table({{ $e.Type.Package }}.Table) t2 := {{ $receiver }}.sqlQuery() t2.Select(t2.C({{ $.Package }}.{{ $.ID.Constant }})) t3 := sql.Table({{ $.Package }}.{{ $e.TableConstant }}) t4 := sql.Select(t3.C({{ $.Package }}.{{ $e.PKConstant }}[{{ $i }}])). From(t3). Join(t2). On(t3.C({{ $.Package }}.{{ $e.PKConstant }}[{{ $j }}]), t2.C({{ $.Package }}.{{ $.ID.Constant }})) query.sql = sql.Select(). From(t1). Join(t4). On(t1.C({{ $e.Type.Package }}.{{ $e.Type.ID.Constant }}), t4.C({{ $.Package }}.{{ $e.PKConstant }}[{{ $i }}])) {{- else if or $e.M2O (and $e.O2O $e.IsInverse) }}{{/* M2O || (O2O with inverse edge) */}} t1 := sql.Table({{ $e.Type.Package }}.Table) t2 := {{ $receiver }}.sqlQuery() t2.Select(t2.C({{ $.Package }}.{{ $e.ColumnConstant }})) query.sql = sql.Select(t1.Columns({{ $e.Type.Package }}.Columns...)...). From(t1). Join(t2). On(t1.C({{ $e.Type.Package }}.{{ $e.Type.ID.Constant }}), t2.C({{ $.Package }}.{{ $e.ColumnConstant }})) {{- else }}{{/* O2M || (O2O with assoc edge) */}} t1 := sql.Table({{ $e.Type.Package }}.Table) t2 := {{ $receiver }}.sqlQuery() t2.Select(t2.C({{ $.Package }}.{{ $.ID.Constant }})) query.sql = sql.Select(). From(t1). Join(t2). On(t1.C({{ $.Package }}.{{ $e.ColumnConstant }}), t2.C({{ $.Package }}.{{ $.ID.Constant }})) {{- end }} {{ end }} {{/* query/from defines the query generation for an edge query from a given node. */}} {{ define "dialect/sql/query/from" }} {{- $n := $ }} {{/* the node we start the query from. */}} {{- $e := $.Scope.Edge }} {{/* the edge we need to genegrate the path to. */}} {{- $receiver := $.Scope.Receiver -}} id := {{ $receiver }}.{{- if $n.ID.IsString }}id(){{ else }}ID{{ end }} {{- if $e.M2M }} {{ $i := 1 }}{{ $j := 0 }}{{- if $e.IsInverse }}{{ $i = 0 }}{{ $j = 1 }}{{ end -}} t1 := sql.Table({{ $e.Type.Package }}.Table) t2 := sql.Table({{ $n.Package }}.Table) t3 := sql.Table({{ $n.Package }}.{{ $e.TableConstant }}) t4 := sql.Select(t3.C({{ $n.Package }}.{{ $e.PKConstant }}[{{ $i }}])). From(t3). Join(t2). On(t3.C({{ $n.Package }}.{{ $e.PKConstant }}[{{ $j }}]), t2.C({{ $n.Package }}.{{ $n.ID.Constant }})). Where(sql.EQ(t2.C({{ $n.Package }}.{{ $n.ID.Constant }}), id)) query.sql = sql.Select(). From(t1). Join(t4). On(t1.C({{ $e.Type.Package }}.{{ $e.Type.ID.Constant }}), t4.C({{ $n.Package }}.{{ $e.PKConstant }}[{{ $i }}])) {{- else if or $e.M2O (and $e.O2O $e.IsInverse) }}{{/* M2O || (O2O with inverse edge) */}} t1 := sql.Table({{ $e.Type.Package }}.Table) t2 := sql.Select({{ $n.Package }}.{{ $e.ColumnConstant }}). From(sql.Table({{ $n.Package }}.{{ $e.TableConstant }})). Where(sql.EQ({{ $n.Package }}.{{ $n.ID.Constant }}, id)) query.sql = sql.Select().From(t1).Join(t2).On(t1.C({{ $e.Type.Package }}.{{ $e.Type.ID.Constant }}), t2.C({{ $n.Package }}.{{ $e.ColumnConstant }})) {{- else }}{{/* O2M || (O2O with assoc edge) */}} query.sql = sql.Select().From(sql.Table({{ $e.Type.Package }}.Table)). Where(sql.EQ({{ $n.Package }}.{{ $e.ColumnConstant }}, id)) {{- end }} {{ end }}