diff --git a/client.go b/client.go index 183ad1b..1daac73 100644 --- a/client.go +++ b/client.go @@ -2,6 +2,7 @@ package eywa import ( "bytes" + "context" "encoding/json" "fmt" "io" @@ -40,7 +41,7 @@ func NewClient(gqlEndpoint string, opt *ClientOpts) *Client { return c } -func (c *Client) Do(q Queryable) (*bytes.Buffer, error) { +func (c *Client) Do(ctx context.Context, q Queryable) (*bytes.Buffer, error) { reqObj := graphqlRequest{ Query: q.Query(), Variables: q.Variables(), @@ -51,7 +52,7 @@ func (c *Client) Do(q Queryable) (*bytes.Buffer, error) { if err != nil { return nil, err } - req, err := http.NewRequest(http.MethodPost, c.endpoint, &reqBytes) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.endpoint, &reqBytes) if err != nil { return nil, err } diff --git a/cmd/eywagen/eywatest/eywa_generated.go b/cmd/eywagen/eywatest/eywa_generated.go index ec941d7..05edd7a 100644 --- a/cmd/eywagen/eywatest/eywa_generated.go +++ b/cmd/eywagen/eywatest/eywa_generated.go @@ -3,11 +3,13 @@ package eywatest import ( "github.com/imperfect-fourth/eywa" + "fmt" "bytes" "github.com/google/uuid" ) +var testTable_PkeyConstraint = eywa.Constraint[testTable](fmt.Sprintf("%s_pkey", (new(testTable)).TableName())) const testTable_Name eywa.FieldName[testTable] = "name" func testTable_NameField(val string) eywa.Field[testTable] { @@ -38,7 +40,6 @@ func testTable_AgeVar(val *int) eywa.Field[testTable] { Value: eywa.QueryVar("testTable_Age", eywa.NullableIntVar[*int](val)), } } -const testTable_PkeyConstraint eywa.Constraint[testTable] = "testTable_pkey" const testTable_ID eywa.FieldName[testTable] = "id" func testTable_IDField(val int) eywa.Field[testTable] { @@ -86,7 +87,7 @@ func testTable_customVar[T interface{eywa.JSONValue | eywa.JSONBValue;eywa.Typed } func testTable_testTable2(subField eywa.FieldName[testTable2], subFields ...eywa.FieldName[testTable2]) eywa.FieldName[testTable] { - buf := bytes.NewBuffer([]byte("test_table2 {\n")) + buf := bytes.NewBuffer([]byte("testTable2 {\n")) buf.WriteString(string(subField)) for _, f := range subFields { buf.WriteString("\n") @@ -156,7 +157,7 @@ func testTable_FVar(val X[string, int]) eywa.Field[testTable] { } } -const testTable2_PkeyConstraint eywa.Constraint[testTable2] = "testTable2_pkey" +var testTable2_PkeyConstraint = eywa.Constraint[testTable2](fmt.Sprintf("%s_pkey", (new(testTable2)).TableName())) const testTable2_ID eywa.FieldName[testTable2] = "id" func testTable2_IDField(val uuid.UUID) eywa.Field[testTable2] { diff --git a/cmd/eywagen/eywatest/eywa_test.go b/cmd/eywagen/eywatest/eywa_test.go index 3dc8243..2a9a17f 100644 --- a/cmd/eywagen/eywatest/eywa_test.go +++ b/cmd/eywagen/eywatest/eywa_test.go @@ -59,7 +59,7 @@ func TestRelationshipSelectQuery(t *testing.T) { expected := `query get_test_table { test_table(limit: 2, offset: 1, distinct_on: name, where: {_or: [{name: {_eq: "abcd"}}, {age: {_eq: 10}}]}, order_by: {name: desc}) { -test_table2 { +testTable2 { id } name @@ -135,8 +135,8 @@ func TestInsertOneQuery(t *testing.T) { ).Select( testTable2_ID, ) - expected := fmt.Sprintf(`mutation insert_test_table2_one { -insert_test_table2_one(object: {id: "%s"}) { + expected := fmt.Sprintf(`mutation insert_testTable2_one { +insert_testTable2_one(object: {id: "%s"}) { id } }`, id.String()) @@ -181,8 +181,8 @@ func TestInsertOneQueryOnConflict(t *testing.T) { testTable2_ID, testTable2_Age, ) - expected := fmt.Sprintf(`mutation insert_test_table2_one { -insert_test_table2_one(object: {age: 20, id: "%s"}, on_conflict: {constraint: testTable2_pkey, update_columns: [age]}) { + expected := fmt.Sprintf(`mutation insert_testTable2_one { +insert_testTable2_one(object: {age: 20, id: "%s"}, on_conflict: {constraint: testTable2_pkey, update_columns: [age]}) { age id } diff --git a/cmd/eywagen/eywatest/eywatest.go b/cmd/eywagen/eywatest/eywatest.go index 33b7abb..9bd43e2 100644 --- a/cmd/eywagen/eywatest/eywatest.go +++ b/cmd/eywagen/eywatest/eywatest.go @@ -12,7 +12,7 @@ type testTable struct { ID int `json:"id,omitempty",eywa:"pkey"` IDd int32 `json:"idd,omitempty"` custom *customType `json:"custom"` - testTable2 *testTable2 `json:"test_table2"` + testTable2 *testTable2 `json:"testTable2"` JsonBCol jsonbcol `json:"jsonb_col"` RR R `json:"r"` Status eywa.Enum[status] `json:"status"` @@ -29,6 +29,10 @@ var ( type R string +func (t testTable) TableName() string { + return "test_table" +} + func (t testTable) ModelName() string { return "test_table" } @@ -40,8 +44,11 @@ type testTable2 struct { Age int `json:"age"` } +func (t testTable2) TableName() string { + return "testTable2" +} func (t testTable2) ModelName() string { - return "test_table2" + return "testTable2" } type jsonbcol struct { diff --git a/cmd/eywagen/main.go b/cmd/eywagen/main.go index e5d9429..611ee67 100644 --- a/cmd/eywagen/main.go +++ b/cmd/eywagen/main.go @@ -23,7 +23,6 @@ func usage() { } var tagPattern = re.MustCompile(`json:"([^"]+)"`) -var eywaTagPattern = re.MustCompile(`eywa:"([^"]+)"`) const ( genHeader = "// generated by eywa. DO NOT EDIT. Any changes will be overwritten.\npackage " @@ -68,7 +67,7 @@ func %s(subField eywa.FieldName[%s], subFields ...eywa.FieldName[%s]) eywa.Field ) func pkeyConstraint(typeName string) string { - return fmt.Sprintf("const %s_PkeyConstraint eywa.Constraint[%s] = \"%s_pkey\"\n", typeName, typeName, typeName) + return fmt.Sprintf("var %s_PkeyConstraint = eywa.Constraint[%s](fmt.Sprintf(\"%%s_pkey\", (new(%s)).TableName()))\n", typeName, typeName, typeName) } func main() { @@ -146,9 +145,8 @@ func parseType(typeName string, pkg *types.Package, contents *fileContent) error } contents.content.WriteString("\n") + contents.content.WriteString(pkeyConstraint(typeName)) recurseParse := make([]string, 0, typeStruct.NumFields()) - foundPkey := false - pkey := "" for i := 0; i < typeStruct.NumFields(); i++ { tag := tagPattern.FindStringSubmatch(typeStruct.Tag(i)) if tag == nil { @@ -159,20 +157,7 @@ func parseType(typeName string, pkg *types.Package, contents *fileContent) error continue } fieldName := tagValues[0] - if eywaTag := eywaTagPattern.FindStringSubmatch(typeStruct.Tag(i)); eywaTag != nil { - if eywaTagValues := strings.Split(eywaTag[1], ","); len(eywaTagValues) != 0 { - for _, v := range eywaTagValues { - if v == "pkey" && foundPkey { - return fmt.Errorf("model %s has two primary keys: %s, %s", typeName, pkey, fieldName) - } - if v == "pkey" { - foundPkey = true - contents.content.WriteString(pkeyConstraint(typeName)) - pkey = fieldName - } - } - } - } + contents.importsMap["fmt"] = true field := typeStruct.Field(i) fieldType := field.Type() importPackages, fieldTypeNameFull := parseFieldTypeName(field.Type().String(), pkg.Path()) diff --git a/eywa.go b/eywa.go index cf5be29..a6e49b5 100644 --- a/eywa.go +++ b/eywa.go @@ -19,6 +19,7 @@ type GraphQLError struct { type Model interface { ModelName() string + TableName() string } type ModelPtr[T Model] interface { diff --git a/get.go b/get.go index 8afe883..c7e83db 100644 --- a/get.go +++ b/get.go @@ -1,6 +1,7 @@ package eywa import ( + "context" "encoding/json" "errors" "fmt" @@ -82,7 +83,11 @@ func (sq GetQuery[M]) Variables() map[string]interface{} { } func (sq GetQuery[M]) Exec(client *Client) ([]M, error) { - respBytes, err := client.Do(sq) + return sq.ExecWithContext(context.Background(), client) +} + +func (sq GetQuery[M]) ExecWithContext(ctx context.Context, client *Client) ([]M, error) { + respBytes, err := client.Do(ctx, sq) if err != nil { return nil, err } diff --git a/insert_one.go b/insert_one.go index 2ef9da3..84c8a0c 100644 --- a/insert_one.go +++ b/insert_one.go @@ -1,6 +1,7 @@ package eywa import ( + "context" "encoding/json" "fmt" ) @@ -77,7 +78,10 @@ func (iq InsertOneQuery[M]) Variables() map[string]interface{} { } func (iq InsertOneQuery[M]) Exec(client *Client) (*M, error) { - respBytes, err := client.Do(iq) + return iq.ExecWithContext(context.Background(), client) +} +func (iq InsertOneQuery[M]) ExecWithContext(ctx context.Context, client *Client) (*M, error) { + respBytes, err := client.Do(ctx, iq) if err != nil { return nil, err } diff --git a/unsafe/actions.go b/unsafe/actions.go index 69c38f5..2369ee6 100644 --- a/unsafe/actions.go +++ b/unsafe/actions.go @@ -2,6 +2,7 @@ package unsafe import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -93,7 +94,7 @@ func (aq ActionQuery[M]) Variables() map[string]interface{} { } func (aq ActionQuery[M]) Exec(client *eywa.Client) (*M, error) { - respBytes, err := client.Do(aq) + respBytes, err := client.Do(context.Background(), aq) if err != nil { return nil, err } diff --git a/unsafe/actions_test.go b/unsafe/actions_test.go index db7efdf..1e7de81 100644 --- a/unsafe/actions_test.go +++ b/unsafe/actions_test.go @@ -14,6 +14,9 @@ type testAction struct { func (a testAction) ModelName() string { return "test_action" } +func (a testAction) TableName() string { + return "test_action" +} func TestActionQuery(t *testing.T) { const state2 = "state2" diff --git a/update.go b/update.go index 3f4e970..3b2d9a7 100644 --- a/update.go +++ b/update.go @@ -1,6 +1,7 @@ package eywa import ( + "context" "encoding/json" "fmt" ) @@ -81,7 +82,11 @@ func (uq UpdateQuery[M]) Variables() map[string]interface{} { } func (uq UpdateQuery[M]) Exec(client *Client) ([]M, error) { - respBytes, err := client.Do(uq) + return uq.ExecWithContext(context.Background(), client) +} + +func (uq UpdateQuery[M]) ExecWithContext(ctx context.Context, client *Client) ([]M, error) { + respBytes, err := client.Do(ctx, uq) if err != nil { return nil, err }