Commits

Greg Slepak  committed da922f6

added DF.OBJ

  • Participants
  • Parent commits abcd650

Comments (0)

Files changed (4)

 Version 0.7
 
   * all code uses new ++,--,extend,write,read functions (still compatible with older newlisps)
+  * added DB.OBJ - a very simple ORM for DF.DB
   * now $BINARY can handle large data (compensated for a newLISP bug in 'read-buffer').
   * added documentation for MAX_POST_LENGTH in request.lsp
   * fix to Jeff's JSON.lsp plugin (switched to " instead of ' for strings)

File example-site/dragonfly-framework/plugins-inactive/db/database_orm.lsp

+;; @module database_orm
+;; @description DB.OBJ - Simple Object Relational Mapping (ORM) for DF.DB
+;; @version 1.0
+;; @author Greg Slepak
+
+(DF:activate-plugin "db/database_utils")
+(new-class 'DB.OBJ)
+(context DB.OBJ)
+
+(constant 'SELECT_SQL	"SELECT %s FROM %s WHERE %s LIMIT 1"
+          'UPDATE_SQL	"UPDATE %s SET %s=? WHERE %s LIMIT 1")
+
+(define (DB.OBJ:DB.OBJ _db _table _cols _finder)
+	(if (= @self @class)
+		(autorelease (instantiate @class _db _table _cols _finder))
+		(begin
+			(set 'db _db 'table _table 'cols _cols 'finder _finder)
+			(setf revert-set (assoc-row-with-db db (format SELECT_SQL (join cols ",") table finder)))
+			(when (setf change-set revert-set)
+				(dolist (col cols)
+					(letex (attr-sym (sym col) attr-str col)
+						(define (attr-sym value from-revert-set)
+							(if value
+								(begin
+									(setf (<- attr-str change-set) value)
+									(setf dirty true))
+								(if from-revert-set
+									(<- attr-str revert-set)
+									(<- attr-str change-set))))))))))
+
+(define (DB.OBJ:refetch)
+	(set 'dirty nil
+	     'revert-set (assoc-row-with-db db (format SELECT_SQL (join (map first revert-set) ",") table finder))
+	     'change-set revert-set
+	)
+)
+
+(define (DB.OBJ:save , diff)
+	(unless (null? (setf diff (difference change-set revert-set)))
+		(when (db:execute-update (format UPDATE_SQL table (join (map first diff) "=?,") finder) (map last diff))
+			(set 'revert-set change-set 'dirty nil)
+		)
+	)
+)
+
+(context MAIN)

File example-site/dragonfly-framework/plugins-inactive/db/database_sqlite3.lsp

 ;; <h3>Requirements</h3>
 ;; See module @link http://www.taoeffect.com/newlisp/database.lsp.html DF.DB for requirements.
 ;; <h3>Version history</h3>
-;; <b>1.1.3</b> &bull; fixed handling of floats, more improvements needed though
+;; <b>1.1.3</b> &bull; temporary fix for handling of floats, now import sqlite3 functions globally
 ;; <b>1.1.2</b> &bull; fixed a bug in 'get-string-cast' and implemented 'DF.SQL:col-name'
 ;; <b>1.1.1</b> &bull; improved readability in error logging, fixed binding of integers on 32-bit newlisp builds<br/>
 ;; <b>1.1.0</b> &bull; support for 'DF.BLOB'<br/>
 				(throw-error "sqlite3 library not found. Set SQLITE3_LIBRARY_PATH."))))
 
 (set 'lib-funcs '(
-	"sqlite3_open"     "sqlite3_last_insert_rowid"   "sqlite3_changes"
-	"sqlite3_close"    "sqlite3_busy_timeout"        "sqlite3_libversion_number"
-	"sqlite3_prepare"  "sqlite3_errmsg"         
+	; functions for dealing with sqlite3 databases
+	"sqlite3_open"           "sqlite3_last_insert_rowid" "sqlite3_changes"
+	"sqlite3_close"          "sqlite3_busy_timeout"      "sqlite3_libversion_number"
+	"sqlite3_prepare"        "sqlite3_errmsg"
+	; functions for dealing with sqlite3 statements
+	"sqlite3_column_count"   "sqlite3_finalize"          "sqlite3_bind_parameter_index"
+	"sqlite3_column_name"    "sqlite3_reset"             "sqlite3_transfer_bindings"  
+	"sqlite3_column_type"    "sqlite3_errmsg"            "sqlite3_step"
+	"sqlite3_bind_int64"     "sqlite3_column_int64"      "sqlite3_bind_int"
+	"sqlite3_bind_double"    "sqlite3_column_double"     "sqlite3_column_name"
+	"sqlite3_bind_null"      "sqlite3_column_text"       "sqlite3_column_count"
+	"sqlite3_bind_text"      "sqlite3_column_blob"
+	"sqlite3_bind_blob"      "sqlite3_column_bytes"   
 ))
 
-(dolist (func lib-funcs)
-	(import library func "cdecl")
+; Switch to MAIN context and import them as global functions so that we're not copying
+; these symbols each time we create a new sql object. This is OK because they're qualified names.
+(context MAIN)
+
+(dolist (func Sqlite3:lib-funcs)
+	(global (sym func))
+	(import Sqlite3:library func "cdecl")
 )
 
 ; import possibly missing functions
-(catch (import library "sqlite3_open_v2" "cdecl") 'open_v2)
-(catch (import library "sqlite3_prepare_v2" "cdecl") 'prepare_v2)
+(catch (begin (import library "sqlite3_open_v2" "cdecl") (global 'sqlite3_open_v2)) 'Sqlite3:open_v2)
+(catch (begin (import library "sqlite3_prepare_v2" "cdecl") (global 'sqlite3_prepare_v2)) 'Sqlite3:prepare_v2)
+
+(context Sqlite3)
+
 ; if open_v2 = sqlite3_open_v2 then sqlite3_open_v2 is available
 (set 'open_v2 (= open_v2 sqlite3_open_v2)
      'prepare_v2 (= prepare_v2 sqlite3_prepare_v2)
 (def-new 'Sqlite3:good-errors)
 (def-new 'Sqlite3:failable)
 
-(set 'lib-funcs '(                                       
-	"sqlite3_column_count"   "sqlite3_finalize"         "sqlite3_bind_parameter_index"
-	"sqlite3_column_name"    "sqlite3_reset"            "sqlite3_transfer_bindings"  
-	"sqlite3_column_type"    "sqlite3_errmsg"           "sqlite3_step"
-	"sqlite3_bind_int64"     "sqlite3_column_int64"     "sqlite3_bind_int"
-	"sqlite3_bind_double"    "sqlite3_column_double"    "sqlite3_column_name"
-	"sqlite3_bind_null"      "sqlite3_column_text"      "sqlite3_column_count"
-	"sqlite3_bind_text"      "sqlite3_column_blob"       
-	"sqlite3_bind_blob"      "sqlite3_column_bytes"   
-))
-
-(dolist (func lib-funcs)
-	(import Sqlite3:library func "cdecl")
-)
-
 ; sqlite3 types
 (constant 'SQLITE_INTEGER 1 'SQLITE_BLOB    4
           'SQLITE_FLOAT   2 'SQLITE_NULL    5

File example-site/views/dragonfly_sqlite3.html

 					</tr>
 				<% ) %>
 			</table>
-			
+			<%
+				(setf obj (instantiate DB.OBJ db "people" '("name" "age") "ROWID=1"))
+			%>
+			<p>
+				I've found a person called <%=(obj:name)%> in the table '<%=obj:table%>' at location <%=obj:finder%>, this person is <%=(obj:age)%> years old.
+			</p>
+			<p>
+				Let's set their age to 10.<%(obj:age 10) (obj:save)%>
+			</p>
+			<p>
+				They are now <%=(obj:age)%> years old.
+			</p>
 		</p>
 		<p>
 			The table above was created like so: