Skip to content

Commit 75272b5

Browse files
committed
add {} support(example: "id{}": [1, 2]); update tests and demo; bump version number to 0.2.2
1 parent b0ec28f commit 75272b5

File tree

4 files changed

+301
-12
lines changed

4 files changed

+301
-12
lines changed

demo/apps/apijson_demo/views.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,28 @@ def index():
8585
}''',
8686
},
8787

88+
{
89+
"label":"Array query: {} with list",
90+
"value":'''{
91+
"[]":{
92+
"moment":{
93+
"id{}":[2,3]
94+
}
95+
}
96+
}''',
97+
},
98+
99+
{
100+
"label":"Array query: {} with conditions",
101+
"value":'''{
102+
"[]":{
103+
"user":{
104+
"id&{}":">2,<=4"
105+
}
106+
}
107+
}''',
108+
},
109+
88110
{
89111
"label":"Array query: simple @expr",
90112
"value":'''{

tests/test.py

Lines changed: 219 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ def setup():
1111
manage.call('uliweb reset -v -y')
1212
manage.call('uliweb dbinit -v')
1313

14-
def teardown():
15-
pass
16-
1714
def pre_call_as(username):
1815
from uliweb import models
1916
User = models.user
@@ -22,7 +19,6 @@ def pre_call(request):
2219
request.user = user
2320
return pre_call
2421

25-
@with_setup(setup,teardown)
2622
def test_apijson_get():
2723
"""
2824
>>> application = make_simple_application(project_dir='.')
@@ -747,7 +743,7 @@ def test_apijson_get():
747743
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
748744
>>> d = json_loads(r.data)
749745
>>> print(d)
750-
{'code': 400, 'msg': "model does not have this column: 'nonexist'"}
746+
{'code': 400, 'msg': "model does not have column: 'nonexist'"}
751747
752748
>>> #query array with a nonexist column
753749
>>> data ='''{
@@ -767,6 +763,224 @@ def test_apijson_get():
767763
>>> print(d)
768764
{'code': 400, 'msg': "non-existent column or not support item: 'nonexist'"}
769765
766+
>>> #query array, {} with list
767+
>>> data ='''{
768+
... "[]":{
769+
... "moment": {
770+
... "id{}": [1, 2]
771+
... }
772+
... }
773+
... }'''
774+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
775+
>>> d = json_loads(r.data)
776+
>>> print(d)
777+
{'code': 200, 'msg': 'success', '[]': [{'moment': {'user_id': 2, 'date': '2018-11-01 00:00:00', 'content': 'test moment', 'picture_list': '[]', 'id': 1}}, {'moment': {'user_id': 3, 'date': '2018-11-02 00:00:00', 'content': 'test moment from b', 'picture_list': '[]', 'id': 2}}]}
778+
779+
>>> #query array, !{} with list
780+
>>> data ='''{
781+
... "[]":{
782+
... "moment": {
783+
... "id!{}": [1, 2]
784+
... }
785+
... }
786+
... }'''
787+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
788+
>>> d = json_loads(r.data)
789+
>>> print(d)
790+
{'code': 200, 'msg': 'success', '[]': [{'moment': {'user_id': 4, 'date': '2018-11-06 00:00:00', 'content': 'test moment from c', 'picture_list': '[]', 'id': 3}}]}
791+
792+
>>> #query array, {} with a non-exist column name
793+
>>> data ='''{
794+
... "[]":{
795+
... "moment": {
796+
... "nonexist{}": [1, 2]
797+
... }
798+
... }
799+
... }'''
800+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
801+
>>> d = json_loads(r.data)
802+
>>> print(d)
803+
{'code': 400, 'msg': "model does not have column: 'nonexist'"}
804+
805+
>>> #query array, {} >=
806+
>>> data ='''{
807+
... "[]":{
808+
... "moment": {
809+
... "id{}": ">=2"
810+
... }
811+
... }
812+
... }'''
813+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
814+
>>> d = json_loads(r.data)
815+
>>> print(d)
816+
{'code': 200, 'msg': 'success', '[]': [{'moment': {'user_id': 3, 'date': '2018-11-02 00:00:00', 'content': 'test moment from b', 'picture_list': '[]', 'id': 2}}, {'moment': {'user_id': 4, 'date': '2018-11-06 00:00:00', 'content': 'test moment from c', 'picture_list': '[]', 'id': 3}}]}
817+
818+
>>> #query array, {} =
819+
>>> data ='''{
820+
... "[]":{
821+
... "moment": {
822+
... "id{}": "=2"
823+
... }
824+
... }
825+
... }'''
826+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
827+
>>> d = json_loads(r.data)
828+
>>> print(d)
829+
{'code': 200, 'msg': 'success', '[]': [{'moment': {'user_id': 3, 'date': '2018-11-02 00:00:00', 'content': 'test moment from b', 'picture_list': '[]', 'id': 2}}]}
830+
831+
>>> #query array, {} >
832+
>>> data ='''{
833+
... "[]":{
834+
... "moment": {
835+
... "id{}": ">2"
836+
... }
837+
... }
838+
... }'''
839+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
840+
>>> d = json_loads(r.data)
841+
>>> print(d)
842+
{'code': 200, 'msg': 'success', '[]': [{'moment': {'user_id': 4, 'date': '2018-11-06 00:00:00', 'content': 'test moment from c', 'picture_list': '[]', 'id': 3}}]}
843+
844+
>>> #query array, {} <=
845+
>>> data ='''{
846+
... "[]":{
847+
... "moment": {
848+
... "id{}": "<=2"
849+
... }
850+
... }
851+
... }'''
852+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
853+
>>> d = json_loads(r.data)
854+
>>> print(d)
855+
{'code': 200, 'msg': 'success', '[]': [{'moment': {'user_id': 2, 'date': '2018-11-01 00:00:00', 'content': 'test moment', 'picture_list': '[]', 'id': 1}}, {'moment': {'user_id': 3, 'date': '2018-11-02 00:00:00', 'content': 'test moment from b', 'picture_list': '[]', 'id': 2}}]}
856+
857+
>>> #query array, {} <
858+
>>> data ='''{
859+
... "[]":{
860+
... "moment": {
861+
... "id{}": "<2"
862+
... }
863+
... }
864+
... }'''
865+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
866+
>>> d = json_loads(r.data)
867+
>>> print(d)
868+
{'code': 200, 'msg': 'success', '[]': [{'moment': {'user_id': 2, 'date': '2018-11-01 00:00:00', 'content': 'test moment', 'picture_list': '[]', 'id': 1}}]}
869+
870+
>>> #query array, !{} <
871+
>>> data ='''{
872+
... "[]":{
873+
... "moment": {
874+
... "id!{}": "<2"
875+
... }
876+
... }
877+
... }'''
878+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
879+
>>> d = json_loads(r.data)
880+
>>> print(d)
881+
{'code': 200, 'msg': 'success', '[]': [{'moment': {'user_id': 3, 'date': '2018-11-02 00:00:00', 'content': 'test moment from b', 'picture_list': '[]', 'id': 2}}, {'moment': {'user_id': 4, 'date': '2018-11-06 00:00:00', 'content': 'test moment from c', 'picture_list': '[]', 'id': 3}}]}
882+
883+
>>> #query array, {} !=
884+
>>> data ='''{
885+
... "[]":{
886+
... "moment": {
887+
... "id{}": "!=2"
888+
... }
889+
... }
890+
... }'''
891+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
892+
>>> d = json_loads(r.data)
893+
>>> print(d)
894+
{'code': 200, 'msg': 'success', '[]': [{'moment': {'user_id': 2, 'date': '2018-11-01 00:00:00', 'content': 'test moment', 'picture_list': '[]', 'id': 1}}, {'moment': {'user_id': 4, 'date': '2018-11-06 00:00:00', 'content': 'test moment from c', 'picture_list': '[]', 'id': 3}}]}
895+
896+
>>> #query array, {} with wrong operator
897+
>>> data ='''{
898+
... "[]":{
899+
... "moment": {
900+
... "id{}": "%=2"
901+
... }
902+
... }
903+
... }'''
904+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
905+
>>> d = json_loads(r.data)
906+
>>> print(d)
907+
{'code': 400, 'msg': "not support '%=2'"}
908+
909+
>>> #query array, {} condition list
910+
>>> data ='''{
911+
... "[]":{
912+
... "user": {
913+
... "@role": "ADMIN",
914+
... "id{}": "<=2,>3",
915+
... "@column": "username,nickname,id"
916+
... }
917+
... }
918+
... }'''
919+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
920+
>>> d = json_loads(r.data)
921+
>>> print(d)
922+
{'code': 200, 'msg': 'success', '[]': [{'user': {'username': 'admin', 'nickname': 'Administrator', 'id': 1}}, {'user': {'username': 'usera', 'nickname': 'User A', 'id': 2}}, {'user': {'username': 'userc', 'nickname': 'User C', 'id': 4}}]}
923+
924+
>>> #query array, |{} condition list
925+
>>> data ='''{
926+
... "[]":{
927+
... "user": {
928+
... "@role": "ADMIN",
929+
... "id|{}": "<=2,>3",
930+
... "@column": "username,nickname,id"
931+
... }
932+
... }
933+
... }'''
934+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
935+
>>> d = json_loads(r.data)
936+
>>> print(d)
937+
{'code': 200, 'msg': 'success', '[]': [{'user': {'username': 'admin', 'nickname': 'Administrator', 'id': 1}}, {'user': {'username': 'usera', 'nickname': 'User A', 'id': 2}}, {'user': {'username': 'userc', 'nickname': 'User C', 'id': 4}}]}
938+
939+
>>> #query array, &{} condition list
940+
>>> data ='''{
941+
... "[]":{
942+
... "user": {
943+
... "@role": "ADMIN",
944+
... "id&{}": ">2,<=4",
945+
... "@column": "username,nickname,id"
946+
... }
947+
... }
948+
... }'''
949+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
950+
>>> d = json_loads(r.data)
951+
>>> print(d)
952+
{'code': 200, 'msg': 'success', '[]': [{'user': {'username': 'userb', 'nickname': 'User B', 'id': 3}}, {'user': {'username': 'userc', 'nickname': 'User C', 'id': 4}}]}
953+
954+
>>> #query array, !{} condition list
955+
>>> data ='''{
956+
... "[]":{
957+
... "user": {
958+
... "@role": "ADMIN",
959+
... "id!{}": ">2,<=4",
960+
... "@column": "username,nickname,id"
961+
... }
962+
... }
963+
... }'''
964+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
965+
>>> d = json_loads(r.data)
966+
>>> print(d)
967+
{'code': 400, 'msg': "'!' not supported in condition list"}
968+
969+
>>> #query array, |{} condition list, item more than 2
970+
>>> data ='''{
971+
... "[]":{
972+
... "user": {
973+
... "@role": "ADMIN",
974+
... "id|{}": "=1,=2,>=4",
975+
... "@column": "username,id"
976+
... }
977+
... }
978+
... }'''
979+
>>> r = handler.post('/apijson/get', data=data, pre_call=pre_call_as("admin"), middlewares=[])
980+
>>> d = json_loads(r.data)
981+
>>> print(d)
982+
{'code': 200, 'msg': 'success', '[]': [{'user': {'username': 'admin', 'id': 1}}, {'user': {'username': 'usera', 'id': 2}}, {'user': {'username': 'userc', 'id': 4}}]}
983+
770984
>>> #Association query: Two tables, one to one,ref path is absolute path
771985
>>> data ='''{
772986
... "moment":{},

uliweb_apijson/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = '0.2.1'
1+
__version__ = '0.2.2'
22
__url__ = 'https://github.com/zhangchunlin/uliweb-apijson'
33
__author__ = 'Chunlin Zhang'
44
__email__ = 'zhangchunlin@gmail.com'

uliweb_apijson/apijson/views.py

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -244,18 +244,71 @@ def _get_filter_condition(self,model,model_param,item,expr=False):
244244
if hasattr(model,name):
245245
return getattr(model.c,name).like(model_param[n])
246246
else:
247-
raise UliwebError("model does not have this column: '%s'"%(name))
247+
raise UliwebError("model does not have column: '%s'"%(name))
248248
elif n[-1]=="}" and n[-2]=="{":
249-
name = n[:-2]
250-
if hasattr(model,name):
251-
# TODO: https://github.com/APIJSON/APIJSON/blob/master/Document.md#32-%E5%8A%9F%E8%83%BD%E7%AC%A6
252-
pass
253-
raise UliwebError("still not support '%s'"%(name))
249+
if n[-3] in ["&","|","!"]:
250+
operator = n[-3]
251+
name = n[:-3]
252+
else:
253+
operator = None
254+
name = n[:-2]
255+
256+
if not hasattr(model,name):
257+
raise UliwebError("model does not have column: '%s'"%(name))
258+
259+
# https://github.com/APIJSON/APIJSON/blob/master/Document.md#32-%E5%8A%9F%E8%83%BD%E7%AC%A6
260+
# https://vincentcheng.github.io/apijson-doc/zh/grammar.html#%E9%80%BB%E8%BE%91%E8%BF%90%E7%AE%97-%E7%AD%9B%E9%80%89
261+
col = getattr(model.c,name)
262+
cond = model_param[n]
263+
if isinstance(cond,list):
264+
fcond = col.in_(cond)
265+
if operator== "!":
266+
fcond = not_(fcond)
267+
return fcond
268+
elif isinstance(cond,str):
269+
cond_list = cond.strip().split(",")
270+
if len(cond_list)==1:
271+
fcond = self._get_filter_condition_from_str(col,cond_list[0])
272+
if operator=="!":
273+
fcond = not_(fcond)
274+
return fcond
275+
elif len(cond_list)>1:
276+
fcond = self._get_filter_condition_from_str(col,cond_list[0])
277+
for c in cond_list:
278+
fc = self._get_filter_condition_from_str(col,c)
279+
if operator=="&":
280+
fcond = and_(fcond,fc)
281+
elif operator=="|" or operator==None:
282+
fcond = or_(fcond,fc)
283+
else:
284+
raise UliwebError("'%s' not supported in condition list"%(operator))
285+
return fcond
286+
287+
raise UliwebError("not support '%s':'%s'"%(n,cond))
254288
elif hasattr(model,n):
255289
return getattr(model.c,n)==model_param[n]
256290
else:
257291
raise UliwebError("non-existent column or not support item: '%s'"%(item))
258292

293+
def _get_filter_condition_from_str(self,col,cond_str):
294+
cond_str = cond_str.strip()
295+
c1,c2 = cond_str[0],cond_str[1]
296+
if c1=='>':
297+
if c2=="=":
298+
return col >= cond_str[2:]
299+
else:
300+
return col > cond_str[1:]
301+
elif c1=='<':
302+
if c2=="=":
303+
return col <= cond_str[2:]
304+
else:
305+
return col < cond_str[1:]
306+
elif c1=="=":
307+
return col == cond_str[1:]
308+
elif c1=="!" and c2=="=":
309+
return col != cond_str[2:]
310+
raise UliwebError("not support '%s'"%(cond_str))
311+
259312
def head(self):
260313
try:
261314
for key in self.request_data:

0 commit comments

Comments
 (0)