@onchaindb/sdk 0.4.0 → 0.4.2
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/.DS_Store +0 -0
- package/.claude/settings.local.json +8 -0
- package/.gitignore +5 -0
- package/.idea/.gitignore +5 -0
- package/.idea/compiler.xml +6 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/jsLinters/eslint.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/prettier.xml +7 -0
- package/.idea/sdk.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/workspace.xml +257 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +11 -3
- package/dist/client.js.map +1 -1
- package/dist/database.d.ts +0 -20
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +0 -40
- package/dist/database.js.map +1 -1
- package/dist/query-sdk/tests/setup.d.ts +16 -0
- package/dist/query-sdk/tests/setup.d.ts.map +1 -0
- package/dist/query-sdk/tests/setup.js +49 -0
- package/dist/query-sdk/tests/setup.js.map +1 -0
- package/examples/basic-usage.ts +136 -0
- package/examples/blob-upload-example.ts +140 -0
- package/examples/collection-schema-example.ts +304 -0
- package/examples/server-side-joins.ts +201 -0
- package/examples/tweet-self-joins-example.ts +352 -0
- package/package-lock.json +3823 -0
- package/package.json +1 -1
- package/skills.md +1096 -0
- package/src/.env +1 -0
- package/src/batch.d.ts +121 -0
- package/src/batch.js +205 -0
- package/src/batch.ts +257 -0
- package/src/client.ts +1856 -0
- package/src/database.d.ts +268 -0
- package/src/database.js +294 -0
- package/src/database.ts +695 -0
- package/src/index.d.ts +160 -0
- package/src/index.js +186 -0
- package/src/index.ts +253 -0
- package/src/query-sdk/ConditionBuilder.ts +103 -0
- package/src/query-sdk/FieldConditionBuilder.ts +2 -0
- package/src/query-sdk/NestedBuilders.ts +186 -0
- package/src/query-sdk/OnChainDB.ts +294 -0
- package/src/query-sdk/QueryBuilder.ts +1191 -0
- package/src/query-sdk/QueryResult.ts +375 -0
- package/src/query-sdk/README.md +866 -0
- package/src/query-sdk/SelectionBuilder.ts +94 -0
- package/src/query-sdk/adapters/HttpClientAdapter.ts +249 -0
- package/src/query-sdk/dist/ConditionBuilder.d.ts +22 -0
- package/src/query-sdk/dist/ConditionBuilder.js +90 -0
- package/src/query-sdk/dist/FieldConditionBuilder.d.ts +1 -0
- package/src/query-sdk/dist/FieldConditionBuilder.js +6 -0
- package/src/query-sdk/dist/NestedBuilders.d.ts +43 -0
- package/src/query-sdk/dist/NestedBuilders.js +144 -0
- package/src/query-sdk/dist/OnChainDB.d.ts +19 -0
- package/src/query-sdk/dist/OnChainDB.js +123 -0
- package/src/query-sdk/dist/QueryBuilder.d.ts +70 -0
- package/src/query-sdk/dist/QueryBuilder.js +295 -0
- package/src/query-sdk/dist/QueryResult.d.ts +52 -0
- package/src/query-sdk/dist/QueryResult.js +293 -0
- package/src/query-sdk/dist/SelectionBuilder.d.ts +20 -0
- package/src/query-sdk/dist/SelectionBuilder.js +80 -0
- package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +27 -0
- package/src/query-sdk/dist/adapters/HttpClientAdapter.js +170 -0
- package/src/query-sdk/dist/index.d.ts +36 -0
- package/src/query-sdk/dist/index.js +27 -0
- package/src/query-sdk/dist/operators.d.ts +56 -0
- package/src/query-sdk/dist/operators.js +289 -0
- package/src/query-sdk/dist/tests/setup.d.ts +15 -0
- package/src/query-sdk/dist/tests/setup.js +46 -0
- package/src/query-sdk/index.ts +59 -0
- package/src/query-sdk/jest.config.js +25 -0
- package/src/query-sdk/operators.ts +335 -0
- package/src/query-sdk/package.json +46 -0
- package/src/query-sdk/tests/FieldConditionBuilder.test.ts +84 -0
- package/src/query-sdk/tests/LogicalOperator.test.ts +85 -0
- package/src/query-sdk/tests/NestedBuilders.test.ts +321 -0
- package/src/query-sdk/tests/QueryBuilder.test.ts +348 -0
- package/src/query-sdk/tests/QueryResult.test.ts +464 -0
- package/src/query-sdk/tests/aggregations.test.ts +653 -0
- package/src/query-sdk/tests/comprehensive.test.ts +279 -0
- package/src/query-sdk/tests/integration.test.ts +608 -0
- package/src/query-sdk/tests/operators.test.ts +327 -0
- package/src/query-sdk/tests/setup.ts +59 -0
- package/src/query-sdk/tests/unit.test.ts +794 -0
- package/src/query-sdk/tsconfig.json +26 -0
- package/src/query-sdk/yarn.lock +3092 -0
- package/src/types.d.ts +131 -0
- package/src/types.js +46 -0
- package/src/types.ts +534 -0
- package/src/x402/index.ts +12 -0
- package/src/x402/types.ts +250 -0
- package/src/x402/utils.ts +332 -0
- package/tsconfig.json +20 -0
- package/yarn.lock +2309 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
/**
|
|
3
|
+
* Example: Server-Side Self-Referential JOINs for Tweet Collection
|
|
4
|
+
*
|
|
5
|
+
* This demonstrates how to use server-side JOINs for tweets that reference other tweets:
|
|
6
|
+
* - tweet → reply_to_tweet (replies)
|
|
7
|
+
* - tweet → quote_tweet (quote tweets)
|
|
8
|
+
* - tweet → retweet_of (retweets)
|
|
9
|
+
*
|
|
10
|
+
* These are all self-referential JOINs (tweets joining with tweets)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { createClient } from '../src/index';
|
|
14
|
+
import type { ConditionBuilder, LogicalOperator } from '../src/index';
|
|
15
|
+
|
|
16
|
+
async function demonstrateTweetSelfJoins() {
|
|
17
|
+
console.log('🐦 Tweet Collection Self-Referential JOINs\n');
|
|
18
|
+
console.log('='.repeat(70));
|
|
19
|
+
console.log('');
|
|
20
|
+
|
|
21
|
+
// Initialize OnChainDB client
|
|
22
|
+
const client = createClient({
|
|
23
|
+
endpoint: 'http://localhost:9092',
|
|
24
|
+
appId: 'app_c50ae7013e424cfc'
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// ========================================
|
|
28
|
+
// Example 1: Get tweets with their replies
|
|
29
|
+
// ========================================
|
|
30
|
+
console.log('1️⃣ Get Tweets with Replies (Self-Referential JOIN)\n');
|
|
31
|
+
console.log('Query: Root tweets that have no reply_to_id, joined with their replies');
|
|
32
|
+
console.log('');
|
|
33
|
+
|
|
34
|
+
const tweetsWithReplies = client.queryBuilder()
|
|
35
|
+
.collection('tweets')
|
|
36
|
+
.whereField('reply_to_id').isNull() // Only root tweets (not replies themselves)
|
|
37
|
+
// JOIN: Get all tweets that reply to this tweet
|
|
38
|
+
.joinWith('replies', 'tweets')
|
|
39
|
+
.onField('reply_to_id').equals('$data.id') // Join condition: reply_to_id = parent.id
|
|
40
|
+
.selectFields(['id', 'content', 'author', 'created_at', 'like_count'])
|
|
41
|
+
.build()
|
|
42
|
+
.selectFields(['id', 'content', 'author', 'created_at', 'reply_count', 'replies'])
|
|
43
|
+
.limit(10);
|
|
44
|
+
|
|
45
|
+
console.log('Generated Query:');
|
|
46
|
+
console.log(JSON.stringify(tweetsWithReplies.buildRawQuery(), null, 2));
|
|
47
|
+
console.log('');
|
|
48
|
+
console.log('Expected Result Structure:');
|
|
49
|
+
console.log(`{
|
|
50
|
+
"records": [
|
|
51
|
+
{
|
|
52
|
+
"id": "tweet_123",
|
|
53
|
+
"content": "Original tweet",
|
|
54
|
+
"author": "celestia1abc...",
|
|
55
|
+
"created_at": "2025-01-15T10:00:00Z",
|
|
56
|
+
"reply_count": 3,
|
|
57
|
+
"replies": [
|
|
58
|
+
{
|
|
59
|
+
"id": "tweet_456",
|
|
60
|
+
"content": "First reply",
|
|
61
|
+
"author": "celestia1def...",
|
|
62
|
+
"created_at": "2025-01-15T10:05:00Z",
|
|
63
|
+
"like_count": 5
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "tweet_789",
|
|
67
|
+
"content": "Second reply",
|
|
68
|
+
"author": "celestia1ghi...",
|
|
69
|
+
"created_at": "2025-01-15T10:10:00Z",
|
|
70
|
+
"like_count": 2
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}`);
|
|
76
|
+
console.log('');
|
|
77
|
+
console.log('─'.repeat(70));
|
|
78
|
+
console.log('');
|
|
79
|
+
|
|
80
|
+
// ========================================
|
|
81
|
+
// Example 2: Get a specific tweet with all its replies (Thread View)
|
|
82
|
+
// ========================================
|
|
83
|
+
console.log('2️⃣ Get Single Tweet with All Replies (Thread View)\n');
|
|
84
|
+
console.log('Query: One specific tweet with all replies joined');
|
|
85
|
+
console.log('');
|
|
86
|
+
|
|
87
|
+
const tweetThread = client.queryBuilder()
|
|
88
|
+
.collection('tweets')
|
|
89
|
+
.whereField('id').equals('tweet_specific_id_here')
|
|
90
|
+
// JOIN: Get all replies to this specific tweet
|
|
91
|
+
.joinWith('replies', 'tweets')
|
|
92
|
+
.onField('reply_to_id').equals('$data.id')
|
|
93
|
+
.selectAll()
|
|
94
|
+
.build()
|
|
95
|
+
.selectAll()
|
|
96
|
+
.limit(1);
|
|
97
|
+
|
|
98
|
+
console.log('Generated Query:');
|
|
99
|
+
console.log(JSON.stringify(tweetThread.buildRawQuery(), null, 2));
|
|
100
|
+
console.log('');
|
|
101
|
+
console.log('Use Case: Tweet detail page showing the main tweet and all replies');
|
|
102
|
+
console.log('');
|
|
103
|
+
console.log('─'.repeat(70));
|
|
104
|
+
console.log('');
|
|
105
|
+
|
|
106
|
+
// ========================================
|
|
107
|
+
// Example 3: Get tweets with quoted tweets
|
|
108
|
+
// ========================================
|
|
109
|
+
console.log('3️⃣ Get Tweets with Quote Tweets (Self-Referential JOIN)\n');
|
|
110
|
+
console.log('Query: Tweets that quote other tweets');
|
|
111
|
+
console.log('');
|
|
112
|
+
|
|
113
|
+
const tweetsWithQuotes = client.queryBuilder()
|
|
114
|
+
.collection('tweets')
|
|
115
|
+
.whereField('quote_tweet_id').isNotNull() // Only quote tweets
|
|
116
|
+
// JOIN: Get the original quoted tweet
|
|
117
|
+
.joinWith('quoted_tweet', 'tweets')
|
|
118
|
+
.onField('id').equals('$data.quote_tweet_id') // Join condition: id = quote_tweet_id
|
|
119
|
+
.selectFields(['id', 'content', 'author', 'like_count', 'created_at'])
|
|
120
|
+
.build()
|
|
121
|
+
.selectFields(['id', 'content', 'author', 'quote_tweet_id', 'quoted_tweet', 'created_at'])
|
|
122
|
+
.limit(20);
|
|
123
|
+
|
|
124
|
+
console.log('Generated Query:');
|
|
125
|
+
console.log(JSON.stringify(tweetsWithQuotes.buildRawQuery(), null, 2));
|
|
126
|
+
console.log('');
|
|
127
|
+
console.log('Expected Result Structure:');
|
|
128
|
+
console.log(`{
|
|
129
|
+
"records": [
|
|
130
|
+
{
|
|
131
|
+
"id": "tweet_999",
|
|
132
|
+
"content": "Great point! Adding my thoughts...",
|
|
133
|
+
"author": "celestia1xyz...",
|
|
134
|
+
"quote_tweet_id": "tweet_777",
|
|
135
|
+
"quoted_tweet": {
|
|
136
|
+
"id": "tweet_777",
|
|
137
|
+
"content": "Original insight about decentralization",
|
|
138
|
+
"author": "celestia1abc...",
|
|
139
|
+
"like_count": 42,
|
|
140
|
+
"created_at": "2025-01-14T15:00:00Z"
|
|
141
|
+
},
|
|
142
|
+
"created_at": "2025-01-15T12:00:00Z"
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}`);
|
|
146
|
+
console.log('');
|
|
147
|
+
console.log('─'.repeat(70));
|
|
148
|
+
console.log('');
|
|
149
|
+
|
|
150
|
+
// ========================================
|
|
151
|
+
// Example 4: Multiple Self-Referential JOINs
|
|
152
|
+
// ========================================
|
|
153
|
+
console.log('4️⃣ Multiple Self-Referential JOINs (Replies + Quoted Tweets)\n');
|
|
154
|
+
console.log('Query: Root tweets with both replies AND quoted tweet info');
|
|
155
|
+
console.log('');
|
|
156
|
+
|
|
157
|
+
const complexTweets = client.queryBuilder()
|
|
158
|
+
.collection('tweets')
|
|
159
|
+
.whereField('reply_to_id').isNull()
|
|
160
|
+
// JOIN 1: Get replies
|
|
161
|
+
.joinWith('replies', 'tweets')
|
|
162
|
+
.onField('reply_to_id').equals('$data.id')
|
|
163
|
+
.selectFields(['id', 'content', 'author'])
|
|
164
|
+
.build()
|
|
165
|
+
// JOIN 2: Get quoted tweet (if this tweet is a quote)
|
|
166
|
+
.joinWith('quoted_tweet', 'tweets')
|
|
167
|
+
.onField('id').equals('$data.quote_tweet_id')
|
|
168
|
+
.selectFields(['id', 'content', 'author'])
|
|
169
|
+
.build()
|
|
170
|
+
.selectAll()
|
|
171
|
+
.limit(10);
|
|
172
|
+
|
|
173
|
+
console.log('Generated Query:');
|
|
174
|
+
console.log(JSON.stringify(complexTweets.buildRawQuery(), null, 2));
|
|
175
|
+
console.log('');
|
|
176
|
+
console.log('Use Case: Full timeline view with all tweet relationships');
|
|
177
|
+
console.log('');
|
|
178
|
+
console.log('─'.repeat(70));
|
|
179
|
+
console.log('');
|
|
180
|
+
|
|
181
|
+
// ========================================
|
|
182
|
+
// Example 5: Nested Replies (Reply Chain)
|
|
183
|
+
// ========================================
|
|
184
|
+
console.log('5️⃣ Get Reply Chain (Nested Self-Referential JOINs)\n');
|
|
185
|
+
console.log('Query: A tweet and its reply, with that reply\'s replies');
|
|
186
|
+
console.log('Note: This shows the nested JOIN structure');
|
|
187
|
+
console.log('');
|
|
188
|
+
|
|
189
|
+
// Note: For deeply nested replies, you'd need to structure nested JOINs
|
|
190
|
+
// This is a conceptual example - actual implementation depends on Scepter support
|
|
191
|
+
const replyChain = client.queryBuilder()
|
|
192
|
+
.collection('tweets')
|
|
193
|
+
.whereField('id').equals('tweet_root_id')
|
|
194
|
+
// Get direct replies to this tweet
|
|
195
|
+
.serverJoin('replies', 'tweets', {
|
|
196
|
+
find: {
|
|
197
|
+
reply_to_id: { is: '$data.id' }
|
|
198
|
+
},
|
|
199
|
+
select: {
|
|
200
|
+
id: true,
|
|
201
|
+
content: true,
|
|
202
|
+
author: true,
|
|
203
|
+
reply_count: true
|
|
204
|
+
// For nested replies, you'd add another JOIN here
|
|
205
|
+
// but that requires more complex query structure
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
.selectAll()
|
|
209
|
+
.limit(1);
|
|
210
|
+
|
|
211
|
+
console.log('Generated Query:');
|
|
212
|
+
console.log(JSON.stringify(replyChain.buildRawQuery(), null, 2));
|
|
213
|
+
console.log('');
|
|
214
|
+
console.log('For deeper nesting, you would use recursive JOIN resolution in Scepter');
|
|
215
|
+
console.log('');
|
|
216
|
+
console.log('─'.repeat(70));
|
|
217
|
+
console.log('');
|
|
218
|
+
|
|
219
|
+
// ========================================
|
|
220
|
+
// Example 6: Using Direct serverJoin() Method
|
|
221
|
+
// ========================================
|
|
222
|
+
console.log('6️⃣ Direct serverJoin() for Advanced Queries\n');
|
|
223
|
+
console.log('Query: Tweets with replies using direct JSON format');
|
|
224
|
+
console.log('');
|
|
225
|
+
|
|
226
|
+
const directServerJoin = client.queryBuilder()
|
|
227
|
+
.collection('tweets')
|
|
228
|
+
.whereField('reply_to_id').isNull()
|
|
229
|
+
// Use direct serverJoin() method for more control
|
|
230
|
+
.serverJoin('replies', 'tweets', {
|
|
231
|
+
find: {
|
|
232
|
+
reply_to_id: { is: '$data.id' }
|
|
233
|
+
},
|
|
234
|
+
select: {
|
|
235
|
+
id: true,
|
|
236
|
+
content: true,
|
|
237
|
+
author: true,
|
|
238
|
+
like_count: true
|
|
239
|
+
}
|
|
240
|
+
})
|
|
241
|
+
.selectFields(['id', 'content', 'author', 'replies'])
|
|
242
|
+
.limit(10);
|
|
243
|
+
|
|
244
|
+
console.log('Generated Query:');
|
|
245
|
+
console.log(JSON.stringify(directServerJoin.buildRawQuery(), null, 2));
|
|
246
|
+
console.log('');
|
|
247
|
+
console.log('Use Case: When you need precise control over JOIN query structure');
|
|
248
|
+
console.log('');
|
|
249
|
+
console.log('─'.repeat(70));
|
|
250
|
+
console.log('');
|
|
251
|
+
|
|
252
|
+
// ========================================
|
|
253
|
+
// Comparison: Client-Side vs Server-Side JOINs
|
|
254
|
+
// ========================================
|
|
255
|
+
console.log('📊 Performance Comparison: Client vs Server JOINs\n');
|
|
256
|
+
console.log('CLIENT-SIDE JOIN (deprecated .join() method):');
|
|
257
|
+
console.log(' 1. Query main tweets → HTTP Request 1');
|
|
258
|
+
console.log(' 2. Extract all reply_to_ids → Client processing');
|
|
259
|
+
console.log(' 3. Query tweets WHERE id IN [...] → HTTP Request 2');
|
|
260
|
+
console.log(' 4. Merge results in JavaScript → Client processing');
|
|
261
|
+
console.log(' Total: 2+ HTTP requests, client-side merging');
|
|
262
|
+
console.log('');
|
|
263
|
+
console.log('SERVER-SIDE JOIN (new .joinWith() method):');
|
|
264
|
+
console.log(' 1. Send query with JOIN clause → HTTP Request 1');
|
|
265
|
+
console.log(' 2. Backend executes recursive JOIN → Scepter engine');
|
|
266
|
+
console.log(' 3. Return fully resolved data → Single response');
|
|
267
|
+
console.log(' Total: 1 HTTP request, server-side optimization');
|
|
268
|
+
console.log('');
|
|
269
|
+
console.log('─'.repeat(70));
|
|
270
|
+
console.log('');
|
|
271
|
+
|
|
272
|
+
// ========================================
|
|
273
|
+
// Migration Guide
|
|
274
|
+
// ========================================
|
|
275
|
+
console.log('🔄 Migration from Client-Side to Server-Side JOINs\n');
|
|
276
|
+
console.log('OLD CODE (client-side):');
|
|
277
|
+
console.log(`
|
|
278
|
+
const result = await client.queryBuilder()
|
|
279
|
+
.collection('tweets')
|
|
280
|
+
.join('tweets', 'id', 'reply_to_id', 'replies') // DEPRECATED
|
|
281
|
+
.whereField('reply_to_id').isNull()
|
|
282
|
+
.execute();
|
|
283
|
+
`);
|
|
284
|
+
console.log('NEW CODE (server-side):');
|
|
285
|
+
console.log(`
|
|
286
|
+
const result = await client.queryBuilder()
|
|
287
|
+
.collection('tweets')
|
|
288
|
+
.whereField('reply_to_id').isNull()
|
|
289
|
+
.joinWith('replies', 'tweets')
|
|
290
|
+
.onField('reply_to_id').equals('$data.id')
|
|
291
|
+
.selectFields(['id', 'content', 'author'])
|
|
292
|
+
.build()
|
|
293
|
+
.execute();
|
|
294
|
+
`);
|
|
295
|
+
console.log('');
|
|
296
|
+
console.log('Benefits:');
|
|
297
|
+
console.log(' ✅ Single HTTP request instead of multiple');
|
|
298
|
+
console.log(' ✅ Recursive JOIN resolution by Scepter');
|
|
299
|
+
console.log(' ✅ Indexed lookups (O(log N) performance)');
|
|
300
|
+
console.log(' ✅ Supports nested JOINs (tweet → reply → reply)');
|
|
301
|
+
console.log(' ✅ Less client-side JavaScript processing');
|
|
302
|
+
console.log('');
|
|
303
|
+
console.log('─'.repeat(70));
|
|
304
|
+
console.log('');
|
|
305
|
+
|
|
306
|
+
// ========================================
|
|
307
|
+
// Common Patterns
|
|
308
|
+
// ========================================
|
|
309
|
+
console.log('📝 Common Tweet JOIN Patterns\n');
|
|
310
|
+
console.log('');
|
|
311
|
+
console.log('PATTERN 1: Timeline with Replies');
|
|
312
|
+
console.log(' .whereField("reply_to_id").isNull() // Root tweets only');
|
|
313
|
+
console.log(' .joinWith("replies", "tweets")');
|
|
314
|
+
console.log(' .onField("reply_to_id").equals("$data.id")');
|
|
315
|
+
console.log('');
|
|
316
|
+
console.log('PATTERN 2: Quote Tweets');
|
|
317
|
+
console.log(' .whereField("quote_tweet_id").isNotNull() // Only quotes');
|
|
318
|
+
console.log(' .joinWith("quoted_tweet", "tweets")');
|
|
319
|
+
console.log(' .onField("id").equals("$data.quote_tweet_id")');
|
|
320
|
+
console.log('');
|
|
321
|
+
console.log('PATTERN 3: Thread View');
|
|
322
|
+
console.log(' .whereField("id").equals(tweetId) // Specific tweet');
|
|
323
|
+
console.log(' .joinWith("replies", "tweets")');
|
|
324
|
+
console.log(' .onField("reply_to_id").equals("$data.id")');
|
|
325
|
+
console.log('');
|
|
326
|
+
console.log('PATTERN 4: Filtered Replies');
|
|
327
|
+
console.log(' .joinWith("verified_replies", "tweets")');
|
|
328
|
+
console.log(' .on(builder => builder.and([');
|
|
329
|
+
console.log(' builder.condition("reply_to_id", c => c.equals("$data.id")),');
|
|
330
|
+
console.log(' builder.condition("like_count", c => c.greaterThan(threshold))');
|
|
331
|
+
console.log(' ]))');
|
|
332
|
+
console.log('');
|
|
333
|
+
console.log('─'.repeat(70));
|
|
334
|
+
console.log('');
|
|
335
|
+
|
|
336
|
+
console.log('🎉 Tweet Self-Referential JOIN Examples Complete!\n');
|
|
337
|
+
console.log('Next Step: Update RealSocialService.ts to use server-side JOINs');
|
|
338
|
+
console.log('');
|
|
339
|
+
|
|
340
|
+
// Uncomment to actually execute a query:
|
|
341
|
+
// try {
|
|
342
|
+
// console.log('Executing query...');
|
|
343
|
+
// const result = await tweetsWithReplies.execute();
|
|
344
|
+
// console.log(`\n✅ Query executed: ${result.records.length} records returned`);
|
|
345
|
+
// console.log('Sample record:', JSON.stringify(result.records[0], null, 2));
|
|
346
|
+
// } catch (error) {
|
|
347
|
+
// console.error('❌ Query execution failed:', error);
|
|
348
|
+
// }
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Run the demonstration
|
|
352
|
+
demonstrateTweetSelfJoins().catch(console.error);
|