Динамический запрос выбора SQL в Голанге - PullRequest
2 голосов
/ 27 марта 2019

Я пытаюсь создать API с драйвером базы данных / sql и mysql, который будет считывать данные на основе параметров URL.
Примерно так

myapi.com/users?columns=id,first_name,last_name,country&sort=desc&sortColumn=last_name&limit=10&offset=20

Я знаю, как получить все столбцы илитолько определенные столбцы, когда это определено в структуре.Но я хочу знать, возможно ли получить столбцы из URL и вместо предопределенной структуры сохранить их на карту, а затем просто сканировать эти столбцы.
У меня есть рабочий код, который будет получать данные из конечной точки выше, только если количество столбцов одинаковокак в структуре.Например, если я удаляю country, я получаю сообщение об ошибке, что Scan ожидает 4 параметра, но дается 3.

Мне не нужен конкретный код, только некоторые указания, так как я изучаю Go, а мой фон - PHPгде это легче сделать.

Обновление

Благодаря ответам у меня есть частично рабочее решение.
Вот код:

cols := []string{"id", "first_name", "last_name"}
vals := make([]interface{}, len(cols))
w := map[string]interface{}{"id": 105}

var whereVal []interface{}
var whereCol []string

for k, v := range w {
    whereVal = append(whereVal, v)
    whereCol = append(whereCol, fmt.Sprintf("%s = ?", k))
}

for i := range cols {
    vals[i] = new(interface{})
}
err := db.QueryRow("SELECT "+strings.Join(cols, ",")+" FROM users WHERE "+strings.Join(whereCol, " AND "), whereVal...).Scan(vals...)

if err != nil {
    fmt.Println(err)
}

b, _ := json.Marshal(vals)
fmt.Println(string(b))

Это должно запросить SELECT id, first_name, last_name FROM users WHERE id = 105;

Но как мне получить данные для правильного объекта json?Теперь он выводит строки, закодированные в base64 следующим образом.

[105,"Sm9obm55","QnJhdm8="]

Ответы [ 3 ]

1 голос
/ 27 марта 2019

Я бы создал оператор запроса с динамическими полями (используйте заполнитель, чтобы избежать внедрения sql):

rows := db.QueryRow("SELECT {{YOUR_FIELDS}} from table_tbl")

Создание переменной-носителя с одинаковым размером столбцов

vals := make([]interface{}, len(rows.Columns()))

Использованиеsql.RawBytes для типа поля, если вам не нужна проверка типов или вы не можете знать их типы, в противном случае используйте тот же тип поля.

for i, _ := range cols {
    vals[i] = new(sql.RawBytes)
    //check column name, if it is id, and you know it is integer
    //vals[i] = new(int)
}

Итерируйте строки и сканируйте

for rows.Next() {
    err = rows.Scan(vals...)
}
1 голос
/ 28 марта 2019

Из того, что я знаю (также не очень опытно в Go), если вы не назначите вещественному типу значение, то Scan вернет []byte, а при маршалинге вернет строку в кодировке base64.

Таким образом, вы должны назначить тип для ваших столбцов, и если вы хотите, чтобы правильный json назначил ключи значениям.

В вашем примере это можно сделать примерно так:

cols := []string{"id", "first_name", "last_name"}
vals := make([]interface{}, len(cols))
result := make(map[string]interface{}, len(cols))

for i, key := range cols {
    switch key {
    case "id", "status":
        vals[i] = new(int)
    default:
        vals[i] = new(string)
    }

    result[key] = vals[i]
}

b, _ := json.Marshal(result)
fmt.Println(string(b))

Таким образом, вместо того, чтобы зацикливаться на cols и создавать новый интерфейс для каждого столбца, теперь мы создаем пары ключ / значение и присваиваем тип на основе имени столбца.

Кроме того, если в таблице есть столбцы, допускающие значения NULL, ивозможно, вы получите ошибку, потому что nil не может войти в string.Поэтому я предлагаю этот пакет gopkg.in/guregu/null.v3 и затем присваиваю тип, например null.String.Таким образом, вы получите null в качестве значения.

Например:

for i, key := range cols {
    switch key {
    case "id", "status":
        vals[i] = new(int)
    case "updated_at", "created_at":
        vals[i] = new(null.Time)
    default:
        vals[i] = new(null.String)
    }

    result[key] = vals[i]
}
1 голос
/ 27 марта 2019

Сначала необходимо получить количество столбцов результата, а затем не превышать их размер.

Если вы имели в виду поля запроса, вам нужно динамически создать строку запроса, размер параметров должен быть одинаковым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...