@@ -208,10 +208,17 @@ export abstract class SqlProviderBase extends NoSqlProvider.DbProvider {
208208
209209 dropQueries = _ . map ( tableNames , name => trans . runQuery ( 'DROP TABLE ' + name ) ) ;
210210
211- // Drop all existing metadata
212- const metaToDropArg = _ . map ( indexMetadata , meta => meta . key ) . join ( ', ' ) ;
213- dropQueries . push ( trans . runQuery ( 'DELETE FROM metadata where name in (?) ' , [ metaToDropArg ] ) ) ;
214- indexMetadata = [ ] ;
211+ if ( indexMetadata . length > 0 ) {
212+ // Generate as many '?' as there are params
213+ let placeholder = '?' ;
214+ for ( let i = 1 ; i < indexMetadata . length ; i ++ ) {
215+ placeholder += ',?' ;
216+ }
217+ // Drop all existing metadata
218+ dropQueries . push ( trans . runQuery ( 'DELETE FROM metadata WHERE name IN (' + placeholder + ')' ,
219+ _ . map ( indexMetadata , meta => meta . key ) ) ) ;
220+ indexMetadata = [ ] ;
221+ }
215222 tableNames = [ ] ;
216223 } else {
217224 // Just delete tables we don't care about anymore. Preserve multi-entry tables, they may not be changed
@@ -232,7 +239,13 @@ export abstract class SqlProviderBase extends NoSqlProvider.DbProvider {
232239
233240 // Clean up metas
234241 if ( metasToDelete . length > 0 ) {
235- transList . push ( trans . runQuery ( 'DELETE FROM metadata where name in (?)' , [ metasToDelete . join ( ', ' ) ] ) ) ;
242+ // Generate as many '?' as there are params
243+ let placeholder = '?' ;
244+ for ( let i = 1 ; i < metasToDelete . length ; i ++ ) {
245+ placeholder += ',?' ;
246+ }
247+ transList . push ( trans . runQuery ( 'DELETE FROM metadata where name in (' + placeholder + ')' ,
248+ _ . map ( metasToDelete , meta => meta . key ) ) ) ;
236249 indexMetadata = _ . filter ( indexMetadata , meta => ! _ . includes ( metaKeysToDelete , meta . key ) ) ;
237250 }
238251 return transList ;
@@ -246,9 +259,11 @@ export abstract class SqlProviderBase extends NoSqlProvider.DbProvider {
246259
247260 // Go over each store and see what needs changing
248261 _ . each ( this . _schema ! ! ! . stores , storeSchema => {
249- const indexMaker = ( ) => {
262+
263+ // creates indexes for provided schemas
264+ const indexMaker = ( indexes : NoSqlProvider . IndexSchema [ ] = [ ] ) => {
250265 let metaQueries : SyncTasks . Promise < any > [ ] = [ ] ;
251- const indexQueries = _ . map ( storeSchema . indexes , index => {
266+ const indexQueries = _ . map ( indexes , index => {
252267 const indexIdentifier = getIndexIdentifier ( storeSchema , index ) ;
253268
254269 // Store meta for the index
@@ -293,31 +308,64 @@ export abstract class SqlProviderBase extends NoSqlProvider.DbProvider {
293308
294309 const columnBasedIndexes = _ . filter ( storeSchema . indexes , index =>
295310 ! indexUsesSeparateTable ( index , this . _supportsFTS3 ) ) ;
311+
296312 const indexColumns = _ . map ( columnBasedIndexes , index => 'nsp_i_' + index . name + ' TEXT' ) ;
297313 fieldList = fieldList . concat ( indexColumns ) ;
298314 const tableMakerSql = 'CREATE TABLE ' + storeSchema . name + ' (' + fieldList . join ( ', ' ) + ')' ;
315+
316+ const currentIndexMetas = _ . filter ( indexMetadata , meta => meta . storeName === storeSchema . name ) ;
317+
318+ // find new indices which don't require backfill
319+ const newNoBackfillIndices = _ . filter ( storeSchema . indexes , index => {
320+ const indexIdentifier = getIndexIdentifier ( storeSchema , index ) ;
321+ return ! ! index . doNotBackfill && ! _ . some ( currentIndexMetas , meta => meta . key === indexIdentifier ) ;
322+ } ) ;
323+
324+ // columns requiring no backfill could be simply added to the table
325+ const newIndexColumnsNoBackfill = _ . intersection ( newNoBackfillIndices , columnBasedIndexes ) ;
326+
327+ const columnAdder = ( ) => {
328+ const addQueries = _ . map ( newIndexColumnsNoBackfill , index =>
329+ trans . runQuery ( 'ALTER TABLE ' + storeSchema . name + ' ADD COLUMN ' + 'nsp_i_' + index . name + ' TEXT' )
330+ ) ;
331+
332+ return SyncTasks . all ( addQueries ) ;
333+ } ;
299334
300335 const tableMaker = ( ) => {
301336 // Create the table
302337 return trans . runQuery ( tableMakerSql )
303- . then ( indexMaker ) ;
338+ . then ( ( ) => indexMaker ( storeSchema . indexes ) ) ;
304339 } ;
305340
306- const needsMigration = ( ) => {
307- // Check if sql used to create the base table has changed
308- if ( tableSqlStatements [ storeSchema . name ] !== tableMakerSql ) {
341+ const needsDataMigration = ( ) => {
342+ // If some indices have been removed - migration is needed
343+ const areIndicesRemoved = _ . some ( currentIndexMetas , meta =>
344+ ! _ . some ( storeSchema . indexes , newIndex => getIndexIdentifier ( storeSchema , newIndex ) === meta . key ) ) ;
345+ if ( areIndicesRemoved ) {
309346 return true ;
310347 }
311348
312- // Check if indicies are missing
349+ // Check all the indices in the schema
313350 return _ . some ( storeSchema . indexes , index => {
314- // Check if key paths agree
315351 const indexIdentifier = getIndexIdentifier ( storeSchema , index ) ;
316352 const indexMeta = _ . find ( indexMetadata , meta => meta . key === indexIdentifier ) ;
317- if ( ! indexMeta || ! _ . isEqual ( indexMeta . index , index ) ) {
353+
354+ // if there's a new index that doesn't require backfill, continue
355+ if ( ! indexMeta && index . doNotBackfill ) {
356+ return false ;
357+ }
358+
359+ // If we have a new index that requires backfill - we need to migrate
360+ if ( ! indexMeta ) {
318361 return true ;
319362 }
320363
364+ // If the index schemas don't match - we need to migrate
365+ if ( ! _ . isEqual ( indexMeta . index , index ) ) {
366+ return true ;
367+ }
368+
321369 // Check that indicies actually exist in the right place
322370 if ( indexUsesSeparateTable ( index , this . _supportsFTS3 ) ) {
323371 if ( ! _ . includes ( tableNames , indexIdentifier ) ) {
@@ -336,7 +384,7 @@ export abstract class SqlProviderBase extends NoSqlProvider.DbProvider {
336384 // If the table exists, check if we can view the sql statement used to create this table. Use it to determine
337385 // if a migration is needed, otherwise just make a copy and fully migrate the data over.
338386 const tableExists = _ . includes ( tableNames , storeSchema . name ) ;
339- const tableRequiresMigration = tableExists && needsMigration ( ) ;
387+ const tableRequiresMigration = tableExists && needsDataMigration ( ) ;
340388
341389 if ( tableExists && tableRequiresMigration ) {
342390 // Nuke old indexes on the original table (since they don't change names and we don't need them anymore).
@@ -364,6 +412,9 @@ export abstract class SqlProviderBase extends NoSqlProvider.DbProvider {
364412 } ;
365413
366414 tableQueries . push ( nukeIndexesAndRename . then ( tableMaker ) . then ( migrator ) ) ;
415+ } else if ( tableExists && newNoBackfillIndices . length > 0 ) {
416+ // we can add new indices without migrating
417+ tableQueries . push ( columnAdder ( ) . then ( ( ) => indexMaker ( newNoBackfillIndices ) ) ) ;
367418 } else if ( ! tableExists ) {
368419 // Table doesn't exist -- just go ahead and create it without the migration path
369420 tableQueries . push ( tableMaker ( ) ) ;
@@ -803,18 +854,25 @@ class SqlStore implements NoSqlProvider.DbStore {
803854 const queries = _ . map ( arrayOfParams , params => {
804855 let queries : SyncTasks . Promise < void > [ ] = [ ] ;
805856
857+ if ( params . length === 0 ) {
858+ return undefined ;
859+ }
860+
806861 // Generate as many '?' as there are params
807- let sqlPart = Array . apply ( null , new Array ( params . length ) ) . map ( ( ) => '?' ) . join ( ',' ) ;
862+ let placeholder = '?' ;
863+ for ( let i = 1 ; i < params . length ; i ++ ) {
864+ placeholder += ',?' ;
865+ }
808866
809867 _ . each ( this . _schema . indexes , index => {
810868 if ( indexUsesSeparateTable ( index , this . _supportsFTS3 ) ) {
811869 queries . push ( this . _trans . internal_nonQuery ( 'DELETE FROM ' + this . _schema . name + '_' + index . name +
812- ' WHERE nsp_refpk IN (' + sqlPart + ')' , params ) ) ;
870+ ' WHERE nsp_refpk IN (' + placeholder + ')' , params ) ) ;
813871 }
814872 } ) ;
815873
816874 queries . push ( this . _trans . internal_nonQuery ( 'DELETE FROM ' + this . _schema . name +
817- ' WHERE nsp_pk IN (' + sqlPart + ')' , params ) ) ;
875+ ' WHERE nsp_pk IN (' + placeholder + ')' , params ) ) ;
818876
819877 return SyncTasks . all ( queries ) . then ( _ . noop ) ;
820878 } ) ;
0 commit comments