feat: consume selected mechanic revisions
This commit is contained in:
@@ -1,6 +1,16 @@
|
||||
import { getDatabase } from '$lib/server/database';
|
||||
import { getRegistrySearch } from '$lib/server/pagination';
|
||||
import { databaseCategories } from '$lib/database/categories';
|
||||
import {
|
||||
loadMechanicPublicProjectionsForOwners,
|
||||
type MechanicPublicProjectionOwnerRef,
|
||||
type MechanicPublicProjectionsByOwner,
|
||||
} from '$lib/server/mechanic-public-projection';
|
||||
import {
|
||||
databaseMechanicGroup,
|
||||
databaseMechanicOwnersMatchSearch,
|
||||
databaseMechanicSearchSummary,
|
||||
} from './public-mechanics';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
const tables = {
|
||||
@@ -28,110 +38,465 @@ export const load: PageServerLoad = async ({ url }) => {
|
||||
return { ...category, count: Number(row?.count ?? 0) };
|
||||
}),
|
||||
);
|
||||
const searchResults = search
|
||||
const rawSearchResults = search
|
||||
? await (
|
||||
await database.prepare(`
|
||||
SELECT * FROM (
|
||||
SELECT 'gear' AS slug,'Gear' AS category,item.name,
|
||||
item.slot || ' · T' || item.tier AS detail
|
||||
FROM gear item
|
||||
WHERE item.active=1 AND (item.name LIKE ? ESCAPE '\\' COLLATE NOCASE OR item.slot LIKE ? ESCAPE '\\' COLLATE NOCASE)
|
||||
UNION ALL
|
||||
SELECT 'weapons','Weapons',item.name,
|
||||
item.category || ' · ' || item.damage_type || ' damage'
|
||||
FROM weapons item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE OR item.category LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.damage_type LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'weapon-mods','Weapon Mods',item.name,item.slot_type
|
||||
FROM weapon_mods item
|
||||
WHERE item.active=1 AND (item.name LIKE ? ESCAPE '\\' COLLATE NOCASE OR item.slot_type LIKE ? ESCAPE '\\' COLLATE NOCASE)
|
||||
UNION ALL
|
||||
SELECT 'gear-mods','Gear Mods',item.name,'Gear modification'
|
||||
FROM gear_mods item
|
||||
WHERE item.active=1 AND item.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
UNION ALL
|
||||
SELECT 'os-protocols','OS Protocols',item.name,
|
||||
item.quality || ' · ' || item.primary_attribute_type
|
||||
FROM os_protocols item
|
||||
LEFT JOIN os_protocol_talents talent ON talent.protocol_id=item.id
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE OR item.quality LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.primary_attribute_type LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR talent.name LIKE ? ESCAPE '\\' COLLATE NOCASE OR talent.description_template LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'talents','Talents',item.name,item.category
|
||||
FROM talents item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE OR item.category LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM talent_tiers tier
|
||||
WHERE tier.talent_id=item.id AND (
|
||||
tier.description LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR tier.trigger_text LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR tier.effect_text LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'brands','Brands',item.name,
|
||||
COALESCE((
|
||||
SELECT GROUP_CONCAT(attribute.name, ', ')
|
||||
FROM brand_set_effects effect
|
||||
JOIN stat_attributes attribute ON attribute.id=effect.stat_attribute_id
|
||||
WHERE effect.brand_set_id=item.id
|
||||
),'Brand Set bonuses')
|
||||
FROM brand_sets item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM brand_set_effects effect
|
||||
JOIN stat_attributes attribute ON attribute.id=effect.stat_attribute_id
|
||||
WHERE effect.brand_set_id=item.id AND attribute.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'skill-chips','Skill Chips',item.name,COALESCE(talent.name,'Skill Chip set')
|
||||
FROM skill_chip_sets item
|
||||
LEFT JOIN skill_chip_talents talent ON talent.skill_chip_set_id=item.id
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE OR talent.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR talent.description_template LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'specializations','Specializations',item.name,'Specialization'
|
||||
FROM specializations item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE OR item.description LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM specialization_focuses focus
|
||||
WHERE focus.specialization_id=item.id AND focus.active=1
|
||||
AND focus.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM specialization_abilities ability
|
||||
WHERE ability.specialization_id=item.id AND ability.active=1
|
||||
AND ability.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
) matches
|
||||
ORDER BY name COLLATE NOCASE
|
||||
LIMIT 40
|
||||
`)
|
||||
).all(...Array(27).fill(pattern))
|
||||
SELECT * FROM (
|
||||
SELECT 'gear' AS slug,'Gear' AS category,item.id AS parent_id,item.name,
|
||||
item.slot || ' · T' || item.tier AS detail
|
||||
FROM gear item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.slot LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM gear_talents link
|
||||
JOIN talents linked_talent
|
||||
ON linked_talent.id=link.talent_id AND linked_talent.active=1
|
||||
JOIN mechanic_authored_sources source
|
||||
ON source.owner_type='talent' AND source.owner_id=linked_talent.id
|
||||
JOIN mechanic_public_variants variant ON variant.source_id=source.id
|
||||
WHERE link.gear_id=item.id
|
||||
AND variant.behavior_text LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'weapons','Weapons',item.id,item.name,
|
||||
item.category || ' · ' || item.damage_type || ' damage'
|
||||
FROM weapons item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.category LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.damage_type LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM talents linked_talent
|
||||
JOIN mechanic_authored_sources source
|
||||
ON source.owner_type='talent' AND source.owner_id=linked_talent.id
|
||||
JOIN mechanic_public_variants variant ON variant.source_id=source.id
|
||||
WHERE linked_talent.active=1
|
||||
AND (
|
||||
linked_talent.id=item.exotic_talent_id
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM weapon_talent_options link
|
||||
WHERE link.weapon_id=item.id AND link.talent_id=linked_talent.id
|
||||
)
|
||||
)
|
||||
AND variant.behavior_text LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'weapon-mods','Weapon Mods',item.id,item.name,item.slot_type
|
||||
FROM weapon_mods item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.slot_type LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'gear-mods','Gear Mods',item.id,item.name,'Gear modification'
|
||||
FROM gear_mods item
|
||||
WHERE item.active=1 AND item.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
UNION ALL
|
||||
SELECT 'os-protocols','OS Protocols',item.id,item.name,
|
||||
item.quality || ' · ' || item.primary_attribute_type
|
||||
FROM os_protocols item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.quality LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.primary_attribute_type LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM os_protocol_talents talent
|
||||
WHERE talent.protocol_id=item.id AND (
|
||||
talent.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR talent.description_template LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM mechanic_authored_sources source
|
||||
JOIN mechanic_public_variants variant ON variant.source_id=source.id
|
||||
WHERE source.owner_type='os_protocol_talent' AND source.owner_id=talent.id
|
||||
AND variant.behavior_text LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'talents','Talents',item.id,item.name,item.category
|
||||
FROM talents item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.category LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM talent_tiers tier
|
||||
WHERE tier.talent_id=item.id AND (
|
||||
tier.description LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR tier.trigger_text LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR tier.effect_text LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM mechanic_authored_sources source
|
||||
JOIN mechanic_public_variants variant ON variant.source_id=source.id
|
||||
WHERE source.owner_type='talent' AND source.owner_id=item.id
|
||||
AND variant.behavior_text LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'brands','Brands',item.id,item.name,
|
||||
COALESCE((
|
||||
SELECT GROUP_CONCAT(attribute.name, ', ')
|
||||
FROM brand_set_effects effect
|
||||
JOIN stat_attributes attribute ON attribute.id=effect.stat_attribute_id
|
||||
WHERE effect.brand_set_id=item.id
|
||||
),'Brand Set bonuses')
|
||||
FROM brand_sets item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM brand_set_effects effect
|
||||
JOIN stat_attributes attribute ON attribute.id=effect.stat_attribute_id
|
||||
WHERE effect.brand_set_id=item.id
|
||||
AND attribute.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'skill-chips','Skill Chips',item.id,item.name,
|
||||
COALESCE((SELECT talent.name FROM skill_chip_talents talent
|
||||
WHERE talent.skill_chip_set_id=item.id),'Skill Chip set')
|
||||
FROM skill_chip_sets item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM skill_chip_talents talent
|
||||
WHERE talent.skill_chip_set_id=item.id AND (
|
||||
talent.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR talent.description_template LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM mechanic_authored_sources source
|
||||
JOIN mechanic_public_variants variant ON variant.source_id=source.id
|
||||
WHERE source.owner_type='skill_chip_talent' AND source.owner_id=talent.id
|
||||
AND variant.behavior_text LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'specializations','Specializations',item.id,item.name,'Specialization'
|
||||
FROM specializations item
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.description LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM specialization_focuses focus
|
||||
WHERE focus.specialization_id=item.id AND focus.active=1
|
||||
AND focus.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM specialization_abilities ability
|
||||
WHERE ability.specialization_id=item.id AND ability.active=1
|
||||
AND ability.name LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM specialization_tree_rank_combat_effects attachment
|
||||
JOIN specialization_tree_nodes node ON node.id=attachment.node_id AND node.active=1
|
||||
JOIN specialization_focuses focus ON focus.id=node.focus_id AND focus.active=1
|
||||
JOIN specialization_combat_effects combat_effect
|
||||
ON combat_effect.id=attachment.combat_effect_id
|
||||
AND combat_effect.specialization_id=focus.specialization_id
|
||||
AND combat_effect.active=1
|
||||
JOIN mechanic_authored_sources source
|
||||
ON source.owner_type='specialization_tree_rank' AND source.owner_id=attachment.id
|
||||
JOIN mechanic_public_variants variant ON variant.source_id=source.id
|
||||
WHERE focus.specialization_id=item.id
|
||||
AND variant.behavior_text LIKE ? ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
) matches
|
||||
ORDER BY name COLLATE NOCASE
|
||||
`)
|
||||
).all(...Array(33).fill(pattern))
|
||||
: [];
|
||||
// Raw projection text produces a candidate set only. Canonical projections
|
||||
// below decide behavior matches; this query preserves independent metadata matches.
|
||||
const metadataSearchResultKeys = search
|
||||
? new Set(
|
||||
(
|
||||
await (
|
||||
await database.prepare(`WITH search(pattern) AS (VALUES (?))
|
||||
SELECT 'gear' AS slug,item.id AS parent_id
|
||||
FROM gear item,search
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.slot LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'weapons',item.id
|
||||
FROM weapons item,search
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.category LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.damage_type LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'weapon-mods',item.id
|
||||
FROM weapon_mods item,search
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.slot_type LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'gear-mods',item.id
|
||||
FROM gear_mods item,search
|
||||
WHERE item.active=1
|
||||
AND item.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
UNION ALL
|
||||
SELECT 'os-protocols',item.id
|
||||
FROM os_protocols item,search
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.quality LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.primary_attribute_type LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM os_protocol_talents talent
|
||||
WHERE talent.protocol_id=item.id AND (
|
||||
talent.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR talent.description_template LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'talents',item.id
|
||||
FROM talents item,search
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.category LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM talent_tiers tier
|
||||
WHERE tier.talent_id=item.id AND (
|
||||
tier.description LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR tier.trigger_text LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR tier.effect_text LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'brands',item.id
|
||||
FROM brand_sets item,search
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM brand_set_effects effect
|
||||
JOIN stat_attributes attribute ON attribute.id=effect.stat_attribute_id
|
||||
WHERE effect.brand_set_id=item.id
|
||||
AND attribute.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'skill-chips',item.id
|
||||
FROM skill_chip_sets item,search
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM skill_chip_talents talent
|
||||
WHERE talent.skill_chip_set_id=item.id AND (
|
||||
talent.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR talent.description_template LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)
|
||||
)
|
||||
UNION ALL
|
||||
SELECT 'specializations',item.id
|
||||
FROM specializations item,search
|
||||
WHERE item.active=1 AND (
|
||||
item.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR item.description LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM specialization_focuses focus
|
||||
WHERE focus.specialization_id=item.id AND focus.active=1
|
||||
AND focus.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM specialization_abilities ability
|
||||
WHERE ability.specialization_id=item.id AND ability.active=1
|
||||
AND ability.name LIKE search.pattern ESCAPE '\\' COLLATE NOCASE
|
||||
)
|
||||
)`)
|
||||
).all(pattern)
|
||||
).map((result) => `${result.slug}\u0000${result.parent_id}`),
|
||||
)
|
||||
: new Set<string>();
|
||||
const resultIds = (slug: string) =>
|
||||
rawSearchResults
|
||||
.filter((result) => String(result.slug) === slug)
|
||||
.map((result) => String(result.parent_id));
|
||||
const [
|
||||
gearTalentRows,
|
||||
weaponTalentRows,
|
||||
protocolTalentRows,
|
||||
skillChipTalentRows,
|
||||
specializationAttachmentRows,
|
||||
] = await Promise.all([
|
||||
resultIds('gear').length
|
||||
? (
|
||||
await database.prepare(`SELECT link.gear_id,link.talent_id FROM gear_talents link
|
||||
JOIN talents ON talents.id=link.talent_id AND talents.active=1
|
||||
WHERE link.gear_id IN (${resultIds('gear')
|
||||
.map(() => '?')
|
||||
.join(',')})
|
||||
ORDER BY link.gear_id,link.talent_id`)
|
||||
).all(...resultIds('gear'))
|
||||
: [],
|
||||
resultIds('weapons').length
|
||||
? (
|
||||
await database.prepare(`SELECT relation.weapon_id,relation.talent_id FROM (
|
||||
SELECT weapon_id,talent_slot,talent_id FROM weapon_talent_options
|
||||
UNION ALL
|
||||
SELECT id AS weapon_id,NULL AS talent_slot,exotic_talent_id AS talent_id
|
||||
FROM weapons WHERE exotic_talent_id IS NOT NULL
|
||||
) relation
|
||||
JOIN talents ON talents.id=relation.talent_id AND talents.active=1
|
||||
WHERE relation.weapon_id IN (${resultIds('weapons')
|
||||
.map(() => '?')
|
||||
.join(',')})
|
||||
ORDER BY relation.weapon_id,relation.talent_slot,relation.talent_id`)
|
||||
).all(...resultIds('weapons'))
|
||||
: [],
|
||||
resultIds('os-protocols').length
|
||||
? (
|
||||
await database.prepare(`SELECT protocol_id,id FROM os_protocol_talents
|
||||
WHERE protocol_id IN (${resultIds('os-protocols')
|
||||
.map(() => '?')
|
||||
.join(',')})
|
||||
ORDER BY protocol_id,id`)
|
||||
).all(...resultIds('os-protocols'))
|
||||
: [],
|
||||
resultIds('skill-chips').length
|
||||
? (
|
||||
await database.prepare(`SELECT skill_chip_set_id,id FROM skill_chip_talents
|
||||
WHERE skill_chip_set_id IN (${resultIds('skill-chips')
|
||||
.map(() => '?')
|
||||
.join(',')})
|
||||
ORDER BY skill_chip_set_id,id`)
|
||||
).all(...resultIds('skill-chips'))
|
||||
: [],
|
||||
resultIds('specializations').length
|
||||
? (
|
||||
await database.prepare(`SELECT attachment.id,focus.specialization_id
|
||||
FROM specialization_tree_rank_combat_effects attachment
|
||||
JOIN specialization_tree_nodes node ON node.id=attachment.node_id AND node.active=1
|
||||
JOIN specialization_focuses focus ON focus.id=node.focus_id AND focus.active=1
|
||||
JOIN specialization_combat_effects combat_effect
|
||||
ON combat_effect.id=attachment.combat_effect_id
|
||||
AND combat_effect.specialization_id=focus.specialization_id
|
||||
AND combat_effect.active=1
|
||||
WHERE focus.specialization_id IN (${resultIds('specializations')
|
||||
.map(() => '?')
|
||||
.join(',')})
|
||||
ORDER BY focus.specialization_id,focus.display_order,focus.name COLLATE NOCASE,
|
||||
node.row_number,node.column_number,attachment.rank,attachment.effect_order`)
|
||||
).all(...resultIds('specializations'))
|
||||
: [],
|
||||
]);
|
||||
const resultKey = (slug: string, id: string) => `${slug}\u0000${id}`;
|
||||
const ownersByResult = new Map<string, MechanicPublicProjectionOwnerRef[]>();
|
||||
const addOwner = (
|
||||
slug: string,
|
||||
parentId: string,
|
||||
owner: MechanicPublicProjectionOwnerRef,
|
||||
) => {
|
||||
const key = resultKey(slug, parentId);
|
||||
ownersByResult.set(key, [...(ownersByResult.get(key) ?? []), owner]);
|
||||
};
|
||||
for (const result of rawSearchResults) {
|
||||
if (String(result.slug) === 'talents') {
|
||||
addOwner('talents', String(result.parent_id), {
|
||||
type: 'talent',
|
||||
id: String(result.parent_id),
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const row of gearTalentRows) {
|
||||
addOwner('gear', String(row.gear_id), {
|
||||
type: 'talent',
|
||||
id: String(row.talent_id),
|
||||
});
|
||||
}
|
||||
for (const row of weaponTalentRows) {
|
||||
addOwner('weapons', String(row.weapon_id), {
|
||||
type: 'talent',
|
||||
id: String(row.talent_id),
|
||||
});
|
||||
}
|
||||
for (const row of protocolTalentRows) {
|
||||
addOwner('os-protocols', String(row.protocol_id), {
|
||||
type: 'os_protocol_talent',
|
||||
id: String(row.id),
|
||||
});
|
||||
}
|
||||
for (const row of skillChipTalentRows) {
|
||||
addOwner('skill-chips', String(row.skill_chip_set_id), {
|
||||
type: 'skill_chip_talent',
|
||||
id: String(row.id),
|
||||
});
|
||||
}
|
||||
for (const row of specializationAttachmentRows) {
|
||||
addOwner('specializations', String(row.specialization_id), {
|
||||
type: 'specialization_tree_rank',
|
||||
id: String(row.id),
|
||||
});
|
||||
}
|
||||
const owners = [
|
||||
...new Map(
|
||||
[...ownersByResult.values()]
|
||||
.flat()
|
||||
.map((owner) => [`${owner.type}\u0000${owner.id}`, owner]),
|
||||
).values(),
|
||||
];
|
||||
const publicMechanics: MechanicPublicProjectionsByOwner = owners.length
|
||||
? await loadMechanicPublicProjectionsForOwners(database, owners)
|
||||
: ({} as MechanicPublicProjectionsByOwner);
|
||||
const searchResults = rawSearchResults
|
||||
.filter(
|
||||
(result) =>
|
||||
metadataSearchResultKeys.has(
|
||||
resultKey(String(result.slug), String(result.parent_id)),
|
||||
) ||
|
||||
databaseMechanicOwnersMatchSearch(
|
||||
ownersByResult.get(
|
||||
resultKey(String(result.slug), String(result.parent_id)),
|
||||
) ?? [],
|
||||
publicMechanics,
|
||||
search,
|
||||
),
|
||||
)
|
||||
.slice(0, 40);
|
||||
const normalizedSearch = search.toLocaleLowerCase();
|
||||
return {
|
||||
registries: counts,
|
||||
total: counts.reduce((total, registry) => total + registry.count, 0),
|
||||
search,
|
||||
searchResults: searchResults.map((result) => ({
|
||||
slug: String(result.slug),
|
||||
category: String(result.category),
|
||||
name: String(result.name),
|
||||
detail: String(result.detail ?? ''),
|
||||
})),
|
||||
searchResults: searchResults.map((result) => {
|
||||
const groups = (
|
||||
ownersByResult.get(
|
||||
resultKey(String(result.slug), String(result.parent_id)),
|
||||
) ?? []
|
||||
)
|
||||
.map((owner) =>
|
||||
databaseMechanicGroup(owner, publicMechanics, { label: 'BEHAVIOR' }),
|
||||
)
|
||||
.filter((group) => group !== null);
|
||||
const group =
|
||||
groups.find((candidate) =>
|
||||
candidate.variants.some((variant) =>
|
||||
variant.behaviorText.toLocaleLowerCase().includes(normalizedSearch),
|
||||
),
|
||||
) ??
|
||||
groups[0] ??
|
||||
null;
|
||||
const behavior = databaseMechanicSearchSummary(group);
|
||||
return {
|
||||
slug: String(result.slug),
|
||||
category: String(result.category),
|
||||
name: String(result.name),
|
||||
detail: String(result.detail ?? ''),
|
||||
...(behavior ?? {}),
|
||||
};
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user