add composite primary keys to db

db4
Doug Coleman 2008-09-27 14:07:39 -05:00
parent 876e3d0e04
commit 511ecaff59
6 changed files with 114 additions and 75 deletions

View File

@ -37,8 +37,7 @@ M: postgresql-db db-open ( db -- db )
M: postgresql-db dispose ( db -- ) M: postgresql-db dispose ( db -- )
handle>> PQfinish ; handle>> PQfinish ;
M: postgresql-statement bind-statement* ( statement -- ) M: postgresql-statement bind-statement* ( statement -- ) drop ;
drop ;
GENERIC: postgresql-bind-conversion ( tuple object -- low-level-binding ) GENERIC: postgresql-bind-conversion ( tuple object -- low-level-binding )
@ -67,11 +66,11 @@ M: postgresql-result-set #columns ( result-set -- n )
[ handle>> ] [ n>> ] bi ; [ handle>> ] [ n>> ] bi ;
M: postgresql-result-set row-column ( result-set column -- object ) M: postgresql-result-set row-column ( result-set column -- object )
>r result-handle-n r> pq-get-string ; [ result-handle-n ] dip pq-get-string ;
M: postgresql-result-set row-column-typed ( result-set column -- object ) M: postgresql-result-set row-column-typed ( result-set column -- object )
dup pick out-params>> nth type>> dup pick out-params>> nth type>>
>r >r result-handle-n r> r> postgresql-column-typed ; [ result-handle-n ] 2dip postgresql-column-typed ;
M: postgresql-statement query-results ( query -- result-set ) M: postgresql-statement query-results ( query -- result-set )
dup bind-params>> [ dup bind-params>> [
@ -126,13 +125,20 @@ M: postgresql-db bind# ( spec object -- )
: create-table-sql ( class -- statement ) : create-table-sql ( class -- statement )
[ [
dupd
"create table " 0% 0% "create table " 0% 0%
"(" 0% [ ", " 0% ] [ "(" 0% [ ", " 0% ] [
dup column-name>> 0% dup column-name>> 0%
" " 0% " " 0%
dup type>> lookup-create-type 0% dup type>> lookup-create-type 0%
modifiers 0% modifiers 0%
] interleave ");" 0% ] interleave
", " 0%
find-primary-key
"primary key(" 0%
[ "," 0% ] [ column-name>> 0% ] interleave
"));" 0%
] query-make ; ] query-make ;
: create-function-sql ( class -- statement ) : create-function-sql ( class -- statement )
@ -160,8 +166,7 @@ M: postgresql-db bind# ( spec object -- )
M: postgresql-db create-sql-statement ( class -- seq ) M: postgresql-db create-sql-statement ( class -- seq )
[ [
[ create-table-sql , ] keep [ create-table-sql , ] keep
dup db-columns find-primary-key db-assigned-id-spec? dup db-assigned? [ create-function-sql , ] [ drop ] if
[ create-function-sql , ] [ drop ] if
] { } make ; ] { } make ;
: drop-function-sql ( class -- statement ) : drop-function-sql ( class -- statement )
@ -181,15 +186,14 @@ M: postgresql-db create-sql-statement ( class -- seq )
M: postgresql-db drop-sql-statement ( class -- seq ) M: postgresql-db drop-sql-statement ( class -- seq )
[ [
[ drop-table-sql , ] keep [ drop-table-sql , ] keep
dup db-columns find-primary-key db-assigned-id-spec? dup db-assigned? [ drop-function-sql , ] [ drop ] if
[ drop-function-sql , ] [ drop ] if
] { } make ; ] { } make ;
M: postgresql-db <insert-db-assigned-statement> ( class -- statement ) M: postgresql-db <insert-db-assigned-statement> ( class -- statement )
[ [
"select add_" 0% 0% "select add_" 0% 0%
"(" 0% "(" 0%
dup find-primary-key 2, dup find-primary-key first 2,
remove-id remove-id
[ ", " 0% ] [ bind% ] interleave [ ", " 0% ] [ bind% ] interleave
");" 0% ");" 0%
@ -218,14 +222,14 @@ M: postgresql-db <insert-user-assigned-statement> ( class -- statement )
");" 0% ");" 0%
] query-make ; ] query-make ;
M: postgresql-db insert-tuple* ( tuple statement -- ) M: postgresql-db insert-tuple-set-key ( tuple statement -- )
query-modify-tuple ; query-modify-tuple ;
M: postgresql-db persistent-table ( -- hashtable ) M: postgresql-db persistent-table ( -- hashtable )
H{ H{
{ +db-assigned-id+ { "integer" "serial primary key" f } } { +db-assigned-id+ { "integer" "serial" f } }
{ +user-assigned-id+ { f f "primary key" } } { +user-assigned-id+ { f f f } }
{ +random-id+ { "bigint" "bigint primary key" f } } { +random-id+ { "bigint" "bigint" f } }
{ TEXT { "text" "text" f } } { TEXT { "text" "text" f } }
{ VARCHAR { "varchar" "varchar" f } } { VARCHAR { "varchar" "varchar" f } }
{ INTEGER { "integer" "integer" f } } { INTEGER { "integer" "integer" f } }

View File

@ -46,13 +46,18 @@ M: retryable execute-statement* ( statement type -- )
[ db-columns ] [ db-table ] bi ; [ db-columns ] [ db-table ] bi ;
: query-make ( class quot -- ) : query-make ( class quot -- )
>r sql-props r> [ sql-props ] dip
[ 0 sql-counter rot with-variable ] curry { "" { } { } } nmake [ 0 sql-counter rot with-variable ] curry
{ "" { } { } } nmake
<simple-statement> maybe-make-retryable ; inline <simple-statement> maybe-make-retryable ; inline
: where-primary-key% ( specs -- ) : where-primary-key% ( specs -- )
" where " 0% " where " 0%
find-primary-key dup column-name>> 0% " = " 0% bind% ; find-primary-key [
" and " 0%
] [
dup column-name>> 0% " = " 0% bind%
] interleave ;
M: db <update-tuple-statement> ( class -- statement ) M: db <update-tuple-statement> ( class -- statement )
[ [
@ -121,16 +126,15 @@ M: string where ( spec obj -- ) object-where ;
dup double-infinite-interval? [ drop f ] when dup double-infinite-interval? [ drop f ] when
] with filter ; ] with filter ;
: where-clause ( tuple specs -- ) : many-where ( tuple seq -- )
dupd filter-slots [ " where " 0% [
drop " and " 0%
] [ ] [
" where " 0% [ 2dup slot-name>> swap get-slot-named where
" and " 0% ] interleave drop ;
] [
2dup slot-name>> swap get-slot-named where : where-clause ( tuple specs -- )
] interleave drop dupd filter-slots [ drop ] [ many-where ] if-empty ;
] if-empty ;
M: db <delete-tuples-statement> ( tuple table -- sql ) M: db <delete-tuples-statement> ( tuple table -- sql )
[ [

View File

@ -88,7 +88,7 @@ M: sqlite-statement bind-tuple ( tuple statement -- )
db get handle>> sqlite3_last_insert_rowid db get handle>> sqlite3_last_insert_rowid
dup zero? [ "last-id failed" throw ] when ; dup zero? [ "last-id failed" throw ] when ;
M: sqlite-db insert-tuple* ( tuple statement -- ) M: sqlite-db insert-tuple-set-key ( tuple statement -- )
execute-statement last-insert-id swap set-primary-key ; execute-statement last-insert-id swap set-primary-key ;
M: sqlite-result-set #columns ( result-set -- n ) M: sqlite-result-set #columns ( result-set -- n )
@ -114,13 +114,20 @@ M: sqlite-statement query-results ( query -- result-set )
M: sqlite-db create-sql-statement ( class -- statement ) M: sqlite-db create-sql-statement ( class -- statement )
[ [
dupd
"create table " 0% 0% "create table " 0% 0%
"(" 0% [ ", " 0% ] [ "(" 0% [ ", " 0% ] [
dup column-name>> 0% dup column-name>> 0%
" " 0% " " 0%
dup type>> lookup-create-type 0% dup type>> lookup-create-type 0%
modifiers 0% modifiers 0%
] interleave ");" 0% ] interleave
", " 0%
find-primary-key
"primary key(" 0%
[ "," 0% ] [ column-name>> 0% ] interleave
"));" 0%
] query-make ; ] query-make ;
M: sqlite-db drop-sql-statement ( class -- statement ) M: sqlite-db drop-sql-statement ( class -- statement )
@ -161,10 +168,10 @@ M: sqlite-db bind% ( spec -- )
M: sqlite-db persistent-table ( -- assoc ) M: sqlite-db persistent-table ( -- assoc )
H{ H{
{ +db-assigned-id+ { "integer primary key" "integer primary key" "primary key" } } { +db-assigned-id+ { "integer" "integer" f } }
{ +user-assigned-id+ { f f "primary key" } } { +user-assigned-id+ { f f f } }
{ +random-id+ { "integer primary key" "integer primary key" "primary key" } } { +random-id+ { "integer" "integer" f } }
{ INTEGER { "integer" "integer" "primary key" } } { INTEGER { "integer" "integer" f } }
{ BIG-INTEGER { "bigint" "bigint" } } { BIG-INTEGER { "bigint" "bigint" } }
{ SIGNED-BIG-INTEGER { "bigint" "bigint" } } { SIGNED-BIG-INTEGER { "bigint" "bigint" } }
{ UNSIGNED-BIG-INTEGER { "bigint" "bigint" } } { UNSIGNED-BIG-INTEGER { "bigint" "bigint" } }

View File

@ -513,15 +513,35 @@ string-encoding-test "STRING_ENCODING_TEST" {
: test-queries ( -- ) : test-queries ( -- )
[ ] [ exam ensure-table ] unit-test [ ] [ exam ensure-table ] unit-test
! [ ] [ T{ exam f f "Kyle" 100 } insert-tuple ] unit-test [ ] [ 1000 [ random-exam insert-tuple ] times ] unit-test
! [ ] [ T{ exam f f "Stan" 80 } insert-tuple ] unit-test [ 5 ] [
! [ ] [ T{ exam f f "Kenny" 60 } insert-tuple ] unit-test <query>
! [ ] [ T{ exam f f "Cartman" 41 } insert-tuple ] unit-test T{ exam { score T{ interval { from { 0 t } } { to { 100 t } } } } }
[ ] [ 10 [ random-exam insert-tuple ] times ] unit-test >>tuple
[ 5 ] [ <query> T{ exam { score T{ interval { from { 0 t } } { to { 100 t } } } } } >>tuple 5 >>limit select-tuples length ] unit-test 5 >>limit select-tuples length
! [ ] [ T{ exam { name "Kenny" } } >query ] unit-test ] unit-test ;
! [ ] [ query ] unit-test
; TUPLE: compound-foo a b c ;
compound-foo "COMPOUND_FOO"
{
{ "a" "A" INTEGER +user-assigned-id+ }
{ "b" "B" INTEGER +user-assigned-id+ }
{ "c" "C" INTEGER }
} define-persistent
: test-compound-primary-key ( -- )
[ ] [ compound-foo ensure-table ] unit-test
[ ] [ compound-foo drop-table ] unit-test
[ ] [ compound-foo create-table ] unit-test
[ ] [ 1 2 3 compound-foo boa insert-tuple ] unit-test
[ 1 2 3 compound-foo boa insert-tuple ] must-fail
[ ] [ 2 3 4 compound-foo boa insert-tuple ] unit-test
[ T{ compound-foo { a 2 } { b 3 } { c 4 } } ]
[ compound-foo new 4 >>c select-tuple ] unit-test ;
[ test-compound-primary-key ] test-sqlite
[ test-compound-primary-key ] test-postgresql
: test-db ( -- ) : test-db ( -- )
"tuples-test.db" temp-file sqlite-db make-db db-open db set ; "tuples-test.db" temp-file sqlite-db make-db db-open db set ;

View File

@ -19,23 +19,7 @@ HOOK: <select-by-slots-statement> db ( tuple class -- tuple )
HOOK: <count-statement> db ( query -- statement ) HOOK: <count-statement> db ( query -- statement )
HOOK: query>statement db ( query -- statement ) HOOK: query>statement db ( query -- statement )
HOOK: insert-tuple* db ( tuple statement -- ) HOOK: insert-tuple-set-key db ( tuple statement -- )
ERROR: not-persistent class ;
: db-table ( class -- object )
dup "db-table" word-prop [ ] [ not-persistent ] ?if ;
: db-columns ( class -- object )
superclasses [ "db-columns" word-prop ] map concat ;
: db-relations ( class -- object )
"db-relations" word-prop ;
: set-primary-key ( key tuple -- )
[
class db-columns find-primary-key slot-name>>
] keep set-slot-named ;
SYMBOL: sql-counter SYMBOL: sql-counter
: next-sql-counter ( -- str ) : next-sql-counter ( -- str )
@ -69,7 +53,7 @@ GENERIC: eval-generator ( singleton -- object )
: insert-db-assigned-statement ( tuple -- ) : insert-db-assigned-statement ( tuple -- )
dup class dup class
db get insert-statements>> [ <insert-db-assigned-statement> ] cache db get insert-statements>> [ <insert-db-assigned-statement> ] cache
[ bind-tuple ] 2keep insert-tuple* ; [ bind-tuple ] 2keep insert-tuple-set-key ;
: insert-user-assigned-statement ( tuple -- ) : insert-user-assigned-statement ( tuple -- )
dup class dup class

View File

@ -30,14 +30,44 @@ UNION: +primary-key+ +db-assigned-id+ +user-assigned-id+ +random-id+ ;
SYMBOLS: +autoincrement+ +serial+ +unique+ +default+ +null+ +not-null+ SYMBOLS: +autoincrement+ +serial+ +unique+ +default+ +null+ +not-null+
+foreign-id+ +has-many+ ; +foreign-id+ +has-many+ ;
: offset-of-slot ( string tuple -- n )
class superclasses [ "slots" word-prop ] map concat
slot-named offset>> ;
: get-slot-named ( name tuple -- value )
tuck offset-of-slot slot ;
: set-slot-named ( value name obj -- )
tuck offset-of-slot set-slot ;
ERROR: not-persistent class ;
: db-table ( class -- object )
dup "db-table" word-prop [ ] [ not-persistent ] ?if ;
: db-columns ( class -- object )
superclasses [ "db-columns" word-prop ] map concat ;
: db-relations ( class -- object )
"db-relations" word-prop ;
: find-primary-key ( specs -- seq )
[ primary-key>> ] filter ;
: set-primary-key ( value tuple -- )
[
class db-columns
find-primary-key first slot-name>>
] keep set-slot-named ;
: primary-key? ( spec -- ? ) : primary-key? ( spec -- ? )
primary-key>> +primary-key+? ; primary-key>> +primary-key+? ;
: db-assigned-id-spec? ( spec -- ? ) : db-assigned-id-spec? ( specs -- ? )
primary-key>> +db-assigned-id+? ; [ primary-key>> +db-assigned-id+? ] contains? ;
: assigned-id-spec? ( spec -- ? ) : assigned-id-spec? ( specs -- ? )
primary-key>> +user-assigned-id+? ; [ primary-key>> +user-assigned-id+? ] contains? ;
: normalize-spec ( spec -- ) : normalize-spec ( spec -- )
dup type>> dup +primary-key+? [ dup type>> dup +primary-key+? [
@ -49,8 +79,8 @@ SYMBOLS: +autoincrement+ +serial+ +unique+ +default+ +null+ +not-null+
[ >>primary-key drop ] [ drop ] if* [ >>primary-key drop ] [ drop ] if*
] if ; ] if ;
: find-primary-key ( specs -- obj ) : db-assigned? ( class -- ? )
[ primary-key>> ] find nip ; db-columns find-primary-key db-assigned-id-spec? ;
: relation? ( spec -- ? ) [ +has-many+ = ] deep-find ; : relation? ( spec -- ? ) [ +has-many+ = ] deep-find ;
@ -125,13 +155,3 @@ ERROR: no-sql-type ;
HOOK: bind% db ( spec -- ) HOOK: bind% db ( spec -- )
HOOK: bind# db ( spec obj -- ) HOOK: bind# db ( spec obj -- )
: offset-of-slot ( string tuple -- n )
class superclasses [ "slots" word-prop ] map concat
slot-named offset>> ;
: get-slot-named ( name tuple -- value )
tuck offset-of-slot slot ;
: set-slot-named ( value name obj -- )
tuck offset-of-slot set-slot ;