mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
orm: default attribute (#15221)
This commit is contained in:
parent
c976a691ad
commit
e5e750d533
@ -1,6 +1,7 @@
|
||||
import orm
|
||||
import mysql
|
||||
import time
|
||||
import v.ast
|
||||
|
||||
struct TestCustomSqlType {
|
||||
id int [primary; sql: serial]
|
||||
@ -29,20 +30,28 @@ mut:
|
||||
deleted_at time.Time
|
||||
}
|
||||
|
||||
struct TestDefaultAtribute {
|
||||
id string [primary; sql: serial]
|
||||
name string
|
||||
created_at string [default: 'CURRENT_TIMESTAMP'; sql_type: 'TIMESTAMP']
|
||||
}
|
||||
|
||||
fn test_mysql_orm() {
|
||||
mut mdb := mysql.Connection{
|
||||
mut db := mysql.Connection{
|
||||
host: 'localhost'
|
||||
port: 3306
|
||||
username: 'root'
|
||||
password: ''
|
||||
dbname: 'mysql'
|
||||
}
|
||||
mdb.connect() or { panic(err) }
|
||||
db := orm.Connection(mdb)
|
||||
db.connect() or { panic(err) }
|
||||
defer {
|
||||
db.close()
|
||||
}
|
||||
db.create('Test', [
|
||||
orm.TableField{
|
||||
name: 'id'
|
||||
typ: 7
|
||||
typ: ast.int_type_idx
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
name: 'primary'
|
||||
@ -57,12 +66,12 @@ fn test_mysql_orm() {
|
||||
},
|
||||
orm.TableField{
|
||||
name: 'name'
|
||||
typ: 20
|
||||
typ: ast.string_type_idx
|
||||
attrs: []
|
||||
},
|
||||
orm.TableField{
|
||||
name: 'age'
|
||||
typ: 7
|
||||
typ: ast.int_type_idx
|
||||
},
|
||||
]) or { panic(err) }
|
||||
|
||||
@ -75,11 +84,11 @@ fn test_mysql_orm() {
|
||||
table: 'Test'
|
||||
has_where: true
|
||||
fields: ['id', 'name', 'age']
|
||||
types: [7, 20, 8]
|
||||
types: [ast.int_type_idx, ast.string_type_idx, ast.i64_type_idx]
|
||||
}, orm.QueryData{}, orm.QueryData{
|
||||
fields: ['name', 'age']
|
||||
data: [orm.Primitive('Louis'), i64(101)]
|
||||
types: [20, 8]
|
||||
types: [ast.string_type_idx, ast.i64_type_idx]
|
||||
is_and: [true, true]
|
||||
kinds: [.eq, .eq]
|
||||
}) or { panic(err) }
|
||||
@ -88,8 +97,6 @@ fn test_mysql_orm() {
|
||||
name := res[0][1]
|
||||
age := res[0][2]
|
||||
|
||||
mdb.close()
|
||||
|
||||
assert id is int
|
||||
if id is int {
|
||||
assert id == 1
|
||||
@ -104,22 +111,10 @@ fn test_mysql_orm() {
|
||||
if age is i64 {
|
||||
assert age == 101
|
||||
}
|
||||
}
|
||||
|
||||
fn test_orm() {
|
||||
mut db := mysql.Connection{
|
||||
host: 'localhost'
|
||||
port: 3306
|
||||
username: 'root'
|
||||
password: ''
|
||||
dbname: 'mysql'
|
||||
}
|
||||
|
||||
db.connect() or {
|
||||
println(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
/** test orm sql type
|
||||
* - verify if all type create by attribute sql_type has created
|
||||
*/
|
||||
sql db {
|
||||
create table TestCustomSqlType
|
||||
}
|
||||
@ -168,27 +163,19 @@ fn test_orm() {
|
||||
sql db {
|
||||
drop table TestCustomSqlType
|
||||
}
|
||||
db.close()
|
||||
|
||||
assert result_custom_sql.maps() == information_schema_custom_sql
|
||||
}
|
||||
|
||||
fn test_orm_time_type() ? {
|
||||
mut db := mysql.Connection{
|
||||
host: 'localhost'
|
||||
port: 3306
|
||||
username: 'root'
|
||||
password: ''
|
||||
dbname: 'mysql'
|
||||
}
|
||||
|
||||
db.connect() or {
|
||||
/** test_orm_time_type
|
||||
* - test time.Time v type with sql_type: 'TIMESTAMP'
|
||||
* - test string v type with sql_type: 'TIMESTAMP'
|
||||
* - test time.Time v type without
|
||||
*/
|
||||
today := time.parse('2022-07-16 15:13:27') or {
|
||||
println(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
today := time.parse('2022-07-16 15:13:27')?
|
||||
|
||||
model := TestTimeType{
|
||||
username: 'hitalo'
|
||||
created_at: today
|
||||
@ -212,10 +199,38 @@ fn test_orm_time_type() ? {
|
||||
drop table TestTimeType
|
||||
}
|
||||
|
||||
db.close()
|
||||
|
||||
assert results[0].username == model.username
|
||||
assert results[0].created_at == model.created_at
|
||||
assert results[0].updated_at == model.updated_at
|
||||
assert results[0].deleted_at == model.deleted_at
|
||||
|
||||
/** test default attribute
|
||||
*/
|
||||
sql db {
|
||||
create table TestDefaultAtribute
|
||||
}
|
||||
|
||||
mut result_defaults := db.query("
|
||||
SELECT COLUMN_DEFAULT
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_NAME = 'TestDefaultAtribute'
|
||||
ORDER BY ORDINAL_POSITION
|
||||
") or {
|
||||
println(err)
|
||||
panic(err)
|
||||
}
|
||||
mut information_schema_defaults_results := []string{}
|
||||
|
||||
sql db {
|
||||
drop table TestDefaultAtribute
|
||||
}
|
||||
|
||||
information_schema_column_default_sql := [{
|
||||
'COLUMN_DEFAULT': ''
|
||||
}, {
|
||||
'COLUMN_DEFAULT': ''
|
||||
}, {
|
||||
'COLUMN_DEFAULT': 'CURRENT_TIMESTAMP'
|
||||
}]
|
||||
assert information_schema_column_default_sql == result_defaults.maps()
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ pub fn (db Connection) insert(table string, data orm.QueryData) ? {
|
||||
mut converted_primitive_array := db.factory_orm_primitive_converted_from_sql(table,
|
||||
data)?
|
||||
|
||||
converted_data := orm.QueryData{
|
||||
converted_primitive_data := orm.QueryData{
|
||||
fields: data.fields
|
||||
data: converted_primitive_array
|
||||
types: []
|
||||
@ -132,17 +132,19 @@ pub fn (db Connection) insert(table string, data orm.QueryData) ? {
|
||||
is_and: []
|
||||
}
|
||||
|
||||
query := orm.orm_stmt_gen(table, '`', .insert, false, '?', 1, converted_data, orm.QueryData{})
|
||||
query, converted_data := orm.orm_stmt_gen(table, '`', .insert, false, '?', 1, converted_primitive_data,
|
||||
orm.QueryData{})
|
||||
mysql_stmt_worker(db, query, converted_data, orm.QueryData{})?
|
||||
}
|
||||
|
||||
pub fn (db Connection) update(table string, data orm.QueryData, where orm.QueryData) ? {
|
||||
query := orm.orm_stmt_gen(table, '`', .update, false, '?', 1, data, where)
|
||||
query, _ := orm.orm_stmt_gen(table, '`', .update, false, '?', 1, data, where)
|
||||
mysql_stmt_worker(db, query, data, where)?
|
||||
}
|
||||
|
||||
pub fn (db Connection) delete(table string, where orm.QueryData) ? {
|
||||
query := orm.orm_stmt_gen(table, '`', .delete, false, '?', 1, orm.QueryData{}, where)
|
||||
query, _ := orm.orm_stmt_gen(table, '`', .delete, false, '?', 1, orm.QueryData{},
|
||||
where)
|
||||
mysql_stmt_worker(db, query, orm.QueryData{}, where)?
|
||||
}
|
||||
|
||||
@ -158,7 +160,7 @@ pub fn (db Connection) last_id() orm.Primitive {
|
||||
|
||||
// table
|
||||
pub fn (db Connection) create(table string, fields []orm.TableField) ? {
|
||||
query := orm.orm_table_gen(table, '`', false, 0, fields, mysql_type_from_v, false) or {
|
||||
query := orm.orm_table_gen(table, '`', true, 0, fields, mysql_type_from_v, false) or {
|
||||
return err
|
||||
}
|
||||
mysql_stmt_worker(db, query, orm.QueryData{}, orm.QueryData{})?
|
||||
|
@ -15,6 +15,7 @@
|
||||
- `[sql: type]` where `type` is a V type such as `int` or `f64`, or special type `serial`
|
||||
- `[sql: 'name']` sets a custom column name for the field
|
||||
- `[sql_type: 'SQL TYPE']` sets the sql type which is used in sql
|
||||
- `[default: 'sql defaults']` sets the default value or function when create a new table
|
||||
|
||||
## Usage
|
||||
|
||||
@ -90,3 +91,53 @@ result := sql db {
|
||||
select from Foo where id > 1 order by id
|
||||
}
|
||||
```
|
||||
|
||||
### Example
|
||||
```v ignore
|
||||
import pg
|
||||
|
||||
struct Member {
|
||||
id string [default: 'gen_random_uuid()'; primary; sql_type: 'uuid']
|
||||
name string
|
||||
created_at string [default: 'CURRENT_TIMESTAMP'; sql_type: 'TIMESTAMP']
|
||||
}
|
||||
|
||||
fn main() {
|
||||
db := pg.connect(pg.Config{
|
||||
host: 'localhost'
|
||||
port: 5432
|
||||
user: 'user'
|
||||
password: 'password'
|
||||
dbname: 'dbname'
|
||||
}) or {
|
||||
println(err)
|
||||
return
|
||||
}
|
||||
|
||||
defer {
|
||||
db.close()
|
||||
}
|
||||
|
||||
sql db {
|
||||
create table Member
|
||||
}
|
||||
|
||||
new_member := Member{
|
||||
name: 'John Doe'
|
||||
}
|
||||
|
||||
sql db {
|
||||
insert new_member into Member
|
||||
}
|
||||
|
||||
selected_member := sql db {
|
||||
select from Member where name == 'John Doe' limit 1
|
||||
}
|
||||
|
||||
sql db {
|
||||
update Member set name = 'Hitalo' where id == selected_member.id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
@ -182,27 +182,42 @@ pub interface Connection {
|
||||
// num - Stmt uses nums at prepared statements (? or ?1)
|
||||
// qm - Character for prepared statment, qm because of quotation mark like in sqlite
|
||||
// start_pos - When num is true, it's the start position of the counter
|
||||
pub fn orm_stmt_gen(table string, q string, kind StmtKind, num bool, qm string, start_pos int, data QueryData, where QueryData) string {
|
||||
pub fn orm_stmt_gen(table string, q string, kind StmtKind, num bool, qm string, start_pos int, data QueryData, where QueryData) (string, QueryData) {
|
||||
mut str := ''
|
||||
|
||||
mut c := start_pos
|
||||
mut data_fields := []string{}
|
||||
mut data_data := []Primitive{}
|
||||
|
||||
match kind {
|
||||
.insert {
|
||||
mut values := []string{}
|
||||
mut select_fields := []string{}
|
||||
|
||||
for _ in 0 .. data.fields.len {
|
||||
// loop over the length of data.field and generate ?0, ?1 or just ? based on the $num qmeter for value placeholders
|
||||
if num {
|
||||
values << '$qm$c'
|
||||
c++
|
||||
} else {
|
||||
values << '$qm'
|
||||
for i in 0 .. data.fields.len {
|
||||
if data.data.len > 0 {
|
||||
match data.data[i].type_name() {
|
||||
'string' {
|
||||
if (data.data[i] as string).len == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
'time.Time' {
|
||||
if (data.data[i] as time.Time).unix == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
data_data << data.data[i]
|
||||
}
|
||||
select_fields << '$q${data.fields[i]}$q'
|
||||
values << factory_insert_qm_value(num, qm, c)
|
||||
data_fields << data.fields[i]
|
||||
c++
|
||||
}
|
||||
|
||||
str += 'INSERT INTO $q$table$q ('
|
||||
str += data.fields.map('$q$it$q').join(', ')
|
||||
str += select_fields.join(', ')
|
||||
str += ') VALUES ('
|
||||
str += values.join(', ')
|
||||
str += ')'
|
||||
@ -262,7 +277,13 @@ pub fn orm_stmt_gen(table string, q string, kind StmtKind, num bool, qm string,
|
||||
}
|
||||
}
|
||||
str += ';'
|
||||
return str
|
||||
return str, QueryData{
|
||||
fields: data_fields
|
||||
data: data_data
|
||||
types: data.types
|
||||
kinds: data.kinds
|
||||
is_and: data.is_and
|
||||
}
|
||||
}
|
||||
|
||||
// Generates an sql select stmt, from universal parameter
|
||||
@ -357,6 +378,7 @@ pub fn orm_table_gen(table string, q string, defaults bool, def_unique_len int,
|
||||
if field.is_arr {
|
||||
continue
|
||||
}
|
||||
mut default_val := field.default_val
|
||||
mut no_null := false
|
||||
mut is_unique := false
|
||||
mut is_skip := false
|
||||
@ -397,6 +419,14 @@ pub fn orm_table_gen(table string, q string, defaults bool, def_unique_len int,
|
||||
}
|
||||
ctyp = attr.arg
|
||||
}
|
||||
'default' {
|
||||
if attr.kind != .string {
|
||||
return error("default attribute need be string. Try [default: '$attr.arg'] instead of [default: $attr.arg]")
|
||||
}
|
||||
if default_val == '' {
|
||||
default_val = attr.arg
|
||||
}
|
||||
}
|
||||
/*'fkey' {
|
||||
if attr.arg != '' {
|
||||
if attr.kind == .string {
|
||||
@ -416,8 +446,8 @@ pub fn orm_table_gen(table string, q string, defaults bool, def_unique_len int,
|
||||
return error('Unknown type ($field.typ) for field $field.name in struct $table')
|
||||
}
|
||||
stmt = '$q$field_name$q $ctyp'
|
||||
if defaults && field.default_val != '' {
|
||||
stmt += ' DEFAULT $field.default_val'
|
||||
if defaults && default_val != '' {
|
||||
stmt += ' DEFAULT $default_val'
|
||||
}
|
||||
if no_null {
|
||||
stmt += ' NOT NULL'
|
||||
@ -543,3 +573,11 @@ pub fn time_to_primitive(b time.Time) Primitive {
|
||||
pub fn infix_to_primitive(b InfixType) Primitive {
|
||||
return Primitive(b)
|
||||
}
|
||||
|
||||
fn factory_insert_qm_value(num bool, qm string, c int) string {
|
||||
if num {
|
||||
return '$qm$c'
|
||||
} else {
|
||||
return '$qm'
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import orm
|
||||
import v.ast
|
||||
|
||||
fn test_orm_stmt_gen_update() {
|
||||
query := orm.orm_stmt_gen('Test', "'", .update, true, '?', 0, orm.QueryData{
|
||||
query, _ := orm.orm_stmt_gen('Test', "'", .update, true, '?', 0, orm.QueryData{
|
||||
fields: ['test', 'a']
|
||||
data: []
|
||||
types: []
|
||||
@ -17,7 +17,7 @@ fn test_orm_stmt_gen_update() {
|
||||
}
|
||||
|
||||
fn test_orm_stmt_gen_insert() {
|
||||
query := orm.orm_stmt_gen('Test', "'", .insert, true, '?', 0, orm.QueryData{
|
||||
query, _ := orm.orm_stmt_gen('Test', "'", .insert, true, '?', 0, orm.QueryData{
|
||||
fields: ['test', 'a']
|
||||
data: []
|
||||
types: []
|
||||
@ -27,7 +27,7 @@ fn test_orm_stmt_gen_insert() {
|
||||
}
|
||||
|
||||
fn test_orm_stmt_gen_delete() {
|
||||
query := orm.orm_stmt_gen('Test', "'", .delete, true, '?', 0, orm.QueryData{
|
||||
query, _ := orm.orm_stmt_gen('Test', "'", .delete, true, '?', 0, orm.QueryData{
|
||||
fields: ['test', 'a']
|
||||
data: []
|
||||
types: []
|
||||
|
@ -31,17 +31,18 @@ pub fn (db DB) @select(config orm.SelectConfig, data orm.QueryData, where orm.Qu
|
||||
// sql stmt
|
||||
|
||||
pub fn (db DB) insert(table string, data orm.QueryData) ? {
|
||||
query := orm.orm_stmt_gen(table, '"', .insert, true, '$', 1, data, orm.QueryData{})
|
||||
pg_stmt_worker(db, query, data, orm.QueryData{})?
|
||||
query, converted_data := orm.orm_stmt_gen(table, '"', .insert, true, '$', 1, data,
|
||||
orm.QueryData{})
|
||||
pg_stmt_worker(db, query, converted_data, orm.QueryData{})?
|
||||
}
|
||||
|
||||
pub fn (db DB) update(table string, data orm.QueryData, where orm.QueryData) ? {
|
||||
query := orm.orm_stmt_gen(table, '"', .update, true, '$', 1, data, where)
|
||||
query, _ := orm.orm_stmt_gen(table, '"', .update, true, '$', 1, data, where)
|
||||
pg_stmt_worker(db, query, data, where)?
|
||||
}
|
||||
|
||||
pub fn (db DB) delete(table string, where orm.QueryData) ? {
|
||||
query := orm.orm_stmt_gen(table, '"', .delete, true, '$', 1, orm.QueryData{}, where)
|
||||
query, _ := orm.orm_stmt_gen(table, '"', .delete, true, '$', 1, orm.QueryData{}, where)
|
||||
pg_stmt_worker(db, query, orm.QueryData{}, where)?
|
||||
}
|
||||
|
||||
@ -163,18 +164,20 @@ fn pg_stmt_match(mut types []u32, mut vals []&char, mut lens []int, mut formats
|
||||
formats << 1
|
||||
}
|
||||
string {
|
||||
types << u32(Oid.t_text)
|
||||
// If paramTypes is NULL, or any particular element in the array is zero,
|
||||
// the server infers a data type for the parameter symbol in the same way
|
||||
// it would do for an untyped literal string.
|
||||
types << &u8(0)
|
||||
vals << data.str
|
||||
lens << data.len
|
||||
formats << 0
|
||||
}
|
||||
time.Time {
|
||||
types << u32(Oid.t_int4)
|
||||
unix := int(data.unix)
|
||||
num := conv.htn32(unsafe { &u32(&unix) })
|
||||
vals << &char(&num)
|
||||
lens << int(sizeof(u32))
|
||||
formats << 1
|
||||
datetime := ((d as time.Time).format_ss() as string)
|
||||
types << &u8(0)
|
||||
vals << datetime.str
|
||||
lens << datetime.len
|
||||
formats << 0
|
||||
}
|
||||
orm.InfixType {
|
||||
pg_stmt_match(mut types, mut vals, mut lens, mut formats, data.right)
|
||||
@ -190,9 +193,12 @@ fn pg_type_from_v(typ int) ?string {
|
||||
orm.type_idx['bool'] {
|
||||
'BOOLEAN'
|
||||
}
|
||||
orm.type_idx['int'], orm.type_idx['u32'], orm.time {
|
||||
orm.type_idx['int'], orm.type_idx['u32'] {
|
||||
'INT'
|
||||
}
|
||||
orm.time {
|
||||
'TIMESTAMP'
|
||||
}
|
||||
orm.type_idx['i64'], orm.type_idx['u64'] {
|
||||
'BIGINT'
|
||||
}
|
||||
|
@ -2,39 +2,89 @@ module main
|
||||
|
||||
import orm
|
||||
import pg
|
||||
import v.ast
|
||||
import time
|
||||
|
||||
struct TestCustomSqlType {
|
||||
id int [primary; sql: serial]
|
||||
custom string [sql_type: 'TEXT']
|
||||
custom1 string [sql_type: 'VARCHAR(191)']
|
||||
custom2 string [sql_type: 'TIMESTAMP']
|
||||
custom3 string [sql_type: 'uuid']
|
||||
}
|
||||
|
||||
struct TestCustomWrongSqlType {
|
||||
id int [primary; sql: serial]
|
||||
custom string
|
||||
custom1 string [sql_type: 'VARCHAR']
|
||||
custom2 string [sql_type: 'money']
|
||||
custom3 string [sql_type: 'xml']
|
||||
}
|
||||
|
||||
struct TestTimeType {
|
||||
mut:
|
||||
id int [primary; sql: serial]
|
||||
username string
|
||||
created_at time.Time [sql_type: 'TIMESTAMP']
|
||||
updated_at string [sql_type: 'TIMESTAMP']
|
||||
deleted_at time.Time
|
||||
}
|
||||
|
||||
struct TestDefaultAtribute {
|
||||
id string [default: 'gen_random_uuid()'; primary; sql_type: 'uuid']
|
||||
name string
|
||||
created_at string [default: 'CURRENT_TIMESTAMP'; sql_type: 'TIMESTAMP']
|
||||
}
|
||||
|
||||
fn test_pg_orm() {
|
||||
mut db := pg.connect(
|
||||
host: 'localhost'
|
||||
user: 'postgres'
|
||||
password: ''
|
||||
password: 'password'
|
||||
dbname: 'postgres'
|
||||
) or { panic(err) }
|
||||
|
||||
defer {
|
||||
db.close()
|
||||
}
|
||||
|
||||
db.create('Test', [
|
||||
orm.TableField{
|
||||
name: 'id'
|
||||
typ: 7
|
||||
typ: ast.string_type_idx
|
||||
is_time: false
|
||||
default_val: ''
|
||||
is_arr: false
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
name: 'primary'
|
||||
has_arg: false
|
||||
arg: ''
|
||||
kind: .plain
|
||||
},
|
||||
StructAttribute{
|
||||
name: 'sql'
|
||||
has_arg: true
|
||||
kind: .plain
|
||||
arg: 'serial'
|
||||
kind: .plain
|
||||
},
|
||||
]
|
||||
},
|
||||
orm.TableField{
|
||||
name: 'name'
|
||||
typ: 18
|
||||
typ: ast.string_type_idx
|
||||
is_time: false
|
||||
default_val: ''
|
||||
is_arr: false
|
||||
attrs: []
|
||||
},
|
||||
orm.TableField{
|
||||
name: 'age'
|
||||
typ: 7
|
||||
typ: ast.i64_type_idx
|
||||
is_time: false
|
||||
default_val: ''
|
||||
is_arr: false
|
||||
attrs: []
|
||||
},
|
||||
]) or { panic(err) }
|
||||
|
||||
@ -45,15 +95,22 @@ fn test_pg_orm() {
|
||||
|
||||
res := db.@select(orm.SelectConfig{
|
||||
table: 'Test'
|
||||
is_count: false
|
||||
has_where: true
|
||||
has_order: false
|
||||
order: ''
|
||||
order_type: .asc
|
||||
has_limit: false
|
||||
primary: 'id'
|
||||
has_offset: false
|
||||
fields: ['id', 'name', 'age']
|
||||
types: [7, 18, 8]
|
||||
types: [ast.int_type_idx, ast.string_type_idx, ast.i64_type_idx]
|
||||
}, orm.QueryData{}, orm.QueryData{
|
||||
fields: ['name']
|
||||
data: [orm.Primitive('Louis'), i64(101)]
|
||||
types: [18]
|
||||
fields: ['name', 'age']
|
||||
data: [orm.Primitive('Louis'), orm.Primitive(101)]
|
||||
types: []
|
||||
kinds: [.eq, .eq]
|
||||
is_and: [true]
|
||||
kinds: [.eq]
|
||||
}) or { panic(err) }
|
||||
|
||||
id := res[0][0]
|
||||
@ -74,4 +131,97 @@ fn test_pg_orm() {
|
||||
if age is i64 {
|
||||
assert age == 101
|
||||
}
|
||||
|
||||
/** test orm sql type
|
||||
* - verify if all type create by attribute sql_type has created
|
||||
*/
|
||||
|
||||
sql db {
|
||||
create table TestCustomSqlType
|
||||
}
|
||||
|
||||
mut result_custom_sql := db.exec("
|
||||
SELECT DATA_TYPE
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_NAME = 'TestCustomSqlType'
|
||||
ORDER BY ORDINAL_POSITION
|
||||
") or {
|
||||
println(err)
|
||||
panic(err)
|
||||
}
|
||||
mut information_schema_data_types_results := []string{}
|
||||
information_schema_custom_sql := ['integer', 'text', 'character varying',
|
||||
'timestamp without time zone', 'uuid']
|
||||
for data_type in result_custom_sql {
|
||||
information_schema_data_types_results << data_type.vals[0]
|
||||
}
|
||||
|
||||
sql db {
|
||||
drop table TestCustomSqlType
|
||||
}
|
||||
|
||||
assert information_schema_data_types_results == information_schema_custom_sql
|
||||
|
||||
/** test_orm_time_type
|
||||
* - test time.Time v type with sql_type: 'TIMESTAMP'
|
||||
* - test string v type with sql_type: 'TIMESTAMP'
|
||||
* - test time.Time v type without
|
||||
*/
|
||||
today := time.parse('2022-07-16 15:13:27') or {
|
||||
println(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
model := TestTimeType{
|
||||
username: 'hitalo'
|
||||
created_at: today
|
||||
updated_at: today.str()
|
||||
deleted_at: today
|
||||
}
|
||||
|
||||
sql db {
|
||||
create table TestTimeType
|
||||
}
|
||||
|
||||
sql db {
|
||||
insert model into TestTimeType
|
||||
}
|
||||
|
||||
results := sql db {
|
||||
select from TestTimeType where username == 'hitalo'
|
||||
}
|
||||
|
||||
sql db {
|
||||
drop table TestTimeType
|
||||
}
|
||||
|
||||
assert results[0].username == model.username
|
||||
assert results[0].created_at == model.created_at
|
||||
assert results[0].updated_at == model.updated_at
|
||||
assert results[0].deleted_at == model.deleted_at
|
||||
|
||||
/** test default attribute
|
||||
*/
|
||||
sql db {
|
||||
create table TestDefaultAtribute
|
||||
}
|
||||
|
||||
mut result_defaults := db.exec("
|
||||
SELECT column_default
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_NAME = 'TestDefaultAtribute'
|
||||
ORDER BY ORDINAL_POSITION
|
||||
") or {
|
||||
println(err)
|
||||
panic(err)
|
||||
}
|
||||
mut information_schema_defaults_results := []string{}
|
||||
|
||||
for defaults in result_defaults {
|
||||
information_schema_defaults_results << defaults.vals[0]
|
||||
}
|
||||
sql db {
|
||||
drop table TestDefaultAtribute
|
||||
}
|
||||
assert ['gen_random_uuid()', '', 'CURRENT_TIMESTAMP'] == information_schema_defaults_results
|
||||
}
|
||||
|
@ -51,17 +51,18 @@ pub fn (db DB) @select(config orm.SelectConfig, data orm.QueryData, where orm.Qu
|
||||
// sql stmt
|
||||
|
||||
pub fn (db DB) insert(table string, data orm.QueryData) ? {
|
||||
query := orm.orm_stmt_gen(table, '`', .insert, true, '?', 1, data, orm.QueryData{})
|
||||
sqlite_stmt_worker(db, query, data, orm.QueryData{})?
|
||||
query, converted_data := orm.orm_stmt_gen(table, '`', .insert, true, '?', 1, data,
|
||||
orm.QueryData{})
|
||||
sqlite_stmt_worker(db, query, converted_data, orm.QueryData{})?
|
||||
}
|
||||
|
||||
pub fn (db DB) update(table string, data orm.QueryData, where orm.QueryData) ? {
|
||||
query := orm.orm_stmt_gen(table, '`', .update, true, '?', 1, data, where)
|
||||
query, _ := orm.orm_stmt_gen(table, '`', .update, true, '?', 1, data, where)
|
||||
sqlite_stmt_worker(db, query, data, where)?
|
||||
}
|
||||
|
||||
pub fn (db DB) delete(table string, where orm.QueryData) ? {
|
||||
query := orm.orm_stmt_gen(table, '`', .delete, true, '?', 1, orm.QueryData{}, where)
|
||||
query, _ := orm.orm_stmt_gen(table, '`', .delete, true, '?', 1, orm.QueryData{}, where)
|
||||
sqlite_stmt_worker(db, query, orm.QueryData{}, where)?
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,32 @@
|
||||
import orm
|
||||
import sqlite
|
||||
import v.ast
|
||||
import time
|
||||
|
||||
struct TestCustomSqlType {
|
||||
id int [primary; sql: serial]
|
||||
custom string [sql_type: 'INTEGER']
|
||||
custom1 string [sql_type: 'TEXT']
|
||||
custom2 string [sql_type: 'REAL']
|
||||
custom3 string [sql_type: 'NUMERIC']
|
||||
custom4 string
|
||||
custom5 int
|
||||
custom6 time.Time
|
||||
}
|
||||
|
||||
struct TestDefaultAtribute {
|
||||
id string [primary; sql: serial]
|
||||
name string
|
||||
created_at string [default: 'CURRENT_TIME']
|
||||
created_at1 string [default: 'CURRENT_DATE']
|
||||
created_at2 string [default: 'CURRENT_TIMESTAMP']
|
||||
}
|
||||
|
||||
fn test_sqlite_orm() {
|
||||
sdb := sqlite.connect(':memory:') or { panic(err) }
|
||||
db := orm.Connection(sdb)
|
||||
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||
defer {
|
||||
db.close() or { panic(err) }
|
||||
}
|
||||
db.create('Test', [
|
||||
orm.TableField{
|
||||
name: 'id'
|
||||
@ -68,4 +90,74 @@ fn test_sqlite_orm() {
|
||||
if age is i64 {
|
||||
assert age == 100
|
||||
}
|
||||
|
||||
/** test orm sql type
|
||||
* - verify if all type create by attribute sql_type has created
|
||||
*/
|
||||
|
||||
sql db {
|
||||
create table TestCustomSqlType
|
||||
}
|
||||
|
||||
mut result_custom_sql, mut exec_custom_code := db.exec('
|
||||
pragma table_info(TestCustomSqlType);
|
||||
')
|
||||
|
||||
assert exec_custom_code == 101
|
||||
mut table_info_types_results := []string{}
|
||||
information_schema_custom_sql := ['INTEGER', 'INTEGER', 'TEXT', 'REAL', 'NUMERIC', 'TEXT',
|
||||
'INTEGER', 'INTEGER']
|
||||
|
||||
for data_type in result_custom_sql {
|
||||
table_info_types_results << data_type.vals[2]
|
||||
}
|
||||
assert table_info_types_results == information_schema_custom_sql
|
||||
|
||||
sql db {
|
||||
drop table TestCustomSqlType
|
||||
}
|
||||
|
||||
/** test default attribute
|
||||
*/
|
||||
|
||||
sql db {
|
||||
create table TestDefaultAtribute
|
||||
}
|
||||
|
||||
mut result_default_sql, mut code := db.exec('
|
||||
pragma table_info(TestDefaultAtribute);
|
||||
')
|
||||
|
||||
assert code == 101
|
||||
mut information_schema_data_types_results := []string{}
|
||||
information_schema_default_sql := ['', '', 'CURRENT_TIME', 'CURRENT_DATE', 'CURRENT_TIMESTAMP']
|
||||
|
||||
for data_type in result_default_sql {
|
||||
information_schema_data_types_results << data_type.vals[4]
|
||||
}
|
||||
assert information_schema_data_types_results == information_schema_default_sql
|
||||
|
||||
test_default_atribute := TestDefaultAtribute{
|
||||
name: 'Hitalo'
|
||||
}
|
||||
|
||||
sql db {
|
||||
insert test_default_atribute into TestDefaultAtribute
|
||||
}
|
||||
|
||||
result_test_default_atribute := sql db {
|
||||
select from TestDefaultAtribute limit 1
|
||||
}
|
||||
|
||||
assert result_test_default_atribute.name == 'Hitalo'
|
||||
assert test_default_atribute.created_at.len == 0
|
||||
assert test_default_atribute.created_at1.len == 0
|
||||
assert test_default_atribute.created_at2.len == 0
|
||||
assert result_test_default_atribute.created_at.len == 8 // HH:MM:SS
|
||||
assert result_test_default_atribute.created_at1.len == 10 // YYYY-MM-DD
|
||||
assert result_test_default_atribute.created_at2.len == 19 // YYYY-MM-DD HH:MM:SS
|
||||
|
||||
sql db {
|
||||
drop table TestDefaultAtribute
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ fn test_sqlite() {
|
||||
fn test_can_access_sqlite_result_consts() {
|
||||
assert sqlite.sqlite_ok == 0
|
||||
assert sqlite.sqlite_error == 1
|
||||
// assert sqlite.misuse == 21
|
||||
assert sqlite.sqlite_row == 100
|
||||
assert sqlite.sqlite_done == 101
|
||||
}
|
||||
|
@ -51,6 +51,10 @@ fn (stmt Stmt) get_f64(idx int) f64 {
|
||||
|
||||
fn (stmt Stmt) get_text(idx int) string {
|
||||
b := &char(C.sqlite3_column_text(stmt.stmt, idx))
|
||||
|
||||
if b == &char(0) {
|
||||
return ''
|
||||
}
|
||||
return unsafe { b.vstring() }
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user