diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1bcc288 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +_obj +*.6 +6.out +states diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3122f77 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2009 Josh Goebel + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6de67a7 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +include $(GOROOT)/src/Make.$(GOARCH) + +TARG=dm +GOFILES=\ + dm.go\ + +include $(GOROOT)/src/Make.pkg + +states: dm.a + $(GC) states.go + $(LD) -o $@ states.$O + +dm.a: dm.go + $(GC) dm.go diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..6966b12 --- /dev/null +++ b/README.txt @@ -0,0 +1,4 @@ +This is still very raw and I'm still learning Go. + +The idea is to provide some sort of ActiveRecord like wrapper on top of the +sqlite3 C API (mapped to go via cgo). \ No newline at end of file diff --git a/dm.go b/dm.go new file mode 100644 index 0000000..c4cb223 --- /dev/null +++ b/dm.go @@ -0,0 +1,175 @@ +package dm + +import ( + "sqlite3"; + "fmt"; + "strings"; + "reflect"; + "container/vector"; + "os"; + ) + +type Connection sqlite3.Handle; + +type Model struct { + table_name string; + connection Connection; +} + +type ResultSet struct { + Results *vector.Vector; +} + +type Opts map[string] interface{}; + +// func main() +// { +// +// } + +const ( + SQLITE_INTEGER = 1; + SQLITE_TEXT = 3; + SQLITE_ROW = 100; + ) + +var conn *sqlite3.Handle; +var model_map map[string] reflect.Type; + +func Init(dbname string) { + conn = new(sqlite3.Handle); + model_map = make(map[string] reflect.Type); + r := conn.Open(dbname); + if r!="" { + println("ERROR"); + } + +} + +func RegisterModel(model string, t reflect.Type) { + model_map[model]=t; +} + +func Find(model string, id int) interface{} +{ + sql := select_one_sql(model, id); + return single_result(sql, model); +} + +func FindLast(model string) interface{} { + sql := select_all_sql(model) + " order by id desc limit 1"; + return single_result(sql, model); +} + +func FindFirst(model string) interface{} { + sql := select_all_sql(model) + " limit 1"; + return single_result(sql, model); +} + +func Count(model string) int { + sql := select_count_sql(model); + res, err := Execute(sql); + if err!=0 { + defer res.Finalize(); + } + return res.ColumnInt(0); +} + +func single_result(sql string, model string) interface{} { + res, err := Execute(sql); + if err!=0 { + defer res.Finalize(); + } + o := reflect.MakeZero(model_map[model]); + build_result(o, res); + return o.Interface(); +} + +func parse_options(opts ...) (options Opts) { + v := reflect.NewValue(opts).(*reflect.StructValue); + if v.NumField() > 0 { + options = v.Field(0).Interface().(Opts); + } else { + options = Opts{}; + } + return; +} + +func FindAll(model string, opts ...) (r ResultSet) { + options := parse_options(opts); + r = ResultSet{}; + sql := ""; + limit, ok := options["limit"]; + if ok && limit.(int) > 0 { + sql = select_all_sql(model) + fmt.Sprintf (" limit %d", options["limit"].(int)) + } + else + { + sql = select_all_sql(model); + } + res, err := Execute(sql); + if err!=0 { + defer res.Finalize(); + } + r.Results = build_results(model, res); + return; +} + +func camel_case(s string) string { + return strings.ToUpper(s[0:1]) + s[1:len(s)] +} + +func build_results(model string, st *sqlite3.Statement) (r *vector.Vector) +{ + r = vector.New(0); + for i := SQLITE_ROW; i == SQLITE_ROW; i= st.Step() { + o := reflect.MakeZero(model_map[model]); + x := build_result(o, st); + r.Push(x.Interface()); + } + return; +} + +func build_result(o reflect.Value, st *sqlite3.Statement ) reflect.Value +{ + cc := st.ColumnCount(); + for i:=0; i