@@ -11,7 +11,12 @@ pub enum NullableResult {
11
11
}
12
12
13
13
#[ wasm_bindgen]
14
- pub fn is_column_nullable ( column : & str , table_name : & str , query : & str ) -> Option < NullableResult > {
14
+ pub fn is_column_nullable (
15
+ column : & str ,
16
+ table_name : & str ,
17
+ notnull : bool ,
18
+ query : & str ,
19
+ ) -> Option < NullableResult > {
15
20
let mut parser = Parser :: new ( query. as_bytes ( ) ) ;
16
21
let cmd = parser. next ( ) . ok ( ) ??;
17
22
@@ -22,6 +27,11 @@ pub fn is_column_nullable(column: &str, table_name: &str, query: &str) -> Option
22
27
..
23
28
} = select. body . select
24
29
{
30
+ // If a column is declared as not null we only need to prove that the table it came from is always present
31
+ if notnull {
32
+ return get_used_table_name ( table_name, & from) . map ( |_| NullableResult :: NotNull ) ;
33
+ }
34
+
25
35
let used_table_name = get_used_table_name ( table_name, & from) ?;
26
36
27
37
if let Some ( where_clause) = where_clause {
@@ -218,57 +228,85 @@ mod tests {
218
228
219
229
#[ test]
220
230
fn returns_none_when_nothing_is_provable ( ) {
221
- assert_eq ! ( is_column_nullable( "id" , "foo" , "select * from foo" ) , None ) ;
231
+ assert_eq ! (
232
+ is_column_nullable( "id" , "foo" , false , "select * from foo" ) ,
233
+ None
234
+ ) ;
222
235
}
223
236
224
237
#[ test]
225
238
fn support_not_null ( ) {
226
239
assert_eq ! (
227
- is_column_nullable( "id" , "foo" , "select * from foo where id is not null" ) ,
240
+ is_column_nullable( "id" , "foo" , false , "select * from foo where id is not null" ) ,
228
241
Some ( NullableResult :: NotNull )
229
242
) ;
230
243
assert_eq ! (
231
- is_column_nullable( "id" , "foo" , "select * from foo where id notnull" ) ,
244
+ is_column_nullable( "id" , "foo" , false , "select * from foo where id notnull" ) ,
232
245
Some ( NullableResult :: NotNull )
233
246
) ;
234
247
}
235
248
236
249
#[ test]
237
250
fn support_aliased_table ( ) {
238
251
assert_eq ! (
239
- is_column_nullable( "id" , "foo" , "select * from foo f where id notnull" ) ,
252
+ is_column_nullable( "id" , "foo" , false , "select * from foo f where id notnull" ) ,
240
253
Some ( NullableResult :: NotNull )
241
254
) ;
242
255
assert_eq ! (
243
- is_column_nullable( "id" , "foo" , "select * from foo f where f.id notnull" ) ,
256
+ is_column_nullable( "id" , "foo" , false , "select * from foo f where f.id notnull" ) ,
244
257
Some ( NullableResult :: NotNull )
245
258
) ;
246
259
assert_eq ! (
247
- is_column_nullable( "id" , "foo" , "select * from foo f where foo.id notnull" ) ,
260
+ is_column_nullable(
261
+ "id" ,
262
+ "foo" ,
263
+ false ,
264
+ "select * from foo f where foo.id notnull"
265
+ ) ,
248
266
None
249
267
) ;
250
268
}
251
269
252
270
#[ test]
253
271
fn support_aliased_table_using_as ( ) {
254
272
assert_eq ! (
255
- is_column_nullable( "id" , "foo" , "select * from foo as f where id notnull" ) ,
273
+ is_column_nullable(
274
+ "id" ,
275
+ "foo" ,
276
+ false ,
277
+ "select * from foo as f where id notnull"
278
+ ) ,
256
279
Some ( NullableResult :: NotNull )
257
280
) ;
258
281
assert_eq ! (
259
- is_column_nullable( "id" , "foo" , "select * from foo as f where f.id notnull" ) ,
282
+ is_column_nullable(
283
+ "id" ,
284
+ "foo" ,
285
+ false ,
286
+ "select * from foo as f where f.id notnull"
287
+ ) ,
260
288
Some ( NullableResult :: NotNull )
261
289
) ;
262
290
assert_eq ! (
263
- is_column_nullable( "id" , "foo" , "select * from foo as f where foo.id notnull" ) ,
291
+ is_column_nullable(
292
+ "id" ,
293
+ "foo" ,
294
+ false ,
295
+ "select * from foo as f where foo.id notnull"
296
+ ) ,
264
297
None
265
298
) ;
266
299
}
267
300
268
301
#[ test]
269
302
fn support_and ( ) {
270
303
assert_eq ! (
271
- is_column_nullable( "id" , "foo" , "select * from foo where 1=1 and id not null" , ) ,
304
+ is_column_nullable(
305
+ "id" ,
306
+ "foo" ,
307
+ false ,
308
+ "select * from foo where 1=1 and id not null" ,
309
+ ) ,
272
310
Some ( NullableResult :: NotNull )
273
311
) ;
274
312
}
@@ -279,6 +317,7 @@ mod tests {
279
317
is_column_nullable(
280
318
"id" ,
281
319
"foo" ,
320
+ false ,
282
321
"select * from foo where id is not null or id is not null and 1=1" ,
283
322
) ,
284
323
Some ( NullableResult :: NotNull )
@@ -288,13 +327,19 @@ mod tests {
288
327
#[ test]
289
328
fn support_parens ( ) {
290
329
assert_eq ! (
291
- is_column_nullable( "id" , "foo" , "select * from foo f where (id not null)" , ) ,
330
+ is_column_nullable(
331
+ "id" ,
332
+ "foo" ,
333
+ false ,
334
+ "select * from foo f where (id not null)" ,
335
+ ) ,
292
336
Some ( NullableResult :: NotNull )
293
337
) ;
294
338
assert_eq ! (
295
339
is_column_nullable(
296
340
"id" ,
297
341
"foo" ,
342
+ false ,
298
343
"select * from foo f where (id is null) or (id is null)" ,
299
344
) ,
300
345
Some ( NullableResult :: Null )
@@ -303,6 +348,7 @@ mod tests {
303
348
is_column_nullable(
304
349
"id" ,
305
350
"foo" ,
351
+ false ,
306
352
"select * from foo f where (id is null) and (id is null)" ,
307
353
) ,
308
354
Some ( NullableResult :: Null )
@@ -312,7 +358,7 @@ mod tests {
312
358
#[ test]
313
359
fn support_is_null ( ) {
314
360
assert_eq ! (
315
- is_column_nullable( "id" , "foo" , "select * from foo f where id is null" , ) ,
361
+ is_column_nullable( "id" , "foo" , false , "select * from foo f where id is null" , ) ,
316
362
Some ( NullableResult :: Null )
317
363
) ;
318
364
}
@@ -323,6 +369,7 @@ mod tests {
323
369
is_column_nullable(
324
370
"id" ,
325
371
"bar" ,
372
+ false ,
326
373
"select * from foo join bar where bar.id is null"
327
374
) ,
328
375
Some ( NullableResult :: Null )
@@ -331,33 +378,44 @@ mod tests {
331
378
is_column_nullable(
332
379
"id" ,
333
380
"bar" ,
381
+ false ,
334
382
"select * from foo join bar b where b.id is null"
335
383
) ,
336
384
Some ( NullableResult :: Null )
337
385
) ;
338
386
assert_eq ! (
339
- is_column_nullable( "id" , "bar" , "select * from foo, bar b where b.id is null" ) ,
387
+ is_column_nullable(
388
+ "id" ,
389
+ "bar" ,
390
+ false ,
391
+ "select * from foo, bar b where b.id is null"
392
+ ) ,
340
393
Some ( NullableResult :: Null )
341
394
) ;
342
395
}
343
396
344
397
#[ test]
345
398
fn support_yoda_null_check ( ) {
346
399
assert_eq ! (
347
- is_column_nullable( "id" , "foo" , "select * from foo f where null is id" , ) ,
400
+ is_column_nullable( "id" , "foo" , false , "select * from foo f where null is id" , ) ,
348
401
Some ( NullableResult :: Null )
349
402
) ;
350
403
351
404
assert_eq ! (
352
- is_column_nullable( "id" , "foo" , "select * from foo f where null is not id" , ) ,
405
+ is_column_nullable(
406
+ "id" ,
407
+ "foo" ,
408
+ false ,
409
+ "select * from foo f where null is not id" ,
410
+ ) ,
353
411
Some ( NullableResult :: NotNull )
354
412
) ;
355
413
}
356
414
357
415
#[ test]
358
416
fn support_in_list ( ) {
359
417
assert_eq ! (
360
- is_column_nullable( "id" , "foo" , "select * from foo f where id in (:bar)" ) ,
418
+ is_column_nullable( "id" , "foo" , false , "select * from foo f where id in (:bar)" ) ,
361
419
Some ( NullableResult :: NotNull )
362
420
) ;
363
421
}
@@ -368,6 +426,7 @@ mod tests {
368
426
is_column_nullable(
369
427
"id" ,
370
428
"foo" ,
429
+ false ,
371
430
"SELECT foo.id FROM foo INNER JOIN bar ON bar.id = foo.id"
372
431
) ,
373
432
Some ( NullableResult :: NotNull )
@@ -377,6 +436,7 @@ mod tests {
377
436
is_column_nullable(
378
437
"id" ,
379
438
"bar" ,
439
+ false ,
380
440
"SELECT foo.id FROM foo INNER JOIN bar ON bar.id = foo.id"
381
441
) ,
382
442
Some ( NullableResult :: NotNull )
@@ -386,52 +446,92 @@ mod tests {
386
446
#[ test]
387
447
fn support_like_operator ( ) {
388
448
assert_eq ! (
389
- is_column_nullable( "id" , "foo" , "select * from foo f where id like ?" ) ,
449
+ is_column_nullable( "id" , "foo" , false , "select * from foo f where id like ?" ) ,
390
450
Some ( NullableResult :: NotNull )
391
451
) ;
392
452
assert_eq ! (
393
- is_column_nullable( "id" , "foo" , "select * from foo f where id not like ?" ) ,
453
+ is_column_nullable(
454
+ "id" ,
455
+ "foo" ,
456
+ false ,
457
+ "select * from foo f where id not like ?"
458
+ ) ,
394
459
Some ( NullableResult :: NotNull )
395
460
) ;
396
461
assert_eq ! (
397
- is_column_nullable( "id" , "foo" , "select * from foo f where ? like id" ) ,
462
+ is_column_nullable( "id" , "foo" , false , "select * from foo f where ? like id" ) ,
398
463
Some ( NullableResult :: NotNull )
399
464
) ;
400
465
assert_eq ! (
401
- is_column_nullable( "id" , "foo" , "select * from foo f where ? not like id" ) ,
466
+ is_column_nullable(
467
+ "id" ,
468
+ "foo" ,
469
+ false ,
470
+ "select * from foo f where ? not like id"
471
+ ) ,
402
472
Some ( NullableResult :: NotNull )
403
473
) ;
404
474
}
405
475
406
476
#[ test]
407
477
fn support_quoted_names ( ) {
408
478
assert_eq ! (
409
- is_column_nullable( "id" , "foo" , "SELECT id FROM \" foo\" WHERE id = ?" ) ,
479
+ is_column_nullable( "id" , "foo" , false , "SELECT id FROM \" foo\" WHERE id = ?" ) ,
410
480
Some ( NullableResult :: NotNull )
411
481
) ;
412
482
assert_eq ! (
413
- is_column_nullable( "id" , "foo" , "SELECT id FROM \" foo\" WHERE \" foo\" .id = ?" ) ,
483
+ is_column_nullable(
484
+ "id" ,
485
+ "foo" ,
486
+ false ,
487
+ "SELECT id FROM \" foo\" WHERE \" foo\" .id = ?"
488
+ ) ,
414
489
Some ( NullableResult :: NotNull )
415
490
) ;
416
491
assert_eq ! (
417
- is_column_nullable( "id" , "foo" , "SELECT id FROM foo WHERE \" id\" = ?" ) ,
492
+ is_column_nullable( "id" , "foo" , false , "SELECT id FROM foo WHERE \" id\" = ?" ) ,
418
493
Some ( NullableResult :: NotNull )
419
494
) ;
420
495
}
421
496
422
497
#[ test]
423
498
fn support_uppercase_names ( ) {
424
499
assert_eq ! (
425
- is_column_nullable( "id" , "foo" , "SELECT id FROM FOO WHERE id = ?" ) ,
500
+ is_column_nullable( "id" , "foo" , false , "SELECT id FROM FOO WHERE id = ?" ) ,
501
+ Some ( NullableResult :: NotNull )
502
+ ) ;
503
+ assert_eq ! (
504
+ is_column_nullable(
505
+ "id" ,
506
+ "bar" ,
507
+ false ,
508
+ "SELECT id FROM foo, BAR WHERE bar.id = ?"
509
+ ) ,
426
510
Some ( NullableResult :: NotNull )
427
511
) ;
428
512
assert_eq ! (
429
- is_column_nullable( "id" , "bar" , "SELECT id FROM foo, BAR WHERE bar.id = ?" ) ,
513
+ is_column_nullable( "id" , "bar" , false , "SELECT id FROM foo, bar WHERE ID = ?" ) ,
430
514
Some ( NullableResult :: NotNull )
431
515
) ;
516
+ }
517
+
518
+ #[ test]
519
+ fn check_if_not_null_column_is_always_present ( ) {
432
520
assert_eq ! (
433
- is_column_nullable( "id" , "bar " , "SELECT id FROM foo, bar WHERE ID = ? ") ,
521
+ is_column_nullable( "id" , "foo " , true , "select * from foo ") ,
434
522
Some ( NullableResult :: NotNull )
435
523
) ;
524
+ assert_eq ! (
525
+ is_column_nullable( "id" , "bar" , true , "select * from foo, bar" ) ,
526
+ Some ( NullableResult :: NotNull )
527
+ ) ;
528
+ assert_eq ! (
529
+ is_column_nullable( "id" , "bar" , true , "select * from foo join bar" ) ,
530
+ Some ( NullableResult :: NotNull )
531
+ ) ;
532
+ assert_eq ! (
533
+ is_column_nullable( "id" , "bar" , true , "select * from foo left join bar" ) ,
534
+ None
535
+ ) ;
436
536
}
437
537
}
0 commit comments