Skip to content

Commit f43c54f

Browse files
committed
scratch with fun zod
1 parent b76af78 commit f43c54f

File tree

3 files changed

+275
-2
lines changed

3 files changed

+275
-2
lines changed

workspaces/leetcode-api/graphql-codegen.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ const commonTypeScriptPluginConfig: GraphQLCodegen.PluginConfig = {
1111
skipTypename: true,
1212
useTypeImports: true,
1313

14+
scalars: {
15+
JSONString: {
16+
input: "unknown",
17+
output: "string",
18+
},
19+
},
20+
1421
// TODO: add strictScalars: true
1522
};
1623

workspaces/leetcode-api/src/api/question-list/query.graphql

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,99 @@ query QuestionList(
1111
filters: $filters
1212
) {
1313
data {
14+
acRate
15+
adminUrl
16+
allowDiscuss
17+
article
18+
articleTopicId
19+
boundTopicId
20+
canSeeQuestion
21+
categoryTitle
22+
challengeQuestion {
23+
__typename
24+
}
25+
challengeQuestionsV2 {
26+
__typename
27+
}
28+
codeDefinition
29+
codeSnippets {
30+
__typename
31+
}
32+
companyTags {
33+
__typename
34+
}
35+
companyTagStats
36+
companyTagStatsV2
37+
content
38+
contributors {
39+
__typename
40+
}
41+
dataSchemas
1442
difficulty
43+
discussionCount
44+
dislikes
45+
enableDebugger
46+
enableRunCode
47+
enableSubmit
48+
enableTestMode
49+
envInfo
50+
exampleTestcaseList
51+
exampleTestcases
52+
freqBar
53+
frequency
54+
frontendPreviews
55+
hasFrontendPreview
56+
hasSolution
57+
hasVideoSolution
58+
hide
59+
hideLastTestcases {
60+
__typename
61+
}
62+
hints
63+
infoVerified
64+
interpretUrl
65+
isFavor
66+
isLiked
1567
isPaidOnly
68+
judgerAvailable
69+
judgeType
70+
langToValidPlayground
71+
libraryUrl
72+
likes
73+
metaData
74+
mysqlSchemas
75+
nextChallenges {
76+
__typename
77+
}
78+
note
79+
questionDetailUrl
1680
questionFrontendId
81+
questionId
82+
questionTitle
83+
questionTitleSlug
84+
questionType
85+
randomQuestionUrl
86+
sampleTestCase
87+
sessionId
88+
# similarQuestionList {
89+
# __typename
90+
# }
91+
similarQuestions
92+
solution {
93+
__typename
94+
}
95+
solutionNum
96+
stats
97+
status
98+
submitUrl
1799
title
18100
titleSlug
101+
topicTags {
102+
__typename
103+
}
104+
translatedContent
105+
translatedTitle
106+
urlManager
19107
}
20108
totalNum
21109
}

workspaces/leetcode-api/src/scripts/scrape-graphql-schema/patchGraphQLSchema.ts

Lines changed: 180 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
import type { ReadonlyDeep } from "type-fest";
22

33
import { replaceInMap } from "@code-chronicles/util/replaceInMap";
4+
import { z } from "zod";
45

56
import type { LeetCodeGraphQLType } from "../../fetchGraphQLTypeInformation.ts";
67
import { markFieldsNonNull } from "./markFieldsNonNull.ts";
78

89
const FIELDS_TO_MARK_NON_NULL: ReadonlyDeep<Record<string, string[]>> = {
9-
Query: ["activeDailyCodingChallengeQuestion", "questionList", "recentAcSubmissionList", ],
10-
QuestionNode: ["difficulty", "isPaidOnly", "questionFrontendId"],
10+
Query: [
11+
"activeDailyCodingChallengeQuestion",
12+
"questionList",
13+
"recentAcSubmissionList",
14+
],
15+
QuestionNode: [
16+
"acRate",
17+
"allowDiscuss",
18+
"difficulty",
19+
"isPaidOnly",
20+
"questionFrontendId",
21+
],
1122
SubmissionDumpNode: ["id", "timestamp", "title", "titleSlug"],
1223
};
1324

@@ -26,3 +37,170 @@ export function patchGraphQLSchema(
2637

2738
return typeInfos;
2839
}
40+
41+
const zodType = z.object({
42+
acRate: z.number().nonnegative(),
43+
adminUrl: z.null(),
44+
allowDiscuss: z.literal(true),
45+
// { id: 1906, url: '/articles/debounce/', topicId: 3536814 }
46+
article: z
47+
.string()
48+
.transform((s) => JSON.parse(s))
49+
.nullable(),
50+
articleTopicId: z.null(),
51+
boundTopicId: z.null(),
52+
canSeeQuestion: z.boolean(),
53+
categoryTitle: z.enum([
54+
"Algorithms",
55+
"Concurrency",
56+
"Database",
57+
"JavaScript",
58+
"Shell",
59+
"pandas",
60+
]),
61+
challengeQuestion: z.object({}).nullable(),
62+
/*
63+
[
64+
{
65+
value: 'cpp',
66+
text: 'C++',
67+
defaultCode: 'class Solution {\n' +
68+
'public:\n' +
69+
' long long maximumTotalSum(vector<int>& maximumHeight) {\n' +
70+
' \n' +
71+
' }\n' +
72+
'};'
73+
},
74+
{
75+
value: 'java',
76+
text: 'Java',
77+
defaultCode: 'class Solution {\n' +
78+
' public long maximumTotalSum(int[] maximumHeight) {\n' +
79+
' \n' +
80+
' }\n' +
81+
'}'
82+
},
83+
*/
84+
codeDefinition: z
85+
.string()
86+
.transform((s) => JSON.parse(s))
87+
.nullable(),
88+
codeSnippets: z.array(z.object({})).nullable(),
89+
companyTags: z.null(),
90+
companyTagStats: z.null(),
91+
companyTagStatsV2: z.null(),
92+
content: z.string().nullable(),
93+
contributors: z.tuple([]),
94+
dataSchemas: z.array(z.string()),
95+
difficulty: z.enum(["Easy", "Medium", "Hard"]),
96+
discussionCount: z.number().int().nonnegative(),
97+
dislikes: z.number().int().nonnegative(),
98+
enableDebugger: z.boolean(),
99+
enableRunCode: z.boolean(),
100+
enableSubmit: z.boolean(),
101+
enableTestMode: z.boolean(),
102+
103+
/*
104+
105+
{
106+
cpp: [
107+
'C++',
108+
'<p>Compiled with <code> clang 17 </code> using the latest C++ 23 standard, and <code>libstdc++</code> provided by GCC 13.</p>\r\n' +
109+
'\r\n' +
110+
'<p>Your code is compiled with level two optimization (<code>-O2</code>). <a href="https://github.com/google/sanitizers/wiki/AddressSanitizer" target="_blank">AddressSanitizer</a> is also enabled to help detect out-of-bounds and use-after-free bugs.</p>\r\n' +
111+
'\r\n' +
112+
'<p>Most standard library headers are already included automatically for your convenience.</p>'
113+
],
114+
java: [
115+
'Java',
116+
'<p><code>OpenJDK 21</code>. Using compile arguments: <code>--enable-preview --release 21</code></p>\r\n' +
117+
'\r\n' +
118+
'<p>Most standard library headers are already included automatically for your convenience.</p>\r\n' +
119+
'<p>Includes <code>Pair</code> class from https://docs.oracle.com/javase/8/javafx/api/javafx/util/Pair.html.</p>'
120+
],
121+
122+
123+
*/
124+
envInfo: z.string().transform((s) => JSON.parse(s)),
125+
exampleTestcaseList: z.array(z.string()),
126+
exampleTestcases: z.string(),
127+
freqBar: z.null(),
128+
frequency: z.literal(0),
129+
130+
// {}
131+
frontendPreviews: z
132+
.literal("{}")
133+
.transform((s) => JSON.parse(s))
134+
.nullable(),
135+
hasFrontendPreview: z.literal(false),
136+
hasSolution: z.boolean(),
137+
hasVideoSolution: z.boolean(),
138+
hide: z.boolean(),
139+
hideLastTestcases: z.null(),
140+
hints: z.array(z.string()),
141+
infoVerified: z.boolean(),
142+
interpretUrl: z.string(),
143+
isFavor: z.literal(false),
144+
isLiked: z.boolean().nullable(),
145+
isPaidOnly: z.boolean(),
146+
judgerAvailable: z.literal(true),
147+
judgeType: z.enum(["large", "small"]),
148+
149+
// {"cpp": true, "java": true, "python": true, "python3": true, "mysql": false, "mssql": false, "oraclesql": false, "c": false, "csharp": false, "javascript": false, "typescript": false, "bash": false, "php": false, "swift": false, "kotlin": false, "dart": false, "golang": false, "ruby": false, "scala": false, "html": false, "pythonml": false, "rust": false, "racket": false, "erlang": false, "elixir": false, "pythondata": false, "react": false, "vanillajs": false, "postgresql": false, "cangjie": false}
150+
langToValidPlayground: z
151+
.string()
152+
.transform((s) => JSON.parse(s))
153+
.nullable(),
154+
libraryUrl: z.null(),
155+
likes: z.number().int().nonnegative(),
156+
157+
/*
158+
{"mysql": ["CREATE TABLE If not exists Drivers (\n driver_id INT ,\n name VARCHAR(100),\n age INT,\n experience INT,\n accidents INT\n)", "CREATE TABLE If not exists Vehicles (\n vehicle_id INT ,\n driver_id INT,\n model VARCHAR(100),\n fuel_type VARCHAR(50),\n mileage INT)", "CREATE TABLE If not exists Trips (\n trip_id INT ,\n vehicle_id INT,\n distance INT,\n duration INT,\n rating INT\n)"], "mssql": ["CREATE TABLE Drivers (\n driver_id INT,\n name NVARCHAR(100),\n age INT,\n experience INT,\n accidents INT\n)", "CREATE TABLE Vehicles (\n vehicle_id INT,\n driver_id INT,\n model NVARCHAR(100),\n fuel_type NVARCHAR(50),\n mileage INT\n)", "CREATE TABLE Trips (\n trip_id INT,\n vehicle_id INT,\n distance INT,\n duration INT,\n rating INT CHECK (rating BETWEEN 1 AND 5)\n)"], "oraclesql": ["CREATE TABLE Drivers (\n driver_id NUMBER,\n name VARCHAR2(100),\n age NUMBER,\n experience NUMBER,\n accidents NUMBER\n)", "CREATE TABLE Vehicles (\n vehicle_id NUMBER,\n driver_id NUMBER,\n model VARCHAR2(100),\n fuel_type VARCHAR2(50),\n mileage NUMBER\n)", "\nCREATE TABLE Trips (\n trip_id NUMBER,\n vehicle_id NUMBER,\n distance NUMBER,\n duration NUMBER,\n rating NUMBER )"], "database": true, "name": "get_top_performing_drivers", "pythondata": ["Drivers = pd.DataFrame({\n 'driver_id': pd.Series(dtype='int'),\n 'name': pd.Series(dtype='str'),\n 'age': pd.Series(dtype='int'),\n 'experience': pd.Series(dtype='int'),\n 'accidents': pd.Series(dtype='int')\n})", "Vehicles = pd.DataFrame({\n 'vehicle_id': pd.Series(dtype='int'),\n 'driver_id': pd.Series(dtype='int'),\n 'model': pd.Series(dtype='str'),\n 'fuel_type': pd.Series(dtype='str'),\n 'mileage': pd.Series(dtype='int')\n})", "Trips = pd.DataFrame({\n 'trip_id': pd.Series(dtype='int'),\n 'vehicle_id': pd.Series(dtype='int'),\n 'distance': pd.Series(dtype='int'),\n 'duration': pd.Series(dtype='int'),\n 'rating': pd.Series(dtype='int')\n})"], "postgresql": ["CREATE TABLE Drivers (\n driver_id SERIAL PRIMARY KEY,\n name VARCHAR(100),\n age INT,\n experience INT,\n accidents INT\n);\n", "CREATE TABLE Vehicles (\n vehicle_id SERIAL PRIMARY KEY,\n driver_id INT,\n model VARCHAR(100),\n fuel_type VARCHAR(50),\n mileage INT\n);\n", "CREATE TABLE Trips (\n trip_id SERIAL PRIMARY KEY,\n vehicle_id INT,\n distance INT,\n duration INT,\n rating INT CHECK (rating BETWEEN 1 AND 5)\n);\n", "TRUNCATE TABLE Vehicles, Drivers;\n"], "database_schema": {"Drivers": {"driver_id": "INT", "name": "VARCHAR(100)", "age": "INT", "experience": "INT", "accidents": "INT"}, "Vehicles": {"vehicle_id": "INT", "driver_id": "INT", "model": "VARCHAR(100)", "fuel_type": "VARCHAR(50)", "mileage": "INT"}, "Trips": {"trip_id": "INT", "vehicle_id": "INT", "distance": "INT", "duration": "INT", "rating": "INT"}}}
159+
160+
{
161+
"name": "maxGoodNumber",
162+
"params": [
163+
{
164+
"name": "nums",
165+
"type": "integer[]"
166+
}
167+
],
168+
"return": {
169+
"type": "integer"
170+
}
171+
}
172+
173+
*/
174+
175+
metaData: z.string().transform((s) => JSON.parse(s)),
176+
mysqlSchemas: z.array(z.string()),
177+
nextChallenges: z.array(z.object({})),
178+
note: z.null(),
179+
questionDetailUrl: z.string(),
180+
questionFrontendId: z.string(),
181+
questionId: z.string(),
182+
questionTitle: z.string(),
183+
questionTitleSlug: z.string(),
184+
questionType: z.literal("Main"),
185+
randomQuestionUrl: z.literal("/problems/random-one-question/"),
186+
sampleTestCase: z.string(),
187+
sessionId: z.literal("0"),
188+
189+
// [{"title": "Zigzag Iterator", "titleSlug": "zigzag-iterator", "difficulty": "Medium", "translatedTitle": null}, {"title": "Minimum Additions to Make Valid String", "titleSlug": "minimum-additions-to-make-valid-string", "difficulty": "Medium", "translatedTitle": null}]
190+
similarQuestions: z.string().transform((s) => JSON.parse(s)),
191+
solution: z.object({}).nullable(),
192+
193+
solutionNum: z.number().int().nonnegative(),
194+
195+
// {"totalAccepted": "9K", "totalSubmission": "14.9K", "totalAcceptedRaw": 9003, "totalSubmissionRaw": 14933, "acRate": "60.3%"}
196+
stats: z.string().transform((s) => JSON.parse(s)),
197+
submitUrl: z.string(),
198+
title: z.string(),
199+
titleSlug: z.string(),
200+
topicTags: z.array(z.object({})),
201+
translatedContent: z.null(),
202+
translatedTitle: z.null(),
203+
204+
// {"account_login": "/accounts/login/", "maintenance": "/maintenance/", "profile": "/profile/"}
205+
urlManager: z.string().transform((s) => JSON.parse(s)),
206+
});

0 commit comments

Comments
 (0)