22import type { PostsQueryVariables } from ' @vue3-apollo/operations'
33
44import { gql } from ' @apollo/client'
5- import { PostsDocument , UpdatePostDocument } from ' @vue3-apollo/operations'
5+ import { PostDetailFragmentDoc , PostsDocument , UpdatePostDocument } from ' @vue3-apollo/operations'
66import { reactive , ref } from ' vue'
77
88// Constants
@@ -20,6 +20,8 @@ const rawQuery = gql`
2020// Refs
2121const enabled = ref (true )
2222const title = ref (' ' )
23+ const fragmentPostId = ref (1 )
24+ const fragmentEnabled = ref (true )
2325
2426// Reactive variables
2527const vars = reactive <PostsQueryVariables >({
@@ -49,6 +51,23 @@ const { error: rawQueryError, result: rawQueryResult } = useQuery(rawQuery, rawQ
4951 keepPreviousResult: true
5052})
5153
54+ // Fragments
55+ const {
56+ complete : fragmentComplete,
57+ data : fragmentData,
58+ error : fragmentError,
59+ missing : fragmentMissing,
60+ onResult : onFragmentResult,
61+ result : fragmentResult
62+ } = useFragment ({
63+ enabled: fragmentEnabled ,
64+ fragment: PostDetailFragmentDoc ,
65+ from: computed (() => ({
66+ __typename: ' Post' ,
67+ id: fragmentPostId .value
68+ }))
69+ })
70+
5271// Mutations
5372const { loading, mutate } = useMutation (UpdatePostDocument )
5473
@@ -57,6 +76,22 @@ onResult((data) => {
5776 console .warn (' onResult' , data )
5877})
5978
79+ onFragmentResult ((result ) => {
80+ console .warn (' onFragmentResult' , result )
81+ })
82+
83+ // Watch fragment result for type narrowing demo
84+ watchEffect (() => {
85+ if (fragmentResult .value ?.complete ) {
86+ // TypeScript knows data is non-optional here
87+ console .warn (' Fragment complete:' , fragmentResult .value .data )
88+ }
89+ else if (fragmentResult .value ?.data ) {
90+ // Partial data
91+ console .warn (' Fragment partial:' , fragmentResult .value .data )
92+ }
93+ })
94+
6095// Composables
6196const route = useRoute ()
6297const isLoading = useQueriesLoading ()
@@ -185,6 +220,80 @@ watch(isLoading, (loading) => {
185220{{ (rawQueryResult as any)?.users }}
186221 </pre >
187222 </div >
223+
224+ <!-- Fragment Testing Section -->
225+ <div class =" border-t border-white/10 pt-4 space-y-3" >
226+ <div class =" flex items-center gap-3 mb-3" >
227+ <h3 class =" text-sm font-medium text-gray-300" >
228+ Fragment Testing (useFragment)
229+ </h3 >
230+ <button
231+ type =" button"
232+ class =" inline-flex cursor-pointer items-center gap-2 px-2 py-1 rounded text-xs bg-slate-800 hover:bg-slate-700 active:bg-slate-800 text-gray-200 border border-white/10 transition-colors"
233+ @click =" fragmentEnabled = !fragmentEnabled"
234+ >
235+ {{ fragmentEnabled ? 'Disable' : 'Enable' }}
236+ </button >
237+ <div class =" flex items-center gap-2" >
238+ <label class =" text-xs text-gray-400" >Post ID:</label >
239+ <input
240+ v-model.number =" fragmentPostId"
241+ type =" number"
242+ min =" 1"
243+ class =" w-20 px-2 py-1 text-xs rounded bg-slate-800/70 text-gray-100 border border-slate-700 focus:(outline-none ring-1 ring-indigo-500)"
244+ >
245+ </div >
246+ <div class =" ml-auto flex items-center gap-2" >
247+ <span class =" text-xs text-gray-400" >Complete:</span >
248+ <span :class =" fragmentComplete ? 'text-emerald-400' : 'text-amber-400'" class =" text-xs font-medium" >
249+ {{ fragmentComplete ? '✓ Yes' : '⚠ Partial' }}
250+ </span >
251+ </div >
252+ </div >
253+
254+ <div v-if =" fragmentError" class =" text-sm text-rose-400 bg-rose-900/20 border border-rose-700/40 rounded-lg p-3" >
255+ {{ fragmentError }}
256+ </div >
257+
258+ <div class =" grid grid-cols-1 md:grid-cols-2 gap-3" >
259+ <div >
260+ <div class =" text-xs text-gray-400 mb-2" >
261+ Fragment Data (from cache):
262+ </div >
263+ <pre class =" w-full overflow-auto text-sm leading-relaxed bg-slate-950/60 border border-white/10 rounded-lg p-3" >
264+ {{ fragmentData }}
265+ </pre >
266+ </div >
267+
268+ <div >
269+ <div class =" text-xs text-gray-400 mb-2" >
270+ Full Result (type-safe):
271+ </div >
272+ <pre class =" w-full overflow-auto text-sm leading-relaxed bg-slate-950/60 border border-white/10 rounded-lg p-3" >
273+ {{ fragmentResult }}
274+ </pre >
275+ </div >
276+ </div >
277+
278+ <div v-if =" fragmentMissing" class =" text-xs" >
279+ <div class =" text-amber-400 mb-2" >
280+ Missing Fields:
281+ </div >
282+ <pre class =" w-full overflow-auto text-xs leading-relaxed bg-amber-950/20 border border-amber-700/40 rounded-lg p-3" >
283+ {{ fragmentMissing }}
284+ </pre >
285+ </div >
286+
287+ <div class =" text-xs text-gray-500 bg-slate-800/30 border border-white/5 rounded-lg p-3" >
288+ <strong >💡 Tips:</strong >
289+ <ul class =" mt-2 space-y-1 list-disc list-inside" >
290+ <li >Fragment reads data synchronously from Apollo Cache</li >
291+ <li >Update post title above to see fragment auto-update</li >
292+ <li >Change Post ID to read different entities</li >
293+ <li >Use <code class =" px-1 py-0.5 bg-slate-700 rounded" >result.value?.complete</code > for TypeScript type narrowing</li >
294+ </ul >
295+ </div >
296+ </div >
188297 </section >
189298
190299 <footer class =" mt-8 text-center text-xs text-gray-500" >
0 commit comments