: param-values ( statement -- seq seq2 )
[ bind-params>> ] [ in-params>> ] bi
[
- type>> {
+ >r value>> r> type>> {
{ FACTOR-BLOB [
dup [ object>bytes malloc-byte-array/length ] [ 0 ] if
] }
dup array? [ first ] when
{
{ +native-id+ [ pq-get-number ] }
+ { +random-id+ [ pq-get-number ] }
{ INTEGER [ pq-get-number ] }
{ BIG-INTEGER [ pq-get-number ] }
{ DOUBLE [ pq-get-number ] }
M: postgresql-statement bind-statement* ( statement -- )
drop ;
-GENERIC: postgresql-bind-conversion
+GENERIC: postgresql-bind-conversion ( tuple obj -- low-level-binding )
-M: sql-spec postgresql-bind-conversion ( tuple spec -- array )
- slot-name>> swap get-slot-named ;
+M: sql-spec postgresql-bind-conversion ( tuple spec -- obj )
+ slot-name>> swap get-slot-named <low-level-binding> ;
-M: literal-bind postgresql-bind-conversion ( tuple literal-bind -- array )
- nip value>> ;
+M: literal-bind postgresql-bind-conversion ( tuple literal-bind -- obj )
+ nip value>> <low-level-binding> ;
-M: generator-bind postgresql-bind-conversion ( tuple generate-bind -- array )
- nip quot>> call ;
+M: generator-bind postgresql-bind-conversion ( tuple generate-bind -- obj )
+ nip singleton>> eval-generator <low-level-binding> ;
M: postgresql-statement bind-tuple ( tuple statement -- )
tuck in-params>>
")" 0%
" values(" 0%
- [ ", " 0% ] [ bind% ] interleave
+ [ ", " 0% ] [
+ dup type>> +random-id+ = [
+ [
+ drop bind-name%
+ f random-id-generator
+ ] [ type>> ] bi <generator-bind> 1,
+ ] [
+ bind%
+ ] if
+ ] interleave
");" 0%
] query-make ;
math.intervals ;
IN: db.queries
+GENERIC: eval-generator ( singleton -- obj )
+GENERIC: where ( specs obj -- )
+
: maybe-make-retryable ( statement -- statement )
dup in-params>> [ generator-bind? ] contains? [
make-retryable
dup column-name>> 0% " = " 0% bind%
] query-make ;
-M: db random-id-quot ( -- quot )
- [ 63 [ 2^ random ] keep 1 - set-bit ] ;
-
-GENERIC: where ( specs obj -- )
+M: random-id-generator eval-generator ( singleton -- obj )
+ drop
+ system-random-generator get [
+ 63 [ 2^ random ] keep 1 - set-bit
+ ] with-random ;
: interval-comparison ( ? str -- str )
"from" = " >" " <" ? swap [ "= " append ] when ;
M: sqlite-statement low-level-bind ( statement -- )
[ statement-bind-params ] [ statement-handle ] bi
- swap [ first3 sqlite-bind-type ] with each ;
+ swap [ [ key>> ] [ value>> ] [ type>> ] tri sqlite-bind-type ] with each ;
M: sqlite-statement bind-statement* ( statement -- )
sqlite-maybe-prepare
GENERIC: sqlite-bind-conversion ( tuple obj -- array )
+TUPLE: sqlite-low-level-binding < low-level-binding key type ;
+: <sqlite-low-level-binding> ( key value type -- obj )
+ sqlite-low-level-binding new
+ swap >>type
+ swap >>value
+ swap >>key ;
+
M: sql-spec sqlite-bind-conversion ( tuple spec -- array )
[ column-name>> ":" prepend ]
[ slot-name>> rot get-slot-named ]
- [ type>> ] tri 3array ;
+ [ type>> ] tri <sqlite-low-level-binding> ;
M: literal-bind sqlite-bind-conversion ( tuple literal-bind -- array )
- nip [ key>> ] [ value>> ] [ type>> ] tri 3array ;
+ nip [ key>> ] [ value>> ] [ type>> ] tri
+ <sqlite-low-level-binding> ;
M: generator-bind sqlite-bind-conversion ( tuple generate-bind -- array )
- nip [ key>> ] [ quot>> call ] [ type>> ] tri 3array ;
+ nip [ key>> ] [ singleton>> eval-generator ] [ type>> ] tri
+ <sqlite-low-level-binding> ;
M: sqlite-statement bind-tuple ( tuple statement -- )
[
") values(" 0%
[ ", " 0% ] [
dup type>> +random-id+ = [
- dup modifiers>> find-random-generator
[
- [
- column-name>> ":" prepend
- dup 0% random-id-quot
- ] with-random
- ] curry
- [ type>> ] bi <generator-bind> 1,
+ column-name>> ":" prepend dup 0%
+ random-id-generator
+ ] [ type>> ] bi <generator-bind> 1,
] [
bind%
] if
[ test-bignum ] test-postgresql
[ test-serialize ] test-postgresql
[ test-intervals ] test-postgresql
-! [ test-random-id ] test-postgresql
+[ test-random-id ] test-postgresql
TUPLE: does-not-persist ;
-! [
- ! [ does-not-persist create-sql-statement ]
- ! [ class \ not-persistent = ] must-fail-with
-! ] test-sqlite
+[
+ [ does-not-persist create-sql-statement ]
+ [ class \ not-persistent = ] must-fail-with
+] test-sqlite
[
[ does-not-persist create-sql-statement ]
USING: arrays assocs classes db kernel namespaces
classes.tuple words sequences slots math accessors
math.parser io prettyprint db.types continuations
-mirrors sequences.lib tools.walker combinators.lib ;
+mirrors sequences.lib tools.walker combinators.lib db.queries ;
IN: db.tuples
: define-persistent ( class table columns -- )
: set-primary-key ( key tuple -- )
[
- class db-columns find-primary-key sql-spec-slot-name
+ class db-columns find-primary-key slot-name>>
] keep set-slot-named ;
SYMBOL: sql-counter
-: next-sql-counter sql-counter [ inc ] [ get ] bi number>string ;
+: next-sql-counter ( -- str )
+ sql-counter [ inc ] [ get ] bi number>string ;
! returns a sequence of prepared-statements
HOOK: create-sql-statement db ( class -- obj )
[ bind-params>> ] [ in-params>> ] bi
[
dup generator-bind? [
- quot>> call over set-second
+ singleton>> eval-generator >>value
] [
drop
] if
] 2map >>bind-params ;
-: handle-random-id ( statement -- )
- dup in-params>> [ type>> +random-id+ = ] find drop >boolean [
- retryable >>type
- random-id-quot >>quot
- ] when drop ;
-
M: retryable execute-statement* ( statement type -- )
drop
[
] curry 10 retry drop ;
: resulting-tuple ( row out-params -- tuple )
- dup first sql-spec-class new [
+ dup first class>> new [
[
- >r sql-spec-slot-name r> set-slot-named
+ >r slot-name>> r> set-slot-named
] curry 2each
] keep ;
: query-tuples ( statement -- seq )
- [ statement-out-params ] keep query-results [
+ [ out-params>> ] keep query-results [
[ sql-row-typed swap resulting-tuple ] with query-map
] with-disposal ;
: query-modify-tuple ( tuple statement -- )
[ query-results [ sql-row-typed ] with-disposal ] keep
- statement-out-params rot [
- >r sql-spec-slot-name r> set-slot-named
+ out-params>> rot [
+ >r slot-name>> r> set-slot-named
] curry 2each ;
: sql-props ( class -- columns table )
HOOK: persistent-table db ( -- hash )
HOOK: compound db ( str obj -- hash )
-HOOK: random-id-quot db ( -- quot )
-
TUPLE: sql-spec class slot-name column-name type primary-key modifiers ;
TUPLE: literal-bind key type value ;
C: <literal-bind> literal-bind
-TUPLE: generator-bind key quot type ;
+TUPLE: generator-bind key singleton type ;
C: <generator-bind> generator-bind
+SINGLETON: random-id-generator
+
+TUPLE: low-level-binding value ;
+C: <low-level-binding> low-level-binding
SINGLETON: +native-id+
SINGLETON: +assigned-id+