-
Notifications
You must be signed in to change notification settings - Fork 23
/
hsdev.sql
360 lines (317 loc) · 11 KB
/
hsdev.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
-- system table for various options, for now only version
create table hsdev (
option text,
value json
);
-- packages per package-db
create table package_dbs (
package_db text not null, -- global, user or path
package_name text not null,
package_version text not null
);
create index package_names_index on package_dbs (package_db, package_name);
-- same as `package_dbs`, but only latest version of package left
create view latest_packages (
package_db,
package_name,
package_version
) as
select package_db, package_name, max(package_version)
from package_dbs
group by package_db, package_name;
-- sandboxes
create table sandboxes (
type text not null, -- cabal/stack
path text not null, -- sandbox path, should include `.cabal-sandbox`/`.stack-work`
package_db_stack json -- list of package-db of sandbox
);
create unique index sandboxes_path_index on sandboxes (path);
-- source projects
create table projects (
id integer primary key autoincrement,
name text not null,
cabal text not null, -- path to `.cabal` file
version text,
build_tool text not null, -- cabal/stack
package_db_stack json -- list of package-db
);
create unique index projects_id_index on projects (id);
create unique index projects_cabal_index on projects (cabal);
-- project's library targets
create table libraries (
project_id integer not null,
modules json not null, -- list of modules
build_info_id integer not null
);
create unique index libraries_ids_index on libraries (project_id, build_info_id);
-- project's executables targets
create table executables (
project_id integer not null,
name text not null,
path text not null,
build_info_id integer not null
);
create unique index executables_ids_index on executables (project_id, build_info_id);
-- project's tests targets
create table tests (
project_id integer not null,
name text not null,
enabled integer not null,
main text,
build_info_id integer not null
);
create unique index tests_ids_index on tests (project_id, build_info_id);
-- map from project to build-info for all targets
create view targets (
project_id,
build_info_id
) as
select project_id, build_info_id from libraries
union
select project_id, build_info_id from executables
union
select project_id, build_info_id from tests;
-- target build-info
create table build_infos(
id integer primary key autoincrement,
depends json not null, -- list of dependencies
language text,
extensions json not null, -- list of extensions
ghc_options json not null, -- list of ghc-options
source_dirs json not null, -- list of source directories
other_modules json not null -- list of other modules
);
create unique index build_infos_id_index on build_infos (id);
-- project dependent packages
create view projects_deps (
cabal,
package_db,
package_name,
package_version
) as
select distinct p.cabal, ps.package_db, ps.package_name, ps.package_version
from projects as p, json_each(p.package_db_stack) as pdb_stack, build_infos as b, json_each(b.depends) as deps, targets as t, latest_packages as ps
where
(p.id == t.project_id) and
(b.id == t.build_info_id) and
(deps.value <> p.name) and
(ps.package_name == deps.value) and
(ps.package_db == pdb_stack.value);
-- packages in scope of project
-- `cabal` may be null for standalone files, in this case all 'user-db' is in scope
create view projects_modules_scope (
cabal,
module_id
) as
select pdbs.cabal, m.id
from projects_deps as pdbs, modules as m
where
(m.package_name == pdbs.package_name) and
(m.package_version == pdbs.package_version) and
m.exposed
union
select p.cabal, m.id
from projects as p, modules as m
where (m.cabal == p.cabal)
union
select null, m.id
from modules as m, latest_packages as ps
where
(m.package_name == ps.package_name) and
(m.package_version == ps.package_version) and
m.exposed and
(ps.package_db in ('user-db', 'global-db'));
-- symbols
create table symbols (
id integer primary key autoincrement,
name text not null,
module_id integer not null, -- definition module
docs text,
line integer, -- line of definition
column integer, -- column of definition
what text not null, -- kind of symbol: function, method, ...
type text, -- type of function/method/...
parent text, -- parent of selector/method/...
constructors json, -- list of constructors for selector
args json, -- list of arguments for types
context json, -- list of contexts for types
associate text, -- associates for families
pat_type text,
pat_constructor text
);
create unique index symbols_id_index on symbols (id);
create unique index symbols_index on symbols (module_id, name, what);
-- modules
create table modules (
id integer primary key autoincrement,
-- source module location
file text, -- source file
cabal text, -- related project's `.cabal`
-- installed module location
install_dirs json, -- list of paths
package_name text, -- package name of module
package_version text, -- package version
installed_name text, -- if not null, should be equal to name
exposed integer, -- is module exposed or hidden
-- some other location
other_location text, -- anything
name text,
docs text,
fixities json, -- list of fixities
tags json, -- dict of tags, value not used, tag is set if present; used by hsdev to mark if types was inferred or docs scanned
inspection_error text,
inspection_time real,
inspection_opts json -- list of flags
);
create unique index modules_id_index on modules (id);
create index modules_name_index on modules (name);
create unique index modules_file_index on modules (file) where file is not null;
create unique index modules_installed_index on modules (package_name, package_version, installed_name) where
package_name is not null and
package_version is not null and
installed_name is not null;
create unique index modules_other_locations_index on modules (other_location) where other_location is not null;
-- module import statements
create table imports (
module_id integer not null,
line integer not null, -- line number of import
column integer not null, -- column of impoty
module_name text not null, -- import module name
qualified integer not null, -- is import qualified
alias text, -- imported with `as`
hiding integer, -- is list hiding
import_list json, -- list of import specs, null if not specified
import_module_id -- `id` of imported module
);
create unique index imports_position_index on imports (module_id, line, column);
-- symbols bringed into scope by import, with qualifier
create view imported_scopes as
select i.*, q.value as qualifier, s.name as name, s.id as symbol_id
from imports as i, json_each(case when i.qualified then json_array(ifnull(i.alias, i.module_name)) else json_array(ifnull(i.alias, i.module_name), null) end) as q, symbols as s, exports as e
where
e.module_id == i.import_module_id and
e.symbol_id == s.id and
(i.import_list is null or (s.name in (select json_extract(import_list_item.value, '$.name') from json_each(i.import_list) as import_list_item) == not i.hiding));
-- module exports
create table exports (
module_id integer not null,
symbol_id integer not null
);
create index exports_module_id_index on exports (module_id);
-- source file module's symbols in scope
create table scopes (
module_id integer not null,
qualifier text,
name text not null,
symbol_id integer not null
);
create index scopes_name_index on scopes (module_id, name);
-- like `scopes`, but with column `completion` with fully qualified name
create view completions (
module_id,
completion,
qualifier,
symbol_id
) as
select id, (case when sc.qualifier is null then sc.name else sc.qualifier || '.' || sc.name end) as full_name, sc.qualifier, sc.symbol_id
from modules as m, scopes as sc
where (m.id == sc.module_id);
-- resolved names in module
create table names (
module_id integer not null,
qualifier text, -- name qualifier
name text not null, -- name
line integer not null, -- line of name
column integer not null, -- column of name
line_to integer not null, -- line of name end
column_to integer not null, -- column of name end
def_line integer, -- name definition line, for local names
def_column integer, -- name definition column, for local names
inferred_type text, -- inferred name type, set by hsdev
resolved_module text, -- resolved module name, for global and top-level names
resolved_name text, -- resolved name, for global and top-level names
resolved_what text, -- resolved symbol kind
resolve_error text,
symbol_id integer -- resolved symbol id
);
create unique index names_position_index on names (module_id, line, column, line_to, column_to);
create index names_name_index on names (module_id, name);
-- like `names`, but with definition position set for both local and global names
create view definitions (
module_id,
name,
line,
column,
line_to,
column_to,
def_module_id,
def_line,
def_column,
local
) as
select module_id, name, line, column, line_to, column_to, module_id, def_line, def_column, 1
from names
where def_line is not null and def_column is not null
union
select n.module_id, n.resolved_name, n.line, n.column, n.line_to, n.column_to, s.module_id, s.line, s.column, 0
from names as n, modules as srcm, modules as m, symbols as s
where
(n.module_id == srcm.id) and
(n.symbol_id == s.id) and
(m.name == n.resolved_module) and
(s.module_id == m.id) and
(s.name == n.resolved_name);
-- sources dependencies relations
create view sources_depends (
module_id,
module_file,
depends_id,
depends_file
) as
select m.id, m.file, im.id, im.file
from modules as im, imports as i, modules as m, projects_modules_scope as ps
where
(m.cabal is ps.cabal) and
(ps.module_id == im.id) and
(i.module_id == m.id) and
(im.name == i.module_name) and
(m.file is not null) and
(im.file is not null);
-- expressions types
create table types (
module_id integer not null,
line integer not null, -- line of expression
column integer not null, -- column of expression
line_to integer not null, -- line of expression end
column_to integer not null, -- column of expression end
expr text not null, -- expression contents
type text not null -- expression type
);
create unique index types_position_index on types (module_id, line, column, line_to, column_to);
-- modified file contents, hsdev will use it in commands whenever it is newer than file
create table file_contents (
file text not null, -- file path
contents text not null, -- file contents
mtime real not null -- posix modification time
);
create unique index file_contents_index on file_contents (file);
-- table with last time of loading module
create table load_times (
module_id integer not null, -- module affected
load_time real not null -- timestamp
);
create unique index load_times_module_id_index on load_times (module_id);
-- table with ghc warnings on file
-- sequential call to load module won't actually reload file and won't produce warnings
-- but we want to see them again
create table messages (
module_id integer not null,
line integer not null,
column integer not null,
line_to integer not null,
column_to integer not null,
severity text,
message text not null,
suggestion text
);
create index messages_module_id_index on messages (module_id);