mirror of
https://github.com/ent/ent.git
synced 2026-05-24 09:31:56 +03:00
Summary: Pull Request resolved: https://github.com/facebookincubator/ent/pull/140 This part of the effort of moving logic from Go templates to shared packages. Next diffs will migrate the neighbors-set and predicates as well. Dedicated tests for `sql/dialect/graph.go` will be added in a follow-up diff. Reviewed By: alexsn Differential Revision: D18304531 fbshipit-source-id: 93e9cf2636b5b4525eb27305bd2708122cfd6e40
146 lines
5.4 KiB
Cheetah
146 lines
5.4 KiB
Cheetah
{{/*
|
|
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 }}) sqlQuery() *sql.Selector {
|
|
builder := sql.Dialect({{ $receiver }}.driver.Dialect())
|
|
t1 := builder.Table({{ $.Package }}.Table)
|
|
selector := builder.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 }}
|
|
|
|
builder := sql.Dialect({{ $receiver }}.driver.Dialect())
|
|
{{- if $e.M2M }}
|
|
{{ $i := 1 }}{{ $j := 0 }}{{- if $e.IsInverse }}{{ $i = 0 }}{{ $j = 1 }}{{ end -}}
|
|
t1 := builder.Table({{ $e.Type.Package }}.Table)
|
|
t2 := {{ $receiver }}.sqlQuery()
|
|
t2.Select(t2.C({{ $.Package }}.{{ $.ID.Constant }}))
|
|
t3 := builder.Table({{ $.Package }}.{{ $e.TableConstant }})
|
|
t4 := builder.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 = builder.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 := builder.Table({{ $e.Type.Package }}.Table)
|
|
t2 := {{ $receiver }}.sqlQuery()
|
|
t2.Select(t2.C({{ $.Package }}.{{ $e.ColumnConstant }}))
|
|
query.sql = builder.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 := builder.Table({{ $e.Type.Package }}.Table)
|
|
t2 := {{ $receiver }}.sqlQuery()
|
|
t2.Select(t2.C({{ $.Package }}.{{ $.ID.Constant }}))
|
|
query.sql = builder.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 }}
|
|
step := &sql.Step{}
|
|
step.From.V = id
|
|
step.From.Table = {{ $n.Package }}.Table
|
|
step.From.Column = {{ $n.Package }}.{{ $n.ID.Constant }}
|
|
step.To.Table = {{ $e.Type.Package }}.Table
|
|
step.To.Column = {{ $e.Type.Package }}.{{ $e.Type.ID.Constant }}
|
|
step.Edge.Rel = sql.{{ $e.Rel.Type }}
|
|
step.Edge.Inverse = {{ $e.IsInverse }}
|
|
step.Edge.Table = {{ $n.Package }}.{{ $e.TableConstant }}
|
|
step.Edge.Columns = append(step.Edge.Columns, {{ if $e.M2M }}{{ $n.Package }}.{{ $e.PKConstant }}...{{ else }}{{ $n.Package }}.{{ $e.ColumnConstant }}{{ end }})
|
|
query.sql = sql.Neighbors({{ $receiver }}.driver.Dialect(), step)
|
|
{{ end }}
|