1 | /* |
2 | * Copyright 2008-2018 Aerospike, Inc. |
3 | * |
4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor |
5 | * license agreements. |
6 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
8 | * use this file except in compliance with the License. You may obtain a copy of |
9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 |
10 | * |
11 | * Unless required by applicable law or agreed to in writing, software |
12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
14 | * License for the specific language governing permissions and limitations under |
15 | * the License. |
16 | */ |
17 | |
18 | #include <aerospike/as_rec.h> |
19 | #include <aerospike/as_val.h> |
20 | |
21 | #include <aerospike/mod_lua_record.h> |
22 | #include <aerospike/mod_lua_val.h> |
23 | #include <aerospike/mod_lua_bytes.h> |
24 | #include <aerospike/mod_lua_reg.h> |
25 | #include <aerospike/mod_lua_list.h> |
26 | |
27 | #include "internal.h" |
28 | |
29 | /******************************************************************************* |
30 | * MACROS |
31 | ******************************************************************************/ |
32 | |
33 | #define OBJECT_NAME "record" |
34 | #define CLASS_NAME "Record" |
35 | |
36 | /******************************************************************************* |
37 | * FUNCTIONS |
38 | ******************************************************************************/ |
39 | |
40 | /** |
41 | * Read the item at index and convert to a record |
42 | */ |
43 | as_rec * mod_lua_torecord(lua_State * l, int index) { |
44 | mod_lua_box * box = mod_lua_tobox(l, index, CLASS_NAME); |
45 | return (as_rec *) mod_lua_box_value(box); |
46 | } |
47 | |
48 | /** |
49 | * Push a record on to the lua stack |
50 | */ |
51 | as_rec * mod_lua_pushrecord(lua_State * l, as_rec * r) { |
52 | // I am hoping the following is correct use of the free flag |
53 | mod_lua_box * box = mod_lua_pushbox(l, r->_.free ? MOD_LUA_SCOPE_LUA : MOD_LUA_SCOPE_HOST, r, CLASS_NAME); |
54 | return (as_rec *) mod_lua_box_value(box); |
55 | } |
56 | |
57 | /** |
58 | * Get the user record from the stack at index |
59 | */ |
60 | static as_rec * mod_lua_checkrecord(lua_State * l, int index) { |
61 | mod_lua_box * box = mod_lua_checkbox(l, index, CLASS_NAME); |
62 | return (as_rec *) mod_lua_box_value(box); |
63 | } |
64 | |
65 | /** |
66 | * Garbage collection |
67 | */ |
68 | static int mod_lua_record_gc(lua_State * l) { |
69 | mod_lua_freebox(l, 1, CLASS_NAME); |
70 | return 0; |
71 | } |
72 | |
73 | /** |
74 | * Get a record ttl: |
75 | * record.ttl(r) |
76 | */ |
77 | static int mod_lua_record_ttl(lua_State * l) { |
78 | as_rec * rec = (as_rec *) mod_lua_checkrecord(l, 1); |
79 | lua_pushinteger(l, as_rec_ttl(rec)); |
80 | return 1; |
81 | } |
82 | |
83 | /** |
84 | * Get a record's last update time: |
85 | * record.last_update_time(r) |
86 | */ |
87 | static int mod_lua_record_last_update_time(lua_State * l) { |
88 | as_rec * rec = (as_rec *) mod_lua_checkrecord(l, 1); |
89 | lua_pushinteger(l, as_rec_last_update_time(rec)); |
90 | return 1; |
91 | } |
92 | |
93 | /** |
94 | * Get a record generation: |
95 | * record.gen(r) |
96 | */ |
97 | static int mod_lua_record_gen(lua_State * l) { |
98 | as_rec * rec = (as_rec *) mod_lua_checkrecord(l, 1); |
99 | lua_pushinteger(l, as_rec_gen(rec)); |
100 | return 1; |
101 | } |
102 | |
103 | /** |
104 | * Get a record key: |
105 | * record.key(r) |
106 | */ |
107 | static int mod_lua_record_key(lua_State * l) { |
108 | as_rec * rec = (as_rec *) mod_lua_checkrecord(l, 1); |
109 | as_val * value = (as_val *) as_rec_key(rec); |
110 | if ( value != NULL ) { |
111 | mod_lua_pushval(l, value); |
112 | as_val_destroy(value); |
113 | return 1; |
114 | } |
115 | else { |
116 | lua_pushnil(l); |
117 | return 1; |
118 | } |
119 | } |
120 | |
121 | /** |
122 | * Get a set name: |
123 | * record.setname(r) |
124 | */ |
125 | static int mod_lua_record_setname(lua_State * l) { |
126 | as_rec * rec = (as_rec *) mod_lua_checkrecord(l, 1); |
127 | lua_pushstring(l, as_rec_setname(rec)); |
128 | return 1; |
129 | } |
130 | |
131 | /** |
132 | * Get a record digest: |
133 | * record.digest(r) |
134 | */ |
135 | static int mod_lua_record_digest(lua_State * l) { |
136 | as_rec * rec = (as_rec *) mod_lua_checkrecord(l, 1); |
137 | as_bytes * b = as_rec_digest(rec); |
138 | mod_lua_pushbytes(l, b); |
139 | return 1; |
140 | } |
141 | |
142 | /** |
143 | * Get a record numbins: |
144 | * record.numbins(r) |
145 | */ |
146 | static int mod_lua_record_numbins(lua_State * l) { |
147 | as_rec * rec = (as_rec *) mod_lua_checkrecord(l, 1); |
148 | lua_pushinteger(l, as_rec_numbins(rec)); |
149 | return 1; |
150 | } |
151 | |
152 | typedef struct { |
153 | lua_State * state; |
154 | int return_val; |
155 | } bin_names_data; |
156 | |
157 | void bin_names_callback(char * bin_names, uint32_t nbins, uint16_t max_name_size, void * udata) { |
158 | bin_names_data * data = (bin_names_data *) udata; |
159 | lua_State * l = data->state; |
160 | lua_createtable(l, nbins, 0); |
161 | if (nbins == 1 && *bin_names == 0) { // single-bin case |
162 | lua_pushnil(l); |
163 | lua_rawseti(l, -2, 1); |
164 | } |
165 | else { |
166 | for (uint16_t i = 0; i < nbins; i++) { |
167 | lua_pushstring(l, &bin_names[i * max_name_size]); |
168 | lua_rawseti(l, -2, i + 1); |
169 | } |
170 | } |
171 | } |
172 | |
173 | /** |
174 | * Get a table of a record's bin names: |
175 | * record.bin_names(r) |
176 | */ |
177 | static int mod_lua_record_bin_names(lua_State * l) { |
178 | as_rec * rec = (as_rec *) mod_lua_checkrecord(l, 1); |
179 | bin_names_data udata = {.state = l, .return_val = 0}; |
180 | |
181 | as_rec_bin_names(rec, bin_names_callback, (void *) &udata); |
182 | |
183 | return 1; |
184 | } |
185 | |
186 | /** |
187 | * Set a record time to live (ttl) |
188 | */ |
189 | static int mod_lua_record_set_ttl(lua_State * l) { |
190 | as_rec * rec = mod_lua_checkrecord(l, 1); |
191 | |
192 | // Get the 2nd arg off the stack -- and process as ttl |
193 | uint32_t ttl = (uint32_t)luaL_optinteger(l, 2, 0); |
194 | |
195 | // This function just sets up the arguments, |
196 | // The udf record method will do the real work. |
197 | as_rec_set_ttl( rec, ttl ); |
198 | |
199 | return 0; |
200 | } |
201 | |
202 | /** |
203 | * Drop a record's key |
204 | */ |
205 | static int mod_lua_record_drop_key(lua_State * l) { |
206 | as_rec * rec = mod_lua_checkrecord(l, 1); |
207 | |
208 | // This function just sets up the arguments, |
209 | // The udf record method will do the real work. |
210 | as_rec_drop_key( rec ); |
211 | |
212 | return 0; |
213 | } |
214 | |
215 | /** |
216 | * Get a value from the named bin |
217 | */ |
218 | static int mod_lua_record_index(lua_State * l) { |
219 | mod_lua_box * box = mod_lua_checkbox(l, 1, CLASS_NAME); |
220 | as_rec * rec = (as_rec *) mod_lua_box_value(box); |
221 | const char * name = luaL_optstring(l, 2, 0); |
222 | if ( name != NULL ) { |
223 | as_val * value = (as_val *) as_rec_get(rec, name); |
224 | if ( value != NULL ) { |
225 | mod_lua_pushval(l, value); |
226 | return 1; |
227 | } |
228 | else { |
229 | lua_pushnil(l); |
230 | return 1; |
231 | } |
232 | } |
233 | else { |
234 | lua_pushnil(l); |
235 | return 1; |
236 | } |
237 | } |
238 | |
239 | |
240 | /** |
241 | * Set a value in the named bin |
242 | */ |
243 | static int mod_lua_record_newindex(lua_State * l) { |
244 | as_rec * rec = mod_lua_checkrecord(l, 1); |
245 | const char * name = luaL_optstring(l, 2, 0); |
246 | if ( name != NULL ) { |
247 | // reference to this value is created by mod_lua_toval |
248 | // then stashed in the record cache |
249 | as_val * value = (as_val *) mod_lua_toval(l, 3); |
250 | if ( value != NULL ) { |
251 | as_rec_set(rec, name, value); |
252 | } |
253 | else { |
254 | as_rec_remove(rec, name); |
255 | } |
256 | } |
257 | return 0; |
258 | } |
259 | |
260 | /****************************************************************************** |
261 | * OBJECT TABLE |
262 | *****************************************************************************/ |
263 | |
264 | static const luaL_reg object_table[] = { |
265 | {"ttl" , mod_lua_record_ttl}, |
266 | {"last_update_time" , mod_lua_record_last_update_time}, |
267 | {"gen" , mod_lua_record_gen}, |
268 | {"key" , mod_lua_record_key}, |
269 | {"setname" , mod_lua_record_setname}, |
270 | {"digest" , mod_lua_record_digest}, |
271 | {"numbins" , mod_lua_record_numbins}, |
272 | {"set_ttl" , mod_lua_record_set_ttl}, |
273 | {"drop_key" , mod_lua_record_drop_key}, |
274 | {"bin_names" , mod_lua_record_bin_names}, |
275 | {0, 0} |
276 | }; |
277 | |
278 | static const luaL_reg object_metatable[] = { |
279 | // {"__index", mod_lua_record_index}, |
280 | {0, 0} |
281 | }; |
282 | |
283 | /****************************************************************************** |
284 | * CLASS TABLE |
285 | *****************************************************************************/ |
286 | /* |
287 | static const luaL_reg class_table[] = { |
288 | {0, 0} |
289 | }; |
290 | */ |
291 | |
292 | static const luaL_reg class_metatable[] = { |
293 | {"__index" , mod_lua_record_index}, |
294 | {"__newindex" , mod_lua_record_newindex}, |
295 | {"__gc" , mod_lua_record_gc}, |
296 | {0, 0} |
297 | }; |
298 | |
299 | /******************************************************************************* |
300 | * ~~~ Register ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
301 | ******************************************************************************/ |
302 | |
303 | int mod_lua_record_register(lua_State * l) { |
304 | mod_lua_reg_object(l, OBJECT_NAME, object_table, object_metatable); |
305 | mod_lua_reg_class(l, CLASS_NAME, NULL, class_metatable); |
306 | return 1; |
307 | } |
308 | |