1
1
import atob from 'atob' ;
2
- import { gql , useQuery , useSubscription , useApolloClient } from '@apollo/client/index.js' ;
2
+ import { gql , useQuery , useSubscription , useApolloClient , Observable } from '@apollo/client/index.js' ;
3
3
import type { ApolloQueryResult } from '@apollo/client/index.js' ;
4
4
import { generateApolloClient , IApolloClient } from '@deep-foundation/hasura/client.js' ;
5
5
import { useLocalStore } from '@deep-foundation/store/local.js' ;
@@ -14,6 +14,7 @@ import { corePckg } from './core.js';
14
14
import { BoolExpCan , BoolExpHandler , QueryLink , BoolExpSelector , BoolExpTree , BoolExpValue , MutationInputLink , MutationInputLinkPlain , MutationInputValue } from './client_types.js' ;
15
15
import get from 'get-value' ;
16
16
import { debug } from './debug.js'
17
+ import { Traveler as NativeTraveler } from './traveler.js' ;
17
18
const moduleLog = debug . extend ( 'client' ) ;
18
19
19
20
const log = debug . extend ( 'log' ) ;
@@ -268,6 +269,19 @@ export function parseJwt (token): { userId: number; role: string; roles: string[
268
269
...other ,
269
270
} ;
270
271
} ;
272
+
273
+ export interface Subscription {
274
+ closed : boolean ;
275
+ unsubscribe ( ) : void ;
276
+ }
277
+
278
+ export interface Observer < T > {
279
+ start ?( subscription : Subscription ) : any ;
280
+ next ?( value : T ) : void ;
281
+ error ?( errorValue : any ) : void ;
282
+ complete ?( ) : void ;
283
+ } ;
284
+
271
285
export interface DeepClientOptions < L = Link < number > > {
272
286
linkId ?: number ;
273
287
token ?: string ;
@@ -301,6 +315,7 @@ export interface DeepClientOptions<L = Link<number>> {
301
315
302
316
export interface DeepClientResult < R > extends ApolloQueryResult < R > {
303
317
error ?: any ;
318
+ subscribe ?: ( observer : Observer < any > ) => Subscription ;
304
319
}
305
320
306
321
export type DeepClientPackageSelector = string ;
@@ -339,7 +354,8 @@ export interface DeepClientInstance<L = Link<number>> {
339
354
340
355
stringify ( any ?: any ) : string ;
341
356
342
- select < TTable extends 'links' | 'numbers' | 'strings' | 'objects' | 'can' | 'selectors' | 'tree' | 'handlers' , LL = L > ( exp : Exp < TTable > , options ?: ReadOptions < TTable > ) : Promise < DeepClientResult < LL [ ] > > ;
357
+ select < TTable extends 'links' | 'numbers' | 'strings' | 'objects' | 'can' | 'selectors' | 'tree' | 'handlers' , LL = L > ( exp : Exp < TTable > , options ?: ReadOptions < TTable > ) : Promise < DeepClientResult < LL [ ] | number > > ;
358
+ subscribe < TTable extends 'links' | 'numbers' | 'strings' | 'objects' | 'can' | 'selectors' | 'tree' | 'handlers' , LL = L > ( exp : Exp < TTable > , options ?: ReadOptions < TTable > ) : Observable < LL [ ] | number > ;
343
359
344
360
insert < TTable extends 'links' | 'numbers' | 'strings' | 'objects' , LL = L > ( objects : InsertObjects < TTable > , options ?: WriteOptions < TTable > ) :Promise < DeepClientResult < { id } [ ] > > ;
345
361
@@ -377,6 +393,8 @@ export interface DeepClientInstance<L = Link<number>> {
377
393
useDeep : typeof useDeep ;
378
394
DeepProvider : typeof DeepProvider ;
379
395
DeepContext : typeof DeepContext ;
396
+
397
+ Traveler ( links : Link < number > [ ] ) : NativeTraveler ;
380
398
}
381
399
382
400
export interface DeepClientAuthResult {
@@ -615,6 +633,8 @@ export class DeepClient<L = Link<number>> implements DeepClientInstance<L> {
615
633
[ 'strings' , 'numbers' , 'objects' ] . includes ( table ) ? this . valuesSelectReturning :
616
634
table === 'selectors' ? this . selectorsSelectReturning :
617
635
table === 'files' ? this . filesSelectReturning : `id` ) ;
636
+ const tableNamePostfix = options ?. tableNamePostfix ;
637
+ const aggregate = options ?. aggregate ;
618
638
619
639
// console.log(`returning: ${returning}; options.returning:${options?.returning}`)
620
640
const variables = options ?. variables ;
@@ -625,7 +645,8 @@ export class DeepClient<L = Link<number>> implements DeepClientInstance<L> {
625
645
queries : [
626
646
generateQueryData ( {
627
647
tableName : table ,
628
- returning,
648
+ tableNamePostfix : tableNamePostfix || aggregate ? '_aggregate' : '' ,
649
+ returning : aggregate ? `aggregate { ${ aggregate } }` : returning ,
629
650
variables : {
630
651
...variables ,
631
652
...query ,
@@ -634,12 +655,80 @@ export class DeepClient<L = Link<number>> implements DeepClientInstance<L> {
634
655
name : name ,
635
656
} ) ) ;
636
657
637
- return { ...q , data : ( q ) ?. data ?. q0 } ;
658
+ return { ...q , data : aggregate ? ( q ) ?. data ?. q0 ?. aggregate ?. [ aggregate ] : ( q ) ?. data ?. q0 } ;
638
659
} catch ( e ) {
660
+ console . log ( generateQueryData ( {
661
+ tableName : table ,
662
+ tableNamePostfix : tableNamePostfix || aggregate ? '_aggregate' : '' ,
663
+ returning : aggregate ? `aggregate { ${ aggregate } }` : returning ,
664
+ variables : {
665
+ ...variables ,
666
+ ...query ,
667
+ } } ) ( 'a' , 0 ) ) ;
639
668
throw new Error ( `DeepClient Select Error: ${ e . message } ` , { cause : e } ) ;
640
669
}
641
670
} ;
642
671
672
+ /**
673
+ * deep.subscribe
674
+ * @example
675
+ * deep.subscribe({ up: { link_id: 380 } }).subscribe({ next: (links) => {}, error: (err) => {} });
676
+ */
677
+ subscribe < TTable extends 'links' | 'numbers' | 'strings' | 'objects' | 'can' | 'selectors' | 'tree' | 'handlers' , LL = L > ( exp : Exp < TTable > , options ?: ReadOptions < TTable > ) : Observable < LL [ ] > {
678
+ if ( ! exp ) {
679
+ return new Observable ( ( observer ) => {
680
+ observer . error ( '!exp' ) ;
681
+ } ) ;
682
+ }
683
+ const query = serializeQuery ( exp , options ?. table || 'links' ) ;
684
+ const table = options ?. table || this . table ;
685
+ const returning = options ?. returning ??
686
+ ( table === 'links' ? this . linksSelectReturning :
687
+ [ 'strings' , 'numbers' , 'objects' ] . includes ( table ) ? this . valuesSelectReturning :
688
+ table === 'selectors' ? this . selectorsSelectReturning :
689
+ table === 'files' ? this . filesSelectReturning : `id` ) ;
690
+ const tableNamePostfix = options ?. tableNamePostfix ;
691
+ const aggregate = options ?. aggregate ;
692
+
693
+ // console.log(`returning: ${returning}; options.returning:${options?.returning}`)
694
+ const variables = options ?. variables ;
695
+ const name = options ?. name || this . defaultSelectName ;
696
+
697
+ try {
698
+ const apolloObservable = this . apolloClient . subscribe ( {
699
+ ...generateQuery ( {
700
+ operation : 'subscription' ,
701
+ queries : [
702
+ generateQueryData ( {
703
+ tableName : table ,
704
+ tableNamePostfix : tableNamePostfix || aggregate ? '_aggregate' : '' ,
705
+ returning : returning || aggregate ? `aggregate { ${ aggregate } }` : returning ,
706
+ variables : {
707
+ ...variables ,
708
+ ...query ,
709
+ } } ) ,
710
+ ] ,
711
+ name : name ,
712
+ } ) ,
713
+ } ) ;
714
+
715
+ const observable = new Observable ( ( observer ) => {
716
+ const subscription = apolloObservable . subscribe ( {
717
+ next : ( data : any ) => {
718
+ observer . next ( aggregate ? data ?. q0 ?. aggregate ?. [ aggregate ] : data ?. q0 ) ;
719
+ } ,
720
+ error : ( error ) => observer . error ( error ) ,
721
+ } ) ;
722
+ return ( ) => subscription . unsubscribe ( ) ;
723
+ } ) ;
724
+
725
+ // @ts -ignore
726
+ return observable ;
727
+ } catch ( e ) {
728
+ throw new Error ( `DeepClient Subscription Error: ${ e . message } ` , { cause : e } ) ;
729
+ }
730
+ } ;
731
+
643
732
async insert < TTable extends 'links' | 'numbers' | 'strings' | 'objects' , LL = L > ( objects : InsertObjects < TTable > , options ?: WriteOptions < TTable > ) :Promise < DeepClientResult < { id } [ ] > > {
644
733
const _objects = Object . prototype . toString . call ( objects ) === '[object Array]' ? objects : [ objects ] ;
645
734
checkAndFillShorts ( _objects ) ;
@@ -997,6 +1086,10 @@ export class DeepClient<L = Link<number>> implements DeepClientInstance<L> {
997
1086
}
998
1087
return await import ( path ) ;
999
1088
}
1089
+
1090
+ Traveler ( links : Link < number > [ ] ) {
1091
+ return new NativeTraveler ( this , links ) ;
1092
+ } ;
1000
1093
}
1001
1094
1002
1095
export const JWT = gql `query JWT($linkId: Int) {
@@ -1074,6 +1167,7 @@ export function useDeepQuery<Table extends 'links'|'numbers'|'strings'|'objects'
1074
1167
query : QueryLink ,
1075
1168
options ?: {
1076
1169
table ?: Table ;
1170
+ tableNamePostfix ?: string ;
1077
1171
returning ?: string ;
1078
1172
variables ?: any ;
1079
1173
name ?: string ;
@@ -1118,6 +1212,7 @@ export function useDeepSubscription<Table extends 'links'|'numbers'|'strings'|'o
1118
1212
query : QueryLink ,
1119
1213
options ?: {
1120
1214
table ?: Table ;
1215
+ tableNamePostfix ?: string ;
1121
1216
returning ?: string ;
1122
1217
variables ?: any ;
1123
1218
name ?: string ;
@@ -1198,9 +1293,11 @@ export type InsertObjects<TTable extends Table> = (
1198
1293
1199
1294
export type Options < TTable extends Table > = {
1200
1295
table ?: TTable ;
1296
+ tableNamePostfix ?: string ;
1201
1297
returning ?: string ;
1202
1298
variables ?: any ;
1203
1299
name ?: string ;
1300
+ aggregate ?: 'count' | 'sum' | 'avg' | 'min' | 'max' ;
1204
1301
} ;
1205
1302
1206
1303
export type ReadOptions < TTable extends Table > = Options < TTable > ;
0 commit comments