@@ -41,6 +41,7 @@ import {
4141import { In , Not , SelectQueryBuilder } from 'typeorm' ;
4242import { ensureSourcePermissions , GQLSource } from './sources' ;
4343import {
44+ connectionFromNodes ,
4445 CursorPage ,
4546 feedCursorPageGenerator ,
4647 GQLEmptyResponse ,
@@ -87,12 +88,16 @@ import { SourceMemberRoles } from '../roles';
8788import { ContentPreferenceKeyword } from '../entity/contentPreference/ContentPreferenceKeyword' ;
8889import { briefingPostIdsMaxItems } from '../common/brief' ;
8990import {
91+ emptyFeedV2Connection ,
9092 feedV2QueryResolver ,
9193 feedV2Resolvers ,
9294 feedV2TypeDefs ,
9395 type FeedV2Args ,
96+ getFeedV2AllowedPostTypes ,
97+ getFeedV2FieldTree ,
9498 getForYouFeedGenerator ,
9599 isSavedNoAiEnabled ,
100+ toFeedV2PostConnection ,
96101} from './feedV2' ;
97102
98103interface GQLTagsCategory {
@@ -1163,6 +1168,10 @@ interface FeedPage extends Page {
11631168 score ?: number ;
11641169}
11651170
1171+ type FeedVersionArgs = Pick < FeedArgs , 'ranking' > & {
1172+ version : number ;
1173+ } ;
1174+
11661175const feedPageGenerator : PageGenerator < GQLPost , FeedArgs , FeedPage , unknown > = {
11671176 connArgsToPage : ( { ranking, first, after } : FeedArgs ) => {
11681177 const cursor = getCursorFromAfter ( after || undefined ) ;
@@ -1219,6 +1228,36 @@ const applyFeedPaging = (
12191228 return newBuilder ;
12201229} ;
12211230
1231+ const shouldUseFeedGenerator = ( { version } : FeedVersionArgs ) => {
1232+ return version >= 2 ;
1233+ } ;
1234+
1235+ const getConfiguredFeedId = (
1236+ ctx : Pick < Context , 'userId' > ,
1237+ args : Pick < ConfiguredFeedArgs , 'feedId' > | Pick < FeedV2Args , 'feedId' > ,
1238+ ) : string | undefined => args . feedId || ctx . userId ;
1239+
1240+ const getConfiguredFeedQueryParams = (
1241+ ctx : Context ,
1242+ args : Pick < ConfiguredFeedArgs , 'feedId' > | Pick < FeedV2Args , 'feedId' > ,
1243+ ) => feedToFilters ( ctx . con , getConfiguredFeedId ( ctx , args ) , ctx . userId ) ;
1244+
1245+ const buildConfiguredFeedQuery = (
1246+ ctx : Context ,
1247+ args : Pick < ConfiguredFeedArgs , 'feedId' | 'unreadOnly' > | FeedV2Args ,
1248+ builder : SelectQueryBuilder < Post > ,
1249+ alias : string ,
1250+ queryParams : AnonymousFeedFilters | undefined ,
1251+ ) =>
1252+ configuredFeedBuilder (
1253+ ctx ,
1254+ getConfiguredFeedId ( ctx , args ) ,
1255+ args . unreadOnly ,
1256+ builder ,
1257+ alias ,
1258+ queryParams ,
1259+ ) ;
1260+
12221261interface UpvotedPage extends Page {
12231262 timestamp ?: Date ;
12241263}
@@ -1387,27 +1426,86 @@ const feedResolverV1: IFieldResolver<unknown, Context, ConfiguredFeedArgs> =
13871426 builder ,
13881427 alias ,
13891428 queryParams : AnonymousFeedFilters | undefined ,
1390- ) => {
1391- const feedId = args . feedId || ctx . userId ;
1392-
1393- return configuredFeedBuilder (
1394- ctx ,
1395- feedId ,
1396- args . unreadOnly ,
1397- builder ,
1398- alias ,
1399- queryParams ,
1400- ) ;
1401- } ,
1429+ ) => buildConfiguredFeedQuery ( ctx , args , builder , alias , queryParams ) ,
14021430 feedPageGenerator ,
14031431 applyFeedPaging ,
14041432 {
1405- fetchQueryParams : async ( ctx , args ) =>
1406- feedToFilters ( ctx . con , args . feedId || ctx . userId , ctx . userId ) ,
1433+ fetchQueryParams : ( ctx , args ) => getConfiguredFeedQueryParams ( ctx , args ) ,
14071434 allowPrivatePosts : false ,
14081435 } ,
14091436 ) ;
14101437
1438+ const feedResolverV2Local : IFieldResolver <
1439+ unknown ,
1440+ AuthContext ,
1441+ FeedV2Args
1442+ > = async ( source , args , ctx , info ) => {
1443+ const postFieldTree = getFeedV2FieldTree ( info , 'FeedPostItem' , 'post' ) ;
1444+ const allowedPostTypes = getFeedV2AllowedPostTypes ( args . supportedTypes ) ;
1445+
1446+ if ( ( args . supportedTypes && ! allowedPostTypes ?. length ) || ! postFieldTree ) {
1447+ return emptyFeedV2Connection ( args ) ;
1448+ }
1449+
1450+ const page = feedPageGenerator . connArgsToPage ( args ) ;
1451+ const queryParams = await getConfiguredFeedQueryParams ( ctx , args ) ;
1452+ const supportedTypes = allowedPostTypes ?. filter ( ( type ) => {
1453+ return queryParams . excludeTypes
1454+ ? ! queryParams . excludeTypes . includes ( type )
1455+ : true ;
1456+ } ) ;
1457+ const sourceTypes = queryParams . excludeSourceTypes ?. length
1458+ ? baseFeedConfig . source_types ?. filter (
1459+ ( type ) => ! queryParams . excludeSourceTypes ?. includes ( type ) ,
1460+ ) || [ ]
1461+ : [ ] ;
1462+
1463+ const nodes = await graphorm . queryResolveTree < GQLPost > (
1464+ ctx ,
1465+ postFieldTree ,
1466+ ( builder ) => {
1467+ builder . queryBuilder = applyFeedWhere (
1468+ ctx ,
1469+ applyFeedPaging (
1470+ ctx ,
1471+ args ,
1472+ page ,
1473+ buildConfiguredFeedQuery (
1474+ ctx ,
1475+ args ,
1476+ builder . queryBuilder ,
1477+ builder . alias ,
1478+ queryParams ,
1479+ ) ,
1480+ builder . alias ,
1481+ ) ,
1482+ builder . alias ,
1483+ supportedTypes || [ 'article' ] ,
1484+ true ,
1485+ true ,
1486+ false ,
1487+ true ,
1488+ true ,
1489+ sourceTypes ,
1490+ ) ;
1491+ return builder ;
1492+ } ,
1493+ true ,
1494+ ) ;
1495+
1496+ return toFeedV2PostConnection (
1497+ connectionFromNodes (
1498+ args ,
1499+ nodes ,
1500+ undefined ,
1501+ page ,
1502+ feedPageGenerator ,
1503+ undefined ,
1504+ queryParams ,
1505+ ) ,
1506+ ) ;
1507+ } ;
1508+
14111509const feedResolverCursor = feedResolver <
14121510 unknown ,
14131511 FeedArgs & { generator : FeedGenerator } ,
@@ -1554,23 +1652,15 @@ const postRepostsFeedResolver = feedResolver(
15541652export const resolvers : IResolvers < unknown , BaseContext > = {
15551653 Query : {
15561654 anonymousFeed : ( source , args : AnonymousFeedArgs , ctx : Context , info ) => {
1557- if ( args . version >= 2 && args . ranking === Ranking . POPULARITY ) {
1558- return feedResolverCursor (
1559- source ,
1560- {
1561- ...( args as FeedArgs ) ,
1562- generator : feedGenerators [ 'popular' ] ! ,
1563- } ,
1564- ctx ,
1565- info ,
1566- ) ;
1567- }
1568- if ( args . version >= 2 && args . ranking === Ranking . TIME ) {
1655+ if ( shouldUseFeedGenerator ( args ) ) {
15691656 return feedResolverCursor (
15701657 source ,
15711658 {
15721659 ...( args as FeedArgs ) ,
1573- generator : feedGenerators [ 'time' ] ! ,
1660+ generator :
1661+ args . ranking === Ranking . TIME
1662+ ? feedGenerators [ 'time' ] !
1663+ : feedGenerators [ 'popular' ] ! ,
15741664 } ,
15751665 ctx ,
15761666 info ,
@@ -1579,22 +1669,8 @@ export const resolvers: IResolvers<unknown, BaseContext> = {
15791669 return anonymousFeedResolverV1 ( source , args , ctx , info ) ;
15801670 } ,
15811671 feed : async ( source , args : ConfiguredFeedArgs , ctx : AuthContext , info ) => {
1582- const shouldApplyNoAi = args . noAi || ( await isSavedNoAiEnabled ( ctx ) ) ;
1583- if ( args . version >= 2 && args . ranking === Ranking . POPULARITY ) {
1584- return feedResolverCursor (
1585- source ,
1586- {
1587- ...( args as FeedArgs ) ,
1588- generator : getForYouFeedGenerator ( {
1589- ...args ,
1590- noAi : shouldApplyNoAi ,
1591- } ) ,
1592- } ,
1593- ctx ,
1594- info ,
1595- ) ;
1596- }
1597- if ( args . version >= 2 && args . ranking === Ranking . TIME ) {
1672+ if ( shouldUseFeedGenerator ( args ) ) {
1673+ const shouldApplyNoAi = args . noAi || ( await isSavedNoAiEnabled ( ctx ) ) ;
15981674 return feedResolverCursor (
15991675 source ,
16001676 {
@@ -1611,7 +1687,9 @@ export const resolvers: IResolvers<unknown, BaseContext> = {
16111687 return feedResolverV1 ( source , args , ctx , info ) ;
16121688 } ,
16131689 feedV2 : ( source , args : FeedV2Args , ctx : AuthContext , info ) =>
1614- feedV2QueryResolver ( source , args , ctx , info ) ,
1690+ shouldUseFeedGenerator ( args )
1691+ ? feedV2QueryResolver ( source , args , ctx , info )
1692+ : feedResolverV2Local ( source , args , ctx , info ) ,
16151693 followingFeed : async ( source , args : FeedArgs , ctx : Context , info ) => {
16161694 return feedResolverCursor (
16171695 source ,
0 commit comments