package engine import ( "errors" "fmt" "io" "log" "slices" "strings" "git.pablu.de/pablu/sqv-engine/sql" ) type Manager struct { parser *sql.Parser tables []Table } func NewManagerFromFile(sqlTxt string) *Manager { return &Manager{ parser: sql.NewParser(strings.NewReader(sqlTxt)), } } func (m *Manager) Start() error { for { stmt, err := m.parser.Parse() if err != nil && errors.Is(err, io.EOF) { fmt.Println("Finished parsing") break } else if err != nil { log.Fatal(err) } switch v := stmt.(type) { case *sql.CreateTableStatement: t, err := m.convertCreateTableStatementToTable(v) if err != nil { return err } m.tables = append(m.tables, t) default: panic("NOT IMPLEMENTED") } } return nil } func (m *Manager) Refresh(sqlTxt string) error { m.parser = sql.NewParser(strings.NewReader(sqlTxt)) m.tables = make([]Table, 0) return m.Start() } func (m *Manager) GetTables() []Table { return m.tables } func (m *Manager) GetTable(name string) (Table, bool) { index := slices.IndexFunc(m.tables, func(t Table) bool { return t.Name == name }) if index >= 0 { return m.tables[index], true } return Table{}, false } func (m *Manager) convertCreateTableStatementToTable(cts *sql.CreateTableStatement) (Table, error) { res := Table{ Name: cts.TableName, Columns: make([]Column, len(cts.Columns)), Rows: make([]Row, 0), } for i, column := range cts.Columns { flags := extrasToFlags(column.Extra) var ref *Column = nil if flags.Has(FOREIGN_KEY) { index := slices.IndexFunc(column.Extra, func(c string) bool { return strings.HasPrefix(c, "ref") }) refExtra := column.Extra[index] refStr := strings.Split(refExtra, " ")[1] s := strings.Split(refStr, ".") tableName := s[0] columnName := s[1] refTable, ok := m.GetTable(tableName) if !ok { fmt.Println(m.tables) return Table{}, fmt.Errorf("Reference table '%v' not found", tableName) } colIndex := slices.IndexFunc(refTable.Columns, func(c Column) bool { return c.Name == columnName }) ref = &refTable.Columns[colIndex] } res.Columns[i] = Column{ Type: column.Type, Name: column.Name, Reference: ref, Flags: flags, } } return res, nil } func extrasToFlags(extras []string) ColumnFlag { res := NONE for _, extra := range extras { // This is not good switch strings.Split(extra, " ")[0] { case "PRIMARY_KEY": res |= PRIMARY_KEY case "ref": res |= FOREIGN_KEY case "NOT_NULL": res |= NOT_NULL default: log.Panicf("NOT IMPLEMENTED EXTRA: %v", extra) } } return res }