]> gitweb.factorcode.org Git - factor.git/blob - basis/db/types/types.factor
222ac2a9f5f52d4a972acaef00fb55c218c0f6eb
[factor.git] / basis / db / types / types.factor
1 ! Copyright (C) 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays assocs db kernel math math.parser
4 sequences continuations sequences.deep prettyprint
5 words namespaces slots slots.private classes mirrors
6 classes.tuple combinators calendar.format classes.singleton
7 accessors quotations random db.private ;
8 IN: db.types
9
10 HOOK: persistent-table db-connection ( -- hash )
11 HOOK: compound db-connection ( string obj -- hash )
12
13 TUPLE: sql-spec class slot-name column-name type primary-key modifiers ;
14
15 TUPLE: literal-bind key type value ;
16 C: <literal-bind> literal-bind
17
18 TUPLE: generator-bind slot-name key generator-singleton type ;
19 C: <generator-bind> generator-bind
20 SINGLETON: random-id-generator
21
22 TUPLE: low-level-binding value ;
23 C: <low-level-binding> low-level-binding
24
25 SINGLETONS: +db-assigned-id+ +user-assigned-id+ +random-id+ ;
26 UNION: +primary-key+ +db-assigned-id+ +user-assigned-id+ +random-id+ ;
27
28 SYMBOLS: +autoincrement+ +serial+ +unique+ +default+ +null+ +not-null+
29 +foreign-id+ +has-many+ +on-update+ +on-delete+ +restrict+ +cascade+
30 +set-null+ +set-default+ ;
31
32 SYMBOL: IGNORE
33
34 : filter-ignores ( tuple specs -- specs' )
35     [ <mirror> [ nip IGNORE = ] assoc-filter keys ] dip
36     [ slot-name>> swap member? not ] with filter ;
37
38 ERROR: not-persistent class ;
39
40 : db-table-name ( class -- object )
41     dup "db-table" word-prop [ ] [ not-persistent ] ?if ;
42
43 : db-columns ( class -- object )
44     superclasses [ "db-columns" word-prop ] map concat ;
45
46 : db-relations ( class -- object )
47     "db-relations" word-prop ;
48
49 : find-primary-key ( specs -- seq )
50     [ primary-key>> ] filter ;
51
52 : set-primary-key ( value tuple -- )
53     [
54         class-of db-columns
55         find-primary-key first slot-name>>
56     ] keep set-slot-named ;
57
58 : primary-key? ( spec -- ? )
59     primary-key>> +primary-key+? ;
60
61 : db-assigned-id-spec? ( specs -- ? )
62     [ primary-key>> +db-assigned-id+? ] any? ;
63
64 : user-assigned-id-spec? ( specs -- ? )
65     [ primary-key>> +user-assigned-id+? ] any? ;
66
67 : normalize-spec ( spec -- )
68     dup type>> dup +primary-key+? [
69         >>primary-key drop
70     ] [
71         drop dup modifiers>> [
72             +primary-key+?
73         ] deep-find
74         [ >>primary-key drop ] [ drop ] if*
75     ] if ;
76
77 : db-assigned? ( class -- ? )
78     db-columns find-primary-key db-assigned-id-spec? ;
79
80 : relation? ( spec -- ? ) [ +has-many+ = ] deep-find ;
81
82 SINGLETONS: INTEGER BIG-INTEGER SIGNED-BIG-INTEGER UNSIGNED-BIG-INTEGER
83 DOUBLE REAL BOOLEAN TEXT VARCHAR DATE TIME DATETIME TIMESTAMP BLOB
84 FACTOR-BLOB NULL URL ;
85
86 : <sql-spec> ( class slot-name column-name type modifiers -- sql-spec )
87     sql-spec new
88         swap >>modifiers
89         swap >>type
90         swap >>column-name
91         swap >>slot-name
92         swap >>class
93         dup normalize-spec ;
94
95 : spec>tuple ( class spec -- tuple )
96     3 f pad-tail [ first3 ] keep 3 tail <sql-spec> ;
97
98 : number>string* ( n/string -- string )
99     dup number? [ number>string ] when ;
100
101 : remove-db-assigned-id ( specs -- obj )
102     [ +db-assigned-id+? not ] filter ;
103
104 : remove-relations ( specs -- newcolumns )
105     [ relation? not ] filter ;
106
107 : remove-id ( specs -- obj )
108     [ primary-key>> not ] filter ;
109
110 ! SQLite Types: http://www.sqlite.org/datatype3.html
111 ! NULL INTEGER REAL TEXT BLOB
112 ! PostgreSQL Types:
113 ! http://developer.postgresql.org/pgdocs/postgres/datatype.html
114
115 ERROR: unknown-modifier modifier ;
116
117 : lookup-modifier ( obj -- string )
118     {
119         { [ dup array? ] [ unclip lookup-modifier swap compound ] }
120         [ persistent-table ?at [ unknown-modifier ] unless third ]
121     } cond ;
122
123 ERROR: no-sql-type type ;
124
125 : (lookup-type) ( obj -- string )
126     persistent-table ?at [ no-sql-type ] unless ;
127
128 : lookup-type ( obj -- string )
129     dup array? [
130         unclip (lookup-type) first nip
131     ] [
132         (lookup-type) first
133     ] if ;
134
135 : lookup-create-type ( obj -- string )
136     dup array? [
137         unclip (lookup-type) second swap compound
138     ] [
139         (lookup-type) second
140     ] if ;
141
142 : modifiers ( spec -- string )
143     modifiers>> [ lookup-modifier ] map " " join
144     [ "" ] [ " " prepend ] if-empty ;
145
146 HOOK: bind% db-connection ( spec -- )
147 HOOK: bind# db-connection ( spec obj -- )
148
149 ERROR: no-column column ;
150
151 : >reference-string ( string pair -- string )
152     first2
153     [ [ db-table-name " " glue ] [ db-columns ] bi ] dip
154     swap [ column-name>> = ] with find nip
155     [ no-column ] unless*
156     column-name>> "(" ")" surround append ;