Files
ent/entc/integration/template/ent/node.go
Alex Snast f14653be71 entc/gen: fix node out of bounds check
Signed-off-by: Alex Snast <alexsn@fb.com>
2019-12-19 13:07:06 +02:00

241 lines
5.3 KiB
Go

// Copyright (c) Facebook, Inc. and its affiliates. 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.
// Code generated by entc, DO NOT EDIT.
package ent
import (
"context"
"encoding/json"
"fmt"
"sync"
"sync/atomic"
"github.com/facebookincubator/ent/dialect/sql"
"github.com/facebookincubator/ent/dialect/sql/schema"
"github.com/facebookincubator/ent/entc/integration/template/ent/group"
"github.com/facebookincubator/ent/entc/integration/template/ent/pet"
"github.com/facebookincubator/ent/entc/integration/template/ent/user"
"golang.org/x/sync/semaphore"
)
// Noder wraps the basic Node method.
type Noder interface {
Node(context.Context) (*Node, error)
}
// Node in the graph.
type Node struct {
ID int `json:"id,omitemty"` // node id.
Type string `json:"type,omitempty"` // node type.
Fields []*Field `json:"fields,omitempty"` // node fields.
Edges []*Edge `json:"edges,omitempty"` // node edges.
}
// Field of a node.
type Field struct {
Type string `json:"type,omitempty"` // field type.
Name string `json:"name,omitempty"` // field name (as in struct).
Value string `json:"value,omitempty"` // stringified value.
}
// Edges between two nodes.
type Edge struct {
Type string `json:"type,omitempty"` // edge type.
Name string `json:"name,omitempty"` // edge name.
IDs []int `json:"ids,omitempty"` // node ids (where this edge point to).
}
func (gr *Group) Node(ctx context.Context) (node *Node, err error) {
node = &Node{
ID: gr.ID,
Type: "Group",
Fields: make([]*Field, 1),
Edges: make([]*Edge, 0),
}
var buf []byte
if buf, err = json.Marshal(gr.MaxUsers); err != nil {
return nil, err
}
node.Fields[0] = &Field{
Type: "int",
Name: "MaxUsers",
Value: string(buf),
}
return node, nil
}
func (pe *Pet) Node(ctx context.Context) (node *Node, err error) {
node = &Node{
ID: pe.ID,
Type: "Pet",
Fields: make([]*Field, 2),
Edges: make([]*Edge, 1),
}
var buf []byte
if buf, err = json.Marshal(pe.Age); err != nil {
return nil, err
}
node.Fields[0] = &Field{
Type: "int",
Name: "Age",
Value: string(buf),
}
if buf, err = json.Marshal(pe.LicensedAt); err != nil {
return nil, err
}
node.Fields[1] = &Field{
Type: "time.Time",
Name: "LicensedAt",
Value: string(buf),
}
var ids []int
ids, err = pe.QueryOwner().
Select(user.FieldID).
Ints(ctx)
if err != nil {
return nil, err
}
node.Edges[0] = &Edge{
IDs: ids,
Type: "User",
Name: "Owner",
}
return node, nil
}
func (u *User) Node(ctx context.Context) (node *Node, err error) {
node = &Node{
ID: u.ID,
Type: "User",
Fields: make([]*Field, 1),
Edges: make([]*Edge, 2),
}
var buf []byte
if buf, err = json.Marshal(u.Name); err != nil {
return nil, err
}
node.Fields[0] = &Field{
Type: "string",
Name: "Name",
Value: string(buf),
}
var ids []int
ids, err = u.QueryPets().
Select(pet.FieldID).
Ints(ctx)
if err != nil {
return nil, err
}
node.Edges[0] = &Edge{
IDs: ids,
Type: "Pet",
Name: "Pets",
}
ids, err = u.QueryFriends().
Select(user.FieldID).
Ints(ctx)
if err != nil {
return nil, err
}
node.Edges[1] = &Edge{
IDs: ids,
Type: "User",
Name: "Friends",
}
return node, nil
}
func (c *Client) Node(ctx context.Context, id int) (*Node, error) {
n, err := c.Noder(ctx, id)
if err != nil {
return nil, err
}
return n.Node(ctx)
}
func (c *Client) Noder(ctx context.Context, id int) (Noder, error) {
tables, err := c.tables.Load(ctx, c.driver)
if err != nil {
return nil, err
}
idx := id / (1<<32 - 1)
if idx < 0 || idx >= len(tables) {
return nil, fmt.Errorf("cannot resolve table from id %v: %w", id, &ErrNotFound{"invalid/unknown"})
}
return c.noder(ctx, tables[idx], id)
}
func (c *Client) noder(ctx context.Context, tbl string, id int) (Noder, error) {
switch tbl {
case group.Table:
n, err := c.Group.Get(ctx, id)
if err != nil {
return nil, err
}
return n, nil
case pet.Table:
n, err := c.Pet.Get(ctx, id)
if err != nil {
return nil, err
}
return n, nil
case user.Table:
n, err := c.User.Get(ctx, id)
if err != nil {
return nil, err
}
return n, nil
default:
return nil, fmt.Errorf("cannot resolve noder from table %q: %w", tbl, &ErrNotFound{"invalid/unknown"})
}
}
type (
tables struct {
once sync.Once
sem *semaphore.Weighted
value atomic.Value
}
querier interface {
Query(ctx context.Context, query string, args, v interface{}) error
}
)
func (t *tables) Load(ctx context.Context, querier querier) ([]string, error) {
if tables := t.value.Load(); tables != nil {
return tables.([]string), nil
}
t.once.Do(func() { t.sem = semaphore.NewWeighted(1) })
if err := t.sem.Acquire(ctx, 1); err != nil {
return nil, err
}
defer t.sem.Release(1)
if tables := t.value.Load(); tables != nil {
return tables.([]string), nil
}
tables, err := t.load(ctx, querier)
if err == nil {
t.value.Store(tables)
}
return tables, err
}
func (tables) load(ctx context.Context, querier querier) ([]string, error) {
rows := &sql.Rows{}
query, args := sql.Select("type").
From(sql.Table(schema.TypeTable)).
OrderBy(sql.Asc("id")).
Query()
if err := querier.Query(ctx, query, args, rows); err != nil {
return nil, err
}
defer rows.Close()
var tables []string
return tables, sql.ScanSlice(rows, &tables)
}