This repository was archived by the owner on Nov 30, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy patharrays.jl
More file actions
248 lines (181 loc) · 6.19 KB
/
arrays.jl
File metadata and controls
248 lines (181 loc) · 6.19 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
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
module ArrayInterfaces
import Base: connect, close, getindex, start, next, done, length, isopen, isempty
importall ..DBAPIBase
import Compat.view
### Underlying column data structures
abstract type AbstractColumn{T} end
immutable Column{T} <: AbstractColumn{T}
name::Symbol
data::Vector{T}
end
immutable SubColumn{T} <: AbstractColumn{T}
name::Symbol
data::SubArray{T}
end
SubColumn(column::Column, indices...) = SubColumn(column.name, view(column.data, indices...))
start(column::AbstractColumn) = start(column.data)
next{T}(column::AbstractColumn{T}, state) = next(column.data, state)::Tuple{T, Any}
done(column::AbstractColumn, state) = done(column.data, state)
getindex(column::AbstractColumn, indexes...) = getindex(column.data, indexes...)
length(column::AbstractColumn) = length(column.data)
function allequal{T}(things::AbstractArray{T})
thing_set = Set{T}()
for thing in things
push!(thing_set, thing)
if length(thing_set) > 1
return false
end
end
return true
end
### Interface
type ColumnarArrayInterface <: DatabaseInterface end
### Connections
type ColumnarArrayConnection <: DatabaseConnection{ColumnarArrayInterface}
columns::Vector{Column}
closed::Bool
end
function connect(
::Type{ColumnarArrayInterface},
names::AbstractArray{Symbol},
columns::AbstractArray{Vector}
)
if length(names) != length(columns)
throw(ArrayInterfaceError("Arrays of names and columns must be the same length"))
end
if !allequal(map(length, columns))
throw(ArrayInterfaceError("Columns must be the same length"))
end
ColumnarArrayConnection(
map(names, columns) do name, column
Column(name, column)
end,
false,
)
end
function close(connection::ColumnarArrayConnection)
connection.closed = true
empty!(connection.columns)
return nothing
end
# does not support transactions
commit(connection::ColumnarArrayConnection) = nothing
isopen(connection::ColumnarArrayConnection) = !connection.closed
### Cursors
type ColumnarArrayCursor <: FixedLengthDatabaseCursor{ColumnarArrayInterface}
connection::ColumnarArrayConnection
columns::Vector{SubColumn}
ColumnarArrayCursor(connection) = new(connection)
end
cursor(connection::ColumnarArrayConnection) = ColumnarArrayCursor(connection)
connection(cursor::ColumnarArrayCursor) = cursor.connection
isempty(cursor::ColumnarArrayCursor) = isempty(cursor.columns)
length(cursor::ColumnarArrayCursor) = isempty(cursor) ? 0 : length(first(cursor.columns))
### Queries
immutable ColumnarArrayQuery{T<:OrdinalRange} <: DatabaseQuery
columns::Vector{Symbol}
rows::T
end
function execute!(cursor::ColumnarArrayCursor, query::ColumnarArrayQuery)
try
# handle case where there are rows requested from no columns
if isempty(query.columns) && !isempty(query.rows)
throw(BoundsError())
end
remaining_columns = Set(query.columns)
cursor.columns = map(filter(cursor.connection.columns) do col
is_queried = col.name in query.columns
if is_queried
pop!(remaining_columns, col.name)
end
is_queried
end) do col
SubColumn(col, query.rows)
end
# don't allow queries for nonexistent columns
if !isempty(remaining_columns)
throw(BoundsError())
end
catch error
if isa(error, BoundsError) || isa(error, KeyError)
rethrow(DatabaseQueryError(interface(cursor), query))
else
rethrow(error)
end
end
return nothing
end
### Results
immutable ColumnarArrayRowIterator
cursor::ColumnarArrayCursor
end
function rows(cursor::ColumnarArrayCursor)
if !isdefined(cursor, :columns)
throw(ArrayInterfaceError("No query has been run on $cursor"))
end
return ColumnarArrayRowIterator(cursor)
end
function start(iter::ColumnarArrayRowIterator)
if isempty(iter.cursor.columns)
# needed because the method zip() does not exist
zip_iterator = zip(())
else
zip_iterator = zip(iter.cursor.columns...)
end
return (zip_iterator, start(zip_iterator))
end
function next(iter::ColumnarArrayRowIterator, state)
(zip_iterator, current_state) = state
(next_set, next_state) = next(zip_iterator, current_state)
return (next_set, (zip_iterator, next_state))
end
function done(iter::ColumnarArrayRowIterator, state)
return done(state...)
end
immutable ColumnarArrayColumnIterator
cursor::ColumnarArrayCursor
end
function columns(cursor::ColumnarArrayCursor)
if !isdefined(cursor, :columns)
throw(ArrayInterfaceError("No query has been run on $cursor"))
end
return ColumnarArrayColumnIterator(cursor)
end
start(iter::ColumnarArrayColumnIterator) = start(iter.cursor.columns)
function next(iter::ColumnarArrayColumnIterator, state)
(next_col, next_state) = next(iter.cursor.columns, state)
return (collect(next_col), next_state)
end
done(iter::ColumnarArrayColumnIterator, state) = done(iter.cursor.columns, state)
function getindex(cursor::ColumnarArrayCursor, row_ind::Int, column_name::Symbol)
if_failed = BoundsError(cursor, (row_ind, column_name))
for column in cursor.columns
if column.name == column_name
try
return column[row_ind]
catch error
rethrow(if_failed)
end
end
end
throw(if_failed)
end
function getindex(cursor::ColumnarArrayCursor, row_ind::Int, column_ind::Int)
if_failed = BoundsError(cursor, (row_ind, column_ind))
try
return cursor.columns[column_ind][row_ind]
catch error
rethrow(if_failed)
end
end
### Errors
immutable ArrayInterfaceError{T<:AbstractString} <: DatabaseError{ColumnarArrayInterface}
message::T
end
if VERSION >= v"0.5-"
Base.iteratorsize(::ColumnarArrayRowIterator) = Base.SizeUnknown()
Base.iteratoreltype(::ColumnarArrayRowIterator) = Base.EltypeUnknown()
Base.iteratorsize(::ColumnarArrayColumnIterator) = Base.SizeUnknown()
Base.iteratoreltype(::ColumnarArrayColumnIterator) = Base.EltypeUnknown()
end
end # module