Fix empty results errors

This commit is contained in:
Syer10
2023-04-07 00:02:00 -04:00
parent 671466a737
commit 0b88207ad5
11 changed files with 197 additions and 81 deletions

View File

@@ -99,7 +99,7 @@ class CategoryQuery {
andFilterWithCompareEntity(CategoryTable.id, id), andFilterWithCompareEntity(CategoryTable.id, id),
andFilterWithCompare(CategoryTable.order, order), andFilterWithCompare(CategoryTable.order, order),
andFilterWithCompareString(CategoryTable.name, name), andFilterWithCompareString(CategoryTable.name, name),
andFilterWithCompare(CategoryTable.isDefault, default), andFilterWithCompare(CategoryTable.isDefault, default)
) )
} }
} }
@@ -191,15 +191,29 @@ class CategoryQuery {
return CategoryNodeList( return CategoryNodeList(
resultsAsType, resultsAsType,
CategoryNodeList.CategoryEdges( if (resultsAsType.isEmpty()) {
cursor = getAsCursor(orderBy, resultsAsType.last()), emptyList()
node = resultsAsType.last() } else {
), listOf(
resultsAsType.first().let {
CategoryNodeList.CategoryEdge(
getAsCursor(orderBy, it),
it
)
},
resultsAsType.last().let {
CategoryNodeList.CategoryEdge(
getAsCursor(orderBy, it),
it
)
}
)
},
pageInfo = PageInfo( pageInfo = PageInfo(
hasNextPage = queryResults.lastKey != resultsAsType.last().id, hasNextPage = queryResults.lastKey != resultsAsType.last().id,
hasPreviousPage = queryResults.firstKey != resultsAsType.first().id, hasPreviousPage = queryResults.firstKey != resultsAsType.first().id,
startCursor = getAsCursor(orderBy, resultsAsType.first()), startCursor = resultsAsType.firstOrNull()?.let { getAsCursor(orderBy, it) },
endCursor = getAsCursor(orderBy, resultsAsType.last()) endCursor = resultsAsType.lastOrNull()?.let { getAsCursor(orderBy, it) }
), ),
totalCount = queryResults.total.toInt() totalCount = queryResults.total.toInt()
) )

View File

@@ -259,15 +259,29 @@ class MangaQuery {
return MangaNodeList( return MangaNodeList(
resultsAsType, resultsAsType,
MangaNodeList.MangaEdges( if (resultsAsType.isEmpty()) {
cursor = getAsCursor(orderBy, resultsAsType.last()), emptyList()
node = resultsAsType.last() } else {
), listOf(
resultsAsType.first().let {
MangaNodeList.MangaEdge(
getAsCursor(orderBy, it),
it
)
},
resultsAsType.last().let {
MangaNodeList.MangaEdge(
getAsCursor(orderBy, it),
it
)
}
)
},
pageInfo = PageInfo( pageInfo = PageInfo(
hasNextPage = queryResults.lastKey != resultsAsType.last().id, hasNextPage = queryResults.lastKey != resultsAsType.last().id,
hasPreviousPage = queryResults.firstKey != resultsAsType.first().id, hasPreviousPage = queryResults.firstKey != resultsAsType.first().id,
startCursor = getAsCursor(orderBy, resultsAsType.first()), startCursor = resultsAsType.firstOrNull()?.let { getAsCursor(orderBy, it) },
endCursor = getAsCursor(orderBy, resultsAsType.last()) endCursor = resultsAsType.lastOrNull()?.let { getAsCursor(orderBy, it) }
), ),
totalCount = queryResults.total.toInt() totalCount = queryResults.total.toInt()
) )

View File

@@ -9,7 +9,7 @@ abstract class NodeList {
abstract val nodes: List<Node> abstract val nodes: List<Node>
@GraphQLDescription("A list of edges which contains the [T] and cursor to aid in pagination.") @GraphQLDescription("A list of edges which contains the [T] and cursor to aid in pagination.")
abstract val edges: Edges abstract val edges: List<Edge>
@GraphQLDescription("Information to aid in pagination.") @GraphQLDescription("Information to aid in pagination.")
abstract val pageInfo: PageInfo abstract val pageInfo: PageInfo
@@ -24,12 +24,12 @@ data class PageInfo(
@GraphQLDescription("When paginating backwards, are there more items?") @GraphQLDescription("When paginating backwards, are there more items?")
val hasPreviousPage: Boolean, val hasPreviousPage: Boolean,
@GraphQLDescription("When paginating backwards, the cursor to continue.") @GraphQLDescription("When paginating backwards, the cursor to continue.")
val startCursor: Cursor, val startCursor: Cursor?,
@GraphQLDescription("When paginating forwards, the cursor to continue.") @GraphQLDescription("When paginating forwards, the cursor to continue.")
val endCursor: Cursor val endCursor: Cursor?
) )
abstract class Edges { abstract class Edge {
@GraphQLDescription("A cursor for use in pagination.") @GraphQLDescription("A cursor for use in pagination.")
abstract val cursor: Cursor abstract val cursor: Cursor

View File

@@ -11,7 +11,7 @@ import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import graphql.schema.DataFetchingEnvironment import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.ResultRow
import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Edges import suwayomi.tachidesk.graphql.server.primitives.Edge
import suwayomi.tachidesk.graphql.server.primitives.Node import suwayomi.tachidesk.graphql.server.primitives.Node
import suwayomi.tachidesk.graphql.server.primitives.NodeList import suwayomi.tachidesk.graphql.server.primitives.NodeList
import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.graphql.server.primitives.PageInfo
@@ -42,23 +42,20 @@ class CategoryType(
data class CategoryNodeList( data class CategoryNodeList(
override val nodes: List<CategoryType>, override val nodes: List<CategoryType>,
override val edges: CategoryEdges, override val edges: List<CategoryEdge>,
override val pageInfo: PageInfo, override val pageInfo: PageInfo,
override val totalCount: Int override val totalCount: Int
) : NodeList() { ) : NodeList() {
data class CategoryEdges( data class CategoryEdge(
override val cursor: Cursor, override val cursor: Cursor,
override val node: CategoryType override val node: CategoryType
) : Edges() ) : Edge()
companion object { companion object {
fun List<CategoryType>.toNodeList(): CategoryNodeList { fun List<CategoryType>.toNodeList(): CategoryNodeList {
return CategoryNodeList( return CategoryNodeList(
nodes = this, nodes = this,
edges = CategoryEdges( edges = getEdges(),
cursor = Cursor(lastIndex.toString()),
node = last()
),
pageInfo = PageInfo( pageInfo = PageInfo(
hasNextPage = false, hasNextPage = false,
hasPreviousPage = false, hasPreviousPage = false,
@@ -68,5 +65,19 @@ data class CategoryNodeList(
totalCount = size totalCount = size
) )
} }
private fun List<CategoryType>.getEdges(): List<CategoryEdge> {
if (isEmpty()) return emptyList()
return listOf(
CategoryEdge(
cursor = Cursor("0"),
node = first()
),
CategoryEdge(
cursor = Cursor(lastIndex.toString()),
node = last()
)
)
}
} }
} }

View File

@@ -11,7 +11,7 @@ import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import graphql.schema.DataFetchingEnvironment import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.ResultRow
import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Edges import suwayomi.tachidesk.graphql.server.primitives.Edge
import suwayomi.tachidesk.graphql.server.primitives.Node import suwayomi.tachidesk.graphql.server.primitives.Node
import suwayomi.tachidesk.graphql.server.primitives.NodeList import suwayomi.tachidesk.graphql.server.primitives.NodeList
import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.graphql.server.primitives.PageInfo
@@ -85,23 +85,20 @@ class ChapterType(
data class ChapterNodeList( data class ChapterNodeList(
override val nodes: List<ChapterType>, override val nodes: List<ChapterType>,
override val edges: ChapterEdges, override val edges: List<ChapterEdge>,
override val pageInfo: PageInfo, override val pageInfo: PageInfo,
override val totalCount: Int override val totalCount: Int
) : NodeList() { ) : NodeList() {
data class ChapterEdges( data class ChapterEdge(
override val cursor: Cursor, override val cursor: Cursor,
override val node: ChapterType override val node: ChapterType
) : Edges() ) : Edge()
companion object { companion object {
fun List<ChapterType>.toNodeList(): ChapterNodeList { fun List<ChapterType>.toNodeList(): ChapterNodeList {
return ChapterNodeList( return ChapterNodeList(
nodes = this, nodes = this,
edges = ChapterEdges( edges = getEdges(),
cursor = Cursor(lastIndex.toString()),
node = last()
),
pageInfo = PageInfo( pageInfo = PageInfo(
hasNextPage = false, hasNextPage = false,
hasPreviousPage = false, hasPreviousPage = false,
@@ -111,5 +108,19 @@ data class ChapterNodeList(
totalCount = size totalCount = size
) )
} }
private fun List<ChapterType>.getEdges(): List<ChapterEdge> {
if (isEmpty()) return emptyList()
return listOf(
ChapterEdge(
cursor = Cursor("0"),
node = first()
),
ChapterEdge(
cursor = Cursor(lastIndex.toString()),
node = last()
)
)
}
} }
} }

View File

@@ -9,7 +9,7 @@ package suwayomi.tachidesk.graphql.types
import com.expediagroup.graphql.generator.annotations.GraphQLIgnore import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Edges import suwayomi.tachidesk.graphql.server.primitives.Edge
import suwayomi.tachidesk.graphql.server.primitives.Node import suwayomi.tachidesk.graphql.server.primitives.Node
import suwayomi.tachidesk.graphql.server.primitives.NodeList import suwayomi.tachidesk.graphql.server.primitives.NodeList
import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.graphql.server.primitives.PageInfo
@@ -52,23 +52,20 @@ class DownloadType(
data class DownloadNodeList( data class DownloadNodeList(
override val nodes: List<DownloadType>, override val nodes: List<DownloadType>,
override val edges: DownloadEdges, override val edges: List<DownloadEdge>,
override val pageInfo: PageInfo, override val pageInfo: PageInfo,
override val totalCount: Int override val totalCount: Int
) : NodeList() { ) : NodeList() {
data class DownloadEdges( data class DownloadEdge(
override val cursor: Cursor, override val cursor: Cursor,
override val node: DownloadType override val node: DownloadType
) : Edges() ) : Edge()
companion object { companion object {
fun List<DownloadType>.toNodeList(): DownloadNodeList { fun List<DownloadType>.toNodeList(): DownloadNodeList {
return DownloadNodeList( return DownloadNodeList(
nodes = this, nodes = this,
edges = DownloadEdges( edges = getEdges(),
cursor = Cursor(lastIndex.toString()),
node = last()
),
pageInfo = PageInfo( pageInfo = PageInfo(
hasNextPage = false, hasNextPage = false,
hasPreviousPage = false, hasPreviousPage = false,
@@ -78,5 +75,19 @@ data class DownloadNodeList(
totalCount = size totalCount = size
) )
} }
private fun List<DownloadType>.getEdges(): List<DownloadEdge> {
if (isEmpty()) return emptyList()
return listOf(
DownloadEdge(
cursor = Cursor("0"),
node = first()
),
DownloadEdge(
cursor = Cursor(lastIndex.toString()),
node = last()
)
)
}
} }
} }

View File

@@ -11,7 +11,7 @@ import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import graphql.schema.DataFetchingEnvironment import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.ResultRow
import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Edges import suwayomi.tachidesk.graphql.server.primitives.Edge
import suwayomi.tachidesk.graphql.server.primitives.Node import suwayomi.tachidesk.graphql.server.primitives.Node
import suwayomi.tachidesk.graphql.server.primitives.NodeList import suwayomi.tachidesk.graphql.server.primitives.NodeList
import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.graphql.server.primitives.PageInfo
@@ -54,23 +54,20 @@ class ExtensionType(
data class ExtensionNodeList( data class ExtensionNodeList(
override val nodes: List<ExtensionType>, override val nodes: List<ExtensionType>,
override val edges: ExtensionEdges, override val edges: List<ExtensionEdge>,
override val pageInfo: PageInfo, override val pageInfo: PageInfo,
override val totalCount: Int override val totalCount: Int
) : NodeList() { ) : NodeList() {
data class ExtensionEdges( data class ExtensionEdge(
override val cursor: Cursor, override val cursor: Cursor,
override val node: ExtensionType override val node: ExtensionType
) : Edges() ) : Edge()
companion object { companion object {
fun List<ExtensionType>.toNodeList(): ExtensionNodeList { fun List<ExtensionType>.toNodeList(): ExtensionNodeList {
return ExtensionNodeList( return ExtensionNodeList(
nodes = this, nodes = this,
edges = ExtensionEdges( edges = getEdges(),
cursor = Cursor(lastIndex.toString()),
node = last()
),
pageInfo = PageInfo( pageInfo = PageInfo(
hasNextPage = false, hasNextPage = false,
hasPreviousPage = false, hasPreviousPage = false,
@@ -80,5 +77,19 @@ data class ExtensionNodeList(
totalCount = size totalCount = size
) )
} }
private fun List<ExtensionType>.getEdges(): List<ExtensionEdge> {
if (isEmpty()) return emptyList()
return listOf(
ExtensionEdge(
cursor = Cursor("0"),
node = first()
),
ExtensionEdge(
cursor = Cursor(lastIndex.toString()),
node = last()
)
)
}
} }
} }

View File

@@ -11,7 +11,7 @@ import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import graphql.schema.DataFetchingEnvironment import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.ResultRow
import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Edges import suwayomi.tachidesk.graphql.server.primitives.Edge
import suwayomi.tachidesk.graphql.server.primitives.Node import suwayomi.tachidesk.graphql.server.primitives.Node
import suwayomi.tachidesk.graphql.server.primitives.NodeList import suwayomi.tachidesk.graphql.server.primitives.NodeList
import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.graphql.server.primitives.PageInfo
@@ -108,23 +108,20 @@ class MangaType(
data class MangaNodeList( data class MangaNodeList(
override val nodes: List<MangaType>, override val nodes: List<MangaType>,
override val edges: MangaEdges, override val edges: List<MangaEdge>,
override val pageInfo: PageInfo, override val pageInfo: PageInfo,
override val totalCount: Int override val totalCount: Int
) : NodeList() { ) : NodeList() {
data class MangaEdges( data class MangaEdge(
override val cursor: Cursor, override val cursor: Cursor,
override val node: MangaType override val node: MangaType
) : Edges() ) : Edge()
companion object { companion object {
fun List<MangaType>.toNodeList(): MangaNodeList { fun List<MangaType>.toNodeList(): MangaNodeList {
return MangaNodeList( return MangaNodeList(
nodes = this, nodes = this,
edges = MangaEdges( edges = getEdges(),
cursor = Cursor(lastIndex.toString()),
node = last()
),
pageInfo = PageInfo( pageInfo = PageInfo(
hasNextPage = false, hasNextPage = false,
hasPreviousPage = false, hasPreviousPage = false,
@@ -134,5 +131,19 @@ data class MangaNodeList(
totalCount = size totalCount = size
) )
} }
private fun List<MangaType>.getEdges(): List<MangaEdge> {
if (isEmpty()) return emptyList()
return listOf(
MangaEdge(
cursor = Cursor("0"),
node = first()
),
MangaEdge(
cursor = Cursor(lastIndex.toString()),
node = last()
)
)
}
} }
} }

View File

@@ -4,7 +4,7 @@ import com.expediagroup.graphql.generator.annotations.GraphQLIgnore
import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.ResultRow
import suwayomi.tachidesk.global.model.table.GlobalMetaTable import suwayomi.tachidesk.global.model.table.GlobalMetaTable
import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Edges import suwayomi.tachidesk.graphql.server.primitives.Edge
import suwayomi.tachidesk.graphql.server.primitives.Node import suwayomi.tachidesk.graphql.server.primitives.Node
import suwayomi.tachidesk.graphql.server.primitives.NodeList import suwayomi.tachidesk.graphql.server.primitives.NodeList
import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.graphql.server.primitives.PageInfo
@@ -37,23 +37,20 @@ class GlobalMetaItem(
data class MetaNodeList( data class MetaNodeList(
override val nodes: List<MetaItem>, override val nodes: List<MetaItem>,
override val edges: MetaEdges, override val edges: List<MetaEdge>,
override val pageInfo: PageInfo, override val pageInfo: PageInfo,
override val totalCount: Int override val totalCount: Int
) : NodeList() { ) : NodeList() {
data class MetaEdges( data class MetaEdge(
override val cursor: Cursor, override val cursor: Cursor,
override val node: MetaItem override val node: MetaItem
) : Edges() ) : Edge()
companion object { companion object {
fun List<MetaItem>.toNodeList(): MetaNodeList { fun List<MetaItem>.toNodeList(): MetaNodeList {
return MetaNodeList( return MetaNodeList(
nodes = this, nodes = this,
edges = MetaEdges( edges = getEdges(),
cursor = Cursor(lastIndex.toString()),
node = last()
),
pageInfo = PageInfo( pageInfo = PageInfo(
hasNextPage = false, hasNextPage = false,
hasPreviousPage = false, hasPreviousPage = false,
@@ -63,5 +60,19 @@ data class MetaNodeList(
totalCount = size totalCount = size
) )
} }
private fun List<MetaItem>.getEdges(): List<MetaEdge> {
if (isEmpty()) return emptyList()
return listOf(
MetaEdge(
cursor = Cursor("0"),
node = first()
),
MetaEdge(
cursor = Cursor(lastIndex.toString()),
node = last()
)
)
}
} }
} }

View File

@@ -14,7 +14,7 @@ import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Edges import suwayomi.tachidesk.graphql.server.primitives.Edge
import suwayomi.tachidesk.graphql.server.primitives.Node import suwayomi.tachidesk.graphql.server.primitives.Node
import suwayomi.tachidesk.graphql.server.primitives.NodeList import suwayomi.tachidesk.graphql.server.primitives.NodeList
import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.graphql.server.primitives.PageInfo
@@ -83,23 +83,20 @@ fun SourceType(row: ResultRow): SourceType? {
data class SourceNodeList( data class SourceNodeList(
override val nodes: List<SourceType>, override val nodes: List<SourceType>,
override val edges: SourceEdges, override val edges: List<SourceEdge>,
override val pageInfo: PageInfo, override val pageInfo: PageInfo,
override val totalCount: Int override val totalCount: Int
) : NodeList() { ) : NodeList() {
data class SourceEdges( data class SourceEdge(
override val cursor: Cursor, override val cursor: Cursor,
override val node: SourceType override val node: SourceType
) : Edges() ) : Edge()
companion object { companion object {
fun List<SourceType>.toNodeList(): SourceNodeList { fun List<SourceType>.toNodeList(): SourceNodeList {
return SourceNodeList( return SourceNodeList(
nodes = this, nodes = this,
edges = SourceEdges( edges = getEdges(),
cursor = Cursor(lastIndex.toString()),
node = last()
),
pageInfo = PageInfo( pageInfo = PageInfo(
hasNextPage = false, hasNextPage = false,
hasPreviousPage = false, hasPreviousPage = false,
@@ -109,5 +106,19 @@ data class SourceNodeList(
totalCount = size totalCount = size
) )
} }
private fun List<SourceType>.getEdges(): List<SourceEdge> {
if (isEmpty()) return emptyList()
return listOf(
SourceEdge(
cursor = Cursor("0"),
node = first()
),
SourceEdge(
cursor = Cursor(lastIndex.toString()),
node = last()
)
)
}
} }
} }

View File

@@ -9,7 +9,7 @@ package suwayomi.tachidesk.graphql.types
import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.ResultRow
import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Cursor
import suwayomi.tachidesk.graphql.server.primitives.Edges import suwayomi.tachidesk.graphql.server.primitives.Edge
import suwayomi.tachidesk.graphql.server.primitives.Node import suwayomi.tachidesk.graphql.server.primitives.Node
import suwayomi.tachidesk.graphql.server.primitives.NodeList import suwayomi.tachidesk.graphql.server.primitives.NodeList
import suwayomi.tachidesk.graphql.server.primitives.PageInfo import suwayomi.tachidesk.graphql.server.primitives.PageInfo
@@ -26,23 +26,20 @@ class UpdatesType(
data class UpdatesNodeList( data class UpdatesNodeList(
override val nodes: List<UpdatesType>, override val nodes: List<UpdatesType>,
override val edges: UpdatesEdges, override val edges: List<UpdatesEdge>,
override val pageInfo: PageInfo, override val pageInfo: PageInfo,
override val totalCount: Int override val totalCount: Int
) : NodeList() { ) : NodeList() {
data class UpdatesEdges( data class UpdatesEdge(
override val cursor: Cursor, override val cursor: Cursor,
override val node: UpdatesType override val node: UpdatesType
) : Edges() ) : Edge()
companion object { companion object {
fun List<UpdatesType>.toNodeList(): UpdatesNodeList { fun List<UpdatesType>.toNodeList(): UpdatesNodeList {
return UpdatesNodeList( return UpdatesNodeList(
nodes = this, nodes = this,
edges = UpdatesEdges( edges = getEdges(),
cursor = Cursor(lastIndex.toString()),
node = last()
),
pageInfo = PageInfo( pageInfo = PageInfo(
hasNextPage = false, hasNextPage = false,
hasPreviousPage = false, hasPreviousPage = false,
@@ -52,5 +49,19 @@ data class UpdatesNodeList(
totalCount = size totalCount = size
) )
} }
private fun List<UpdatesType>.getEdges(): List<UpdatesEdge> {
if (isEmpty()) return emptyList()
return listOf(
UpdatesEdge(
cursor = Cursor("0"),
node = first()
),
UpdatesEdge(
cursor = Cursor(lastIndex.toString()),
node = last()
)
)
}
} }
} }