Skip to content

Commit

Permalink
Merge pull request #48 from sev-2/import/rpc
Browse files Browse the repository at this point in the history
fix(apply) fix import rpc
  • Loading branch information
toopay authored Jul 24, 2024
2 parents 954c9f4 + 3cda974 commit 5d2ba3f
Show file tree
Hide file tree
Showing 11 changed files with 509 additions and 87 deletions.
103 changes: 59 additions & 44 deletions pkg/generator/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,49 +118,8 @@ func GenerateModel(folderPath string, input *GenerateModelInput, generateFn Gene
// define file path
filePath := filepath.Join(folderPath, fmt.Sprintf("%s.%s", input.Table.Name, "go"))

// build relation tag
mapRelationName := make(map[string]bool)
relation := make([]state.Relation, 0)

for i := range input.Relations {
r := input.Relations[i]

if r.RelationType == raiden.RelationTypeManyToMany {
key := fmt.Sprintf("%s_%s", input.Table.Name, r.Table)
_, exist := mapRelationName[key]
if exist {
r.Table = inflection.Plural(r.Through)
key = fmt.Sprintf("%s_%s", input.Table.Name, r.Table)
mapRelationName[key] = true
} else {
mapRelationName[key] = true
}
}

if r.RelationType == raiden.RelationTypeHasOne {
snakeFk := utils.ToSnakeCase(r.ForeignKey)
fkTableSplit := strings.Split(snakeFk, "_")
fkName := inflection.Singular(utils.SnakeCaseToPascalCase(fkTableSplit[0]))

r.Table = inflection.Singular(utils.SnakeCaseToPascalCase(r.Table))
if fkName != r.Table {
r.Table = fmt.Sprintf("%s%s", r.Table, fkName)
}
}

if r.RelationType == raiden.RelationTypeHasMany {
snakeFk := utils.ToSnakeCase(r.ForeignKey)
fkTableSplit := strings.Split(snakeFk, "_")
fkName := inflection.Plural(utils.SnakeCaseToPascalCase(fkTableSplit[0]))
r.Table = inflection.Plural(utils.SnakeCaseToPascalCase(r.Table))
if fkName != r.Table {
r.Table = fmt.Sprintf("%s%s", inflection.Singular(r.Table), fkName)
}
}

r.Tag = BuildJoinTag(&r)
relation = append(relation, r)
}
// build relation field
relations := BuildRelationFields(input.Table, input.Relations)

// set data
data := GenerateModelData{
Expand All @@ -173,7 +132,7 @@ func GenerateModel(folderPath string, input *GenerateModelInput, generateFn Gene
RlsTag: rlsTag,
RlsEnable: input.Table.RLSEnabled,
RlsForced: input.Table.RLSForced,
Relations: relation,
Relations: relations,
}

// setup generate input param
Expand Down Expand Up @@ -338,3 +297,59 @@ func BuildJoinTag(r *state.Relation) string {

return strings.Join(tags, " ")
}

func BuildRelationFields(table objects.Table, relations []state.Relation) (mappedRelations []state.Relation) {
mapRelationName := make(map[string]bool)

for i := range relations {
r := relations[i]

if r.RelationType == raiden.RelationTypeHasOne {
snakeFk := utils.ToSnakeCase(r.ForeignKey)
fkTableSplit := strings.Split(snakeFk, "_")
fkName := inflection.Singular(utils.SnakeCaseToPascalCase(fkTableSplit[0]))

r.Table = inflection.Singular(utils.SnakeCaseToPascalCase(r.Table))
if fkName != r.Table {
r.Table = fmt.Sprintf("%s%s", r.Table, fkName)
}
mapRelationName[r.Table] = true
}

if r.RelationType == raiden.RelationTypeHasMany {
snakeFk := utils.ToSnakeCase(r.ForeignKey)
fkTableSplit := strings.Split(snakeFk, "_")
fkName := inflection.Plural(utils.SnakeCaseToPascalCase(fkTableSplit[0]))
r.Table = inflection.Plural(utils.SnakeCaseToPascalCase(r.Table))
if fkName != r.Table {
r.Table = fmt.Sprintf("%s%s", inflection.Singular(r.Table), fkName)
}
mapRelationName[r.Table] = true
}

if r.RelationType == raiden.RelationTypeManyToMany {
r.Table = inflection.Plural(r.Table)
_, exist := mapRelationName[r.Table]
if exist {
r.Table = inflection.Plural(r.Through)
}

_, exist = mapRelationName[r.Table]
if exist {
snakeFk := utils.ToSnakeCase(r.ForeignKey)
fkTableSplit := strings.Split(snakeFk, "_")
fkName := inflection.Plural(utils.SnakeCaseToPascalCase(fkTableSplit[0]))
r.Table = inflection.Plural(utils.SnakeCaseToPascalCase(r.Table))
if fkName != r.Table {
r.Table = fmt.Sprintf("%s%s", inflection.Singular(r.Table), fkName)
}
}
mapRelationName[r.Table] = true
}

r.Tag = BuildJoinTag(&r)
mappedRelations = append(mappedRelations, r)
}

return
}
20 changes: 20 additions & 0 deletions pkg/generator/model_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package generator_test

import (
"encoding/json"
"os"
"path/filepath"
"testing"
Expand Down Expand Up @@ -55,3 +56,22 @@ func TestGenerateModels(t *testing.T) {
assert.NoError(t, err2)
assert.FileExists(t, dir+"/internal/models/test_table.go")
}

func TestBuildRelationFields(t *testing.T) {
table := objects.Table{
Name: "profiles",
}
relationStr := `[{"Table":"places","Type":"[]*Places","RelationType":"manyToMany","PrimaryKey":"","ForeignKey":"","Tag":"","SourcePrimaryKey":"id","JoinsSourceForeignKey":"profile_id","TargetPrimaryKey":"id","JoinTargetForeignKey":"place_id","Through":"place_likes"},{"Table":"followers","Type":"[]*Followers","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"food_review_likes","Type":"[]*FoodReviewLikes","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"food_review_buddies","Type":"[]*FoodReviewBuddies","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"place_reviews","Type":"[]*PlaceReviews","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"place_likes","Type":"[]*PlaceLikes","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"collections","Type":"[]*Collections","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"chat_messages","Type":"[]*ChatMessages","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"place_review_likes","Type":"[]*PlaceReviewLikes","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"contact_numbers","Type":"[]*ContactNumbers","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"food_likes","Type":"[]*FoodLikes","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"place_review_buddies","Type":"[]*PlaceReviewBuddies","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"profile_badges","Type":"[]*ProfileBadges","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"place_check_ins","Type":"[]*PlaceCheckIns","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"food_reviews","Type":"[]*FoodReviews","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"posts","Type":"[]*Posts","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"activity_logs","Type":"[]*ActivityLogs","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"social_media_accounts","Type":"[]*SocialMediaAccounts","RelationType":"hasMany","PrimaryKey":"id","ForeignKey":"profile_id","Tag":""},{"Table":"places","Type":"[]*Places","RelationType":"manyToMany","PrimaryKey":"","ForeignKey":"","Tag":"","SourcePrimaryKey":"id","JoinsSourceForeignKey":"profile_id","TargetPrimaryKey":"id","JoinTargetForeignKey":"place_id","Through":"place_reviews"},{"Table":"place_reviews","Type":"[]*PlaceReviews","RelationType":"manyToMany","PrimaryKey":"","ForeignKey":"","Tag":"","SourcePrimaryKey":"id","JoinsSourceForeignKey":"profile_id","TargetPrimaryKey":"id","JoinTargetForeignKey":"place_review_id","Through":"place_review_likes"},{"Table":"collection_types","Type":"[]*CollectionTypes","RelationType":"manyToMany","PrimaryKey":"","ForeignKey":"","Tag":"","SourcePrimaryKey":"id","JoinsSourceForeignKey":"profile_id","TargetPrimaryKey":"id","JoinTargetForeignKey":"collection_type_id","Through":"collections"},{"Table":"foods","Type":"[]*Foods","RelationType":"manyToMany","PrimaryKey":"","ForeignKey":"","Tag":"","SourcePrimaryKey":"id","JoinsSourceForeignKey":"profile_id","TargetPrimaryKey":"id","JoinTargetForeignKey":"food_id","Through":"food_likes"},{"Table":"food_reviews","Type":"[]*FoodReviews","RelationType":"manyToMany","PrimaryKey":"","ForeignKey":"","Tag":"","SourcePrimaryKey":"id","JoinsSourceForeignKey":"profile_id","TargetPrimaryKey":"id","JoinTargetForeignKey":"food_review_id","Through":"food_review_likes"},{"Table":"places","Type":"[]*Places","RelationType":"manyToMany","PrimaryKey":"","ForeignKey":"","Tag":"","SourcePrimaryKey":"id","JoinsSourceForeignKey":"profile_id","TargetPrimaryKey":"id","JoinTargetForeignKey":"place_id","Through":"place_check_ins"},{"Table":"place_reviews","Type":"[]*PlaceReviews","RelationType":"manyToMany","PrimaryKey":"","ForeignKey":"","Tag":"","SourcePrimaryKey":"id","JoinsSourceForeignKey":"profile_id","TargetPrimaryKey":"id","JoinTargetForeignKey":"place_review_id","Through":"place_review_buddies"},{"Table":"food_reviews","Type":"[]*FoodReviews","RelationType":"manyToMany","PrimaryKey":"","ForeignKey":"","Tag":"","SourcePrimaryKey":"id","JoinsSourceForeignKey":"profile_id","TargetPrimaryKey":"id","JoinTargetForeignKey":"food_review_id","Through":"food_review_buddies"},{"Table":"badges","Type":"[]*Badges","RelationType":"manyToMany","PrimaryKey":"","ForeignKey":"","Tag":"","SourcePrimaryKey":"id","JoinsSourceForeignKey":"profile_id","TargetPrimaryKey":"id","JoinTargetForeignKey":"badge_id","Through":"profile_badges"},{"Table":"foods","Type":"[]*Foods","RelationType":"manyToMany","PrimaryKey":"","ForeignKey":"","Tag":"","SourcePrimaryKey":"id","JoinsSourceForeignKey":"profile_id","TargetPrimaryKey":"id","JoinTargetForeignKey":"food_id","Through":"food_reviews"}]`
relations := make([]state.Relation, 0)
err := json.Unmarshal([]byte(relationStr), &relations)
assert.NoError(t, err)

result := generator.BuildRelationFields(table, relations)

mapTable := make(map[string]bool)
for _, v := range result {
_, exist := mapTable[v.Table]
assert.False(t, exist)
mapTable[v.Table] = true
}
}
67 changes: 46 additions & 21 deletions pkg/generator/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (r *{{ .Name }}) GetRawDefinition() string {
}`
)

func GenerateRpc(basePath string, projectName string, functions []objects.Function, generateFn GenerateFn) (err error) {
func GenerateRpc(basePath string, projectName string, functions []objects.Function, tables []objects.Table, generateFn GenerateFn) (err error) {
folderPath := filepath.Join(basePath, RpcDir)
RpcLogger.Trace("create rpc folder if not exist", "path", folderPath)
if exist := utils.IsFolderExists(folderPath); !exist {
Expand All @@ -153,15 +153,15 @@ func GenerateRpc(basePath string, projectName string, functions []objects.Functi

for i := range functions {
f := functions[i]
if err := generateRpcItem(folderPath, projectName, &f, generateFn); err != nil {
if err := generateRpcItem(folderPath, projectName, &f, tables, generateFn); err != nil {
return err
}
}

return nil
}

func generateRpcItem(folderPath string, projectName string, function *objects.Function, generateFn GenerateFn) error {
func generateRpcItem(folderPath string, projectName string, function *objects.Function, tables []objects.Table, generateFn GenerateFn) error {
// define binding func
funcMaps := []template.FuncMap{
{"ToSnakeCase": utils.ToSnakeCase},
Expand All @@ -178,7 +178,7 @@ func generateRpcItem(folderPath string, projectName string, function *objects.Fu
filePath := filepath.Join(folderPath, fmt.Sprintf("%s.%s", utils.ToSnakeCase(function.Name), "go"))

// // extract rpc function
result, err := ExtractRpcFunction(function)
result, err := ExtractRpcFunction(function, tables)
if err != nil {
return err
}
Expand Down Expand Up @@ -240,7 +240,7 @@ func generateRpcItem(folderPath string, projectName string, function *objects.Fu
return generateFn(generateInput, nil)
}

func ExtractRpcFunction(fn *objects.Function) (result ExtractRpcDataResult, err error) {
func ExtractRpcFunction(fn *objects.Function, tables []objects.Table) (result ExtractRpcDataResult, err error) {
// extract param
params, usePrefix, e := ExtractRpcParam(fn)
if e != nil {
Expand All @@ -256,6 +256,21 @@ func ExtractRpcFunction(fn *objects.Function) (result ExtractRpcDataResult, err
return
}

// validate to actual exist table
if len(tables) > 0 {
mapTable := make(map[string]any)
for _, v := range tables {
mapTable[v.Name] = true
}

for k := range mapScannedTable {
_, exist := mapTable[k]
if !exist {
delete(mapScannedTable, k)
}
}
}

// normalize aliases
if e := RpcNormalizeTableAliases(mapScannedTable); e != nil {
err = e
Expand Down Expand Up @@ -371,7 +386,8 @@ func ExtractRpcParam(fn *objects.Function) (params []raiden.RpcParam, usePrefix
pt = strings.TrimLeft(strings.TrimRight(pt, " "), " ")
paramType, err := raiden.GetValidRpcParamType(pt, true)
if err != nil {
return params, usePrefix, err
err = fmt.Errorf("got error in rpc '%s' return param type > %s", fn.Name, err.Error())
return params, usePrefix, fmt.Errorf("%s %s", fa.Name, err.Error())
}
p.Type = paramType
}
Expand All @@ -390,6 +406,7 @@ func ExtractRpcParam(fn *objects.Function) (params []raiden.RpcParam, usePrefix

// code for detect table in query and return array of object contain table name, table aliases and relation
func ExtractRpcTable(def string) (string, map[string]*RpcScannedTable, error) {
def = removeSQLComments(def)
dFields := strings.Fields(utils.CleanUpString(def))
mapResult := make(map[string]*RpcScannedTable)
mapTableOrAlias := make(map[string]string)
Expand All @@ -407,14 +424,15 @@ func ExtractRpcTable(def string) (string, map[string]*RpcScannedTable, error) {
k := strings.ToUpper(f)

switch k {
case postgres.Create, postgres.Update, postgres.Delete, postgres.Alter:
case postgres.Create, postgres.Update, postgres.Delete, postgres.Alter, postgres.With:
readMode = false
case postgres.Select, postgres.With:
case postgres.Select:
readMode = true
}

switch lastField {
case postgres.From:
// stop condition
if postgres.IsReservedKeyword(k) {
mapResult[foundTable.Name] = foundTable
mapTableOrAlias[foundTable.Name] = foundTable.Name
Expand All @@ -426,6 +444,10 @@ func ExtractRpcTable(def string) (string, map[string]*RpcScannedTable, error) {
continue
}

if postgres.IsReservedSymbol(f) || k[0] == '(' || k[0] == ')' {
continue
}

if len(foundTable.Name) == 0 {
split := strings.Split(f, ".")
if len(split) == 2 {
Expand All @@ -434,9 +456,6 @@ func ExtractRpcTable(def string) (string, map[string]*RpcScannedTable, error) {
}
foundTable.Name = f
} else {
if postgres.IsReservedSymbol(f) {
continue
}
foundTable.Alias = f
}
case postgres.Inner, postgres.Outer, postgres.Left, postgres.Right:
Expand All @@ -445,7 +464,7 @@ func ExtractRpcTable(def string) (string, map[string]*RpcScannedTable, error) {
continue
}
case postgres.Join, postgres.InnerJoin, postgres.OuterJoin, postgres.LeftJoin, postgres.RightJoin:
if k == postgres.On {
if k == postgres.On || postgres.IsReservedSymbol(f) || k[0] == '(' || k[0] == ')' {
lastField = k
continue
}
Expand All @@ -458,13 +477,10 @@ func ExtractRpcTable(def string) (string, map[string]*RpcScannedTable, error) {
}
foundTable.Name = f
} else {
if postgres.IsReservedSymbol(f) {
continue
}
foundTable.Alias = f
}
case postgres.On:
if !readMode {
if !readMode || k[0] == '(' || k[0] == ')' {
lastField = k
continue
}
Expand Down Expand Up @@ -525,8 +541,6 @@ func ExtractRpcTable(def string) (string, map[string]*RpcScannedTable, error) {
}
}

fmt.Printf("mapResult : %+v\n", mapResult)

return strings.Join(dFields, " "), mapResult, nil
}

Expand All @@ -539,7 +553,7 @@ func RpcNormalizeTableAliases(mapTables map[string]*RpcScannedTable) error {
}

for _, v := range mapTables {
if v.Alias != "" && v.Name != "" {
if (v.Alias != "" && v.Name != "") || v.Name == "" {
continue
}
newAlias := findAvailableAlias(v.Name, mapAlias, 1)
Expand Down Expand Up @@ -572,7 +586,7 @@ func bindModelToDefinition(def string, mapTable map[string]*RpcScannedTable, par
}

func findAvailableAlias(tableName string, mapAlias map[string]bool, sub int) (alias string) {
if len(tableName) == sub {
if sub >= len(tableName) {
return ""
}

Expand Down Expand Up @@ -677,7 +691,7 @@ func (r *ExtractRpcDataResult) GetReturn(mapImports map[string]bool) (returnDecl
cName := splitC[0]
cType, e := raiden.GetValidRpcParamType(splitC[1], true)
if e != nil {
err = e
err = fmt.Errorf("got error in rpc '%s' return table in column %s > %s", r.Rpc.Name, splitC[0], e.Error())
return
}

Expand Down Expand Up @@ -746,3 +760,14 @@ func (r *ExtractRpcDataResult) GetBehavior() (behavior string) {
return "RpcBehaviorVolatile"
}
}

func removeSQLComments(query string) string {
lines := strings.Split(query, "\n")
var result []string
for _, line := range lines {
if !strings.HasPrefix(strings.TrimSpace(line), "--") {
result = append(result, line)
}
}
return strings.Join(result, "\n")
}
Loading

0 comments on commit 5d2ba3f

Please sign in to comment.