Skip to content

Commit 5551b9a

Browse files
authored
Merge pull request walkframe#37 from walkframe/condition
pict constraints
2 parents 2e66202 + 7d37688 commit 5551b9a

File tree

5 files changed

+635
-5
lines changed

5 files changed

+635
-5
lines changed

typescript/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

typescript/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "covertable",
3-
"version": "2.2.6",
3+
"version": "2.3.0-alpha.0",
44
"description": "A flexible pairwise tool written in TypeScript",
55
"homepage": "https://github.com/walkframe/covertable",
66
"repository": {
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
import { PictConstraintsLexer } from "../utils/pict";
2+
3+
describe('PictConstraintsLexer with single constraints', () => {
4+
it('should filter correctly with LIKE and IN conditions', () => {
5+
const lexer = new PictConstraintsLexer(`
6+
IF [NAME] LIKE "Alic?" THEN [STATUS] IN {"Active", "Pending"} ELSE [AGE] > 20 OR [COUNTRY] = "USA";
7+
`, false);
8+
const row1 = { NAME: 'Alice', STATUS: 'Active' };
9+
expect(lexer.filter(row1)).toBe(true);
10+
11+
const row2 = { NAME: 'Alice', STATUS: 'Inactive' };
12+
expect(lexer.filter(row2)).toBe(false);
13+
});
14+
15+
it('should filter correctly with numeric conditions', () => {
16+
const lexer = new PictConstraintsLexer(`
17+
IF [PRICE] > 100 THEN [DISCOUNT] = "YES" ELSE [DISCOUNT] = "NO";
18+
`, false);
19+
const row1 = { PRICE: 150, DISCOUNT: 'YES' };
20+
expect(lexer.filter(row1)).toBe(true);
21+
22+
const row2 = { PRICE: 90, DISCOUNT: 'NO' };
23+
expect(lexer.filter(row2)).toBe(true);
24+
25+
const row3 = { PRICE: 90, DISCOUNT: 'YES' };
26+
expect(lexer.filter(row3)).toBe(false);
27+
});
28+
29+
it('should handle NOT conditions correctly', () => {
30+
const lexer = new PictConstraintsLexer(`
31+
IF NOT [PRODUCT] = "Book" THEN [AVAILABLE] = "Yes" ELSE [AVAILABLE] = "No";
32+
`, false);
33+
const row1 = { PRODUCT: 'Pen', AVAILABLE: 'Yes' };
34+
expect(lexer.filter(row1)).toBe(true);
35+
36+
const row2 = { PRODUCT: 'Book', AVAILABLE: 'No' };
37+
expect(lexer.filter(row2)).toBe(true);
38+
39+
const row3 = { PRODUCT: 'Pen', AVAILABLE: 'No' };
40+
expect(lexer.filter(row3)).toBe(false);
41+
});
42+
43+
it('should filter with AND conditions', () => {
44+
const lexer = new PictConstraintsLexer(`
45+
IF [CATEGORY] = "Electronics" AND [BRAND] = "Sony" THEN [WARRANTY] = "Included" ELSE [WARRANTY] = "Not Included";
46+
`, false);
47+
const row1 = { CATEGORY: 'Electronics', BRAND: 'Sony', WARRANTY: 'Included' };
48+
expect(lexer.filter(row1)).toBe(true);
49+
50+
const row2 = { CATEGORY: 'Electronics', BRAND: 'Samsung', WARRANTY: 'Not Included' };
51+
expect(lexer.filter(row2)).toBe(true);
52+
53+
const row3 = { CATEGORY: 'Electronics', BRAND: 'Sony', WARRANTY: 'Not Included' };
54+
expect(lexer.filter(row3)).toBe(false);
55+
});
56+
57+
it('should handle nested conditions with parentheses', () => {
58+
const lexer = new PictConstraintsLexer(`
59+
IF ([CATEGORY] = "Electronics" AND [BRAND] = "Sony") OR [BRAND] = "Apple" THEN [WARRANTY] = "Included" ELSE [WARRANTY] = "Not Included";
60+
`, false);
61+
const row1 = { CATEGORY: 'Electronics', BRAND: 'Sony', WARRANTY: 'Included' };
62+
expect(lexer.filter(row1)).toBe(true);
63+
64+
const row2 = { CATEGORY: 'Electronics', BRAND: 'Apple', WARRANTY: 'Included' };
65+
expect(lexer.filter(row2)).toBe(true);
66+
67+
const row3 = { CATEGORY: 'Furniture', BRAND: 'IKEA', WARRANTY: 'Not Included' };
68+
expect(lexer.filter(row3)).toBe(true);
69+
70+
const row4 = { CATEGORY: 'Electronics', BRAND: 'Samsung', WARRANTY: 'Included' };
71+
expect(lexer.filter(row4)).toBe(false);
72+
});
73+
74+
it('should handle string equality conditions', () => {
75+
const lexer = new PictConstraintsLexer(`
76+
IF [NAME] = "Bob" THEN [STATUS] = "Inactive" ELSE [STATUS] = "Active";
77+
`, false);
78+
const row1 = { NAME: 'Bob', STATUS: 'Inactive' };
79+
expect(lexer.filter(row1)).toBe(true);
80+
81+
const row2 = { NAME: 'Alice', STATUS: 'Active' };
82+
expect(lexer.filter(row2)).toBe(true);
83+
84+
const row3 = { NAME: 'Bob', STATUS: 'Active' };
85+
expect(lexer.filter(row3)).toBe(false);
86+
});
87+
88+
it('should handle IN conditions', () => {
89+
const lexer = new PictConstraintsLexer(`
90+
IF [COLOR] IN {"Red", "Blue", "Green"} THEN [CATEGORY] = "Primary" ELSE [CATEGORY] = "Secondary";
91+
`, false);
92+
const row1 = { COLOR: 'Red', CATEGORY: 'Primary' };
93+
expect(lexer.filter(row1)).toBe(true);
94+
95+
const row2 = { COLOR: 'Yellow', CATEGORY: 'Secondary' };
96+
expect(lexer.filter(row2)).toBe(true);
97+
98+
const row3 = { COLOR: 'Red', CATEGORY: 'Secondary' };
99+
expect(lexer.filter(row3)).toBe(false);
100+
});
101+
102+
it('should handle complex conditions with nested parentheses', () => {
103+
const lexer = new PictConstraintsLexer(`
104+
IF ([AGE] > 20 AND ([COUNTRY] = "USA" OR [COUNTRY] = "Canada")) THEN [STATUS] = "Allowed" ELSE [STATUS] = "Denied";
105+
`, false);
106+
const row1 = { AGE: 25, COUNTRY: 'USA', STATUS: 'Allowed' };
107+
expect(lexer.filter(row1)).toBe(true);
108+
109+
const row2 = { AGE: 18, COUNTRY: 'USA', STATUS: 'Denied' };
110+
expect(lexer.filter(row2)).toBe(true);
111+
112+
const row3 = { AGE: 25, COUNTRY: 'UK', STATUS: 'Denied' };
113+
expect(lexer.filter(row3)).toBe(true);
114+
115+
const row4 = { AGE: 25, COUNTRY: 'Canada', STATUS: 'Allowed' };
116+
expect(lexer.filter(row4)).toBe(true);
117+
118+
const row5 = { AGE: 25, COUNTRY: 'Canada', STATUS: 'Denied' };
119+
expect(lexer.filter(row5)).toBe(false);
120+
});
121+
});
122+
123+
describe('PictConstraintsLexer with multiple constraints', () => {
124+
it('should handle multiple constraints correctly (Test Case 1)', () => {
125+
const lexer = new PictConstraintsLexer(`
126+
IF [NAME] = "Alice" THEN [AGE] > 20 ELSE [AGE] < 20;
127+
IF [COUNTRY] = "USA" THEN [STATUS] = "Active" ELSE [STATUS] = "Inactive";
128+
`, false);
129+
130+
const row1 = { NAME: 'Alice', AGE: 25, COUNTRY: 'USA', STATUS: 'Active' };
131+
expect(lexer.filter(row1)).toBe(true);
132+
133+
const row2 = { NAME: 'Alice', AGE: 25, COUNTRY: 'Canada', STATUS: 'Inactive' };
134+
expect(lexer.filter(row2)).toBe(true);
135+
136+
const row3 = { NAME: 'Alice', AGE: 18, COUNTRY: 'USA', STATUS: 'Active' };
137+
expect(lexer.filter(row3)).toBe(false);
138+
139+
const row4 = { NAME: 'Bob', AGE: 15, COUNTRY: 'USA', STATUS: 'Inactive' };
140+
expect(lexer.filter(row4)).toBe(false);
141+
});
142+
143+
it('should handle multiple constraints correctly (Test Case 2)', () => {
144+
const lexer = new PictConstraintsLexer(`
145+
IF [SCORE] >= 90 THEN [GRADE] = "A" ELSE [GRADE] = "B";
146+
IF [MEMBER] = "YES" THEN [DISCOUNT] = "20%" ELSE [DISCOUNT] = "10%";
147+
`, false);
148+
149+
const row1 = { SCORE: 95, GRADE: 'A', MEMBER: 'YES', DISCOUNT: '20%' };
150+
expect(lexer.filter(row1)).toBe(true);
151+
152+
const row2 = { SCORE: 85, GRADE: 'B', MEMBER: 'NO', DISCOUNT: '10%' };
153+
expect(lexer.filter(row2)).toBe(true);
154+
155+
const row3 = { SCORE: 85, GRADE: 'B', MEMBER: 'YES', DISCOUNT: '20%' };
156+
expect(lexer.filter(row3)).toBe(true);
157+
158+
const row4 = { SCORE: 85, GRADE: 'A', MEMBER: 'YES', DISCOUNT: '10%' };
159+
expect(lexer.filter(row4)).toBe(false);
160+
});
161+
162+
it('should handle multiple constraints correctly (Test Case 3)', () => {
163+
const lexer = new PictConstraintsLexer(`
164+
IF [TEMP] > 30 THEN [STATE] = "HOT" ELSE [STATE] = "COLD";
165+
IF [HUMIDITY] < 50 THEN [COMFORT] = "DRY" ELSE [COMFORT] = "HUMID";
166+
`, false);
167+
168+
const row1 = { TEMP: 35, STATE: 'HOT', HUMIDITY: 45, COMFORT: 'DRY' };
169+
expect(lexer.filter(row1)).toBe(true);
170+
171+
const row2 = { TEMP: 25, STATE: 'COLD', HUMIDITY: 55, COMFORT: 'HUMID' };
172+
expect(lexer.filter(row2)).toBe(true);
173+
174+
const row3 = { TEMP: 25, STATE: 'HOT', HUMIDITY: 55, COMFORT: 'DRY' };
175+
expect(lexer.filter(row3)).toBe(false);
176+
177+
const row4 = { TEMP: 35, STATE: 'HOT', HUMIDITY: 55, COMFORT: 'HUMID' };
178+
expect(lexer.filter(row4)).toBe(true);
179+
});
180+
181+
it('should handle multiple constraints correctly (Test Case 4)', () => {
182+
const lexer = new PictConstraintsLexer(`
183+
IF [CATEGORY] = "Electronics" THEN [WARRANTY] = "Included" ELSE [WARRANTY] = "Not Included";
184+
IF [PRICE] > 100 THEN [DISCOUNT] = "YES" ELSE [DISCOUNT] = "NO";
185+
`, false);
186+
187+
const row1 = { CATEGORY: 'Electronics', WARRANTY: 'Included', PRICE: 150, DISCOUNT: 'YES' };
188+
expect(lexer.filter(row1)).toBe(true);
189+
190+
const row2 = { CATEGORY: 'Furniture', WARRANTY: 'Not Included', PRICE: 90, DISCOUNT: 'NO' };
191+
expect(lexer.filter(row2)).toBe(true);
192+
193+
const row3 = { CATEGORY: 'Electronics', WARRANTY: 'Not Included', PRICE: 150, DISCOUNT: 'NO' };
194+
expect(lexer.filter(row3)).toBe(false);
195+
196+
const row4 = { CATEGORY: 'Furniture', WARRANTY: 'Not Included', PRICE: 150, DISCOUNT: 'YES' };
197+
expect(lexer.filter(row4)).toBe(true);
198+
});
199+
200+
it('should handle multiple constraints correctly (Test Case 5)', () => {
201+
const lexer = new PictConstraintsLexer(`
202+
IF [COLOR] = "Red" THEN [CATEGORY] = "Primary" ELSE [CATEGORY] = "Secondary";
203+
IF [QUANTITY] < 10 THEN [STOCK] = "Low" ELSE [STOCK] = "High";
204+
`, false);
205+
206+
const row1 = { COLOR: 'Red', CATEGORY: 'Primary', QUANTITY: 5, STOCK: 'Low' };
207+
expect(lexer.filter(row1)).toBe(true);
208+
209+
const row2 = { COLOR: 'Blue', CATEGORY: 'Secondary', QUANTITY: 20, STOCK: 'High' };
210+
expect(lexer.filter(row2)).toBe(true);
211+
212+
const row3 = { COLOR: 'Red', CATEGORY: 'Secondary', QUANTITY: 5, STOCK: 'High' };
213+
expect(lexer.filter(row3)).toBe(false);
214+
215+
const row4 = { COLOR: 'Red', CATEGORY: 'Primary', QUANTITY: 20, STOCK: 'High' };
216+
expect(lexer.filter(row4)).toBe(true);
217+
});
218+
219+
it('should handle multiple constraints correctly (Test Case 6)', () => {
220+
const lexer = new PictConstraintsLexer(`
221+
IF [SIZE] = "Large" THEN [AVAILABILITY] = "In Stock" ELSE [AVAILABILITY] = "Out of Stock";
222+
IF ([DISCOUNT] = "YES" AND [MEMBER] = "YES") THEN [PRICE] < 100 ELSE [PRICE] >= 100;
223+
`, false);
224+
225+
const row1 = { SIZE: 'Large', AVAILABILITY: 'In Stock', DISCOUNT: 'YES', MEMBER: 'YES', PRICE: 90 };
226+
expect(lexer.filter(row1)).toBe(true);
227+
228+
const row2 = { SIZE: 'Medium', AVAILABILITY: 'Out of Stock', DISCOUNT: 'NO', MEMBER: 'NO', PRICE: 120 };
229+
expect(lexer.filter(row2)).toBe(true);
230+
231+
const row3 = { SIZE: 'Large', AVAILABILITY: 'In Stock', DISCOUNT: 'YES', MEMBER: 'NO', PRICE: 110 };
232+
expect(lexer.filter(row3)).toBe(true);
233+
});
234+
235+
it('should handle multiple constraints correctly (Test Case 7)', () => {
236+
const lexer = new PictConstraintsLexer(`
237+
IF [SEASON] = "Winter" THEN [CLOTHING] = "Coat" ELSE [CLOTHING] = "Shirt";
238+
IF ([TEMP] < 0 AND [WEATHER] = "Snowy") THEN [ACTIVITY] = "Skiing" ELSE [ACTIVITY] = "Running";
239+
`, false);
240+
241+
const row1 = { SEASON: 'Winter', CLOTHING: 'Coat', TEMP: -5, WEATHER: 'Snowy', ACTIVITY: 'Skiing' };
242+
expect(lexer.filter(row1)).toBe(true);
243+
244+
const row2 = { SEASON: 'Summer', CLOTHING: 'Shirt', TEMP: 25, WEATHER: 'Sunny', ACTIVITY: 'Running' };
245+
expect(lexer.filter(row2)).toBe(true);
246+
247+
const row3 = { SEASON: 'Winter', CLOTHING: 'Coat', TEMP: 5, WEATHER: 'Sunny', ACTIVITY: 'Running' };
248+
expect(lexer.filter(row3)).toBe(true);
249+
});
250+
});

typescript/src/types.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ export type MappingTypes = {
1212
indices: IndicesType;
1313
};
1414

15-
export type FilterType = (row: {
15+
export type FilterRowType = {
1616
[key: string]: any;
1717
[index: number]: any;
18-
}) => boolean;
18+
}
19+
20+
export type FilterType = (row: FilterRowType) => boolean;
1921

2022
export type PairType = number[];
2123

0 commit comments

Comments
 (0)