libs/uci: optimize get & set performance in luci.model.uci.bind, fix ambiguous case...
[project/luci.git] / libs / uci / luasrc / model / uci / bind.lua
1 --[[
2 LuCI - UCI utilities for model classes
3
4 Copyright 2009 Jo-Philipp Wich <xm@subsignal.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17
18 ]]--
19
20 local assert, pairs, type = assert, pairs, type
21 local utl = require "luci.util"
22
23 module "luci.model.uci.bind"
24
25 bind = utl.class()
26
27 function bind.__init__(self, config, cursor)
28 assert(config, "call to bind() without config file")
29 self.cfg = config
30 self.uci = cursor
31 end
32
33 function bind.init(self, cursor)
34 assert(cursor, "call to init() without uci cursor")
35 self.uci = cursor
36 end
37
38 function bind.section(self, stype)
39 local x = utl.class(bsection)
40 x.__init__ = function(inst, sid)
41 assert(self.uci:get(self.cfg, sid) == stype,
42 "attempt to instantiate bsection(%q) of wrong type, expected %q"
43 % { sid, stype })
44
45 inst.bind = self
46 inst.stype = stype
47 inst.sid = sid
48 end
49 return x
50 end
51
52 function bind.usection(self, stype)
53 local x = utl.class(bsection)
54 x.__init__ = function(inst)
55 inst.bind = self
56 inst.stype = stype
57 inst.sid = true
58 end
59 return x()
60 end
61
62 function bind.list(self, list, add, rem)
63 local lookup = { }
64
65 if type(list) == "string" then
66 local item
67 for item in list:gmatch("%S+") do
68 lookup[item] = true
69 end
70
71 elseif type(list) == "table" then
72 local item
73 for _, item in pairs(list) do
74 lookup[item] = true
75 end
76 end
77
78 if add then lookup[add] = true end
79 if rem then lookup[rem] = nil end
80
81 return utl.keys(lookup)
82 end
83
84 function bind.bool(self, v)
85 return ( v == "1" or v == "true" or v == "yes" or v == "on" )
86 end
87
88
89 bsection = utl.class()
90
91 function bsection.uciop(self, op, ...)
92 assert(self.bind and self.bind.uci,
93 "attempt to use unitialized binding")
94
95 if op then
96 return self.bind.uci[op](self.bind.uci, self.bind.cfg, ...)
97 else
98 return self.bind.uci
99 end
100 end
101
102 function bsection.get(self, k, c)
103 local v
104 if type(c) == "string" then
105 v = self:uciop("get", c, k)
106 else
107 self:uciop("foreach", self.stype,
108 function(s)
109 if type(c) == "table" then
110 local ck, cv
111 for ck, cv in pairs(c) do
112 if s[ck] ~= cv then return true end
113 end
114 end
115 if k ~= nil then
116 v = s[k]
117 else
118 v = s
119 end
120 return false
121 end)
122 end
123 return v
124 end
125
126 function bsection.set(self, k, v, c)
127 local stat
128 if type(c) == "string" then
129 stat = self:uciop("set", c, k, v)
130 else
131 self:uciop("foreach", self.stype,
132 function(s)
133 if type(c) == "table" then
134 local ck, cv
135 for ck, cv in pairs(c) do
136 if s[ck] ~= cv then return true end
137 end
138 end
139 stat = self:uciop("set", c, k, v)
140 return false
141 end)
142 end
143 return stat or false
144 end
145
146 function bsection.property(self, k, n)
147 self[n or k] = function(c, val)
148 if val == nil then
149 return c:get(k, c.sid)
150 else
151 return c:set(k, val, c.sid)
152 end
153 end
154 end
155
156 function bsection.property_bool(self, k, n)
157 self[n or k] = function(c, val)
158 if val == nil then
159 return self.bind:bool(c:get(k, c.sid))
160 else
161 return c:set(k, self.bind:bool(val) and "1" or "0", c.sid)
162 end
163 end
164 end
165