Skip to content

Commit 437242c

Browse files
committed
Merge branch 'dev' into prod
2 parents 2d92d9e + 3db4299 commit 437242c

39 files changed

Lines changed: 1472 additions & 343 deletions

be/src/Controller/UsersController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ function (int $paramIndex, QueryBuilder $queryBuilder, $paramValue, string $para
5454

5555
['result' => $result, 'hasMorePages' => $hasMorePages] =
5656
$this->queryResult->getQueryResult($queries, $this->perPageItems);
57-
$resultCount = count($result);
57+
$resultCount = $result->count();
5858
Helper::abortAPIIf(40402, $resultCount === 0);
5959

6060
return [

be/src/PostsQuery/QueryResult.php

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function __construct(
4444
private Stopwatch $stopwatch,
4545
private CursorCodec $cursorCodec,
4646
private ContainerBagInterface $containerBag,
47-
private int $perPageItems = 50,
47+
private int $perPageItems = 100,
4848
) {}
4949

5050
/** @return array{result: Collection, hasMorePages: bool, queryPlan: array} */
@@ -116,11 +116,11 @@ public function setResult(
116116
$qb->setParameter("cursor_$fieldName", $fieldValue)); // prevent overwriting existing param
117117
});
118118
[
119-
'unionOfQueriesSQL' => $unionOfQueriesSQL,
119+
'rawSQL' => $rawSQL,
120120
'postsKeyByTypePluralName' => $postsKeyByTypePluralName,
121121
'hasMorePages' => $hasMorePages,
122122
'queryPlan' => $queryPlan
123-
] = $this->getUnionQueryResult($queries, $isOrderByDesc, $maxResults);
123+
] = $this->getPostQueriesResult($queries, $isOrderByDesc, $maxResults);
124124

125125
$this->threads = $postsKeyByTypePluralName->get('threads', collect());
126126
$this->replies = $postsKeyByTypePluralName->get('replies', collect());
@@ -134,7 +134,7 @@ public function setResult(
134134
$queryByPostIDParamsName->map(static fn(string $postID) => Helper::POST_ID_TO_TYPE_PLURAL[$postID])
135135
))
136136
: null;
137-
$this->query = ['query' => $unionOfQueriesSQL, 'plan' => $queryPlan];
137+
$this->query = ['query' => $rawSQL, 'plan' => $queryPlan];
138138

139139
$this->stopwatch->stop('setResult');
140140
}
@@ -151,41 +151,51 @@ public function setResult(
151151
* @param Collection<Helpecr::POST_TYPE, QueryBuilder> $queries
152152
* @param bool $isOrderByDesc
153153
* @param int $maxResults
154-
* @return array{unionOfQueriesSQL: string, postsKeyByTypePluralName: PostsKeyByTypePluralName, hasMorePages: bool, queryPlan: array}
154+
* @return array{rawSQL: string, postsKeyByTypePluralName: PostsKeyByTypePluralName, hasMorePages: bool, queryPlan: array}
155155
*/
156-
private function getUnionQueryResult(Collection $queries, bool $isOrderByDesc, int $maxResults): array
156+
private function getPostQueriesResult(Collection $queries, bool $isOrderByDesc, int $maxResults): array
157157
{
158-
/** @var DBALQueryBuilder $unionOfQueries */
159-
// https://stackoverflow.com/questions/36959801/doctrine-orm-querybuilder-or-dbal-querybuilder
160-
$unionOfQueries = $queries->reduce(function (?DBALQueryBuilder $dbalQueryBuilder, QueryBuilder $ormQueryBuilder) {
161-
$ormQuery = $ormQueryBuilder->getQuery();
162-
$ormQuery->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, InterpolateParametersSQLOutputWalker::class);
163-
$sql = $ormQuery->getSQL();
164-
if ($dbalQueryBuilder === null) {
165-
return $ormQueryBuilder->getEntityManager()->getConnection()
166-
->createQueryBuilder()->union($sql);
167-
}
168-
return $dbalQueryBuilder->addUnion($sql, UnionType::ALL);
169-
});
158+
$getParametersInterpolatedRawSQL = static function (QueryBuilder $queryBuilder) {
159+
$query = $queryBuilder->getQuery();
160+
$query->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, InterpolateParametersSQLOutputWalker::class);
161+
return $query->getSQL();
162+
};
170163
$firstQuery = $queries->first();
164+
/** @var DBALQueryBuilder|QueryBuilder $flattedQueryBuilder */
165+
$flattedQueryBuilder = $queries->count() === 1
166+
? $firstQuery
167+
// https://stackoverflow.com/questions/36959801/doctrine-orm-querybuilder-or-dbal-querybuilder
168+
: $queries->reduce(function (?DBALQueryBuilder $dbalQueryBuilder, QueryBuilder $ormQueryBuilder) use ($getParametersInterpolatedRawSQL) {
169+
$sql = $getParametersInterpolatedRawSQL($ormQueryBuilder);
170+
if ($dbalQueryBuilder === null) {
171+
return $ormQueryBuilder->getEntityManager()->getConnection()
172+
->createQueryBuilder()->union($sql);
173+
}
174+
return $dbalQueryBuilder->addUnion($sql, UnionType::ALL);
175+
});
171176

172177
/** @var array{key-of<UnionPostKey>, string} $firstQueryFieldAliases */
173178
// field name and aliases in the first query in a union will override any other queries in union
174179
$firstQueryFieldAliases = array_flip((new Parser($firstQuery->getQuery()))
175180
->parse()->getResultSetMapping()->scalarMappings);
176-
$unionOfQueries = $unionOfQueries
177-
->addOrderBy($firstQueryFieldAliases['orderByField'], $isOrderByDesc === true ? 'DESC' : 'ASC')
178-
->addOrderBy($firstQueryFieldAliases['postId'])
179-
->setMaxResults($maxResults);
180-
$unionOfQueriesSQL = (new SqlFormatter(new NullHighlighter()))->format($unionOfQueries->getSQL());
181+
if ($flattedQueryBuilder instanceof DBALQueryBuilder) {
182+
$flattedQueryBuilder = $flattedQueryBuilder
183+
->addOrderBy($firstQueryFieldAliases['orderByField'], $isOrderByDesc === true ? 'DESC' : 'ASC')
184+
->addOrderBy($firstQueryFieldAliases['postId'])
185+
->setMaxResults($maxResults);
186+
}
187+
$rawSQL = (new SqlFormatter(new NullHighlighter()))->format(match (true) {
188+
$flattedQueryBuilder instanceof DBALQueryBuilder => $flattedQueryBuilder->getSQL(),
189+
$flattedQueryBuilder instanceof QueryBuilder => $getParametersInterpolatedRawSQL($flattedQueryBuilder)
190+
});
181191

182192
$rsm = new ResultSetMapping();
183193
foreach ($firstQueryFieldAliases as $fieldName => $fieldAlias) {
184194
$rsm->addScalarResult($fieldAlias, $fieldName);
185195
}
186196

187197
['result' => $result, 'hasMorePages' => $hasMorePages, 'queryPlan' => $queryPlan] = $this->getQueryResult(
188-
$firstQuery->getEntityManager()->createNativeQuery($unionOfQueriesSQL, $rsm),
198+
$firstQuery->getEntityManager()->createNativeQuery($rawSQL, $rsm),
189199
$this->perPageItems
190200
);
191201
/** @var PostsKeyByTypePluralName $postsKeyByTypePluralName */
@@ -211,7 +221,7 @@ private function getUnionQueryResult(Collection $queries, bool $isOrderByDesc, i
211221
Helper::abortAPIIf(40401, $postsKeyByTypePluralName->every(static fn(Collection $i) => $i->isEmpty()));
212222

213223
return [
214-
'unionOfQueriesSQL' => $unionOfQueriesSQL,
224+
'rawSQL' => $rawSQL,
215225
'postsKeyByTypePluralName' => $postsKeyByTypePluralName,
216226
'hasMorePages' => $hasMorePages,
217227
'queryPlan' => $queryPlan

fe/browserslist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# https://browsersl.ist
12
defaults
23
> 0.1% in CN
34
fully supports es6-module and fully supports url

fe/eslint.config.js

Lines changed: 71 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -71,117 +71,117 @@ const rules = {
7171
},
7272
'@stylistic/eslint-plugin-plus@1.5.1': {
7373
optin: {
74-
// '@stylistic/indent-binary-ops': ['error', 4],
75-
'@stylistic/type-generic-spacing': 'error',
76-
'@stylistic/type-named-tuple-spacing': 'error',
74+
// '@stylistic/indent-binary-ops': ['warn', 4],
75+
'@stylistic/type-generic-spacing': 'warn',
76+
'@stylistic/type-named-tuple-spacing': 'warn',
7777
},
7878
},
7979
'@stylistic/eslint-plugin@1.5.1': {
8080
optin: {
81-
'@stylistic/dot-location': ['error', 'property'],
82-
'@stylistic/no-floating-decimal': 'error',
83-
'@stylistic/no-multi-spaces': 'error',
84-
'@stylistic/wrap-iife': ['error', 'inside'],
85-
'@stylistic/array-bracket-newline': ['error', 'consistent'],
86-
'@stylistic/array-bracket-spacing': 'error',
87-
'@stylistic/array-element-newline': ['error', 'consistent'],
88-
'@stylistic/block-spacing': 'error',
89-
'@stylistic/comma-style': 'error',
90-
'@stylistic/computed-property-spacing': 'error',
91-
'@stylistic/eol-last': 'error',
92-
'@stylistic/function-call-argument-newline': ['error', 'consistent'],
93-
'@stylistic/function-paren-newline': ['error', 'consistent'],
94-
'@stylistic/jsx-quotes': 'error',
95-
'@stylistic/key-spacing': ['error', {
81+
'@stylistic/dot-location': ['warn', 'property'],
82+
'@stylistic/no-floating-decimal': 'warn',
83+
'@stylistic/no-multi-spaces': 'warn',
84+
'@stylistic/wrap-iife': ['warn', 'inside'],
85+
'@stylistic/array-bracket-newline': ['warn', 'consistent'],
86+
'@stylistic/array-bracket-spacing': 'warn',
87+
'@stylistic/array-element-newline': ['warn', 'consistent'],
88+
'@stylistic/block-spacing': 'warn',
89+
'@stylistic/comma-style': 'warn',
90+
'@stylistic/computed-property-spacing': 'warn',
91+
'@stylistic/eol-last': 'warn',
92+
'@stylistic/function-call-argument-newline': ['warn', 'consistent'],
93+
'@stylistic/function-paren-newline': ['warn', 'consistent'],
94+
'@stylistic/jsx-quotes': 'warn',
95+
'@stylistic/key-spacing': ['warn', {
9696
beforeColon: false,
9797
afterColon: true,
9898
mode: 'strict',
9999
}],
100-
'@stylistic/linebreak-style': 'error',
101-
'@stylistic/max-statements-per-line': ['error', { max: 2 }],
102-
'@stylistic/multiline-ternary': ['error', 'always-multiline'],
103-
'@stylistic/new-parens': 'error',
104-
'@stylistic/no-mixed-operators': 'error',
105-
'@stylistic/no-multiple-empty-lines': ['error', { max: 1 }],
106-
'@stylistic/no-tabs': 'error',
107-
'@stylistic/no-trailing-spaces': 'error',
108-
'@stylistic/no-whitespace-before-property': 'error',
109-
'@stylistic/nonblock-statement-body-position': ['error', 'below'],
110-
'@stylistic/object-curly-newline': ['error', {
100+
'@stylistic/linebreak-style': 'warn',
101+
'@stylistic/max-statements-per-line': ['warn', { max: 2 }],
102+
'@stylistic/multiline-ternary': ['warn', 'always-multiline'],
103+
'@stylistic/new-parens': 'warn',
104+
'@stylistic/no-mixed-operators': 'warn',
105+
'@stylistic/no-multiple-empty-lines': ['warn', { max: 1 }],
106+
'@stylistic/no-tabs': 'warn',
107+
'@stylistic/no-trailing-spaces': 'warn',
108+
'@stylistic/no-whitespace-before-property': 'warn',
109+
'@stylistic/nonblock-statement-body-position': ['warn', 'below'],
110+
'@stylistic/object-curly-newline': ['warn', {
111111
multiline: true,
112112
consistent: true,
113113
}],
114-
'@stylistic/object-property-newline': ['error', { allowAllPropertiesOnSameLine: true }],
115-
'@stylistic/operator-linebreak': ['error', 'before', { overrides: { '=': 'after' } }],
116-
'@stylistic/padded-blocks': ['error', 'never'],
117-
'@stylistic/quote-props': ['error', 'as-needed'],
118-
'@stylistic/semi-spacing': 'error',
119-
'@stylistic/semi-style': 'error',
120-
'@stylistic/space-before-blocks': 'error',
121-
'@stylistic/space-in-parens': 'error',
122-
'@stylistic/space-unary-ops': ['error', {
114+
'@stylistic/object-property-newline': ['warn', { allowAllPropertiesOnSameLine: true }],
115+
'@stylistic/operator-linebreak': ['warn', 'before', { overrides: { '=': 'after' } }],
116+
'@stylistic/padded-blocks': ['warn', 'never'],
117+
'@stylistic/quote-props': ['warn', 'as-needed'],
118+
'@stylistic/semi-spacing': 'warn',
119+
'@stylistic/semi-style': 'warn',
120+
'@stylistic/space-before-blocks': 'warn',
121+
'@stylistic/space-in-parens': 'warn',
122+
'@stylistic/space-unary-ops': ['warn', {
123123
words: true,
124124
nonwords: false,
125125
}],
126126

127127
// https://github.com/typescript-eslint/typescript-eslint/issues/600#issuecomment-499979248
128-
'@stylistic/spaced-comment': ['error', 'always', { markers: ['/'] }],
129-
'@stylistic/switch-colon-spacing': 'error',
130-
'@stylistic/template-tag-spacing': 'error',
131-
'@stylistic/arrow-parens': ['error', 'as-needed'],
132-
'@stylistic/arrow-spacing': 'error',
133-
'@stylistic/generator-star-spacing': ['error', {
128+
'@stylistic/spaced-comment': ['warn', 'always', { markers: ['/'] }],
129+
'@stylistic/switch-colon-spacing': 'warn',
130+
'@stylistic/template-tag-spacing': 'warn',
131+
'@stylistic/arrow-parens': ['warn', 'as-needed'],
132+
'@stylistic/arrow-spacing': 'warn',
133+
'@stylistic/generator-star-spacing': ['warn', {
134134
before: false,
135135
after: true,
136136
method: {
137137
before: true,
138138
after: false,
139139
},
140140
}],
141-
'@stylistic/no-confusing-arrow': 'error',
142-
'@stylistic/rest-spread-spacing': 'error',
143-
'@stylistic/template-curly-spacing': 'error',
144-
'@stylistic/yield-star-spacing': 'error',
145-
'@stylistic/lines-around-comment': ['error', {
141+
'@stylistic/no-confusing-arrow': 'warn',
142+
'@stylistic/rest-spread-spacing': 'warn',
143+
'@stylistic/template-curly-spacing': 'warn',
144+
'@stylistic/yield-star-spacing': 'warn',
145+
'@stylistic/lines-around-comment': ['warn', {
146146
beforeBlockComment: true,
147147
beforeLineComment: true,
148148
allowBlockStart: true,
149149
allowObjectStart: true,
150150
allowArrayStart: true,
151151
allowClassStart: true,
152152
}],
153-
'@stylistic/brace-style': ['error', '1tbs', { allowSingleLine: true }],
154-
'@stylistic/comma-dangle': 'error',
155-
'@stylistic/comma-spacing': 'error',
156-
'@stylistic/func-call-spacing': 'error',
157-
'@stylistic/indent': 'error',
158-
'@stylistic/keyword-spacing': 'error',
159-
'@stylistic/no-extra-parens': ['error', 'all', {
153+
'@stylistic/brace-style': ['warn', '1tbs', { allowSingleLine: true }],
154+
'@stylistic/comma-dangle': 'warn',
155+
'@stylistic/comma-spacing': 'warn',
156+
'@stylistic/func-call-spacing': 'warn',
157+
'@stylistic/indent': 'warn',
158+
'@stylistic/keyword-spacing': 'warn',
159+
'@stylistic/no-extra-parens': ['warn', 'all', {
160160
ignoreJSX: 'multi-line',
161161
enforceForArrowConditionals: false, // https://github.com/eslint/eslint/issues/6196#issuecomment-333344466
162162
nestedBinaryExpressions: false, // https://github.com/eslint/eslint/issues/8891#issuecomment-313618753
163163
}],
164-
'@stylistic/object-curly-spacing': ['error', 'always'],
165-
'@stylistic/quotes': ['error', 'single', { avoidEscape: true }],
166-
'@stylistic/semi': ['error', 'always', { omitLastInOneLineBlock: true }],
167-
'@stylistic/space-before-function-paren': ['error', {
164+
'@stylistic/object-curly-spacing': ['warn', 'always'],
165+
'@stylistic/quotes': ['warn', 'single', { avoidEscape: true }],
166+
'@stylistic/semi': ['warn', 'always', { omitLastInOneLineBlock: true }],
167+
'@stylistic/space-before-function-paren': ['warn', {
168168
anonymous: 'always',
169169
named: 'never',
170170
asyncArrow: 'always',
171171
}],
172-
'@stylistic/space-infix-ops': ['error', { int32Hint: false }],
172+
'@stylistic/space-infix-ops': ['warn', { int32Hint: false }],
173173
'@stylistic/padding-line-between-statements': [
174-
'error',
174+
'warn',
175175
{ blankLine: 'always', prev: '*', next: 'return' },
176176
],
177-
'@stylistic/member-delimiter-style': ['error', {
177+
'@stylistic/member-delimiter-style': ['warn', {
178178
multiline: { delimiter: 'comma', requireLast: false },
179179
singleline: { delimiter: 'comma', requireLast: false },
180180
}],
181181

182182
// https://github.com/eslint-stylistic/eslint-stylistic/issues/249
183-
// '@stylistic/type-annotation-spacing': 'error',
184-
'@stylistic/multiline-comment-style': ['error', 'separate-lines'],
183+
// '@stylistic/type-annotation-spacing': 'warn',
184+
'@stylistic/multiline-comment-style': ['warn', 'separate-lines'],
185185
},
186186
},
187187
'eslint@8.56.0': {
@@ -419,15 +419,16 @@ const rules = {
419419
'vue/attributes-order': ['error', {
420420
order: [
421421
'DEFINITION',
422-
['LIST_RENDERING', 'UNIQUE'],
422+
'LIST_RENDERING',
423+
'UNIQUE',
423424
'CONDITIONALS',
424425
'RENDER_MODIFIERS',
425-
'TWO_WAY_BINDING',
426-
'EVENTS',
427426
'SLOT',
427+
'TWO_WAY_BINDING',
428428
'OTHER_DIRECTIVES',
429-
'OTHER_ATTR',
429+
'EVENTS',
430430
'GLOBAL',
431+
'OTHER_ATTR',
431432
'CONTENT',
432433
],
433434
}],
@@ -609,7 +610,7 @@ export default withNuxt(defineConfigWithVueTs(
609610
files: ['eslint.config.js'],
610611
plugins: { '@stylistic': pluginStylistic },
611612
rules: {
612-
'@stylistic/comma-dangle': ['error', 'always-multiline'],
613+
'@stylistic/comma-dangle': ['warn', 'always-multiline'],
613614
'@typescript-eslint/naming-convention': 'off',
614615
'@typescript-eslint/no-unsafe-call': 'off',
615616
'@typescript-eslint/no-unsafe-argument': 'off',

fe/nuxt.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ export default defineNuxtConfig({
7272
}
7373
}
7474
},
75+
postcss: {
76+
// eslint-disable-next-line @typescript-eslint/naming-convention
77+
plugins: { 'postcss-preset-env': { minimumVendorImplementations: 2 } }
78+
},
7579
experimental: {
7680
viewTransition: true,
7781
respectNoSSRHeader: true,

fe/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"dev": "NODE_OPTIONS=--stack-trace-limit=100 nuxt dev",
99
"generate": "nuxt generate",
1010
"preview": "nuxt preview",
11-
"postinstall": "nuxt prepare"
11+
"postinstall": "nuxt prepare",
12+
"lint": "eslint; stylelint '**/*.vue'; stylelint '**/*.css'"
1213
},
1314
"dependencies": {
1415
"@ant-design-vue/nuxt": "^1.4.6",
@@ -36,6 +37,7 @@
3637
"requestidlecallback": "^0.3.0",
3738
"scroll-into-view-if-needed": "^3.1.0",
3839
"serialize-error": "^12.0.0",
40+
"style-observer": "^0.1.1",
3941
"tippy.js": "^6.3.7",
4042
"v-viewer": "^3.0.21",
4143
"viewerjs": "^1.11.7",
@@ -65,6 +67,7 @@
6567
"eslint-plugin-pinia": "^0.4.1",
6668
"eslint-plugin-vue": "^10.1.0",
6769
"postcss-html": "^1.8.0",
70+
"postcss-preset-env": "^10.2.1",
6871
"schema-dts": "^1.1.5",
6972
"stats.js": "^0.17.0",
7073
"stylelint": "^16.20.0",

fe/src/api/post.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ export interface Thread extends Post {
3232
shareCount: UInt,
3333
zan: ObjUnknown | null,
3434
geolocation: ObjUnknown | null,
35-
authorPhoneType: string
35+
authorPhoneType: string,
36+
isMatchQuery: boolean
3637
}
3738
export interface Reply extends Post {
3839
pid: Pid,
@@ -41,7 +42,8 @@ export interface Reply extends Post {
4142
subReplyCount: UInt,
4243
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
4344
isFold: UInt | 0 | 6,
44-
geolocation: ObjUnknown | null
45+
geolocation: ObjUnknown | null,
46+
isMatchQuery: boolean
4547
}
4648
export interface SubReply extends Post {
4749
pid: Pid,

0 commit comments

Comments
 (0)