18 июля 2021

πŸ›  ВзаимодСйствиС MySQL ΠΈ Go: ΠΏΠΎΠ΄Π²ΠΎΠ΄Π½Ρ‹Π΅ ΠΊΠ°ΠΌΠ½ΠΈ автоматичСской ΠΊΠΎΠ΄ΠΎΠ³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ

backend Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ с 15 Π»Π΅Ρ‚Π½ΠΈΠΌ стаТСм ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΡŽΡΡŒ Π½Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠ² ΠΏΠΎΠ΄ Π²Ρ‹ΡΠΎΠΊΡƒΡŽ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ
Π‘ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²ΠΎ статСй ΠΏΡ€ΠΎ использованиС MySQL Π² Golang повторяСт ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΈΠ· ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ руководства. РСальная Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π΄Π°Π»Π΅ΠΊΠ° ΠΎΡ‚ простых ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ²: ΠΈΠ·-Π·Π° строгой Ρ‚ΠΈΠΏΠΈΠ·Π°Ρ†ΠΈΠΈ часто Π²ΠΎΠ·Π½ΠΈΠΊΠ°ΡŽΡ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹. РазбираСмся с ΠΈΡ… Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ΠΌ, Ссли Π²Π°ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΌΠ½ΠΎΠ³ΠΎ ΠΎΠ΄Π½ΠΎΡ‚ΠΈΠΏΠ½Ρ‹Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ.
πŸ›  ВзаимодСйствиС MySQL ΠΈ Go: ΠΏΠΎΠ΄Π²ΠΎΠ΄Π½Ρ‹Π΅ ΠΊΠ°ΠΌΠ½ΠΈ автоматичСской ΠΊΠΎΠ΄ΠΎΠ³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ

Π’Π²Π΅Π΄Π΅Π½ΠΈΠ΅ Π² ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ

Для ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ всё ΠΎΡ‡Π΅Π½ΡŒ просто Π² скриптовых языках, Π²Ρ€ΠΎΠ΄Π΅ PHP ΠΈΠ»ΠΈ Python: Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· Π±Π°Π·Ρ‹ мапятся Π² ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ, доступ ΠΊ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠ°ΠΊ ΠΏΠΎ ΠΈΠΌΠ΅Π½ΠΈ поля, Ρ‚Π°ΠΊ ΠΈ ΠΏΠΎ Π΅Π³ΠΎ Π½ΠΎΠΌΠ΅Ρ€Ρƒ Π² датасСтС.

Π’ Go всС устроСно Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΈΠ½Π°Ρ‡Π΅: это язык строгой Ρ‚ΠΈΠΏΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΈ Π΄Π°Π½Π½Ρ‹Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΈΠΏΠ°ΠΌ, Π° количСство ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡΠΎΠ²ΠΏΠ°Π΄Π°Ρ‚ΡŒ с количСством принятых Π΄Π°Π½Π½Ρ‹Ρ…. Запросы Ρ‚ΠΈΠΏΠ° SELECT * подходят Π΄Π°Π»Π΅ΠΊΠΎ Π½Π΅ всСгда, Π° ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΠ»Π΅ΠΉ становится большС дСсяти, ΠΎΡ‚Π»Π°ΠΆΠΈΠ²Π°Π½ΠΈΠ΅ запроса прСвращаСтся Π² ΠΌΡƒΠΊΡƒ.

Π’ΠΎΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΈΠ· руководства:

           // Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ запроса
    results, err := db.Query("SELECT id, name FROM tags")
    if err != nil {
        panic(err.Error()) // ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибки
    }

    for results.Next() {
        var id   int
      var name string

        // Ρ‚ΡƒΡ‚ пСрСписываСм Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π² наши ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅
        err = results.Scan(&id, &name)
        if err != nil {
            panic(err.Error()) 
        }
}

    

ΠŸΡ€ΠΈ использовании Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Row.Scan Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΠ·Π²Π»Π΅Ρ‡ΡŒ ΠΈΠ· Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… Π΄Π²Π° поля, Ρ‚.Π΅. Π½Π°ΠΌ потрСбуСтся ΠΎΠ±ΡŠΡΠ²ΠΈΡ‚ΡŒ всСго Π΄Π²Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅. Если Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΠ·Π²Π»Π΅Ρ‡ΡŒ 10 ΠΏΠΎΠ»Π΅ΠΉ, Π½ΡƒΠΆΠ½ΠΎ ΡƒΠΆΠ΅ 10 ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ…. А Ссли ΠΏΠΎΠ»Π΅ΠΉ Π±ΠΎΠ»Π΅Π΅ 20? На ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΈ с полусотнСй ΠΏΠΎΠ»Π΅ΠΉ, Ρ‚ΠΎΠ³Π΄Π° написаниС ΠΊΠΎΠ΄Π° прСвращаСтся Π² ад… И Ρ‚ΡƒΡ‚ Π½Π°ΠΌ Π½Π° ΠΏΠΎΠΌΠΎΡ‰ΡŒ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΡ‚ кодогСнСрация.

Как Π·Π°ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΌΠ°ΡˆΠΈΠ½Ρƒ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡΡŽΡ‰ΠΈΠΉΡΡ ΠΊΠΎΠ΄?

Π’ MySQL Π΅ΡΡ‚ΡŒ конструкция DESCRIBE, которая описываСт структуру Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ эту ΠΊΠΎΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ, ΠΌΠΎΠΆΠ½ΠΎ ΡΠ³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ:

  • объявлСниС списка ΠΏΠΎΠ»Π΅ΠΉ;
  • списки ΠΏΠΎΠ»Π΅ΠΉ для ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠ² SELECT, INSERT ΠΈΠ»ΠΈ UPDATE;
  • список ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… для Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Scan;
  • Π³ΠΎΡ‚ΠΎΠ²Ρ‹Π΅ Ρ‚ΠΈΠΏΠΎΠ²Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ для Π²Ρ‹Π±ΠΎΡ€ΠΊΠΈ/вставки Π΄Π°Π½Π½Ρ‹Ρ….

Π”Π°Π½Π½Ρ‹Π΅ ΠΈΠ· запроса DESCRIBE <имя Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹> заносим Π² структуру:

        type Field struct {
    name  string      // имя поля
    ftype string      // Ρ‚ΠΈΠΏ поля
    sqltype string    // Ρ‚ΠΈΠΏ SQL поля
    fn_conv string    // имя Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ прСобразования
}

    

ΠŸΡ€ΠΎ послСдниС Π΄Π²Π° поля ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠΌ Ρ‡ΡƒΡ‚ΡŒ ΠΏΠΎΠΏΠΎΠ·ΠΆΠ΅. Из этой структуры ΠΌΠΎΠΆΠ½ΠΎ ΡΠ³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ список ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… ΠΈ список ΠΏΠΎΠ»Π΅ΠΉ Π±Π΅Π·ΠΎ всякого Π°Π½Π°Π»ΠΈΠ·Π° ΠΈ построСния AST (abstract syntax structure):

Для ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° взята Ρ‚Π°Π±Π»ΠΈΡ†Π° ΠΎΡ‚Π·Ρ‹Π²ΠΎΠ² review со ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ структурой:

        CREATE TABLE `review` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `model` varchar(30) DEFAULT NULL,
  `url` varchar(126) DEFAULT NULL,
  `rate` int(11) DEFAULT NULL,
  `positive` varchar(510) DEFAULT NULL,
  `negative` varchar(510) DEFAULT NULL,
  `review` text,
  `created` int(10) unsigned DEFAULT NULL,
  `title` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

    

Когда ΠΌΡ‹ выполняСм ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ DESCRIBE review, Ρ‚ΠΎ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚:

        +----------+------------------+------+-----+---------+----------------+
| Field    | Type             | Null | Key | Default | Extra          |
+----------+------------------+------+-----+---------+----------------+
| id       | int(11)          | NO   | PRI | NULL    | auto_increment |
| model    | varchar(30)      | YES  |     | NULL    |                |
| url      | varchar(126)     | YES  |     | NULL    |                |
| rate     | int(11)          | YES  |     | NULL    |                |
| positive | varchar(510)     | YES  |     | NULL    |                |
| negative | varchar(510)     | YES  |     | NULL    |                |
| review   | text             | YES  |     | NULL    |                |
| created  | int(10) unsigned | YES  |     | NULL    |                |
| title    | varchar(255)     | YES  |     | NULL    |                |
+----------+------------------+------+-----+---------+----------------+
9 rows in set (0.00 sec)

    

ΠŸΠΎΠΏΡ‹Ρ‚Π°Π΅ΠΌΡΡ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ этот датасСт ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½Ρ‹ΠΌ Π½ΠΈΠΆΠ΅ ΠΊΠΎΠ΄ΠΎΠΌ:

        var fieldName string
var fieldType string
var fieldIsNull  string 
var fieldDefault string 
var fieldComment string
var isKey string

sql_1 := "DESCRIBE " + tabName
rows, err := dg.Db.Query(sql_1)
errorCheck(err)
defer rows.Close()
for rows.Next() {
    err = rows.Scan(&fieldName, &fieldType, &fieldIsNull, &isKey, &fieldDefault, &fieldComment)

    

ΠœΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ ΠΎΡˆΠΈΠ±ΠΊΡƒ:

        panic: sql: Scan error on column index 4, name "Default": converting NULL to string is unsupported
    

Ошибка прСобразования Π²ΠΎΠ·Π½ΠΈΠΊΠ»Π° ΠΈΠ·-Π·Π° Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ поля NULL Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ явно ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΎ Π² Ρ‚ΠΈΠΏ string.

Как ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ NULL?

Π§Ρ‚ΠΎΠ±Ρ‹ Ρ‚Π°ΠΊΠΈΡ… ошибок Π½Π΅ Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π»ΠΎ, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ Ρ‚ΠΈΠΏΡ‹:

            sql.NullString
    sql.NullFloat64
    sql.NullInt32 ΠΈΠ»ΠΈ  sql.NullInt64 
    sql.NullBool
    sql.NullTime 

    

ВсС ΠΎΠ½ΠΈ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡŽΡ‚ ΠΏΡ€ΠΈΠ±Π»ΠΈΠ·ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΡƒΡŽ структуру (Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ sql.NullString):

        type NullString struct {
    String string   // Π΄Π°Π½Π½Ρ‹Π΅ строки, Ссли Π½Π΅ NULL, ΠΈΠ½Π°Ρ‡Π΅ пусто
    Valid  bool     // Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ true Ссли String ΠΈΠΌΠ΅Π΅Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ NULL
}

    

Если ΠΏΠΎΠ»Π΅ Valid ΠΈΠΌΠ΅Π΅Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ true, Ρ‚ΠΎ Π² ΠΏΠΎΠ»Π΅ String находится Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, ΠΈΠ½Π°Ρ‡Π΅ NULL. ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»Π΅Π½Π½ΡƒΡŽ Π½ΠΈΠΆΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ прСобразования:

        func sql2String(str sql.NullString) string {
    if str.Valid {
        return str.String
    }
    return ""
}

    

АналогичныС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ прСобразования ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°. Если Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒΡΡ ΠΊ структурС нашСй Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹, ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ ΠΏΡ€ΠΈΠΌΡƒΡ‚ Ρ‚ΠΈΠΏ:

            var fieldIsNull  sql.NullString
    var fieldDefault sql.NullString

    

Π£ΠΏΡ€ΠΎΡ‰Π΅Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π°Π½Π°Π»ΠΈΠ·Π° Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ прСдставлСн Π½ΠΈΠΆΠ΅:

            for rows.Next() {
        err = rows.Scan(&fieldName, &fieldType, &fieldIsNull, &isKey, &fieldDefault, &fieldComment)
        errorCheck(err)
        type_out := "string"
        sql_type := "sql.NullString"
        fn_conv := "sql2String"
        if strings.Index(fieldType, "int") >= 0 {
            type_out = "int64"
            sql_type = "sql.NullInt64"
            fn_conv  = "sql2Int"
        } else if strings.Index(fieldType, "char") >= 0 {
            type_out = "string"
            sql_type = "sql.NullString"
            fn_conv = "sql2String"
        } else if strings.Index(fieldType, "date") >= 0 {
            type_out = "string"
            sql_type = "sql.NullString"
            fn_conv = "sql2String"
        } else if strings.Index(fieldType, "double") >= 0 {
            type_out = "float"
            sql_type = "sql.NullFloat64"
            fn_conv  = "sql2Float"
        } else if strings.Index(fieldType, "text") >= 0 {
            type_out = "string"
            sql_type = "sql.NullString"
            fn_conv = "sql2String"
        }
        fields = append(fields, Field{fieldName, type_out, sql_type, fn_conv} )
    }

    
ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅
Π’ нашСм ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ бизнСс Π»ΠΎΠ³ΠΈΠΊΠ° Π±Ρ‹Π»Π° Ρ‚Π°ΠΊΠΎΠ²Π°, Ρ‡Ρ‚ΠΎ Ρ‚ΠΈΠΏ DateTime ΠΈΠ»ΠΈ Date ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Ρ‹Π²Π°Π»ΠΈΡΡŒ Π² строку. ΠŸΡ€ΠΈ нСобходимости ΠΌΠΎΠΆΠ½ΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ‚ΠΈΠΏ Π½Π° sql.Time.

Π”Π°Π»Π΅Π΅ – Π΄Π΅Π»ΠΎ Ρ‚Π΅Ρ…Π½ΠΈΠΊΠΈ.

ΠšΠΎΠ΄ΠΎΠ³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΡ – это ΠΎΡ‡Π΅Π½ΡŒ просто

Из срСза ΠΏΠΎΠ»Π΅ΠΉ fields ΠΌΠΎΠΆΠ½ΠΎ ΡΠ³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ любой ΠΊΠΎΠ΄. Π’ качСствС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° взят ΠΊΠΎΠ΄ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, которая сохраняСт всС Π΄Π°Π½Π½Ρ‹Π΅ структуру (структура Ρ‚ΠΎΠΆΠ΅ сгСнСрирована этим ΠΊΠΎΠ΄ΠΎΠΌ):

        func (dg *DbGen) generate() {
    var fieldList []string

    fmt.Printf("\tfunc get%s(db *sql.DB, %s %s) %s {\n", strings.Title(strings.ToLower(dg.tablename)),
        dg.pk, dg.type_pk, strings.Title(strings.ToLower(dg.tablename )))
    fmt.Println("\t\tvar(")
    fmt.Printf("\t\t\tret %s\n", strings.Title(strings.ToLower(dg.tablename )))

    for _,field := range dg.fields {
        if field.name == dg.pk {
            continue
        }
        fieldList = append(fieldList, field.name)
        fmt.Printf("\t\t\t%s %s\n", field.name, field.sqltype)
    }
    fmt.Println("\t\t)")

    out_fieldList := strings.Join(fieldList, ",")
    out_vars := strings.Join(fieldList, ", &")

    sql_txt := fmt.Sprintf( "SELECT %s FROM %s WHERE %s=?", out_fieldList, dg.tablename, dg.pk)
    fmt.Printf("\t\tsql_s := \" %s \"\n" , sql_txt)
    fmt.Printf("\t\trows, err := db.Query(sql_s, %s)\n ", dg.pk)
    fmt.Println("\t\terrorCheck(err)")
    fmt.Println("\t\tdefer rows.Close()")
    fmt.Println("\t\tfor rows.Next() {")
    fmt.Printf("\t\t\terr = rows.Scan(&%s)\n", out_vars)
    fmt.Println("\t\t\terrorCheck(err)")

    for _,field := range dg.fields {
        if field.name == dg.pk {
            fmt.Printf("\t\t\tret.%s=%s\n", field.name, field.name)
        } else {
            fmt.Printf("\t\t\tret.%s=%s(%s)\n", field.name, field.fn_conv, field.name)
        }
    }

    fmt.Println("\t\t}")
    fmt.Println("\t\treturn ret")
    fmt.Println("\t}")
} 

    

Π’ этом ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ хрСстоматийная функция errorCheck(err):

            func errorCheck(err) {
        if err != nil {
            panic(err.Error())
        }
    }

    

Π’Π°ΠΊΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ NULL:

  • sql2String
  • sql2Int
  • sql2Float

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

ΠŸΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½Π½Ρ‹ΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ сокращаСт врСмя написания ΠΈ ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ ΠΊΠΎΠ΄Π° Ρ‡ΡƒΡ‚ΡŒ Π»ΠΈ Π½Π΅ Π²Π΄Π²ΠΎΠ΅, Π° ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈ Π²Ρ‚Ρ€ΠΎΠ΅, Ссли Π²Π°ΠΌ потрСбуСтся Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ API для ΠΈΠΌΠΏΠΎΡ€Ρ‚Π° Π±ΠΎΠ»Π΅Π΅ дСсятка Ρ‚Π°Π±Π»ΠΈΡ† (ΠΎΡ‚ 10 Π΄ΠΎ 20 ΠΈ Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ»Π΅ΠΉ). Π‘ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Ρ‹ΠΉ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ΄ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ Π½Π° GitHub: https://github.com/akalend/mysql-golang-generator

ΠŸΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½Ρ‹ΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ описываСт Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΏΠΎ ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½ΠΎΠΌΡƒ ΠΊΠ»ΡŽΡ‡Ρƒ, Π½ΠΎ Ρ‚Π°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ для вставки ΠΈ обновлСния записСй, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΊΠΎΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ ON DUPLICATE KEY UPDATE. МоТно Ρ€Π°Π·Π²ΠΈΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠ΄ Π² Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠΈ составного ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½ΠΎΠ³ΠΎ ΠΊΠ»ΡŽΡ‡Π° ΠΈΠ»ΠΈ Π²ΠΎΠΎΠ±Ρ‰Π΅ Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΏΠ΅Ρ€Π²ΠΈΡ‡Π½Ρ‹ΠΉ ΠΊΠ»ΡŽΡ‡ – всС зависит ΠΎΡ‚ вашСй Ρ„Π°Π½Ρ‚Π°Π·ΠΈΠΈ. ВсСгда Π΅ΡΡ‚ΡŒ ΠΊΡƒΠ΄Π° Ρ€Π°Π·Π²ΠΈΠ²Π°Ρ‚ΡŒΡΡ: Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΏΡ€ΠΈΠΊΡ€ΡƒΡ‚ΠΈΡ‚ΡŒ ΠΊ ΠΊΠΎΠ΄Ρƒ ΡˆΠ°Π±Π»ΠΎΠ½ΠΈΠ·Π°Ρ‚ΠΎΡ€, Ρ‡Ρ‚ΠΎΠ± ΠΏΡ€ΠΎΡ‰Π΅ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΡˆΠ°Π±Π»ΠΎΠ½Ρ‹ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ. НадСюсь, ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π» ΠΌΠΎΠ΅ΠΉ ΡΡ‚Π°Ρ‚ΡŒΠΈ ΠΈ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½Ρ‹ΠΉ Π² Π½Π΅ΠΉ ΠΊΠΎΠ΄ΠΎΠ³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ ΠΊΠΎΠΌΡƒ-Ρ‚ΠΎ сократит врСмя Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ. Π£Π΄Π°Ρ‡ΠΈ!

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ

ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ

Π’ΠΠšΠΠΠ‘Π˜Π˜

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ вакансию
Π Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ C++
Москва, ΠΏΠΎ ΠΈΡ‚ΠΎΠ³Π°ΠΌ собСсСдования

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•