-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathacset_interface.jl
More file actions
156 lines (136 loc) · 5.44 KB
/
Copy pathacset_interface.jl
File metadata and controls
156 lines (136 loc) · 5.44 KB
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
# ACSet Interface
get_table(column) = From(:Table=>:tname)|>
Where(:Table, From(:Column=>:table)|>Where(:cname, column))
function decide_source(fabric::DataFabric, attr::Pair{Symbol, Tuple{Symbol, Symbol}})
id = incident(fabric.catalog, attr.second[1], attr.first)
source_id = subpart(fabric.catalog, only(id), :source)
subpart(fabric.graph, source_id, :value)
end
# Pair is tablename, col name
function decide_source(fabric::DataFabric, attr::Pair{Symbol, Symbol})
id = incident(fabric.catalog, attr.second, attr.first)
if attr.first == :cname
id = subpart(fabric.catalog, id, :table)
end
@assert length(id) == 1
source_id = subpart(fabric.catalog, id, :source)
source = subpart(fabric.graph, source_id, :value)
only(source)
end
function ACSetInterface.add_part!(fabric::DataFabric, table::Symbol, args...)
source = decide_source(fabric, :tname => table)
add_part!(source, table, args...)
end
export add_part!
function ACSetInterface.nparts(fabric::DataFabric, table::Symbol)
source = decide_source(fabric, :tname => table)
nparts(source, table)
end
export nparts
function ACSetInterface.maxpart(fabric::DataFabric, table::Symbol)
source = decide_source(fabric, :tname => table)
maxpart(source, table)
end
export maxpart
function ACSetInterface.subpart(fabric::DataFabric, column::Symbol)
subpart(fabric, :, column)
end
export subpart
# TODO
# function ACSetInterface.subpart(fabric::DataFabric, column::PK{T<:ACSet})
# nparts(fabric.graph
# end
function ACSetInterface.subpart(fabric::DataFabric, fks::Vector{FK{T}}, column::Symbol; formatter=identity) where T
out = subpart(fabric, getproperty.(fks, :val), column)
formatter(out)
end
function ACSetInterface.subpart(fabric::DataFabric, id, column::Symbol; formatter=identity)
column = if isempty(incident(fabric.catalog, column, :tname))
column
else
Symbol("$(column)_id")
end
source = decide_source(fabric, :cname => column)
tableid = subpart(fabric.catalog, incident(fabric.catalog, column, :cname), :table)
table = subpart(fabric.catalog, tableid, :tname) |> only
# TODO move handling of FK types to another method
id = eltype(id) <: FK ? getproperty.(id, :val) : id
if !isempty(id)
out = subpart(source, id, table => column)
formatter(out)
else
[]
end
end
# Winemaker => name
function ACSetInterface.subpart(fabric::DataFabric, id, column::Pair{Symbol, Symbol}; formatter=identity)
# get columns
columns = subpart(fabric.catalog, incident(fabric.catalog, column.first, [:table, :tname]), :cname)
@assert !isempty(columns[columns .== column.second])
# TODO simplify
source = subpart(fabric.graph,
subpart(fabric.catalog,
# get the id of the table
incident(fabric.catalog, column.first, :tname),
:source),
:value)
out = subpart(only(source), id, column.second)
formatter(out)
end
function ACSetInterface.subpart(fabric::DataFabric, column::Pair{Symbol, Symbol}; formatter=identity)
out = subpart(fabric, :, column)
formatter(out)
end
function ACSetInterface.subpart(fabric::DataFabric, columns::Vector{Symbol}; formatter=identity)
out = subpart(fabric, :, columns)
formatter(out)
end
# TODO wrap in datA frame here
function ACSetInterface.subpart(fabric::DataFabric, id=(:), columns::Vector{Symbol}=[]; formatter=identity)
out = reduce((new_id, column) -> subpart(fabric, new_id, column), columns; init=id)
formatter(out)
end
function another(X::ACSet, val, col::Symbol, other::Symbol)
subpart(X, incident(X, val, col), other)
end
function ACSetInterface.incident(fabric::DataFabric, id, column::Symbol; formatter=identity)
if column ∈ [:id, :_id]
return formatter(id)
end
# TODO could be multiple
source = decide_source(fabric, :cname => column)
_, table = get_table(column)(fabric.catalog) |> only
# TODO I don't like calling other here.
# what if the column (`val`) had the same name as another, so `incident` in `another` returns |vector|>1?
fkmaybe = let T = only(another(fabric.catalog, column, :cname, :type))
T <: FK ? T : identity
end
# TODO we broadcast over ids, which excludes vector-valued data
out = incident(source, fkmaybe.(id), only(table) => column)
formatter(out)
end
export incident
# incident(fabric, (3, :b), ([3,4], :c))
function ACSetInterface.incident(fabric::DataFabric, kvs::Vector{Tuple{<:T, Symbol}}; formatter=identity) where T
ids = map([incident(fabric, val, col; formatter=identity) for (val,col) in kvs]) do result
result isa DataFrame ? result._id : result
end
isempty(ids) && return []
out = intersect(ids...)
# TODO if a result is a DataFrame, then we have have an issue
formatter(out)
end
# TODO returns ids of matching rows
# TODO does not work with DataStore
function ACSetInterface.incident(fabric::DataFabric, id, columns::Vector{Symbol}; formatter=identity)
@info columns
out = reduce((new_id, column) -> incident(fabric, new_id, column), columns; init=id)
formatter(out)
end
# calls ultimately go into this
function ACSetInterface.incident(fabric::DataFabric, value, tablecol::Tuple{Symbol, Symbol}; formatter=identity)
source = decide_source(fabric, :tname => tablecol)
@warn tablecol
out = incident(source, value, tablecol[2])
formatter(out)
end