Skip to content

Commit 29d552e

Browse files
alixaxelrockwotj
authored andcommitted
Enclose Logical Expressions with Parentheses (FirebaseExtended#233)
* enforce parentheses on logical operations * updated output in docs
1 parent aa52c5e commit 29d552e

22 files changed

+142
-94
lines changed

docs/guide.md

+19-18
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ To access properties of a type in an expression, use the `this` variable (e.g.
153153
"posts": {
154154
".read": "true",
155155
"$id": {
156-
".validate": "newData.hasChildren(['message', 'from']) && newData.child('message').val().length <= 140",
156+
".validate": "(newData.hasChildren(['message', 'from']) && newData.child('message').val().length <= 140)",
157157
"message": {
158158
".validate": "newData.isString()"
159159
},
@@ -203,7 +203,7 @@ type Person {
203203
".validate": "newData.isBoolean()"
204204
},
205205
"extra": {
206-
".validate": "newData.hasChildren() || newData.val() == null"
206+
".validate": "newData.hasChildren()"
207207
},
208208
"$other": {
209209
".validate": "false"
@@ -252,7 +252,7 @@ This example compiles to:
252252
"$id": {
253253
".validate": "newData.hasChildren(['name', 'isAdmin'])",
254254
"name": {
255-
".validate": "newData.isString() && newData.val().length > 0 && newData.val().length <= 32"
255+
".validate": "((newData.isString() && newData.val().length > 0) && newData.val().length <= 32)"
256256
},
257257
"isAdmin": {
258258
".validate": "newData.isBoolean()"
@@ -266,7 +266,7 @@ This example compiles to:
266266
"$id": {
267267
".validate": "newData.hasChildren(['name', 'creator'])",
268268
"name": {
269-
".validate": "newData.isString() && newData.val().length > 0 && newData.val().length <= 32"
269+
".validate": "((newData.isString() && newData.val().length > 0) && newData.val().length <= 32)"
270270
},
271271
"creator": {
272272
".validate": "newData.isString()"
@@ -311,13 +311,13 @@ isCurrentUser(uid) { auth != null && auth.uid == uid }
311311
".validate": "newData.isString()"
312312
},
313313
"age": {
314-
".validate": "newData.isNumber() || newData.val() == null"
314+
".validate": "newData.isNumber()"
315315
},
316316
"$other": {
317317
".validate": "false"
318318
},
319319
".read": "true",
320-
".write": "auth != null && auth.uid == $userid"
320+
".write": "(auth != null && auth.uid == $userid)"
321321
}
322322
}
323323
}
@@ -409,10 +409,10 @@ Note the special function `prior(ref)` - returns the previous value stored at a
409409
".validate": "newData.isString()"
410410
},
411411
"modified": {
412-
".validate": "newData.isNumber() && newData.val() == now"
412+
".validate": "(newData.isNumber() && newData.val() == now)"
413413
},
414414
"created": {
415-
".validate": "newData.isNumber() && newData.val() == (data.val() == null ? now : data.val())"
415+
".validate": "(newData.isNumber() && newData.val() == (data.val() == null ? now : data.val()))"
416416
},
417417
"$other": {
418418
".validate": "false"
@@ -472,10 +472,10 @@ initial(value, init) { value == (prior(value) == null ? init : prior(value)) }
472472
".validate": "false"
473473
},
474474
"modified": {
475-
".validate": "newData.isNumber() && newData.val() == now"
475+
".validate": "(newData.isNumber() && newData.val() == now)"
476476
},
477477
"created": {
478-
".validate": "newData.isNumber() && newData.val() == (data.val() == null ? now : data.val())"
478+
".validate": "(newData.isNumber() && newData.val() == (data.val() == null ? now : data.val()))"
479479
},
480480
".read": "true",
481481
".write": "true"
@@ -561,36 +561,37 @@ createOnly(value) { prior(value) == null && value != null }
561561
"$key1": {
562562
".validate": "newData.isString()"
563563
},
564+
".validate": "newData.hasChildren()",
564565
".read": "auth != null"
565566
},
566567
"members": {
567568
"$room_id": {
568-
".read": "auth != null && root.child('members').child($room_id).child(auth.uid).val() != null",
569+
".read": "(auth != null && root.child('members').child($room_id).child(auth.uid).val() != null)",
569570
"$user_id": {
570-
".validate": "newData.val().length > 0 && newData.val().length < 20",
571-
".write": "auth != null && auth.uid == $user_id"
571+
".validate": "(newData.val().length > 0 && newData.val().length < 20)",
572+
".write": "(auth != null && auth.uid == $user_id)"
572573
}
573574
}
574575
},
575576
"messages": {
576577
"$room_id": {
577578
".validate": "root.child('room_names').child($room_id).val() != null",
578-
".read": "auth != null && root.child('members').child($room_id).child(auth.uid).val() != null",
579+
".read": "(auth != null && root.child('members').child($room_id).child(auth.uid).val() != null)",
579580
"$message_id": {
580581
".validate": "newData.hasChildren(['name', 'message', 'timestamp'])",
581582
"name": {
582-
".validate": "newData.val().length > 0 && newData.val().length < 20"
583+
".validate": "(newData.val().length > 0 && newData.val().length < 20)"
583584
},
584585
"message": {
585-
".validate": "newData.isString() && newData.val().length > 0 && newData.val().length < 50"
586+
".validate": "((newData.isString() && newData.val().length > 0) && newData.val().length < 50)"
586587
},
587588
"timestamp": {
588-
".validate": "newData.isNumber() && newData.val() == now"
589+
".validate": "(newData.isNumber() && newData.val() == now)"
589590
},
590591
"$other": {
591592
".validate": "false"
592593
},
593-
".write": "data.val() == null && newData.val() != null && (auth != null && root.child('members').child($room_id).child(auth.uid).val() != null)"
594+
".write": "((data.val() == null && newData.val() != null) && (auth != null && root.child('members').child($room_id).child(auth.uid).val() != null))"
594595
}
595596
}
596597
}

samples/chat.json

+11-11
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,34 @@
22
"rules": {
33
"rooms": {
44
"$key1": {
5-
".validate": "newData.hasChildren(['name', 'creator']) && $key1.length >= 1 && $key1.length <= 32",
5+
".validate": "((newData.hasChildren(['name', 'creator']) && $key1.length >= 1) && $key1.length <= 32)",
66
"name": {
7-
".validate": "newData.val().length > 0 && newData.val().length <= 32"
7+
".validate": "(newData.val().length > 0 && newData.val().length <= 32)"
88
},
99
"creator": {
10-
".validate": "newData.isString() && (auth != null && newData.val() == auth.uid)"
10+
".validate": "(newData.isString() && (auth != null && newData.val() == auth.uid))"
1111
},
1212
"members": {
1313
"$key2": {
1414
".validate": "newData.hasChildren(['nickname', 'isBanned'])",
1515
"nickname": {
16-
".validate": "newData.val().length > 0 && newData.val().length <= 32"
16+
".validate": "(newData.val().length > 0 && newData.val().length <= 32)"
1717
},
1818
"isBanned": {
1919
".validate": "newData.isBoolean()"
2020
},
2121
"$other": {
2222
".validate": "false"
2323
},
24-
".write": "data.val() == null && (auth != null && $key2 == auth.uid)"
24+
".write": "(data.val() == null && (auth != null && $key2 == auth.uid))"
2525
},
2626
".validate": "newData.hasChildren()"
2727
},
2828
"$other": {
2929
".validate": "false"
3030
},
31-
".write": "data.val() == null || data.val() != null && newData.val() != null && (auth != null && data.child('creator').val() == auth.uid) || data.val() != null && newData.val() == null && (auth != null && data.child('creator').val() == auth.uid)",
32-
".read": "data.child('members').child(auth.uid).val() != null && !(data.child('members').child(auth.uid).child('isBanned').val() == true) || auth != null && data.child('creator').val() == auth.uid"
31+
".write": "((data.val() == null || ((data.val() != null && newData.val() != null) && (auth != null && data.child('creator').val() == auth.uid))) || ((data.val() != null && newData.val() == null) && (auth != null && data.child('creator').val() == auth.uid)))",
32+
".read": "((data.child('members').child(auth.uid).val() != null && !(data.child('members').child(auth.uid).child('isBanned').val() == true)) || (auth != null && data.child('creator').val() == auth.uid))"
3333
},
3434
".validate": "newData.hasChildren()"
3535
},
@@ -39,17 +39,17 @@
3939
"$postid": {
4040
".validate": "newData.hasChildren(['from', 'message', 'created'])",
4141
"from": {
42-
".validate": "newData.isString() && (auth != null && newData.val() == auth.uid)"
42+
".validate": "(newData.isString() && (auth != null && newData.val() == auth.uid))"
4343
},
4444
"message": {
45-
".validate": "newData.isString() && newData.val().length > 0 && newData.val().length <= 140"
45+
".validate": "((newData.isString() && newData.val().length > 0) && newData.val().length <= 140)"
4646
},
4747
"$other": {
4848
".validate": "false"
4949
},
50-
".write": "data.val() == null && (root.child('rooms').child($roomid).child('members').child(auth.uid).val() != null && !(root.child('rooms').child($roomid).child('members').child(auth.uid).child('isBanned').val() == true))",
50+
".write": "(data.val() == null && (root.child('rooms').child($roomid).child('members').child(auth.uid).val() != null && !(root.child('rooms').child($roomid).child('members').child(auth.uid).child('isBanned').val() == true)))",
5151
"created": {
52-
".validate": "newData.isNumber() && newData.val() == (data.val() == null ? now : data.val())"
52+
".validate": "(newData.isNumber() && newData.val() == (data.val() == null ? now : data.val()))"
5353
}
5454
}
5555
}

samples/create-update-delete.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
".write": "data.val() == null"
77
},
88
"update": {
9-
".write": "data.val() != null && newData.val() != null"
9+
".write": "(data.val() != null && newData.val() != null)"
1010
},
1111
"delete": {
12-
".write": "data.val() != null && newData.val() == null"
12+
".write": "(data.val() != null && newData.val() == null)"
1313
},
1414
"create-or-update": {
15-
".write": "data.val() == null || data.val() != null && newData.val() != null"
15+
".write": "(data.val() == null || (data.val() != null && newData.val() != null))"
1616
},
1717
"owner-create-delete": {
18-
".write": "data.val() == null && $uid == auth.uid || data.val() != null && newData.val() != null || data.val() != null && newData.val() == null && $uid == auth.uid"
18+
".write": "(((data.val() == null && $uid == auth.uid) || (data.val() != null && newData.val() != null)) || ((data.val() != null && newData.val() == null) && $uid == auth.uid))"
1919
}
2020
}
2121
}

samples/generics.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
".validate": "newData.hasChildren()",
44
"users": {
55
"$key1": {
6-
".validate": "newData.hasChildren(['name', 'age']) && $key1.length == 20",
6+
".validate": "(newData.hasChildren(['name', 'age']) && $key1.length == 20)",
77
"name": {
88
".validate": "newData.isString()"
99
},
@@ -18,9 +18,9 @@
1818
},
1919
"products": {
2020
"$key2": {
21-
".validate": "newData.hasChildren(['id', 'cost']) && $key2.length <= 20 && $key2 == newData.child('id').val()",
21+
".validate": "((newData.hasChildren(['id', 'cost']) && $key2.length <= 20) && $key2 == newData.child('id').val())",
2222
"id": {
23-
".validate": "newData.isString() && newData.val().length <= 20"
23+
".validate": "(newData.isString() && newData.val().length <= 20)"
2424
},
2525
"cost": {
2626
".validate": "newData.isNumber()"

samples/groups.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
"rules": {
33
"groups": {
44
"$gid": {
5-
".validate": "newData.hasChildren() && members != null",
5+
".validate": "(newData.hasChildren() && members != null)",
66
"members": {
77
"$key1": {
8-
".validate": "newData.hasChildren(['uid', 'name']) && $key1.length == 1 && $key1 >= '0' && $key1 <= '9'",
8+
".validate": "(((newData.hasChildren(['uid', 'name']) && $key1.length == 1) && $key1 >= '0') && $key1 <= '9')",
99
"uid": {
1010
".validate": "newData.isString()"
1111
},

samples/issue-118.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"$key1": {
2525
".validate": "newData.isNumber()"
2626
},
27-
".validate": "newData.hasChildren() || newData.isNumber()"
27+
".validate": "(newData.hasChildren() || newData.isNumber())"
2828
},
2929
"map": {
3030
"$key1": {
@@ -36,7 +36,7 @@
3636
"$key1": {
3737
".validate": "newData.isNumber()"
3838
},
39-
".validate": "newData.hasChildren() || newData.isNumber()"
39+
".validate": "(newData.hasChildren() || newData.isNumber())"
4040
},
4141
"$other": {
4242
".validate": "false"

samples/issue-136.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"rules": {
33
"entity": {
44
"$entity": {
5-
".validate": "newData.hasChildren(['entityType']) && 'project|user'.contains(newData.child('entityType').val())",
5+
".validate": "(newData.hasChildren(['entityType']) && 'project|user'.contains(newData.child('entityType').val()))",
66
"entityType": {
77
".validate": "newData.isString()"
88
},

samples/issue-169.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"rules": {
33
"test": {
44
"$key1": {
5-
".validate": "root.val() != null && newData.isString()"
5+
".validate": "(root.val() != null && newData.isString())"
66
},
77
".validate": "newData.hasChildren()"
88
}

samples/issue-232.bolt

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
function isAuth() {
2+
(auth != null);
3+
}
4+
5+
function isUser(user) {
6+
isAuth() && (user == auth.uid);
7+
}
8+
9+
function isAdmin() {
10+
isAuth() && (root.child('admins').child(auth.uid).val() != null);
11+
}
12+
13+
path /users/{key1} {
14+
read() {
15+
isUser(key1) || isAdmin();
16+
}
17+
}
18+
19+
path /profile/{key1} {
20+
create() {
21+
isUser(key1);
22+
}
23+
24+
update() {
25+
isUser(key1);
26+
}
27+
}

samples/issue-232.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"rules": {
3+
"users": {
4+
"$key1": {
5+
".read": "((auth != null && $key1 == auth.uid) || (auth != null && root.child('admins').child(auth.uid).val() != null))"
6+
}
7+
},
8+
"profile": {
9+
"$key1": {
10+
".write": "((data.val() == null && (auth != null && $key1 == auth.uid)) || ((data.val() != null && newData.val() != null) && (auth != null && $key1 == auth.uid)))"
11+
}
12+
}
13+
}
14+
}

samples/mail.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"$userid": {
55
"inbox": {
66
"$msg": {
7-
".validate": "newData.hasChildren(['from', 'to', 'message']) && data.val() == null && (auth != null && auth.uid == newData.child('from').val())",
7+
".validate": "((newData.hasChildren(['from', 'to', 'message']) && data.val() == null) && (auth != null && auth.uid == newData.child('from').val()))",
88
"from": {
99
".validate": "newData.isString()"
1010
},
@@ -17,13 +17,13 @@
1717
"$other": {
1818
".validate": "false"
1919
},
20-
".read": "auth != null && auth.uid == $userid",
21-
".write": "data.val() == null || auth != null && auth.uid == $userid"
20+
".read": "(auth != null && auth.uid == $userid)",
21+
".write": "(data.val() == null || (auth != null && auth.uid == $userid))"
2222
}
2323
},
2424
"outbox": {
2525
"$msg": {
26-
".validate": "newData.hasChildren(['from', 'to', 'message']) && data.val() == null && (auth != null && auth.uid == newData.child('from').val())",
26+
".validate": "((newData.hasChildren(['from', 'to', 'message']) && data.val() == null) && (auth != null && auth.uid == newData.child('from').val()))",
2727
"from": {
2828
".validate": "newData.isString()"
2929
},
@@ -36,8 +36,8 @@
3636
"$other": {
3737
".validate": "false"
3838
},
39-
".read": "auth != null && auth.uid == $userid",
40-
".write": "auth != null && auth.uid == $userid"
39+
".read": "(auth != null && auth.uid == $userid)",
40+
".write": "(auth != null && auth.uid == $userid)"
4141
}
4242
}
4343
}

samples/map-scalar.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22
"rules": {
33
".validate": "newData.hasChildren(['s1', 's2'])",
44
"s1": {
5-
".validate": "newData.isString() && newData.val().length >= 0 && newData.val().length <= 16"
5+
".validate": "((newData.isString() && newData.val().length >= 0) && newData.val().length <= 16)"
66
},
77
"s2": {
8-
".validate": "newData.isString() && newData.val().length >= 0 && newData.val().length <= 16"
8+
".validate": "((newData.isString() && newData.val().length >= 0) && newData.val().length <= 16)"
99
},
1010
"m1": {
1111
"$key1": {
12-
".validate": "$key1.length >= 0 && $key1.length <= 16 && newData.isNumber()"
12+
".validate": "(($key1.length >= 0 && $key1.length <= 16) && newData.isNumber())"
1313
},
1414
".validate": "newData.hasChildren()"
1515
},
1616
"m2": {
1717
"$key2": {
18-
".validate": "$key2.length >= 0 && $key2.length <= 16 && newData.isNumber()"
18+
".validate": "(($key2.length >= 0 && $key2.length <= 16) && newData.isNumber())"
1919
},
2020
".validate": "newData.hasChildren()"
2121
},

0 commit comments

Comments
 (0)