diff options
Diffstat (limited to 'v_windows/v/vlib/orm/orm.v')
-rw-r--r-- | v_windows/v/vlib/orm/orm.v | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/v_windows/v/vlib/orm/orm.v b/v_windows/v/vlib/orm/orm.v new file mode 100644 index 0000000..960e176 --- /dev/null +++ b/v_windows/v/vlib/orm/orm.v @@ -0,0 +1,473 @@ +module orm + +import time + +pub const ( + num64 = [8, 12] + nums = [5, 6, 7, 9, 10, 11, 16] + float = [13, 14] + string = 18 + time = -2 + type_idx = { + 'i8': 5 + 'i16': 6 + 'int': 7 + 'i64': 8 + 'byte': 9 + 'u16': 10 + 'u32': 11 + 'u64': 12 + 'f32': 13 + 'f64': 14 + 'bool': 16 + 'string': 18 + } + string_max_len = 2048 +) + +pub type Primitive = InfixType | bool | byte | f32 | f64 | i16 | i64 | i8 | int | string | + time.Time | u16 | u32 | u64 + +pub enum OperationKind { + neq // != + eq // == + gt // > + lt // < + ge // >= + le // <= +} + +pub enum MathOperationKind { + add // + + sub // - + mul // * + div // / +} + +pub enum StmtKind { + insert + update + delete +} + +pub enum OrderType { + asc + desc +} + +fn (kind OperationKind) to_str() string { + str := match kind { + .neq { '!=' } + .eq { '=' } + .gt { '>' } + .lt { '<' } + .ge { '>=' } + .le { '<=' } + } + return str +} + +fn (kind OrderType) to_str() string { + return match kind { + .desc { + 'DESC' + } + .asc { + 'ASC' + } + } +} + +pub struct QueryData { +pub: + fields []string + data []Primitive + types []int + kinds []OperationKind + is_and []bool +} + +pub struct InfixType { +pub: + name string + operator MathOperationKind + right Primitive +} + +pub struct TableField { +pub: + name string + typ int + is_time bool + default_val string + is_arr bool + attrs []StructAttribute +} + +pub struct SelectConfig { +pub: + table string + is_count bool + has_where bool + has_order bool + order string + order_type OrderType + has_limit bool + primary string = 'id' // should be set if primary is different than 'id' and 'has_limit' is false + has_offset bool + fields []string + types []int +} + +pub interface Connection { + @select(config SelectConfig, data QueryData, where QueryData) ?[][]Primitive + insert(table string, data QueryData) ? + update(table string, data QueryData, where QueryData) ? + delete(table string, where QueryData) ? + create(table string, fields []TableField) ? + drop(talbe string) ? + last_id() Primitive +} + +pub fn orm_stmt_gen(table string, para string, kind StmtKind, num bool, qm string, start_pos int, data QueryData, where QueryData) string { + mut str := '' + + mut c := start_pos + + match kind { + .insert { + mut values := []string{} + + for _ in 0 .. data.fields.len { + // loop over the length of data.field and generate ?0, ?1 or just ? based on the $num parameter for value placeholders + if num { + values << '$qm$c' + c++ + } else { + values << '$qm' + } + } + + str += 'INSERT INTO $para$table$para (' + str += data.fields.map('$para$it$para').join(', ') + str += ') VALUES (' + str += values.join(', ') + str += ')' + } + .update { + str += 'UPDATE $para$table$para SET ' + for i, field in data.fields { + str += '$para$field$para = ' + if data.data.len > i { + d := data.data[i] + if d is InfixType { + op := match d.operator { + .add { + '+' + } + .sub { + '-' + } + .mul { + '*' + } + .div { + '/' + } + } + str += '$d.name $op $qm' + } else { + str += '$qm' + } + } else { + str += '$qm' + } + if num { + str += '$c' + c++ + } + if i < data.fields.len - 1 { + str += ', ' + } + } + str += ' WHERE ' + } + .delete { + str += 'DELETE FROM $para$table$para WHERE ' + } + } + if kind == .update || kind == .delete { + for i, field in where.fields { + str += '$para$field$para ${where.kinds[i].to_str()} $qm' + if num { + str += '$c' + c++ + } + if i < where.fields.len - 1 { + str += ' AND ' + } + } + } + str += ';' + return str +} + +pub fn orm_select_gen(orm SelectConfig, para string, num bool, qm string, start_pos int, where QueryData) string { + mut str := 'SELECT ' + + if orm.is_count { + str += 'COUNT(*)' + } else { + for i, field in orm.fields { + str += '$para$field$para' + if i < orm.fields.len - 1 { + str += ', ' + } + } + } + + str += ' FROM $para$orm.table$para' + + mut c := start_pos + + if orm.has_where { + str += ' WHERE ' + for i, field in where.fields { + str += '$para$field$para ${where.kinds[i].to_str()} $qm' + if num { + str += '$c' + c++ + } + if i < where.fields.len - 1 { + if where.is_and[i] { + str += ' AND ' + } else { + str += ' OR ' + } + } + } + } + + str += ' ORDER BY ' + if orm.has_order { + str += '$para$orm.order$para ' + str += orm.order_type.to_str() + } else { + str += '$para$orm.primary$para ' + str += orm.order_type.to_str() + } + + if orm.has_limit { + str += ' LIMIT ?' + if num { + str += '$c' + c++ + } + } + + if orm.has_offset { + str += ' OFFSET ?' + if num { + str += '$c' + c++ + } + } + + str += ';' + return str +} + +pub fn orm_table_gen(table string, para string, defaults bool, def_unique_len int, fields []TableField, sql_from_v fn (int) ?string, alternative bool) ?string { + mut str := 'CREATE TABLE IF NOT EXISTS $para$table$para (' + + if alternative { + str = 'IF NOT EXISTS (SELECT * FROM sysobjects WHERE name=$para$table$para and xtype=${para}U$para) CREATE TABLE $para$table$para (' + } + + mut fs := []string{} + mut unique_fields := []string{} + mut unique := map[string][]string{} + mut primary := '' + + for field in fields { + if field.is_arr { + continue + } + mut no_null := false + mut is_unique := false + mut is_skip := false + mut unique_len := 0 + // mut fkey := '' + mut field_name := sql_field_name(field) + for attr in field.attrs { + match attr.name { + 'primary' { + primary = field.name + } + 'unique' { + if attr.arg != '' { + if attr.kind == .string { + unique[attr.arg] << field_name + continue + } else if attr.kind == .number { + unique_len = attr.arg.int() + is_unique = true + continue + } + } + is_unique = true + } + 'nonull' { + no_null = true + } + 'skip' { + is_skip = true + } + /*'fkey' { + if attr.arg != '' { + if attr.kind == .string { + fkey = attr.arg + continue + } + } + }*/ + else {} + } + } + if is_skip { + continue + } + mut stmt := '' + mut ctyp := sql_from_v(sql_field_type(field)) or { + field_name = '${field_name}_id' + sql_from_v(7) ? + } + if ctyp == '' { + return error('Unknown type ($field.typ) for field $field.name in struct $table') + } + stmt = '$para$field_name$para $ctyp' + if defaults && field.default_val != '' { + stmt += ' DEFAULT $field.default_val' + } + if no_null { + stmt += ' NOT NULL' + } + if is_unique { + mut f := 'UNIQUE($para$field_name$para' + if ctyp == 'TEXT' && def_unique_len > 0 { + if unique_len > 0 { + f += '($unique_len)' + } else { + f += '($def_unique_len)' + } + } + f += ')' + unique_fields << f + } + fs << stmt + } + if primary == '' { + return error('A primary key is required for $table') + } + if unique.len > 0 { + for k, v in unique { + mut tmp := []string{} + for f in v { + tmp << '$para$f$para' + } + fs << '/* $k */UNIQUE(${tmp.join(', ')})' + } + } + fs << 'PRIMARY KEY($para$primary$para)' + fs << unique_fields + str += fs.join(', ') + str += ');' + return str +} + +fn sql_field_type(field TableField) int { + mut typ := field.typ + if field.is_time { + return -2 + } + for attr in field.attrs { + if attr.kind == .plain && attr.name == 'sql' && attr.arg != '' { + if attr.arg.to_lower() == 'serial' { + typ = -1 + break + } + typ = orm.type_idx[attr.arg] + break + } + } + return typ +} + +fn sql_field_name(field TableField) string { + mut name := field.name + for attr in field.attrs { + if attr.name == 'sql' && attr.has_arg && attr.kind == .string { + name = attr.arg + break + } + } + return name +} + +// needed for backend functions + +pub fn bool_to_primitive(b bool) Primitive { + return Primitive(b) +} + +pub fn f32_to_primitive(b f32) Primitive { + return Primitive(b) +} + +pub fn f64_to_primitive(b f64) Primitive { + return Primitive(b) +} + +pub fn i8_to_primitive(b i8) Primitive { + return Primitive(b) +} + +pub fn i16_to_primitive(b i16) Primitive { + return Primitive(b) +} + +pub fn int_to_primitive(b int) Primitive { + return Primitive(b) +} + +pub fn i64_to_primitive(b i64) Primitive { + return Primitive(b) +} + +pub fn byte_to_primitive(b byte) Primitive { + return Primitive(b) +} + +pub fn u16_to_primitive(b u16) Primitive { + return Primitive(b) +} + +pub fn u32_to_primitive(b u32) Primitive { + return Primitive(b) +} + +pub fn u64_to_primitive(b u64) Primitive { + return Primitive(b) +} + +pub fn string_to_primitive(b string) Primitive { + return Primitive(b) +} + +pub fn time_to_primitive(b time.Time) Primitive { + return Primitive(b) +} + +pub fn infix_to_primitive(b InfixType) Primitive { + return Primitive(b) +} |