-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathschema.sql
148 lines (116 loc) · 5.52 KB
/
schema.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
-- pragma foreign_keys=on;
-- begin;
-- FYI: "At this time SQLite supports only FOR EACH ROW triggers"
--------------------------------------------------------------------------------
create table "soup"
( rowid integer primary key
, t integer not null
, v blob not null
, rc integer not null default 0
);
-- I guess t values are decided at compile time? So we can do this fairly reliably?
-- This seems to improve query time a bit but insert performance is much slower so idk.
create unique index "soup-tv-0" on "soup" (v) where t = 0;
create unique index "soup-tv-1" on "soup" (v) where t = 1;
create unique index "soup-tv-2" on "soup" (v) where t = 2;
create trigger "soup/no-updates" before update
on "soup" when new.t != old.t or new.v != old.v
begin select raise (abort, 'not yet implemented (also confusing)');
end;
create trigger "soup/forget-zero-rc" before update
on "soup" when new.rc = 0
begin delete from "soup" where rowid = new.rowid;
end;
--------------------------------------------------------------------------------
create table "triples"
( e integer not null references "entities" (rowid)
, a integer not null references "attributes" (rowid)
, v integer not null references "soup" (rowid)
, primary key (e, a, v)
) without rowid; -- <_<
-- Created programatically by the owoof library.
--- create index "triples-ave-N" on "triples" (v, e) where a = N;
-- TODO this kills the following query...
--- owoof '?calvin :book/title "The Complete Calvin and Hobbes"' \
--- '?rating :rating/book ?calvin' \
--- '?rating :rating/score 1' \
--- '?rating :rating/user ?u' \
--- '?more-great-takes :rating/user ?u' \
--- '?more-great-takes :rating/book ?b' \
--- '?more-great-takes :rating/score 5' \
--- --show '?b :book/title :book/avg-rating' \
--- --asc '?b :book/avg-rating' --db /tmp/owoof-three.sqlite
-- The following index is very slow to populate :(
--- create index "triples-v" on "triples" (v);
-- When creating a triple, increment the value's soup.rc.
create trigger "triples/soup-inc-rc" after insert
on "triples"
begin update "soup" set rc = rc + 1 where rowid = new.v;
end;
-- When removing a triple, decrement the value's soup.rc.
create trigger "triples/soup-dec-rc" after delete
on "triples"
begin update "soup" set rc = rc - 1 where rowid = old.v;
end;
--------------------------------------------------------------------------------
-- "entities" is a materialized view maintained by triggers.
create table "entities"
( rowid integer primary key references "soup" (rowid) );
create trigger "soup/replicate-entities" after insert
on "soup" when new.t = 1
begin insert into "entities" (rowid) values (new.rowid);
end;
create trigger "soup/unreplicate-entities" after delete
on "soup" when old.t = 1
begin delete from "entities" where rowid = old.rowid;
end;
-- When an entity id is encoded, a row in soup with t = 1 is inserted. This row must
-- have a corresponding row in "triples" (soup.rowid :db/id soup.rowid) for its entire
-- lifetime and a row in "entities" so that the triple is valid.
create trigger "soup/assert-dbid-triples" after insert
on "soup" when new.t = 1 -- src/driver.rs ENTITY_ID_TAG
-- a = 1, the soup rowid for :db/id
begin insert into "triples" (e, a, v) values (new.rowid, 1, new.rowid);
end;
-- If the triple is deleted, the "entities" and "soup" rows must also be deleted,
-- meaning they can't be referenced anywhere else. So you can't delete (a :db/id a)
-- while (b :buddy/friend a) exists or while (a :pet/name "Spot") exists.
create trigger "triples/retract-dbid-soup" after delete
on "triples" when old.a = 1 -- the soup rowid for :db/id
and old.e = old.v
begin delete from "soup" where rowid = old.e;
end;
--------------------------------------------------------------------------------
-- "attributes" is a materialized view maintained by triggers.
create table "attributes"
-- rowid points to the attribute's uuid value in "soup" ... not the identifier
( rowid integer primary key references "entities" (rowid)
, ident integer not null references "soup" (rowid) );
create unique index "attribute-ident-unique" on "attributes" (ident);
create trigger "triples/no-updates" before update
on "triples"
begin select raise (abort, 'not yet implemented (also confusing)');
end;
-- tiggers to maintain the attributes materialized view
create trigger "triples/replicate-attributes" after insert
on "triples" when new.a = 3 -- :db/attributes's :db/id
begin insert into "attributes" (rowid, ident) values (new.e, new.v);
end;
create trigger "triples/unreplicate-attributes" after delete
on "triples" when old.a = 3 -- :db/attributes's :db/id
begin delete from "attributes" where rowid = old.e;
end;
-- Initial data; the entity and attribute identifier for :db/id and :db/attribute.
-- TODO is randomblob(16) a valid v4 uuid?
insert into "soup" (rowid, t, v)
values (1, 1, randomblob(16)) -- :db/id's :db/id
, (2, 2, "db/id")
, (3, 1, randomblob(16)) -- :db/attribute's :db/id
, (4, 2, "db/attribute");
-- Also, two other triples should already exist (v :db/id v)
-- for both :db/id and :db/attribute entities.
insert into "triples" (e, a, v)
values (1, 3, 2) -- :db/id :db/attribute :db/id
, (3, 3, 4) -- :db/attribute :db/attribute :db/attribute
;
-- commit;