add lots of unit tests to postgresql

select queries are generated now
db4
Doug Coleman 2008-02-19 16:00:50 -06:00
parent 78d5798082
commit c12600815f
6 changed files with 480 additions and 183 deletions

View File

@ -23,12 +23,12 @@ HOOK: db-close db ( handle -- )
db-handle db-close db-handle db-close
] with-variable ; ] with-variable ;
TUPLE: statement sql params handle bound? slot-names ; TUPLE: statement handle sql slot-names bind-params bound? ;
TUPLE: simple-statement ; TUPLE: simple-statement ;
TUPLE: prepared-statement ; TUPLE: prepared-statement ;
HOOK: <simple-statement> db ( str -- statement ) HOOK: <simple-statement> db ( str -- statement )
HOOK: <prepared-statement> db ( str -- statement ) HOOK: <prepared-statement> db ( str slot-names -- statement )
GENERIC: prepare-statement ( statement -- ) GENERIC: prepare-statement ( statement -- )
GENERIC: bind-statement* ( obj statement -- ) GENERIC: bind-statement* ( obj statement -- )
GENERIC: reset-statement ( statement -- ) GENERIC: reset-statement ( statement -- )
@ -47,7 +47,7 @@ GENERIC: more-rows? ( result-set -- ? )
: bind-statement ( obj statement -- ) : bind-statement ( obj statement -- )
dup statement-bound? [ dup reset-statement ] when dup statement-bound? [ dup reset-statement ] when
[ bind-statement* ] 2keep [ bind-statement* ] 2keep
[ set-statement-params ] keep [ set-statement-bind-params ] keep
t swap set-statement-bound? ; t swap set-statement-bound? ;
: init-result-set ( result-set -- ) : init-result-set ( result-set -- )
@ -55,7 +55,7 @@ GENERIC: more-rows? ( result-set -- ? )
0 swap set-result-set-n ; 0 swap set-result-set-n ;
: <result-set> ( query handle tuple -- result-set ) : <result-set> ( query handle tuple -- result-set )
>r >r { statement-sql statement-params } get-slots r> >r >r { statement-sql statement-bind-params } get-slots r>
{ {
set-result-set-sql set-result-set-sql
set-result-set-params set-result-set-params

4
extra/db/postgresql/lib/lib.factor Normal file → Executable file
View File

@ -37,8 +37,8 @@ IN: db.postgresql.lib
: do-postgresql-bound-statement ( statement -- res ) : do-postgresql-bound-statement ( statement -- res )
>r db get db-handle r> >r db get db-handle r>
[ statement-sql ] keep [ statement-sql ] keep
[ statement-params length f ] keep [ statement-bind-params length f ] keep
statement-params statement-bind-params
[ first number>string* malloc-char-string ] map >c-void*-array [ first number>string* malloc-char-string ] map >c-void*-array
f f 0 PQexecParams f f 0 PQexecParams
dup postgresql-result-ok? [ dup postgresql-result-ok? [

226
extra/db/postgresql/postgresql-tests.factor Normal file → Executable file
View File

@ -111,6 +111,8 @@ IN: temporary
] unit-test ] unit-test
: with-dummy-db ( quot -- )
>r T{ postgresql-db } db r> with-variable ;
! TEST TUPLE DB ! TEST TUPLE DB
@ -119,8 +121,8 @@ TUPLE: puppy id name age ;
{ set-puppy-name set-puppy-age } puppy construct ; { set-puppy-name set-puppy-age } puppy construct ;
puppy "PUPPY" { puppy "PUPPY" {
{ "id" "ID" +native-id+ } { "id" "ID" +native-id+ +not-null+ }
{ "name" "NAME" TEXT } { "name" "NAME" { VARCHAR 256 } }
{ "age" "AGE" INTEGER } { "age" "AGE" INTEGER }
} define-persistent } define-persistent
@ -129,7 +131,7 @@ TUPLE: kitty id name age ;
{ set-kitty-name set-kitty-age } kitty construct ; { set-kitty-name set-kitty-age } kitty construct ;
kitty "KITTY" { kitty "KITTY" {
{ "id" "ID" +native-id+ } { "id" "ID" INTEGER +assigned-id+ }
{ "name" "NAME" TEXT } { "name" "NAME" TEXT }
{ "age" "AGE" INTEGER } { "age" "AGE" INTEGER }
} define-persistent } define-persistent
@ -137,20 +139,226 @@ kitty "KITTY" {
TUPLE: basket id puppies kitties ; TUPLE: basket id puppies kitties ;
basket "BASKET" basket "BASKET"
{ {
{ "id" "ID" +native-id+ } { "id" "ID" +native-id+ +not-null+ }
{ "location" "LOCATION" TEXT } { "location" "LOCATION" TEXT }
{ "puppies" { +has-many+ puppy } } { "puppies" { +has-many+ puppy } }
{ "kitties" { +has-many+ kitty } } { "kitties" { +has-many+ kitty } }
} define-persistent } define-persistent
! Create table
[ [
{ "name" "age" } "create table puppy(id serial primary key not null, name varchar 256, age integer);"
! "insert into table puppy(name, age) values($1, $2);"
"select add_puppy($1, $2, $3);"
] [ ] [
T{ postgresql-db } db [ T{ postgresql-db } db [
"Mr Clunkers" 3 <puppy> puppy dup db-columns swap db-table create-table-sql >lower
class dup db-columns swap db-table insert-sql* >lower
] with-variable ] with-variable
] unit-test ] unit-test
[
"create table kitty(id integer primary key, name text, age integer);"
] [
T{ postgresql-db } db [
kitty dup db-columns swap db-table create-table-sql >lower
] with-variable
] unit-test
[
"create table basket(id serial primary key not null, location text);"
] [
T{ postgresql-db } db [
basket dup db-columns swap db-table create-table-sql >lower
] with-variable
] unit-test
! Create function
[
"create function add_puppy(varchar,integer) returns bigint as 'insert into puppy(name, age) values($1, $2); select currval(''puppy_id_seq'');' language sql;"
] [
T{ postgresql-db } db [
puppy dup db-columns swap db-table create-function-sql >lower
] with-variable
] unit-test
! Drop table
[
"drop table puppy;"
] [
T{ postgresql-db } db [
puppy db-table drop-table-sql >lower
] with-variable
] unit-test
[
"drop table kitty;"
] [
T{ postgresql-db } db [
kitty db-table drop-table-sql >lower
] with-variable
] unit-test
[
"drop table basket;"
] [
T{ postgresql-db } db [
basket db-table drop-table-sql >lower
] with-variable
] unit-test
! Drop function
[
"drop function add_puppy(varchar, integer);"
] [
T{ postgresql-db } db [
puppy dup db-columns swap db-table drop-function-sql >lower
] with-variable
] unit-test
! Insert
[
"select add_puppy($1, $2);"
{
T{ sql-spec f "name" "NAME" { VARCHAR 256 } { } }
T{ sql-spec f "age" "AGE" INTEGER { } }
}
{
T{ sql-spec f "id" "ID" +native-id+ { +not-null+ } +native-id+ }
}
] [
T{ postgresql-db } db [
puppy dup db-columns swap db-table insert-sql* >r >r >lower r> r>
] with-variable
] unit-test
[
"insert into kitty(id, name, age) values($1, $2, $3);"
{
T{
sql-spec
f
"id"
"ID"
INTEGER
{ +assigned-id+ }
+assigned-id+
}
T{ sql-spec f "name" "NAME" TEXT { } f }
T{ sql-spec f "age" "AGE" INTEGER { } f }
}
{ }
] [
T{ postgresql-db } db [
kitty dup db-columns swap db-table insert-sql* >r >r >lower r> r>
] with-variable
] unit-test
! Update
[
"update puppy set name = $1, age = $2 where id = $3"
{
T{ sql-spec f "name" "NAME" { VARCHAR 256 } { } f }
T{ sql-spec f "age" "AGE" INTEGER { } f }
T{
sql-spec
f
"id"
"ID"
+native-id+
{ +not-null+ }
+native-id+
}
}
{ }
] [
T{ postgresql-db } db [
puppy dup db-columns swap db-table update-sql* >r >r >lower r> r>
] with-variable
] unit-test
[
"update kitty set name = $1, age = $2 where id = $3"
{
T{ sql-spec f "name" "NAME" TEXT { } f }
T{ sql-spec f "age" "AGE" INTEGER { } f }
T{
sql-spec
f
"id"
"ID"
INTEGER
{ +assigned-id+ }
+assigned-id+
}
}
{ }
] [
T{ postgresql-db } db [
kitty dup db-columns swap db-table update-sql* >r >r >lower r> r>
] with-variable
] unit-test
! Delete
[
"delete from puppy where id = $1"
{
T{
sql-spec
f
"id"
"ID"
+native-id+
{ +not-null+ }
+native-id+
}
}
{ }
] [
T{ postgresql-db } db [
puppy dup db-columns swap db-table delete-sql* >r >r >lower r> r>
] with-variable
] unit-test
[
"delete from KITTY where ID = $1"
{
T{
sql-spec
f
"id"
"ID"
INTEGER
{ +assigned-id+ }
+assigned-id+
}
}
{ }
] [
T{ postgresql-db } db [
kitty dup db-columns swap db-table delete-sql*
] with-variable
] unit-test
! Select
[
"select from PUPPY ID, NAME, AGE where NAME = $1;"
{ T{ sql-spec f "name" "NAME" { VARCHAR 256 } { } f } }
{
T{
sql-spec
f
"id"
"ID"
+native-id+
{ +not-null+ }
+native-id+
}
T{ sql-spec f "name" "NAME" { VARCHAR 256 } { } f }
T{ sql-spec f "age" "AGE" INTEGER { } f }
}
] [
T{ postgresql-db } db [
T{ puppy f f "Mr. Clunkers" }
select-by-slots-sql
] with-variable
] unit-test

View File

@ -4,7 +4,7 @@ USING: arrays assocs alien alien.syntax continuations io
kernel math math.parser namespaces prettyprint quotations kernel math math.parser namespaces prettyprint quotations
sequences debugger db db.postgresql.lib db.postgresql.ffi sequences debugger db db.postgresql.lib db.postgresql.ffi
db.tuples db.types tools.annotations math.ranges db.tuples db.types tools.annotations math.ranges
combinators sequences.lib classes ; combinators sequences.lib classes locals words ;
IN: db.postgresql IN: db.postgresql
TUPLE: postgresql-db host port pgopts pgtty db user pass ; TUPLE: postgresql-db host port pgopts pgtty db user pass ;
@ -39,7 +39,7 @@ M: postgresql-db dispose ( db -- )
>r <postgresql-db> r> with-disposal ; >r <postgresql-db> r> with-disposal ;
M: postgresql-statement bind-statement* ( seq statement -- ) M: postgresql-statement bind-statement* ( seq statement -- )
set-statement-params ; set-statement-bind-params ;
M: postgresql-statement reset-statement ( statement -- ) M: postgresql-statement reset-statement ( statement -- )
drop ; drop ;
@ -68,7 +68,7 @@ M: postgresql-statement insert-statement ( statement -- id )
query-results [ 0 row-column ] with-disposal string>number ; query-results [ 0 row-column ] with-disposal string>number ;
M: postgresql-statement query-results ( query -- result-set ) M: postgresql-statement query-results ( query -- result-set )
dup statement-params [ dup statement-bind-params [
over [ bind-statement ] keep over [ bind-statement ] keep
do-postgresql-bound-statement do-postgresql-bound-statement
] [ ] [
@ -96,7 +96,7 @@ M: postgresql-result-set dispose ( result-set -- )
M: postgresql-statement prepare-statement ( statement -- ) M: postgresql-statement prepare-statement ( statement -- )
[ [
>r db get db-handle "" r> >r db get db-handle "" r>
dup statement-sql swap statement-params dup statement-sql swap statement-bind-params
length f PQprepare postgresql-error length f PQprepare postgresql-error
] keep set-statement-handle ; ] keep set-statement-handle ;
@ -104,9 +104,10 @@ M: postgresql-db <simple-statement> ( sql -- statement )
{ set-statement-sql } statement construct { set-statement-sql } statement construct
<postgresql-statement> ; <postgresql-statement> ;
M: postgresql-db <prepared-statement> ( sql -- statement ) M: postgresql-db <prepared-statement> ( pair -- statement )
{ set-statement-sql } statement construct ?first2
<postgresql-statement> ; { set-statement-sql set-statement-slot-names }
statement construct <postgresql-statement> ;
M: postgresql-db begin-transaction ( -- ) M: postgresql-db begin-transaction ( -- )
"BEGIN" sql-command ; "BEGIN" sql-command ;
@ -117,134 +118,179 @@ M: postgresql-db commit-transaction ( -- )
M: postgresql-db rollback-transaction ( -- ) M: postgresql-db rollback-transaction ( -- )
"ROLLBACK" sql-command ; "ROLLBACK" sql-command ;
: insert-function ( columns table -- sql types ) : modifiers% ( spec -- )
sql-spec-modifiers
[ lookup-modifier ] map
" " join
dup empty? [ drop ] [ " " % % ] if ;
SYMBOL: postgresql-counter
: bind% ( spec -- )
1,
CHAR: $ 0,
postgresql-counter [ inc ] keep get 0# ;
: postgresql-make ( quot -- )
[ postgresql-counter off ] swap compose
{ "" { } { } } nmake ;
:: create-table-sql | specs table |
[ [
>r remove-id r> "create table " % table %
"create function add_" % dup %
"(" % "(" %
over [ "," % ] specs [ ", " % ] [
[ third dup array? [ first ] when >sql-type-string % ] interleave dup sql-spec-column-name %
")" % " " %
" returns bigint as '" % dup sql-spec-type t lookup-type %
modifiers%
] interleave ");" %
] "" make ;
2dup "insert into " % :: create-function-sql | specs table |
% [
"(" % [let | specs [ specs remove-id ] |
dup [ ", " % ] [ second % ] interleave "create function add_" 0% table 0%
") " % "(" 0%
" values (" % specs [ "," 0% ]
length [1,b] [ ", " % ] [ "$" % # ] interleave [
"); " % sql-spec-type f lookup-type 0%
] interleave
"select currval(''" % % "_id_seq'');' language sql;" % ")" 0%
drop " returns bigint as '" 0%
] "" make f ;
"insert into " 0%
: drop-function ( columns table -- sql ) table 0%
"(" 0%
specs [ ", " 0% ] [ sql-spec-column-name 0% ] interleave
") values(" 0%
specs [ ", " 0% ] [ bind% ] interleave
"); " 0%
"select currval(''" 0% table 0% "_id_seq'');' language sql;" 0%
]
] postgresql-make 2drop ;
: drop-function-sql ( specs table -- sql )
[ [
>r remove-id r>
"drop function add_" % % "drop function add_" % %
"(" % "(" %
[ "," % ] [ third >sql-type-string % ] interleave remove-id
")" % [ ", " % ] [ sql-spec-type f lookup-type % ] interleave
] "" nmake ;
! M: postgresql-db create-sql ( columns table -- seq )
! [
! [
! 2dup
! "create table " % %
! " (" % [ ", " % ] [
! dup second % " " %
! dup third >sql-type-string % " " %
! sql-modifiers " " join %
! ] interleave "); " %
! ] "" make ,
!
! over native-id? [ insert-function , ] [ 2drop ] if
! ] { } make ;
M: postgresql-db drop-sql ( columns table -- seq )
[
[
dup "drop table " % % ";" %
] "" make ,
over native-id? [ drop-function , ] [ 2drop ] if
] { } make ;
M: postgresql-db insert-sql* ( columns table -- sql slots )
[
"select add_" % %
"(" %
dup length [1,b] [ ", " % ] [ "$" % # ] interleave
");" % ");" %
] "" make ; ] "" make ;
M: postgresql-db update-sql* ( columns table -- sql slots ) : drop-table-sql ( table -- sql )
[ [
"update " % "drop table " % % ";" %
% ] "" make ;
" set " %
M: postgresql-db create-sql ( specs table -- seq )
[
2dup create-table-sql ,
over find-primary-key native-id?
[ create-function-sql , ] [ 2drop ] if
] { } make ;
M: postgresql-db drop-sql ( specs table -- seq )
[
dup drop-table-sql ,
over find-primary-key native-id?
[ drop-function-sql , ] [ 2drop ] if
] { } make ;
: insert-table-sql ( specs table -- sql in-specs out-specs )
[
"insert into " 0% 0%
"(" 0%
dup [ ", " 0% ] [ sql-spec-column-name 0% ] interleave
")" 0%
" values(" 0%
[ ", " 0% ] [ bind% ] interleave
");" 0%
] postgresql-make ;
: insert-function-sql ( specs table -- sql in-specs out-specs )
[
"select add_" 0% 0%
"(" 0%
dup find-primary-key 2,
remove-id
[ ", " 0% ] [ bind% ] interleave
");" 0%
] postgresql-make ;
M: postgresql-db insert-sql* ( specs table -- sql in-specs out-specs )
over find-primary-key native-id?
[ insert-function-sql ] [ insert-table-sql ] if ;
M: postgresql-db update-sql* ( specs table -- sql in-specs out-specs )
[
"update " 0% 0%
" set " 0%
dup remove-id dup remove-id
dup length [1,b] swap 2array flip [ ", " 0% ]
[ ", " % ] [ first2 second % " = $" % # ] interleave [ dup sql-spec-column-name 0% " = " 0% bind% ] interleave
" where " % " where " 0%
[ primary-key? ] find nip second dup % " = $" % length 2 + # find-primary-key
] "" make ; dup sql-spec-column-name 0% " = " 0% bind%
] postgresql-make ;
M: postgresql-db delete-sql* ( columns table -- slot-names sql ) M: postgresql-db delete-sql* ( specs table -- sql in-specs out-specs )
[ [
"delete from " % "delete from " 0% 0%
% " where " 0%
" where " % find-primary-key
first second % " = $1" % dup sql-spec-column-name 0% " = " 0% bind%
] "" make ; ] postgresql-make ;
: column-name% ( spec -- ) : select-by-slots-sql ( tuple -- sql in-specs out-specs )
dup sql-spec-column-name 0%
sql-spec-type >sql-type-string 1, ;
: column-names% ( class -- )
db-columns [ "," 0, ] [ column-name% ] interleave ;
M: postgresql-db column-bind% ( spec -- )
;
! : select-foreign-table-sql ( tuple relation -- )
! ! select id, name, age from puppy, basket where puppy.basket_id = basket.id
! "select " 0%
! ;
! TODO
: select-relations-sql ( tuple -- seq )
! seq -- { sql types }
dup class db-relations [
[
! select-foreign-table-sql
] { "" { } } 2 nmake
] with { } map>assoc ;
! TODO
: select-by-slots-sql ( tuple -- sql )
dup tuple>filled-slots
;
M: postgresql-db select-sql ( tuple -- sql slot-names )
[ [
"select from " 0% dup class db-table 0%
] { } 2 nmake ; " " 0%
dup class db-columns [ ", " 0% ]
[ dup sql-spec-column-name 0% 2, ] interleave
M: postgresql-db tuple>params ( columns tuple -- obj ) dup class db-columns
[ sql-spec-slot-name swap get-slot-named ] with subset
" where " 0%
[ ", " 0% ]
[ dup sql-spec-column-name 0% " = " 0% bind% ] interleave
";" 0%
] postgresql-make ;
! : select-with-relations ( tuple -- sql in-specs out-specs )
M: postgresql-db select-sql ( tuple -- sql in-specs out-specs )
select-by-slots-sql ;
M: postgresql-db tuple>params ( specs tuple -- obj )
[ >r dup third swap first r> get-slot-named swap ] [ >r dup third swap first r> get-slot-named swap ]
curry { } map>assoc ; curry { } map>assoc ;
M: postgresql-db type-table ( -- hash )
H{
{ +native-id+ "integer" }
{ TEXT "text" }
{ VARCHAR "varchar" }
{ INTEGER "integer" }
} ;
M: postgresql-db create-type-table ( -- hash )
H{
{ +native-id+ "serial primary key" }
} ;
: postgresql-compound ( str n -- newstr )
dup number? [ "compound -- not a number" throw ] unless
number>string " " swap 3append ;
M: postgresql-db compound-modifier ( str n -- newstr )
postgresql-compound ;
: postgresql-db-modifiers ( -- hashtable ) M: postgresql-db modifier-table ( -- hashtable )
H{ H{
{ +native-id+ "primary key" } { +native-id+ "primary key" }
{ +foreign-key+ "" }
{ +assigned-id+ "primary key" } { +assigned-id+ "primary key" }
{ +autoincrement+ "autoincrement" } { +autoincrement+ "autoincrement" }
{ +unique+ "unique" } { +unique+ "unique" }
@ -253,16 +299,5 @@ M: postgresql-db tuple>params ( columns tuple -- obj )
{ +not-null+ "not null" } { +not-null+ "not null" }
} ; } ;
! M: postgresql-db sql-modifier>string ( modifier -- str ) M: postgresql-db compound-type ( str n -- newstr )
! dup array? [ postgresql-compound ;
! first2
! >r swap at r> number>string*
! " " swap 3append
! ] [
! swap at
! ] if ;
!
! M: postgresql-db sql-modifiers* ( modifiers -- str )
! postgresql-db-modifiers swap [
! sql-modifier>string
! ] with map [ ] subset ;

View File

@ -47,6 +47,7 @@ HOOK: insert-sql* db ( columns table -- sql slot-names )
HOOK: update-sql* db ( columns table -- sql slot-names ) HOOK: update-sql* db ( columns table -- sql slot-names )
HOOK: delete-sql* db ( columns table -- sql slot-names ) HOOK: delete-sql* db ( columns table -- sql slot-names )
HOOK: select-sql db ( tuple -- seq/statement ) HOOK: select-sql db ( tuple -- seq/statement )
HOOK: select-relations-sql db ( tuple -- seq/statement )
HOOK: row-column-typed db ( result-set n type -- sql ) HOOK: row-column-typed db ( result-set n type -- sql )
HOOK: sql-type>factor-type db ( obj type -- obj ) HOOK: sql-type>factor-type db ( obj type -- obj )
@ -101,7 +102,8 @@ HOOK: tuple>params db ( columns tuple -- obj )
: define-persistent ( class table columns -- ) : define-persistent ( class table columns -- )
>r dupd "db-table" set-word-prop dup r> >r dupd "db-table" set-word-prop dup r>
[ relation? ] partition swapd [ relation? ] partition swapd
[ spec>tuple ] map "db-columns" set-word-prop [ spec>tuple ] map
"db-columns" set-word-prop
"db-relations" set-word-prop ; "db-relations" set-word-prop ;
: tuple>filled-slots ( tuple -- alist ) : tuple>filled-slots ( tuple -- alist )
@ -117,13 +119,17 @@ SYMBOL: building-seq
: n, get-building-seq push ; : n, get-building-seq push ;
: n% get-building-seq push-all ; : n% get-building-seq push-all ;
: n# >r number>string r> n% ;
: 0, 0 n, ; : 0, 0 n, ;
: 0% 0 n% ; : 0% 0 n% ;
: 0# 0 n# ;
: 1, 1 n, ; : 1, 1 n, ;
: 1% 1 n% ; : 1% 1 n% ;
: 1# 1 n# ;
: 2, 2 n, ; : 2, 2 n, ;
: 2% 2 n% ; : 2% 2 n% ;
: 2# 2 n# ;
: nmake ( quot exemplars -- seqs ) : nmake ( quot exemplars -- seqs )
dup length dup zero? [ 1+ ] when dup length dup zero? [ 1+ ] when

View File

@ -1,21 +1,38 @@
! Copyright (C) 2008 Doug Coleman. ! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: arrays assocs db kernel math math.parser USING: arrays assocs db kernel math math.parser
sequences continuations sequences.deep sequences.lib ; sequences continuations sequences.deep sequences.lib
words ;
IN: db.types IN: db.types
TUPLE: sql-spec slot-name column-name type modifiers primary-key ;
! ID is the Primary key ! ID is the Primary key
! +native-id+ can be a columns type or a modifier
SYMBOL: +native-id+ SYMBOL: +native-id+
! +assigned-id+ can only be a modifier
SYMBOL: +assigned-id+ SYMBOL: +assigned-id+
: primary-key? ( spec -- ? ) : primary-key? ( obj -- ? )
[ { +native-id+ +assigned-id+ } member? ] contains? ; { +native-id+ +assigned-id+ } member? ;
: contains-id? ( columns id -- ? ) : normalize-spec ( spec -- )
swap [ member? ] with contains? ; dup sql-spec-type dup primary-key? [
swap set-sql-spec-primary-key
: assigned-id? ( columns -- ? ) +assigned-id+ contains-id? ; ] [
: native-id? ( columns -- ? ) +native-id+ contains-id? ; drop dup sql-spec-modifiers [
primary-key?
] deep-find
[ swap set-sql-spec-primary-key ] [ drop ] if*
] if ;
: find-primary-key ( specs -- obj )
[ sql-spec-primary-key ] find nip ;
: native-id? ( spec -- ? )
sql-spec-primary-key +native-id+ = ;
: assigned-id? ( spec -- ? )
sql-spec-primary-key +assigned-id+ = ;
SYMBOL: +foreign-key+ SYMBOL: +foreign-key+
@ -31,7 +48,7 @@ SYMBOL: +not-null+
SYMBOL: +has-many+ SYMBOL: +has-many+
: relation? ( spec -- ? ) : relation? ( spec -- ? )
[ +has-many+ = ] deep-find* nip ; [ +has-many+ = ] deep-find ;
SYMBOL: INTEGER SYMBOL: INTEGER
SYMBOL: BIG_INTEGER SYMBOL: BIG_INTEGER
@ -45,30 +62,15 @@ SYMBOL: VARCHAR
SYMBOL: TIMESTAMP SYMBOL: TIMESTAMP
SYMBOL: DATE SYMBOL: DATE
TUPLE: no-sql-type ;
: no-sql-type ( -- * ) T{ no-sql-type } throw ;
: number>string* ( n/str -- str )
dup number? [ number>string ] when ;
: maybe-remove-id ( columns -- obj )
[ +native-id+ swap member? not ] subset ;
: remove-relations ( columns -- newcolumns )
[ relation? not ] subset ;
: remove-id ( columns -- obj )
[ primary-key? not ] subset ;
! SQLite Types: http://www.sqlite.org/datatype3.html
! NULL INTEGER REAL TEXT BLOB
! PostgreSQL Types:
! http://developer.postgresql.org/pgdocs/postgres/datatype.html
TUPLE: sql-spec slot-name column-name type modifiers ;
: spec>tuple ( spec -- tuple ) : spec>tuple ( spec -- tuple )
[ ?first3 ] keep 3 ?tail* sql-spec construct-boa ; [ ?first3 ] keep 3 ?tail*
{
set-sql-spec-slot-name
set-sql-spec-column-name
set-sql-spec-type
set-sql-spec-modifiers
} sql-spec construct
dup normalize-spec ;
: sql-type-hash ( -- assoc ) : sql-type-hash ( -- assoc )
H{ H{
@ -79,16 +81,62 @@ TUPLE: sql-spec slot-name column-name type modifiers ;
{ TIMESTAMP "timestamp" } { TIMESTAMP "timestamp" }
} ; } ;
! HOOK: sql-type-hash db ( -- obj ) TUPLE: no-sql-type ;
! HOOK: >sql-type-string db ( obj -- str ) : no-sql-type ( -- * ) T{ no-sql-type } throw ;
: >sql-type-string ( obj -- str/f ) TUPLE: no-sql-modifier ;
: no-sql-modifier ( -- * ) T{ no-sql-modifier } throw ;
: number>string* ( n/str -- str )
dup number? [ number>string ] when ;
: maybe-remove-id ( specs -- obj )
[ native-id? not ] subset ;
: remove-relations ( specs -- newcolumns )
[ relation? not ] subset ;
: remove-id ( specs -- obj )
[ sql-spec-primary-key not ] subset ;
! SQLite Types: http://www.sqlite.org/datatype3.html
! NULL INTEGER REAL TEXT BLOB
! PostgreSQL Types:
! http://developer.postgresql.org/pgdocs/postgres/datatype.html
HOOK: modifier-table db ( -- hash )
HOOK: compound-modifier db ( str n -- hash )
: lookup-modifier ( obj -- str )
dup pair? [ dup pair? [
first >sql-type-string first2 >r lookup-modifier r> compound-modifier
] [ ] [
sql-type-hash at* [ drop "" ] unless modifier-table at*
[ "unknown modifier" throw ] unless
] if ; ] if ;
: full-sql-type-string ( obj -- str )
[ >sql-type-string ] keep second HOOK: type-table db ( -- hash )
number>string " " swap 3append ; HOOK: create-type-table db ( -- hash )
HOOK: compound-type db ( str n -- hash )
: lookup-type* ( obj -- str )
dup pair? [
first lookup-type*
] [
type-table at*
[ no-sql-type ] unless
] if ;
: lookup-create-type ( obj -- str )
dup pair? [
first2 >r lookup-create-type r> compound-type
] [
dup create-type-table at*
[ nip ] [ drop lookup-type* ] if
] if ;
: lookup-type ( obj create? -- str )
[ lookup-create-type ] [ lookup-type* ] if ;