Sfoglia il codice sorgente

pub-query checks: mutations and mutations refresh

asmer 3 mesi fa
parent
commit
ced31b930a
3 ha cambiato i file con 140 aggiunte e 20 eliminazioni
  1. 106 14
      src/App.tsx
  2. 1 0
      src/lib/pub/createPub.ts
  3. 33 6
      src/lib/pub/query/index.ts

+ 106 - 14
src/App.tsx

@@ -11,39 +11,131 @@ const history = createBrowserHistory()
 //console.log(createQueryPub)
 //
 
-const {queryPub, createQuery} = createQueryPub({
-    queryFunc(route, id=''){
-        return fetch(`https://swapi.dev/api/${route}/${id}`).then(res => res.json())
-    },
-    cacheTimeout: 5000,
+
+//
+//
+const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOnsiaWQiOiI2NjdmZjBkYTIyMzIxMjBjN2M4NzFmN2MiLCJsb2dpbiI6InRzdDE5IiwiYWNsIjpbIjY2N2ZmMGRhMjIzMjEyMGM3Yzg3MWY3YyIsInVzZXIiXX0sImlhdCI6MTcyMDI1OTEwN30.eDcInxQlskt32LjaCe5sdCcJ3B97BKYZtgUARxThYQM'
+
+console.log(JSON.parse(atob(token.split('.')[1])).sub.id)
+
+const gql = (query, variables={}) => 
+    fetch('http://shop-roles.node.ed.asmer.org.ua/graphql',{
+        method: 'POST',
+        headers: {
+            'Content-Type': 'application/json',
+            Accept: 'application/json',
+            Authorization: 'Bearer ' + token
+        },
+        body: JSON.stringify({query, variables})
+    }).then(res => res.json())
+
+const {queryPub, createQuery, withQueryFunc} = createQueryPub({
+    queryFunc: gql,
+    cacheTimeout: 500000,
     //hidePendingOnRefresh: false,
 })
 
-const {usePeopleQuery} = createQuery({promiseName: 'people',
-                                     cacheTagFunc: (payload) => payload.results.map(man => ({type: 'people', id: +man.url.split('/')[5]}))})
-
-//queryPub.subscribe(() => console.log(JSON.stringify(queryPub, null, 4)))
 
+//queryPub.subscribe(() => console.log(JSON.stringify(queryPub.queries.user, null, 4)))
+
+const {useGoodsQuery} = createQuery({promiseName: 'goods',
+                                     cacheTagFunc: (payload) => payload.data.GoodFind.map(good => ({type: 'Good', id: good._id}))})
+
+//const {useUserQuery}  = createQuery({
+    //promiseName: 'user',
+    //args: [` 
+        //query user($query: String) {
+            //UserFindOne(query: $query){
+                //_id login nick
+            //}
+        //}
+    //`],
+    //cacheTagFunc: ({data: {UserFindOne: {_id}}}) => ({_id, type: 'User'})
+//})
+//const userState = useUserQuery({query: JSON.stringify([{_id: '667ff0da2232120c7c871f7c'}])})
+
+//const {useUserQuery} = withQueryFunc(_id => gql(
+   //`query user($query: String) {
+        //UserFindOne(query: $query){
+            //_id login nick
+        //}
+    //}`,
+    //{query: JSON.stringify([{_id}])}
+//))({
+    //promiseName: 'user',
+    //cacheTagFunc: ({data: {UserFindOne: {_id}}}) => ({_id, type: 'User'})
+//})
+
+
+const {useUserQuery}  = createQuery({
+    promiseName: 'user',
+    args: (_id) =>  [` 
+        query user($query: String) {
+            UserFindOne(query: $query){
+                _id login nick
+            }
+        }
+    `, {query: JSON.stringify([{_id}])}],
+    cacheTagFunc: ({data: {UserFindOne: {_id}}}) => [{_id, type: 'User'}]
+})
 
+const {useUserMutation} = createQuery({
+    promiseName: 'user',
+    isMutation: true,
+    args: (_id, nick) => [
+        `mutation changeNick($_id:String, $nick:String){
+            UserUpsert(user:{_id:$_id, nick:$nick}){
+                _id nick
+            }
+        }`,
+        {_id, nick}],
+    cacheTagFunc: ({data: {UserUpsert: {_id}}}) => [{_id, type: 'User'}]
+})
 
+const EditNick = () => {
+    const [nick, setNick] = useState('')
+    const [update, {status, payload, error}] = useUserMutation()
+    console.log(status, payload, error)
+    return (
+        <div>
+            <input type='text' value={nick} onChange={e => setNick(e.target.value)} />
+            <button onClick={() => update('667ff0da2232120c7c871f7c', nick)}>Save</button>
+        </div>
+    )
+}
 
 
 function App() {
-    const queryState = usePeopleQuery('people')
+    //const queryState = useGoodsQuery(`query {
+        //GoodFind(query: "[{}]"){
+            //name price _id
+        //}
+    //}`)
+
+
+    const userState = useUserQuery('667ff0da2232120c7c871f7c')
+    console.log(userState)
+
     const [,setRandomState] = useState<number>()
 
     useEffect(() => {
         //setInterval(() => setRandomState(Math.random()), 1000)
     },[])
 
-    console.log(queryState)
+    //console.log(queryState)
 
-    const {status, payload,cacheTags} = queryState
+    //const {status, payload,cacheTags} = queryState
     //console.log(JSON.stringify(cacheTags))
     return (
         <Router history={history}>
-        {status === 'PENDING' && <h1>Loading</h1>}
-        {status === 'FULFILLED' && payload.results.map(man => <h2 key={man.url}>{man.name}</h2>)}
+        <EditNick />
+        {userState.status === 'PENDING' && <h1>Loading</h1>}
+        {userState.status === 'FULFILLED' && userState.payload.data.UserFindOne.nick}
+
+
+
+        {/*status === 'PENDING' && <h1>Loading</h1>}
+        {status === 'FULFILLED' && payload.data.GoodFind.map(good => <h2 key={good._id}>{good.name}</h2>) */}
 
 
         </Router>

+ 1 - 0
src/lib/pub/createPub.ts

@@ -39,6 +39,7 @@ const createPub = (state:object={}): Pub => {
                 delete childUnsubcribers[prop]
             }
             delete obj[prop]
+            return true
         },
         set(obj, prop, value){
             if (prop === 'subscribe') throw new SyntaxError('You cannot substitute subscribe to other value')

+ 33 - 6
src/lib/pub/query/index.ts

@@ -37,11 +37,37 @@ export default (options:CreateQueryPubOptions) => {
     options = {...defaultOptions, ...options}
 
     const withQueryFunc = (queryFunc?: QueryFuncType):Function => {
-        return ({promiseName, isMutation, cacheTagFunc}) => {
+        return ({promiseName, isMutation, cacheTagFunc, args=[]}) => {
             const qF = queryFunc || options.queryFunc
+            const defaultArgs = args
+
+            const mixArgs = (args:any[]) => 
+                Array.isArray(defaultArgs) ? 
+                    [...defaultArgs, ...args] :
+                    (typeof defaultArgs === 'function' ? 
+                        defaultArgs(...args) : args)
+
+            const stringifyArgs = args => 
+                JSON.stringify(mixArgs(args))
 
             const makeQuery = (...args:any[]) => {
-                return qF(...args)
+                return qF(...mixArgs(args))
+            }
+
+            const intersectTags = (first:Array<any>, second:Array<any>) => 
+                first.find(firstItem => second.find(secondItem => firstItem.type === secondItem.type && firstItem.id === secondItem.id))
+
+
+            const invalidateTags = tags => {
+                console.log(tags)
+                if (!tags) return
+                for (const promiseBranch of Object.values(queryPub.queries)){
+                    for (const [args, promiseState] of Object.entries(promiseBranch))
+                        if (promiseState.cacheTags && intersectTags(tags, promiseState.cacheTags)){
+                            console.log('invalidate', tags, args, promiseState)
+                            delete promiseBranch[args]
+                        }
+                }
             }
 
             const query = (...args:any[]) => {
@@ -56,12 +82,12 @@ export default (options:CreateQueryPubOptions) => {
                         if (!queryPub.mutations[promiseName].refreshing){
                             queryPub.mutations[promiseName].refreshing = true
                         }
-                        return currentPromises.mutations[promiseName] = makeQuery(...args).then(payload => queryPub.mutations[promiseName] = {status: 'FULFILLED', payload},
+                        return currentPromises.mutations[promiseName] = makeQuery(...args).then(payload => queryPub.mutations[promiseName] = (invalidateTags(cacheTagFunc && cacheTagFunc(payload)),{status: 'FULFILLED', payload}),
                                                                                                 error   => queryPub.mutations[promiseName] = {status: 'REJECTED', error})
                     }
                 }
                 if (!isMutation){
-                    const stringifiedArgs = JSON.stringify(args)
+                    const stringifiedArgs = stringifyArgs(args)
                     if ((!options.cacheTimeout && queryPub.queries[promiseName]?.[stringifiedArgs].status === 'FULFILLED') || 
                         (queryPub.queries[promiseName]?.[stringifiedArgs] && (Date.now() - queryPub.queries[promiseName][stringifiedArgs].timeStamp) < options.cacheTimeout)){
 
@@ -76,7 +102,8 @@ export default (options:CreateQueryPubOptions) => {
 
 
 
-                const stringifiedArgs = JSON.stringify(args)
+                const stringifiedArgs = stringifyArgs(args)
+
                 if (!queryPub.queries[promiseName]) {
                     queryPub.queries[promiseName] = {}
                 }
@@ -133,7 +160,7 @@ export default (options:CreateQueryPubOptions) => {
 
                 usePub(queryPub.queries[promiseName])
 
-                const stringifiedArgs = JSON.stringify(args)
+                const stringifiedArgs = stringifyArgs(args)
                 return queryPub.queries[promiseName][stringifiedArgs]
             }