
type AddModem struct {
	IMEI            string           `table:"modems" pk:"imei"`
	SchemaVersion   int              `json:"schemaVersion"`
	AttachedDevices []AddModemDevice `json:"devices"`
}

type AddModemDevice struct {
	DeviceNo int    `table:"modemDevices" pk:"deviceNo" seq:"auto"`
	DeviceID int    `json:"deviceID"`
	IMEI     string `json:"imei"`
	ConfigID int    `json:"configID"`
	Addr     int    `json:"addr"`
}



/*
type Config struct {
	ConfigID int    `table:"configs" c:"configID"`
	Name     string `c:"name"`
}

func TestParseStruct(t *testing.T) {
	var x Modem
	info, err := parseStruct(reflect.TypeOf(x))
	if err != nil {
		t.Fatal(err)
	}

	//fmt.Printf("%#v\n", info)
	//fmt.Printf("%#v\n", info.AttachedDevi	)
	//spew.Dump(info)
	//prettyPrint(info)
	fmt.Printf("%# v", pretty.Formatter(info))
}

func TestParseBuildInsert(t *testing.T) {
	core := newCore(&mysql{})
	var x Modem
	info, err := parseStruct(reflect.TypeOf(x))
	if err != nil {
		t.Fatal(err)
	}

	r, err := core.buildInsertStruct(info, nil)
	if err != nil {
		t.Fatal(err)
	}

	//fmt.Printf("%#v\n", info)
	//fmt.Printf("%#v\n", info.AttachedDevi	)
	//spew.Dump(info)
	//prettyPrint(info)
	fmt.Printf("%# v", pretty.Formatter(r))
}
*/
/*
func prettyPrint(i interface{}) {
	s, _ := json.MarshalIndent(i, "", "    ")
	//return string(s)
	fmt.Printf("%s\n", s)
}



Сделать формат по которому генерить SQL и структуры

ModemDevice {
	deviceNo     int
	deviceID     int
	imei (IMEI)  string
	configID     int
	addr         int

	pk(deviceNo, deviceID) auto
	unique(addr)
}


func TestSelect(t *testing.T) {
	rawdb, err := sql.Open("mysql", "root:zkx75fcy@/qx")
	if err != nil {
		t.Fatal(err)
	}

	//tx, err := rawdb.Begin()
	//if err != nil {
	//	t.Fatal(err)
	//}

	//tx.QueryRow()

	//db := New(rawdb, "mysql")
	db := New(rawdb, "oracle")

	//tx, err := db.Tx()
	//if err != nil {
	//	t.Fatal(err)
	//}
	//defer tx.Close(err)

	//"WHERE modemDevices.deviceNo !=11 ORDER BY modemDevices.deviceNo DESC"

	var list []*ModemDevice

	//var list []ConfiguredModem

	err = db.ListBy(&list, "WHERE devices.DeviceID>? AND modemDevices.deviceNo IN ( ? )", 150, []int{10, 12})
	if err != nil {
		t.Fatal(err)
	}

	//tx.ListBy(&list, qx.By{
	//	"":                "",
	//	"AttachedDevices": "ORDER BY modemDevices.deviceNo DESC",
	//})

	for _, d := range list {
		fmt.Printf("\n%+v\n", d)
	}

	var list2 []*ConfiguredModem

	err = db.List(&list2)
	if err != nil {
		t.Fatal(err)
	}

	for _, d := range list2 {
		fmt.Printf("\n%+v\n", d)
	}

	var list3 []*ConfiguredModem

	err = db.ListBy(&list3, `
	SELECT IMEI, schemaVersion FROM modems ORDER BY schemaVersion ASC`)
	if err != nil {
		t.Fatal(err)
	}

	for _, d := range list3 {
		fmt.Printf("\n%+v\n", d)
	}

	var m ModemDevice
	//m.DeviceNo = 11

	found, err := db.One(&m, 11)
	if err != nil {
		t.Fatal(err)
	}

	fmt.Printf("\nfound: %t, obj: %+v\n", found, m)

	var m2 ModemDevice

	found, err = db.OneBy(&m2, "WHERE devices.deviceID=?", 11)
	if err != nil {
		t.Fatal(err)
	}

	fmt.Printf("\nfound: %t, obj: %+v\n", found, m)

	//fmt.Printf("\n%+v\n", x.Nested[0])
	//fmt.Printf("\n%+v\n", x.Nested[0].Nested[0])

}
*/

/*
type AddConnectorLimit struct {
	//HardwareVersion int `json:"-" qx:"table=hardwareConnectors;"`
	ConnectorID int `json:"connectorID" qx:"table=hardwareConnectors;fk=connectors"`
	MinAddr     int `json:"minAddr"`
	MaxAddr     int `json:"maxAddr"`
}

type AddHardware struct {
	HardwareVersion int                 `json:"hardwareVersion" qx:"table=hardwares; seq=gen_hardwares_id; pk;"`
	Name            string              `json:"name" qx:"unique=connectorID,name"`
	About           string              `json:"about" qx:"unique"`
	ConfigID        int                 `json:"about" qx:"fk=configs.configID"`
	ConnectorLimits []AddConnectorLimit `json:"connectorLimits"`
}


Сперва парсим в мапу, затем валидируем.
pk опционален если нет детей (Lists)

Первое поле:
table = текст
seq = ?
pk = name / name,nextID / пусто
// если нет pk
unique   = name / name,nextID / пусто
fk = configs / configs.configID

Любое поле:
unique   = name / name,nextID / пусто
fk = configs / configs.configID


*/

/*
		unique := []Unique{
			Column: "name",
			Code: 100,
		}
	UNIQUE error возвращается как field + стандартный код. Если нужно сделать
	кастомизацию, допустим "IMEI занят", "Производитель существует" - можно проверить
	что это апи ошибка, затем проверить код и поле. По полю модифицировать код.
	Таким образом Unique можно задавать в тегах, причем напротив поля, под которым нужно
	вывести ошибку

*/
//s.db.Insert(, unique)
/*
	db.RegisterTypes([]interface{
		AddHardware{},
		User{},
		Connector{},
	})
*/

/*
Для вложенной таблицы мне нужно знать:
table чтобы знать куда вставить запись
pk/seq, чтобы исключить из INSERT, и чтобы вставить детей с правильным parentID
fk, чтобы проверить ключи


Как быть с List таблицей при Insert. Когда не нужен родительский ключ. При этом он
является частью PK. Может указывать напротив поля массива?
*/
/*
func TestParseTag(t *testing.T) {
	m, err := parseTag("table=modemDevices; pk; seq; fk=configs")
	if err != nil {
		t.Fatal(err)
	}
	fmt.Printf("%# v", pretty.Formatter(m))
}
*/

columnIns, err := tx.Prepare(`INSERT INTO object_info (ID_IMEI, COLUMN_NAME_PARAM, COLUMN_NAME_DISPLAY, VISIBLE_COLUMN, ID_TYPE_UNIT) VALUES (?, ?, ?, 1, 1)`)


// fix
/*
func (s *Storage) lastInsertID(tx *sql.Tx, seq string) (id int64, err error) {
	err = tx.QueryRow(fmt.Sprintf(`SELECT %s.currval FROM DUAL`, seq)).Scan(&id)
	return
}
*/


