Ejemplo n.º 1
0
// 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
}
Ejemplo n.º 2
0
// 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
}