apollo-angular-signal 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -1,63 +1,186 @@
|
|
|
1
1
|
# ApolloAngularSignal
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A lightweight Angular library that converts Apollo GraphQL queries into Angular signals, enabling seamless integration between Apollo Client and Angular's signal-based reactive programming.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
|
5
|
+
## Installation
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
|
-
|
|
8
|
+
npm install apollo-angular-signal
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
## What It Does
|
|
12
|
+
|
|
13
|
+
This library takes Apollo Angular `ObservableQuery` results and transforms them into Angular signals, providing a more idiomatic way to work with GraphQL data in modern Angular applications.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Basic Query
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Component, inject } from '@angular/core';
|
|
21
|
+
import { Apollo, gql } from 'apollo-angular';
|
|
22
|
+
import { gqlQuery } from 'apollo-angular-signal';
|
|
23
|
+
|
|
24
|
+
const GET_USERS = gql`
|
|
25
|
+
query GetUsers {
|
|
26
|
+
users {
|
|
27
|
+
id
|
|
28
|
+
name
|
|
29
|
+
email
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
@Component({
|
|
35
|
+
selector: 'app-users',
|
|
36
|
+
template: `
|
|
37
|
+
@if (users().loading) {
|
|
38
|
+
<div>Loading...</div>
|
|
39
|
+
}
|
|
40
|
+
@if (users().hasError) {
|
|
41
|
+
<div>Error: {{ users().error }}</div>
|
|
42
|
+
}
|
|
43
|
+
@if (users().data) {
|
|
44
|
+
<ul>
|
|
45
|
+
@for (user of users().data.users; track user.id) {
|
|
46
|
+
<li>{{ user.name }} - {{ user.email }}</li>
|
|
47
|
+
}
|
|
48
|
+
</ul>
|
|
49
|
+
}
|
|
50
|
+
`
|
|
51
|
+
})
|
|
52
|
+
export class UsersComponent {
|
|
53
|
+
private apollo = inject(Apollo);
|
|
54
|
+
|
|
55
|
+
users = gqlQuery<{ users: Array<{ id: string; name: string; email: string }> }>(
|
|
56
|
+
this.apollo.watchQuery({
|
|
57
|
+
query: GET_USERS
|
|
58
|
+
}).valueChanges
|
|
59
|
+
);
|
|
60
|
+
}
|
|
17
61
|
```
|
|
18
62
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
63
|
+
### Query with Variables
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { Component, inject, signal } from '@angular/core';
|
|
67
|
+
import { Apollo, gql } from 'apollo-angular';
|
|
68
|
+
import { gqlQuery } from 'apollo-angular-signal';
|
|
69
|
+
|
|
70
|
+
const GET_USER = gql`
|
|
71
|
+
query GetUser($id: ID!) {
|
|
72
|
+
user(id: $id) {
|
|
73
|
+
id
|
|
74
|
+
name
|
|
75
|
+
email
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
`;
|
|
79
|
+
|
|
80
|
+
@Component({
|
|
81
|
+
selector: 'app-user-detail',
|
|
82
|
+
template: `
|
|
83
|
+
<input [(ngModel)]="userId" placeholder="Enter user ID">
|
|
84
|
+
|
|
85
|
+
@if (user().loading) {
|
|
86
|
+
<div>Loading...</div>
|
|
87
|
+
}
|
|
88
|
+
@if (user().data) {
|
|
89
|
+
<div>
|
|
90
|
+
<h2>{{ user().data.user.name }}</h2>
|
|
91
|
+
<p>{{ user().data.user.email }}</p>
|
|
92
|
+
</div>
|
|
93
|
+
}
|
|
94
|
+
`
|
|
95
|
+
})
|
|
96
|
+
export class UserDetailComponent {
|
|
97
|
+
private apollo = inject(Apollo);
|
|
98
|
+
|
|
99
|
+
userId = signal('1');
|
|
100
|
+
|
|
101
|
+
// Reactive query that re-executes when userId changes
|
|
102
|
+
user = gqlQuery<{ user: { id: string; name: string; email: string } }>(() => {
|
|
103
|
+
const id = this.userId();
|
|
104
|
+
if (!id) return null;
|
|
105
|
+
|
|
106
|
+
return this.apollo.watchQuery({
|
|
107
|
+
query: GET_USER,
|
|
108
|
+
variables: { id }
|
|
109
|
+
}).valueChanges;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
25
112
|
```
|
|
26
113
|
|
|
27
|
-
|
|
114
|
+
### Subscriptions
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { Component, inject } from '@angular/core';
|
|
118
|
+
import { Apollo, gql } from 'apollo-angular';
|
|
119
|
+
import { gqlQuery } from 'apollo-angular-signal';
|
|
120
|
+
|
|
121
|
+
const MESSAGE_SUBSCRIPTION = gql`
|
|
122
|
+
subscription OnMessageAdded {
|
|
123
|
+
messageAdded {
|
|
124
|
+
id
|
|
125
|
+
text
|
|
126
|
+
author
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
`;
|
|
130
|
+
|
|
131
|
+
@Component({
|
|
132
|
+
selector: 'app-messages',
|
|
133
|
+
template: `
|
|
134
|
+
@if (messages().data) {
|
|
135
|
+
<div>
|
|
136
|
+
<p><strong>{{ messages().data.messageAdded.author }}:</strong></p>
|
|
137
|
+
<p>{{ messages().data.messageAdded.text }}</p>
|
|
138
|
+
</div>
|
|
139
|
+
}
|
|
140
|
+
`
|
|
141
|
+
})
|
|
142
|
+
export class MessagesComponent {
|
|
143
|
+
private apollo = inject(Apollo);
|
|
144
|
+
|
|
145
|
+
messages = gqlQuery<{ messageAdded: { id: string; text: string; author: string } }>(
|
|
146
|
+
this.apollo.subscribe({
|
|
147
|
+
query: MESSAGE_SUBSCRIPTION
|
|
148
|
+
})
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
28
152
|
|
|
29
|
-
|
|
153
|
+
## API
|
|
30
154
|
|
|
31
|
-
|
|
155
|
+
### `gqlQuery<T>(query)`
|
|
32
156
|
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
cd dist/apollo-angular-signal
|
|
36
|
-
```
|
|
157
|
+
Converts an Apollo query/subscription observable into an Angular signal.
|
|
37
158
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
npm publish
|
|
41
|
-
```
|
|
159
|
+
**Parameters:**
|
|
160
|
+
- `query`: Either an `Observable<QueryResult<T>>` or a function returning one (for reactive queries)
|
|
42
161
|
|
|
43
|
-
|
|
162
|
+
**Returns:**
|
|
163
|
+
A `Signal<LibResult<T>>` where `LibResult` contains:
|
|
164
|
+
- `data?: T` - The query result data
|
|
165
|
+
- `loading: boolean` - Loading state
|
|
166
|
+
- `hasError: boolean` - Whether an error occurred
|
|
167
|
+
- `error?: unknown` - Error object if present
|
|
44
168
|
|
|
45
|
-
|
|
169
|
+
**Two modes:**
|
|
46
170
|
|
|
47
|
-
|
|
48
|
-
|
|
171
|
+
1. **Static mode**: Pass observable directly
|
|
172
|
+
```typescript
|
|
173
|
+
gqlQuery(apollo.watchQuery({ query: GET_DATA }).valueChanges)
|
|
49
174
|
```
|
|
50
175
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
176
|
+
2. **Reactive mode**: Pass a function for reactive re-execution
|
|
177
|
+
```typescript
|
|
178
|
+
gqlQuery(() => {
|
|
179
|
+
const id = someSignal();
|
|
180
|
+
return apollo.watchQuery({ query: GET_DATA, variables: { id } }).valueChanges;
|
|
181
|
+
})
|
|
57
182
|
```
|
|
58
183
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
## Additional Resources
|
|
184
|
+
## License
|
|
62
185
|
|
|
63
|
-
|
|
186
|
+
MIT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apollo-angular-signal.mjs","sources":["../../../projects/apollo-angular-signal/src/lib/apollo-angular-signal.ts","../../../projects/apollo-angular-signal/src/public-api.ts","../../../projects/apollo-angular-signal/src/apollo-angular-signal.ts"],"sourcesContent":["import { computed, effect, signal, type Signal } from '@angular/core';\nimport { ObservableQuery } from '@apollo/client';\nimport type { Apollo } from 'apollo-angular';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport type { Subscription, Observable } from 'rxjs';\n\nexport type GqlQueryResult<T> =\n | Apollo.QueryResult<T>\n | Apollo.SubscribeResult<T>\n | ObservableQuery.Result<T>;\n\nexport type ObservableResult<T> = Observable<GqlQueryResult<T>>;\n\ntype Maybe<T> = T | null | undefined;\n\
|
|
1
|
+
{"version":3,"file":"apollo-angular-signal.mjs","sources":["../../../projects/apollo-angular-signal/src/lib/apollo-angular-signal.ts","../../../projects/apollo-angular-signal/src/public-api.ts","../../../projects/apollo-angular-signal/src/apollo-angular-signal.ts"],"sourcesContent":["import { computed, effect, signal, type Signal } from '@angular/core';\nimport type { ObservableQuery } from '@apollo/client';\nimport type { Apollo } from 'apollo-angular';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport type { Subscription, Observable } from 'rxjs';\n\nexport type GqlQueryResult<T> =\n | Apollo.QueryResult<T>\n | Apollo.SubscribeResult<T>\n | ObservableQuery.Result<T>;\n\nexport type ObservableResult<T> = Observable<GqlQueryResult<T>>;\n\ntype Maybe<T> = T | null | undefined;\n\ninterface LibResult<T> {\n data?: T;\n loading: boolean;\n hasError: boolean;\n error?: unknown;\n}\n\nexport function gqlQuery<T>(\n query: ObservableResult<T> | (() => Maybe<ObservableResult<T>>),\n): Signal<LibResult<T>> {\n if (typeof query === 'function') {\n return gqlAsync(query);\n } else {\n const state = signal<LibResult<T>>({\n loading: true,\n hasError: false,\n });\n\n query.pipe(takeUntilDestroyed()).subscribe({\n next: (res) => {\n state.set({\n data: res.data as T,\n hasError: !!res.error,\n error: res.error,\n loading: 'loading' in res ? res.loading : false,\n });\n },\n error: (error: unknown) => {\n state.set({\n loading: false,\n hasError: true,\n error,\n });\n },\n });\n\n return state;\n }\n}\n\nfunction gqlAsync<T>(\n fn: () => Maybe<ObservableResult<T>>,\n): Signal<LibResult<T>> {\n const state = signal<LibResult<T>>({\n loading: true,\n hasError: false,\n });\n\n const source$ = computed(fn);\n\n effect((onCleanup) => {\n const observable = source$();\n let sub: Maybe<Subscription>;\n if (observable) {\n sub = observable.subscribe({\n next: (res) => {\n state.set({\n data: res.data as T,\n loading: 'loading' in res ? res.loading : false,\n hasError: !!res.error,\n error: res.error,\n });\n },\n error: (error: unknown) => {\n state.set({\n loading: false,\n hasError: true,\n error,\n });\n },\n });\n }\n\n onCleanup(() => {\n sub?.unsubscribe();\n });\n });\n\n return state;\n}\n","/*\n * Public API Surface of apollo-angular-signal\n */\n\nexport * from './lib/apollo-angular-signal';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;AAsBM,SAAU,QAAQ,CACtB,KAA+D,EAAA;AAE/D,IAAA,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE;AAC/B,QAAA,OAAO,QAAQ,CAAC,KAAK,CAAC;IACxB;SAAO;QACL,MAAM,KAAK,GAAG,MAAM,CAAe;AACjC,YAAA,OAAO,EAAE,IAAI;AACb,YAAA,QAAQ,EAAE,KAAK;AAChB,SAAA,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,OAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAC;QAEF,KAAK,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAC,SAAS,CAAC;AACzC,YAAA,IAAI,EAAE,CAAC,GAAG,KAAI;gBACZ,KAAK,CAAC,GAAG,CAAC;oBACR,IAAI,EAAE,GAAG,CAAC,IAAS;AACnB,oBAAA,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK;oBACrB,KAAK,EAAE,GAAG,CAAC,KAAK;AAChB,oBAAA,OAAO,EAAE,SAAS,IAAI,GAAG,GAAG,GAAG,CAAC,OAAO,GAAG,KAAK;AAChD,iBAAA,CAAC;YACJ,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,KAAc,KAAI;gBACxB,KAAK,CAAC,GAAG,CAAC;AACR,oBAAA,OAAO,EAAE,KAAK;AACd,oBAAA,QAAQ,EAAE,IAAI;oBACd,KAAK;AACN,iBAAA,CAAC;YACJ,CAAC;AACF,SAAA,CAAC;AAEF,QAAA,OAAO,KAAK;IACd;AACF;AAEA,SAAS,QAAQ,CACf,EAAoC,EAAA;IAEpC,MAAM,KAAK,GAAG,MAAM,CAAe;AACjC,QAAA,OAAO,EAAE,IAAI;AACb,QAAA,QAAQ,EAAE,KAAK;AAChB,KAAA,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,OAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAC;AAEF,IAAA,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,mDAAC;AAE5B,IAAA,MAAM,CAAC,CAAC,SAAS,KAAI;AACnB,QAAA,MAAM,UAAU,GAAG,OAAO,EAAE;AAC5B,QAAA,IAAI,GAAwB;QAC5B,IAAI,UAAU,EAAE;AACd,YAAA,GAAG,GAAG,UAAU,CAAC,SAAS,CAAC;AACzB,gBAAA,IAAI,EAAE,CAAC,GAAG,KAAI;oBACZ,KAAK,CAAC,GAAG,CAAC;wBACR,IAAI,EAAE,GAAG,CAAC,IAAS;AACnB,wBAAA,OAAO,EAAE,SAAS,IAAI,GAAG,GAAG,GAAG,CAAC,OAAO,GAAG,KAAK;AAC/C,wBAAA,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK;wBACrB,KAAK,EAAE,GAAG,CAAC,KAAK;AACjB,qBAAA,CAAC;gBACJ,CAAC;AACD,gBAAA,KAAK,EAAE,CAAC,KAAc,KAAI;oBACxB,KAAK,CAAC,GAAG,CAAC;AACR,wBAAA,OAAO,EAAE,KAAK;AACd,wBAAA,QAAQ,EAAE,IAAI;wBACd,KAAK;AACN,qBAAA,CAAC;gBACJ,CAAC;AACF,aAAA,CAAC;QACJ;QAEA,SAAS,CAAC,MAAK;YACb,GAAG,EAAE,WAAW,EAAE;AACpB,QAAA,CAAC,CAAC;AACJ,IAAA,CAAC,CAAC;AAEF,IAAA,OAAO,KAAK;AACd;;AC9FA;;AAEG;;ACFH;;AAEG;;;;"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apollo-angular-signal",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@angular/common": "^20 || ^21",
|
|
6
6
|
"@angular/core": "^20 || ^21",
|
|
7
7
|
"apollo-angular": "^13",
|
|
8
|
+
"@apollo/client": "^4",
|
|
8
9
|
"rxjs": "^7"
|
|
9
10
|
},
|
|
10
11
|
"sideEffects": false,
|
|
@@ -6,13 +6,13 @@ import { Observable } from 'rxjs';
|
|
|
6
6
|
type GqlQueryResult<T> = Apollo.QueryResult<T> | Apollo.SubscribeResult<T> | ObservableQuery.Result<T>;
|
|
7
7
|
type ObservableResult<T> = Observable<GqlQueryResult<T>>;
|
|
8
8
|
type Maybe<T> = T | null | undefined;
|
|
9
|
-
interface
|
|
9
|
+
interface LibResult<T> {
|
|
10
10
|
data?: T;
|
|
11
11
|
loading: boolean;
|
|
12
12
|
hasError: boolean;
|
|
13
13
|
error?: unknown;
|
|
14
14
|
}
|
|
15
|
-
declare function gqlQuery<T>(query: ObservableResult<T> | (() => Maybe<ObservableResult<T>>)): Signal<
|
|
15
|
+
declare function gqlQuery<T>(query: ObservableResult<T> | (() => Maybe<ObservableResult<T>>)): Signal<LibResult<T>>;
|
|
16
16
|
|
|
17
17
|
export { gqlQuery };
|
|
18
|
-
export type { GqlQueryResult,
|
|
18
|
+
export type { GqlQueryResult, ObservableResult };
|