浏览代码

Add experimental GraphQL list members parser

Zed 4 年之前
父节点
当前提交
a54d6aa1eb

+ 1 - 1
src/api.nim

@@ -37,7 +37,7 @@ proc getGraphListMembers*(list: List; after=""): Future[Result[User]] {.async.}
       "withSuperFollowsTweetFields": false
     }
     url = graphListMembers ? {"variables": $variables}
-  result = parseGraphListMembers(await fetch(url, Api.listMembers), after)
+  result = parseGraphListMembers(await fetchRaw(url, Api.listMembers), after)
 
 proc getListTimeline*(id: string; after=""): Future[Timeline] {.async.} =
   if id.len == 0: return

+ 21 - 2
src/experimental/parser/graphql.nim

@@ -1,8 +1,27 @@
 import jsony
-import ../types/graphql, user
-from ../../types import User
+import user, ../types/[graphuser, graphlistmembers]
+from ../../types import User, Result, Query, QueryKind
 
 proc parseGraphUser*(json: string): User =
   let raw = json.fromJson(GraphUser)
   result = toUser raw.data.user.result.legacy
   result.id = raw.data.user.result.restId
+
+proc parseGraphListMembers*(json, cursor: string): Result[User] =
+  result = Result[User](
+    beginning: cursor.len == 0,
+    query: Query(kind: userList)
+  )
+
+  let raw = json.fromJson(GraphListMembers)
+  for instruction in raw.data.list.membersTimeline.timeline.instructions:
+    if instruction.kind == "TimelineAddEntries":
+      for entry in instruction.entries:
+        case entry.content.entryType
+        of TimelineTimelineItem:
+          let userResult = entry.content.itemContent.userResults.result
+          if userResult.restId.len > 0:
+            result.content.add toUser userResult.legacy
+        of TimelineTimelineCursor:
+          if entry.content.cursorType == "Bottom":
+            result.bottom = entry.content.value

+ 31 - 0
src/experimental/types/graphlistmembers.nim

@@ -0,0 +1,31 @@
+import graphuser
+
+type
+  GraphListMembers* = object
+    data*: tuple[list: List]
+
+  List = object
+    membersTimeline*: tuple[timeline: Timeline]
+
+  Timeline = object
+    instructions*: seq[Instruction]
+
+  Instruction = object
+    kind*: string
+    entries*: seq[tuple[content: Content]]
+
+  ContentEntryType* = enum
+    TimelineTimelineItem
+    TimelineTimelineCursor
+
+  Content = object
+    case entryType*: ContentEntryType
+    of TimelineTimelineItem:
+      itemContent*: tuple[userResults: UserData]
+    of TimelineTimelineCursor:
+      value*: string
+      cursorType*: string
+
+proc renameHook*(v: var Instruction; fieldName: var string) =
+  if fieldName == "type":
+    fieldName = "kind"

+ 0 - 12
src/experimental/types/graphql.nim

@@ -1,12 +0,0 @@
-import user
-
-type
-  GraphUserResult* = object
-    legacy*: RawUser
-    restId*: string
-
-  GraphUserData* = object
-    result*: GraphUserResult
-
-  GraphUser* = object
-    data*: tuple[user: GraphUserData]

+ 12 - 0
src/experimental/types/graphuser.nim

@@ -0,0 +1,12 @@
+import user
+
+type
+  GraphUser* = object
+    data*: tuple[user: UserData]
+
+  UserData* = object
+    result*: UserResult
+
+  UserResult = object
+    legacy*: RawUser
+    restId*: string

+ 0 - 19
src/parser.nim

@@ -45,25 +45,6 @@ proc parseGraphList*(js: JsonNode): List =
     banner: list{"custom_banner_media", "media_info", "url"}.getImageStr
   )
 
-proc parseGraphListMembers*(js: JsonNode; cursor: string): Result[User] =
-  result = Result[User](
-    beginning: cursor.len == 0,
-    query: Query(kind: userList)
-  )
-
-  if js.isNull: return
-
-  let root = js{"data", "list", "members_timeline", "timeline", "instructions"}
-  for instruction in root:
-    if instruction{"type"}.getStr == "TimelineAddEntries":
-      for entry in instruction{"entries"}:
-        let content = entry{"content"}
-        if content{"entryType"}.getStr == "TimelineTimelineItem":
-          with legacy, content{"itemContent", "user_results", "result", "legacy"}:
-            result.content.add parseUser(legacy)
-        elif content{"cursorType"}.getStr == "Bottom":
-          result.bottom = content{"value"}.getStr
-
 
 proc parsePoll(js: JsonNode): Poll =
   let vals = js{"binding_values"}