@@ -786,11 +786,7 @@ export class DocStorage implements ISQLiteDB, OnDemandStorage {
786
786
storageId ?: string ,
787
787
) : Promise < boolean > {
788
788
return this . execTransaction ( async ( db ) => {
789
- const isNewFile = await this . _addBasicFileRecord ( db , fileIdent ) ;
790
- if ( isNewFile ) {
791
- await this . _updateFileRecord ( db , fileIdent , fileData , storageId ) ;
792
- }
793
- return isNewFile ;
789
+ return await this . _addFileRecord ( db , fileIdent , fileData , storageId ) ;
794
790
} ) ;
795
791
}
796
792
@@ -813,17 +809,20 @@ export class DocStorage implements ISQLiteDB, OnDemandStorage {
813
809
storageId ?: string ,
814
810
) : Promise < boolean > {
815
811
return this . execTransaction ( async ( db ) => {
816
- const isNewFile = await this . _addBasicFileRecord ( db , fileIdent ) ;
817
- await this . _updateFileRecord ( db , fileIdent , fileData , storageId ) ;
818
- return isNewFile ;
812
+ const wasAdded = await this . _addFileRecord ( db , fileIdent , fileData , storageId ) ;
813
+ if ( ! wasAdded ) {
814
+ await this . _updateFileRecord ( db , fileIdent , fileData , storageId ) ;
815
+ }
816
+ return wasAdded ;
819
817
} ) ;
820
818
}
821
819
822
820
/**
823
821
* Reads and returns the data for the given attachment.
824
822
* @param {string } fileIdent - The unique identifier of a file, as used by attachFileIfNew.
825
823
* @param {boolean } includeData - Load file contents from the database, in addition to metadata
826
- * @returns {Promise[FileInfo | null] } - File information, or null if no record exists for that file identifier.
824
+ * @returns {Promise[FileInfo | null] } - File information, or null if no record exists for that
825
+ * file identifier.
827
826
*/
828
827
public getFileInfo ( fileIdent : string , includeData : boolean = true ) : Promise < FileInfo | null > {
829
828
const columns = includeData ? 'ident, storageId, data' : 'ident, storageId' ;
@@ -938,9 +937,10 @@ export class DocStorage implements ISQLiteDB, OnDemandStorage {
938
937
}
939
938
940
939
/**
941
- * Unmarshals and decodes data received from db.allMarshal() method (which we added to node-sqlite3).
942
- * The data is a dictionary mapping column ids (including 'id') to arrays of values. This should
943
- * be used for Grist data, which is encoded. For non-Grist data, use `marshal.loads()`.
940
+ * Unmarshals and decodes data received from db.allMarshal() method (which we added to
941
+ * node-sqlite3). The data is a dictionary mapping column ids (including 'id') to arrays of
942
+ * values. This should be used for Grist data, which is encoded. For non-Grist data, use
943
+ * `marshal.loads()`.
944
944
*
945
945
* Note that we do NOT use this when loading data from a document, since the whole point of
946
946
* db.allMarshal() is to pass data directly to Python data engine without parsing in Node.
@@ -1446,8 +1446,9 @@ export class DocStorage implements ISQLiteDB, OnDemandStorage {
1446
1446
}
1447
1447
1448
1448
/**
1449
- * Delete attachments from _gristsys_Files that have no matching metadata row in _grist_Attachments.
1450
- * This leaves any attachment files in any remote attachment stores, which will be cleaned up separately.
1449
+ * Delete attachments from _gristsys_Files that have no matching metadata row in
1450
+ * _grist_Attachments. This leaves any attachment files in any remote attachment stores, which
1451
+ * will be cleaned up separately.
1451
1452
*/
1452
1453
public async removeUnusedAttachments ( ) {
1453
1454
const result = await this . _getDB ( ) . run ( `
@@ -1861,18 +1862,18 @@ export class DocStorage implements ISQLiteDB, OnDemandStorage {
1861
1862
return null ;
1862
1863
}
1863
1864
1864
- private async _addBasicFileRecord ( db : SQLiteDB , fileIdent : string ) : Promise < boolean > {
1865
- try {
1866
- // Try to insert a new record with the given ident. It'll fail UNIQUE constraint if exists.
1867
- await db . run ( 'INSERT INTO _gristsys_Files (ident, data, storageId) VALUES (?)' , fileIdent ) ;
1868
- } catch ( err ) {
1869
- // If UNIQUE constraint failed, this ident must already exist.
1870
- if ( / ^ ( S Q L I T E _ C O N S T R A I N T : ) ? U N I Q U E c o n s t r a i n t f a i l e d / . test ( err . message ) ) {
1871
- return false ;
1872
- } else {
1873
- throw err ;
1874
- }
1865
+ // This should be executed inside a transaction.
1866
+ private async _addFileRecord (
1867
+ db : SQLiteDB , fileIdent : string , fileData ?: Buffer , storageId ?: string
1868
+ ) : Promise < boolean > {
1869
+ const result = await db . get ( "SELECT 1 AS fileExists from _gristsys_Files WHERE ident = ?" , fileIdent ) ;
1870
+ if ( result ?. fileExists ) {
1871
+ return false ;
1875
1872
}
1873
+ await db . run (
1874
+ 'INSERT INTO main._gristsys_Files (ident, data, storageId) VALUES (?, ?, ?)' ,
1875
+ fileIdent , fileData , storageId
1876
+ ) ;
1876
1877
return true ;
1877
1878
}
1878
1879
@@ -1881,6 +1882,7 @@ export class DocStorage implements ISQLiteDB, OnDemandStorage {
1881
1882
) : Promise < void > {
1882
1883
await db . run ( 'UPDATE _gristsys_Files SET data=?, storageId=? WHERE ident=?' , fileData , storageId , fileIdent ) ;
1883
1884
}
1885
+
1884
1886
}
1885
1887
1886
1888
interface RebuildResult {
@@ -1905,7 +1907,8 @@ export interface IndexInfo extends IndexColumns {
1905
1907
}
1906
1908
1907
1909
/**
1908
- * Creates an index that allows fast SQL JOIN between _grist_Attachments.fileIdent and _gristsys_Files.ident.
1910
+ * Creates an index that allows fast SQL JOIN between _grist_Attachments.fileIdent and
1911
+ * _gristsys_Files.ident.
1909
1912
*/
1910
1913
export async function createAttachmentsIndex ( db : ISQLiteDB ) {
1911
1914
await db . exec ( `CREATE INDEX _grist_Attachments_fileIdent ON _grist_Attachments(fileIdent)` ) ;
0 commit comments