@@ -7,76 +7,100 @@ import {
7
7
isModuleWorkerSupport ,
8
8
isOpfsSupported ,
9
9
useMemoryStorage ,
10
- } from '../../src'
11
- import { useIdbStorage } from '../../src/vfs/idb'
10
+ withExistDB ,
11
+ } from '../../src/index'
12
+ import { useIdbMemoryStorage as useIdbStorage } from '../../src/vfs/idb'
12
13
import { runSQL } from './runSQL'
13
14
import OpfsWorker from './worker?worker'
14
15
15
- const { run, close } = await initSQLite ( useIdbStorage ( 'test.db' , {
16
- url,
17
- // url: 'https://cdn.jsdelivr.net/gh/rhashimoto/wa-sqlite@v0.9.9/dist/wa-sqlite-async.wasm',
18
- } ) )
16
+ let db = await initSQLite ( useIdbStorage ( 'test.db' , { url } ) )
19
17
20
18
const supportModuleWorker = isModuleWorkerSupport ( )
21
19
const supportIDB = isIdbSupported ( )
22
20
const supportOPFS = await isOpfsSupported ( )
23
21
console . log ( 'support module worker:' , supportModuleWorker )
24
22
console . log ( 'support IDBBatchAtomicVFS:' , supportIDB )
25
23
console . log ( 'support OPFSCoopSyncVFS:' , supportOPFS )
26
- await runSQL ( run )
27
- await runSQL ( ( await initSQLite ( useMemoryStorage ( { url : syncUrl } ) ) ) . run )
28
-
29
- const worker = new OpfsWorker ( )
30
- const ee = mitt < {
31
- data : [ any ]
32
- done : [ ]
33
- } > ( )
34
- worker . onmessage = ( { data } ) => {
35
- if ( data === 'done' ) {
36
- ee . emit ( 'done' )
37
- } else {
38
- ee . emit ( 'data' , data )
24
+ document . querySelector ( '.main' ) ?. addEventListener ( 'click' , async ( ) => {
25
+ if ( ! db ) {
26
+ db = await initSQLite ( useIdbStorage ( 'test.db' , { url } ) )
39
27
}
40
- }
41
- function test ( ) : AsyncIterableIterator < any > {
42
- let resolver : ( ( value : IteratorResult < any > ) => void ) | null = null
28
+ await runSQL ( db . run )
29
+ await runSQL ( ( await initSQLite ( useMemoryStorage ( { url : syncUrl } ) ) ) . run )
30
+ } )
31
+ document . querySelector ( '.import' ) ?. addEventListener ( 'click' , async ( ) => {
32
+ await db ?. close ( )
33
+ let file
34
+ try {
35
+ file = await selectFile ( '.db,.sqlite,.sqlite3' )
36
+ } catch ( error ) {
37
+ // eslint-disable-next-line no-alert
38
+ prompt ( `${ error } ` )
39
+ return
40
+ }
41
+ db = await initSQLite (
42
+ useIdbStorage ( 'test.db' , withExistDB ( file , { url } ) ) ,
43
+ )
44
+ console . log (
45
+ await db . run ( `SELECT "type", "tbl_name" AS "table", CASE WHEN "sql" LIKE '%PRIMARY KEY AUTOINCREMENT%' THEN 1 ELSE "name" END AS "name" FROM "sqlite_master"` ) ,
46
+ )
47
+ } )
43
48
44
- ee . on ( 'data' , ( ...data ) => {
45
- if ( resolver ) {
46
- console . log ( 'data' )
47
- resolver ( { value : data [ 0 ] } )
48
- resolver = null
49
- }
50
- } )
49
+ document . querySelector ( '.download' ) ?. addEventListener ( 'click' , async ( ) => {
50
+ download ( await db . dump ( ) )
51
+ } )
51
52
52
- ee . on ( 'done' , ( ) => {
53
- if ( resolver ) {
54
- resolver ( { value : undefined , done : true } )
53
+ document . querySelector ( '.worker' ) ?. addEventListener ( 'click' , async ( ) => {
54
+ const worker = new OpfsWorker ( )
55
+ const ee = mitt < {
56
+ data : [ any ]
57
+ done : [ ]
58
+ } > ( )
59
+ worker . onmessage = ( { data } ) => {
60
+ if ( data === 'done' ) {
61
+ ee . emit ( 'done' )
62
+ } else {
63
+ ee . emit ( 'data' , data )
55
64
}
56
- } )
65
+ }
66
+ function test ( ) : AsyncIterableIterator < any > {
67
+ let resolver : ( ( value : IteratorResult < any > ) => void ) | null = null
57
68
58
- return {
59
- [ Symbol . asyncIterator ] ( ) {
60
- return this
61
- } ,
62
- async next ( ) {
63
- return new Promise < IteratorResult < any > > ( ( resolve ) => {
64
- resolver = resolve
65
- } )
66
- } ,
67
- async return ( ) {
68
- return { value : undefined , done : true }
69
- } ,
70
- } satisfies AsyncIterableIterator < any >
71
- }
72
- document . querySelector ( '.worker' ) ?. addEventListener ( 'click' , async ( ) => {
69
+ ee . on ( 'data' , ( ...data ) => {
70
+ if ( resolver ) {
71
+ console . log ( 'data' )
72
+ resolver ( { value : data [ 0 ] } )
73
+ resolver = null
74
+ }
75
+ } )
76
+
77
+ ee . on ( 'done' , ( ) => {
78
+ if ( resolver ) {
79
+ resolver ( { value : undefined , done : true } )
80
+ }
81
+ } )
82
+
83
+ return {
84
+ [ Symbol . asyncIterator ] ( ) {
85
+ return this
86
+ } ,
87
+ async next ( ) {
88
+ return new Promise < IteratorResult < any > > ( ( resolve ) => {
89
+ resolver = resolve
90
+ } )
91
+ } ,
92
+ async return ( ) {
93
+ return { value : undefined , done : true }
94
+ } ,
95
+ } satisfies AsyncIterableIterator < any >
96
+ }
73
97
worker . postMessage ( '' )
74
98
for await ( const data of test ( ) ) {
75
99
console . log ( 'iterator' , data )
76
100
}
77
101
} )
78
102
document . querySelector ( '.clear' ) ?. addEventListener ( 'click' , async ( ) => {
79
- await close ( )
103
+ await db . close ( )
80
104
const root = await navigator . storage . getDirectory ( )
81
105
for await ( const [ name ] of root . entries ( ) ) {
82
106
console . log ( 'clear' , name )
@@ -91,3 +115,54 @@ document.querySelector('.clear')?.addEventListener('click', async () => {
91
115
} )
92
116
console . log ( 'clear all IndexedDB' )
93
117
} )
118
+
119
+ function download ( buffer : Uint8Array ) : void {
120
+ const blob = new Blob ( [ buffer ] )
121
+ const reader = new FileReader ( )
122
+ reader . readAsDataURL ( blob )
123
+ reader . onload = ( e ) => {
124
+ const a = document . createElement ( 'a' )
125
+ a . download = `test.db`
126
+ a . href = e . target ?. result as string
127
+ document . body . appendChild ( a )
128
+ a . click ( )
129
+ document . body . removeChild ( a )
130
+ }
131
+ }
132
+
133
+ async function selectFile ( accept ?: string ) : Promise < File > {
134
+ return await new Promise ( ( resolve , reject ) => {
135
+ const input = document . createElement ( 'input' )
136
+ input . type = 'file'
137
+ if ( accept ) {
138
+ input . accept = accept
139
+ }
140
+
141
+ input . onchange = ( ) => {
142
+ const file = input . files ?. [ 0 ]
143
+ if ( file ) {
144
+ resolve ( file )
145
+ } else {
146
+ reject ( new Error ( 'No file selected' ) )
147
+ }
148
+ input . remove ( )
149
+ }
150
+
151
+ input . oncancel = ( ) => {
152
+ reject ( new Error ( 'File selection cancelled' ) )
153
+ input . remove ( )
154
+ }
155
+
156
+ // 处理用户点击取消的情况
157
+ window . addEventListener ( 'focus' , ( ) => {
158
+ setTimeout ( ( ) => {
159
+ if ( ! input . files ?. length ) {
160
+ reject ( new Error ( 'File selection cancelled' ) )
161
+ input . remove ( )
162
+ }
163
+ } , 300 )
164
+ } , { once : true } )
165
+
166
+ input . click ( )
167
+ } )
168
+ }
0 commit comments