/
tracks.lua
194 lines (174 loc) · 4.47 KB
/
tracks.lua
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
-- MODEL ------------------------
-- objects:
-- - track
-- - stations, length - artist - title - path
-- - id - mood - played list, playcount
-- - playlist
-- - sequential list of tracks to play
-- - selector
-- - station - name - criteria - mood - happy
-- - program
-- - station - start - stop - selector - items
-- - recurring -> weekly, daily, blank
-- - stations
-- - name - selector
---------------------------------
-- Goals:
-- unique add(artist,track,{key=val})
-- search(track{key=val},sort) : paginate
-- filter to return only specific fields
-- count total results (or pages)
require "os"
local db = require "couch"
local u = require "lib/util"
module("tracks", package.seeall)
local database = "tracks"
function tracks:init()
return db:init(database)
end
-- local instance of the db connection saves us an init call
local trk = tracks:init()
function tracks:put(pkey,cols)
return db:put(trk, pkey, cols)
end
-- can have table of tags
-- returns: trackid,entry,error
function tracks:add(cols)
local cols = cols or {}
local pkey = db:genuid()
cols.added = os.time()
cols.station = cols.station or default_station
print("adding ".. u.dump(cols))
if cols.md5 then
id = tracks:ssearch({md5=md5})
if #id ~= 0 then
print("found id "..u.dump(id))
return id
end
end
return tracks:put(pkey, cols)
end
-- the simple search
function tracks:ssearch(query, qop, order)
local query = query or {station=default_station}
local qop = qop or db.op.equal
-- q:setlimit(limit, skip) -- we need the size so there is no use
local res = db:search(trk, query, qop, order)
return res, #res
end
-- search within the database
-- returns array [id]={result}
function tracks:search(query, qf, qop, order)
local order = order or {"added", db.sort.decreasing}
if type(order) ~= "table" then order = {order, db.sort.increasing} end
if not query or query == "" then query = {} end
local result, size
if type(query) == "table" then
result,size = tracks:ssearch(query, qop, order)
else
result,size = tracks:gsearch(query, qf, order)
end
return tracks.fill(result),size
end
function tracks.fields(result)
local fset = {}
for _,t in ipairs(result) do
for k,v in pairs(t) do
fset[k] = true
end
end
local rset = {}
for k,v in pairs(fset) do
table.insert(rset,k)
end
return rset
end
-- take an array of id's and return a set of result tracks
function tracks.fill(result)
local rset = {}
for i,v in ipairs(result) do
rawset(rset,tonumber(v),tracks:get(v))
end
return rset
end
-- search for query in all queryfields
-- honour queries like "foo bar tag:value"
-- todo: filter out results that don't match whole query
function tracks:gsearch(q, qf, order)
local queries = {}
q,qf = q or '', qf or ''
local tokens = u.split(q,', ')
local qf = u.split(qf)
local qry
-- collect terms
local accu = {}
local tags = {}
for i,v in pairs(tokens) do
t = u.split(v,':')
if #t > 1 then
tags[t[1]] = t[2]
else
table.insert(accu, v)
end
end
-- create one search per field
for j,f in pairs(qf) do
local q = tokyocabinet.tdbqrynew(trk)
for t,v in pairs(tags) do
a = u.split(v,',')
if #a > 1 then
q:addcond(t,db.op.one,v)
else
q:addcond(t,db.op.inclusive,v)
end
end
if #accu > 0 then
print("search " .. f .. " for " .. u.join(accu))
q:addcond(f,db.op.onetoken,u.join(accu))
end
table.insert(queries,q)
end
-- pull out last query and execute on it
qry = table.remove(queries)
qry:setorder(unpack(order))
local result = qry:metasearch(queries,qry.MSUNION)
return result, #result
end
function tracks:dump()
return u.dump(db:dump())
end
function tracks:get(pkey)
local track = trk:get(pkey)
track.id = pkey
return track
end
function tracks:update(pkey, cols)
return tracks:put(pkey, cols)
end
-- return result with only fields
-- you can specify limit and page number
function tracks.filter(result, fields, limit, skip)
local res = {}
local c = 0
for k,v in pairs(result) do
c = c + 1
if(c > skip+limit) then
break
end
if(c > skip) then
if not fields or #fields == 0 then
one = v -- no fields, so all fields
else
local one = {}
for i,f in pairs(fields) do
one[f] = v[f] -- just these fields
end
end
res[k] = one
end
end
return res
end
u.out("fapfapfap")
u.out(tracks:dump())
return tracks