From 362e442b9ff6081bee8d5de31fb3bbe496537ae7 Mon Sep 17 00:00:00 2001 From: Ashwini Gaddagi <51714308+ashwiniag@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:52:18 +0530 Subject: [PATCH] api: adds CRUD operations for scans and scanLabels (#58) * adds schema for scans and scanlabels * adds CRUD operations for scans * updates routes for CRUD * adds CRUD operations for scanlabels * updates routes for CRUD * remove comment * api: adds test cases for scans and scanlabels (#63) * adds test cases for scans * adds test cases for scanlabels --- ent/client.go | 372 ++++- ent/ent.go | 4 + ent/hook/hook.go | 24 + ent/migrate/schema.go | 48 + ent/mutation.go | 1309 ++++++++++++++++- ent/policies.go | 18 +- ent/policies/policies.go | 30 + ent/policies/where.go | 23 + ent/policies_create.go | 32 + ent/policies_query.go | 76 +- ent/policies_update.go | 164 +++ ent/predicate/predicate.go | 6 + ent/runtime.go | 22 + ent/scanlabels.go | 157 ++ ent/scanlabels/scanlabels.go | 94 ++ ent/scanlabels/where.go | 258 ++++ ent/scanlabels_create.go | 242 +++ ent/scanlabels_delete.go | 88 ++ ent/scanlabels_query.go | 607 ++++++++ ent/scanlabels_update.go | 395 +++++ ent/scans.go | 200 +++ ent/scans/scans.go | 136 ++ ent/scans/where.go | 371 +++++ ent/scans_create.go | 342 +++++ ent/scans_delete.go | 88 ++ ent/scans_query.go | 682 +++++++++ ent/scans_update.go | 643 ++++++++ ent/schema/policies.go | 2 + ent/schema/scanlabels.go | 38 + ent/schema/scans.go | 49 + ent/tx.go | 6 + internal/restapi/v1/policylabels/post.go | 2 +- internal/restapi/v1/scanlabels/delete.go | 51 + internal/restapi/v1/scanlabels/delete_test.go | 120 ++ internal/restapi/v1/scanlabels/get.go | 82 ++ internal/restapi/v1/scanlabels/get_test.go | 154 ++ internal/restapi/v1/scanlabels/post.go | 57 + internal/restapi/v1/scanlabels/post_test.go | 130 ++ internal/restapi/v1/scanlabels/put.go | 116 ++ internal/restapi/v1/scanlabels/put_test.go | 134 ++ internal/restapi/v1/scans/delete.go | 36 + internal/restapi/v1/scans/delete_test.go | 86 ++ internal/restapi/v1/scans/get.go | 72 + internal/restapi/v1/scans/get_test.go | 87 ++ internal/restapi/v1/scans/post.go | 78 + internal/restapi/v1/scans/post_test.go | 80 + internal/restapi/v1/scans/put.go | 55 + internal/restapi/v1/scans/put_test.go | 99 ++ internal/restapi/v1/server.go | 15 + 49 files changed, 7964 insertions(+), 16 deletions(-) create mode 100644 ent/scanlabels.go create mode 100644 ent/scanlabels/scanlabels.go create mode 100644 ent/scanlabels/where.go create mode 100644 ent/scanlabels_create.go create mode 100644 ent/scanlabels_delete.go create mode 100644 ent/scanlabels_query.go create mode 100644 ent/scanlabels_update.go create mode 100644 ent/scans.go create mode 100644 ent/scans/scans.go create mode 100644 ent/scans/where.go create mode 100644 ent/scans_create.go create mode 100644 ent/scans_delete.go create mode 100644 ent/scans_query.go create mode 100644 ent/scans_update.go create mode 100644 ent/schema/scanlabels.go create mode 100644 ent/schema/scans.go create mode 100644 internal/restapi/v1/scanlabels/delete.go create mode 100644 internal/restapi/v1/scanlabels/delete_test.go create mode 100644 internal/restapi/v1/scanlabels/get.go create mode 100644 internal/restapi/v1/scanlabels/get_test.go create mode 100644 internal/restapi/v1/scanlabels/post.go create mode 100644 internal/restapi/v1/scanlabels/post_test.go create mode 100644 internal/restapi/v1/scanlabels/put.go create mode 100644 internal/restapi/v1/scanlabels/put_test.go create mode 100644 internal/restapi/v1/scans/delete.go create mode 100644 internal/restapi/v1/scans/delete_test.go create mode 100644 internal/restapi/v1/scans/get.go create mode 100644 internal/restapi/v1/scans/get_test.go create mode 100644 internal/restapi/v1/scans/post.go create mode 100644 internal/restapi/v1/scans/post_test.go create mode 100644 internal/restapi/v1/scans/put.go create mode 100644 internal/restapi/v1/scans/put_test.go diff --git a/ent/client.go b/ent/client.go index 7ad2890..805d9f0 100644 --- a/ent/client.go +++ b/ent/client.go @@ -20,6 +20,8 @@ import ( "github.com/shinobistack/gokakashi/ent/integrationtype" "github.com/shinobistack/gokakashi/ent/policies" "github.com/shinobistack/gokakashi/ent/policylabels" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/shinobistack/gokakashi/ent/scans" ) // Client is the client that holds all ent builders. @@ -35,6 +37,10 @@ type Client struct { Policies *PoliciesClient // PolicyLabels is the client for interacting with the PolicyLabels builders. PolicyLabels *PolicyLabelsClient + // ScanLabels is the client for interacting with the ScanLabels builders. + ScanLabels *ScanLabelsClient + // Scans is the client for interacting with the Scans builders. + Scans *ScansClient } // NewClient creates a new client configured with the given options. @@ -50,6 +56,8 @@ func (c *Client) init() { c.Integrations = NewIntegrationsClient(c.config) c.Policies = NewPoliciesClient(c.config) c.PolicyLabels = NewPolicyLabelsClient(c.config) + c.ScanLabels = NewScanLabelsClient(c.config) + c.Scans = NewScansClient(c.config) } type ( @@ -146,6 +154,8 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { Integrations: NewIntegrationsClient(cfg), Policies: NewPoliciesClient(cfg), PolicyLabels: NewPolicyLabelsClient(cfg), + ScanLabels: NewScanLabelsClient(cfg), + Scans: NewScansClient(cfg), }, nil } @@ -169,6 +179,8 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) Integrations: NewIntegrationsClient(cfg), Policies: NewPoliciesClient(cfg), PolicyLabels: NewPolicyLabelsClient(cfg), + ScanLabels: NewScanLabelsClient(cfg), + Scans: NewScansClient(cfg), }, nil } @@ -197,19 +209,23 @@ func (c *Client) Close() error { // Use adds the mutation hooks to all the entity clients. // In order to add hooks to a specific client, call: `client.Node.Use(...)`. func (c *Client) Use(hooks ...Hook) { - c.IntegrationType.Use(hooks...) - c.Integrations.Use(hooks...) - c.Policies.Use(hooks...) - c.PolicyLabels.Use(hooks...) + for _, n := range []interface{ Use(...Hook) }{ + c.IntegrationType, c.Integrations, c.Policies, c.PolicyLabels, c.ScanLabels, + c.Scans, + } { + n.Use(hooks...) + } } // Intercept adds the query interceptors to all the entity clients. // In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`. func (c *Client) Intercept(interceptors ...Interceptor) { - c.IntegrationType.Intercept(interceptors...) - c.Integrations.Intercept(interceptors...) - c.Policies.Intercept(interceptors...) - c.PolicyLabels.Intercept(interceptors...) + for _, n := range []interface{ Intercept(...Interceptor) }{ + c.IntegrationType, c.Integrations, c.Policies, c.PolicyLabels, c.ScanLabels, + c.Scans, + } { + n.Intercept(interceptors...) + } } // Mutate implements the ent.Mutator interface. @@ -223,6 +239,10 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { return c.Policies.mutate(ctx, m) case *PolicyLabelsMutation: return c.PolicyLabels.mutate(ctx, m) + case *ScanLabelsMutation: + return c.ScanLabels.mutate(ctx, m) + case *ScansMutation: + return c.Scans.mutate(ctx, m) default: return nil, fmt.Errorf("ent: unknown mutation type %T", m) } @@ -634,6 +654,22 @@ func (c *PoliciesClient) QueryPolicyLabels(po *Policies) *PolicyLabelsQuery { return query } +// QueryScans queries the scans edge of a Policies. +func (c *PoliciesClient) QueryScans(po *Policies) *ScansQuery { + query := (&ScansClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := po.ID + step := sqlgraph.NewStep( + sqlgraph.From(policies.Table, policies.FieldID, id), + sqlgraph.To(scans.Table, scans.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, policies.ScansTable, policies.ScansColumn), + ) + fromV = sqlgraph.Neighbors(po.driver.Dialect(), step) + return fromV, nil + } + return query +} + // Hooks returns the client hooks. func (c *PoliciesClient) Hooks() []Hook { return c.hooks.Policies @@ -808,12 +844,328 @@ func (c *PolicyLabelsClient) mutate(ctx context.Context, m *PolicyLabelsMutation } } +// ScanLabelsClient is a client for the ScanLabels schema. +type ScanLabelsClient struct { + config +} + +// NewScanLabelsClient returns a client for the ScanLabels from the given config. +func NewScanLabelsClient(c config) *ScanLabelsClient { + return &ScanLabelsClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `scanlabels.Hooks(f(g(h())))`. +func (c *ScanLabelsClient) Use(hooks ...Hook) { + c.hooks.ScanLabels = append(c.hooks.ScanLabels, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `scanlabels.Intercept(f(g(h())))`. +func (c *ScanLabelsClient) Intercept(interceptors ...Interceptor) { + c.inters.ScanLabels = append(c.inters.ScanLabels, interceptors...) +} + +// Create returns a builder for creating a ScanLabels entity. +func (c *ScanLabelsClient) Create() *ScanLabelsCreate { + mutation := newScanLabelsMutation(c.config, OpCreate) + return &ScanLabelsCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of ScanLabels entities. +func (c *ScanLabelsClient) CreateBulk(builders ...*ScanLabelsCreate) *ScanLabelsCreateBulk { + return &ScanLabelsCreateBulk{config: c.config, builders: builders} +} + +// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates +// a builder and applies setFunc on it. +func (c *ScanLabelsClient) MapCreateBulk(slice any, setFunc func(*ScanLabelsCreate, int)) *ScanLabelsCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &ScanLabelsCreateBulk{err: fmt.Errorf("calling to ScanLabelsClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*ScanLabelsCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &ScanLabelsCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for ScanLabels. +func (c *ScanLabelsClient) Update() *ScanLabelsUpdate { + mutation := newScanLabelsMutation(c.config, OpUpdate) + return &ScanLabelsUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *ScanLabelsClient) UpdateOne(sl *ScanLabels) *ScanLabelsUpdateOne { + mutation := newScanLabelsMutation(c.config, OpUpdateOne, withScanLabels(sl)) + return &ScanLabelsUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *ScanLabelsClient) UpdateOneID(id int) *ScanLabelsUpdateOne { + mutation := newScanLabelsMutation(c.config, OpUpdateOne, withScanLabelsID(id)) + return &ScanLabelsUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for ScanLabels. +func (c *ScanLabelsClient) Delete() *ScanLabelsDelete { + mutation := newScanLabelsMutation(c.config, OpDelete) + return &ScanLabelsDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *ScanLabelsClient) DeleteOne(sl *ScanLabels) *ScanLabelsDeleteOne { + return c.DeleteOneID(sl.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *ScanLabelsClient) DeleteOneID(id int) *ScanLabelsDeleteOne { + builder := c.Delete().Where(scanlabels.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &ScanLabelsDeleteOne{builder} +} + +// Query returns a query builder for ScanLabels. +func (c *ScanLabelsClient) Query() *ScanLabelsQuery { + return &ScanLabelsQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeScanLabels}, + inters: c.Interceptors(), + } +} + +// Get returns a ScanLabels entity by its id. +func (c *ScanLabelsClient) Get(ctx context.Context, id int) (*ScanLabels, error) { + return c.Query().Where(scanlabels.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *ScanLabelsClient) GetX(ctx context.Context, id int) *ScanLabels { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryScan queries the scan edge of a ScanLabels. +func (c *ScanLabelsClient) QueryScan(sl *ScanLabels) *ScansQuery { + query := (&ScansClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := sl.ID + step := sqlgraph.NewStep( + sqlgraph.From(scanlabels.Table, scanlabels.FieldID, id), + sqlgraph.To(scans.Table, scans.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, scanlabels.ScanTable, scanlabels.ScanColumn), + ) + fromV = sqlgraph.Neighbors(sl.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *ScanLabelsClient) Hooks() []Hook { + return c.hooks.ScanLabels +} + +// Interceptors returns the client interceptors. +func (c *ScanLabelsClient) Interceptors() []Interceptor { + return c.inters.ScanLabels +} + +func (c *ScanLabelsClient) mutate(ctx context.Context, m *ScanLabelsMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&ScanLabelsCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&ScanLabelsUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&ScanLabelsUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&ScanLabelsDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown ScanLabels mutation op: %q", m.Op()) + } +} + +// ScansClient is a client for the Scans schema. +type ScansClient struct { + config +} + +// NewScansClient returns a client for the Scans from the given config. +func NewScansClient(c config) *ScansClient { + return &ScansClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `scans.Hooks(f(g(h())))`. +func (c *ScansClient) Use(hooks ...Hook) { + c.hooks.Scans = append(c.hooks.Scans, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `scans.Intercept(f(g(h())))`. +func (c *ScansClient) Intercept(interceptors ...Interceptor) { + c.inters.Scans = append(c.inters.Scans, interceptors...) +} + +// Create returns a builder for creating a Scans entity. +func (c *ScansClient) Create() *ScansCreate { + mutation := newScansMutation(c.config, OpCreate) + return &ScansCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of Scans entities. +func (c *ScansClient) CreateBulk(builders ...*ScansCreate) *ScansCreateBulk { + return &ScansCreateBulk{config: c.config, builders: builders} +} + +// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates +// a builder and applies setFunc on it. +func (c *ScansClient) MapCreateBulk(slice any, setFunc func(*ScansCreate, int)) *ScansCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &ScansCreateBulk{err: fmt.Errorf("calling to ScansClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*ScansCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &ScansCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for Scans. +func (c *ScansClient) Update() *ScansUpdate { + mutation := newScansMutation(c.config, OpUpdate) + return &ScansUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *ScansClient) UpdateOne(s *Scans) *ScansUpdateOne { + mutation := newScansMutation(c.config, OpUpdateOne, withScans(s)) + return &ScansUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *ScansClient) UpdateOneID(id uuid.UUID) *ScansUpdateOne { + mutation := newScansMutation(c.config, OpUpdateOne, withScansID(id)) + return &ScansUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for Scans. +func (c *ScansClient) Delete() *ScansDelete { + mutation := newScansMutation(c.config, OpDelete) + return &ScansDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *ScansClient) DeleteOne(s *Scans) *ScansDeleteOne { + return c.DeleteOneID(s.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *ScansClient) DeleteOneID(id uuid.UUID) *ScansDeleteOne { + builder := c.Delete().Where(scans.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &ScansDeleteOne{builder} +} + +// Query returns a query builder for Scans. +func (c *ScansClient) Query() *ScansQuery { + return &ScansQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeScans}, + inters: c.Interceptors(), + } +} + +// Get returns a Scans entity by its id. +func (c *ScansClient) Get(ctx context.Context, id uuid.UUID) (*Scans, error) { + return c.Query().Where(scans.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *ScansClient) GetX(ctx context.Context, id uuid.UUID) *Scans { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryPolicy queries the policy edge of a Scans. +func (c *ScansClient) QueryPolicy(s *Scans) *PoliciesQuery { + query := (&PoliciesClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := s.ID + step := sqlgraph.NewStep( + sqlgraph.From(scans.Table, scans.FieldID, id), + sqlgraph.To(policies.Table, policies.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, scans.PolicyTable, scans.PolicyColumn), + ) + fromV = sqlgraph.Neighbors(s.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// QueryScanLabels queries the scan_labels edge of a Scans. +func (c *ScansClient) QueryScanLabels(s *Scans) *ScanLabelsQuery { + query := (&ScanLabelsClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := s.ID + step := sqlgraph.NewStep( + sqlgraph.From(scans.Table, scans.FieldID, id), + sqlgraph.To(scanlabels.Table, scanlabels.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, scans.ScanLabelsTable, scans.ScanLabelsColumn), + ) + fromV = sqlgraph.Neighbors(s.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *ScansClient) Hooks() []Hook { + return c.hooks.Scans +} + +// Interceptors returns the client interceptors. +func (c *ScansClient) Interceptors() []Interceptor { + return c.inters.Scans +} + +func (c *ScansClient) mutate(ctx context.Context, m *ScansMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&ScansCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&ScansUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&ScansUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&ScansDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown Scans mutation op: %q", m.Op()) + } +} + // hooks and interceptors per client, for fast access. type ( hooks struct { - IntegrationType, Integrations, Policies, PolicyLabels []ent.Hook + IntegrationType, Integrations, Policies, PolicyLabels, ScanLabels, + Scans []ent.Hook } inters struct { - IntegrationType, Integrations, Policies, PolicyLabels []ent.Interceptor + IntegrationType, Integrations, Policies, PolicyLabels, ScanLabels, + Scans []ent.Interceptor } ) diff --git a/ent/ent.go b/ent/ent.go index 7d4689c..abd1b24 100644 --- a/ent/ent.go +++ b/ent/ent.go @@ -16,6 +16,8 @@ import ( "github.com/shinobistack/gokakashi/ent/integrationtype" "github.com/shinobistack/gokakashi/ent/policies" "github.com/shinobistack/gokakashi/ent/policylabels" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/shinobistack/gokakashi/ent/scans" ) // ent aliases to avoid import conflicts in user's code. @@ -80,6 +82,8 @@ func checkColumn(table, column string) error { integrations.Table: integrations.ValidColumn, policies.Table: policies.ValidColumn, policylabels.Table: policylabels.ValidColumn, + scanlabels.Table: scanlabels.ValidColumn, + scans.Table: scans.ValidColumn, }) }) return columnCheck(table, column) diff --git a/ent/hook/hook.go b/ent/hook/hook.go index 9c70373..d8d3dd7 100644 --- a/ent/hook/hook.go +++ b/ent/hook/hook.go @@ -57,6 +57,30 @@ func (f PolicyLabelsFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.PolicyLabelsMutation", m) } +// The ScanLabelsFunc type is an adapter to allow the use of ordinary +// function as ScanLabels mutator. +type ScanLabelsFunc func(context.Context, *ent.ScanLabelsMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f ScanLabelsFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.ScanLabelsMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ScanLabelsMutation", m) +} + +// The ScansFunc type is an adapter to allow the use of ordinary +// function as Scans mutator. +type ScansFunc func(context.Context, *ent.ScansMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f ScansFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.ScansMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ScansMutation", m) +} + // Condition is a hook condition function. type Condition func(context.Context, ent.Mutation) bool diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index a2cda70..b6e85e0 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -77,16 +77,64 @@ var ( }, }, } + // ScanLabelsColumns holds the columns for the "scan_labels" table. + ScanLabelsColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt, Increment: true}, + {Name: "key", Type: field.TypeString}, + {Name: "value", Type: field.TypeString}, + {Name: "scan_id", Type: field.TypeUUID}, + } + // ScanLabelsTable holds the schema information for the "scan_labels" table. + ScanLabelsTable = &schema.Table{ + Name: "scan_labels", + Columns: ScanLabelsColumns, + PrimaryKey: []*schema.Column{ScanLabelsColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "scan_labels_scans_scan_labels", + Columns: []*schema.Column{ScanLabelsColumns[3]}, + RefColumns: []*schema.Column{ScansColumns[0]}, + OnDelete: schema.NoAction, + }, + }, + } + // ScansColumns holds the columns for the "scans" table. + ScansColumns = []*schema.Column{ + {Name: "id", Type: field.TypeUUID, Unique: true}, + {Name: "status", Type: field.TypeString, Default: "scan_pending"}, + {Name: "image", Type: field.TypeString}, + {Name: "check", Type: field.TypeJSON, Nullable: true}, + {Name: "report", Type: field.TypeString, Nullable: true}, + {Name: "policy_id", Type: field.TypeUUID}, + } + // ScansTable holds the schema information for the "scans" table. + ScansTable = &schema.Table{ + Name: "scans", + Columns: ScansColumns, + PrimaryKey: []*schema.Column{ScansColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "scans_policies_scans", + Columns: []*schema.Column{ScansColumns[5]}, + RefColumns: []*schema.Column{PoliciesColumns[0]}, + OnDelete: schema.NoAction, + }, + }, + } // Tables holds all the tables in the schema. Tables = []*schema.Table{ IntegrationTypesTable, IntegrationsTable, PoliciesTable, PolicyLabelsTable, + ScanLabelsTable, + ScansTable, } ) func init() { IntegrationsTable.ForeignKeys[0].RefTable = IntegrationTypesTable PolicyLabelsTable.ForeignKeys[0].RefTable = PoliciesTable + ScanLabelsTable.ForeignKeys[0].RefTable = ScansTable + ScansTable.ForeignKeys[0].RefTable = PoliciesTable } diff --git a/ent/mutation.go b/ent/mutation.go index c67af8d..a6befd9 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -16,6 +16,8 @@ import ( "github.com/shinobistack/gokakashi/ent/policies" "github.com/shinobistack/gokakashi/ent/policylabels" "github.com/shinobistack/gokakashi/ent/predicate" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/shinobistack/gokakashi/ent/scans" "github.com/shinobistack/gokakashi/ent/schema" ) @@ -32,6 +34,8 @@ const ( TypeIntegrations = "Integrations" TypePolicies = "Policies" TypePolicyLabels = "PolicyLabels" + TypeScanLabels = "ScanLabels" + TypeScans = "Scans" ) // IntegrationTypeMutation represents an operation that mutates the IntegrationType nodes in the graph. @@ -914,6 +918,9 @@ type PoliciesMutation struct { policy_labels map[int]struct{} removedpolicy_labels map[int]struct{} clearedpolicy_labels bool + scans map[uuid.UUID]struct{} + removedscans map[uuid.UUID]struct{} + clearedscans bool done bool oldValue func(context.Context) (*Policies, error) predicates []predicate.Policies @@ -1296,6 +1303,60 @@ func (m *PoliciesMutation) ResetPolicyLabels() { m.removedpolicy_labels = nil } +// AddScanIDs adds the "scans" edge to the Scans entity by ids. +func (m *PoliciesMutation) AddScanIDs(ids ...uuid.UUID) { + if m.scans == nil { + m.scans = make(map[uuid.UUID]struct{}) + } + for i := range ids { + m.scans[ids[i]] = struct{}{} + } +} + +// ClearScans clears the "scans" edge to the Scans entity. +func (m *PoliciesMutation) ClearScans() { + m.clearedscans = true +} + +// ScansCleared reports if the "scans" edge to the Scans entity was cleared. +func (m *PoliciesMutation) ScansCleared() bool { + return m.clearedscans +} + +// RemoveScanIDs removes the "scans" edge to the Scans entity by IDs. +func (m *PoliciesMutation) RemoveScanIDs(ids ...uuid.UUID) { + if m.removedscans == nil { + m.removedscans = make(map[uuid.UUID]struct{}) + } + for i := range ids { + delete(m.scans, ids[i]) + m.removedscans[ids[i]] = struct{}{} + } +} + +// RemovedScans returns the removed IDs of the "scans" edge to the Scans entity. +func (m *PoliciesMutation) RemovedScansIDs() (ids []uuid.UUID) { + for id := range m.removedscans { + ids = append(ids, id) + } + return +} + +// ScansIDs returns the "scans" edge IDs in the mutation. +func (m *PoliciesMutation) ScansIDs() (ids []uuid.UUID) { + for id := range m.scans { + ids = append(ids, id) + } + return +} + +// ResetScans resets all changes to the "scans" edge. +func (m *PoliciesMutation) ResetScans() { + m.scans = nil + m.clearedscans = false + m.removedscans = nil +} + // Where appends a list predicates to the PoliciesMutation builder. func (m *PoliciesMutation) Where(ps ...predicate.Policies) { m.predicates = append(m.predicates, ps...) @@ -1518,10 +1579,13 @@ func (m *PoliciesMutation) ResetField(name string) error { // AddedEdges returns all edge names that were set/added in this mutation. func (m *PoliciesMutation) AddedEdges() []string { - edges := make([]string, 0, 1) + edges := make([]string, 0, 2) if m.policy_labels != nil { edges = append(edges, policies.EdgePolicyLabels) } + if m.scans != nil { + edges = append(edges, policies.EdgeScans) + } return edges } @@ -1535,16 +1599,25 @@ func (m *PoliciesMutation) AddedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case policies.EdgeScans: + ids := make([]ent.Value, 0, len(m.scans)) + for id := range m.scans { + ids = append(ids, id) + } + return ids } return nil } // RemovedEdges returns all edge names that were removed in this mutation. func (m *PoliciesMutation) RemovedEdges() []string { - edges := make([]string, 0, 1) + edges := make([]string, 0, 2) if m.removedpolicy_labels != nil { edges = append(edges, policies.EdgePolicyLabels) } + if m.removedscans != nil { + edges = append(edges, policies.EdgeScans) + } return edges } @@ -1558,16 +1631,25 @@ func (m *PoliciesMutation) RemovedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case policies.EdgeScans: + ids := make([]ent.Value, 0, len(m.removedscans)) + for id := range m.removedscans { + ids = append(ids, id) + } + return ids } return nil } // ClearedEdges returns all edge names that were cleared in this mutation. func (m *PoliciesMutation) ClearedEdges() []string { - edges := make([]string, 0, 1) + edges := make([]string, 0, 2) if m.clearedpolicy_labels { edges = append(edges, policies.EdgePolicyLabels) } + if m.clearedscans { + edges = append(edges, policies.EdgeScans) + } return edges } @@ -1577,6 +1659,8 @@ func (m *PoliciesMutation) EdgeCleared(name string) bool { switch name { case policies.EdgePolicyLabels: return m.clearedpolicy_labels + case policies.EdgeScans: + return m.clearedscans } return false } @@ -1596,6 +1680,9 @@ func (m *PoliciesMutation) ResetEdge(name string) error { case policies.EdgePolicyLabels: m.ResetPolicyLabels() return nil + case policies.EdgeScans: + m.ResetScans() + return nil } return fmt.Errorf("unknown Policies edge %s", name) } @@ -2087,3 +2174,1219 @@ func (m *PolicyLabelsMutation) ResetEdge(name string) error { } return fmt.Errorf("unknown PolicyLabels edge %s", name) } + +// ScanLabelsMutation represents an operation that mutates the ScanLabels nodes in the graph. +type ScanLabelsMutation struct { + config + op Op + typ string + id *int + key *string + value *string + clearedFields map[string]struct{} + scan *uuid.UUID + clearedscan bool + done bool + oldValue func(context.Context) (*ScanLabels, error) + predicates []predicate.ScanLabels +} + +var _ ent.Mutation = (*ScanLabelsMutation)(nil) + +// scanlabelsOption allows management of the mutation configuration using functional options. +type scanlabelsOption func(*ScanLabelsMutation) + +// newScanLabelsMutation creates new mutation for the ScanLabels entity. +func newScanLabelsMutation(c config, op Op, opts ...scanlabelsOption) *ScanLabelsMutation { + m := &ScanLabelsMutation{ + config: c, + op: op, + typ: TypeScanLabels, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withScanLabelsID sets the ID field of the mutation. +func withScanLabelsID(id int) scanlabelsOption { + return func(m *ScanLabelsMutation) { + var ( + err error + once sync.Once + value *ScanLabels + ) + m.oldValue = func(ctx context.Context) (*ScanLabels, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().ScanLabels.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withScanLabels sets the old ScanLabels of the mutation. +func withScanLabels(node *ScanLabels) scanlabelsOption { + return func(m *ScanLabelsMutation) { + m.oldValue = func(context.Context) (*ScanLabels, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m ScanLabelsMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m ScanLabelsMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *ScanLabelsMutation) ID() (id int, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *ScanLabelsMutation) IDs(ctx context.Context) ([]int, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().ScanLabels.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetScanID sets the "scan_id" field. +func (m *ScanLabelsMutation) SetScanID(u uuid.UUID) { + m.scan = &u +} + +// ScanID returns the value of the "scan_id" field in the mutation. +func (m *ScanLabelsMutation) ScanID() (r uuid.UUID, exists bool) { + v := m.scan + if v == nil { + return + } + return *v, true +} + +// OldScanID returns the old "scan_id" field's value of the ScanLabels entity. +// If the ScanLabels object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ScanLabelsMutation) OldScanID(ctx context.Context) (v uuid.UUID, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldScanID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldScanID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldScanID: %w", err) + } + return oldValue.ScanID, nil +} + +// ResetScanID resets all changes to the "scan_id" field. +func (m *ScanLabelsMutation) ResetScanID() { + m.scan = nil +} + +// SetKey sets the "key" field. +func (m *ScanLabelsMutation) SetKey(s string) { + m.key = &s +} + +// Key returns the value of the "key" field in the mutation. +func (m *ScanLabelsMutation) Key() (r string, exists bool) { + v := m.key + if v == nil { + return + } + return *v, true +} + +// OldKey returns the old "key" field's value of the ScanLabels entity. +// If the ScanLabels object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ScanLabelsMutation) OldKey(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldKey is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldKey requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldKey: %w", err) + } + return oldValue.Key, nil +} + +// ResetKey resets all changes to the "key" field. +func (m *ScanLabelsMutation) ResetKey() { + m.key = nil +} + +// SetValue sets the "value" field. +func (m *ScanLabelsMutation) SetValue(s string) { + m.value = &s +} + +// Value returns the value of the "value" field in the mutation. +func (m *ScanLabelsMutation) Value() (r string, exists bool) { + v := m.value + if v == nil { + return + } + return *v, true +} + +// OldValue returns the old "value" field's value of the ScanLabels entity. +// If the ScanLabels object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ScanLabelsMutation) OldValue(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldValue is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldValue requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldValue: %w", err) + } + return oldValue.Value, nil +} + +// ResetValue resets all changes to the "value" field. +func (m *ScanLabelsMutation) ResetValue() { + m.value = nil +} + +// ClearScan clears the "scan" edge to the Scans entity. +func (m *ScanLabelsMutation) ClearScan() { + m.clearedscan = true + m.clearedFields[scanlabels.FieldScanID] = struct{}{} +} + +// ScanCleared reports if the "scan" edge to the Scans entity was cleared. +func (m *ScanLabelsMutation) ScanCleared() bool { + return m.clearedscan +} + +// ScanIDs returns the "scan" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// ScanID instead. It exists only for internal usage by the builders. +func (m *ScanLabelsMutation) ScanIDs() (ids []uuid.UUID) { + if id := m.scan; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetScan resets all changes to the "scan" edge. +func (m *ScanLabelsMutation) ResetScan() { + m.scan = nil + m.clearedscan = false +} + +// Where appends a list predicates to the ScanLabelsMutation builder. +func (m *ScanLabelsMutation) Where(ps ...predicate.ScanLabels) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the ScanLabelsMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *ScanLabelsMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.ScanLabels, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *ScanLabelsMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *ScanLabelsMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (ScanLabels). +func (m *ScanLabelsMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *ScanLabelsMutation) Fields() []string { + fields := make([]string, 0, 3) + if m.scan != nil { + fields = append(fields, scanlabels.FieldScanID) + } + if m.key != nil { + fields = append(fields, scanlabels.FieldKey) + } + if m.value != nil { + fields = append(fields, scanlabels.FieldValue) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *ScanLabelsMutation) Field(name string) (ent.Value, bool) { + switch name { + case scanlabels.FieldScanID: + return m.ScanID() + case scanlabels.FieldKey: + return m.Key() + case scanlabels.FieldValue: + return m.Value() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *ScanLabelsMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case scanlabels.FieldScanID: + return m.OldScanID(ctx) + case scanlabels.FieldKey: + return m.OldKey(ctx) + case scanlabels.FieldValue: + return m.OldValue(ctx) + } + return nil, fmt.Errorf("unknown ScanLabels field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ScanLabelsMutation) SetField(name string, value ent.Value) error { + switch name { + case scanlabels.FieldScanID: + v, ok := value.(uuid.UUID) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetScanID(v) + return nil + case scanlabels.FieldKey: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetKey(v) + return nil + case scanlabels.FieldValue: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetValue(v) + return nil + } + return fmt.Errorf("unknown ScanLabels field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *ScanLabelsMutation) AddedFields() []string { + return nil +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *ScanLabelsMutation) AddedField(name string) (ent.Value, bool) { + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ScanLabelsMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown ScanLabels numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *ScanLabelsMutation) ClearedFields() []string { + return nil +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *ScanLabelsMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *ScanLabelsMutation) ClearField(name string) error { + return fmt.Errorf("unknown ScanLabels nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *ScanLabelsMutation) ResetField(name string) error { + switch name { + case scanlabels.FieldScanID: + m.ResetScanID() + return nil + case scanlabels.FieldKey: + m.ResetKey() + return nil + case scanlabels.FieldValue: + m.ResetValue() + return nil + } + return fmt.Errorf("unknown ScanLabels field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *ScanLabelsMutation) AddedEdges() []string { + edges := make([]string, 0, 1) + if m.scan != nil { + edges = append(edges, scanlabels.EdgeScan) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *ScanLabelsMutation) AddedIDs(name string) []ent.Value { + switch name { + case scanlabels.EdgeScan: + if id := m.scan; id != nil { + return []ent.Value{*id} + } + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *ScanLabelsMutation) RemovedEdges() []string { + edges := make([]string, 0, 1) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *ScanLabelsMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *ScanLabelsMutation) ClearedEdges() []string { + edges := make([]string, 0, 1) + if m.clearedscan { + edges = append(edges, scanlabels.EdgeScan) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *ScanLabelsMutation) EdgeCleared(name string) bool { + switch name { + case scanlabels.EdgeScan: + return m.clearedscan + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *ScanLabelsMutation) ClearEdge(name string) error { + switch name { + case scanlabels.EdgeScan: + m.ClearScan() + return nil + } + return fmt.Errorf("unknown ScanLabels unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *ScanLabelsMutation) ResetEdge(name string) error { + switch name { + case scanlabels.EdgeScan: + m.ResetScan() + return nil + } + return fmt.Errorf("unknown ScanLabels edge %s", name) +} + +// ScansMutation represents an operation that mutates the Scans nodes in the graph. +type ScansMutation struct { + config + op Op + typ string + id *uuid.UUID + status *string + image *string + check *schema.Check + report *string + clearedFields map[string]struct{} + policy *uuid.UUID + clearedpolicy bool + scan_labels map[int]struct{} + removedscan_labels map[int]struct{} + clearedscan_labels bool + done bool + oldValue func(context.Context) (*Scans, error) + predicates []predicate.Scans +} + +var _ ent.Mutation = (*ScansMutation)(nil) + +// scansOption allows management of the mutation configuration using functional options. +type scansOption func(*ScansMutation) + +// newScansMutation creates new mutation for the Scans entity. +func newScansMutation(c config, op Op, opts ...scansOption) *ScansMutation { + m := &ScansMutation{ + config: c, + op: op, + typ: TypeScans, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withScansID sets the ID field of the mutation. +func withScansID(id uuid.UUID) scansOption { + return func(m *ScansMutation) { + var ( + err error + once sync.Once + value *Scans + ) + m.oldValue = func(ctx context.Context) (*Scans, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().Scans.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withScans sets the old Scans of the mutation. +func withScans(node *Scans) scansOption { + return func(m *ScansMutation) { + m.oldValue = func(context.Context) (*Scans, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m ScansMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m ScansMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// SetID sets the value of the id field. Note that this +// operation is only accepted on creation of Scans entities. +func (m *ScansMutation) SetID(id uuid.UUID) { + m.id = &id +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *ScansMutation) ID() (id uuid.UUID, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *ScansMutation) IDs(ctx context.Context) ([]uuid.UUID, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []uuid.UUID{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().Scans.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetPolicyID sets the "policy_id" field. +func (m *ScansMutation) SetPolicyID(u uuid.UUID) { + m.policy = &u +} + +// PolicyID returns the value of the "policy_id" field in the mutation. +func (m *ScansMutation) PolicyID() (r uuid.UUID, exists bool) { + v := m.policy + if v == nil { + return + } + return *v, true +} + +// OldPolicyID returns the old "policy_id" field's value of the Scans entity. +// If the Scans object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ScansMutation) OldPolicyID(ctx context.Context) (v uuid.UUID, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPolicyID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPolicyID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPolicyID: %w", err) + } + return oldValue.PolicyID, nil +} + +// ResetPolicyID resets all changes to the "policy_id" field. +func (m *ScansMutation) ResetPolicyID() { + m.policy = nil +} + +// SetStatus sets the "status" field. +func (m *ScansMutation) SetStatus(s string) { + m.status = &s +} + +// Status returns the value of the "status" field in the mutation. +func (m *ScansMutation) Status() (r string, exists bool) { + v := m.status + if v == nil { + return + } + return *v, true +} + +// OldStatus returns the old "status" field's value of the Scans entity. +// If the Scans object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ScansMutation) OldStatus(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldStatus is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldStatus requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldStatus: %w", err) + } + return oldValue.Status, nil +} + +// ResetStatus resets all changes to the "status" field. +func (m *ScansMutation) ResetStatus() { + m.status = nil +} + +// SetImage sets the "image" field. +func (m *ScansMutation) SetImage(s string) { + m.image = &s +} + +// Image returns the value of the "image" field in the mutation. +func (m *ScansMutation) Image() (r string, exists bool) { + v := m.image + if v == nil { + return + } + return *v, true +} + +// OldImage returns the old "image" field's value of the Scans entity. +// If the Scans object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ScansMutation) OldImage(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldImage is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldImage requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldImage: %w", err) + } + return oldValue.Image, nil +} + +// ResetImage resets all changes to the "image" field. +func (m *ScansMutation) ResetImage() { + m.image = nil +} + +// SetCheck sets the "check" field. +func (m *ScansMutation) SetCheck(s schema.Check) { + m.check = &s +} + +// Check returns the value of the "check" field in the mutation. +func (m *ScansMutation) Check() (r schema.Check, exists bool) { + v := m.check + if v == nil { + return + } + return *v, true +} + +// OldCheck returns the old "check" field's value of the Scans entity. +// If the Scans object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ScansMutation) OldCheck(ctx context.Context) (v schema.Check, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCheck is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCheck requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCheck: %w", err) + } + return oldValue.Check, nil +} + +// ClearCheck clears the value of the "check" field. +func (m *ScansMutation) ClearCheck() { + m.check = nil + m.clearedFields[scans.FieldCheck] = struct{}{} +} + +// CheckCleared returns if the "check" field was cleared in this mutation. +func (m *ScansMutation) CheckCleared() bool { + _, ok := m.clearedFields[scans.FieldCheck] + return ok +} + +// ResetCheck resets all changes to the "check" field. +func (m *ScansMutation) ResetCheck() { + m.check = nil + delete(m.clearedFields, scans.FieldCheck) +} + +// SetReport sets the "report" field. +func (m *ScansMutation) SetReport(s string) { + m.report = &s +} + +// Report returns the value of the "report" field in the mutation. +func (m *ScansMutation) Report() (r string, exists bool) { + v := m.report + if v == nil { + return + } + return *v, true +} + +// OldReport returns the old "report" field's value of the Scans entity. +// If the Scans object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ScansMutation) OldReport(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldReport is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldReport requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldReport: %w", err) + } + return oldValue.Report, nil +} + +// ClearReport clears the value of the "report" field. +func (m *ScansMutation) ClearReport() { + m.report = nil + m.clearedFields[scans.FieldReport] = struct{}{} +} + +// ReportCleared returns if the "report" field was cleared in this mutation. +func (m *ScansMutation) ReportCleared() bool { + _, ok := m.clearedFields[scans.FieldReport] + return ok +} + +// ResetReport resets all changes to the "report" field. +func (m *ScansMutation) ResetReport() { + m.report = nil + delete(m.clearedFields, scans.FieldReport) +} + +// ClearPolicy clears the "policy" edge to the Policies entity. +func (m *ScansMutation) ClearPolicy() { + m.clearedpolicy = true + m.clearedFields[scans.FieldPolicyID] = struct{}{} +} + +// PolicyCleared reports if the "policy" edge to the Policies entity was cleared. +func (m *ScansMutation) PolicyCleared() bool { + return m.clearedpolicy +} + +// PolicyIDs returns the "policy" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// PolicyID instead. It exists only for internal usage by the builders. +func (m *ScansMutation) PolicyIDs() (ids []uuid.UUID) { + if id := m.policy; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetPolicy resets all changes to the "policy" edge. +func (m *ScansMutation) ResetPolicy() { + m.policy = nil + m.clearedpolicy = false +} + +// AddScanLabelIDs adds the "scan_labels" edge to the ScanLabels entity by ids. +func (m *ScansMutation) AddScanLabelIDs(ids ...int) { + if m.scan_labels == nil { + m.scan_labels = make(map[int]struct{}) + } + for i := range ids { + m.scan_labels[ids[i]] = struct{}{} + } +} + +// ClearScanLabels clears the "scan_labels" edge to the ScanLabels entity. +func (m *ScansMutation) ClearScanLabels() { + m.clearedscan_labels = true +} + +// ScanLabelsCleared reports if the "scan_labels" edge to the ScanLabels entity was cleared. +func (m *ScansMutation) ScanLabelsCleared() bool { + return m.clearedscan_labels +} + +// RemoveScanLabelIDs removes the "scan_labels" edge to the ScanLabels entity by IDs. +func (m *ScansMutation) RemoveScanLabelIDs(ids ...int) { + if m.removedscan_labels == nil { + m.removedscan_labels = make(map[int]struct{}) + } + for i := range ids { + delete(m.scan_labels, ids[i]) + m.removedscan_labels[ids[i]] = struct{}{} + } +} + +// RemovedScanLabels returns the removed IDs of the "scan_labels" edge to the ScanLabels entity. +func (m *ScansMutation) RemovedScanLabelsIDs() (ids []int) { + for id := range m.removedscan_labels { + ids = append(ids, id) + } + return +} + +// ScanLabelsIDs returns the "scan_labels" edge IDs in the mutation. +func (m *ScansMutation) ScanLabelsIDs() (ids []int) { + for id := range m.scan_labels { + ids = append(ids, id) + } + return +} + +// ResetScanLabels resets all changes to the "scan_labels" edge. +func (m *ScansMutation) ResetScanLabels() { + m.scan_labels = nil + m.clearedscan_labels = false + m.removedscan_labels = nil +} + +// Where appends a list predicates to the ScansMutation builder. +func (m *ScansMutation) Where(ps ...predicate.Scans) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the ScansMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *ScansMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.Scans, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *ScansMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *ScansMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (Scans). +func (m *ScansMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *ScansMutation) Fields() []string { + fields := make([]string, 0, 5) + if m.policy != nil { + fields = append(fields, scans.FieldPolicyID) + } + if m.status != nil { + fields = append(fields, scans.FieldStatus) + } + if m.image != nil { + fields = append(fields, scans.FieldImage) + } + if m.check != nil { + fields = append(fields, scans.FieldCheck) + } + if m.report != nil { + fields = append(fields, scans.FieldReport) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *ScansMutation) Field(name string) (ent.Value, bool) { + switch name { + case scans.FieldPolicyID: + return m.PolicyID() + case scans.FieldStatus: + return m.Status() + case scans.FieldImage: + return m.Image() + case scans.FieldCheck: + return m.Check() + case scans.FieldReport: + return m.Report() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *ScansMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case scans.FieldPolicyID: + return m.OldPolicyID(ctx) + case scans.FieldStatus: + return m.OldStatus(ctx) + case scans.FieldImage: + return m.OldImage(ctx) + case scans.FieldCheck: + return m.OldCheck(ctx) + case scans.FieldReport: + return m.OldReport(ctx) + } + return nil, fmt.Errorf("unknown Scans field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ScansMutation) SetField(name string, value ent.Value) error { + switch name { + case scans.FieldPolicyID: + v, ok := value.(uuid.UUID) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPolicyID(v) + return nil + case scans.FieldStatus: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetStatus(v) + return nil + case scans.FieldImage: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetImage(v) + return nil + case scans.FieldCheck: + v, ok := value.(schema.Check) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCheck(v) + return nil + case scans.FieldReport: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetReport(v) + return nil + } + return fmt.Errorf("unknown Scans field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *ScansMutation) AddedFields() []string { + return nil +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *ScansMutation) AddedField(name string) (ent.Value, bool) { + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ScansMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown Scans numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *ScansMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(scans.FieldCheck) { + fields = append(fields, scans.FieldCheck) + } + if m.FieldCleared(scans.FieldReport) { + fields = append(fields, scans.FieldReport) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *ScansMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *ScansMutation) ClearField(name string) error { + switch name { + case scans.FieldCheck: + m.ClearCheck() + return nil + case scans.FieldReport: + m.ClearReport() + return nil + } + return fmt.Errorf("unknown Scans nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *ScansMutation) ResetField(name string) error { + switch name { + case scans.FieldPolicyID: + m.ResetPolicyID() + return nil + case scans.FieldStatus: + m.ResetStatus() + return nil + case scans.FieldImage: + m.ResetImage() + return nil + case scans.FieldCheck: + m.ResetCheck() + return nil + case scans.FieldReport: + m.ResetReport() + return nil + } + return fmt.Errorf("unknown Scans field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *ScansMutation) AddedEdges() []string { + edges := make([]string, 0, 2) + if m.policy != nil { + edges = append(edges, scans.EdgePolicy) + } + if m.scan_labels != nil { + edges = append(edges, scans.EdgeScanLabels) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *ScansMutation) AddedIDs(name string) []ent.Value { + switch name { + case scans.EdgePolicy: + if id := m.policy; id != nil { + return []ent.Value{*id} + } + case scans.EdgeScanLabels: + ids := make([]ent.Value, 0, len(m.scan_labels)) + for id := range m.scan_labels { + ids = append(ids, id) + } + return ids + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *ScansMutation) RemovedEdges() []string { + edges := make([]string, 0, 2) + if m.removedscan_labels != nil { + edges = append(edges, scans.EdgeScanLabels) + } + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *ScansMutation) RemovedIDs(name string) []ent.Value { + switch name { + case scans.EdgeScanLabels: + ids := make([]ent.Value, 0, len(m.removedscan_labels)) + for id := range m.removedscan_labels { + ids = append(ids, id) + } + return ids + } + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *ScansMutation) ClearedEdges() []string { + edges := make([]string, 0, 2) + if m.clearedpolicy { + edges = append(edges, scans.EdgePolicy) + } + if m.clearedscan_labels { + edges = append(edges, scans.EdgeScanLabels) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *ScansMutation) EdgeCleared(name string) bool { + switch name { + case scans.EdgePolicy: + return m.clearedpolicy + case scans.EdgeScanLabels: + return m.clearedscan_labels + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *ScansMutation) ClearEdge(name string) error { + switch name { + case scans.EdgePolicy: + m.ClearPolicy() + return nil + } + return fmt.Errorf("unknown Scans unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *ScansMutation) ResetEdge(name string) error { + switch name { + case scans.EdgePolicy: + m.ResetPolicy() + return nil + case scans.EdgeScanLabels: + m.ResetScanLabels() + return nil + } + return fmt.Errorf("unknown Scans edge %s", name) +} diff --git a/ent/policies.go b/ent/policies.go index 36978bf..287bfec 100644 --- a/ent/policies.go +++ b/ent/policies.go @@ -40,9 +40,11 @@ type Policies struct { type PoliciesEdges struct { // PolicyLabels holds the value of the policy_labels edge. PolicyLabels []*PolicyLabels `json:"policy_labels,omitempty"` + // Scans holds the value of the scans edge. + Scans []*Scans `json:"scans,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. - loadedTypes [1]bool + loadedTypes [2]bool } // PolicyLabelsOrErr returns the PolicyLabels value or an error if the edge @@ -54,6 +56,15 @@ func (e PoliciesEdges) PolicyLabelsOrErr() ([]*PolicyLabels, error) { return nil, &NotLoadedError{edge: "policy_labels"} } +// ScansOrErr returns the Scans value or an error if the edge +// was not loaded in eager-loading. +func (e PoliciesEdges) ScansOrErr() ([]*Scans, error) { + if e.loadedTypes[1] { + return e.Scans, nil + } + return nil, &NotLoadedError{edge: "scans"} +} + // scanValues returns the types for scanning values from sql.Rows. func (*Policies) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) @@ -142,6 +153,11 @@ func (po *Policies) QueryPolicyLabels() *PolicyLabelsQuery { return NewPoliciesClient(po.config).QueryPolicyLabels(po) } +// QueryScans queries the "scans" edge of the Policies entity. +func (po *Policies) QueryScans() *ScansQuery { + return NewPoliciesClient(po.config).QueryScans(po) +} + // Update returns a builder for updating this Policies. // Note that you need to call Policies.Unwrap() before calling this method if this Policies // was returned from a transaction, and the transaction was committed or rolled back. diff --git a/ent/policies/policies.go b/ent/policies/policies.go index 92d31b5..928cfd7 100644 --- a/ent/policies/policies.go +++ b/ent/policies/policies.go @@ -25,6 +25,8 @@ const ( FieldCheck = "check" // EdgePolicyLabels holds the string denoting the policy_labels edge name in mutations. EdgePolicyLabels = "policy_labels" + // EdgeScans holds the string denoting the scans edge name in mutations. + EdgeScans = "scans" // Table holds the table name of the policies in the database. Table = "policies" // PolicyLabelsTable is the table that holds the policy_labels relation/edge. @@ -34,6 +36,13 @@ const ( PolicyLabelsInverseTable = "policy_labels" // PolicyLabelsColumn is the table column denoting the policy_labels relation/edge. PolicyLabelsColumn = "policy_id" + // ScansTable is the table that holds the scans relation/edge. + ScansTable = "scans" + // ScansInverseTable is the table name for the Scans entity. + // It exists in this package in order to avoid circular dependency with the "scans" package. + ScansInverseTable = "scans" + // ScansColumn is the table column denoting the scans relation/edge. + ScansColumn = "policy_id" ) // Columns holds all SQL columns for policies fields. @@ -89,6 +98,20 @@ func ByPolicyLabels(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { sqlgraph.OrderByNeighborTerms(s, newPolicyLabelsStep(), append([]sql.OrderTerm{term}, terms...)...) } } + +// ByScansCount orders the results by scans count. +func ByScansCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newScansStep(), opts...) + } +} + +// ByScans orders the results by scans terms. +func ByScans(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newScansStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} func newPolicyLabelsStep() *sqlgraph.Step { return sqlgraph.NewStep( sqlgraph.From(Table, FieldID), @@ -96,3 +119,10 @@ func newPolicyLabelsStep() *sqlgraph.Step { sqlgraph.Edge(sqlgraph.O2M, false, PolicyLabelsTable, PolicyLabelsColumn), ) } +func newScansStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(ScansInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, ScansTable, ScansColumn), + ) +} diff --git a/ent/policies/where.go b/ent/policies/where.go index 8ff6617..e94c88c 100644 --- a/ent/policies/where.go +++ b/ent/policies/where.go @@ -177,6 +177,29 @@ func HasPolicyLabelsWith(preds ...predicate.PolicyLabels) predicate.Policies { }) } +// HasScans applies the HasEdge predicate on the "scans" edge. +func HasScans() predicate.Policies { + return predicate.Policies(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, ScansTable, ScansColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasScansWith applies the HasEdge predicate on the "scans" edge with a given conditions (other predicates). +func HasScansWith(preds ...predicate.Scans) predicate.Policies { + return predicate.Policies(func(s *sql.Selector) { + step := newScansStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + // And groups predicates with the AND operator between them. func And(predicates ...predicate.Policies) predicate.Policies { return predicate.Policies(sql.AndPredicates(predicates...)) diff --git a/ent/policies_create.go b/ent/policies_create.go index ffcb004..2b4f23a 100644 --- a/ent/policies_create.go +++ b/ent/policies_create.go @@ -12,6 +12,7 @@ import ( "github.com/google/uuid" "github.com/shinobistack/gokakashi/ent/policies" "github.com/shinobistack/gokakashi/ent/policylabels" + "github.com/shinobistack/gokakashi/ent/scans" "github.com/shinobistack/gokakashi/ent/schema" ) @@ -97,6 +98,21 @@ func (pc *PoliciesCreate) AddPolicyLabels(p ...*PolicyLabels) *PoliciesCreate { return pc.AddPolicyLabelIDs(ids...) } +// AddScanIDs adds the "scans" edge to the Scans entity by IDs. +func (pc *PoliciesCreate) AddScanIDs(ids ...uuid.UUID) *PoliciesCreate { + pc.mutation.AddScanIDs(ids...) + return pc +} + +// AddScans adds the "scans" edges to the Scans entity. +func (pc *PoliciesCreate) AddScans(s ...*Scans) *PoliciesCreate { + ids := make([]uuid.UUID, len(s)) + for i := range s { + ids[i] = s[i].ID + } + return pc.AddScanIDs(ids...) +} + // Mutation returns the PoliciesMutation object of the builder. func (pc *PoliciesCreate) Mutation() *PoliciesMutation { return pc.mutation @@ -222,6 +238,22 @@ func (pc *PoliciesCreate) createSpec() (*Policies, *sqlgraph.CreateSpec) { } _spec.Edges = append(_spec.Edges, edge) } + if nodes := pc.mutation.ScansIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: policies.ScansTable, + Columns: []string{policies.ScansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } return _node, _spec } diff --git a/ent/policies_query.go b/ent/policies_query.go index 057121b..f00bd77 100644 --- a/ent/policies_query.go +++ b/ent/policies_query.go @@ -16,6 +16,7 @@ import ( "github.com/shinobistack/gokakashi/ent/policies" "github.com/shinobistack/gokakashi/ent/policylabels" "github.com/shinobistack/gokakashi/ent/predicate" + "github.com/shinobistack/gokakashi/ent/scans" ) // PoliciesQuery is the builder for querying Policies entities. @@ -26,6 +27,7 @@ type PoliciesQuery struct { inters []Interceptor predicates []predicate.Policies withPolicyLabels *PolicyLabelsQuery + withScans *ScansQuery // intermediate query (i.e. traversal path). sql *sql.Selector path func(context.Context) (*sql.Selector, error) @@ -84,6 +86,28 @@ func (pq *PoliciesQuery) QueryPolicyLabels() *PolicyLabelsQuery { return query } +// QueryScans chains the current query on the "scans" edge. +func (pq *PoliciesQuery) QueryScans() *ScansQuery { + query := (&ScansClient{config: pq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := pq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := pq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(policies.Table, policies.FieldID, selector), + sqlgraph.To(scans.Table, scans.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, policies.ScansTable, policies.ScansColumn), + ) + fromU = sqlgraph.SetNeighbors(pq.driver.Dialect(), step) + return fromU, nil + } + return query +} + // First returns the first Policies entity from the query. // Returns a *NotFoundError when no Policies was found. func (pq *PoliciesQuery) First(ctx context.Context) (*Policies, error) { @@ -277,6 +301,7 @@ func (pq *PoliciesQuery) Clone() *PoliciesQuery { inters: append([]Interceptor{}, pq.inters...), predicates: append([]predicate.Policies{}, pq.predicates...), withPolicyLabels: pq.withPolicyLabels.Clone(), + withScans: pq.withScans.Clone(), // clone intermediate query. sql: pq.sql.Clone(), path: pq.path, @@ -294,6 +319,17 @@ func (pq *PoliciesQuery) WithPolicyLabels(opts ...func(*PolicyLabelsQuery)) *Pol return pq } +// WithScans tells the query-builder to eager-load the nodes that are connected to +// the "scans" edge. The optional arguments are used to configure the query builder of the edge. +func (pq *PoliciesQuery) WithScans(opts ...func(*ScansQuery)) *PoliciesQuery { + query := (&ScansClient{config: pq.config}).Query() + for _, opt := range opts { + opt(query) + } + pq.withScans = query + return pq +} + // GroupBy is used to group vertices by one or more fields/columns. // It is often used with aggregate functions, like: count, max, mean, min, sum. // @@ -372,8 +408,9 @@ func (pq *PoliciesQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Pol var ( nodes = []*Policies{} _spec = pq.querySpec() - loadedTypes = [1]bool{ + loadedTypes = [2]bool{ pq.withPolicyLabels != nil, + pq.withScans != nil, } ) _spec.ScanValues = func(columns []string) ([]any, error) { @@ -401,6 +438,13 @@ func (pq *PoliciesQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Pol return nil, err } } + if query := pq.withScans; query != nil { + if err := pq.loadScans(ctx, query, nodes, + func(n *Policies) { n.Edges.Scans = []*Scans{} }, + func(n *Policies, e *Scans) { n.Edges.Scans = append(n.Edges.Scans, e) }); err != nil { + return nil, err + } + } return nodes, nil } @@ -434,6 +478,36 @@ func (pq *PoliciesQuery) loadPolicyLabels(ctx context.Context, query *PolicyLabe } return nil } +func (pq *PoliciesQuery) loadScans(ctx context.Context, query *ScansQuery, nodes []*Policies, init func(*Policies), assign func(*Policies, *Scans)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[uuid.UUID]*Policies) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(scans.FieldPolicyID) + } + query.Where(predicate.Scans(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(policies.ScansColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.PolicyID + node, ok := nodeids[fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "policy_id" returned %v for node %v`, fk, n.ID) + } + assign(node, n) + } + return nil +} func (pq *PoliciesQuery) sqlCount(ctx context.Context) (int, error) { _spec := pq.querySpec() diff --git a/ent/policies_update.go b/ent/policies_update.go index 96e3e26..ca07d04 100644 --- a/ent/policies_update.go +++ b/ent/policies_update.go @@ -10,9 +10,11 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" + "github.com/google/uuid" "github.com/shinobistack/gokakashi/ent/policies" "github.com/shinobistack/gokakashi/ent/policylabels" "github.com/shinobistack/gokakashi/ent/predicate" + "github.com/shinobistack/gokakashi/ent/scans" "github.com/shinobistack/gokakashi/ent/schema" ) @@ -124,6 +126,21 @@ func (pu *PoliciesUpdate) AddPolicyLabels(p ...*PolicyLabels) *PoliciesUpdate { return pu.AddPolicyLabelIDs(ids...) } +// AddScanIDs adds the "scans" edge to the Scans entity by IDs. +func (pu *PoliciesUpdate) AddScanIDs(ids ...uuid.UUID) *PoliciesUpdate { + pu.mutation.AddScanIDs(ids...) + return pu +} + +// AddScans adds the "scans" edges to the Scans entity. +func (pu *PoliciesUpdate) AddScans(s ...*Scans) *PoliciesUpdate { + ids := make([]uuid.UUID, len(s)) + for i := range s { + ids[i] = s[i].ID + } + return pu.AddScanIDs(ids...) +} + // Mutation returns the PoliciesMutation object of the builder. func (pu *PoliciesUpdate) Mutation() *PoliciesMutation { return pu.mutation @@ -150,6 +167,27 @@ func (pu *PoliciesUpdate) RemovePolicyLabels(p ...*PolicyLabels) *PoliciesUpdate return pu.RemovePolicyLabelIDs(ids...) } +// ClearScans clears all "scans" edges to the Scans entity. +func (pu *PoliciesUpdate) ClearScans() *PoliciesUpdate { + pu.mutation.ClearScans() + return pu +} + +// RemoveScanIDs removes the "scans" edge to Scans entities by IDs. +func (pu *PoliciesUpdate) RemoveScanIDs(ids ...uuid.UUID) *PoliciesUpdate { + pu.mutation.RemoveScanIDs(ids...) + return pu +} + +// RemoveScans removes "scans" edges to Scans entities. +func (pu *PoliciesUpdate) RemoveScans(s ...*Scans) *PoliciesUpdate { + ids := make([]uuid.UUID, len(s)) + for i := range s { + ids[i] = s[i].ID + } + return pu.RemoveScanIDs(ids...) +} + // Save executes the query and returns the number of nodes affected by the update operation. func (pu *PoliciesUpdate) Save(ctx context.Context) (int, error) { return withHooks(ctx, pu.sqlSave, pu.mutation, pu.hooks) @@ -268,6 +306,51 @@ func (pu *PoliciesUpdate) sqlSave(ctx context.Context) (n int, err error) { } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if pu.mutation.ScansCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: policies.ScansTable, + Columns: []string{policies.ScansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := pu.mutation.RemovedScansIDs(); len(nodes) > 0 && !pu.mutation.ScansCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: policies.ScansTable, + Columns: []string{policies.ScansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := pu.mutation.ScansIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: policies.ScansTable, + Columns: []string{policies.ScansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } if n, err = sqlgraph.UpdateNodes(ctx, pu.driver, _spec); err != nil { if _, ok := err.(*sqlgraph.NotFoundError); ok { err = &NotFoundError{policies.Label} @@ -383,6 +466,21 @@ func (puo *PoliciesUpdateOne) AddPolicyLabels(p ...*PolicyLabels) *PoliciesUpdat return puo.AddPolicyLabelIDs(ids...) } +// AddScanIDs adds the "scans" edge to the Scans entity by IDs. +func (puo *PoliciesUpdateOne) AddScanIDs(ids ...uuid.UUID) *PoliciesUpdateOne { + puo.mutation.AddScanIDs(ids...) + return puo +} + +// AddScans adds the "scans" edges to the Scans entity. +func (puo *PoliciesUpdateOne) AddScans(s ...*Scans) *PoliciesUpdateOne { + ids := make([]uuid.UUID, len(s)) + for i := range s { + ids[i] = s[i].ID + } + return puo.AddScanIDs(ids...) +} + // Mutation returns the PoliciesMutation object of the builder. func (puo *PoliciesUpdateOne) Mutation() *PoliciesMutation { return puo.mutation @@ -409,6 +507,27 @@ func (puo *PoliciesUpdateOne) RemovePolicyLabels(p ...*PolicyLabels) *PoliciesUp return puo.RemovePolicyLabelIDs(ids...) } +// ClearScans clears all "scans" edges to the Scans entity. +func (puo *PoliciesUpdateOne) ClearScans() *PoliciesUpdateOne { + puo.mutation.ClearScans() + return puo +} + +// RemoveScanIDs removes the "scans" edge to Scans entities by IDs. +func (puo *PoliciesUpdateOne) RemoveScanIDs(ids ...uuid.UUID) *PoliciesUpdateOne { + puo.mutation.RemoveScanIDs(ids...) + return puo +} + +// RemoveScans removes "scans" edges to Scans entities. +func (puo *PoliciesUpdateOne) RemoveScans(s ...*Scans) *PoliciesUpdateOne { + ids := make([]uuid.UUID, len(s)) + for i := range s { + ids[i] = s[i].ID + } + return puo.RemoveScanIDs(ids...) +} + // Where appends a list predicates to the PoliciesUpdate builder. func (puo *PoliciesUpdateOne) Where(ps ...predicate.Policies) *PoliciesUpdateOne { puo.mutation.Where(ps...) @@ -557,6 +676,51 @@ func (puo *PoliciesUpdateOne) sqlSave(ctx context.Context) (_node *Policies, err } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if puo.mutation.ScansCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: policies.ScansTable, + Columns: []string{policies.ScansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := puo.mutation.RemovedScansIDs(); len(nodes) > 0 && !puo.mutation.ScansCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: policies.ScansTable, + Columns: []string{policies.ScansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := puo.mutation.ScansIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: policies.ScansTable, + Columns: []string{policies.ScansColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } _node = &Policies{config: puo.config} _spec.Assign = _node.assignValues _spec.ScanValues = _node.scanValues diff --git a/ent/predicate/predicate.go b/ent/predicate/predicate.go index ca231c0..27ea1c1 100644 --- a/ent/predicate/predicate.go +++ b/ent/predicate/predicate.go @@ -17,3 +17,9 @@ type Policies func(*sql.Selector) // PolicyLabels is the predicate function for policylabels builders. type PolicyLabels func(*sql.Selector) + +// ScanLabels is the predicate function for scanlabels builders. +type ScanLabels func(*sql.Selector) + +// Scans is the predicate function for scans builders. +type Scans func(*sql.Selector) diff --git a/ent/runtime.go b/ent/runtime.go index 70a10b5..f205de7 100644 --- a/ent/runtime.go +++ b/ent/runtime.go @@ -8,6 +8,8 @@ import ( "github.com/shinobistack/gokakashi/ent/integrationtype" "github.com/shinobistack/gokakashi/ent/policies" "github.com/shinobistack/gokakashi/ent/policylabels" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/shinobistack/gokakashi/ent/scans" "github.com/shinobistack/gokakashi/ent/schema" ) @@ -69,4 +71,24 @@ func init() { policylabelsDescValue := policylabelsFields[2].Descriptor() // policylabels.ValueValidator is a validator for the "value" field. It is called by the builders before save. policylabels.ValueValidator = policylabelsDescValue.Validators[0].(func(string) error) + scanlabelsFields := schema.ScanLabels{}.Fields() + _ = scanlabelsFields + // scanlabelsDescKey is the schema descriptor for key field. + scanlabelsDescKey := scanlabelsFields[1].Descriptor() + // scanlabels.KeyValidator is a validator for the "key" field. It is called by the builders before save. + scanlabels.KeyValidator = scanlabelsDescKey.Validators[0].(func(string) error) + // scanlabelsDescValue is the schema descriptor for value field. + scanlabelsDescValue := scanlabelsFields[2].Descriptor() + // scanlabels.ValueValidator is a validator for the "value" field. It is called by the builders before save. + scanlabels.ValueValidator = scanlabelsDescValue.Validators[0].(func(string) error) + scansFields := schema.Scans{}.Fields() + _ = scansFields + // scansDescStatus is the schema descriptor for status field. + scansDescStatus := scansFields[2].Descriptor() + // scans.DefaultStatus holds the default value on creation for the status field. + scans.DefaultStatus = scansDescStatus.Default.(string) + // scansDescID is the schema descriptor for id field. + scansDescID := scansFields[0].Descriptor() + // scans.DefaultID holds the default value on creation for the id field. + scans.DefaultID = scansDescID.Default.(func() uuid.UUID) } diff --git a/ent/scanlabels.go b/ent/scanlabels.go new file mode 100644 index 0000000..4dcb962 --- /dev/null +++ b/ent/scanlabels.go @@ -0,0 +1,157 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "fmt" + "strings" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/shinobistack/gokakashi/ent/scans" +) + +// ScanLabels is the model entity for the ScanLabels schema. +type ScanLabels struct { + config `json:"-"` + // ID of the ent. + ID int `json:"id,omitempty"` + // Foreign key to Scans.ID. + ScanID uuid.UUID `json:"scan_id,omitempty"` + // Label key. + Key string `json:"key,omitempty"` + // Label value. + Value string `json:"value,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the ScanLabelsQuery when eager-loading is set. + Edges ScanLabelsEdges `json:"edges"` + selectValues sql.SelectValues +} + +// ScanLabelsEdges holds the relations/edges for other nodes in the graph. +type ScanLabelsEdges struct { + // Scan holds the value of the scan edge. + Scan *Scans `json:"scan,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [1]bool +} + +// ScanOrErr returns the Scan value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e ScanLabelsEdges) ScanOrErr() (*Scans, error) { + if e.Scan != nil { + return e.Scan, nil + } else if e.loadedTypes[0] { + return nil, &NotFoundError{label: scans.Label} + } + return nil, &NotLoadedError{edge: "scan"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*ScanLabels) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case scanlabels.FieldID: + values[i] = new(sql.NullInt64) + case scanlabels.FieldKey, scanlabels.FieldValue: + values[i] = new(sql.NullString) + case scanlabels.FieldScanID: + values[i] = new(uuid.UUID) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the ScanLabels fields. +func (sl *ScanLabels) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case scanlabels.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + sl.ID = int(value.Int64) + case scanlabels.FieldScanID: + if value, ok := values[i].(*uuid.UUID); !ok { + return fmt.Errorf("unexpected type %T for field scan_id", values[i]) + } else if value != nil { + sl.ScanID = *value + } + case scanlabels.FieldKey: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field key", values[i]) + } else if value.Valid { + sl.Key = value.String + } + case scanlabels.FieldValue: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field value", values[i]) + } else if value.Valid { + sl.Value = value.String + } + default: + sl.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// GetValue returns the ent.Value that was dynamically selected and assigned to the ScanLabels. +// This includes values selected through modifiers, order, etc. +func (sl *ScanLabels) GetValue(name string) (ent.Value, error) { + return sl.selectValues.Get(name) +} + +// QueryScan queries the "scan" edge of the ScanLabels entity. +func (sl *ScanLabels) QueryScan() *ScansQuery { + return NewScanLabelsClient(sl.config).QueryScan(sl) +} + +// Update returns a builder for updating this ScanLabels. +// Note that you need to call ScanLabels.Unwrap() before calling this method if this ScanLabels +// was returned from a transaction, and the transaction was committed or rolled back. +func (sl *ScanLabels) Update() *ScanLabelsUpdateOne { + return NewScanLabelsClient(sl.config).UpdateOne(sl) +} + +// Unwrap unwraps the ScanLabels entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (sl *ScanLabels) Unwrap() *ScanLabels { + _tx, ok := sl.config.driver.(*txDriver) + if !ok { + panic("ent: ScanLabels is not a transactional entity") + } + sl.config.driver = _tx.drv + return sl +} + +// String implements the fmt.Stringer. +func (sl *ScanLabels) String() string { + var builder strings.Builder + builder.WriteString("ScanLabels(") + builder.WriteString(fmt.Sprintf("id=%v, ", sl.ID)) + builder.WriteString("scan_id=") + builder.WriteString(fmt.Sprintf("%v", sl.ScanID)) + builder.WriteString(", ") + builder.WriteString("key=") + builder.WriteString(sl.Key) + builder.WriteString(", ") + builder.WriteString("value=") + builder.WriteString(sl.Value) + builder.WriteByte(')') + return builder.String() +} + +// ScanLabelsSlice is a parsable slice of ScanLabels. +type ScanLabelsSlice []*ScanLabels diff --git a/ent/scanlabels/scanlabels.go b/ent/scanlabels/scanlabels.go new file mode 100644 index 0000000..1b4e063 --- /dev/null +++ b/ent/scanlabels/scanlabels.go @@ -0,0 +1,94 @@ +// Code generated by ent, DO NOT EDIT. + +package scanlabels + +import ( + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" +) + +const ( + // Label holds the string label denoting the scanlabels type in the database. + Label = "scan_labels" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldScanID holds the string denoting the scan_id field in the database. + FieldScanID = "scan_id" + // FieldKey holds the string denoting the key field in the database. + FieldKey = "key" + // FieldValue holds the string denoting the value field in the database. + FieldValue = "value" + // EdgeScan holds the string denoting the scan edge name in mutations. + EdgeScan = "scan" + // Table holds the table name of the scanlabels in the database. + Table = "scan_labels" + // ScanTable is the table that holds the scan relation/edge. + ScanTable = "scan_labels" + // ScanInverseTable is the table name for the Scans entity. + // It exists in this package in order to avoid circular dependency with the "scans" package. + ScanInverseTable = "scans" + // ScanColumn is the table column denoting the scan relation/edge. + ScanColumn = "scan_id" +) + +// Columns holds all SQL columns for scanlabels fields. +var Columns = []string{ + FieldID, + FieldScanID, + FieldKey, + FieldValue, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // KeyValidator is a validator for the "key" field. It is called by the builders before save. + KeyValidator func(string) error + // ValueValidator is a validator for the "value" field. It is called by the builders before save. + ValueValidator func(string) error +) + +// OrderOption defines the ordering options for the ScanLabels queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByScanID orders the results by the scan_id field. +func ByScanID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldScanID, opts...).ToFunc() +} + +// ByKey orders the results by the key field. +func ByKey(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldKey, opts...).ToFunc() +} + +// ByValue orders the results by the value field. +func ByValue(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldValue, opts...).ToFunc() +} + +// ByScanField orders the results by scan field. +func ByScanField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newScanStep(), sql.OrderByField(field, opts...)) + } +} +func newScanStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(ScanInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, ScanTable, ScanColumn), + ) +} diff --git a/ent/scanlabels/where.go b/ent/scanlabels/where.go new file mode 100644 index 0000000..bb15702 --- /dev/null +++ b/ent/scanlabels/where.go @@ -0,0 +1,258 @@ +// Code generated by ent, DO NOT EDIT. + +package scanlabels + +import ( + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id int) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldLTE(FieldID, id)) +} + +// ScanID applies equality check predicate on the "scan_id" field. It's identical to ScanIDEQ. +func ScanID(v uuid.UUID) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldEQ(FieldScanID, v)) +} + +// Key applies equality check predicate on the "key" field. It's identical to KeyEQ. +func Key(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldEQ(FieldKey, v)) +} + +// Value applies equality check predicate on the "value" field. It's identical to ValueEQ. +func Value(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldEQ(FieldValue, v)) +} + +// ScanIDEQ applies the EQ predicate on the "scan_id" field. +func ScanIDEQ(v uuid.UUID) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldEQ(FieldScanID, v)) +} + +// ScanIDNEQ applies the NEQ predicate on the "scan_id" field. +func ScanIDNEQ(v uuid.UUID) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldNEQ(FieldScanID, v)) +} + +// ScanIDIn applies the In predicate on the "scan_id" field. +func ScanIDIn(vs ...uuid.UUID) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldIn(FieldScanID, vs...)) +} + +// ScanIDNotIn applies the NotIn predicate on the "scan_id" field. +func ScanIDNotIn(vs ...uuid.UUID) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldNotIn(FieldScanID, vs...)) +} + +// KeyEQ applies the EQ predicate on the "key" field. +func KeyEQ(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldEQ(FieldKey, v)) +} + +// KeyNEQ applies the NEQ predicate on the "key" field. +func KeyNEQ(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldNEQ(FieldKey, v)) +} + +// KeyIn applies the In predicate on the "key" field. +func KeyIn(vs ...string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldIn(FieldKey, vs...)) +} + +// KeyNotIn applies the NotIn predicate on the "key" field. +func KeyNotIn(vs ...string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldNotIn(FieldKey, vs...)) +} + +// KeyGT applies the GT predicate on the "key" field. +func KeyGT(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldGT(FieldKey, v)) +} + +// KeyGTE applies the GTE predicate on the "key" field. +func KeyGTE(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldGTE(FieldKey, v)) +} + +// KeyLT applies the LT predicate on the "key" field. +func KeyLT(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldLT(FieldKey, v)) +} + +// KeyLTE applies the LTE predicate on the "key" field. +func KeyLTE(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldLTE(FieldKey, v)) +} + +// KeyContains applies the Contains predicate on the "key" field. +func KeyContains(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldContains(FieldKey, v)) +} + +// KeyHasPrefix applies the HasPrefix predicate on the "key" field. +func KeyHasPrefix(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldHasPrefix(FieldKey, v)) +} + +// KeyHasSuffix applies the HasSuffix predicate on the "key" field. +func KeyHasSuffix(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldHasSuffix(FieldKey, v)) +} + +// KeyEqualFold applies the EqualFold predicate on the "key" field. +func KeyEqualFold(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldEqualFold(FieldKey, v)) +} + +// KeyContainsFold applies the ContainsFold predicate on the "key" field. +func KeyContainsFold(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldContainsFold(FieldKey, v)) +} + +// ValueEQ applies the EQ predicate on the "value" field. +func ValueEQ(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldEQ(FieldValue, v)) +} + +// ValueNEQ applies the NEQ predicate on the "value" field. +func ValueNEQ(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldNEQ(FieldValue, v)) +} + +// ValueIn applies the In predicate on the "value" field. +func ValueIn(vs ...string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldIn(FieldValue, vs...)) +} + +// ValueNotIn applies the NotIn predicate on the "value" field. +func ValueNotIn(vs ...string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldNotIn(FieldValue, vs...)) +} + +// ValueGT applies the GT predicate on the "value" field. +func ValueGT(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldGT(FieldValue, v)) +} + +// ValueGTE applies the GTE predicate on the "value" field. +func ValueGTE(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldGTE(FieldValue, v)) +} + +// ValueLT applies the LT predicate on the "value" field. +func ValueLT(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldLT(FieldValue, v)) +} + +// ValueLTE applies the LTE predicate on the "value" field. +func ValueLTE(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldLTE(FieldValue, v)) +} + +// ValueContains applies the Contains predicate on the "value" field. +func ValueContains(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldContains(FieldValue, v)) +} + +// ValueHasPrefix applies the HasPrefix predicate on the "value" field. +func ValueHasPrefix(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldHasPrefix(FieldValue, v)) +} + +// ValueHasSuffix applies the HasSuffix predicate on the "value" field. +func ValueHasSuffix(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldHasSuffix(FieldValue, v)) +} + +// ValueEqualFold applies the EqualFold predicate on the "value" field. +func ValueEqualFold(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldEqualFold(FieldValue, v)) +} + +// ValueContainsFold applies the ContainsFold predicate on the "value" field. +func ValueContainsFold(v string) predicate.ScanLabels { + return predicate.ScanLabels(sql.FieldContainsFold(FieldValue, v)) +} + +// HasScan applies the HasEdge predicate on the "scan" edge. +func HasScan() predicate.ScanLabels { + return predicate.ScanLabels(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, ScanTable, ScanColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasScanWith applies the HasEdge predicate on the "scan" edge with a given conditions (other predicates). +func HasScanWith(preds ...predicate.Scans) predicate.ScanLabels { + return predicate.ScanLabels(func(s *sql.Selector) { + step := newScanStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.ScanLabels) predicate.ScanLabels { + return predicate.ScanLabels(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.ScanLabels) predicate.ScanLabels { + return predicate.ScanLabels(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.ScanLabels) predicate.ScanLabels { + return predicate.ScanLabels(sql.NotPredicates(p)) +} diff --git a/ent/scanlabels_create.go b/ent/scanlabels_create.go new file mode 100644 index 0000000..47ad67d --- /dev/null +++ b/ent/scanlabels_create.go @@ -0,0 +1,242 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/shinobistack/gokakashi/ent/scans" +) + +// ScanLabelsCreate is the builder for creating a ScanLabels entity. +type ScanLabelsCreate struct { + config + mutation *ScanLabelsMutation + hooks []Hook +} + +// SetScanID sets the "scan_id" field. +func (slc *ScanLabelsCreate) SetScanID(u uuid.UUID) *ScanLabelsCreate { + slc.mutation.SetScanID(u) + return slc +} + +// SetKey sets the "key" field. +func (slc *ScanLabelsCreate) SetKey(s string) *ScanLabelsCreate { + slc.mutation.SetKey(s) + return slc +} + +// SetValue sets the "value" field. +func (slc *ScanLabelsCreate) SetValue(s string) *ScanLabelsCreate { + slc.mutation.SetValue(s) + return slc +} + +// SetScan sets the "scan" edge to the Scans entity. +func (slc *ScanLabelsCreate) SetScan(s *Scans) *ScanLabelsCreate { + return slc.SetScanID(s.ID) +} + +// Mutation returns the ScanLabelsMutation object of the builder. +func (slc *ScanLabelsCreate) Mutation() *ScanLabelsMutation { + return slc.mutation +} + +// Save creates the ScanLabels in the database. +func (slc *ScanLabelsCreate) Save(ctx context.Context) (*ScanLabels, error) { + return withHooks(ctx, slc.sqlSave, slc.mutation, slc.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (slc *ScanLabelsCreate) SaveX(ctx context.Context) *ScanLabels { + v, err := slc.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (slc *ScanLabelsCreate) Exec(ctx context.Context) error { + _, err := slc.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (slc *ScanLabelsCreate) ExecX(ctx context.Context) { + if err := slc.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (slc *ScanLabelsCreate) check() error { + if _, ok := slc.mutation.ScanID(); !ok { + return &ValidationError{Name: "scan_id", err: errors.New(`ent: missing required field "ScanLabels.scan_id"`)} + } + if _, ok := slc.mutation.Key(); !ok { + return &ValidationError{Name: "key", err: errors.New(`ent: missing required field "ScanLabels.key"`)} + } + if v, ok := slc.mutation.Key(); ok { + if err := scanlabels.KeyValidator(v); err != nil { + return &ValidationError{Name: "key", err: fmt.Errorf(`ent: validator failed for field "ScanLabels.key": %w`, err)} + } + } + if _, ok := slc.mutation.Value(); !ok { + return &ValidationError{Name: "value", err: errors.New(`ent: missing required field "ScanLabels.value"`)} + } + if v, ok := slc.mutation.Value(); ok { + if err := scanlabels.ValueValidator(v); err != nil { + return &ValidationError{Name: "value", err: fmt.Errorf(`ent: validator failed for field "ScanLabels.value": %w`, err)} + } + } + if len(slc.mutation.ScanIDs()) == 0 { + return &ValidationError{Name: "scan", err: errors.New(`ent: missing required edge "ScanLabels.scan"`)} + } + return nil +} + +func (slc *ScanLabelsCreate) sqlSave(ctx context.Context) (*ScanLabels, error) { + if err := slc.check(); err != nil { + return nil, err + } + _node, _spec := slc.createSpec() + if err := sqlgraph.CreateNode(ctx, slc.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + id := _spec.ID.Value.(int64) + _node.ID = int(id) + slc.mutation.id = &_node.ID + slc.mutation.done = true + return _node, nil +} + +func (slc *ScanLabelsCreate) createSpec() (*ScanLabels, *sqlgraph.CreateSpec) { + var ( + _node = &ScanLabels{config: slc.config} + _spec = sqlgraph.NewCreateSpec(scanlabels.Table, sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt)) + ) + if value, ok := slc.mutation.Key(); ok { + _spec.SetField(scanlabels.FieldKey, field.TypeString, value) + _node.Key = value + } + if value, ok := slc.mutation.Value(); ok { + _spec.SetField(scanlabels.FieldValue, field.TypeString, value) + _node.Value = value + } + if nodes := slc.mutation.ScanIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: scanlabels.ScanTable, + Columns: []string{scanlabels.ScanColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.ScanID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// ScanLabelsCreateBulk is the builder for creating many ScanLabels entities in bulk. +type ScanLabelsCreateBulk struct { + config + err error + builders []*ScanLabelsCreate +} + +// Save creates the ScanLabels entities in the database. +func (slcb *ScanLabelsCreateBulk) Save(ctx context.Context) ([]*ScanLabels, error) { + if slcb.err != nil { + return nil, slcb.err + } + specs := make([]*sqlgraph.CreateSpec, len(slcb.builders)) + nodes := make([]*ScanLabels, len(slcb.builders)) + mutators := make([]Mutator, len(slcb.builders)) + for i := range slcb.builders { + func(i int, root context.Context) { + builder := slcb.builders[i] + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*ScanLabelsMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, slcb.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, slcb.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + if specs[i].ID.Value != nil { + id := specs[i].ID.Value.(int64) + nodes[i].ID = int(id) + } + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, slcb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (slcb *ScanLabelsCreateBulk) SaveX(ctx context.Context) []*ScanLabels { + v, err := slcb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (slcb *ScanLabelsCreateBulk) Exec(ctx context.Context) error { + _, err := slcb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (slcb *ScanLabelsCreateBulk) ExecX(ctx context.Context) { + if err := slcb.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/scanlabels_delete.go b/ent/scanlabels_delete.go new file mode 100644 index 0000000..ff2d1f0 --- /dev/null +++ b/ent/scanlabels_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/shinobistack/gokakashi/ent/predicate" + "github.com/shinobistack/gokakashi/ent/scanlabels" +) + +// ScanLabelsDelete is the builder for deleting a ScanLabels entity. +type ScanLabelsDelete struct { + config + hooks []Hook + mutation *ScanLabelsMutation +} + +// Where appends a list predicates to the ScanLabelsDelete builder. +func (sld *ScanLabelsDelete) Where(ps ...predicate.ScanLabels) *ScanLabelsDelete { + sld.mutation.Where(ps...) + return sld +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (sld *ScanLabelsDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, sld.sqlExec, sld.mutation, sld.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (sld *ScanLabelsDelete) ExecX(ctx context.Context) int { + n, err := sld.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (sld *ScanLabelsDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(scanlabels.Table, sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt)) + if ps := sld.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, sld.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + sld.mutation.done = true + return affected, err +} + +// ScanLabelsDeleteOne is the builder for deleting a single ScanLabels entity. +type ScanLabelsDeleteOne struct { + sld *ScanLabelsDelete +} + +// Where appends a list predicates to the ScanLabelsDelete builder. +func (sldo *ScanLabelsDeleteOne) Where(ps ...predicate.ScanLabels) *ScanLabelsDeleteOne { + sldo.sld.mutation.Where(ps...) + return sldo +} + +// Exec executes the deletion query. +func (sldo *ScanLabelsDeleteOne) Exec(ctx context.Context) error { + n, err := sldo.sld.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{scanlabels.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (sldo *ScanLabelsDeleteOne) ExecX(ctx context.Context) { + if err := sldo.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/scanlabels_query.go b/ent/scanlabels_query.go new file mode 100644 index 0000000..bedc210 --- /dev/null +++ b/ent/scanlabels_query.go @@ -0,0 +1,607 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/predicate" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/shinobistack/gokakashi/ent/scans" +) + +// ScanLabelsQuery is the builder for querying ScanLabels entities. +type ScanLabelsQuery struct { + config + ctx *QueryContext + order []scanlabels.OrderOption + inters []Interceptor + predicates []predicate.ScanLabels + withScan *ScansQuery + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the ScanLabelsQuery builder. +func (slq *ScanLabelsQuery) Where(ps ...predicate.ScanLabels) *ScanLabelsQuery { + slq.predicates = append(slq.predicates, ps...) + return slq +} + +// Limit the number of records to be returned by this query. +func (slq *ScanLabelsQuery) Limit(limit int) *ScanLabelsQuery { + slq.ctx.Limit = &limit + return slq +} + +// Offset to start from. +func (slq *ScanLabelsQuery) Offset(offset int) *ScanLabelsQuery { + slq.ctx.Offset = &offset + return slq +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (slq *ScanLabelsQuery) Unique(unique bool) *ScanLabelsQuery { + slq.ctx.Unique = &unique + return slq +} + +// Order specifies how the records should be ordered. +func (slq *ScanLabelsQuery) Order(o ...scanlabels.OrderOption) *ScanLabelsQuery { + slq.order = append(slq.order, o...) + return slq +} + +// QueryScan chains the current query on the "scan" edge. +func (slq *ScanLabelsQuery) QueryScan() *ScansQuery { + query := (&ScansClient{config: slq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := slq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := slq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(scanlabels.Table, scanlabels.FieldID, selector), + sqlgraph.To(scans.Table, scans.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, scanlabels.ScanTable, scanlabels.ScanColumn), + ) + fromU = sqlgraph.SetNeighbors(slq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first ScanLabels entity from the query. +// Returns a *NotFoundError when no ScanLabels was found. +func (slq *ScanLabelsQuery) First(ctx context.Context) (*ScanLabels, error) { + nodes, err := slq.Limit(1).All(setContextOp(ctx, slq.ctx, ent.OpQueryFirst)) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{scanlabels.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (slq *ScanLabelsQuery) FirstX(ctx context.Context) *ScanLabels { + node, err := slq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first ScanLabels ID from the query. +// Returns a *NotFoundError when no ScanLabels ID was found. +func (slq *ScanLabelsQuery) FirstID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = slq.Limit(1).IDs(setContextOp(ctx, slq.ctx, ent.OpQueryFirstID)); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{scanlabels.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (slq *ScanLabelsQuery) FirstIDX(ctx context.Context) int { + id, err := slq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single ScanLabels entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one ScanLabels entity is found. +// Returns a *NotFoundError when no ScanLabels entities are found. +func (slq *ScanLabelsQuery) Only(ctx context.Context) (*ScanLabels, error) { + nodes, err := slq.Limit(2).All(setContextOp(ctx, slq.ctx, ent.OpQueryOnly)) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{scanlabels.Label} + default: + return nil, &NotSingularError{scanlabels.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (slq *ScanLabelsQuery) OnlyX(ctx context.Context) *ScanLabels { + node, err := slq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only ScanLabels ID in the query. +// Returns a *NotSingularError when more than one ScanLabels ID is found. +// Returns a *NotFoundError when no entities are found. +func (slq *ScanLabelsQuery) OnlyID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = slq.Limit(2).IDs(setContextOp(ctx, slq.ctx, ent.OpQueryOnlyID)); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{scanlabels.Label} + default: + err = &NotSingularError{scanlabels.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (slq *ScanLabelsQuery) OnlyIDX(ctx context.Context) int { + id, err := slq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of ScanLabelsSlice. +func (slq *ScanLabelsQuery) All(ctx context.Context) ([]*ScanLabels, error) { + ctx = setContextOp(ctx, slq.ctx, ent.OpQueryAll) + if err := slq.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*ScanLabels, *ScanLabelsQuery]() + return withInterceptors[[]*ScanLabels](ctx, slq, qr, slq.inters) +} + +// AllX is like All, but panics if an error occurs. +func (slq *ScanLabelsQuery) AllX(ctx context.Context) []*ScanLabels { + nodes, err := slq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of ScanLabels IDs. +func (slq *ScanLabelsQuery) IDs(ctx context.Context) (ids []int, err error) { + if slq.ctx.Unique == nil && slq.path != nil { + slq.Unique(true) + } + ctx = setContextOp(ctx, slq.ctx, ent.OpQueryIDs) + if err = slq.Select(scanlabels.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (slq *ScanLabelsQuery) IDsX(ctx context.Context) []int { + ids, err := slq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (slq *ScanLabelsQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, slq.ctx, ent.OpQueryCount) + if err := slq.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, slq, querierCount[*ScanLabelsQuery](), slq.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (slq *ScanLabelsQuery) CountX(ctx context.Context) int { + count, err := slq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (slq *ScanLabelsQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, slq.ctx, ent.OpQueryExist) + switch _, err := slq.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (slq *ScanLabelsQuery) ExistX(ctx context.Context) bool { + exist, err := slq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the ScanLabelsQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (slq *ScanLabelsQuery) Clone() *ScanLabelsQuery { + if slq == nil { + return nil + } + return &ScanLabelsQuery{ + config: slq.config, + ctx: slq.ctx.Clone(), + order: append([]scanlabels.OrderOption{}, slq.order...), + inters: append([]Interceptor{}, slq.inters...), + predicates: append([]predicate.ScanLabels{}, slq.predicates...), + withScan: slq.withScan.Clone(), + // clone intermediate query. + sql: slq.sql.Clone(), + path: slq.path, + } +} + +// WithScan tells the query-builder to eager-load the nodes that are connected to +// the "scan" edge. The optional arguments are used to configure the query builder of the edge. +func (slq *ScanLabelsQuery) WithScan(opts ...func(*ScansQuery)) *ScanLabelsQuery { + query := (&ScansClient{config: slq.config}).Query() + for _, opt := range opts { + opt(query) + } + slq.withScan = query + return slq +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// ScanID uuid.UUID `json:"scan_id,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.ScanLabels.Query(). +// GroupBy(scanlabels.FieldScanID). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (slq *ScanLabelsQuery) GroupBy(field string, fields ...string) *ScanLabelsGroupBy { + slq.ctx.Fields = append([]string{field}, fields...) + grbuild := &ScanLabelsGroupBy{build: slq} + grbuild.flds = &slq.ctx.Fields + grbuild.label = scanlabels.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// ScanID uuid.UUID `json:"scan_id,omitempty"` +// } +// +// client.ScanLabels.Query(). +// Select(scanlabels.FieldScanID). +// Scan(ctx, &v) +func (slq *ScanLabelsQuery) Select(fields ...string) *ScanLabelsSelect { + slq.ctx.Fields = append(slq.ctx.Fields, fields...) + sbuild := &ScanLabelsSelect{ScanLabelsQuery: slq} + sbuild.label = scanlabels.Label + sbuild.flds, sbuild.scan = &slq.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a ScanLabelsSelect configured with the given aggregations. +func (slq *ScanLabelsQuery) Aggregate(fns ...AggregateFunc) *ScanLabelsSelect { + return slq.Select().Aggregate(fns...) +} + +func (slq *ScanLabelsQuery) prepareQuery(ctx context.Context) error { + for _, inter := range slq.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, slq); err != nil { + return err + } + } + } + for _, f := range slq.ctx.Fields { + if !scanlabels.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if slq.path != nil { + prev, err := slq.path(ctx) + if err != nil { + return err + } + slq.sql = prev + } + return nil +} + +func (slq *ScanLabelsQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*ScanLabels, error) { + var ( + nodes = []*ScanLabels{} + _spec = slq.querySpec() + loadedTypes = [1]bool{ + slq.withScan != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*ScanLabels).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &ScanLabels{config: slq.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, slq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := slq.withScan; query != nil { + if err := slq.loadScan(ctx, query, nodes, nil, + func(n *ScanLabels, e *Scans) { n.Edges.Scan = e }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (slq *ScanLabelsQuery) loadScan(ctx context.Context, query *ScansQuery, nodes []*ScanLabels, init func(*ScanLabels), assign func(*ScanLabels, *Scans)) error { + ids := make([]uuid.UUID, 0, len(nodes)) + nodeids := make(map[uuid.UUID][]*ScanLabels) + for i := range nodes { + fk := nodes[i].ScanID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(scans.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "scan_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} + +func (slq *ScanLabelsQuery) sqlCount(ctx context.Context) (int, error) { + _spec := slq.querySpec() + _spec.Node.Columns = slq.ctx.Fields + if len(slq.ctx.Fields) > 0 { + _spec.Unique = slq.ctx.Unique != nil && *slq.ctx.Unique + } + return sqlgraph.CountNodes(ctx, slq.driver, _spec) +} + +func (slq *ScanLabelsQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(scanlabels.Table, scanlabels.Columns, sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt)) + _spec.From = slq.sql + if unique := slq.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if slq.path != nil { + _spec.Unique = true + } + if fields := slq.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, scanlabels.FieldID) + for i := range fields { + if fields[i] != scanlabels.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + if slq.withScan != nil { + _spec.Node.AddColumnOnce(scanlabels.FieldScanID) + } + } + if ps := slq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := slq.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := slq.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := slq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (slq *ScanLabelsQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(slq.driver.Dialect()) + t1 := builder.Table(scanlabels.Table) + columns := slq.ctx.Fields + if len(columns) == 0 { + columns = scanlabels.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if slq.sql != nil { + selector = slq.sql + selector.Select(selector.Columns(columns...)...) + } + if slq.ctx.Unique != nil && *slq.ctx.Unique { + selector.Distinct() + } + for _, p := range slq.predicates { + p(selector) + } + for _, p := range slq.order { + p(selector) + } + if offset := slq.ctx.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 := slq.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// ScanLabelsGroupBy is the group-by builder for ScanLabels entities. +type ScanLabelsGroupBy struct { + selector + build *ScanLabelsQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (slgb *ScanLabelsGroupBy) Aggregate(fns ...AggregateFunc) *ScanLabelsGroupBy { + slgb.fns = append(slgb.fns, fns...) + return slgb +} + +// Scan applies the selector query and scans the result into the given value. +func (slgb *ScanLabelsGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, slgb.build.ctx, ent.OpQueryGroupBy) + if err := slgb.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ScanLabelsQuery, *ScanLabelsGroupBy](ctx, slgb.build, slgb, slgb.build.inters, v) +} + +func (slgb *ScanLabelsGroupBy) sqlScan(ctx context.Context, root *ScanLabelsQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(slgb.fns)) + for _, fn := range slgb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*slgb.flds)+len(slgb.fns)) + for _, f := range *slgb.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*slgb.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := slgb.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// ScanLabelsSelect is the builder for selecting fields of ScanLabels entities. +type ScanLabelsSelect struct { + *ScanLabelsQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (sls *ScanLabelsSelect) Aggregate(fns ...AggregateFunc) *ScanLabelsSelect { + sls.fns = append(sls.fns, fns...) + return sls +} + +// Scan applies the selector query and scans the result into the given value. +func (sls *ScanLabelsSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, sls.ctx, ent.OpQuerySelect) + if err := sls.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ScanLabelsQuery, *ScanLabelsSelect](ctx, sls.ScanLabelsQuery, sls, sls.inters, v) +} + +func (sls *ScanLabelsSelect) sqlScan(ctx context.Context, root *ScanLabelsQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(sls.fns)) + for _, fn := range sls.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*sls.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := sls.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/ent/scanlabels_update.go b/ent/scanlabels_update.go new file mode 100644 index 0000000..fac53ee --- /dev/null +++ b/ent/scanlabels_update.go @@ -0,0 +1,395 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/predicate" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/shinobistack/gokakashi/ent/scans" +) + +// ScanLabelsUpdate is the builder for updating ScanLabels entities. +type ScanLabelsUpdate struct { + config + hooks []Hook + mutation *ScanLabelsMutation +} + +// Where appends a list predicates to the ScanLabelsUpdate builder. +func (slu *ScanLabelsUpdate) Where(ps ...predicate.ScanLabels) *ScanLabelsUpdate { + slu.mutation.Where(ps...) + return slu +} + +// SetScanID sets the "scan_id" field. +func (slu *ScanLabelsUpdate) SetScanID(u uuid.UUID) *ScanLabelsUpdate { + slu.mutation.SetScanID(u) + return slu +} + +// SetNillableScanID sets the "scan_id" field if the given value is not nil. +func (slu *ScanLabelsUpdate) SetNillableScanID(u *uuid.UUID) *ScanLabelsUpdate { + if u != nil { + slu.SetScanID(*u) + } + return slu +} + +// SetKey sets the "key" field. +func (slu *ScanLabelsUpdate) SetKey(s string) *ScanLabelsUpdate { + slu.mutation.SetKey(s) + return slu +} + +// SetNillableKey sets the "key" field if the given value is not nil. +func (slu *ScanLabelsUpdate) SetNillableKey(s *string) *ScanLabelsUpdate { + if s != nil { + slu.SetKey(*s) + } + return slu +} + +// SetValue sets the "value" field. +func (slu *ScanLabelsUpdate) SetValue(s string) *ScanLabelsUpdate { + slu.mutation.SetValue(s) + return slu +} + +// SetNillableValue sets the "value" field if the given value is not nil. +func (slu *ScanLabelsUpdate) SetNillableValue(s *string) *ScanLabelsUpdate { + if s != nil { + slu.SetValue(*s) + } + return slu +} + +// SetScan sets the "scan" edge to the Scans entity. +func (slu *ScanLabelsUpdate) SetScan(s *Scans) *ScanLabelsUpdate { + return slu.SetScanID(s.ID) +} + +// Mutation returns the ScanLabelsMutation object of the builder. +func (slu *ScanLabelsUpdate) Mutation() *ScanLabelsMutation { + return slu.mutation +} + +// ClearScan clears the "scan" edge to the Scans entity. +func (slu *ScanLabelsUpdate) ClearScan() *ScanLabelsUpdate { + slu.mutation.ClearScan() + return slu +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (slu *ScanLabelsUpdate) Save(ctx context.Context) (int, error) { + return withHooks(ctx, slu.sqlSave, slu.mutation, slu.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (slu *ScanLabelsUpdate) SaveX(ctx context.Context) int { + affected, err := slu.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (slu *ScanLabelsUpdate) Exec(ctx context.Context) error { + _, err := slu.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (slu *ScanLabelsUpdate) ExecX(ctx context.Context) { + if err := slu.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (slu *ScanLabelsUpdate) check() error { + if v, ok := slu.mutation.Key(); ok { + if err := scanlabels.KeyValidator(v); err != nil { + return &ValidationError{Name: "key", err: fmt.Errorf(`ent: validator failed for field "ScanLabels.key": %w`, err)} + } + } + if v, ok := slu.mutation.Value(); ok { + if err := scanlabels.ValueValidator(v); err != nil { + return &ValidationError{Name: "value", err: fmt.Errorf(`ent: validator failed for field "ScanLabels.value": %w`, err)} + } + } + if slu.mutation.ScanCleared() && len(slu.mutation.ScanIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "ScanLabels.scan"`) + } + return nil +} + +func (slu *ScanLabelsUpdate) sqlSave(ctx context.Context) (n int, err error) { + if err := slu.check(); err != nil { + return n, err + } + _spec := sqlgraph.NewUpdateSpec(scanlabels.Table, scanlabels.Columns, sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt)) + if ps := slu.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := slu.mutation.Key(); ok { + _spec.SetField(scanlabels.FieldKey, field.TypeString, value) + } + if value, ok := slu.mutation.Value(); ok { + _spec.SetField(scanlabels.FieldValue, field.TypeString, value) + } + if slu.mutation.ScanCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: scanlabels.ScanTable, + Columns: []string{scanlabels.ScanColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := slu.mutation.ScanIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: scanlabels.ScanTable, + Columns: []string{scanlabels.ScanColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if n, err = sqlgraph.UpdateNodes(ctx, slu.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{scanlabels.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + slu.mutation.done = true + return n, nil +} + +// ScanLabelsUpdateOne is the builder for updating a single ScanLabels entity. +type ScanLabelsUpdateOne struct { + config + fields []string + hooks []Hook + mutation *ScanLabelsMutation +} + +// SetScanID sets the "scan_id" field. +func (sluo *ScanLabelsUpdateOne) SetScanID(u uuid.UUID) *ScanLabelsUpdateOne { + sluo.mutation.SetScanID(u) + return sluo +} + +// SetNillableScanID sets the "scan_id" field if the given value is not nil. +func (sluo *ScanLabelsUpdateOne) SetNillableScanID(u *uuid.UUID) *ScanLabelsUpdateOne { + if u != nil { + sluo.SetScanID(*u) + } + return sluo +} + +// SetKey sets the "key" field. +func (sluo *ScanLabelsUpdateOne) SetKey(s string) *ScanLabelsUpdateOne { + sluo.mutation.SetKey(s) + return sluo +} + +// SetNillableKey sets the "key" field if the given value is not nil. +func (sluo *ScanLabelsUpdateOne) SetNillableKey(s *string) *ScanLabelsUpdateOne { + if s != nil { + sluo.SetKey(*s) + } + return sluo +} + +// SetValue sets the "value" field. +func (sluo *ScanLabelsUpdateOne) SetValue(s string) *ScanLabelsUpdateOne { + sluo.mutation.SetValue(s) + return sluo +} + +// SetNillableValue sets the "value" field if the given value is not nil. +func (sluo *ScanLabelsUpdateOne) SetNillableValue(s *string) *ScanLabelsUpdateOne { + if s != nil { + sluo.SetValue(*s) + } + return sluo +} + +// SetScan sets the "scan" edge to the Scans entity. +func (sluo *ScanLabelsUpdateOne) SetScan(s *Scans) *ScanLabelsUpdateOne { + return sluo.SetScanID(s.ID) +} + +// Mutation returns the ScanLabelsMutation object of the builder. +func (sluo *ScanLabelsUpdateOne) Mutation() *ScanLabelsMutation { + return sluo.mutation +} + +// ClearScan clears the "scan" edge to the Scans entity. +func (sluo *ScanLabelsUpdateOne) ClearScan() *ScanLabelsUpdateOne { + sluo.mutation.ClearScan() + return sluo +} + +// Where appends a list predicates to the ScanLabelsUpdate builder. +func (sluo *ScanLabelsUpdateOne) Where(ps ...predicate.ScanLabels) *ScanLabelsUpdateOne { + sluo.mutation.Where(ps...) + return sluo +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (sluo *ScanLabelsUpdateOne) Select(field string, fields ...string) *ScanLabelsUpdateOne { + sluo.fields = append([]string{field}, fields...) + return sluo +} + +// Save executes the query and returns the updated ScanLabels entity. +func (sluo *ScanLabelsUpdateOne) Save(ctx context.Context) (*ScanLabels, error) { + return withHooks(ctx, sluo.sqlSave, sluo.mutation, sluo.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (sluo *ScanLabelsUpdateOne) SaveX(ctx context.Context) *ScanLabels { + node, err := sluo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (sluo *ScanLabelsUpdateOne) Exec(ctx context.Context) error { + _, err := sluo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (sluo *ScanLabelsUpdateOne) ExecX(ctx context.Context) { + if err := sluo.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (sluo *ScanLabelsUpdateOne) check() error { + if v, ok := sluo.mutation.Key(); ok { + if err := scanlabels.KeyValidator(v); err != nil { + return &ValidationError{Name: "key", err: fmt.Errorf(`ent: validator failed for field "ScanLabels.key": %w`, err)} + } + } + if v, ok := sluo.mutation.Value(); ok { + if err := scanlabels.ValueValidator(v); err != nil { + return &ValidationError{Name: "value", err: fmt.Errorf(`ent: validator failed for field "ScanLabels.value": %w`, err)} + } + } + if sluo.mutation.ScanCleared() && len(sluo.mutation.ScanIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "ScanLabels.scan"`) + } + return nil +} + +func (sluo *ScanLabelsUpdateOne) sqlSave(ctx context.Context) (_node *ScanLabels, err error) { + if err := sluo.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(scanlabels.Table, scanlabels.Columns, sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt)) + id, ok := sluo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "ScanLabels.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := sluo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, scanlabels.FieldID) + for _, f := range fields { + if !scanlabels.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != scanlabels.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := sluo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := sluo.mutation.Key(); ok { + _spec.SetField(scanlabels.FieldKey, field.TypeString, value) + } + if value, ok := sluo.mutation.Value(); ok { + _spec.SetField(scanlabels.FieldValue, field.TypeString, value) + } + if sluo.mutation.ScanCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: scanlabels.ScanTable, + Columns: []string{scanlabels.ScanColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := sluo.mutation.ScanIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: scanlabels.ScanTable, + Columns: []string{scanlabels.ScanColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &ScanLabels{config: sluo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, sluo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{scanlabels.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + sluo.mutation.done = true + return _node, nil +} diff --git a/ent/scans.go b/ent/scans.go new file mode 100644 index 0000000..c556ca3 --- /dev/null +++ b/ent/scans.go @@ -0,0 +1,200 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "encoding/json" + "fmt" + "strings" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/policies" + "github.com/shinobistack/gokakashi/ent/scans" + "github.com/shinobistack/gokakashi/ent/schema" +) + +// Scans is the model entity for the Scans schema. +type Scans struct { + config `json:"-"` + // ID of the ent. + // Primary key, unique identifier. + ID uuid.UUID `json:"id,omitempty"` + // Foreign key to Policies.ID + PolicyID uuid.UUID `json:"policy_id,omitempty"` + // Enum: { scan_pending, scan_in_progress, check_pending, check_in_progress, success, error }. + Status string `json:"status,omitempty"` + // Details of the image being scanned. + Image string `json:"image,omitempty"` + // Conditions checked during the scan. + Check schema.Check `json:"check,omitempty"` + // Stores the scan results or report. + Report string `json:"report,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the ScansQuery when eager-loading is set. + Edges ScansEdges `json:"edges"` + selectValues sql.SelectValues +} + +// ScansEdges holds the relations/edges for other nodes in the graph. +type ScansEdges struct { + // Policy holds the value of the policy edge. + Policy *Policies `json:"policy,omitempty"` + // ScanLabels holds the value of the scan_labels edge. + ScanLabels []*ScanLabels `json:"scan_labels,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [2]bool +} + +// PolicyOrErr returns the Policy value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e ScansEdges) PolicyOrErr() (*Policies, error) { + if e.Policy != nil { + return e.Policy, nil + } else if e.loadedTypes[0] { + return nil, &NotFoundError{label: policies.Label} + } + return nil, &NotLoadedError{edge: "policy"} +} + +// ScanLabelsOrErr returns the ScanLabels value or an error if the edge +// was not loaded in eager-loading. +func (e ScansEdges) ScanLabelsOrErr() ([]*ScanLabels, error) { + if e.loadedTypes[1] { + return e.ScanLabels, nil + } + return nil, &NotLoadedError{edge: "scan_labels"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*Scans) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case scans.FieldCheck: + values[i] = new([]byte) + case scans.FieldStatus, scans.FieldImage, scans.FieldReport: + values[i] = new(sql.NullString) + case scans.FieldID, scans.FieldPolicyID: + values[i] = new(uuid.UUID) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the Scans fields. +func (s *Scans) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case scans.FieldID: + if value, ok := values[i].(*uuid.UUID); !ok { + return fmt.Errorf("unexpected type %T for field id", values[i]) + } else if value != nil { + s.ID = *value + } + case scans.FieldPolicyID: + if value, ok := values[i].(*uuid.UUID); !ok { + return fmt.Errorf("unexpected type %T for field policy_id", values[i]) + } else if value != nil { + s.PolicyID = *value + } + case scans.FieldStatus: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field status", values[i]) + } else if value.Valid { + s.Status = value.String + } + case scans.FieldImage: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field image", values[i]) + } else if value.Valid { + s.Image = value.String + } + case scans.FieldCheck: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field check", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &s.Check); err != nil { + return fmt.Errorf("unmarshal field check: %w", err) + } + } + case scans.FieldReport: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field report", values[i]) + } else if value.Valid { + s.Report = value.String + } + default: + s.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the Scans. +// This includes values selected through modifiers, order, etc. +func (s *Scans) Value(name string) (ent.Value, error) { + return s.selectValues.Get(name) +} + +// QueryPolicy queries the "policy" edge of the Scans entity. +func (s *Scans) QueryPolicy() *PoliciesQuery { + return NewScansClient(s.config).QueryPolicy(s) +} + +// QueryScanLabels queries the "scan_labels" edge of the Scans entity. +func (s *Scans) QueryScanLabels() *ScanLabelsQuery { + return NewScansClient(s.config).QueryScanLabels(s) +} + +// Update returns a builder for updating this Scans. +// Note that you need to call Scans.Unwrap() before calling this method if this Scans +// was returned from a transaction, and the transaction was committed or rolled back. +func (s *Scans) Update() *ScansUpdateOne { + return NewScansClient(s.config).UpdateOne(s) +} + +// Unwrap unwraps the Scans entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (s *Scans) Unwrap() *Scans { + _tx, ok := s.config.driver.(*txDriver) + if !ok { + panic("ent: Scans is not a transactional entity") + } + s.config.driver = _tx.drv + return s +} + +// String implements the fmt.Stringer. +func (s *Scans) String() string { + var builder strings.Builder + builder.WriteString("Scans(") + builder.WriteString(fmt.Sprintf("id=%v, ", s.ID)) + builder.WriteString("policy_id=") + builder.WriteString(fmt.Sprintf("%v", s.PolicyID)) + builder.WriteString(", ") + builder.WriteString("status=") + builder.WriteString(s.Status) + builder.WriteString(", ") + builder.WriteString("image=") + builder.WriteString(s.Image) + builder.WriteString(", ") + builder.WriteString("check=") + builder.WriteString(fmt.Sprintf("%v", s.Check)) + builder.WriteString(", ") + builder.WriteString("report=") + builder.WriteString(s.Report) + builder.WriteByte(')') + return builder.String() +} + +// ScansSlice is a parsable slice of Scans. +type ScansSlice []*Scans diff --git a/ent/scans/scans.go b/ent/scans/scans.go new file mode 100644 index 0000000..f26a683 --- /dev/null +++ b/ent/scans/scans.go @@ -0,0 +1,136 @@ +// Code generated by ent, DO NOT EDIT. + +package scans + +import ( + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/google/uuid" +) + +const ( + // Label holds the string label denoting the scans type in the database. + Label = "scans" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldPolicyID holds the string denoting the policy_id field in the database. + FieldPolicyID = "policy_id" + // FieldStatus holds the string denoting the status field in the database. + FieldStatus = "status" + // FieldImage holds the string denoting the image field in the database. + FieldImage = "image" + // FieldCheck holds the string denoting the check field in the database. + FieldCheck = "check" + // FieldReport holds the string denoting the report field in the database. + FieldReport = "report" + // EdgePolicy holds the string denoting the policy edge name in mutations. + EdgePolicy = "policy" + // EdgeScanLabels holds the string denoting the scan_labels edge name in mutations. + EdgeScanLabels = "scan_labels" + // Table holds the table name of the scans in the database. + Table = "scans" + // PolicyTable is the table that holds the policy relation/edge. + PolicyTable = "scans" + // PolicyInverseTable is the table name for the Policies entity. + // It exists in this package in order to avoid circular dependency with the "policies" package. + PolicyInverseTable = "policies" + // PolicyColumn is the table column denoting the policy relation/edge. + PolicyColumn = "policy_id" + // ScanLabelsTable is the table that holds the scan_labels relation/edge. + ScanLabelsTable = "scan_labels" + // ScanLabelsInverseTable is the table name for the ScanLabels entity. + // It exists in this package in order to avoid circular dependency with the "scanlabels" package. + ScanLabelsInverseTable = "scan_labels" + // ScanLabelsColumn is the table column denoting the scan_labels relation/edge. + ScanLabelsColumn = "scan_id" +) + +// Columns holds all SQL columns for scans fields. +var Columns = []string{ + FieldID, + FieldPolicyID, + FieldStatus, + FieldImage, + FieldCheck, + FieldReport, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // DefaultStatus holds the default value on creation for the "status" field. + DefaultStatus string + // DefaultID holds the default value on creation for the "id" field. + DefaultID func() uuid.UUID +) + +// OrderOption defines the ordering options for the Scans queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByPolicyID orders the results by the policy_id field. +func ByPolicyID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldPolicyID, opts...).ToFunc() +} + +// ByStatus orders the results by the status field. +func ByStatus(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldStatus, opts...).ToFunc() +} + +// ByImage orders the results by the image field. +func ByImage(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldImage, opts...).ToFunc() +} + +// ByReport orders the results by the report field. +func ByReport(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldReport, opts...).ToFunc() +} + +// ByPolicyField orders the results by policy field. +func ByPolicyField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newPolicyStep(), sql.OrderByField(field, opts...)) + } +} + +// ByScanLabelsCount orders the results by scan_labels count. +func ByScanLabelsCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newScanLabelsStep(), opts...) + } +} + +// ByScanLabels orders the results by scan_labels terms. +func ByScanLabels(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newScanLabelsStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} +func newPolicyStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(PolicyInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, PolicyTable, PolicyColumn), + ) +} +func newScanLabelsStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(ScanLabelsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, ScanLabelsTable, ScanLabelsColumn), + ) +} diff --git a/ent/scans/where.go b/ent/scans/where.go new file mode 100644 index 0000000..2e052e6 --- /dev/null +++ b/ent/scans/where.go @@ -0,0 +1,371 @@ +// Code generated by ent, DO NOT EDIT. + +package scans + +import ( + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldLTE(FieldID, id)) +} + +// PolicyID applies equality check predicate on the "policy_id" field. It's identical to PolicyIDEQ. +func PolicyID(v uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldEQ(FieldPolicyID, v)) +} + +// Status applies equality check predicate on the "status" field. It's identical to StatusEQ. +func Status(v string) predicate.Scans { + return predicate.Scans(sql.FieldEQ(FieldStatus, v)) +} + +// Image applies equality check predicate on the "image" field. It's identical to ImageEQ. +func Image(v string) predicate.Scans { + return predicate.Scans(sql.FieldEQ(FieldImage, v)) +} + +// Report applies equality check predicate on the "report" field. It's identical to ReportEQ. +func Report(v string) predicate.Scans { + return predicate.Scans(sql.FieldEQ(FieldReport, v)) +} + +// PolicyIDEQ applies the EQ predicate on the "policy_id" field. +func PolicyIDEQ(v uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldEQ(FieldPolicyID, v)) +} + +// PolicyIDNEQ applies the NEQ predicate on the "policy_id" field. +func PolicyIDNEQ(v uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldNEQ(FieldPolicyID, v)) +} + +// PolicyIDIn applies the In predicate on the "policy_id" field. +func PolicyIDIn(vs ...uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldIn(FieldPolicyID, vs...)) +} + +// PolicyIDNotIn applies the NotIn predicate on the "policy_id" field. +func PolicyIDNotIn(vs ...uuid.UUID) predicate.Scans { + return predicate.Scans(sql.FieldNotIn(FieldPolicyID, vs...)) +} + +// StatusEQ applies the EQ predicate on the "status" field. +func StatusEQ(v string) predicate.Scans { + return predicate.Scans(sql.FieldEQ(FieldStatus, v)) +} + +// StatusNEQ applies the NEQ predicate on the "status" field. +func StatusNEQ(v string) predicate.Scans { + return predicate.Scans(sql.FieldNEQ(FieldStatus, v)) +} + +// StatusIn applies the In predicate on the "status" field. +func StatusIn(vs ...string) predicate.Scans { + return predicate.Scans(sql.FieldIn(FieldStatus, vs...)) +} + +// StatusNotIn applies the NotIn predicate on the "status" field. +func StatusNotIn(vs ...string) predicate.Scans { + return predicate.Scans(sql.FieldNotIn(FieldStatus, vs...)) +} + +// StatusGT applies the GT predicate on the "status" field. +func StatusGT(v string) predicate.Scans { + return predicate.Scans(sql.FieldGT(FieldStatus, v)) +} + +// StatusGTE applies the GTE predicate on the "status" field. +func StatusGTE(v string) predicate.Scans { + return predicate.Scans(sql.FieldGTE(FieldStatus, v)) +} + +// StatusLT applies the LT predicate on the "status" field. +func StatusLT(v string) predicate.Scans { + return predicate.Scans(sql.FieldLT(FieldStatus, v)) +} + +// StatusLTE applies the LTE predicate on the "status" field. +func StatusLTE(v string) predicate.Scans { + return predicate.Scans(sql.FieldLTE(FieldStatus, v)) +} + +// StatusContains applies the Contains predicate on the "status" field. +func StatusContains(v string) predicate.Scans { + return predicate.Scans(sql.FieldContains(FieldStatus, v)) +} + +// StatusHasPrefix applies the HasPrefix predicate on the "status" field. +func StatusHasPrefix(v string) predicate.Scans { + return predicate.Scans(sql.FieldHasPrefix(FieldStatus, v)) +} + +// StatusHasSuffix applies the HasSuffix predicate on the "status" field. +func StatusHasSuffix(v string) predicate.Scans { + return predicate.Scans(sql.FieldHasSuffix(FieldStatus, v)) +} + +// StatusEqualFold applies the EqualFold predicate on the "status" field. +func StatusEqualFold(v string) predicate.Scans { + return predicate.Scans(sql.FieldEqualFold(FieldStatus, v)) +} + +// StatusContainsFold applies the ContainsFold predicate on the "status" field. +func StatusContainsFold(v string) predicate.Scans { + return predicate.Scans(sql.FieldContainsFold(FieldStatus, v)) +} + +// ImageEQ applies the EQ predicate on the "image" field. +func ImageEQ(v string) predicate.Scans { + return predicate.Scans(sql.FieldEQ(FieldImage, v)) +} + +// ImageNEQ applies the NEQ predicate on the "image" field. +func ImageNEQ(v string) predicate.Scans { + return predicate.Scans(sql.FieldNEQ(FieldImage, v)) +} + +// ImageIn applies the In predicate on the "image" field. +func ImageIn(vs ...string) predicate.Scans { + return predicate.Scans(sql.FieldIn(FieldImage, vs...)) +} + +// ImageNotIn applies the NotIn predicate on the "image" field. +func ImageNotIn(vs ...string) predicate.Scans { + return predicate.Scans(sql.FieldNotIn(FieldImage, vs...)) +} + +// ImageGT applies the GT predicate on the "image" field. +func ImageGT(v string) predicate.Scans { + return predicate.Scans(sql.FieldGT(FieldImage, v)) +} + +// ImageGTE applies the GTE predicate on the "image" field. +func ImageGTE(v string) predicate.Scans { + return predicate.Scans(sql.FieldGTE(FieldImage, v)) +} + +// ImageLT applies the LT predicate on the "image" field. +func ImageLT(v string) predicate.Scans { + return predicate.Scans(sql.FieldLT(FieldImage, v)) +} + +// ImageLTE applies the LTE predicate on the "image" field. +func ImageLTE(v string) predicate.Scans { + return predicate.Scans(sql.FieldLTE(FieldImage, v)) +} + +// ImageContains applies the Contains predicate on the "image" field. +func ImageContains(v string) predicate.Scans { + return predicate.Scans(sql.FieldContains(FieldImage, v)) +} + +// ImageHasPrefix applies the HasPrefix predicate on the "image" field. +func ImageHasPrefix(v string) predicate.Scans { + return predicate.Scans(sql.FieldHasPrefix(FieldImage, v)) +} + +// ImageHasSuffix applies the HasSuffix predicate on the "image" field. +func ImageHasSuffix(v string) predicate.Scans { + return predicate.Scans(sql.FieldHasSuffix(FieldImage, v)) +} + +// ImageEqualFold applies the EqualFold predicate on the "image" field. +func ImageEqualFold(v string) predicate.Scans { + return predicate.Scans(sql.FieldEqualFold(FieldImage, v)) +} + +// ImageContainsFold applies the ContainsFold predicate on the "image" field. +func ImageContainsFold(v string) predicate.Scans { + return predicate.Scans(sql.FieldContainsFold(FieldImage, v)) +} + +// CheckIsNil applies the IsNil predicate on the "check" field. +func CheckIsNil() predicate.Scans { + return predicate.Scans(sql.FieldIsNull(FieldCheck)) +} + +// CheckNotNil applies the NotNil predicate on the "check" field. +func CheckNotNil() predicate.Scans { + return predicate.Scans(sql.FieldNotNull(FieldCheck)) +} + +// ReportEQ applies the EQ predicate on the "report" field. +func ReportEQ(v string) predicate.Scans { + return predicate.Scans(sql.FieldEQ(FieldReport, v)) +} + +// ReportNEQ applies the NEQ predicate on the "report" field. +func ReportNEQ(v string) predicate.Scans { + return predicate.Scans(sql.FieldNEQ(FieldReport, v)) +} + +// ReportIn applies the In predicate on the "report" field. +func ReportIn(vs ...string) predicate.Scans { + return predicate.Scans(sql.FieldIn(FieldReport, vs...)) +} + +// ReportNotIn applies the NotIn predicate on the "report" field. +func ReportNotIn(vs ...string) predicate.Scans { + return predicate.Scans(sql.FieldNotIn(FieldReport, vs...)) +} + +// ReportGT applies the GT predicate on the "report" field. +func ReportGT(v string) predicate.Scans { + return predicate.Scans(sql.FieldGT(FieldReport, v)) +} + +// ReportGTE applies the GTE predicate on the "report" field. +func ReportGTE(v string) predicate.Scans { + return predicate.Scans(sql.FieldGTE(FieldReport, v)) +} + +// ReportLT applies the LT predicate on the "report" field. +func ReportLT(v string) predicate.Scans { + return predicate.Scans(sql.FieldLT(FieldReport, v)) +} + +// ReportLTE applies the LTE predicate on the "report" field. +func ReportLTE(v string) predicate.Scans { + return predicate.Scans(sql.FieldLTE(FieldReport, v)) +} + +// ReportContains applies the Contains predicate on the "report" field. +func ReportContains(v string) predicate.Scans { + return predicate.Scans(sql.FieldContains(FieldReport, v)) +} + +// ReportHasPrefix applies the HasPrefix predicate on the "report" field. +func ReportHasPrefix(v string) predicate.Scans { + return predicate.Scans(sql.FieldHasPrefix(FieldReport, v)) +} + +// ReportHasSuffix applies the HasSuffix predicate on the "report" field. +func ReportHasSuffix(v string) predicate.Scans { + return predicate.Scans(sql.FieldHasSuffix(FieldReport, v)) +} + +// ReportIsNil applies the IsNil predicate on the "report" field. +func ReportIsNil() predicate.Scans { + return predicate.Scans(sql.FieldIsNull(FieldReport)) +} + +// ReportNotNil applies the NotNil predicate on the "report" field. +func ReportNotNil() predicate.Scans { + return predicate.Scans(sql.FieldNotNull(FieldReport)) +} + +// ReportEqualFold applies the EqualFold predicate on the "report" field. +func ReportEqualFold(v string) predicate.Scans { + return predicate.Scans(sql.FieldEqualFold(FieldReport, v)) +} + +// ReportContainsFold applies the ContainsFold predicate on the "report" field. +func ReportContainsFold(v string) predicate.Scans { + return predicate.Scans(sql.FieldContainsFold(FieldReport, v)) +} + +// HasPolicy applies the HasEdge predicate on the "policy" edge. +func HasPolicy() predicate.Scans { + return predicate.Scans(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, PolicyTable, PolicyColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasPolicyWith applies the HasEdge predicate on the "policy" edge with a given conditions (other predicates). +func HasPolicyWith(preds ...predicate.Policies) predicate.Scans { + return predicate.Scans(func(s *sql.Selector) { + step := newPolicyStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// HasScanLabels applies the HasEdge predicate on the "scan_labels" edge. +func HasScanLabels() predicate.Scans { + return predicate.Scans(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, ScanLabelsTable, ScanLabelsColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasScanLabelsWith applies the HasEdge predicate on the "scan_labels" edge with a given conditions (other predicates). +func HasScanLabelsWith(preds ...predicate.ScanLabels) predicate.Scans { + return predicate.Scans(func(s *sql.Selector) { + step := newScanLabelsStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.Scans) predicate.Scans { + return predicate.Scans(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.Scans) predicate.Scans { + return predicate.Scans(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.Scans) predicate.Scans { + return predicate.Scans(sql.NotPredicates(p)) +} diff --git a/ent/scans_create.go b/ent/scans_create.go new file mode 100644 index 0000000..77d2a52 --- /dev/null +++ b/ent/scans_create.go @@ -0,0 +1,342 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/policies" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/shinobistack/gokakashi/ent/scans" + "github.com/shinobistack/gokakashi/ent/schema" +) + +// ScansCreate is the builder for creating a Scans entity. +type ScansCreate struct { + config + mutation *ScansMutation + hooks []Hook +} + +// SetPolicyID sets the "policy_id" field. +func (sc *ScansCreate) SetPolicyID(u uuid.UUID) *ScansCreate { + sc.mutation.SetPolicyID(u) + return sc +} + +// SetStatus sets the "status" field. +func (sc *ScansCreate) SetStatus(s string) *ScansCreate { + sc.mutation.SetStatus(s) + return sc +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (sc *ScansCreate) SetNillableStatus(s *string) *ScansCreate { + if s != nil { + sc.SetStatus(*s) + } + return sc +} + +// SetImage sets the "image" field. +func (sc *ScansCreate) SetImage(s string) *ScansCreate { + sc.mutation.SetImage(s) + return sc +} + +// SetCheck sets the "check" field. +func (sc *ScansCreate) SetCheck(s schema.Check) *ScansCreate { + sc.mutation.SetCheck(s) + return sc +} + +// SetNillableCheck sets the "check" field if the given value is not nil. +func (sc *ScansCreate) SetNillableCheck(s *schema.Check) *ScansCreate { + if s != nil { + sc.SetCheck(*s) + } + return sc +} + +// SetReport sets the "report" field. +func (sc *ScansCreate) SetReport(s string) *ScansCreate { + sc.mutation.SetReport(s) + return sc +} + +// SetNillableReport sets the "report" field if the given value is not nil. +func (sc *ScansCreate) SetNillableReport(s *string) *ScansCreate { + if s != nil { + sc.SetReport(*s) + } + return sc +} + +// SetID sets the "id" field. +func (sc *ScansCreate) SetID(u uuid.UUID) *ScansCreate { + sc.mutation.SetID(u) + return sc +} + +// SetNillableID sets the "id" field if the given value is not nil. +func (sc *ScansCreate) SetNillableID(u *uuid.UUID) *ScansCreate { + if u != nil { + sc.SetID(*u) + } + return sc +} + +// SetPolicy sets the "policy" edge to the Policies entity. +func (sc *ScansCreate) SetPolicy(p *Policies) *ScansCreate { + return sc.SetPolicyID(p.ID) +} + +// AddScanLabelIDs adds the "scan_labels" edge to the ScanLabels entity by IDs. +func (sc *ScansCreate) AddScanLabelIDs(ids ...int) *ScansCreate { + sc.mutation.AddScanLabelIDs(ids...) + return sc +} + +// AddScanLabels adds the "scan_labels" edges to the ScanLabels entity. +func (sc *ScansCreate) AddScanLabels(s ...*ScanLabels) *ScansCreate { + ids := make([]int, len(s)) + for i := range s { + ids[i] = s[i].ID + } + return sc.AddScanLabelIDs(ids...) +} + +// Mutation returns the ScansMutation object of the builder. +func (sc *ScansCreate) Mutation() *ScansMutation { + return sc.mutation +} + +// Save creates the Scans in the database. +func (sc *ScansCreate) Save(ctx context.Context) (*Scans, error) { + sc.defaults() + return withHooks(ctx, sc.sqlSave, sc.mutation, sc.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (sc *ScansCreate) SaveX(ctx context.Context) *Scans { + v, err := sc.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (sc *ScansCreate) Exec(ctx context.Context) error { + _, err := sc.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (sc *ScansCreate) ExecX(ctx context.Context) { + if err := sc.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (sc *ScansCreate) defaults() { + if _, ok := sc.mutation.Status(); !ok { + v := scans.DefaultStatus + sc.mutation.SetStatus(v) + } + if _, ok := sc.mutation.ID(); !ok { + v := scans.DefaultID() + sc.mutation.SetID(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (sc *ScansCreate) check() error { + if _, ok := sc.mutation.PolicyID(); !ok { + return &ValidationError{Name: "policy_id", err: errors.New(`ent: missing required field "Scans.policy_id"`)} + } + if _, ok := sc.mutation.Status(); !ok { + return &ValidationError{Name: "status", err: errors.New(`ent: missing required field "Scans.status"`)} + } + if _, ok := sc.mutation.Image(); !ok { + return &ValidationError{Name: "image", err: errors.New(`ent: missing required field "Scans.image"`)} + } + if len(sc.mutation.PolicyIDs()) == 0 { + return &ValidationError{Name: "policy", err: errors.New(`ent: missing required edge "Scans.policy"`)} + } + return nil +} + +func (sc *ScansCreate) sqlSave(ctx context.Context) (*Scans, error) { + if err := sc.check(); err != nil { + return nil, err + } + _node, _spec := sc.createSpec() + if err := sqlgraph.CreateNode(ctx, sc.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + if _spec.ID.Value != nil { + if id, ok := _spec.ID.Value.(*uuid.UUID); ok { + _node.ID = *id + } else if err := _node.ID.Scan(_spec.ID.Value); err != nil { + return nil, err + } + } + sc.mutation.id = &_node.ID + sc.mutation.done = true + return _node, nil +} + +func (sc *ScansCreate) createSpec() (*Scans, *sqlgraph.CreateSpec) { + var ( + _node = &Scans{config: sc.config} + _spec = sqlgraph.NewCreateSpec(scans.Table, sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID)) + ) + if id, ok := sc.mutation.ID(); ok { + _node.ID = id + _spec.ID.Value = &id + } + if value, ok := sc.mutation.Status(); ok { + _spec.SetField(scans.FieldStatus, field.TypeString, value) + _node.Status = value + } + if value, ok := sc.mutation.Image(); ok { + _spec.SetField(scans.FieldImage, field.TypeString, value) + _node.Image = value + } + if value, ok := sc.mutation.Check(); ok { + _spec.SetField(scans.FieldCheck, field.TypeJSON, value) + _node.Check = value + } + if value, ok := sc.mutation.Report(); ok { + _spec.SetField(scans.FieldReport, field.TypeString, value) + _node.Report = value + } + if nodes := sc.mutation.PolicyIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: scans.PolicyTable, + Columns: []string{scans.PolicyColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(policies.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.PolicyID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + if nodes := sc.mutation.ScanLabelsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: scans.ScanLabelsTable, + Columns: []string{scans.ScanLabelsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// ScansCreateBulk is the builder for creating many Scans entities in bulk. +type ScansCreateBulk struct { + config + err error + builders []*ScansCreate +} + +// Save creates the Scans entities in the database. +func (scb *ScansCreateBulk) Save(ctx context.Context) ([]*Scans, error) { + if scb.err != nil { + return nil, scb.err + } + specs := make([]*sqlgraph.CreateSpec, len(scb.builders)) + nodes := make([]*Scans, len(scb.builders)) + mutators := make([]Mutator, len(scb.builders)) + for i := range scb.builders { + func(i int, root context.Context) { + builder := scb.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*ScansMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, scb.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, scb.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, scb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (scb *ScansCreateBulk) SaveX(ctx context.Context) []*Scans { + v, err := scb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (scb *ScansCreateBulk) Exec(ctx context.Context) error { + _, err := scb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (scb *ScansCreateBulk) ExecX(ctx context.Context) { + if err := scb.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/scans_delete.go b/ent/scans_delete.go new file mode 100644 index 0000000..696aef8 --- /dev/null +++ b/ent/scans_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/shinobistack/gokakashi/ent/predicate" + "github.com/shinobistack/gokakashi/ent/scans" +) + +// ScansDelete is the builder for deleting a Scans entity. +type ScansDelete struct { + config + hooks []Hook + mutation *ScansMutation +} + +// Where appends a list predicates to the ScansDelete builder. +func (sd *ScansDelete) Where(ps ...predicate.Scans) *ScansDelete { + sd.mutation.Where(ps...) + return sd +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (sd *ScansDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, sd.sqlExec, sd.mutation, sd.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (sd *ScansDelete) ExecX(ctx context.Context) int { + n, err := sd.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (sd *ScansDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(scans.Table, sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID)) + if ps := sd.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, sd.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + sd.mutation.done = true + return affected, err +} + +// ScansDeleteOne is the builder for deleting a single Scans entity. +type ScansDeleteOne struct { + sd *ScansDelete +} + +// Where appends a list predicates to the ScansDelete builder. +func (sdo *ScansDeleteOne) Where(ps ...predicate.Scans) *ScansDeleteOne { + sdo.sd.mutation.Where(ps...) + return sdo +} + +// Exec executes the deletion query. +func (sdo *ScansDeleteOne) Exec(ctx context.Context) error { + n, err := sdo.sd.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{scans.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (sdo *ScansDeleteOne) ExecX(ctx context.Context) { + if err := sdo.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/scans_query.go b/ent/scans_query.go new file mode 100644 index 0000000..178df8d --- /dev/null +++ b/ent/scans_query.go @@ -0,0 +1,682 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "database/sql/driver" + "fmt" + "math" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/policies" + "github.com/shinobistack/gokakashi/ent/predicate" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/shinobistack/gokakashi/ent/scans" +) + +// ScansQuery is the builder for querying Scans entities. +type ScansQuery struct { + config + ctx *QueryContext + order []scans.OrderOption + inters []Interceptor + predicates []predicate.Scans + withPolicy *PoliciesQuery + withScanLabels *ScanLabelsQuery + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the ScansQuery builder. +func (sq *ScansQuery) Where(ps ...predicate.Scans) *ScansQuery { + sq.predicates = append(sq.predicates, ps...) + return sq +} + +// Limit the number of records to be returned by this query. +func (sq *ScansQuery) Limit(limit int) *ScansQuery { + sq.ctx.Limit = &limit + return sq +} + +// Offset to start from. +func (sq *ScansQuery) Offset(offset int) *ScansQuery { + sq.ctx.Offset = &offset + return sq +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (sq *ScansQuery) Unique(unique bool) *ScansQuery { + sq.ctx.Unique = &unique + return sq +} + +// Order specifies how the records should be ordered. +func (sq *ScansQuery) Order(o ...scans.OrderOption) *ScansQuery { + sq.order = append(sq.order, o...) + return sq +} + +// QueryPolicy chains the current query on the "policy" edge. +func (sq *ScansQuery) QueryPolicy() *PoliciesQuery { + query := (&PoliciesClient{config: sq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := sq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := sq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(scans.Table, scans.FieldID, selector), + sqlgraph.To(policies.Table, policies.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, scans.PolicyTable, scans.PolicyColumn), + ) + fromU = sqlgraph.SetNeighbors(sq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// QueryScanLabels chains the current query on the "scan_labels" edge. +func (sq *ScansQuery) QueryScanLabels() *ScanLabelsQuery { + query := (&ScanLabelsClient{config: sq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := sq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := sq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(scans.Table, scans.FieldID, selector), + sqlgraph.To(scanlabels.Table, scanlabels.FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, scans.ScanLabelsTable, scans.ScanLabelsColumn), + ) + fromU = sqlgraph.SetNeighbors(sq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first Scans entity from the query. +// Returns a *NotFoundError when no Scans was found. +func (sq *ScansQuery) First(ctx context.Context) (*Scans, error) { + nodes, err := sq.Limit(1).All(setContextOp(ctx, sq.ctx, ent.OpQueryFirst)) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{scans.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (sq *ScansQuery) FirstX(ctx context.Context) *Scans { + node, err := sq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first Scans ID from the query. +// Returns a *NotFoundError when no Scans ID was found. +func (sq *ScansQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) { + var ids []uuid.UUID + if ids, err = sq.Limit(1).IDs(setContextOp(ctx, sq.ctx, ent.OpQueryFirstID)); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{scans.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (sq *ScansQuery) FirstIDX(ctx context.Context) uuid.UUID { + id, err := sq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single Scans entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one Scans entity is found. +// Returns a *NotFoundError when no Scans entities are found. +func (sq *ScansQuery) Only(ctx context.Context) (*Scans, error) { + nodes, err := sq.Limit(2).All(setContextOp(ctx, sq.ctx, ent.OpQueryOnly)) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{scans.Label} + default: + return nil, &NotSingularError{scans.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (sq *ScansQuery) OnlyX(ctx context.Context) *Scans { + node, err := sq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only Scans ID in the query. +// Returns a *NotSingularError when more than one Scans ID is found. +// Returns a *NotFoundError when no entities are found. +func (sq *ScansQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) { + var ids []uuid.UUID + if ids, err = sq.Limit(2).IDs(setContextOp(ctx, sq.ctx, ent.OpQueryOnlyID)); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{scans.Label} + default: + err = &NotSingularError{scans.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (sq *ScansQuery) OnlyIDX(ctx context.Context) uuid.UUID { + id, err := sq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of ScansSlice. +func (sq *ScansQuery) All(ctx context.Context) ([]*Scans, error) { + ctx = setContextOp(ctx, sq.ctx, ent.OpQueryAll) + if err := sq.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*Scans, *ScansQuery]() + return withInterceptors[[]*Scans](ctx, sq, qr, sq.inters) +} + +// AllX is like All, but panics if an error occurs. +func (sq *ScansQuery) AllX(ctx context.Context) []*Scans { + nodes, err := sq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of Scans IDs. +func (sq *ScansQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) { + if sq.ctx.Unique == nil && sq.path != nil { + sq.Unique(true) + } + ctx = setContextOp(ctx, sq.ctx, ent.OpQueryIDs) + if err = sq.Select(scans.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (sq *ScansQuery) IDsX(ctx context.Context) []uuid.UUID { + ids, err := sq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (sq *ScansQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, sq.ctx, ent.OpQueryCount) + if err := sq.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, sq, querierCount[*ScansQuery](), sq.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (sq *ScansQuery) CountX(ctx context.Context) int { + count, err := sq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (sq *ScansQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, sq.ctx, ent.OpQueryExist) + switch _, err := sq.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (sq *ScansQuery) ExistX(ctx context.Context) bool { + exist, err := sq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the ScansQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (sq *ScansQuery) Clone() *ScansQuery { + if sq == nil { + return nil + } + return &ScansQuery{ + config: sq.config, + ctx: sq.ctx.Clone(), + order: append([]scans.OrderOption{}, sq.order...), + inters: append([]Interceptor{}, sq.inters...), + predicates: append([]predicate.Scans{}, sq.predicates...), + withPolicy: sq.withPolicy.Clone(), + withScanLabels: sq.withScanLabels.Clone(), + // clone intermediate query. + sql: sq.sql.Clone(), + path: sq.path, + } +} + +// WithPolicy tells the query-builder to eager-load the nodes that are connected to +// the "policy" edge. The optional arguments are used to configure the query builder of the edge. +func (sq *ScansQuery) WithPolicy(opts ...func(*PoliciesQuery)) *ScansQuery { + query := (&PoliciesClient{config: sq.config}).Query() + for _, opt := range opts { + opt(query) + } + sq.withPolicy = query + return sq +} + +// WithScanLabels tells the query-builder to eager-load the nodes that are connected to +// the "scan_labels" edge. The optional arguments are used to configure the query builder of the edge. +func (sq *ScansQuery) WithScanLabels(opts ...func(*ScanLabelsQuery)) *ScansQuery { + query := (&ScanLabelsClient{config: sq.config}).Query() + for _, opt := range opts { + opt(query) + } + sq.withScanLabels = query + return sq +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// PolicyID uuid.UUID `json:"policy_id,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.Scans.Query(). +// GroupBy(scans.FieldPolicyID). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (sq *ScansQuery) GroupBy(field string, fields ...string) *ScansGroupBy { + sq.ctx.Fields = append([]string{field}, fields...) + grbuild := &ScansGroupBy{build: sq} + grbuild.flds = &sq.ctx.Fields + grbuild.label = scans.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// PolicyID uuid.UUID `json:"policy_id,omitempty"` +// } +// +// client.Scans.Query(). +// Select(scans.FieldPolicyID). +// Scan(ctx, &v) +func (sq *ScansQuery) Select(fields ...string) *ScansSelect { + sq.ctx.Fields = append(sq.ctx.Fields, fields...) + sbuild := &ScansSelect{ScansQuery: sq} + sbuild.label = scans.Label + sbuild.flds, sbuild.scan = &sq.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a ScansSelect configured with the given aggregations. +func (sq *ScansQuery) Aggregate(fns ...AggregateFunc) *ScansSelect { + return sq.Select().Aggregate(fns...) +} + +func (sq *ScansQuery) prepareQuery(ctx context.Context) error { + for _, inter := range sq.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, sq); err != nil { + return err + } + } + } + for _, f := range sq.ctx.Fields { + if !scans.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if sq.path != nil { + prev, err := sq.path(ctx) + if err != nil { + return err + } + sq.sql = prev + } + return nil +} + +func (sq *ScansQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Scans, error) { + var ( + nodes = []*Scans{} + _spec = sq.querySpec() + loadedTypes = [2]bool{ + sq.withPolicy != nil, + sq.withScanLabels != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*Scans).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &Scans{config: sq.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, sq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := sq.withPolicy; query != nil { + if err := sq.loadPolicy(ctx, query, nodes, nil, + func(n *Scans, e *Policies) { n.Edges.Policy = e }); err != nil { + return nil, err + } + } + if query := sq.withScanLabels; query != nil { + if err := sq.loadScanLabels(ctx, query, nodes, + func(n *Scans) { n.Edges.ScanLabels = []*ScanLabels{} }, + func(n *Scans, e *ScanLabels) { n.Edges.ScanLabels = append(n.Edges.ScanLabels, e) }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (sq *ScansQuery) loadPolicy(ctx context.Context, query *PoliciesQuery, nodes []*Scans, init func(*Scans), assign func(*Scans, *Policies)) error { + ids := make([]uuid.UUID, 0, len(nodes)) + nodeids := make(map[uuid.UUID][]*Scans) + for i := range nodes { + fk := nodes[i].PolicyID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(policies.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "policy_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} +func (sq *ScansQuery) loadScanLabels(ctx context.Context, query *ScanLabelsQuery, nodes []*Scans, init func(*Scans), assign func(*Scans, *ScanLabels)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[uuid.UUID]*Scans) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(scanlabels.FieldScanID) + } + query.Where(predicate.ScanLabels(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(scans.ScanLabelsColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.ScanID + node, ok := nodeids[fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "scan_id" returned %v for node %v`, fk, n.ID) + } + assign(node, n) + } + return nil +} + +func (sq *ScansQuery) sqlCount(ctx context.Context) (int, error) { + _spec := sq.querySpec() + _spec.Node.Columns = sq.ctx.Fields + if len(sq.ctx.Fields) > 0 { + _spec.Unique = sq.ctx.Unique != nil && *sq.ctx.Unique + } + return sqlgraph.CountNodes(ctx, sq.driver, _spec) +} + +func (sq *ScansQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(scans.Table, scans.Columns, sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID)) + _spec.From = sq.sql + if unique := sq.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if sq.path != nil { + _spec.Unique = true + } + if fields := sq.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, scans.FieldID) + for i := range fields { + if fields[i] != scans.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + if sq.withPolicy != nil { + _spec.Node.AddColumnOnce(scans.FieldPolicyID) + } + } + if ps := sq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := sq.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := sq.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := sq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (sq *ScansQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(sq.driver.Dialect()) + t1 := builder.Table(scans.Table) + columns := sq.ctx.Fields + if len(columns) == 0 { + columns = scans.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if sq.sql != nil { + selector = sq.sql + selector.Select(selector.Columns(columns...)...) + } + if sq.ctx.Unique != nil && *sq.ctx.Unique { + selector.Distinct() + } + for _, p := range sq.predicates { + p(selector) + } + for _, p := range sq.order { + p(selector) + } + if offset := sq.ctx.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 := sq.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// ScansGroupBy is the group-by builder for Scans entities. +type ScansGroupBy struct { + selector + build *ScansQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (sgb *ScansGroupBy) Aggregate(fns ...AggregateFunc) *ScansGroupBy { + sgb.fns = append(sgb.fns, fns...) + return sgb +} + +// Scan applies the selector query and scans the result into the given value. +func (sgb *ScansGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, sgb.build.ctx, ent.OpQueryGroupBy) + if err := sgb.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ScansQuery, *ScansGroupBy](ctx, sgb.build, sgb, sgb.build.inters, v) +} + +func (sgb *ScansGroupBy) sqlScan(ctx context.Context, root *ScansQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(sgb.fns)) + for _, fn := range sgb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*sgb.flds)+len(sgb.fns)) + for _, f := range *sgb.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*sgb.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := sgb.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// ScansSelect is the builder for selecting fields of Scans entities. +type ScansSelect struct { + *ScansQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (ss *ScansSelect) Aggregate(fns ...AggregateFunc) *ScansSelect { + ss.fns = append(ss.fns, fns...) + return ss +} + +// Scan applies the selector query and scans the result into the given value. +func (ss *ScansSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, ss.ctx, ent.OpQuerySelect) + if err := ss.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ScansQuery, *ScansSelect](ctx, ss.ScansQuery, ss, ss.inters, v) +} + +func (ss *ScansSelect) sqlScan(ctx context.Context, root *ScansQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(ss.fns)) + for _, fn := range ss.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*ss.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := ss.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/ent/scans_update.go b/ent/scans_update.go new file mode 100644 index 0000000..b03cac1 --- /dev/null +++ b/ent/scans_update.go @@ -0,0 +1,643 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/policies" + "github.com/shinobistack/gokakashi/ent/predicate" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/shinobistack/gokakashi/ent/scans" + "github.com/shinobistack/gokakashi/ent/schema" +) + +// ScansUpdate is the builder for updating Scans entities. +type ScansUpdate struct { + config + hooks []Hook + mutation *ScansMutation +} + +// Where appends a list predicates to the ScansUpdate builder. +func (su *ScansUpdate) Where(ps ...predicate.Scans) *ScansUpdate { + su.mutation.Where(ps...) + return su +} + +// SetPolicyID sets the "policy_id" field. +func (su *ScansUpdate) SetPolicyID(u uuid.UUID) *ScansUpdate { + su.mutation.SetPolicyID(u) + return su +} + +// SetNillablePolicyID sets the "policy_id" field if the given value is not nil. +func (su *ScansUpdate) SetNillablePolicyID(u *uuid.UUID) *ScansUpdate { + if u != nil { + su.SetPolicyID(*u) + } + return su +} + +// SetStatus sets the "status" field. +func (su *ScansUpdate) SetStatus(s string) *ScansUpdate { + su.mutation.SetStatus(s) + return su +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (su *ScansUpdate) SetNillableStatus(s *string) *ScansUpdate { + if s != nil { + su.SetStatus(*s) + } + return su +} + +// SetImage sets the "image" field. +func (su *ScansUpdate) SetImage(s string) *ScansUpdate { + su.mutation.SetImage(s) + return su +} + +// SetNillableImage sets the "image" field if the given value is not nil. +func (su *ScansUpdate) SetNillableImage(s *string) *ScansUpdate { + if s != nil { + su.SetImage(*s) + } + return su +} + +// SetCheck sets the "check" field. +func (su *ScansUpdate) SetCheck(s schema.Check) *ScansUpdate { + su.mutation.SetCheck(s) + return su +} + +// SetNillableCheck sets the "check" field if the given value is not nil. +func (su *ScansUpdate) SetNillableCheck(s *schema.Check) *ScansUpdate { + if s != nil { + su.SetCheck(*s) + } + return su +} + +// ClearCheck clears the value of the "check" field. +func (su *ScansUpdate) ClearCheck() *ScansUpdate { + su.mutation.ClearCheck() + return su +} + +// SetReport sets the "report" field. +func (su *ScansUpdate) SetReport(s string) *ScansUpdate { + su.mutation.SetReport(s) + return su +} + +// SetNillableReport sets the "report" field if the given value is not nil. +func (su *ScansUpdate) SetNillableReport(s *string) *ScansUpdate { + if s != nil { + su.SetReport(*s) + } + return su +} + +// ClearReport clears the value of the "report" field. +func (su *ScansUpdate) ClearReport() *ScansUpdate { + su.mutation.ClearReport() + return su +} + +// SetPolicy sets the "policy" edge to the Policies entity. +func (su *ScansUpdate) SetPolicy(p *Policies) *ScansUpdate { + return su.SetPolicyID(p.ID) +} + +// AddScanLabelIDs adds the "scan_labels" edge to the ScanLabels entity by IDs. +func (su *ScansUpdate) AddScanLabelIDs(ids ...int) *ScansUpdate { + su.mutation.AddScanLabelIDs(ids...) + return su +} + +// AddScanLabels adds the "scan_labels" edges to the ScanLabels entity. +func (su *ScansUpdate) AddScanLabels(s ...*ScanLabels) *ScansUpdate { + ids := make([]int, len(s)) + for i := range s { + ids[i] = s[i].ID + } + return su.AddScanLabelIDs(ids...) +} + +// Mutation returns the ScansMutation object of the builder. +func (su *ScansUpdate) Mutation() *ScansMutation { + return su.mutation +} + +// ClearPolicy clears the "policy" edge to the Policies entity. +func (su *ScansUpdate) ClearPolicy() *ScansUpdate { + su.mutation.ClearPolicy() + return su +} + +// ClearScanLabels clears all "scan_labels" edges to the ScanLabels entity. +func (su *ScansUpdate) ClearScanLabels() *ScansUpdate { + su.mutation.ClearScanLabels() + return su +} + +// RemoveScanLabelIDs removes the "scan_labels" edge to ScanLabels entities by IDs. +func (su *ScansUpdate) RemoveScanLabelIDs(ids ...int) *ScansUpdate { + su.mutation.RemoveScanLabelIDs(ids...) + return su +} + +// RemoveScanLabels removes "scan_labels" edges to ScanLabels entities. +func (su *ScansUpdate) RemoveScanLabels(s ...*ScanLabels) *ScansUpdate { + ids := make([]int, len(s)) + for i := range s { + ids[i] = s[i].ID + } + return su.RemoveScanLabelIDs(ids...) +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (su *ScansUpdate) Save(ctx context.Context) (int, error) { + return withHooks(ctx, su.sqlSave, su.mutation, su.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (su *ScansUpdate) SaveX(ctx context.Context) int { + affected, err := su.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (su *ScansUpdate) Exec(ctx context.Context) error { + _, err := su.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (su *ScansUpdate) ExecX(ctx context.Context) { + if err := su.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (su *ScansUpdate) check() error { + if su.mutation.PolicyCleared() && len(su.mutation.PolicyIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "Scans.policy"`) + } + return nil +} + +func (su *ScansUpdate) sqlSave(ctx context.Context) (n int, err error) { + if err := su.check(); err != nil { + return n, err + } + _spec := sqlgraph.NewUpdateSpec(scans.Table, scans.Columns, sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID)) + if ps := su.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := su.mutation.Status(); ok { + _spec.SetField(scans.FieldStatus, field.TypeString, value) + } + if value, ok := su.mutation.Image(); ok { + _spec.SetField(scans.FieldImage, field.TypeString, value) + } + if value, ok := su.mutation.Check(); ok { + _spec.SetField(scans.FieldCheck, field.TypeJSON, value) + } + if su.mutation.CheckCleared() { + _spec.ClearField(scans.FieldCheck, field.TypeJSON) + } + if value, ok := su.mutation.Report(); ok { + _spec.SetField(scans.FieldReport, field.TypeString, value) + } + if su.mutation.ReportCleared() { + _spec.ClearField(scans.FieldReport, field.TypeString) + } + if su.mutation.PolicyCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: scans.PolicyTable, + Columns: []string{scans.PolicyColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(policies.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := su.mutation.PolicyIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: scans.PolicyTable, + Columns: []string{scans.PolicyColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(policies.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if su.mutation.ScanLabelsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: scans.ScanLabelsTable, + Columns: []string{scans.ScanLabelsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := su.mutation.RemovedScanLabelsIDs(); len(nodes) > 0 && !su.mutation.ScanLabelsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: scans.ScanLabelsTable, + Columns: []string{scans.ScanLabelsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := su.mutation.ScanLabelsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: scans.ScanLabelsTable, + Columns: []string{scans.ScanLabelsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if n, err = sqlgraph.UpdateNodes(ctx, su.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{scans.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + su.mutation.done = true + return n, nil +} + +// ScansUpdateOne is the builder for updating a single Scans entity. +type ScansUpdateOne struct { + config + fields []string + hooks []Hook + mutation *ScansMutation +} + +// SetPolicyID sets the "policy_id" field. +func (suo *ScansUpdateOne) SetPolicyID(u uuid.UUID) *ScansUpdateOne { + suo.mutation.SetPolicyID(u) + return suo +} + +// SetNillablePolicyID sets the "policy_id" field if the given value is not nil. +func (suo *ScansUpdateOne) SetNillablePolicyID(u *uuid.UUID) *ScansUpdateOne { + if u != nil { + suo.SetPolicyID(*u) + } + return suo +} + +// SetStatus sets the "status" field. +func (suo *ScansUpdateOne) SetStatus(s string) *ScansUpdateOne { + suo.mutation.SetStatus(s) + return suo +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (suo *ScansUpdateOne) SetNillableStatus(s *string) *ScansUpdateOne { + if s != nil { + suo.SetStatus(*s) + } + return suo +} + +// SetImage sets the "image" field. +func (suo *ScansUpdateOne) SetImage(s string) *ScansUpdateOne { + suo.mutation.SetImage(s) + return suo +} + +// SetNillableImage sets the "image" field if the given value is not nil. +func (suo *ScansUpdateOne) SetNillableImage(s *string) *ScansUpdateOne { + if s != nil { + suo.SetImage(*s) + } + return suo +} + +// SetCheck sets the "check" field. +func (suo *ScansUpdateOne) SetCheck(s schema.Check) *ScansUpdateOne { + suo.mutation.SetCheck(s) + return suo +} + +// SetNillableCheck sets the "check" field if the given value is not nil. +func (suo *ScansUpdateOne) SetNillableCheck(s *schema.Check) *ScansUpdateOne { + if s != nil { + suo.SetCheck(*s) + } + return suo +} + +// ClearCheck clears the value of the "check" field. +func (suo *ScansUpdateOne) ClearCheck() *ScansUpdateOne { + suo.mutation.ClearCheck() + return suo +} + +// SetReport sets the "report" field. +func (suo *ScansUpdateOne) SetReport(s string) *ScansUpdateOne { + suo.mutation.SetReport(s) + return suo +} + +// SetNillableReport sets the "report" field if the given value is not nil. +func (suo *ScansUpdateOne) SetNillableReport(s *string) *ScansUpdateOne { + if s != nil { + suo.SetReport(*s) + } + return suo +} + +// ClearReport clears the value of the "report" field. +func (suo *ScansUpdateOne) ClearReport() *ScansUpdateOne { + suo.mutation.ClearReport() + return suo +} + +// SetPolicy sets the "policy" edge to the Policies entity. +func (suo *ScansUpdateOne) SetPolicy(p *Policies) *ScansUpdateOne { + return suo.SetPolicyID(p.ID) +} + +// AddScanLabelIDs adds the "scan_labels" edge to the ScanLabels entity by IDs. +func (suo *ScansUpdateOne) AddScanLabelIDs(ids ...int) *ScansUpdateOne { + suo.mutation.AddScanLabelIDs(ids...) + return suo +} + +// AddScanLabels adds the "scan_labels" edges to the ScanLabels entity. +func (suo *ScansUpdateOne) AddScanLabels(s ...*ScanLabels) *ScansUpdateOne { + ids := make([]int, len(s)) + for i := range s { + ids[i] = s[i].ID + } + return suo.AddScanLabelIDs(ids...) +} + +// Mutation returns the ScansMutation object of the builder. +func (suo *ScansUpdateOne) Mutation() *ScansMutation { + return suo.mutation +} + +// ClearPolicy clears the "policy" edge to the Policies entity. +func (suo *ScansUpdateOne) ClearPolicy() *ScansUpdateOne { + suo.mutation.ClearPolicy() + return suo +} + +// ClearScanLabels clears all "scan_labels" edges to the ScanLabels entity. +func (suo *ScansUpdateOne) ClearScanLabels() *ScansUpdateOne { + suo.mutation.ClearScanLabels() + return suo +} + +// RemoveScanLabelIDs removes the "scan_labels" edge to ScanLabels entities by IDs. +func (suo *ScansUpdateOne) RemoveScanLabelIDs(ids ...int) *ScansUpdateOne { + suo.mutation.RemoveScanLabelIDs(ids...) + return suo +} + +// RemoveScanLabels removes "scan_labels" edges to ScanLabels entities. +func (suo *ScansUpdateOne) RemoveScanLabels(s ...*ScanLabels) *ScansUpdateOne { + ids := make([]int, len(s)) + for i := range s { + ids[i] = s[i].ID + } + return suo.RemoveScanLabelIDs(ids...) +} + +// Where appends a list predicates to the ScansUpdate builder. +func (suo *ScansUpdateOne) Where(ps ...predicate.Scans) *ScansUpdateOne { + suo.mutation.Where(ps...) + return suo +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (suo *ScansUpdateOne) Select(field string, fields ...string) *ScansUpdateOne { + suo.fields = append([]string{field}, fields...) + return suo +} + +// Save executes the query and returns the updated Scans entity. +func (suo *ScansUpdateOne) Save(ctx context.Context) (*Scans, error) { + return withHooks(ctx, suo.sqlSave, suo.mutation, suo.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (suo *ScansUpdateOne) SaveX(ctx context.Context) *Scans { + node, err := suo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (suo *ScansUpdateOne) Exec(ctx context.Context) error { + _, err := suo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (suo *ScansUpdateOne) ExecX(ctx context.Context) { + if err := suo.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (suo *ScansUpdateOne) check() error { + if suo.mutation.PolicyCleared() && len(suo.mutation.PolicyIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "Scans.policy"`) + } + return nil +} + +func (suo *ScansUpdateOne) sqlSave(ctx context.Context) (_node *Scans, err error) { + if err := suo.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(scans.Table, scans.Columns, sqlgraph.NewFieldSpec(scans.FieldID, field.TypeUUID)) + id, ok := suo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Scans.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := suo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, scans.FieldID) + for _, f := range fields { + if !scans.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != scans.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := suo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := suo.mutation.Status(); ok { + _spec.SetField(scans.FieldStatus, field.TypeString, value) + } + if value, ok := suo.mutation.Image(); ok { + _spec.SetField(scans.FieldImage, field.TypeString, value) + } + if value, ok := suo.mutation.Check(); ok { + _spec.SetField(scans.FieldCheck, field.TypeJSON, value) + } + if suo.mutation.CheckCleared() { + _spec.ClearField(scans.FieldCheck, field.TypeJSON) + } + if value, ok := suo.mutation.Report(); ok { + _spec.SetField(scans.FieldReport, field.TypeString, value) + } + if suo.mutation.ReportCleared() { + _spec.ClearField(scans.FieldReport, field.TypeString) + } + if suo.mutation.PolicyCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: scans.PolicyTable, + Columns: []string{scans.PolicyColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(policies.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := suo.mutation.PolicyIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: scans.PolicyTable, + Columns: []string{scans.PolicyColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(policies.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if suo.mutation.ScanLabelsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: scans.ScanLabelsTable, + Columns: []string{scans.ScanLabelsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := suo.mutation.RemovedScanLabelsIDs(); len(nodes) > 0 && !suo.mutation.ScanLabelsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: scans.ScanLabelsTable, + Columns: []string{scans.ScanLabelsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := suo.mutation.ScanLabelsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: false, + Table: scans.ScanLabelsTable, + Columns: []string{scans.ScanLabelsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(scanlabels.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &Scans{config: suo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, suo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{scans.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + suo.mutation.done = true + return _node, nil +} diff --git a/ent/schema/policies.go b/ent/schema/policies.go index f0a5c1f..4812501 100644 --- a/ent/schema/policies.go +++ b/ent/schema/policies.go @@ -59,5 +59,7 @@ func (Policies) Edges() []ent.Edge { // a one-to-many relationship with PolicyLabels. return []ent.Edge{ edge.To("policy_labels", PolicyLabels.Type), + // A policy can have multiple scans. + edge.To("scans", Scans.Type), } } diff --git a/ent/schema/scanlabels.go b/ent/schema/scanlabels.go new file mode 100644 index 0000000..615f573 --- /dev/null +++ b/ent/schema/scanlabels.go @@ -0,0 +1,38 @@ +package schema + +import ( + "entgo.io/ent" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "github.com/google/uuid" +) + +// ScanLabels holds the schema definition for the ScanLabels entity. +type ScanLabels struct { + ent.Schema +} + +// Fields of the ScanLabels. +func (ScanLabels) Fields() []ent.Field { + return []ent.Field{ + field.UUID("scan_id", uuid.UUID{}). + Comment("Foreign key to Scans.ID."), + field.String("key"). + NotEmpty(). + Comment("Label key."), + field.String("value"). + NotEmpty(). + Comment("Label value."), + } +} + +// Edges of the ScanLabels. +func (ScanLabels) Edges() []ent.Edge { + return []ent.Edge{ + edge.From("scan", Scans.Type). + Ref("scan_labels"). + Field("scan_id"). + Unique(). + Required(), + } +} diff --git a/ent/schema/scans.go b/ent/schema/scans.go new file mode 100644 index 0000000..96b81df --- /dev/null +++ b/ent/schema/scans.go @@ -0,0 +1,49 @@ +package schema + +import ( + "entgo.io/ent" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "github.com/google/uuid" +) + +// Scans holds the schema definition for the Scans entity. +type Scans struct { + ent.Schema +} + +// Fields of the Scans. +func (Scans) Fields() []ent.Field { + return []ent.Field{ + field.UUID("id", uuid.UUID{}). + Default(uuid.New). + Unique(). + Comment("Primary key, unique identifier."), + field.UUID("policy_id", uuid.UUID{}). + Comment("Foreign key to Policies.ID"), + field.String("status"). + Default("scan_pending"). + Comment("Enum: { scan_pending, scan_in_progress, check_pending, check_in_progress, success, error }."), + field.String("image"). + Comment("Details of the image being scanned."), + field.JSON("check", Check{}). + Optional(). + Comment("Conditions checked during the scan."), + field.String("report"). + Optional(). + Comment("Stores the scan results or report."), + } +} + +// Edges of the Scans. +func (Scans) Edges() []ent.Edge { + return []ent.Edge{ + edge.From("policy", Policies.Type). + Ref("scans"). + Unique(). + Required(). + Field("policy_id"), + // A single scan can have multiple labels. + edge.To("scan_labels", ScanLabels.Type), + } +} diff --git a/ent/tx.go b/ent/tx.go index 24551cd..616aa83 100644 --- a/ent/tx.go +++ b/ent/tx.go @@ -20,6 +20,10 @@ type Tx struct { Policies *PoliciesClient // PolicyLabels is the client for interacting with the PolicyLabels builders. PolicyLabels *PolicyLabelsClient + // ScanLabels is the client for interacting with the ScanLabels builders. + ScanLabels *ScanLabelsClient + // Scans is the client for interacting with the Scans builders. + Scans *ScansClient // lazily loaded. client *Client @@ -155,6 +159,8 @@ func (tx *Tx) init() { tx.Integrations = NewIntegrationsClient(tx.config) tx.Policies = NewPoliciesClient(tx.config) tx.PolicyLabels = NewPolicyLabelsClient(tx.config) + tx.ScanLabels = NewScanLabelsClient(tx.config) + tx.Scans = NewScansClient(tx.config) } // txDriver wraps the given dialect.Tx with a nop dialect.Driver implementation. diff --git a/internal/restapi/v1/policylabels/post.go b/internal/restapi/v1/policylabels/post.go index 4ee5954..f96a7bf 100644 --- a/internal/restapi/v1/policylabels/post.go +++ b/internal/restapi/v1/policylabels/post.go @@ -9,6 +9,7 @@ import ( "github.com/swaggest/usecase/status" ) +// ToDo: To have a requests to create labels in bulk? type CreatePolicyLabelRequest struct { PolicyID uuid.UUID `path:"policy_id"` Key string `json:"key"` @@ -40,7 +41,6 @@ func CreatePolicyLabel(client *ent.Client) func(ctx context.Context, req CreateP return status.Wrap(err, status.Internal) } // Validate of if label exists - // Query the label exists, _ := client.PolicyLabels.Query(). Where(policylabels.PolicyID(req.PolicyID), policylabels.Key(req.Key)). Exist(ctx) diff --git a/internal/restapi/v1/scanlabels/delete.go b/internal/restapi/v1/scanlabels/delete.go new file mode 100644 index 0000000..bf29aaa --- /dev/null +++ b/internal/restapi/v1/scanlabels/delete.go @@ -0,0 +1,51 @@ +package scanlabels + +import ( + "context" + "errors" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/swaggest/usecase/status" +) + +type DeleteScanLabelRequest struct { + ScanID uuid.UUID `path:"scan_id"` + Key string `path:"key"` +} + +type DeleteScanLabelResponse struct { + Status string `json:"status"` +} + +func DeleteScanLabel(client *ent.Client) func(ctx context.Context, req DeleteScanLabelRequest, res *DeleteScanLabelResponse) error { + return func(ctx context.Context, req DeleteScanLabelRequest, res *DeleteScanLabelResponse) error { + if req.ScanID == uuid.Nil { + return status.Wrap(errors.New("invalid UUID: cannot be nil"), status.InvalidArgument) + } + if req.Key == "" { + return status.Wrap(errors.New("invalid key: cannot be nil"), status.InvalidArgument) + } + // Check if the label exists + exists, err := client.ScanLabels.Query(). + Where(scanlabels.ScanID(req.ScanID), scanlabels.Key(req.Key)). + Exist(ctx) + if err != nil { + return status.Wrap(err, status.Internal) + } + if !exists { + return status.Wrap(errors.New("label not found"), status.NotFound) + } + + // Delete the label + _, err = client.ScanLabels.Delete(). + Where(scanlabels.ScanID(req.ScanID), scanlabels.Key(req.Key)). + Exec(ctx) + if err != nil { + return status.Wrap(err, status.Internal) + } + + res.Status = "deleted" + return nil + } +} diff --git a/internal/restapi/v1/scanlabels/delete_test.go b/internal/restapi/v1/scanlabels/delete_test.go new file mode 100644 index 0000000..18f7087 --- /dev/null +++ b/internal/restapi/v1/scanlabels/delete_test.go @@ -0,0 +1,120 @@ +package scanlabels_test + +import ( + "context" + "github.com/shinobistack/gokakashi/ent/schema" + "testing" + + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/enttest" + "github.com/shinobistack/gokakashi/internal/restapi/v1/scanlabels" + "github.com/stretchr/testify/assert" +) + +func TestDeleteScanLabel_Valid(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + // Add a label + client.ScanLabels.Create(). + SetScanID(scan.ID). + SetKey("env"). + SetValue("prod"). + SaveX(context.Background()) + + req := scanlabels.DeleteScanLabelRequest{ + ScanID: scan.ID, + Key: "env", + } + res := &scanlabels.DeleteScanLabelResponse{} + + err := scanlabels.DeleteScanLabel(client)(context.Background(), req, res) + + assert.NoError(t, err) + assert.Equal(t, "deleted", res.Status) +} + +func TestDeleteScanLabel_MissingFields(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + req := scanlabels.DeleteScanLabelRequest{ + ScanID: scan.ID, // Missing ScanID + Key: "", + } + res := &scanlabels.DeleteScanLabelResponse{} + + err := scanlabels.DeleteScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) +} + +func TestDeleteScanLabel_LabelNotFound(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + // Create a test scan + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + client.ScanLabels.Create(). + SetScanID(scan.ID). + SetKey("env"). + SetValue("prod"). + SaveX(context.Background()) + + req := scanlabels.DeleteScanLabelRequest{ + ScanID: scan.ID, + Key: "nonexistent-key", + } + res := &scanlabels.DeleteScanLabelResponse{} + + err := scanlabels.DeleteScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "label not found") +} + +func TestDeleteScanLabel_InvalidScanID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + req := scanlabels.DeleteScanLabelRequest{ + ScanID: uuid.Nil, // Invalid ScanID + Key: "env", + } + res := &scanlabels.DeleteScanLabelResponse{} + + err := scanlabels.DeleteScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid UUID") +} diff --git a/internal/restapi/v1/scanlabels/get.go b/internal/restapi/v1/scanlabels/get.go new file mode 100644 index 0000000..237c3bf --- /dev/null +++ b/internal/restapi/v1/scanlabels/get.go @@ -0,0 +1,82 @@ +package scanlabels + +import ( + "context" + "errors" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/swaggest/usecase/status" +) + +type ListScanLabelsRequest struct { + ScanID uuid.UUID `path:"scan_id"` + Keys []string `query:"key"` +} + +type ListScanLabelsResponse struct { + Labels []ScanLabel `json:"labels"` +} + +type ScanLabel struct { + Key string `json:"key"` + Value string `json:"value"` +} + +type GetScanLabelRequest struct { + ScanID uuid.UUID `path:"scan_id"` + Key string `path:"key"` +} + +type GetScanLabelResponse struct { + Key string `json:"key"` + Value string `json:"value"` +} + +func ListScanLabels(client *ent.Client) func(ctx context.Context, req ListScanLabelsRequest, res *ListScanLabelsResponse) error { + return func(ctx context.Context, req ListScanLabelsRequest, res *ListScanLabelsResponse) error { + if req.ScanID == uuid.Nil { + return status.Wrap(errors.New("invalid UUID: cannot be nil"), status.InvalidArgument) + } + query := client.ScanLabels.Query().Where(scanlabels.ScanID(req.ScanID)) + + // Filter by keys if provided + if len(req.Keys) > 0 { + query = query.Where(scanlabels.KeyIn(req.Keys...)) + } + + labels, err := query.All(ctx) + if err != nil { + return status.Wrap(err, status.Internal) + } + + res.Labels = make([]ScanLabel, len(labels)) + for i, label := range labels { + res.Labels[i] = ScanLabel{ + Key: label.Key, + Value: label.Value, + } + } + return nil + } +} + +func GetScanLabel(client *ent.Client) func(ctx context.Context, req GetScanLabelRequest, res *GetScanLabelResponse) error { + return func(ctx context.Context, req GetScanLabelRequest, res *GetScanLabelResponse) error { + // Validate inputs + if req.ScanID == uuid.Nil || req.Key == "" { + return status.Wrap(errors.New("invalid Scan ID or Key"), status.InvalidArgument) + } + + label, err := client.ScanLabels.Query(). + Where(scanlabels.ScanID(req.ScanID), scanlabels.Key(req.Key)). + Only(ctx) + if err != nil { + return status.Wrap(err, status.Internal) + } + + res.Key = label.Key + res.Value = label.Value + return nil + } +} diff --git a/internal/restapi/v1/scanlabels/get_test.go b/internal/restapi/v1/scanlabels/get_test.go new file mode 100644 index 0000000..2ab2bbd --- /dev/null +++ b/internal/restapi/v1/scanlabels/get_test.go @@ -0,0 +1,154 @@ +package scanlabels_test + +import ( + "context" + "github.com/shinobistack/gokakashi/ent/schema" + "testing" + + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/enttest" + "github.com/shinobistack/gokakashi/internal/restapi/v1/scanlabels" + "github.com/stretchr/testify/assert" +) + +func TestListScanLabels_Valid(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + // Create a test scan + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + // Add labels + client.ScanLabels.Create(). + SetScanID(scan.ID). + SetKey("env"). + SetValue("prod"). + SaveX(context.Background()) + + client.ScanLabels.Create(). + SetScanID(scan.ID). + SetKey("version"). + SetValue("v1.0"). + SaveX(context.Background()) + + req := scanlabels.ListScanLabelsRequest{ + ScanID: scan.ID, + } + res := &scanlabels.ListScanLabelsResponse{} + + err := scanlabels.ListScanLabels(client)(context.Background(), req, res) + + assert.NoError(t, err) + assert.Len(t, res.Labels, 2) +} + +func TestListScanLabels_NoLabels(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + // Create a test scan + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + req := scanlabels.ListScanLabelsRequest{ + ScanID: scan.ID, + } + res := &scanlabels.ListScanLabelsResponse{} + + err := scanlabels.ListScanLabels(client)(context.Background(), req, res) + + assert.NoError(t, err) + assert.Len(t, res.Labels, 0) +} + +func TestGetScanLabel_Valid(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + // Create a test scan + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + // Add a label + client.ScanLabels.Create(). + SetScanID(scan.ID). + SetKey("env"). + SetValue("prod"). + SaveX(context.Background()) + + req := scanlabels.GetScanLabelRequest{ + ScanID: scan.ID, + Key: "env", + } + res := &scanlabels.GetScanLabelResponse{} + + err := scanlabels.GetScanLabel(client)(context.Background(), req, res) + + assert.NoError(t, err) + assert.Equal(t, "env", res.Key) + assert.Equal(t, "prod", res.Value) +} + +func TestGetScanLabel_NotFound(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + // Create a test scan + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + req := scanlabels.GetScanLabelRequest{ + ScanID: scan.ID, + Key: "nonexistent-key", + } + res := &scanlabels.GetScanLabelResponse{} + + err := scanlabels.GetScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) +} + +func TestGetScanLabel_InvalidScanID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + req := scanlabels.GetScanLabelRequest{ + ScanID: uuid.Nil, // Invalid ScanID + Key: "env", + } + res := &scanlabels.GetScanLabelResponse{} + + err := scanlabels.GetScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) +} diff --git a/internal/restapi/v1/scanlabels/post.go b/internal/restapi/v1/scanlabels/post.go new file mode 100644 index 0000000..f6ce1b6 --- /dev/null +++ b/internal/restapi/v1/scanlabels/post.go @@ -0,0 +1,57 @@ +package scanlabels + +import ( + "context" + "errors" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/swaggest/usecase/status" +) + +// ToDo: To have a requests to create labels in bulk? +type CreateScanLabelRequest struct { + ScanID uuid.UUID `path:"scan_id"` + Key string `json:"key"` + Value string `json:"value"` +} + +type CreateScanLabelResponse struct { + ScanID uuid.UUID `path:"scan_id"` + Key string `json:"key"` + Value string `json:"value"` +} + +func CreateScanLabel(client *ent.Client) func(ctx context.Context, req CreateScanLabelRequest, res *CreateScanLabelResponse) error { + return func(ctx context.Context, req CreateScanLabelRequest, res *CreateScanLabelResponse) error { + if req.ScanID == uuid.Nil || req.Key == "" || req.Value == "" { + return status.Wrap(errors.New("invalid input: missing fields"), status.InvalidArgument) + } + + // Check if the label already exists + exists, err := client.ScanLabels.Query(). + Where(scanlabels.ScanID(req.ScanID), scanlabels.Key(req.Key)). + Exist(ctx) + if err != nil { + return status.Wrap(err, status.Internal) + } + if exists { + return status.Wrap(errors.New("label already exists"), status.AlreadyExists) + } + + label, err := client.ScanLabels.Create(). + SetScanID(req.ScanID). + SetKey(req.Key). + SetValue(req.Value). + Save(ctx) + if err != nil { + return status.Wrap(err, status.Internal) + } + + res.ScanID = label.ScanID + res.Key = label.Key + res.Value = label.Value + + return nil + } +} diff --git a/internal/restapi/v1/scanlabels/post_test.go b/internal/restapi/v1/scanlabels/post_test.go new file mode 100644 index 0000000..3ec9885 --- /dev/null +++ b/internal/restapi/v1/scanlabels/post_test.go @@ -0,0 +1,130 @@ +package scanlabels_test + +import ( + "context" + "github.com/shinobistack/gokakashi/ent/schema" + "testing" + + "github.com/google/uuid" + _ "github.com/mattn/go-sqlite3" + "github.com/shinobistack/gokakashi/ent/enttest" + "github.com/shinobistack/gokakashi/internal/restapi/v1/scanlabels" + "github.com/stretchr/testify/assert" +) + +func TestCreateScanLabel_Valid(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + // Create a test scan + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + req := scanlabels.CreateScanLabelRequest{ + ScanID: scan.ID, + Key: "env", + Value: "prod", + } + res := &scanlabels.CreateScanLabelResponse{} + + err := scanlabels.CreateScanLabel(client)(context.Background(), req, res) + + assert.NoError(t, err) + assert.Equal(t, req.ScanID, res.ScanID) + assert.Equal(t, req.Key, res.Key) + assert.Equal(t, req.Value, res.Value) +} + +func TestCreateScanLabel_MissingFields(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + req := scanlabels.CreateScanLabelRequest{ + ScanID: policy.ID, + Key: "", + Value: "", + } + res := &scanlabels.CreateScanLabelResponse{} + + err := scanlabels.CreateScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) +} + +func TestCreateScanLabel_InvalidScanID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + req := scanlabels.CreateScanLabelRequest{ + ScanID: uuid.Nil, // Invalid ID + Key: "env", + Value: "prod", + } + res := &scanlabels.CreateScanLabelResponse{} + + err := scanlabels.CreateScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) +} + +func TestCreateScanLabel_DuplicateKey(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + // Create a test scan + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + // Create a label + client.ScanLabels.Create(). + SetScanID(scan.ID). + SetKey("env"). + SetValue("prod"). + SaveX(context.Background()) + + req := scanlabels.CreateScanLabelRequest{ + ScanID: scan.ID, + Key: "env", + Value: "staging", + } + res := &scanlabels.CreateScanLabelResponse{} + + err := scanlabels.CreateScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) +} + +func TestCreateScanLabel_NonExistentScanID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + req := scanlabels.CreateScanLabelRequest{ + ScanID: uuid.New(), // Non-existent ID + Key: "env", + Value: "prod", + } + res := &scanlabels.CreateScanLabelResponse{} + + err := scanlabels.CreateScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) +} diff --git a/internal/restapi/v1/scanlabels/put.go b/internal/restapi/v1/scanlabels/put.go new file mode 100644 index 0000000..ba2aef7 --- /dev/null +++ b/internal/restapi/v1/scanlabels/put.go @@ -0,0 +1,116 @@ +package scanlabels + +import ( + "context" + "errors" + "fmt" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent" + "github.com/shinobistack/gokakashi/ent/scanlabels" + "github.com/swaggest/usecase/status" +) + +type UpdateScanLabelRequest struct { + ScanID uuid.UUID `path:"scan_id"` + Labels []ScanLabel `json:"labels"` + Key *string `json:"key"` + Value *string `json:"value"` +} + +type UpdateScanLabelResponse struct { + Labels []ScanLabel `json:"labels"` +} + +func UpdateScanLabel(client *ent.Client) func(ctx context.Context, req UpdateScanLabelRequest, res *UpdateScanLabelResponse) error { + return func(ctx context.Context, req UpdateScanLabelRequest, res *UpdateScanLabelResponse) error { + if req.ScanID == uuid.Nil { + return status.Wrap(errors.New("invalid UUID: cannot be nil"), status.InvalidArgument) + } + + if req.Key != nil && req.Value != nil { + // Update a specific label + _, err := client.ScanLabels.Update(). + Where(scanlabels.ScanID(req.ScanID), scanlabels.Key(*req.Key)). + SetValue(*req.Value). + Save(ctx) + if err != nil { + if ent.IsNotFound(err) { + return status.Wrap(errors.New("label not found"), status.NotFound) + } + return status.Wrap(err, status.Internal) + } + + updatedLabel, err := client.ScanLabels.Query(). + Where(scanlabels.ScanID(req.ScanID), scanlabels.Key(*req.Key)). + Only(ctx) + if err != nil { + if ent.IsNotFound(err) { + return status.Wrap(errors.New("label not found after update"), status.NotFound) + } + return status.Wrap(err, status.Internal) + } + + // Return the updated label + res.Labels = []ScanLabel{ + { + Key: updatedLabel.Key, + Value: updatedLabel.Value, + }, + } + return nil + } + + if req.Labels != nil { + // Replace all labels + tx, err := client.Tx(ctx) + if err != nil { + return status.Wrap(err, status.Internal) + } + + // Delete existing labels + _, err = tx.ScanLabels.Delete(). + Where(scanlabels.ScanID(req.ScanID)). + Exec(ctx) + if err != nil { + if rollbackErr := tx.Rollback(); rollbackErr != nil { + fmt.Printf("rollback failed: %v\n", rollbackErr) + } + return status.Wrap(err, status.Internal) + } + + // Add new labels + bulk := make([]*ent.ScanLabelsCreate, len(req.Labels)) + for i, label := range req.Labels { + bulk[i] = tx.ScanLabels.Create(). + SetScanID(req.ScanID). + SetKey(label.Key). + SetValue(label.Value) + } + + createdLabels, err := tx.ScanLabels.CreateBulk(bulk...).Save(ctx) + if err != nil { + if rollbackErr := tx.Rollback(); rollbackErr != nil { + fmt.Printf("rollback failed: %v\n", rollbackErr) + } + return status.Wrap(err, status.Internal) + } + + err = tx.Commit() + if err != nil { + return status.Wrap(err, status.Internal) + } + + // Build the response + res.Labels = make([]ScanLabel, len(createdLabels)) + for i, label := range createdLabels { + res.Labels[i] = ScanLabel{ + Key: label.Key, + Value: label.Value, + } + } + return nil + } + + return status.Wrap(errors.New("invalid request: either key-value or labels must be provided"), status.InvalidArgument) + } +} diff --git a/internal/restapi/v1/scanlabels/put_test.go b/internal/restapi/v1/scanlabels/put_test.go new file mode 100644 index 0000000..108ab67 --- /dev/null +++ b/internal/restapi/v1/scanlabels/put_test.go @@ -0,0 +1,134 @@ +package scanlabels_test + +import ( + "context" + "github.com/shinobistack/gokakashi/ent/schema" + "testing" + + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent/enttest" + "github.com/shinobistack/gokakashi/internal/restapi/v1/scanlabels" + "github.com/stretchr/testify/assert" +) + +func TestUpdateScanLabel_Valid(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + // Create a test scan + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + // Add a label + client.ScanLabels.Create(). + SetScanID(scan.ID). + SetKey("env"). + SetValue("prod"). + SaveX(context.Background()) + + req := scanlabels.UpdateScanLabelRequest{ + ScanID: scan.ID, + Key: strPtr("env"), + Value: strPtr("dev"), + } + res := &scanlabels.UpdateScanLabelResponse{} + + err := scanlabels.UpdateScanLabel(client)(context.Background(), req, res) + + assert.NoError(t, err) + assert.Equal(t, "dev", res.Labels[0].Value) +} + +func TestUpdateScanLabel_MissingFields(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + client.ScanLabels.Create(). + SetScanID(scan.ID). + SetKey("env"). + SetValue("prod"). + SaveX(context.Background()) + + req := scanlabels.UpdateScanLabelRequest{ + ScanID: scan.ID, + Key: strPtr(""), + Value: strPtr(""), + } + res := &scanlabels.UpdateScanLabelResponse{} + + err := scanlabels.UpdateScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) +} + +func TestUpdateScanLabel_LabelNotFound(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + client.ScanLabels.Create(). + SetScanID(scan.ID). + SetKey("env"). + SetValue("prod"). + SaveX(context.Background()) + + req := scanlabels.UpdateScanLabelRequest{ + ScanID: scan.ID, + Key: strPtr("nonexistent-key"), + Value: strPtr("new-value"), + } + res := &scanlabels.UpdateScanLabelResponse{} + + err := scanlabels.UpdateScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "label not found") +} + +func TestUpdateScanLabel_InvalidScanID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + req := scanlabels.UpdateScanLabelRequest{ + ScanID: uuid.Nil, // Invalid ScanID + Key: strPtr("env"), + Value: strPtr("new-value"), + } + res := &scanlabels.UpdateScanLabelResponse{} + + err := scanlabels.UpdateScanLabel(client)(context.Background(), req, res) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid UUID") +} + +func strPtr(s string) *string { + return &s +} diff --git a/internal/restapi/v1/scans/delete.go b/internal/restapi/v1/scans/delete.go new file mode 100644 index 0000000..07592c2 --- /dev/null +++ b/internal/restapi/v1/scans/delete.go @@ -0,0 +1,36 @@ +package scans + +import ( + "context" + "errors" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent" + "github.com/swaggest/usecase/status" +) + +type DeleteScanRequest struct { + ID uuid.UUID `path:"id"` +} + +type DeleteScanResponse struct { + ID uuid.UUID `json:"id"` + Status string `json:"status"` +} + +func DeleteScan(client *ent.Client) func(ctx context.Context, req DeleteScanRequest, res *DeleteScanResponse) error { + return func(ctx context.Context, req DeleteScanRequest, res *DeleteScanResponse) error { + // Validate ID + if req.ID == uuid.Nil { + return status.Wrap(errors.New("invalid UUID: cannot be nil"), status.InvalidArgument) + } + + err := client.Scans.DeleteOneID(req.ID).Exec(ctx) + if err != nil { + return status.Wrap(err, status.Internal) + } + + res.ID = req.ID + res.Status = "deleted" + return nil + } +} diff --git a/internal/restapi/v1/scans/delete_test.go b/internal/restapi/v1/scans/delete_test.go new file mode 100644 index 0000000..56322ae --- /dev/null +++ b/internal/restapi/v1/scans/delete_test.go @@ -0,0 +1,86 @@ +package scans_test + +import ( + "context" + "github.com/shinobistack/gokakashi/ent/schema" + "testing" + + "github.com/google/uuid" + _ "github.com/mattn/go-sqlite3" + "github.com/shinobistack/gokakashi/ent/enttest" + "github.com/shinobistack/gokakashi/internal/restapi/v1/scans" + "github.com/stretchr/testify/assert" +) + +func TestDeleteScan_Valid(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + // Create a test scan + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + req := scans.DeleteScanRequest{ + ID: scan.ID, + } + + res := &scans.DeleteScanResponse{} + err := scans.DeleteScan(client)(context.Background(), req, res) + + assert.NoError(t, err) + assert.Equal(t, req.ID, res.ID) + assert.Equal(t, "deleted", res.Status) +} + +func TestDeleteScan_InvalidScanID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + req := scans.DeleteScanRequest{ + ID: uuid.Nil, // Invalid ID + } + + res := &scans.DeleteScanResponse{} + err := scans.DeleteScan(client)(context.Background(), req, res) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid UUID") +} + +func TestDeleteScan_NonExistentScanID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + req := scans.DeleteScanRequest{ + ID: uuid.New(), // Non-existent ID + } + + res := &scans.DeleteScanResponse{} + err := scans.DeleteScan(client)(context.Background(), req, res) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "not found") +} + +// Todo: to use when we do transaction operation +//func TestDeleteScan_ErrorDuringDeletion(t *testing.T) { +// client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") +// defer client.Close() +// +// req := scans.DeleteScanRequest{ +// ID: uuid.New(), +// } +// +// res := &scans.DeleteScanResponse{} +// err := scans.DeleteScan(client)(context.Background(), req, res) +// +// assert.Error(t, err) +// assert.Contains(t, err.Error(), "failed to delete") +//} diff --git a/internal/restapi/v1/scans/get.go b/internal/restapi/v1/scans/get.go new file mode 100644 index 0000000..362fb05 --- /dev/null +++ b/internal/restapi/v1/scans/get.go @@ -0,0 +1,72 @@ +package scans + +import ( + "context" + "errors" + "fmt" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent" + "github.com/shinobistack/gokakashi/ent/schema" + "github.com/swaggest/usecase/status" +) + +type GetScanResponse struct { + ID uuid.UUID `json:"id"` + PolicyID uuid.UUID `json:"policy_id"` + Image string `json:"image"` + Status string `json:"status"` + Check schema.Check `json:"check"` + Report interface{} `json:"report"` +} + +type ListScanRequest struct{} + +type GetScanRequest struct { + ID uuid.UUID `path:"id"` +} + +func ListScans(client *ent.Client) func(ctx context.Context, req ListScanRequest, res *[]GetScanResponse) error { + return func(ctx context.Context, req ListScanRequest, res *[]GetScanResponse) error { + scans, err := client.Scans.Query().All(ctx) + if err != nil { + return status.Wrap(errors.New("failed to fetch scan details"), status.Internal) + } + + *res = make([]GetScanResponse, len(scans)) + for i, scan := range scans { + (*res)[i] = GetScanResponse{ + ID: scan.ID, + PolicyID: scan.PolicyID, + Image: scan.Image, + Status: scan.Status, + Check: scan.Check, + Report: scan.Report, + } + } + return nil + } +} + +func GetScan(client *ent.Client) func(ctx context.Context, req GetScanRequest, res *GetScanResponse) error { + return func(ctx context.Context, req GetScanRequest, res *GetScanResponse) error { + if req.ID == uuid.Nil { + return status.Wrap(errors.New("invalid UUID: cannot be nil"), status.InvalidArgument) + } + + scan, err := client.Scans.Get(ctx, req.ID) + if err != nil { + if ent.IsNotFound(err) { + return status.Wrap(errors.New("scan not found"), status.NotFound) + } + return status.Wrap(fmt.Errorf("unexpected error: %v", err), status.Internal) + } + + res.ID = scan.ID + res.PolicyID = scan.PolicyID + res.Image = scan.Image + res.Status = scan.Status + res.Check = scan.Check + res.Report = scan.Report + return nil + } +} diff --git a/internal/restapi/v1/scans/get_test.go b/internal/restapi/v1/scans/get_test.go new file mode 100644 index 0000000..c9c3a77 --- /dev/null +++ b/internal/restapi/v1/scans/get_test.go @@ -0,0 +1,87 @@ +package scans_test + +import ( + "context" + "testing" + + "github.com/google/uuid" + _ "github.com/mattn/go-sqlite3" + "github.com/shinobistack/gokakashi/ent/enttest" + "github.com/shinobistack/gokakashi/ent/schema" + "github.com/shinobistack/gokakashi/internal/restapi/v1/scans" + "github.com/stretchr/testify/assert" +) + +func TestListScans_Valid(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("test-image-1"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("test-image-2"). + SetStatus("success"). + SaveX(context.Background()) + + req := scans.ListScanRequest{} + res := []scans.GetScanResponse{} + err := scans.ListScans(client)(context.Background(), req, &res) + + assert.NoError(t, err) + assert.Equal(t, 2, len(res)) +} + +func TestGetScan_Valid(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("test-image"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + res := scans.GetScanResponse{} + err := scans.GetScan(client)(context.Background(), scans.GetScanRequest{ID: scan.ID}, &res) + + assert.NoError(t, err) + assert.Equal(t, scan.ID, res.ID) + assert.Equal(t, "test-image", res.Image) +} + +func TestGetScan_NonExistentID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + res := scans.GetScanResponse{} + err := scans.GetScan(client)(context.Background(), scans.GetScanRequest{ID: uuid.New()}, &res) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "scan not found") +} + +func TestGetScan_InvalidID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + res := scans.GetScanResponse{} + err := scans.GetScan(client)(context.Background(), scans.GetScanRequest{ID: uuid.Nil}, &res) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid UUID: cannot be nil") +} diff --git a/internal/restapi/v1/scans/post.go b/internal/restapi/v1/scans/post.go new file mode 100644 index 0000000..0bad673 --- /dev/null +++ b/internal/restapi/v1/scans/post.go @@ -0,0 +1,78 @@ +package scans + +import ( + "context" + "errors" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent" + "github.com/shinobistack/gokakashi/ent/policies" + "github.com/shinobistack/gokakashi/ent/scans" + "github.com/shinobistack/gokakashi/ent/schema" + "github.com/swaggest/usecase/status" +) + +type CreateScanRequest struct { + PolicyID uuid.UUID `json:"policy_id"` + // ToDo: To think if the image stored would be single registery/image:tag. + Image string `json:"image"` + //ToDo: Similarly to think if the check should have the evaluate conditions. How would the notify work. + Check schema.Check `json:"check"` + // ToDo: can we pre-define the values for scan status that can be used? + Status string `json:"status"` + // ToDo: Just the report URL or status of public or private + Report string `json:"report"` +} + +type CreateScanResponse struct { + ID uuid.UUID `json:"id"` + Status string `json:"status"` +} + +// ToDo: The server would pick up and filter and give the single image, evaluated to check condition and notify + +func CreateScan(client *ent.Client) func(ctx context.Context, req CreateScanRequest, res *CreateScanResponse) error { + return func(ctx context.Context, req CreateScanRequest, res *CreateScanResponse) error { + // Validate + if req.PolicyID == uuid.Nil || req.Image == "" || req.Status == "" { + return status.Wrap(errors.New("missing required fields"), status.InvalidArgument) + } + // ToDo: To think if we need to check image duplicate for scans? IF image already scheduled for scans? + // Check if PolicyID exists before creating the scan. + exists, err := client.Policies.Query(). + Where(policies.ID(req.PolicyID)). + Exist(ctx) + if err != nil { + return status.Wrap(err, status.Internal) + } + if !exists { + return status.Wrap(errors.New("policy not found"), status.NotFound) + } + // Check for duplicate scans for the same image under a policy + duplicate, err := client.Scans.Query(). + Where(scans.PolicyID(req.PolicyID), scans.Image(req.Image)). + Exist(ctx) + if err != nil { + return status.Wrap(err, status.Internal) + } + if duplicate { + return status.Wrap(errors.New("scan already scheduled for this image"), status.AlreadyExists) + } + + // Create the scan + scan, err := client.Scans.Create(). + SetPolicyID(req.PolicyID). + SetImage(req.Image). + SetCheck(req.Check). + SetStatus(req.Status). + SetReport(req.Report). + Save(ctx) + + if err != nil { + return status.Wrap(err, status.Internal) + } + + res.ID = scan.ID + res.Status = "scan_pending" + return nil + } +} diff --git a/internal/restapi/v1/scans/post_test.go b/internal/restapi/v1/scans/post_test.go new file mode 100644 index 0000000..446870b --- /dev/null +++ b/internal/restapi/v1/scans/post_test.go @@ -0,0 +1,80 @@ +// Example test file for Scans - post_test.go +package scans_test + +import ( + "context" + "github.com/shinobistack/gokakashi/ent/schema" + "testing" + + "github.com/google/uuid" + _ "github.com/mattn/go-sqlite3" + "github.com/shinobistack/gokakashi/ent/enttest" + "github.com/shinobistack/gokakashi/internal/restapi/v1/scans" + "github.com/stretchr/testify/assert" +) + +func TestCreateScan_ValidInput(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + policy := client.Policies.Create(). + SetName("to-be-deleted-test-policy"). + SetImage(schema.Image{Registry: "example-registry", Name: "example-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + req := scans.CreateScanRequest{ + PolicyID: policy.ID, + Image: "dockerhub/nginx:latest", + Check: schema.Check{Condition: "severity > high", Notify: []string{"email"}}, + Status: "scan_pending", + Report: "", + } + res := &scans.CreateScanResponse{} + + err := scans.CreateScan(client)(context.Background(), req, res) + + assert.NoError(t, err) + assert.NotNil(t, res.ID) + assert.Equal(t, "scan_pending", res.Status) +} + +func TestCreateScan_MissingFields(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + policy := client.Policies.Create(). + SetName("to-be-deleted-test-policy"). + SetImage(schema.Image{Registry: "example-registry", Name: "example-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + req := scans.CreateScanRequest{ + PolicyID: policy.ID, + Image: "", + Check: schema.Check{Condition: "severity > high", Notify: []string{"email"}}, + Status: "scan_pending", + Report: "", + } + res := &scans.CreateScanResponse{} + + err := scans.CreateScan(client)(context.Background(), req, res) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "missing required fields") +} + +func TestCreateScan_InvalidPolicyID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + req := scans.CreateScanRequest{ + PolicyID: uuid.Nil, + Image: "dockerhub/nginx:latest", + Check: schema.Check{Condition: "severity > high", Notify: []string{"email"}}, + Status: "scan_pending", + Report: "", + } + res := &scans.CreateScanResponse{} + + err := scans.CreateScan(client)(context.Background(), req, res) + + assert.Error(t, err) +} diff --git a/internal/restapi/v1/scans/put.go b/internal/restapi/v1/scans/put.go new file mode 100644 index 0000000..999921c --- /dev/null +++ b/internal/restapi/v1/scans/put.go @@ -0,0 +1,55 @@ +package scans + +import ( + "context" + "errors" + "fmt" + "github.com/google/uuid" + "github.com/shinobistack/gokakashi/ent" + "github.com/swaggest/usecase/status" +) + +type UpdateScanRequest struct { + ID uuid.UUID `path:"id"` + Status *string `json:"status"` + Report string `json:"report,omitempty"` +} + +type UpdateScanResponse struct { + ID uuid.UUID `json:"id"` + Status string `json:"status"` +} + +func UpdateScan(client *ent.Client) func(ctx context.Context, req UpdateScanRequest, res *UpdateScanResponse) error { + return func(ctx context.Context, req UpdateScanRequest, res *UpdateScanResponse) error { + if req.ID == uuid.Nil { + return status.Wrap(errors.New("invalid UUID: cannot be nil"), status.InvalidArgument) + } + + _, err := client.Scans.Get(ctx, req.ID) + if err != nil { + if ent.IsNotFound(err) { + return status.Wrap(errors.New("scan not found"), status.NotFound) + } + return status.Wrap(fmt.Errorf("unexpected error: %v", err), status.Internal) + } + + update := client.Scans.UpdateOneID(req.ID) + + if req.Status != nil { + update.SetStatus(*req.Status) + } + + if req.Report != "" { + update.SetReport(req.Report) + } + + updatedScan, err := update.Save(ctx) + if err != nil { + return status.Wrap(fmt.Errorf("failed to update scan: %v", err), status.Internal) + } + res.ID = updatedScan.ID + res.Status = updatedScan.Status + return nil + } +} diff --git a/internal/restapi/v1/scans/put_test.go b/internal/restapi/v1/scans/put_test.go new file mode 100644 index 0000000..75278b1 --- /dev/null +++ b/internal/restapi/v1/scans/put_test.go @@ -0,0 +1,99 @@ +package scans_test + +import ( + "context" + "github.com/shinobistack/gokakashi/ent/schema" + "testing" + + "github.com/google/uuid" + _ "github.com/mattn/go-sqlite3" + "github.com/shinobistack/gokakashi/ent/enttest" + + "github.com/shinobistack/gokakashi/internal/restapi/v1/scans" + "github.com/stretchr/testify/assert" +) + +func TestUpdateScan_Valid(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + // Create a test scan + scan := client.Scans.Create(). + SetPolicyID(policy.ID). + SetImage("example-image:latest"). + SetStatus("scan_pending"). + SaveX(context.Background()) + + req := scans.UpdateScanRequest{ + ID: scan.ID, + Status: strPtr("in_progress"), + Report: "https://reports.server.com/scan/123", + } + + res := &scans.UpdateScanResponse{} + err := scans.UpdateScan(client)(context.Background(), req, res) + + assert.NoError(t, err) + assert.Equal(t, req.ID, res.ID) + assert.Equal(t, "in_progress", res.Status) +} + +func TestUpdateScan_MissingFields(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + policy := client.Policies.Create(). + SetName("test-policy"). + SetImage(schema.Image{Registry: "test-registry", Name: "test-name", Tags: []string{"v1.0"}}). + SaveX(context.Background()) + + req := scans.UpdateScanRequest{ + ID: policy.ID, + // Missing required fields + } + + res := &scans.UpdateScanResponse{} + err := scans.UpdateScan(client)(context.Background(), req, res) + + assert.Error(t, err) +} + +func TestUpdateScan_InvalidScanID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + req := scans.UpdateScanRequest{ + ID: uuid.Nil, + Status: strPtr("in_progress"), + } + + res := &scans.UpdateScanResponse{} + err := scans.UpdateScan(client)(context.Background(), req, res) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "invalid UUID") +} + +func TestUpdateScan_NonExistentScanID(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") + defer client.Close() + + req := scans.UpdateScanRequest{ + ID: uuid.New(), // Non-existent ID + Status: strPtr("in_progress"), + } + + res := &scans.UpdateScanResponse{} + err := scans.UpdateScan(client)(context.Background(), req, res) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "not found") +} + +func strPtr(s string) *string { + return &s +} diff --git a/internal/restapi/v1/server.go b/internal/restapi/v1/server.go index 4e5f2a3..719925d 100644 --- a/internal/restapi/v1/server.go +++ b/internal/restapi/v1/server.go @@ -12,6 +12,9 @@ import ( integrationtype1 "github.com/shinobistack/gokakashi/internal/restapi/v1/integrationtype" policies1 "github.com/shinobistack/gokakashi/internal/restapi/v1/policies" policylabels1 "github.com/shinobistack/gokakashi/internal/restapi/v1/policylabels" + scanlabels1 "github.com/shinobistack/gokakashi/internal/restapi/v1/scanlabels" + scans1 "github.com/shinobistack/gokakashi/internal/restapi/v1/scans" + "github.com/swaggest/openapi-go/openapi31" "github.com/swaggest/rest/web" swg "github.com/swaggest/swgui" @@ -69,6 +72,18 @@ func (srv *Server) Service() *web.Service { apiV1.Put("/policies/{policy_id}/labels", usecase.NewInteractor(policylabels1.UpdatePolicyLabels(srv.DB))) apiV1.Delete("/policies/{policy_id}/labels/{key}", usecase.NewInteractor(policylabels1.DeletePolicyLabel(srv.DB))) + apiV1.Post("/scans", usecase.NewInteractor(scans1.CreateScan(srv.DB))) + apiV1.Get("/scans", usecase.NewInteractor(scans1.ListScans(srv.DB))) + apiV1.Get("/scans/{id}", usecase.NewInteractor(scans1.GetScan(srv.DB))) + apiV1.Put("/scans/{id}", usecase.NewInteractor(scans1.UpdateScan(srv.DB))) + apiV1.Delete("/scans/{id}", usecase.NewInteractor(scans1.DeleteScan(srv.DB))) + + apiV1.Post("/scans/{scan_id}/labels", usecase.NewInteractor(scanlabels1.CreateScanLabel(srv.DB))) + apiV1.Get("/scans/{scan_id}/labels", usecase.NewInteractor(scanlabels1.ListScanLabels(srv.DB))) + apiV1.Get("/scans/{scan_id}/labels/{key}", usecase.NewInteractor(scanlabels1.GetScanLabel(srv.DB))) + apiV1.Put("/scans/{scan_id}/labels", usecase.NewInteractor(scanlabels1.UpdateScanLabel(srv.DB))) + apiV1.Delete("/scans/{scan_id}/labels/{key}", usecase.NewInteractor(scanlabels1.DeleteScanLabel(srv.DB))) + s.Mount("/api/v1/openapi.json", specHandler(apiV1.OpenAPICollector.SpecSchema().(*openapi31.Spec))) s.Mount("/api/v1", apiV1)