Skip to content

Commit

Permalink
ability to expose a private field to action.
Browse files Browse the repository at this point in the history
ent API and graphql accessor still unchanged
  • Loading branch information
lolopinto committed Aug 2, 2022
1 parent 881c050 commit 8de37f6
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 19 deletions.
123 changes: 123 additions & 0 deletions internal/action/action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,129 @@ func TestOverriddenRequiredActionField(t *testing.T) {
)
}

func TestPrivateFieldExposedToActions(t *testing.T) {
actionInfo := testhelper.ParseActionInfoForTest(
t,
map[string]string{
"user.ts": testhelper.GetCodeWithSchema(
`import {Schema, FieldMap, StringType, Action, ActionOperation, BaseEntSchema, requiredField} from "{schema}";
export default class User extends BaseEntSchema {
fields: FieldMap = {
FirstName: StringType(),
LastName: StringType(),
EmailAddress: StringType(),
Password: StringType({
private: {
exposeToActions: true,
},
}),
};
actions: Action[] = [
{
operation: ActionOperation.Create,
},
];
}
`,
),
},
base.TypeScript,
"UserConfig",
)

verifyExpectedActions(
t,
actionInfo,
[]expectedAction{
{
name: "CreateUserAction",
fields: []expectedField{
{
name: "FirstName",
tsType: "string",
gqlType: "String!",
},
{
name: "LastName",
tsType: "string",
gqlType: "String!",
},
{
name: "EmailAddress",
tsType: "string",
gqlType: "String!",
},
{
name: "Password",
tsType: "string",
gqlType: "String!",
},
},
},
},
)
}

func TestPrivateField(t *testing.T) {
actionInfo := testhelper.ParseActionInfoForTest(
t,
map[string]string{
"user.ts": testhelper.GetCodeWithSchema(
`import {Schema, FieldMap, StringType, Action, ActionOperation, BaseEntSchema, requiredField} from "{schema}";
export default class User extends BaseEntSchema {
fields: FieldMap = {
FirstName: StringType(),
LastName: StringType(),
EmailAddress: StringType(),
Password: StringType({
private: true,
}),
};
actions: Action[] = [
{
operation: ActionOperation.Create,
},
];
}
`,
),
},
base.TypeScript,
"UserConfig",
)

verifyExpectedActions(
t,
actionInfo,
[]expectedAction{
{
name: "CreateUserAction",
fields: []expectedField{
{
name: "FirstName",
tsType: "string",
gqlType: "String!",
},
{
name: "LastName",
tsType: "string",
gqlType: "String!",
},
{
name: "EmailAddress",
tsType: "string",
gqlType: "String!",
},
},
},
},
)
}

func TestOverriddenOptionalActionField(t *testing.T) {
actionInfo := testhelper.ParseActionInfoForTest(
t,
Expand Down
8 changes: 4 additions & 4 deletions internal/field/field_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func newFieldFromInput(cfg codegenapi.Config, nodeName string, f *input.Field) (
nullable: f.Nullable,
dbName: f.StorageKey,
hideFromGraphQL: f.HideFromGraphQL,
private: f.Private,
private: f.Private != nil,
polymorphic: f.Polymorphic,
index: f.Index,
graphQLName: f.GraphQLName,
Expand Down Expand Up @@ -172,7 +172,7 @@ func newFieldFromInput(cfg codegenapi.Config, nodeName string, f *input.Field) (
}

if ret.private {
ret.setPrivate()
ret.setPrivate(f.Private)
}

getSchemaName := func(config string) string {
Expand Down Expand Up @@ -771,10 +771,10 @@ func (f *Field) setTsFieldType(fieldType enttype.Type) error {
return nil
}

func (f *Field) setPrivate() {
func (f *Field) setPrivate(p *input.PrivateOptions) {
f.private = true
f.hideFromGraphQL = true
f.exposeToActionsByDefault = false
f.exposeToActionsByDefault = p.ExposeToActions
}

func (f *Field) AddInverseEdge(cfg codegenapi.Config, edge *edge.AssociationEdge) error {
Expand Down
2 changes: 1 addition & 1 deletion internal/field/new_field_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func modifyFieldForDataType(
}
// if the datatype is specifically private, field makes it private
if res.private {
f.Private = true
f.Private = &input.PrivateOptions{}
}

f.DataTypePkgPath = getImportedPackageThatMatchesIdent(pkg, info.PkgName, info.IdentName).PkgPath
Expand Down
11 changes: 10 additions & 1 deletion internal/schema/input/compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func fieldEqual(existingField, field *Field) bool {
existingField.StorageKey == field.StorageKey &&
existingField.Unique == field.Unique &&
existingField.HideFromGraphQL == field.HideFromGraphQL &&
existingField.Private == field.Private &&
PrivateOptionsEqual(existingField.Private, field.Private) &&
existingField.GraphQLName == field.GraphQLName &&
existingField.Index == field.Index &&
existingField.PrimaryKey == field.PrimaryKey &&
Expand Down Expand Up @@ -132,6 +132,15 @@ func PolymorphicOptionsEqual(existing, p *PolymorphicOptions) bool {
existing.DisableBuilderType == p.DisableBuilderType
}

func PrivateOptionsEqual(existing, p *PrivateOptions) bool {
ret := change.CompareNilVals(existing == nil, p == nil)
if ret != nil {
return *ret
}

return existing.ExposeToActions == p.ExposeToActions
}

func assocEdgesEqual(existing, edges []*AssocEdge) bool {
if len(existing) != len(edges) {
return false
Expand Down
18 changes: 11 additions & 7 deletions internal/schema/input/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ type Field struct {
Nullable bool `json:"nullable,omitempty"`
StorageKey string `json:"storageKey,omitempty"`
// TODO need a way to indicate unique edge is Required also. this changes type generated in ent and graphql
Unique bool `json:"unique,omitempty"`
HideFromGraphQL bool `json:"hideFromGraphQL,omitempty"`
Private bool `json:"private,omitempty"`
GraphQLName string `json:"graphqlName,omitempty"`
Index bool `json:"index,omitempty"`
PrimaryKey bool `json:"primaryKey,omitempty"`
DefaultToViewerOnCreate bool `json:"defaultToViewerOnCreate,omitempty"`
Unique bool `json:"unique,omitempty"`
HideFromGraphQL bool `json:"hideFromGraphQL,omitempty"`
Private *PrivateOptions `json:"private,omitempty"`
GraphQLName string `json:"graphqlName,omitempty"`
Index bool `json:"index,omitempty"`
PrimaryKey bool `json:"primaryKey,omitempty"`
DefaultToViewerOnCreate bool `json:"defaultToViewerOnCreate,omitempty"`

FieldEdge *FieldEdge `json:"fieldEdge,omitempty"` // this only really makes sense on id fields...
ForeignKey *ForeignKey `json:"foreignKey,omitempty"`
Expand Down Expand Up @@ -198,6 +198,10 @@ type PolymorphicOptions struct {
DisableBuilderType bool `json:"disableBuilderType,omitempty"`
}

type PrivateOptions struct {
ExposeToActions bool `json:"exposeToActions,omitempty"`
}

func getTypeFor(nodeName, fieldName string, typ *FieldType, nullable bool, foreignKey *ForeignKey) (enttype.TSGraphQLType, error) {
switch typ.DBType {
case UUID:
Expand Down
31 changes: 29 additions & 2 deletions internal/schema/input/parse_ts_field_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,34 @@ func TestParseFields(t *testing.T) {
{
name: "password",
dbType: input.String,
private: true,
private: &input.PrivateOptions{},
},
},
},
},
},
"private field exposed to actions": {
code: map[string]string{
"user.ts": getCodeWithSchema(`
import {Schema, FieldMap, StringType} from "{schema}";
export default class User implements Schema {
fields: FieldMap = {
password: StringType({private: {
exposeToActions: true,
}}),
};
}`),
},
expectedNodes: map[string]node{
"User": {
fields: []field{
{
name: "password",
dbType: input.String,
private: &input.PrivateOptions{
ExposeToActions: true,
},
},
},
},
Expand Down Expand Up @@ -331,7 +358,7 @@ func TestParseFields(t *testing.T) {
field{
name: "password",
dbType: input.String,
private: true,
private: &input.PrivateOptions{},
hideFromGraphQL: true,
},
),
Expand Down
9 changes: 7 additions & 2 deletions internal/schema/input/parse_ts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type field struct {
storageKey string
unique bool
hideFromGraphQL bool
private bool
private *input.PrivateOptions
graphqlName string
index bool
primaryKey bool
Expand Down Expand Up @@ -210,7 +210,12 @@ func verifyField(t *testing.T, expField field, field *input.Field) {
assert.Equal(t, expField.nullable, field.Nullable)
assert.Equal(t, expField.unique, field.Unique)
assert.Equal(t, expField.hideFromGraphQL, field.HideFromGraphQL)
assert.Equal(t, expField.private, field.Private)
if expField.private == nil {
require.Nil(t, field.Private)
} else {
require.NotNil(t, field.Private)
assert.Equal(t, expField.private, field.Private)
}
assert.Equal(t, expField.graphqlName, field.GraphQLName)
assert.Equal(t, expField.index, field.Index)
assert.Equal(t, expField.primaryKey, field.PrimaryKey)
Expand Down
2 changes: 1 addition & 1 deletion ts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@snowtop/ent",
"version": "0.1.0-alpha58",
"version": "0.1.0-alpha59",
"description": "snowtop ent framework",
"main": "index.js",
"types": "index.d.ts",
Expand Down
11 changes: 11 additions & 0 deletions ts/src/parse_schema/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ function processFields(
} else {
delete f.polymorphic;
}
if (field.private) {
// convert boolean into object
// we keep boolean as an option to keep API simple
if (typeof field.private === "boolean") {
f.private = {};
} else {
f.private = field.private;
}
} else {
delete f.private;
}
// convert string to object to make API consumed by go simple
if (f.fieldEdge && f.fieldEdge.inverseEdge) {
if (typeof f.fieldEdge.inverseEdge === "string") {
Expand Down
9 changes: 8 additions & 1 deletion ts/src/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,10 @@ export interface FieldEdge {
disableBuilderType?: boolean;
}

interface PrivateOptions {
exposeToActions?: boolean;
}

// FieldOptions are configurable options for fields.
// Can be combined with options for specific field types as neededs
export interface FieldOptions {
Expand All @@ -376,7 +380,10 @@ export interface FieldOptions {
serverDefault?: any;
unique?: boolean;
hideFromGraphQL?: boolean;
private?: boolean;
// private automatically hides from graphql and actions
// but you may want something which is private and visible in actions
// e.g. because you have custom code you want to run in the accessors
private?: boolean | PrivateOptions;
sensitive?: boolean;
graphqlName?: string;
index?: boolean;
Expand Down

0 comments on commit 8de37f6

Please sign in to comment.