MAk110 commited on
Commit
8d6dcd8
·
verified ·
1 Parent(s): f9e8932

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +874 -19
index.html CHANGED
@@ -1,19 +1,874 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SQL Query Converter</title>
7
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-sql.min.js"></script>
9
+ <link href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" />
10
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet">
11
+ <style>
12
+ :root {
13
+ --bg-primary: #0a0e17;
14
+ --bg-secondary: #111827;
15
+ --bg-tertiary: #1a2234;
16
+ --bg-card: #141c2e;
17
+ --text-primary: #e2e8f0;
18
+ --text-secondary: #94a3b8;
19
+ --text-muted: #64748b;
20
+ --accent: #22d3ee;
21
+ --accent-secondary: #a78bfa;
22
+ --accent-glow: rgba(34, 211, 238, 0.3);
23
+ --border: #1e293b;
24
+ --success: #10b981;
25
+ --warning: #f59e0b;
26
+ --code-bg: #0d1117;
27
+ }
28
+
29
+ * {
30
+ margin: 0;
31
+ padding: 0;
32
+ box-sizing: border-box;
33
+ }
34
+
35
+ body {
36
+ font-family: 'Space Grotesk', sans-serif;
37
+ background: var(--bg-primary);
38
+ color: var(--text-primary);
39
+ min-height: 100vh;
40
+ overflow-x: hidden;
41
+ }
42
+
43
+ /* Animated background */
44
+ .bg-grid {
45
+ position: fixed;
46
+ inset: 0;
47
+ background-image:
48
+ linear-gradient(rgba(34, 211, 238, 0.03) 1px, transparent 1px),
49
+ linear-gradient(90deg, rgba(34, 211, 238, 0.03) 1px, transparent 1px);
50
+ background-size: 50px 50px;
51
+ z-index: -2;
52
+ }
53
+
54
+ .bg-glow {
55
+ position: fixed;
56
+ width: 600px;
57
+ height: 600px;
58
+ border-radius: 50%;
59
+ filter: blur(150px);
60
+ opacity: 0.15;
61
+ z-index: -1;
62
+ animation: float 20s ease-in-out infinite;
63
+ }
64
+
65
+ .bg-glow-1 {
66
+ top: -200px;
67
+ left: -200px;
68
+ background: var(--accent);
69
+ }
70
+
71
+ .bg-glow-2 {
72
+ bottom: -200px;
73
+ right: -200px;
74
+ background: var(--accent-secondary);
75
+ animation-delay: -10s;
76
+ }
77
+
78
+ @keyframes float {
79
+ 0%, 100% { transform: translate(0, 0) scale(1); }
80
+ 50% { transform: translate(50px, 50px) scale(1.1); }
81
+ }
82
+
83
+ /* Header */
84
+ .header {
85
+ padding: 1.5rem 2rem;
86
+ border-bottom: 1px solid var(--border);
87
+ background: rgba(10, 14, 23, 0.8);
88
+ backdrop-filter: blur(20px);
89
+ position: sticky;
90
+ top: 0;
91
+ z-index: 100;
92
+ }
93
+
94
+ .header-content {
95
+ max-width: 1400px;
96
+ margin: 0 auto;
97
+ display: flex;
98
+ align-items: center;
99
+ justify-content: space-between;
100
+ gap: 1rem;
101
+ flex-wrap: wrap;
102
+ }
103
+
104
+ .logo {
105
+ display: flex;
106
+ align-items: center;
107
+ gap: 0.75rem;
108
+ }
109
+
110
+ .logo-icon {
111
+ width: 40px;
112
+ height: 40px;
113
+ background: linear-gradient(135deg, var(--accent), var(--accent-secondary));
114
+ border-radius: 10px;
115
+ display: flex;
116
+ align-items: center;
117
+ justify-content: center;
118
+ font-weight: 700;
119
+ font-size: 1.25rem;
120
+ }
121
+
122
+ .logo-text {
123
+ font-size: 1.5rem;
124
+ font-weight: 700;
125
+ background: linear-gradient(135deg, var(--text-primary), var(--accent));
126
+ -webkit-background-clip: text;
127
+ -webkit-text-fill-color: transparent;
128
+ background-clip: text;
129
+ }
130
+
131
+ .built-with {
132
+ font-size: 0.875rem;
133
+ color: var(--text-muted);
134
+ text-decoration: none;
135
+ padding: 0.5rem 1rem;
136
+ border: 1px solid var(--border);
137
+ border-radius: 8px;
138
+ transition: all 0.3s ease;
139
+ }
140
+
141
+ .built-with:hover {
142
+ border-color: var(--accent);
143
+ color: var(--accent);
144
+ background: rgba(34, 211, 238, 0.1);
145
+ }
146
+
147
+ /* Main container */
148
+ .container {
149
+ max-width: 1400px;
150
+ margin: 0 auto;
151
+ padding: 2rem;
152
+ }
153
+
154
+ /* Title section */
155
+ .title-section {
156
+ text-align: center;
157
+ margin-bottom: 3rem;
158
+ animation: fadeInUp 0.8s ease-out;
159
+ }
160
+
161
+ @keyframes fadeInUp {
162
+ from {
163
+ opacity: 0;
164
+ transform: translateY(30px);
165
+ }
166
+ to {
167
+ opacity: 1;
168
+ transform: translateY(0);
169
+ }
170
+ }
171
+
172
+ .title-section h1 {
173
+ font-size: clamp(1.75rem, 4vw, 2.5rem);
174
+ font-weight: 700;
175
+ margin-bottom: 0.75rem;
176
+ background: linear-gradient(135deg, var(--text-primary), var(--accent));
177
+ -webkit-background-clip: text;
178
+ -webkit-text-fill-color: transparent;
179
+ background-clip: text;
180
+ }
181
+
182
+ .title-section p {
183
+ color: var(--text-secondary);
184
+ font-size: 1rem;
185
+ max-width: 600px;
186
+ margin: 0 auto;
187
+ }
188
+
189
+ /* Tabs */
190
+ .tabs {
191
+ display: flex;
192
+ gap: 0.5rem;
193
+ margin-bottom: 1.5rem;
194
+ border-bottom: 1px solid var(--border);
195
+ padding-bottom: 0.5rem;
196
+ animation: fadeInUp 0.8s ease-out 0.1s both;
197
+ }
198
+
199
+ .tab-btn {
200
+ padding: 0.75rem 1.5rem;
201
+ background: transparent;
202
+ border: 1px solid transparent;
203
+ border-radius: 8px 8px 0 0;
204
+ color: var(--text-secondary);
205
+ font-family: inherit;
206
+ font-size: 0.9rem;
207
+ font-weight: 500;
208
+ cursor: pointer;
209
+ transition: all 0.3s ease;
210
+ position: relative;
211
+ }
212
+
213
+ .tab-btn:hover {
214
+ color: var(--text-primary);
215
+ background: var(--bg-tertiary);
216
+ }
217
+
218
+ .tab-btn.active {
219
+ color: var(--accent);
220
+ background: var(--bg-card);
221
+ border-color: var(--border);
222
+ border-bottom-color: var(--bg-card);
223
+ }
224
+
225
+ .tab-btn.active::after {
226
+ content: '';
227
+ position: absolute;
228
+ bottom: -1px;
229
+ left: 0;
230
+ right: 0;
231
+ height: 2px;
232
+ background: var(--accent);
233
+ }
234
+
235
+ /* Code panels */
236
+ .code-panel {
237
+ display: none;
238
+ animation: fadeInUp 0.5s ease-out;
239
+ }
240
+
241
+ .code-panel.active {
242
+ display: block;
243
+ }
244
+
245
+ .code-card {
246
+ background: var(--bg-card);
247
+ border: 1px solid var(--border);
248
+ border-radius: 12px;
249
+ overflow: hidden;
250
+ }
251
+
252
+ .code-header {
253
+ display: flex;
254
+ align-items: center;
255
+ justify-content: space-between;
256
+ padding: 1rem 1.5rem;
257
+ background: var(--bg-tertiary);
258
+ border-bottom: 1px solid var(--border);
259
+ }
260
+
261
+ .code-header-left {
262
+ display: flex;
263
+ align-items: center;
264
+ gap: 0.75rem;
265
+ }
266
+
267
+ .code-dots {
268
+ display: flex;
269
+ gap: 6px;
270
+ }
271
+
272
+ .code-dot {
273
+ width: 12px;
274
+ height: 12px;
275
+ border-radius: 50%;
276
+ }
277
+
278
+ .code-dot.red { background: #ff5f57; }
279
+ .code-dot.yellow { background: #febc2e; }
280
+ .code-dot.green { background: #28c840; }
281
+
282
+ .code-title {
283
+ font-size: 0.875rem;
284
+ color: var(--text-secondary);
285
+ font-weight: 500;
286
+ }
287
+
288
+ .copy-btn {
289
+ display: flex;
290
+ align-items: center;
291
+ gap: 0.5rem;
292
+ padding: 0.5rem 1rem;
293
+ background: var(--bg-secondary);
294
+ border: 1px solid var(--border);
295
+ border-radius: 6px;
296
+ color: var(--text-secondary);
297
+ font-family: inherit;
298
+ font-size: 0.8rem;
299
+ cursor: pointer;
300
+ transition: all 0.3s ease;
301
+ }
302
+
303
+ .copy-btn:hover {
304
+ border-color: var(--accent);
305
+ color: var(--accent);
306
+ }
307
+
308
+ .copy-btn.copied {
309
+ border-color: var(--success);
310
+ color: var(--success);
311
+ }
312
+
313
+ .code-body {
314
+ padding: 1.5rem;
315
+ overflow-x: auto;
316
+ max-height: 600px;
317
+ overflow-y: auto;
318
+ }
319
+
320
+ .code-body pre {
321
+ margin: 0;
322
+ font-family: 'JetBrains Mono', monospace;
323
+ font-size: 0.85rem;
324
+ line-height: 1.7;
325
+ background: transparent !important;
326
+ }
327
+
328
+ .code-body code {
329
+ font-family: 'JetBrains Mono', monospace;
330
+ background: transparent !important;
331
+ }
332
+
333
+ /* Info cards */
334
+ .info-section {
335
+ margin-top: 2rem;
336
+ display: grid;
337
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
338
+ gap: 1.5rem;
339
+ animation: fadeInUp 0.8s ease-out 0.3s both;
340
+ }
341
+
342
+ .info-card {
343
+ background: var(--bg-card);
344
+ border: 1px solid var(--border);
345
+ border-radius: 12px;
346
+ padding: 1.5rem;
347
+ transition: all 0.3s ease;
348
+ }
349
+
350
+ .info-card:hover {
351
+ border-color: var(--accent);
352
+ transform: translateY(-2px);
353
+ box-shadow: 0 10px 40px rgba(34, 211, 238, 0.1);
354
+ }
355
+
356
+ .info-card h3 {
357
+ font-size: 1rem;
358
+ font-weight: 600;
359
+ margin-bottom: 1rem;
360
+ display: flex;
361
+ align-items: center;
362
+ gap: 0.5rem;
363
+ }
364
+
365
+ .info-card h3 svg {
366
+ width: 20px;
367
+ height: 20px;
368
+ color: var(--accent);
369
+ }
370
+
371
+ .info-card p {
372
+ color: var(--text-secondary);
373
+ font-size: 0.9rem;
374
+ line-height: 1.6;
375
+ }
376
+
377
+ .info-card ul {
378
+ list-style: none;
379
+ color: var(--text-secondary);
380
+ font-size: 0.9rem;
381
+ line-height: 1.8;
382
+ }
383
+
384
+ .info-card ul li {
385
+ display: flex;
386
+ align-items: flex-start;
387
+ gap: 0.5rem;
388
+ }
389
+
390
+ .info-card ul li::before {
391
+ content: '→';
392
+ color: var(--accent);
393
+ flex-shrink: 0;
394
+ }
395
+
396
+ /* Changes highlight */
397
+ .change-badge {
398
+ display: inline-flex;
399
+ align-items: center;
400
+ gap: 0.25rem;
401
+ padding: 0.25rem 0.5rem;
402
+ background: rgba(34, 211, 238, 0.1);
403
+ border: 1px solid rgba(34, 211, 238, 0.3);
404
+ border-radius: 4px;
405
+ font-size: 0.75rem;
406
+ color: var(--accent);
407
+ margin-left: 0.5rem;
408
+ }
409
+
410
+ /* Responsive */
411
+ @media (max-width: 768px) {
412
+ .header {
413
+ padding: 1rem;
414
+ }
415
+
416
+ .header-content {
417
+ flex-direction: column;
418
+ align-items: flex-start;
419
+ }
420
+
421
+ .container {
422
+ padding: 1rem;
423
+ }
424
+
425
+ .tabs {
426
+ overflow-x: auto;
427
+ padding-bottom: 0;
428
+ }
429
+
430
+ .tab-btn {
431
+ padding: 0.5rem 1rem;
432
+ font-size: 0.8rem;
433
+ white-space: nowrap;
434
+ }
435
+
436
+ .code-body {
437
+ padding: 1rem;
438
+ }
439
+
440
+ .code-body pre {
441
+ font-size: 0.75rem;
442
+ }
443
+
444
+ .info-section {
445
+ grid-template-columns: 1fr;
446
+ }
447
+ }
448
+
449
+ /* Scrollbar */
450
+ ::-webkit-scrollbar {
451
+ width: 8px;
452
+ height: 8px;
453
+ }
454
+
455
+ ::-webkit-scrollbar-track {
456
+ background: var(--bg-secondary);
457
+ }
458
+
459
+ ::-webkit-scrollbar-thumb {
460
+ background: var(--border);
461
+ border-radius: 4px;
462
+ }
463
+
464
+ ::-webkit-scrollbar-thumb:hover {
465
+ background: var(--text-muted);
466
+ }
467
+
468
+ /* Focus states */
469
+ button:focus-visible,
470
+ a:focus-visible {
471
+ outline: 2px solid var(--accent);
472
+ outline-offset: 2px;
473
+ }
474
+
475
+ /* Reduced motion */
476
+ @media (prefers-reduced-motion: reduce) {
477
+ *, *::before, *::after {
478
+ animation-duration: 0.01ms !important;
479
+ animation-iteration-count: 1 !important;
480
+ transition-duration: 0.01ms !important;
481
+ }
482
+ }
483
+ </style>
484
+ </head>
485
+ <body>
486
+ <div class="bg-grid"></div>
487
+ <div class="bg-glow bg-glow-1"></div>
488
+ <div class="bg-glow bg-glow-2"></div>
489
+
490
+ <header class="header">
491
+ <div class="header-content">
492
+ <div class="logo">
493
+ <div class="logo-icon">S</div>
494
+ <span class="logo-text">SQL Converter</span>
495
+ </div>
496
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" class="built-with" target="_blank" rel="noopener noreferrer">
497
+ Built with anycoder
498
+ </a>
499
+ </div>
500
+ </header>
501
+
502
+ <main class="container">
503
+ <section class="title-section">
504
+ <h1>JOIN to WHERE Clause Converter</h1>
505
+ <p>Transform your SQL queries from explicit JOIN syntax to comma-separated table syntax with WHERE clause conditions</p>
506
+ </section>
507
+
508
+ <div class="tabs">
509
+ <button class="tab-btn active" data-tab="original">Original SQL</button>
510
+ <button class="tab-btn" data-tab="converted">Converted SQL <span class="change-badge">Updated</span></button>
511
+ <button class="tab-btn" data-tab="comparison">Side by Side</button>
512
+ </div>
513
+
514
+ <div class="code-panel active" id="original">
515
+ <div class="code-card">
516
+ <div class="code-header">
517
+ <div class="code-header-left">
518
+ <div class="code-dots">
519
+ <span class="code-dot red"></span>
520
+ <span class="code-dot yellow"></span>
521
+ <span class="code-dot green"></span>
522
+ </div>
523
+ <span class="code-title">original_query.sql</span>
524
+ </div>
525
+ <button class="copy-btn" data-target="original-code">
526
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
527
+ <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
528
+ <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
529
+ </svg>
530
+ Copy
531
+ </button>
532
+ </div>
533
+ <div class="code-body">
534
+ <pre><code id="original-code" class="language-sql">WITH schema_ai_fields AS (
535
+ -- Get all metadata fields from schemas where assignee = 'ai'
536
+ SELECT
537
+ ms.id as schema_id,
538
+ ms.metadata as schema_metadata,
539
+ jsonb_object_keys(ms.metadata) as metadata_key
540
+ FROM "MediaSchema" ms
541
+ WHERE ms.metadata IS NOT NULL
542
+ AND ms.metadata != '{}'::jsonb
543
+ ),
544
+ ai_fields_expanded AS (
545
+ -- Expand to get details of each AI-assigned field
546
+ SELECT
547
+ saf.schema_id,
548
+ saf.metadata_key,
549
+ saf.schema_metadata -> saf.metadata_key as metadata_struct
550
+ FROM schema_ai_fields saf
551
+ WHERE (saf.schema_metadata -> saf.metadata_key ->> 'assignee') = 'ai'
552
+ ),
553
+ media_with_data AS (
554
+ -- Get all media with their latest MediaData
555
+ SELECT
556
+ m.id as media_id,
557
+ m.schema_id,
558
+ m.file_data,
559
+ m.file_mime_type,
560
+ md.id as media_data_id,
561
+ md.metadata as media_metadata
562
+ FROM "Media" m
563
+ LEFT JOIN "MediaData" md ON md.media_id = m.id
564
+ WHERE m.status != 'approved'
565
+ ),
566
+ items_needing_processing AS (
567
+ -- Find items where metadata doesn't exist or has status 'init'
568
+ SELECT
569
+ mwd.media_id,
570
+ mwd.media_data_id,
571
+ mwd.schema_id,
572
+ mwd.file_data,
573
+ mwd.file_mime_type,
574
+ afe.metadata_key,
575
+ afe.metadata_struct,
576
+ CASE
577
+ WHEN mwd.media_metadata IS NULL THEN NULL
578
+ WHEN mwd.media_metadata -> afe.metadata_key IS NULL THEN NULL
579
+ ELSE mwd.media_metadata -> afe.metadata_key
580
+ END as metadata_value
581
+ FROM media_with_data mwd
582
+ INNER JOIN ai_fields_expanded afe ON mwd.schema_id = afe.schema_id
583
+ WHERE
584
+ -- Either metadata is null, or the specific key doesn't exist, or status is 'init'
585
+ mwd.media_metadata IS NULL
586
+ OR mwd.media_metadata -> afe.metadata_key IS NULL
587
+ OR (mwd.media_metadata -> afe.metadata_key ->> 'status') = 'init'
588
+ )
589
+ -- Final selection excluding items that already have InstructJobs
590
+ SELECT
591
+ inp.media_id,
592
+ inp.media_data_id,
593
+ inp.schema_id,
594
+ inp.file_data,
595
+ inp.file_mime_type,
596
+ inp.metadata_key,
597
+ inp.metadata_struct,
598
+ inp.metadata_value
599
+ FROM items_needing_processing inp
600
+ WHERE NOT EXISTS (
601
+ SELECT 1 FROM "InstructJob" ij
602
+ WHERE ij.media_id = inp.media_id
603
+ AND ij.key_type = 'metadata'
604
+ AND ij.key_id = inp.metadata_key
605
+ )
606
+ ORDER BY inp.media_id, inp.metadata_key
607
+ LIMIT $1;</code></pre>
608
+ </div>
609
+ </div>
610
+ </div>
611
+
612
+ <div class="code-panel" id="converted">
613
+ <div class="code-card">
614
+ <div class="code-header">
615
+ <div class="code-header-left">
616
+ <div class="code-dots">
617
+ <span class="code-dot red"></span>
618
+ <span class="code-dot yellow"></span>
619
+ <span class="code-dot green"></span>
620
+ </div>
621
+ <span class="code-title">converted_query.sql</span>
622
+ </div>
623
+ <button class="copy-btn" data-target="converted-code">
624
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
625
+ <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
626
+ <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
627
+ </svg>
628
+ Copy
629
+ </button>
630
+ </div>
631
+ <div class="code-body">
632
+ <pre><code id="converted-code" class="language-sql">WITH schema_ai_fields AS (
633
+ -- Get all metadata fields from schemas where assignee = 'ai'
634
+ SELECT
635
+ ms.id as schema_id,
636
+ ms.metadata as schema_metadata,
637
+ jsonb_object_keys(ms.metadata) as metadata_key
638
+ FROM "MediaSchema" ms
639
+ WHERE ms.metadata IS NOT NULL
640
+ AND ms.metadata != '{}'::jsonb
641
+ ),
642
+ ai_fields_expanded AS (
643
+ -- Expand to get details of each AI-assigned field
644
+ SELECT
645
+ saf.schema_id,
646
+ saf.metadata_key,
647
+ saf.schema_metadata -> saf.metadata_key as metadata_struct
648
+ FROM schema_ai_fields saf
649
+ WHERE (saf.schema_metadata -> saf.metadata_key ->> 'assignee') = 'ai'
650
+ ),
651
+ media_with_data AS (
652
+ -- Get all media with their latest MediaData
653
+ -- Note: LEFT JOIN converted using (+) Oracle-style syntax
654
+ -- For standard SQL, this becomes an INNER JOIN when using comma syntax
655
+ SELECT
656
+ m.id as media_id,
657
+ m.schema_id,
658
+ m.file_data,
659
+ m.file_mime_type,
660
+ md.id as media_data_id,
661
+ md.metadata as media_metadata
662
+ FROM "Media" m, "MediaData" md
663
+ WHERE md.media_id(+) = m.id
664
+ AND m.status != 'approved'
665
+ ),
666
+ items_needing_processing AS (
667
+ -- Find items where metadata doesn't exist or has status 'init'
668
+ SELECT
669
+ mwd.media_id,
670
+ mwd.media_data_id,
671
+ mwd.schema_id,
672
+ mwd.file_data,
673
+ mwd.file_mime_type,
674
+ afe.metadata_key,
675
+ afe.metadata_struct,
676
+ CASE
677
+ WHEN mwd.media_metadata IS NULL THEN NULL
678
+ WHEN mwd.media_metadata -> afe.metadata_key IS NULL THEN NULL
679
+ ELSE mwd.media_metadata -> afe.metadata_key
680
+ END as metadata_value
681
+ FROM media_with_data mwd, ai_fields_expanded afe
682
+ WHERE mwd.schema_id = afe.schema_id
683
+ AND (
684
+ -- Either metadata is null, or the specific key doesn't exist, or status is 'init'
685
+ mwd.media_metadata IS NULL
686
+ OR mwd.media_metadata -> afe.metadata_key IS NULL
687
+ OR (mwd.media_metadata -> afe.metadata_key ->> 'status') = 'init'
688
+ )
689
+ )
690
+ -- Final selection excluding items that already have InstructJobs
691
+ SELECT
692
+ inp.media_id,
693
+ inp.media_data_id,
694
+ inp.schema_id,
695
+ inp.file_data,
696
+ inp.file_mime_type,
697
+ inp.metadata_key,
698
+ inp.metadata_struct,
699
+ inp.metadata_value
700
+ FROM items_needing_processing inp
701
+ WHERE NOT EXISTS (
702
+ SELECT 1 FROM "InstructJob" ij
703
+ WHERE ij.media_id = inp.media_id
704
+ AND ij.key_type = 'metadata'
705
+ AND ij.key_id = inp.metadata_key
706
+ )
707
+ ORDER BY inp.media_id, inp.metadata_key
708
+ LIMIT $1;</code></pre>
709
+ </div>
710
+ </div>
711
+ </div>
712
+
713
+ <div class="code-panel" id="comparison">
714
+ <div class="comparison-grid" style="display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem;">
715
+ <div class="code-card">
716
+ <div class="code-header">
717
+ <div class="code-header-left">
718
+ <span class="code-title" style="color: var(--warning);">Original (JOIN Syntax)</span>
719
+ </div>
720
+ </div>
721
+ <div class="code-body" style="max-height: 500px;">
722
+ <pre><code class="language-sql">-- media_with_data CTE
723
+ FROM "Media" m
724
+ LEFT JOIN "MediaData" md ON md.media_id = m.id
725
+
726
+ -- items_needing_processing CTE
727
+ FROM media_with_data mwd
728
+ INNER JOIN ai_fields_expanded afe
729
+ ON mwd.schema_id = afe.schema_id</code></pre>
730
+ </div>
731
+ </div>
732
+ <div class="code-card">
733
+ <div class="code-header">
734
+ <div class="code-header-left">
735
+ <span class="code-title" style="color: var(--success);">Converted (WHERE Syntax)</span>
736
+ </div>
737
+ </div>
738
+ <div class="code-body" style="max-height: 500px;">
739
+ <pre><code class="language-sql">-- media_with_data CTE
740
+ FROM "Media" m, "MediaData" md
741
+ WHERE md.media_id(+) = m.id
742
+
743
+ -- items_needing_processing CTE
744
+ FROM media_with_data mwd, ai_fields_expanded afe
745
+ WHERE mwd.schema_id = afe.schema_id</code></pre>
746
+ </div>
747
+ </div>
748
+ </div>
749
+ </div>
750
+
751
+ <section class="info-section">
752
+ <div class="info-card">
753
+ <h3>
754
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
755
+ <circle cx="12" cy="12" r="10"></circle>
756
+ <line x1="12" y1="16" x2="12" y2="12"></line>
757
+ <line x1="12" y1="8" x2="12.01" y2="8"></line>
758
+ </svg>
759
+ Conversion Notes
760
+ </h3>
761
+ <ul>
762
+ <li>INNER JOIN becomes comma-separated tables with WHERE condition</li>
763
+ <li>LEFT JOIN uses Oracle-style (+) syntax for outer join</li>
764
+ <li>Join conditions move from ON clause to WHERE clause</li>
765
+ <li>CTEs remain unchanged in structure</li>
766
+ </ul>
767
+ </div>
768
+ <div class="info-card">
769
+ <h3>
770
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
771
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
772
+ </svg>
773
+ Important Considerations
774
+ </h3>
775
+ <p>The (+) syntax is Oracle-specific. For PostgreSQL, you would need to keep the LEFT JOIN or use a different approach. Standard SQL comma syntax only supports INNER JOIN behavior.</p>
776
+ </div>
777
+ <div class="info-card">
778
+ <h3>
779
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
780
+ <polyline points="16 18 22 12 16 6"></polyline>
781
+ <polyline points="8 6 2 12 8 18"></polyline>
782
+ </svg>
783
+ Key Changes Made
784
+ </h3>
785
+ <ul>
786
+ <li><code>LEFT JOIN ... ON</code> → <code>, ... WHERE ...(+)</code></li>
787
+ <li><code>INNER JOIN ... ON</code> → <code>, ... WHERE ...</code></li>
788
+ <li>Combined join conditions with existing WHERE filters</li>
789
+ </ul>
790
+ </div>
791
+ </section>
792
+ </main>
793
+
794
+ <script>
795
+ // Tab switching
796
+ const tabBtns = document.querySelectorAll('.tab-btn');
797
+ const panels = document.querySelectorAll('.code-panel');
798
+
799
+ tabBtns.forEach(btn => {
800
+ btn.addEventListener('click', () => {
801
+ const tabId = btn.dataset.tab;
802
+
803
+ tabBtns.forEach(b => b.classList.remove('active'));
804
+ panels.forEach(p => p.classList.remove('active'));
805
+
806
+ btn.classList.add('active');
807
+ document.getElementById(tabId).classList.add('active');
808
+ });
809
+ });
810
+
811
+ // Copy functionality
812
+ const copyBtns = document.querySelectorAll('.copy-btn');
813
+
814
+ copyBtns.forEach(btn => {
815
+ btn.addEventListener('click', async () => {
816
+ const targetId = btn.dataset.target;
817
+ const codeElement = document.getElementById(targetId);
818
+ const text = codeElement.textContent;
819
+
820
+ try {
821
+ await navigator.clipboard.writeText(text);
822
+ btn.classList.add('copied');
823
+ btn.innerHTML = `
824
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
825
+ <polyline points="20 6 9 17 4 12"></polyline>
826
+ </svg>
827
+ Copied!
828
+ `;
829
+
830
+ setTimeout(() => {
831
+ btn.classList.remove('copied');
832
+ btn.innerHTML = `
833
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
834
+ <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
835
+ <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
836
+ </svg>
837
+ Copy
838
+ `;
839
+ }, 2000);
840
+ } catch (err) {
841
+ console.error('Failed to copy:', err);
842
+ }
843
+ });
844
+ });
845
+
846
+ // Re-highlight code after DOM is ready
847
+ if (typeof Prism !== 'undefined') {
848
+ Prism.highlightAll();
849
+ }
850
+
851
+ // Intersection Observer for scroll animations
852
+ const observerOptions = {
853
+ threshold: 0.1,
854
+ rootMargin: '0px 0px -50px 0px'
855
+ };
856
+
857
+ const observer = new IntersectionObserver((entries) => {
858
+ entries.forEach(entry => {
859
+ if (entry.isIntersecting) {
860
+ entry.target.style.opacity = '1';
861
+ entry.target.style.transform = 'translateY(0)';
862
+ }
863
+ });
864
+ }, observerOptions);
865
+
866
+ document.querySelectorAll('.info-card').forEach(card => {
867
+ card.style.opacity = '0';
868
+ card.style.transform = 'translateY(20px)';
869
+ card.style.transition = 'all 0.6s ease-out';
870
+ observer.observe(card);
871
+ });
872
+ </script>
873
+ </body>
874
+ </html>