// PgLoadTables loads the table definitions from the database, writing the // resulting templates to typeMap and returning the created templates.TableTemplates. func PgLoadTables(args *internal.ArgType, db *sql.DB, typeMap map[string]*bytes.Buffer) (map[string]*templates.TableTemplate, error) { var err error // load columns cols, err := models.ColumnsByRelkindSchema(db, "r", args.Schema) if err != nil { return nil, err } // process columns fieldMap := map[string]map[string]bool{} tableMap := map[string]*templates.TableTemplate{} for _, c := range cols { if _, ok := fieldMap[c.TableName]; !ok { fieldMap[c.TableName] = map[string]bool{} } // set col info c.Field = snaker.SnakeToCamel(c.ColumnName) c.Len, c.NilType, c.Type = PgParseType(args, c.DataType, c.IsNullable) // set value in table map if not present if _, ok := tableMap[c.TableName]; !ok { tableMap[c.TableName] = &templates.TableTemplate{ Type: inflector.Singularize(snaker.SnakeToCamel(c.TableName)), TableSchema: args.Schema, TableName: c.TableName, Fields: []*models.Column{}, } } // set primary key if c.IsPrimaryKey { tableMap[c.TableName].PrimaryKey = c.ColumnName tableMap[c.TableName].PrimaryKeyField = c.Field tableMap[c.TableName].PrimaryKeyType = c.Type } // append col to template fields if _, ok := fieldMap[c.TableName][c.ColumnName]; !ok { tableMap[c.TableName].Fields = append(tableMap[c.TableName].Fields, c) } fieldMap[c.TableName][c.ColumnName] = true } // generate table templates for _, t := range tableMap { buf := GetBuf(typeMap, strings.ToLower(t.Type)) err = templates.Tpls["postgres.model.go.tpl"].Execute(buf, t) if err != nil { return nil, err } } return tableMap, nil }
// PgParseQuery parses the query and generates a type for it. func PgParseQuery(args *internal.ArgType, db *sql.DB, typeMap map[string]*bytes.Buffer) error { var err error // parse supplied query queryStr, params := parseQuery(args, args.Query, "$%d") inspectStr, _ := parseQuery(args, args.Query, "NULL") // strip out if args.QueryStrip { queryStr = queryStripRE.ReplaceAllString(queryStr, "") } // split up query and inspect based on lines query := strings.Split(queryStr, "\n") inspect := strings.Split(inspectStr, "\n") // build query comments with stripped values // FIXME: this is off by one, because of golang template syntax limitations queryComments := make([]string, len(query)+1) if args.QueryStrip { for i, l := range inspect { pos := queryStripRE.FindStringIndex(l) if pos != nil { queryComments[i+1] = l[pos[0]:pos[1]] } else { queryComments[i+1] = "" } } } // trim whitespace if applicable if args.QueryTrim { for n, l := range query { query[n] = strings.TrimSpace(l) if n < len(query)-1 { query[n] = query[n] + " " } } for n, l := range inspect { inspect[n] = strings.TrimSpace(l) if n < len(inspect)-1 { inspect[n] = inspect[n] + " " } } } // create temporary view xoid xoid := "_xo_" + genRandomID() viewq := `CREATE TEMPORARY VIEW ` + xoid + ` AS (` + strings.Join(inspect, "\n") + `)` _, err = db.Exec(viewq) if err != nil { return err } // determine schema name temporary view was created on // sql query var nspq = `SELECT n.nspname ` + `FROM pg_class c ` + `JOIN pg_namespace n ON n.oid = c.relnamespace ` + `WHERE n.nspname LIKE 'pg_temp%' AND c.relname = $1` // run schema query var schema string err = db.QueryRow(nspq, xoid).Scan(&schema) if err != nil { return err } // load column information ("v" == view) cols, err := models.ColumnsByRelkindSchema(db, "v", schema) if err != nil { return err } // create template for query type typeTpl := &templates.TableTemplate{ Type: args.QueryType, TableSchema: args.Schema, Fields: []*models.Column{}, Comment: args.QueryTypeComment, } // process columns for _, c := range cols { c.Field = snaker.SnakeToCamel(c.ColumnName) c.Len, c.NilType, c.Type = PgParseType(args, c.DataType, false) typeTpl.Fields = append(typeTpl.Fields, c) } // generate query type template buf := GetBuf(typeMap, strings.ToLower(args.QueryType)) err = templates.Tpls["postgres.model.go.tpl"].Execute(buf, typeTpl) if err != nil { return err } // build func name funcName := args.QueryFunc if funcName == "" { // no func name specified, so generate based on type if args.QueryOnlyOne { funcName = args.QueryType } else { funcName = inflector.Pluralize(args.QueryType) } // affix any params if len(params) == 0 { funcName = "Get" + funcName } else { funcName = funcName + "By" for _, p := range params { funcName = funcName + strings.ToUpper(p[0][:1]) + p[0][1:] } } } // create func template funcTpl := &templates.FuncTemplate{ Name: funcName, Type: args.QueryType, Query: query, QueryComments: queryComments, Parameters: params, OnlyOne: args.QueryOnlyOne, Comment: args.QueryFuncComment, Table: typeTpl, } // generate template err = templates.Tpls["postgres.func.go.tpl"].Execute(buf, funcTpl) if err != nil { return err } return nil }