Skip to content

Add query rule filter linkage #152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: feature/rule-based-filtering
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 98 additions & 56 deletions lib/queryrules.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,70 @@
# Keywords = comma-separated list of search terms that trigger this rule
# Query = MongoDB query to execute when this rule is matched

# More specific color/feature rules first
# Specific fruit color rules
[BlueFruit]
Chip = Blue Berries/Fruit
Keywords = Blue Berries, Blue Fruit
Query = { "Fruit Color": "Blue" }
Filters = { "Fruit Color": ["Blue"] }

[RedFruit]
Chip = Red Berries/Fruit
Keywords = Red Berries, Red Fruit
Query = { "Fruit Color": "Red" }
Filters = { "Fruit Color": ["Red"] }

# Specific flower color rules
[BlueFlower]
Chip = Blue Flowers
Keywords = Blue, Blue Flower, Blue Flowers, Blue Blooms
Query = { "Flower Color Flags": { "$in": ["Blue"] } }
Filters = { "Flower Color Flags": ["Blue"] }

[RedFlower]
Chip = Red Flowers
Keywords = Red, Red Flower, Red Flowers, Red Blooms
Query = { "Flower Color Flags": { "$in": ["Red"] } }
Filters = { "Flower Color Flags": ["Red"] }

[YellowFlower]
Chip = Yellow Flowers
Keywords = Yellow, Yellow Flower, Yellow Flowers, Yellow Blooms
Query = { "Flower Color Flags": { "$in": ["Yellow"] } }
Filters = { "Flower Color Flags": ["Yellow"] }

[PurpleFlower]
Chip = Purple Flowers
Keywords = Purple, Purple Flower, Purple Flowers, Purple Blooms, Violet
Query = { "Flower Color Flags": { "$in": ["Purple"] } }
Filters = { "Flower Color Flags": ["Purple"] }

[WhiteFlower]
Chip = White Flowers
Keywords = White, White Flower, White Flowers, White Blooms
Query = { "Flower Color Flags": { "$in": ["White"] } }
Filters = { "Flower Color Flags": ["White"] }

[PinkFlower]
Chip = Pink Flowers
Keywords = Pink, Pink Flower, Pink Flowers, Pink Blooms
Query = { "Flower Color Flags": { "$in": ["Pink"] } }
Filters = { "Flower Color Flags": ["Pink"] }

[OrangeFlower]
Chip = Orange Flowers
Keywords = Orange, Orange Flower, Orange Flowers, Orange Blooms
Query = { "Flower Color Flags": { "$in": ["Orange"] } }
Filters = { "Flower Color Flags": ["Orange"] }

[GreenFlower]
Chip = Green Flowers
Keywords = Green, Green Flower, Green Flowers, Green Blooms
Query = { "Flower Color Flags": { "$in": ["Green"] } }
Filters = { "Flower Color Flags": ["Green"] }

# Native status rules
[NativeStatus_US]
Chip = Native to the Continental US
Keywords = Native, Native to USA, US Native, Lower 48, continental US
Expand All @@ -30,22 +94,26 @@ Query = { "Life Cycle Flags": { "$in": ["Biennial"] } }
[MonarchsCheck]
Chip = Supports Monarchs
Keywords = Monarch Butterfly, Monarchs, Monarch, Monarch Waystation
Query = { "Pollinator Flags": { "$in": ["Monarch Butterfly"] } }
Query = { "Pollinator Flags": { "$in": ["Monarchs", "Larval Host (Monarch)"] } }
Filters = { "Pollinator Flags": ["Monarchs"] }

[SunExposure_PartShade]
Chip = Part Shade
Keywords = partial, Part Shade, Partial Shade, Filtered Light, Partial Sun, Part Sun
Query = { "Sun Exposure Flags": { "$in": ["Part Shade"] } }
Filters = { "Sun Exposure Flags": ["Part Shade"] }

[SunExposure_FullSun]
Chip = Full Sun
Keywords = Full Sun, All day sun, sun
Query = { "Sun Exposure Flags": { "$in": ["Full Sun"] } }
Chip = Sun
Keywords = Full Sun, Sun, Direct Sun
Query = { "Sun Exposure Flags": { "$in": ["Sun"] } }
Filters = { "Sun Exposure Flags": ["Sun"] }

[SunExposure_Shade]
Chip = Shade
Keywords = Full Shade, Deep Shade, Shade, Shady location, Shade Tolerant
Query = { "Sun Exposure Flags": { "$in": ["Shade"] } }
Filters = { "Sun Exposure Flags": ["Shade"] }

[FallBlooming]
Chip = Fall Blooming
Expand All @@ -58,119 +126,95 @@ Keywords = Spring, Spring Flowers, Spring Bloom
Query = { "Flowering Months": { "$regex": "mar|apr|may", "$options": "i" } }

[SoilMoisture_Wet]
Chip = Wet Soil
Chip = Wet
Keywords = Wet, Rain Garden, Puddles, Wet Feet, Wet Soil, Wet Dirt
Query = { "Soil Moisture Flags": { "$in": ["Wet"] } }
Filters = { "Soil Moisture Flags": ["Wet"] }

[SoilMoisture_Dry]
Chip = Dry Soil
Chip = Dry
Keywords = Dry, Cracks in Soil, Dry Soil, Dry Dirt
Query = { "Soil Moisture Flags": { "$in": ["Dry"] } }
Filters = { "Soil Moisture Flags": ["Dry"] }

[SoilMoisture_Moist]
Chip = Moist Soil
Chip = Moist
Keywords = Moist, Slightly Moist, Moist Soil, Slightly Wet
Query = { "Soil Moisture Flags": { "$in": ["Moist"] } }
Filters = { "Soil Moisture Flags": ["Moist"] }

[DroughtTolerance]
Chip = Drought Tolerant
Keywords = Drought Tolerant, Drought, tolerance of drought, droughts
Query = { "Plant Type Flags": { "$in": ["Drought Tolerant"] } }
Query = { "Drought Tolerance": { "$in": ["Medium", "High"] } }

[EvergreenCheck]
Chip = Evergreen Plants
Keywords = Evergreen, Evergreen Trees, Trees that are evergreen
Query = { "Plant Type Flags": { "$in": ["Evergreen"] } }
Query = { "Leaf Retention": "Evergreen" }

[Tree]
Chip = Tree
Keywords = Tree
Query = { "Plant Type Flags": { "$in": ["Tree"] } }
Filters = { "Plant Type Flags": ["Tree"] }

[Shrub]
Chip = Shrub
Keywords = Shrub, Bush
Query = { "Plant Type Flags": { "$in": ["Shrub"] } }
Filters = { "Plant Type Flags": ["Shrub"] }

[Vine]
Chip = Vine
Keywords = Vine, Climbing, Climber
Query = { "Plant Type Flags": { "$in": ["Vine"] } }
Filters = { "Plant Type Flags": ["Vine"] }

[Fern]
Chip = Fern
Keywords = Fern
Query = { "Plant Type Flags": { "$in": ["Fern"] } }
Query = { "$or": [{ "Common Name": { "$regex": "fern", "$options": "i" } }, { "Scientific Name": { "$regex": "fern", "$options": "i" } }] }
Filters = { "Plant Type Flags": ["Fern"] }

[Grass]
Chip = Grass
Keywords = Grass, Grasses, Sedge, Sedges, Rush, Rushes
Query = { "Plant Type Flags": { "$in": ["Grass", "Sedge", "Rush"] } }
Query = { "Plant Family": "Poaceae" }

[Hummingbirds]
Chip = Attracts Hummingbirds
Keywords = Hummingbird, Hummingbirds, Hummingbird-attracting
Query = { "Pollinator Flags": { "$in": ["Hummingbirds"] } }
Filters = { "Pollinator Flags": ["Hummingbirds"] }

[Butterflies]
Chip = Attracts Butterflies
Keywords = Butterfly, Butterflies
Query = { "Pollinator Flags": { "$in": ["Butterflies"] } }
Filters = { "Pollinator Flags": ["Butterflies"] }

[Bees]
Chip = Attracts Bees
Keywords = Bee, Bees, Bumblebee, Bumblebees, Honey Bee
Query = { "Pollinator Flags": { "$in": ["Bees"] } }

[RedFlower]
Chip = Red Flowers
Keywords = Red, Red Flower, Red Flowers, Red Blooms
Query = { "Flower Color Flags": { "$in": ["Red"] } }

[BlueFlower]
Chip = Blue Flowers
Keywords = Blue, Blue Flower, Blue Flowers, Blue Blooms
Query = { "Flower Color Flags": { "$in": ["Blue"] } }

[YellowFlower]
Chip = Yellow Flowers
Keywords = Yellow, Yellow Flower, Yellow Flowers, Yellow Blooms
Query = { "Flower Color Flags": { "$in": ["Yellow"] } }

[PurpleFlower]
Chip = Purple Flowers
Keywords = Purple, Purple Flower, Purple Flowers, Purple Blooms, Violet
Query = { "Flower Color Flags": { "$in": ["Purple"] } }
Query = { "Pollinator Flags": { "$in": ["Native Bees", "Honey Bees", "Bombus"] } }
Filters = { "Pollinator Flags": ["Bees"] }

[WhiteFlower]
Chip = White Flowers
Keywords = White, White Flower, White Flowers, White Blooms
Query = { "Flower Color Flags": { "$in": ["White"] } }
# These flower color rules have been moved to the top of the file

[PinkFlower]
Chip = Pink Flowers
Keywords = Pink, Pink Flower, Pink Flowers, Pink Blooms
Query = { "Flower Color Flags": { "$in": ["Pink"] } }

[OrangeFlower]
Chip = Orange Flowers
Keywords = Orange, Orange Flower, Orange Flowers, Orange Blooms
Query = { "Flower Color Flags": { "$in": ["Orange"] } }

[GreenFlower]
Chip = Green Flowers
Keywords = Green, Green Flower, Green Flowers, Green Blooms
Query = { "Flower Color Flags": { "$in": ["Green"] } }
# These flower color rules have been moved to the top of the file

[Superplant]
Chip = Super Plant
Keywords = Super, Super Plant, Superplant
Query = { "Superplant": true }
Filters = { "Superplant": ["Super Plant"] }

[Showy]
Chip = Showy
Keywords = Showy, Showy Flowers, Showy Blooms
Query = { "Showy": true }
Filters = { "Showy": ["Showy"] }

[FallColor]
Chip = Fall Color
Expand Down Expand Up @@ -227,15 +271,13 @@ Chip = Red Berries/Fruit
Keywords = Red Berries, Red Fruit
Query = { "Fruit Color": "Red" }

[BlueFruit]
Chip = Blue Berries/Fruit
Keywords = Blue Berries, Blue Fruit
Query = { "Fruit Color": "Blue" }


[AsterFamily]
Chip = Aster Family
Keywords = Asteraceae, Aster Family, Daisy Family, Sunflower Family, Composite
Keywords = Asteraceae, Aster Family, Daisy Family, Sunflower Family, Composite, Aster
Query = { "Plant Family": "Asteraceae" }
Filters = { "Plant Family": ["Asteraceae"] }

[SilverFoliage]
Chip = Silver/Gray Foliage
Expand All @@ -245,4 +287,4 @@ Query = { "Foliage Color": "Gray-Green" }
[Cactus]
Chip = Cactus
Keywords = Cactus, Cacti, Succulent, Desert Plant, Prickly, Spiny
Query = { "Plant Family": { "$regex": "Cactaceae", "$options": "i" } }
Query = { "Plant Family": "Cactaceae" }
51 changes: 51 additions & 0 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,34 @@ const version = fs.existsSync(versionFile)
? fs.readFileSync(versionFile, "utf8")
: "0";
const axios = require("axios");
const ini = require("ini");

// Load query rules from queryrules.ini at startup
const queryRulesPath = path.join(__dirname, "queryrules.ini");
let queryRules = {};
if (fs.existsSync(queryRulesPath)) {
const parsed = ini.parse(fs.readFileSync(queryRulesPath, "utf8"));
for (const [name, rule] of Object.entries(parsed)) {
try {
queryRules[name] = {
chip: rule.Chip,
keywords: String(rule.Keywords || "")
.split(/,\s*/)
.filter(Boolean),
query: JSON.parse(rule.Query),
};
if (rule.Filters) {
try {
queryRules[name].filters = JSON.parse(rule.Filters);
} catch (e) {
console.error(`Failed to parse filters for rule ${name}:`, e);
}
}
} catch (e) {
console.error(`Failed to parse query rule ${name}:`, e);
}
}
}

// Disabled for now because it causes confusion when we update the data
// const cache = {};
Expand Down Expand Up @@ -59,11 +87,31 @@ module.exports = async function ({ plants, nurseries }) {
});
return res.send(response.data);
});

// Provide query rules to the frontend
app.get("/api/v1/queryrules", (req, res) => {
res.json(queryRules);
});
app.get("/api/v1/plants", async (req, res) => {
try {
const fetchResults = req.query.results !== "0";
const fetchTotal = req.query.total !== "0";
const query = {};
const ruleChips = [];
const rulesParam = req.query.rules;
if (rulesParam) {
const names = Array.isArray(rulesParam)
? rulesParam
: String(rulesParam).split(/,/);
for (const name of names) {
const rule = queryRules[name];
if (rule) {
if (!query.$and) query.$and = [];
query.$and.push(rule.query);
ruleChips.push({ name, chip: rule.chip });
}
}
}
const sorts = {
"Sort by Common Name (A-Z)": {
"Common Name": 1,
Expand Down Expand Up @@ -437,6 +485,9 @@ module.exports = async function ({ plants, nurseries }) {
);
}
}
if (ruleChips.length) {
response.ruleChips = ruleChips;
}
// setCache(req, response);
return res.send(response);
} catch (e) {
Expand Down
Loading