Filter trade counts to the last 6 months

This commit is contained in:
Emi Matchu 2021-03-23 18:32:22 -07:00
parent 62952b80dd
commit 3984f9c9ba
2 changed files with 43 additions and 56 deletions

View file

@ -535,55 +535,6 @@ const buildItemAllOccupiedZonesLoader = (db) =>
}); });
}); });
const buildItemTradeCountsLoader = (db) =>
new DataLoader(
async (itemIdOwnedPairs) => {
const qs = itemIdOwnedPairs
.map((_) => "(closet_hangers.item_id = ? AND closet_hangers.owned = ?)")
.join(" OR ");
const values = itemIdOwnedPairs
.map(({ itemId, isOwned }) => [itemId, isOwned])
.flat();
const [rows, _] = await db.execute(
`
SELECT
closet_hangers.item_id AS item_id, closet_hangers.owned AS is_owned,
count(DISTINCT closet_hangers.user_id) AS users_count
FROM closet_hangers
INNER JOIN users ON users.id = closet_hangers.user_id
LEFT JOIN closet_lists ON closet_lists.id = closet_hangers.list_id
WHERE (
(${qs})
AND (
(closet_hangers.list_id IS NOT NULL AND closet_lists.visibility >= 2)
OR (
closet_hangers.list_id IS NULL AND closet_hangers.owned = 1
AND users.owned_closet_hangers_visibility >= 2
)
OR (
closet_hangers.list_id IS NULL AND closet_hangers.owned = 0
AND users.wanted_closet_hangers_visibility >= 2
)
)
)
GROUP BY closet_hangers.item_id, closet_hangers.owned;
`,
values
);
const entities = rows.map(normalizeRow);
return itemIdOwnedPairs.map(({ itemId, isOwned }) => {
// NOTE: There may be no matching row, if there are 0 such trades.
const entity = entities.find(
(e) => e.itemId === itemId && Boolean(e.isOwned) === isOwned
);
return entity ? entity.usersCount : 0;
});
},
{ cacheKeyFn: ({ itemId, isOwned }) => `${itemId}-${isOwned}` }
);
const buildItemTradesLoader = (db, loaders) => const buildItemTradesLoader = (db, loaders) =>
new DataLoader( new DataLoader(
async (itemIdOwnedPairs) => { async (itemIdOwnedPairs) => {
@ -1261,7 +1212,6 @@ function buildLoaders(db) {
db db
); );
loaders.itemAllOccupiedZonesLoader = buildItemAllOccupiedZonesLoader(db); loaders.itemAllOccupiedZonesLoader = buildItemAllOccupiedZonesLoader(db);
loaders.itemTradeCountsLoader = buildItemTradeCountsLoader(db);
loaders.itemTradesLoader = buildItemTradesLoader(db, loaders); loaders.itemTradesLoader = buildItemTradesLoader(db, loaders);
loaders.petTypeLoader = buildPetTypeLoader(db, loaders); loaders.petTypeLoader = buildPetTypeLoader(db, loaders);
loaders.petTypeBySpeciesAndColorLoader = buildPetTypeBySpeciesAndColorLoader( loaders.petTypeBySpeciesAndColorLoader = buildPetTypeBySpeciesAndColorLoader(

View file

@ -29,6 +29,7 @@ const typeDefs = gql`
currentUserWantsThis: Boolean! @cacheControl(scope: PRIVATE) currentUserWantsThis: Boolean! @cacheControl(scope: PRIVATE)
# How many users are offering/seeking this in their public trade lists. # How many users are offering/seeking this in their public trade lists.
# Excludes users that seem relatively inactive.
numUsersOfferingThis: Int! @cacheControl(maxAge: ${oneHour}) numUsersOfferingThis: Int! @cacheControl(maxAge: ${oneHour})
numUsersSeekingThis: Int! @cacheControl(maxAge: ${oneHour}) numUsersSeekingThis: Int! @cacheControl(maxAge: ${oneHour})
@ -268,19 +269,55 @@ const resolvers = {
return closetHangers.some((h) => h.itemId === id && !h.owned); return closetHangers.some((h) => h.itemId === id && !h.owned);
}, },
numUsersOfferingThis: async ({ id }, _, { itemTradeCountsLoader }) => { numUsersOfferingThis: async (
const count = await itemTradeCountsLoader.load({ { id },
_,
{ itemTradesLoader, userLastTradeActivityLoader }
) => {
// First, get the trades themselves. TODO: Optimize into one query?
const trades = await itemTradesLoader.load({
itemId: id, itemId: id,
isOwned: true, isOwned: true,
}); });
return count;
// Then, get the last active dates for those users.
const userIds = trades.map((t) => t.user.id);
const lastActiveDates = await userLastTradeActivityLoader.loadMany(
userIds
);
// Finally, count how many of those dates were in the last 6 months.
// Those trades get to be in the count!
const sixMonthsAgo = new Date();
sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6);
const numTrades = lastActiveDates.filter((d) => d > sixMonthsAgo).length;
return numTrades;
}, },
numUsersSeekingThis: async ({ id }, _, { itemTradeCountsLoader }) => { numUsersSeekingThis: async (
const count = await itemTradeCountsLoader.load({ { id },
_,
{ itemTradesLoader, userLastTradeActivityLoader }
) => {
// First, get the trades themselves. TODO: Optimize into one query?
const trades = await itemTradesLoader.load({
itemId: id, itemId: id,
isOwned: false, isOwned: false,
}); });
return count;
// Then, get the last active dates for those users.
const userIds = trades.map((t) => t.user.id);
const lastActiveDates = await userLastTradeActivityLoader.loadMany(
userIds
);
// Finally, count how many of those dates were in the last 6 months.
// Those trades get to be in the count!
const sixMonthsAgo = new Date();
sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6);
const numTrades = lastActiveDates.filter((d) => d > sixMonthsAgo).length;
return numTrades;
}, },
tradesOffering: async ({ id }, _, { itemTradesLoader }) => { tradesOffering: async ({ id }, _, { itemTradesLoader }) => {