search-input-query-parser 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,7 @@ import {
7
7
  stringify,
8
8
  ValidationError,
9
9
  FieldSchema,
10
+ SearchQueryErrorCode,
10
11
  } from "./parser";
11
12
 
12
13
  describe("Search Query Parser", () => {
@@ -103,6 +104,7 @@ describe("Search Query Parser", () => {
103
104
  {
104
105
  length: 6,
105
106
  message: "Expected field value",
107
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
106
108
  position: 0,
107
109
  },
108
110
  ]);
@@ -111,6 +113,7 @@ describe("Search Query Parser", () => {
111
113
  {
112
114
  length: 6,
113
115
  message: "Expected field value",
116
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
114
117
  position: 0,
115
118
  },
116
119
  ]);
@@ -119,6 +122,7 @@ describe("Search Query Parser", () => {
119
122
  {
120
123
  length: 1,
121
124
  message: "Expected field value",
125
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
122
126
  position: 6,
123
127
  },
124
128
  ]);
@@ -128,6 +132,7 @@ describe("Search Query Parser", () => {
128
132
  {
129
133
  length: 6,
130
134
  message: "Expected field value",
135
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
131
136
  position: 0,
132
137
  },
133
138
  ]);
@@ -136,6 +141,7 @@ describe("Search Query Parser", () => {
136
141
  {
137
142
  length: 15,
138
143
  message: "Missing field name",
144
+ code: SearchQueryErrorCode.MISSING_FIELD_NAME,
139
145
  position: 6,
140
146
  },
141
147
  ]);
@@ -437,6 +443,7 @@ describe("Search Query Parser", () => {
437
443
  {
438
444
  length: 6,
439
445
  message: "Expected field value",
446
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
440
447
  position: 0,
441
448
  },
442
449
  ]);
@@ -444,6 +451,7 @@ describe("Search Query Parser", () => {
444
451
  {
445
452
  length: 6,
446
453
  message: "Missing field name",
454
+ code: SearchQueryErrorCode.MISSING_FIELD_NAME,
447
455
  position: 0,
448
456
  },
449
457
  ]);
@@ -451,6 +459,7 @@ describe("Search Query Parser", () => {
451
459
  {
452
460
  length: 1,
453
461
  message: "Expected field value",
462
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
454
463
  position: 0,
455
464
  },
456
465
  ]);
@@ -458,11 +467,13 @@ describe("Search Query Parser", () => {
458
467
  {
459
468
  length: 6,
460
469
  message: "Expected field value",
470
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
461
471
  position: 0,
462
472
  },
463
473
  {
464
474
  length: 1,
465
475
  message: "Expected field value",
476
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
466
477
  position: 6,
467
478
  },
468
479
  ]);
@@ -473,6 +484,8 @@ describe("Search Query Parser", () => {
473
484
  {
474
485
  length: 3,
475
486
  message: "AND is a reserved word",
487
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
488
+ value: "AND",
476
489
  position: 0,
477
490
  },
478
491
  ]);
@@ -480,6 +493,8 @@ describe("Search Query Parser", () => {
480
493
  {
481
494
  length: 2,
482
495
  message: "OR is a reserved word",
496
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
497
+ value: "OR",
483
498
  position: 0,
484
499
  },
485
500
  ]);
@@ -490,6 +505,7 @@ describe("Search Query Parser", () => {
490
505
  {
491
506
  length: 1,
492
507
  message: 'Unexpected ")"',
508
+ code: SearchQueryErrorCode.UNEXPECTED_RIGHT_PAREN,
493
509
  position: 1,
494
510
  },
495
511
  ]);
@@ -497,6 +513,7 @@ describe("Search Query Parser", () => {
497
513
  {
498
514
  length: 1,
499
515
  message: 'Unexpected ")"',
516
+ code: SearchQueryErrorCode.UNEXPECTED_RIGHT_PAREN,
500
517
  position: 6,
501
518
  },
502
519
  ]);
@@ -507,6 +524,7 @@ describe("Search Query Parser", () => {
507
524
  {
508
525
  length: 6,
509
526
  message: "Unterminated quoted string",
527
+ code: SearchQueryErrorCode.UNTERMINATED_QUOTED_STRING,
510
528
  position: 6,
511
529
  },
512
530
  ]);
@@ -514,6 +532,7 @@ describe("Search Query Parser", () => {
514
532
  {
515
533
  length: 7,
516
534
  message: "Unterminated quoted string",
535
+ code: SearchQueryErrorCode.UNTERMINATED_QUOTED_STRING,
517
536
  position: 6,
518
537
  },
519
538
  ]);
@@ -521,6 +540,7 @@ describe("Search Query Parser", () => {
521
540
  {
522
541
  length: 8,
523
542
  message: "Unterminated quoted string",
543
+ code: SearchQueryErrorCode.UNTERMINATED_QUOTED_STRING,
524
544
  position: 6,
525
545
  },
526
546
  ]);
@@ -528,6 +548,7 @@ describe("Search Query Parser", () => {
528
548
  {
529
549
  length: 16,
530
550
  message: "Unterminated quoted string",
551
+ code: SearchQueryErrorCode.UNTERMINATED_QUOTED_STRING,
531
552
  position: 0,
532
553
  },
533
554
  ]);
@@ -538,6 +559,8 @@ describe("Search Query Parser", () => {
538
559
  {
539
560
  length: 3,
540
561
  message: "AND is a reserved word",
562
+ code: SearchQueryErrorCode.RESERVED_WORD,
563
+ value: "AND",
541
564
  position: 0,
542
565
  },
543
566
  ]);
@@ -545,6 +568,8 @@ describe("Search Query Parser", () => {
545
568
  {
546
569
  length: 2,
547
570
  message: "OR is a reserved word",
571
+ code: SearchQueryErrorCode.RESERVED_WORD,
572
+ value: "OR",
548
573
  position: 0,
549
574
  },
550
575
  ]);
@@ -552,6 +577,8 @@ describe("Search Query Parser", () => {
552
577
  {
553
578
  length: 3,
554
579
  message: "Unexpected token: AND",
580
+ code: SearchQueryErrorCode.UNEXPECTED_TOKEN,
581
+ value: "AND",
555
582
  position: 5,
556
583
  },
557
584
  ]);
@@ -559,6 +586,8 @@ describe("Search Query Parser", () => {
559
586
  {
560
587
  length: 2,
561
588
  message: "Unexpected token: OR",
589
+ code: SearchQueryErrorCode.UNEXPECTED_TOKEN,
590
+ value: "OR",
562
591
  position: 5,
563
592
  },
564
593
  ]);
@@ -566,6 +595,8 @@ describe("Search Query Parser", () => {
566
595
  {
567
596
  length: 3,
568
597
  message: "AND is a reserved word",
598
+ code: SearchQueryErrorCode.RESERVED_WORD,
599
+ value: "AND",
569
600
  position: 0,
570
601
  },
571
602
  ]);
@@ -573,6 +604,8 @@ describe("Search Query Parser", () => {
573
604
  {
574
605
  length: 2,
575
606
  message: "OR is a reserved word",
607
+ code: SearchQueryErrorCode.RESERVED_WORD,
608
+ value: "OR",
576
609
  position: 0,
577
610
  },
578
611
  ]);
@@ -585,16 +618,19 @@ describe("Search Query Parser", () => {
585
618
  {
586
619
  length: 6,
587
620
  message: "Expected field value",
621
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
588
622
  position: 29,
589
623
  },
590
624
  {
591
625
  length: 6,
592
626
  message: "Expected field value",
627
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
593
628
  position: 39,
594
629
  },
595
630
  {
596
631
  length: 5,
597
632
  message: "Expected field value",
633
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
598
634
  position: 51,
599
635
  },
600
636
  ]
@@ -605,6 +641,8 @@ describe("Search Query Parser", () => {
605
641
  {
606
642
  length: 3,
607
643
  message: "AND is a reserved word",
644
+ code: SearchQueryErrorCode.RESERVED_WORD,
645
+ value: "AND",
608
646
  position: 61,
609
647
  },
610
648
  ]
@@ -615,6 +653,7 @@ describe("Search Query Parser", () => {
615
653
  testSchemaErrorQuery("amount:>", [
616
654
  {
617
655
  message: "Expected range value",
656
+ code: SearchQueryErrorCode.EXPECTED_RANGE_VALUE,
618
657
  position: 8,
619
658
  length: 0,
620
659
  },
@@ -623,6 +662,7 @@ describe("Search Query Parser", () => {
623
662
  testSchemaErrorQuery("price:>=>100", [
624
663
  {
625
664
  message: "Invalid range operator",
665
+ code: SearchQueryErrorCode.INVALID_RANGE_OPERATOR,
626
666
  position: 6,
627
667
  length: 3,
628
668
  },
@@ -631,6 +671,7 @@ describe("Search Query Parser", () => {
631
671
  testSchemaErrorQuery("price:>..", [
632
672
  {
633
673
  message: "Invalid numeric value",
674
+ code: SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
634
675
  position: 6,
635
676
  length: 1,
636
677
  },
@@ -639,6 +680,7 @@ describe("Search Query Parser", () => {
639
680
  testSchemaErrorQuery("price:...", [
640
681
  {
641
682
  message: "Invalid range format",
683
+ code: SearchQueryErrorCode.INVALID_RANGE_FORMAT,
642
684
  position: 6,
643
685
  length: 3,
644
686
  },
@@ -647,6 +689,7 @@ describe("Search Query Parser", () => {
647
689
  testSchemaErrorQuery("price:100...", [
648
690
  {
649
691
  message: "Invalid range format",
692
+ code: SearchQueryErrorCode.INVALID_RANGE_FORMAT,
650
693
  position: 6,
651
694
  length: 6,
652
695
  },
@@ -655,6 +698,7 @@ describe("Search Query Parser", () => {
655
698
  testSchemaErrorQuery("price:...200", [
656
699
  {
657
700
  message: "Invalid range format",
701
+ code: SearchQueryErrorCode.INVALID_RANGE_FORMAT,
658
702
  position: 6,
659
703
  length: 6,
660
704
  },
@@ -665,11 +709,13 @@ describe("Search Query Parser", () => {
665
709
  testSchemaErrorQuery("price:abc..def", [
666
710
  {
667
711
  message: "Invalid numeric value",
712
+ code: SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
668
713
  position: 6,
669
714
  length: 3,
670
715
  },
671
716
  {
672
717
  message: "Invalid numeric value",
718
+ code: SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
673
719
  position: 11,
674
720
  length: 3,
675
721
  },
@@ -678,6 +724,7 @@ describe("Search Query Parser", () => {
678
724
  testSchemaErrorQuery("amount:>abc", [
679
725
  {
680
726
  message: "Invalid numeric value",
727
+ code: SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
681
728
  position: 8,
682
729
  length: 3,
683
730
  },
@@ -688,6 +735,7 @@ describe("Search Query Parser", () => {
688
735
  testSchemaErrorQuery("date:>not-a-date", [
689
736
  {
690
737
  message: "Invalid date format",
738
+ code: SearchQueryErrorCode.INVALID_DATE_FORMAT,
691
739
  position: 5,
692
740
  length: 11,
693
741
  },
@@ -696,6 +744,7 @@ describe("Search Query Parser", () => {
696
744
  testSchemaErrorQuery("date:2024-13-01..2024-12-31", [
697
745
  {
698
746
  message: "Invalid date format",
747
+ code: SearchQueryErrorCode.INVALID_DATE_FORMAT,
699
748
  position: 5,
700
749
  length: 22,
701
750
  },
@@ -708,6 +757,7 @@ describe("Search Query Parser", () => {
708
757
  testErrorQuery("test*test", [
709
758
  {
710
759
  message: "Wildcard (*) can only appear at the end of a term",
760
+ code: SearchQueryErrorCode.INVALID_WILDCARD_POSITION,
711
761
  position: 4,
712
762
  length: 1,
713
763
  },
@@ -716,11 +766,13 @@ describe("Search Query Parser", () => {
716
766
  testErrorQuery("te*st*", [
717
767
  {
718
768
  message: "Wildcard (*) can only appear at the end of a term",
769
+ code: SearchQueryErrorCode.INVALID_WILDCARD_POSITION,
719
770
  position: 2,
720
771
  length: 1,
721
772
  },
722
773
  {
723
774
  message: "Only one trailing wildcard (*) is allowed",
775
+ code: SearchQueryErrorCode.MULTIPLE_WILDCARDS,
724
776
  position: 5,
725
777
  length: 1,
726
778
  },
@@ -731,6 +783,7 @@ describe("Search Query Parser", () => {
731
783
  testErrorQuery("test**", [
732
784
  {
733
785
  message: "Only one trailing wildcard (*) is allowed",
786
+ code: SearchQueryErrorCode.MULTIPLE_WILDCARDS,
734
787
  position: 5,
735
788
  length: 1,
736
789
  },
@@ -739,6 +792,7 @@ describe("Search Query Parser", () => {
739
792
  testErrorQuery('"test"**', [
740
793
  {
741
794
  message: "Only one trailing wildcard (*) is allowed",
795
+ code: SearchQueryErrorCode.MULTIPLE_WILDCARDS,
742
796
  position: 7,
743
797
  length: 1,
744
798
  },
@@ -747,6 +801,7 @@ describe("Search Query Parser", () => {
747
801
  testErrorQuery('field:"test"**', [
748
802
  {
749
803
  message: "Only one trailing wildcard (*) is allowed",
804
+ code: SearchQueryErrorCode.MULTIPLE_WILDCARDS,
750
805
  position: 13,
751
806
  length: 1,
752
807
  },
@@ -757,11 +812,13 @@ describe("Search Query Parser", () => {
757
812
  testErrorQuery("fie*ld:value", [
758
813
  {
759
814
  message: "Invalid characters in field name",
815
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
760
816
  position: 0,
761
817
  length: 6,
762
818
  },
763
819
  {
764
820
  message: "Wildcard (*) can only appear at the end of a term",
821
+ code: SearchQueryErrorCode.INVALID_WILDCARD_POSITION,
765
822
  position: 3,
766
823
  length: 1,
767
824
  },
@@ -770,11 +827,13 @@ describe("Search Query Parser", () => {
770
827
  testErrorQuery("field*:value", [
771
828
  {
772
829
  message: "Invalid characters in field name",
830
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
773
831
  position: 0,
774
832
  length: 6,
775
833
  },
776
834
  {
777
835
  message: "Wildcard (*) can only appear at the end of a term",
836
+ code: SearchQueryErrorCode.INVALID_WILDCARD_POSITION,
778
837
  position: 5,
779
838
  length: 1,
780
839
  },
@@ -783,11 +842,13 @@ describe("Search Query Parser", () => {
783
842
  testErrorQuery("f*:value", [
784
843
  {
785
844
  message: "Invalid characters in field name",
845
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
786
846
  position: 0,
787
847
  length: 2,
788
848
  },
789
849
  {
790
850
  message: "Wildcard (*) can only appear at the end of a term",
851
+ code: SearchQueryErrorCode.INVALID_WILDCARD_POSITION,
791
852
  position: 1,
792
853
  length: 1,
793
854
  },
@@ -798,11 +859,13 @@ describe("Search Query Parser", () => {
798
859
  testErrorQuery('field*:"test"', [
799
860
  {
800
861
  message: "Invalid characters in field name",
862
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
801
863
  position: 0,
802
864
  length: 6,
803
865
  },
804
866
  {
805
867
  message: "Wildcard (*) can only appear at the end of a term",
868
+ code: SearchQueryErrorCode.INVALID_WILDCARD_POSITION,
806
869
  position: 5,
807
870
  length: 1,
808
871
  },
@@ -811,6 +874,7 @@ describe("Search Query Parser", () => {
811
874
  testErrorQuery('field:"test * test"**', [
812
875
  {
813
876
  message: "Only one trailing wildcard (*) is allowed",
877
+ code: SearchQueryErrorCode.MULTIPLE_WILDCARDS,
814
878
  position: 20,
815
879
  length: 1,
816
880
  },
@@ -819,11 +883,13 @@ describe("Search Query Parser", () => {
819
883
  testErrorQuery("test* field*:value", [
820
884
  {
821
885
  message: "Invalid characters in field name",
886
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
822
887
  position: 6,
823
888
  length: 6,
824
889
  },
825
890
  {
826
891
  message: "Wildcard (*) can only appear at the end of a term",
892
+ code: SearchQueryErrorCode.INVALID_WILDCARD_POSITION,
827
893
  position: 11,
828
894
  length: 1,
829
895
  },
@@ -892,11 +958,13 @@ describe("Search Query Parser", () => {
892
958
  expect((invalidNumResult as SearchQueryError).errors).toStrictEqual([
893
959
  {
894
960
  message: "Invalid numeric value",
961
+ code: SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
895
962
  position: 9,
896
963
  length: 3,
897
964
  },
898
965
  {
899
966
  message: "Invalid numeric value",
967
+ code: SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
900
968
  position: 13,
901
969
  length: 3,
902
970
  },
@@ -931,6 +999,7 @@ describe("Search Query Parser", () => {
931
999
  testErrorQuery("status:IN()", [
932
1000
  {
933
1001
  message: "IN operator requires at least one value",
1002
+ code: SearchQueryErrorCode.EMPTY_IN_LIST,
934
1003
  position: 10,
935
1004
  length: 1,
936
1005
  },
@@ -941,6 +1010,7 @@ describe("Search Query Parser", () => {
941
1010
  testErrorQuery("status:IN(active,pending", [
942
1011
  {
943
1012
  message: "Expected ',' or ')' after IN value",
1013
+ code: SearchQueryErrorCode.EXPECTED_IN_SEPARATOR,
944
1014
  position: 5,
945
1015
  length: 1,
946
1016
  },
@@ -962,6 +1032,7 @@ describe("Search Query Parser", () => {
962
1032
  testErrorQuery("status:IN(active pending)", [
963
1033
  {
964
1034
  message: "Expected ',' or ')' after IN value",
1035
+ code: SearchQueryErrorCode.EXPECTED_IN_SEPARATOR,
965
1036
  position: 17,
966
1037
  length: 1,
967
1038
  },
@@ -972,6 +1043,7 @@ describe("Search Query Parser", () => {
972
1043
  testErrorQuery('status:IN("unclosed', [
973
1044
  {
974
1045
  message: "Unterminated quoted string",
1046
+ code: SearchQueryErrorCode.UNTERMINATED_QUOTED_STRING,
975
1047
  position: 10,
976
1048
  length: 10,
977
1049
  },
package/src/parser.ts CHANGED
@@ -4,7 +4,11 @@ import {
4
4
  PositionLength,
5
5
  WildcardPattern as FirstPassWildcard,
6
6
  } from "./first-pass-parser";
7
- import { validateSearchQuery, ValidationError } from "./validator";
7
+ import {
8
+ validateSearchQuery,
9
+ ValidationError,
10
+ SearchQueryErrorCode,
11
+ } from "./validator";
8
12
  import { validateExpressionFields } from "./validate-expression-fields";
9
13
  import { transformToExpression } from "./transform-to-expression";
10
14
 
@@ -142,6 +146,7 @@ export const parseSearchInputQuery = (
142
146
  if (finalToken.type !== TokenType.EOF) {
143
147
  throw {
144
148
  message: 'Unexpected ")"',
149
+ code: SearchQueryErrorCode.UNEXPECTED_RIGHT_PAREN,
145
150
  position: finalToken.position,
146
151
  length: finalToken.length,
147
152
  };
@@ -210,6 +215,7 @@ export {
210
215
  type SearchQueryError,
211
216
  type Expression,
212
217
  type ValidationError,
218
+ SearchQueryErrorCode,
213
219
  type FieldSchema,
214
220
  type RangeOperator,
215
221
  type RangeExpression,
@@ -1,6 +1,6 @@
1
1
  import { FieldSchema } from "./parser";
2
2
  import { FirstPassExpression } from "./first-pass-parser";
3
- import { ValidationError } from "./validator";
3
+ import { ValidationError, SearchQueryErrorCode } from "./validator";
4
4
 
5
5
  // Helper to validate numeric values
6
6
  const validateNumber = (
@@ -12,6 +12,7 @@ const validateNumber = (
12
12
  if (isNaN(Number(value))) {
13
13
  errors.push({
14
14
  message: "Invalid numeric value",
15
+ code: SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
15
16
  position,
16
17
  length: value.length,
17
18
  });
@@ -44,6 +45,7 @@ const validateNumericRange = (
44
45
  if (startNum > endNum) {
45
46
  errors.push({
46
47
  message: "Range start must be less than or equal to range end",
48
+ code: SearchQueryErrorCode.RANGE_START_GREATER_THAN_END,
47
49
  position: basePosition,
48
50
  length: start.length + 2 + end.length,
49
51
  });
@@ -77,6 +79,8 @@ const validateFieldValue = (
77
79
  if (!allowedFields.has(expr.field.toLowerCase())) {
78
80
  errors.push({
79
81
  message: `Invalid field: "${expr.field}"`,
82
+ code: SearchQueryErrorCode.INVALID_FIELD_NAME,
83
+ value: expr.field,
80
84
  position: expr.position,
81
85
  length: expr.field.length,
82
86
  });
@@ -91,6 +95,7 @@ const validateFieldValue = (
91
95
  if (isNaN(Number(value))) {
92
96
  errors.push({
93
97
  message: "Invalid numeric value",
98
+ code: SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
94
99
  position:
95
100
  expr.position +
96
101
  expr.field.length +
@@ -104,6 +109,7 @@ const validateFieldValue = (
104
109
  if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
105
110
  errors.push({
106
111
  message: "Invalid date format",
112
+ code: SearchQueryErrorCode.INVALID_DATE_FORMAT,
107
113
  position:
108
114
  expr.position +
109
115
  expr.field.length +
@@ -124,6 +130,8 @@ const validateFieldValue = (
124
130
  const schema = schemas.get(expr.prefix.toLowerCase());
125
131
  if (schema?.type === "number" || schema?.type === "date") {
126
132
  errors.push({
133
+ code: SearchQueryErrorCode.WILDCARD_NOT_ALLOWED,
134
+ value: schema.type,
127
135
  message: `Wildcards are not allowed for ${schema.type} fields`,
128
136
  position: expr.position,
129
137
  length: expr.length,
@@ -142,6 +150,8 @@ const validateFieldValue = (
142
150
  if (!allowedFields.has(fieldName.toLowerCase()) && colonIndex > 0) {
143
151
  errors.push({
144
152
  message: `Invalid field: "${fieldName}"`,
153
+ code: SearchQueryErrorCode.INVALID_FIELD_NAME,
154
+ value: fieldName,
145
155
  position: expr.position,
146
156
  length: colonIndex,
147
157
  });
@@ -150,6 +160,7 @@ const validateFieldValue = (
150
160
  if (!value) {
151
161
  errors.push({
152
162
  message: "Expected field value",
163
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
153
164
  position: expr.position,
154
165
  length: colonIndex + 1,
155
166
  });
@@ -159,6 +170,7 @@ const validateFieldValue = (
159
170
  if (value.startsWith(":")) {
160
171
  errors.push({
161
172
  message: "Missing field name",
173
+ code: SearchQueryErrorCode.MISSING_FIELD_NAME,
162
174
  position: expr.position,
163
175
  length: value.length + colonIndex + 1,
164
176
  });
@@ -175,6 +187,7 @@ const validateFieldValue = (
175
187
  if (value === ".." || value.includes("...")) {
176
188
  errors.push({
177
189
  message: "Invalid range format",
190
+ code: SearchQueryErrorCode.INVALID_RANGE_FORMAT,
178
191
  position: valueStartPosition,
179
192
  length: value.length,
180
193
  });
@@ -194,6 +207,7 @@ const validateFieldValue = (
194
207
  if (invalidOp.test(value)) {
195
208
  errors.push({
196
209
  message: "Invalid range operator",
210
+ code: SearchQueryErrorCode.INVALID_RANGE_OPERATOR,
197
211
  position: valueStartPosition,
198
212
  length: 3,
199
213
  });
@@ -203,6 +217,7 @@ const validateFieldValue = (
203
217
  if (!compValue) {
204
218
  errors.push({
205
219
  message: "Expected range value",
220
+ code: SearchQueryErrorCode.EXPECTED_RANGE_VALUE,
206
221
  position: valueStartPosition + operator.length,
207
222
  length: 0,
208
223
  });
@@ -240,6 +255,7 @@ const validateFieldValue = (
240
255
  if (!dateValidator(start) || !dateValidator(end)) {
241
256
  errors.push({
242
257
  message: "Invalid date format",
258
+ code: SearchQueryErrorCode.INVALID_DATE_FORMAT,
243
259
  position: valueStartPosition,
244
260
  length: value.length,
245
261
  });
@@ -252,6 +268,7 @@ const validateFieldValue = (
252
268
  if (!dateValidator(dateStr)) {
253
269
  errors.push({
254
270
  message: "Invalid date format",
271
+ code: SearchQueryErrorCode.INVALID_DATE_FORMAT,
255
272
  position: valueStartPosition,
256
273
  length: value.length,
257
274
  });
@@ -260,6 +277,7 @@ const validateFieldValue = (
260
277
  } else if (!dateValidator(value)) {
261
278
  errors.push({
262
279
  message: "Invalid date format",
280
+ code: SearchQueryErrorCode.INVALID_DATE_FORMAT,
263
281
  position: valueStartPosition,
264
282
  length: value.length,
265
283
  });
@@ -1,5 +1,5 @@
1
1
  import { InExpression } from "./first-pass-parser";
2
- import { ValidationError, reservedWords } from "./validator";
2
+ import { ValidationError, reservedWords, SearchQueryErrorCode } from "./validator";
3
3
 
4
4
  export const validateInExpression = (
5
5
  expr: InExpression,
@@ -9,6 +9,7 @@ export const validateInExpression = (
9
9
  if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(expr.field)) {
10
10
  errors.push({
11
11
  message: "Invalid characters in field name",
12
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
12
13
  position: expr.position,
13
14
  length: expr.field.length,
14
15
  });
@@ -18,6 +19,8 @@ export const validateInExpression = (
18
19
  if (reservedWords.has(expr.field.toUpperCase())) {
19
20
  errors.push({
20
21
  message: `${expr.field} is a reserved word`,
22
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
23
+ value: expr.field,
21
24
  position: expr.position,
22
25
  length: expr.field.length,
23
26
  });
@@ -28,6 +31,7 @@ export const validateInExpression = (
28
31
  if (value.includes(",")) {
29
32
  errors.push({
30
33
  message: "Invalid character in IN value",
34
+ code: SearchQueryErrorCode.INVALID_IN_VALUE,
31
35
  position: expr.position + expr.field.length + 3 + index * (value.length + 1),
32
36
  length: value.length,
33
37
  });