Skip to content

Commit 243562c

Browse files
chtituxclaude
andcommitted
Migrate website to v0.6.0 pluggable-adapter API
- demo.ts: construct adapter via createSqlJsAdapter({ SQL }) and await every query, export, close. Promise.all for the two map() loops that call gtfs.getStops / gtfs.getRoutes per item. - index.html: Quick Start and filter example show the adapter + await. Drop removed *ById lookup methods, list current shape/RT/db methods. - package.json: pin sql.js directly (no longer transitive in v0.6). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4df5c6d commit 243562c

4 files changed

Lines changed: 99 additions & 64 deletions

File tree

website/demo.ts

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import initSqlJs from 'sql.js';
22
import type { SqlJsStatic } from 'sql.js';
33
import { GtfsSqlJs } from 'gtfs-sqljs';
4+
import { createSqlJsAdapter } from 'gtfs-sqljs/adapters/sql-js';
45
import type { Route, Trip, StopTime, Agency, Alert, VehiclePosition, TripWithRealtime, StopTimeWithRealtime } from 'gtfs-sqljs';
56

67
let gtfs: GtfsSqlJs;
@@ -38,7 +39,7 @@ async function loadGTFS(url: string) {
3839
// Load GTFS data
3940
// Skip shapes.txt to reduce memory usage and improve load time
4041
gtfs = await GtfsSqlJs.fromZip(source, {
41-
SQL,
42+
adapter: await createSqlJsAdapter({ SQL }),
4243
skipFiles: ['shapes.txt']
4344
});
4445

@@ -60,13 +61,13 @@ async function loadGTFS(url: string) {
6061
setupRTButtons();
6162

6263
// Render initial data
63-
renderAgencies();
64-
renderActiveCalendars();
65-
renderRoutes();
64+
await renderAgencies();
65+
await renderActiveCalendars();
66+
await renderRoutes();
6667

6768
// Clear RT displays
68-
renderAlerts();
69-
renderVehicleCount();
69+
await renderAlerts();
70+
await renderVehicleCount();
7071
} catch (error) {
7172
console.error('Error loading GTFS data:', error);
7273
loadingEl.style.display = 'none';
@@ -121,11 +122,11 @@ function initDatePicker() {
121122
selectedDate = `${year}${month}${day}`; // YYYYMMDD format for GTFS
122123

123124
// Listen for date changes
124-
dateInput.addEventListener('change', (e) => {
125+
dateInput.addEventListener('change', async (e) => {
125126
const target = e.target as HTMLInputElement;
126127
const [y, m, d] = target.value.split('-');
127128
selectedDate = `${y}${m}${d}`;
128-
renderActiveCalendars();
129+
await renderActiveCalendars();
129130

130131
// Reset trips section
131132
document.getElementById('trips-section')!.style.display = 'none';
@@ -134,11 +135,11 @@ function initDatePicker() {
134135
}
135136

136137
// Render agencies
137-
function renderAgencies() {
138+
async function renderAgencies() {
138139
const agenciesListEl = document.getElementById('agencies-list')!;
139140

140141
try {
141-
const agencies = gtfs.getAgencies();
142+
const agencies = await gtfs.getAgencies();
142143

143144
if (agencies.length === 0) {
144145
agenciesListEl.innerHTML = '<p>No agency information available</p>';
@@ -166,11 +167,11 @@ function renderAgencies() {
166167
}
167168

168169
// Render active calendars for selected date
169-
function renderActiveCalendars() {
170+
async function renderActiveCalendars() {
170171
const activeCalendarsEl = document.getElementById('active-calendars')!;
171172

172173
try {
173-
const serviceIds = gtfs.getActiveServiceIds(selectedDate);
174+
const serviceIds = await gtfs.getActiveServiceIds(selectedDate);
174175

175176
if (serviceIds.length === 0) {
176177
activeCalendarsEl.innerHTML = '<p class="info-text">No active service calendars for this date</p>';
@@ -190,9 +191,9 @@ function renderActiveCalendars() {
190191
}
191192

192193
// Render routes list
193-
function renderRoutes() {
194+
async function renderRoutes() {
194195
const routesListEl = document.getElementById('routes-list')!;
195-
const routes = gtfs.getRoutes();
196+
const routes = await gtfs.getRoutes();
196197

197198
if (routes.length === 0) {
198199
routesListEl.innerHTML = '<p>No routes found</p>';
@@ -218,7 +219,7 @@ function renderRoutes() {
218219
}
219220

220221
// Show trips for a route
221-
(window as any).showTrips = function(routeId: string, routeName: string) {
222+
(window as any).showTrips = async function(routeId: string, routeName: string) {
222223
const tripsSectionEl = document.getElementById('trips-section')!;
223224
const tripsListEl = document.getElementById('trips-list')!;
224225
const selectedRouteNameEl = document.getElementById('selected-route-name')!;
@@ -228,11 +229,11 @@ function renderRoutes() {
228229
stopTimesSectionEl.style.display = 'none';
229230

230231
// Get trips for this route on the selected date (with realtime data)
231-
const trips = gtfs.getTrips({
232+
const trips = (await gtfs.getTrips({
232233
routeId: routeId,
233234
date: selectedDate,
234235
includeRealtime: true
235-
}) as TripWithRealtime[];
236+
})) as TripWithRealtime[];
236237

237238
if (trips.length === 0) {
238239
tripsListEl.innerHTML = '<p>No trips found for this route on the selected date</p>';
@@ -339,16 +340,16 @@ function renderRoutes() {
339340
};
340341

341342
// Show stop times for a trip
342-
(window as any).showStopTimes = function(tripId: string, tripName: string) {
343+
(window as any).showStopTimes = async function(tripId: string, tripName: string) {
343344
const stopTimesSectionEl = document.getElementById('stop-times-section')!;
344345
const stopTimesListEl = document.getElementById('stop-times-list')!;
345346
const selectedTripNameEl = document.getElementById('selected-trip-name')!;
346347

347348
// Get stop times for this trip (with realtime data)
348-
const stopTimes = gtfs.getStopTimes({
349+
const stopTimes = (await gtfs.getStopTimes({
349350
tripId: tripId,
350351
includeRealtime: true
351-
}) as StopTimeWithRealtime[];
352+
})) as StopTimeWithRealtime[];
352353

353354
if (stopTimes.length === 0) {
354355
stopTimesListEl.innerHTML = '<p>No stop times found for this trip</p>';
@@ -358,8 +359,8 @@ function renderRoutes() {
358359
}
359360

360361
// Render stop times with stop names and realtime data
361-
const html = stopTimes.map(st => {
362-
const stops = gtfs.getStops({ stopId: st.stop_id });
362+
const html = (await Promise.all(stopTimes.map(async st => {
363+
const stops = await gtfs.getStops({ stopId: st.stop_id });
363364
const stop = stops.length > 0 ? stops[0] : null;
364365
const stopName = stop ? stop.stop_name : st.stop_id;
365366

@@ -393,7 +394,7 @@ function renderRoutes() {
393394
<div class="stop-name">${escapeHtml(stopName)}</div>
394395
</div>
395396
`;
396-
}).join('');
397+
}))).join('');
397398

398399
stopTimesListEl.innerHTML = html;
399400
stopTimesSectionEl.style.display = 'block';
@@ -417,8 +418,8 @@ async function fetchRealtimeData() {
417418
await gtfs.fetchRealtimeData([proxyUrl]);
418419

419420
// Update displays
420-
renderAlerts();
421-
renderVehicleCount();
421+
await renderAlerts();
422+
await renderVehicleCount();
422423
} catch (error) {
423424
console.error('Error fetching realtime data:', error);
424425
alert(`Failed to fetch realtime data: ${error instanceof Error ? error.message : String(error)}`);
@@ -466,18 +467,18 @@ function setupRTButtons() {
466467
}
467468

468469
// Render alerts
469-
function renderAlerts() {
470+
async function renderAlerts() {
470471
const alertsListEl = document.getElementById('alerts-list')!;
471472

472473
try {
473-
const alerts = gtfs.getAlerts({ activeOnly: true });
474+
const alerts = await gtfs.getAlerts({ activeOnly: true });
474475

475476
if (alerts.length === 0) {
476477
alertsListEl.innerHTML = '<p class="no-data">No active alerts</p>';
477478
return;
478479
}
479480

480-
const html = alerts.map(alert => {
481+
const html = (await Promise.all(alerts.map(async alert => {
481482
let headerText = 'Alert';
482483
if (alert.header_text) {
483484
try {
@@ -508,16 +509,16 @@ function renderAlerts() {
508509
.map(e => e.route_id)
509510
.slice(0, 10); // Show max 10 routes
510511

511-
const routesBadges = affectedRoutes.map(routeId => {
512-
const routes = gtfs.getRoutes({ routeId: routeId! });
512+
const routesBadges = (await Promise.all(affectedRoutes.map(async routeId => {
513+
const routes = await gtfs.getRoutes({ routeId: routeId! });
513514
const route = routes.length > 0 ? routes[0] : null;
514515
if (!route) return '';
515516

516517
const bgColor = route.route_color ? `#${route.route_color}` : '#64748b';
517518
const textColor = route.route_text_color ? `#${route.route_text_color}` : getContrastColor(bgColor);
518519

519520
return `<span class="route-badge" style="background-color: ${bgColor}; color: ${textColor};">${escapeHtml(route.route_short_name ?? '')}</span>`;
520-
}).join('');
521+
}))).join('');
521522

522523
const moreRoutes = alert.informed_entity.filter(e => e.route_id).length > 10
523524
? `<span class="route-badge-more">+${alert.informed_entity.filter(e => e.route_id).length - 10} more</span>`
@@ -530,7 +531,7 @@ function renderAlerts() {
530531
${routesBadges || moreRoutes ? `<div class="alert-routes">Affected routes: ${routesBadges}${moreRoutes}</div>` : ''}
531532
</div>
532533
`;
533-
}).join('');
534+
}))).join('');
534535

535536
alertsListEl.innerHTML = html;
536537
} catch (error) {
@@ -540,11 +541,11 @@ function renderAlerts() {
540541
}
541542

542543
// Render vehicle count
543-
function renderVehicleCount() {
544+
async function renderVehicleCount() {
544545
const vehiclesCountEl = document.getElementById('vehicles-count')!;
545546

546547
try {
547-
const vehicles = gtfs.getVehiclePositions();
548+
const vehicles = await gtfs.getVehiclePositions();
548549

549550
if (vehicles.length === 0) {
550551
vehiclesCountEl.innerHTML = '<p class="no-data">No tracked vehicles</p>';
@@ -568,10 +569,10 @@ function setupDownloadButton() {
568569
const downloadBtn = document.getElementById('download-db-btn') as HTMLButtonElement;
569570
if (!downloadBtn) return;
570571

571-
downloadBtn.addEventListener('click', () => {
572+
downloadBtn.addEventListener('click', async () => {
572573
try {
573574
// Export database to ArrayBuffer
574-
const dbData = gtfs.export();
575+
const dbData = await gtfs.export();
575576

576577
// Create blob and download
577578
const blob = new Blob([dbData], { type: 'application/x-sqlite3' });

website/index.html

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -74,23 +74,25 @@ <h2>Installation</h2>
7474
<section class="quick-start">
7575
<h2>Quick Start</h2>
7676
<pre><code>import { GtfsSqlJs } from 'gtfs-sqljs';
77+
import { createSqlJsAdapter } from 'gtfs-sqljs/adapters/sql-js';
7778

7879
// Load from ZIP file (skip shapes.txt to reduce memory)
7980
const gtfs = await GtfsSqlJs.fromZip('https://example.com/gtfs.zip', {
81+
adapter: await createSqlJsAdapter(),
8082
skipFiles: ['shapes.txt']
8183
});
8284

8385
// Get all routes (using flexible API)
84-
const routes = gtfs.getRoutes();
86+
const routes = await gtfs.getRoutes();
8587

8688
// Get stops for a trip
87-
const stops = gtfs.getStops({ tripId: 'trip_id' });
89+
const stops = await gtfs.getStops({ tripId: 'trip_id' });
8890

8991
// Get active trips for a date
90-
const trips = gtfs.getTrips({ date: '20240115' });
92+
const trips = await gtfs.getTrips({ date: '20240115' });
9193

9294
// Clean up
93-
gtfs.close();</code></pre>
95+
await gtfs.close();</code></pre>
9496
</section>
9597

9698
<section class="api">
@@ -105,20 +107,12 @@ <h3>⭐ Flexible Filter-Based Methods (Recommended)</h3>
105107
<li><code>getStopTimes(filters?)</code> - Filter by: tripId, stopId, routeId, date, directionId, limit</li>
106108
</ul>
107109
<pre><code>// Example: Get trips for a route on a specific date going one direction
108-
const trips = gtfs.getTrips({
110+
const trips = await gtfs.getTrips({
109111
routeId: 'ROUTE_1',
110112
date: '20240115',
111113
directionId: 0
112114
});</code></pre>
113115

114-
<h3>Direct Lookup Methods</h3>
115-
<ul>
116-
<li><code>getStopById(stopId)</code> - Get stop by ID</li>
117-
<li><code>getRouteById(routeId)</code> - Get route by ID</li>
118-
<li><code>getTripById(tripId)</code> - Get trip by ID</li>
119-
<li><code>getAgencyById(agencyId)</code> - Get agency by ID</li>
120-
</ul>
121-
122116
<h3>Calendar Methods</h3>
123117
<ul>
124118
<li><code>getActiveServiceIds(date)</code> - Get active services for a date (YYYYMMDD)</li>
@@ -127,17 +121,33 @@ <h3>Calendar Methods</h3>
127121
<li><code>getCalendarDatesForDate(date)</code> - Get exceptions for a specific date</li>
128122
</ul>
129123

130-
<h3>Special Methods</h3>
124+
<h3>Shape Methods</h3>
131125
<ul>
132-
<li><code>getStopTimesByTrip(tripId)</code> - Get stop times for a trip (ordered by stop_sequence)</li>
126+
<li><code>getShapes(filters?)</code> - Get shape points, optionally filtered by shapeId</li>
127+
<li><code>getShapesToGeojson(filters?, precision?)</code> - Get shapes as a GeoJSON FeatureCollection</li>
128+
<li><code>buildOrderedStopList(tripIds)</code> - Build the ordered stop list for a set of trips</li>
129+
</ul>
130+
131+
<h3>GTFS-Realtime Methods</h3>
132+
<ul>
133+
<li><code>setRealtimeFeedUrls(urls)</code> - Configure RT feed URLs</li>
134+
<li><code>fetchRealtimeData(urls?)</code> - Fetch and load RT data</li>
135+
<li><code>loadRealtimeDataFromBuffers(buffers)</code> - Load pre-fetched protobuf buffers</li>
136+
<li><code>clearRealtimeData()</code> - Clear loaded RT data</li>
137+
<li><code>getAlerts(filters?)</code> - Get service alerts</li>
138+
<li><code>getVehiclePositions(filters?)</code> - Get vehicle positions</li>
139+
<li><code>getTripUpdates(filters?)</code> - Get trip updates</li>
140+
<li><code>getStopTimeUpdates(filters?)</code> - Get stop-time updates</li>
133141
</ul>
134142

135143
<h3>Database Methods</h3>
136144
<ul>
137-
<li><code>export()</code> - Export database to ArrayBuffer</li>
138-
<li><code>getDatabase()</code> - Get direct access to sql.js database</li>
139-
<li><code>close()</code> - Close database connection</li>
145+
<li><code>export()</code> - Export database to <code>ArrayBuffer</code> (async; throws <code>ExportNotSupportedError</code> on file-backed adapters)</li>
146+
<li><code>getDatabase()</code> - Get the underlying <code>GtfsDatabase</code> adapter handle (async <code>prepare</code>/<code>run</code>/<code>export</code>/<code>close</code>)</li>
147+
<li><code>close()</code> - Close database connection (async)</li>
140148
</ul>
149+
150+
<p class="api-note">All query methods return <code>Promise&lt;T&gt;</code>. Direct lookups like <code>getStopById</code> / <code>getRouteById</code> / <code>getTripById</code> / <code>getAgencyById</code> have been replaced by the filter-based methods above (e.g. <code>getStops({ stopId })</code>).</p>
141151
</section>
142152

143153
<section class="author">

0 commit comments

Comments
 (0)