Fossil SCM
Added downloadPath link to /json/dir output when --checkin is specified. Optimized no-checkin cases to use a temp view instead of temp table.
Commit
517d0ef8a5c88c86cf3fa5c8c7ae61232061aa01
Parent
a596198cedd641f…
1 file changed
+53
-24
+53
-24
| --- src/json_dir.c | ||
| +++ src/json_dir.c | ||
| @@ -48,19 +48,20 @@ | ||
| 48 | 48 | /* |
| 49 | 49 | ** Impl of /json/dir. 98% of it was taken directly |
| 50 | 50 | ** from browse.c::page_dir() |
| 51 | 51 | */ |
| 52 | 52 | static cson_value * json_page_dir_list(){ |
| 53 | - cson_object * zPayload = NULL; | |
| 54 | - cson_array * zEntries = NULL; | |
| 55 | - cson_object * zEntry = NULL; | |
| 56 | - cson_array * keyStore = NULL; | |
| 53 | + cson_object * zPayload = NULL; /* return value */ | |
| 54 | + cson_array * zEntries = NULL; /* accumulated list of entries. */ | |
| 55 | + cson_object * zEntry = NULL; /* a single dir/file entry. */ | |
| 56 | + cson_array * keyStore = NULL; /* garbage collector for shared strings. */ | |
| 57 | 57 | cson_string * zKeyName = NULL; |
| 58 | 58 | cson_string * zKeySize = NULL; |
| 59 | 59 | cson_string * zKeyIsDir = NULL; |
| 60 | 60 | cson_string * zKeyUuid = NULL; |
| 61 | 61 | cson_string * zKeyTime = NULL; |
| 62 | + cson_string * zKeyRaw = NULL; | |
| 62 | 63 | char * zD = NULL; |
| 63 | 64 | char const * zDX = NULL; |
| 64 | 65 | int nD; |
| 65 | 66 | char * zUuid = NULL; |
| 66 | 67 | char const * zCI = NULL; |
| @@ -86,10 +87,12 @@ | ||
| 86 | 87 | "Checkin name [%s] is unresolved.", |
| 87 | 88 | zCI); |
| 88 | 89 | return NULL; |
| 89 | 90 | } |
| 90 | 91 | } |
| 92 | + | |
| 93 | + /* Jump through some hoops to find the directory name... */ | |
| 91 | 94 | zDX = json_find_option_cstr("name",NULL,NULL); |
| 92 | 95 | if(!zDX && !g.isHTTP){ |
| 93 | 96 | zDX = json_command_arg(g.json.dispatchDepth+1); |
| 94 | 97 | } |
| 95 | 98 | if(zDX && (!*zDX || (0==strcmp(zDX,"/")))){ |
| @@ -107,26 +110,34 @@ | ||
| 107 | 110 | ** |
| 108 | 111 | ** Subdirectory names begin with "/". This causes them to sort |
| 109 | 112 | ** first and it also gives us an easy way to distinguish files |
| 110 | 113 | ** from directories in the loop that follows. |
| 111 | 114 | */ |
| 112 | - db_multi_exec( | |
| 113 | - "CREATE TEMP TABLE json_dir_files(n UNIQUE NOT NULL %s, u, sz, mtime DEFAULT NULL);", | |
| 114 | - filename_collation() | |
| 115 | - ); | |
| 116 | 115 | |
| 117 | 116 | if( zCI ){ |
| 118 | 117 | Stmt ins; |
| 119 | 118 | ManifestFile *pFile; |
| 120 | 119 | ManifestFile *pPrev = 0; |
| 121 | 120 | int nPrev = 0; |
| 122 | 121 | int c; |
| 123 | 122 | |
| 123 | + db_multi_exec( | |
| 124 | + "CREATE TEMP TABLE json_dir_files(" | |
| 125 | + " n UNIQUE NOT NULL %s," /* file name */ | |
| 126 | + " fn UNIQUE NOT NULL %s," /* full file name */ | |
| 127 | + " u DEFAULT NULL," /* file uuid */ | |
| 128 | + " sz DEFAULT -1," /* file size */ | |
| 129 | + " mtime DEFAULT NULL" /* file mtime in unix epoch format */ | |
| 130 | + ");", | |
| 131 | + filename_collation(), filename_collation() | |
| 132 | + ); | |
| 133 | + | |
| 124 | 134 | db_prepare(&ins, |
| 125 | - "INSERT OR IGNORE INTO json_dir_files (n,u,sz,mtime) " | |
| 135 | + "INSERT OR IGNORE INTO json_dir_files (n,fn,u,sz,mtime) " | |
| 126 | 136 | "SELECT" |
| 127 | 137 | " pathelement(:path,0)," |
| 138 | + " CASE WHEN %Q IS NULL THEN '' ELSE %Q||'/' END ||:abspath," | |
| 128 | 139 | " a.uuid," |
| 129 | 140 | " a.size," |
| 130 | 141 | " CAST(strftime('%%s',e.mtime) AS INTEGER) " |
| 131 | 142 | "FROM" |
| 132 | 143 | " mlink m, " |
| @@ -135,11 +146,12 @@ | ||
| 135 | 146 | " blob b " |
| 136 | 147 | "WHERE" |
| 137 | 148 | " e.objid=m.mid" |
| 138 | 149 | " AND a.rid=m.fid"/*FILE artifact*/ |
| 139 | 150 | " AND b.rid=m.mid"/*CHECKIN artifact*/ |
| 140 | - " AND a.uuid=:uuid" | |
| 151 | + " AND a.uuid=:uuid", | |
| 152 | + zD, zD | |
| 141 | 153 | ); |
| 142 | 154 | manifest_file_rewind(pM); |
| 143 | 155 | while( (pFile = manifest_file_next(pM,0))!=0 ){ |
| 144 | 156 | if( nD>0 |
| 145 | 157 | && ((pFile->zName[nD-1]!='/') || (0!=memcmp(pFile->zName, zD, nD-1))) |
| @@ -152,10 +164,11 @@ | ||
| 152 | 164 | && (pFile->zName[nD+nPrev]==0 || pFile->zName[nD+nPrev]=='/') |
| 153 | 165 | ){ |
| 154 | 166 | continue; |
| 155 | 167 | } |
| 156 | 168 | db_bind_text( &ins, ":path", &pFile->zName[nD] ); |
| 169 | + db_bind_text( &ins, ":abspath", &pFile->zName[nD] ); | |
| 157 | 170 | db_bind_text( &ins, ":uuid", pFile->zUuid ); |
| 158 | 171 | db_step(&ins); |
| 159 | 172 | db_reset(&ins); |
| 160 | 173 | pPrev = pFile; |
| 161 | 174 | for(nPrev=0; (c=pPrev->zName[nD+nPrev]) && c!='/'; nPrev++){} |
| @@ -163,39 +176,49 @@ | ||
| 163 | 176 | } |
| 164 | 177 | db_finalize(&ins); |
| 165 | 178 | }else if( zD && *zD ){ |
| 166 | 179 | if( filenames_are_case_sensitive() ){ |
| 167 | 180 | db_multi_exec( |
| 168 | - "INSERT OR IGNORE INTO json_dir_files" | |
| 169 | - " SELECT pathelement(name,%d), NULL, NULL, NULL FROM filename" | |
| 170 | - " WHERE name GLOB '%q/*'", | |
| 171 | - nD, zD | |
| 181 | + "CREATE TEMP VIEW json_dir_files AS" | |
| 182 | + " SELECT DISTINCT(pathelement(name,%d)) AS n," | |
| 183 | + " %Q||'/'||name AS fn," | |
| 184 | + " NULL AS u, NULL AS sz, NULL AS mtime" | |
| 185 | + " FROM filename" | |
| 186 | + " WHERE name GLOB '%q/*'" | |
| 187 | + " GROUP BY n", | |
| 188 | + nD, zD, zD | |
| 172 | 189 | ); |
| 173 | 190 | }else{ |
| 174 | 191 | db_multi_exec( |
| 175 | - "INSERT OR IGNORE INTO json_dir_files" | |
| 176 | - " SELECT pathelement(name,%d), NULL, NULL, NULL FROM filename" | |
| 177 | - " WHERE name LIKE '%q/%%'", | |
| 178 | - nD, zD | |
| 192 | + "CREATE TEMP VIEW json_dir_files AS" | |
| 193 | + " SELECT DISTINCT(pathelement(name,%d)) AS n, " | |
| 194 | + " %Q||'/'||name AS fn," | |
| 195 | + " NULL AS u, NULL AS sz, NULL AS mtime" | |
| 196 | + " FROM filename" | |
| 197 | + " WHERE name LIKE '%q/%%'" | |
| 198 | + " GROUP BY n", | |
| 199 | + nD, zD, zD | |
| 179 | 200 | ); |
| 180 | 201 | } |
| 181 | 202 | }else{ |
| 182 | 203 | db_multi_exec( |
| 183 | - "INSERT OR IGNORE INTO json_dir_files" | |
| 184 | - " SELECT pathelement(name,0), NULL, NULL, NULL FROM filename" | |
| 204 | + "CREATE TEMP VIEW json_dir_files" | |
| 205 | + " AS SELECT DISTINCT(pathelement(name,0)) AS n, NULL AS fn" | |
| 206 | + " FROM filename" | |
| 185 | 207 | ); |
| 186 | 208 | } |
| 187 | 209 | |
| 188 | 210 | if(zCI){ |
| 189 | 211 | db_prepare( &q, "SELECT" |
| 190 | 212 | " n as name," |
| 213 | + " fn as fullname," | |
| 191 | 214 | " u as uuid," |
| 192 | 215 | " sz as size," |
| 193 | 216 | " mtime as mtime " |
| 194 | 217 | "FROM json_dir_files ORDER BY n"); |
| 195 | 218 | }else{/* UUIDs are all NULL. */ |
| 196 | - db_prepare( &q, "SELECT n as name FROM json_dir_files ORDER BY n"); | |
| 219 | + db_prepare( &q, "SELECT n, fn FROM json_dir_files ORDER BY n"); | |
| 197 | 220 | } |
| 198 | 221 | |
| 199 | 222 | zKeyName = cson_new_string("name",4); |
| 200 | 223 | zKeyUuid = cson_new_string("uuid",4); |
| 201 | 224 | zKeyIsDir = cson_new_string("isDir",5); |
| @@ -207,10 +230,12 @@ | ||
| 207 | 230 | if( zCI ){ |
| 208 | 231 | zKeySize = cson_new_string("size",4); |
| 209 | 232 | cson_array_append( keyStore, cson_string_value(zKeySize) ); |
| 210 | 233 | zKeyTime = cson_new_string("timestamp",9); |
| 211 | 234 | cson_array_append( keyStore, cson_string_value(zKeyTime) ); |
| 235 | + zKeyRaw = cson_new_string("downloadPath",12); | |
| 236 | + cson_array_append( keyStore, cson_string_value(zKeyRaw) ); | |
| 212 | 237 | } |
| 213 | 238 | zPayload = cson_new_object(); |
| 214 | 239 | cson_object_set_s( zPayload, zKeyName, |
| 215 | 240 | json_new_string((zD&&*zD) ? zD : "/") ); |
| 216 | 241 | if( zUuid ){ |
| @@ -239,18 +264,22 @@ | ||
| 239 | 264 | one of the files in that directory :/. Entries with no |
| 240 | 265 | --checkin may refer to N versions, and therefore we cannot |
| 241 | 266 | associate a single size and uuid with them (and fetching all |
| 242 | 267 | would be overkill for most use cases). |
| 243 | 268 | */ |
| 244 | - char const * u = db_column_text(&q,1); | |
| 245 | - sqlite_int64 const sz = db_column_int64(&q,2); | |
| 246 | - sqlite_int64 const ts = db_column_int64(&q,3); | |
| 269 | + char const * fullName = db_column_text(&q,1); | |
| 270 | + char const * u = db_column_text(&q,2); | |
| 271 | + sqlite_int64 const sz = db_column_int64(&q,3); | |
| 272 | + sqlite_int64 const ts = db_column_int64(&q,4); | |
| 247 | 273 | cson_object_set_s(zEntry, zKeyUuid, json_new_string( u ) ); |
| 248 | 274 | cson_object_set_s(zEntry, zKeySize, |
| 249 | 275 | cson_value_new_integer( (cson_int_t)sz )); |
| 250 | 276 | cson_object_set_s(zEntry, zKeyTime, |
| 251 | 277 | cson_value_new_integer( (cson_int_t)ts )); |
| 278 | + cson_object_set_s(zEntry, zKeyRaw, | |
| 279 | + json_new_string_f("/raw/%s?name=%s", | |
| 280 | + fullName, u)); | |
| 252 | 281 | } |
| 253 | 282 | } |
| 254 | 283 | db_finalize(&q); |
| 255 | 284 | if(pM){ |
| 256 | 285 | manifest_destroy(pM); |
| 257 | 286 |
| --- src/json_dir.c | |
| +++ src/json_dir.c | |
| @@ -48,19 +48,20 @@ | |
| 48 | /* |
| 49 | ** Impl of /json/dir. 98% of it was taken directly |
| 50 | ** from browse.c::page_dir() |
| 51 | */ |
| 52 | static cson_value * json_page_dir_list(){ |
| 53 | cson_object * zPayload = NULL; |
| 54 | cson_array * zEntries = NULL; |
| 55 | cson_object * zEntry = NULL; |
| 56 | cson_array * keyStore = NULL; |
| 57 | cson_string * zKeyName = NULL; |
| 58 | cson_string * zKeySize = NULL; |
| 59 | cson_string * zKeyIsDir = NULL; |
| 60 | cson_string * zKeyUuid = NULL; |
| 61 | cson_string * zKeyTime = NULL; |
| 62 | char * zD = NULL; |
| 63 | char const * zDX = NULL; |
| 64 | int nD; |
| 65 | char * zUuid = NULL; |
| 66 | char const * zCI = NULL; |
| @@ -86,10 +87,12 @@ | |
| 86 | "Checkin name [%s] is unresolved.", |
| 87 | zCI); |
| 88 | return NULL; |
| 89 | } |
| 90 | } |
| 91 | zDX = json_find_option_cstr("name",NULL,NULL); |
| 92 | if(!zDX && !g.isHTTP){ |
| 93 | zDX = json_command_arg(g.json.dispatchDepth+1); |
| 94 | } |
| 95 | if(zDX && (!*zDX || (0==strcmp(zDX,"/")))){ |
| @@ -107,26 +110,34 @@ | |
| 107 | ** |
| 108 | ** Subdirectory names begin with "/". This causes them to sort |
| 109 | ** first and it also gives us an easy way to distinguish files |
| 110 | ** from directories in the loop that follows. |
| 111 | */ |
| 112 | db_multi_exec( |
| 113 | "CREATE TEMP TABLE json_dir_files(n UNIQUE NOT NULL %s, u, sz, mtime DEFAULT NULL);", |
| 114 | filename_collation() |
| 115 | ); |
| 116 | |
| 117 | if( zCI ){ |
| 118 | Stmt ins; |
| 119 | ManifestFile *pFile; |
| 120 | ManifestFile *pPrev = 0; |
| 121 | int nPrev = 0; |
| 122 | int c; |
| 123 | |
| 124 | db_prepare(&ins, |
| 125 | "INSERT OR IGNORE INTO json_dir_files (n,u,sz,mtime) " |
| 126 | "SELECT" |
| 127 | " pathelement(:path,0)," |
| 128 | " a.uuid," |
| 129 | " a.size," |
| 130 | " CAST(strftime('%%s',e.mtime) AS INTEGER) " |
| 131 | "FROM" |
| 132 | " mlink m, " |
| @@ -135,11 +146,12 @@ | |
| 135 | " blob b " |
| 136 | "WHERE" |
| 137 | " e.objid=m.mid" |
| 138 | " AND a.rid=m.fid"/*FILE artifact*/ |
| 139 | " AND b.rid=m.mid"/*CHECKIN artifact*/ |
| 140 | " AND a.uuid=:uuid" |
| 141 | ); |
| 142 | manifest_file_rewind(pM); |
| 143 | while( (pFile = manifest_file_next(pM,0))!=0 ){ |
| 144 | if( nD>0 |
| 145 | && ((pFile->zName[nD-1]!='/') || (0!=memcmp(pFile->zName, zD, nD-1))) |
| @@ -152,10 +164,11 @@ | |
| 152 | && (pFile->zName[nD+nPrev]==0 || pFile->zName[nD+nPrev]=='/') |
| 153 | ){ |
| 154 | continue; |
| 155 | } |
| 156 | db_bind_text( &ins, ":path", &pFile->zName[nD] ); |
| 157 | db_bind_text( &ins, ":uuid", pFile->zUuid ); |
| 158 | db_step(&ins); |
| 159 | db_reset(&ins); |
| 160 | pPrev = pFile; |
| 161 | for(nPrev=0; (c=pPrev->zName[nD+nPrev]) && c!='/'; nPrev++){} |
| @@ -163,39 +176,49 @@ | |
| 163 | } |
| 164 | db_finalize(&ins); |
| 165 | }else if( zD && *zD ){ |
| 166 | if( filenames_are_case_sensitive() ){ |
| 167 | db_multi_exec( |
| 168 | "INSERT OR IGNORE INTO json_dir_files" |
| 169 | " SELECT pathelement(name,%d), NULL, NULL, NULL FROM filename" |
| 170 | " WHERE name GLOB '%q/*'", |
| 171 | nD, zD |
| 172 | ); |
| 173 | }else{ |
| 174 | db_multi_exec( |
| 175 | "INSERT OR IGNORE INTO json_dir_files" |
| 176 | " SELECT pathelement(name,%d), NULL, NULL, NULL FROM filename" |
| 177 | " WHERE name LIKE '%q/%%'", |
| 178 | nD, zD |
| 179 | ); |
| 180 | } |
| 181 | }else{ |
| 182 | db_multi_exec( |
| 183 | "INSERT OR IGNORE INTO json_dir_files" |
| 184 | " SELECT pathelement(name,0), NULL, NULL, NULL FROM filename" |
| 185 | ); |
| 186 | } |
| 187 | |
| 188 | if(zCI){ |
| 189 | db_prepare( &q, "SELECT" |
| 190 | " n as name," |
| 191 | " u as uuid," |
| 192 | " sz as size," |
| 193 | " mtime as mtime " |
| 194 | "FROM json_dir_files ORDER BY n"); |
| 195 | }else{/* UUIDs are all NULL. */ |
| 196 | db_prepare( &q, "SELECT n as name FROM json_dir_files ORDER BY n"); |
| 197 | } |
| 198 | |
| 199 | zKeyName = cson_new_string("name",4); |
| 200 | zKeyUuid = cson_new_string("uuid",4); |
| 201 | zKeyIsDir = cson_new_string("isDir",5); |
| @@ -207,10 +230,12 @@ | |
| 207 | if( zCI ){ |
| 208 | zKeySize = cson_new_string("size",4); |
| 209 | cson_array_append( keyStore, cson_string_value(zKeySize) ); |
| 210 | zKeyTime = cson_new_string("timestamp",9); |
| 211 | cson_array_append( keyStore, cson_string_value(zKeyTime) ); |
| 212 | } |
| 213 | zPayload = cson_new_object(); |
| 214 | cson_object_set_s( zPayload, zKeyName, |
| 215 | json_new_string((zD&&*zD) ? zD : "/") ); |
| 216 | if( zUuid ){ |
| @@ -239,18 +264,22 @@ | |
| 239 | one of the files in that directory :/. Entries with no |
| 240 | --checkin may refer to N versions, and therefore we cannot |
| 241 | associate a single size and uuid with them (and fetching all |
| 242 | would be overkill for most use cases). |
| 243 | */ |
| 244 | char const * u = db_column_text(&q,1); |
| 245 | sqlite_int64 const sz = db_column_int64(&q,2); |
| 246 | sqlite_int64 const ts = db_column_int64(&q,3); |
| 247 | cson_object_set_s(zEntry, zKeyUuid, json_new_string( u ) ); |
| 248 | cson_object_set_s(zEntry, zKeySize, |
| 249 | cson_value_new_integer( (cson_int_t)sz )); |
| 250 | cson_object_set_s(zEntry, zKeyTime, |
| 251 | cson_value_new_integer( (cson_int_t)ts )); |
| 252 | } |
| 253 | } |
| 254 | db_finalize(&q); |
| 255 | if(pM){ |
| 256 | manifest_destroy(pM); |
| 257 |
| --- src/json_dir.c | |
| +++ src/json_dir.c | |
| @@ -48,19 +48,20 @@ | |
| 48 | /* |
| 49 | ** Impl of /json/dir. 98% of it was taken directly |
| 50 | ** from browse.c::page_dir() |
| 51 | */ |
| 52 | static cson_value * json_page_dir_list(){ |
| 53 | cson_object * zPayload = NULL; /* return value */ |
| 54 | cson_array * zEntries = NULL; /* accumulated list of entries. */ |
| 55 | cson_object * zEntry = NULL; /* a single dir/file entry. */ |
| 56 | cson_array * keyStore = NULL; /* garbage collector for shared strings. */ |
| 57 | cson_string * zKeyName = NULL; |
| 58 | cson_string * zKeySize = NULL; |
| 59 | cson_string * zKeyIsDir = NULL; |
| 60 | cson_string * zKeyUuid = NULL; |
| 61 | cson_string * zKeyTime = NULL; |
| 62 | cson_string * zKeyRaw = NULL; |
| 63 | char * zD = NULL; |
| 64 | char const * zDX = NULL; |
| 65 | int nD; |
| 66 | char * zUuid = NULL; |
| 67 | char const * zCI = NULL; |
| @@ -86,10 +87,12 @@ | |
| 87 | "Checkin name [%s] is unresolved.", |
| 88 | zCI); |
| 89 | return NULL; |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | /* Jump through some hoops to find the directory name... */ |
| 94 | zDX = json_find_option_cstr("name",NULL,NULL); |
| 95 | if(!zDX && !g.isHTTP){ |
| 96 | zDX = json_command_arg(g.json.dispatchDepth+1); |
| 97 | } |
| 98 | if(zDX && (!*zDX || (0==strcmp(zDX,"/")))){ |
| @@ -107,26 +110,34 @@ | |
| 110 | ** |
| 111 | ** Subdirectory names begin with "/". This causes them to sort |
| 112 | ** first and it also gives us an easy way to distinguish files |
| 113 | ** from directories in the loop that follows. |
| 114 | */ |
| 115 | |
| 116 | if( zCI ){ |
| 117 | Stmt ins; |
| 118 | ManifestFile *pFile; |
| 119 | ManifestFile *pPrev = 0; |
| 120 | int nPrev = 0; |
| 121 | int c; |
| 122 | |
| 123 | db_multi_exec( |
| 124 | "CREATE TEMP TABLE json_dir_files(" |
| 125 | " n UNIQUE NOT NULL %s," /* file name */ |
| 126 | " fn UNIQUE NOT NULL %s," /* full file name */ |
| 127 | " u DEFAULT NULL," /* file uuid */ |
| 128 | " sz DEFAULT -1," /* file size */ |
| 129 | " mtime DEFAULT NULL" /* file mtime in unix epoch format */ |
| 130 | ");", |
| 131 | filename_collation(), filename_collation() |
| 132 | ); |
| 133 | |
| 134 | db_prepare(&ins, |
| 135 | "INSERT OR IGNORE INTO json_dir_files (n,fn,u,sz,mtime) " |
| 136 | "SELECT" |
| 137 | " pathelement(:path,0)," |
| 138 | " CASE WHEN %Q IS NULL THEN '' ELSE %Q||'/' END ||:abspath," |
| 139 | " a.uuid," |
| 140 | " a.size," |
| 141 | " CAST(strftime('%%s',e.mtime) AS INTEGER) " |
| 142 | "FROM" |
| 143 | " mlink m, " |
| @@ -135,11 +146,12 @@ | |
| 146 | " blob b " |
| 147 | "WHERE" |
| 148 | " e.objid=m.mid" |
| 149 | " AND a.rid=m.fid"/*FILE artifact*/ |
| 150 | " AND b.rid=m.mid"/*CHECKIN artifact*/ |
| 151 | " AND a.uuid=:uuid", |
| 152 | zD, zD |
| 153 | ); |
| 154 | manifest_file_rewind(pM); |
| 155 | while( (pFile = manifest_file_next(pM,0))!=0 ){ |
| 156 | if( nD>0 |
| 157 | && ((pFile->zName[nD-1]!='/') || (0!=memcmp(pFile->zName, zD, nD-1))) |
| @@ -152,10 +164,11 @@ | |
| 164 | && (pFile->zName[nD+nPrev]==0 || pFile->zName[nD+nPrev]=='/') |
| 165 | ){ |
| 166 | continue; |
| 167 | } |
| 168 | db_bind_text( &ins, ":path", &pFile->zName[nD] ); |
| 169 | db_bind_text( &ins, ":abspath", &pFile->zName[nD] ); |
| 170 | db_bind_text( &ins, ":uuid", pFile->zUuid ); |
| 171 | db_step(&ins); |
| 172 | db_reset(&ins); |
| 173 | pPrev = pFile; |
| 174 | for(nPrev=0; (c=pPrev->zName[nD+nPrev]) && c!='/'; nPrev++){} |
| @@ -163,39 +176,49 @@ | |
| 176 | } |
| 177 | db_finalize(&ins); |
| 178 | }else if( zD && *zD ){ |
| 179 | if( filenames_are_case_sensitive() ){ |
| 180 | db_multi_exec( |
| 181 | "CREATE TEMP VIEW json_dir_files AS" |
| 182 | " SELECT DISTINCT(pathelement(name,%d)) AS n," |
| 183 | " %Q||'/'||name AS fn," |
| 184 | " NULL AS u, NULL AS sz, NULL AS mtime" |
| 185 | " FROM filename" |
| 186 | " WHERE name GLOB '%q/*'" |
| 187 | " GROUP BY n", |
| 188 | nD, zD, zD |
| 189 | ); |
| 190 | }else{ |
| 191 | db_multi_exec( |
| 192 | "CREATE TEMP VIEW json_dir_files AS" |
| 193 | " SELECT DISTINCT(pathelement(name,%d)) AS n, " |
| 194 | " %Q||'/'||name AS fn," |
| 195 | " NULL AS u, NULL AS sz, NULL AS mtime" |
| 196 | " FROM filename" |
| 197 | " WHERE name LIKE '%q/%%'" |
| 198 | " GROUP BY n", |
| 199 | nD, zD, zD |
| 200 | ); |
| 201 | } |
| 202 | }else{ |
| 203 | db_multi_exec( |
| 204 | "CREATE TEMP VIEW json_dir_files" |
| 205 | " AS SELECT DISTINCT(pathelement(name,0)) AS n, NULL AS fn" |
| 206 | " FROM filename" |
| 207 | ); |
| 208 | } |
| 209 | |
| 210 | if(zCI){ |
| 211 | db_prepare( &q, "SELECT" |
| 212 | " n as name," |
| 213 | " fn as fullname," |
| 214 | " u as uuid," |
| 215 | " sz as size," |
| 216 | " mtime as mtime " |
| 217 | "FROM json_dir_files ORDER BY n"); |
| 218 | }else{/* UUIDs are all NULL. */ |
| 219 | db_prepare( &q, "SELECT n, fn FROM json_dir_files ORDER BY n"); |
| 220 | } |
| 221 | |
| 222 | zKeyName = cson_new_string("name",4); |
| 223 | zKeyUuid = cson_new_string("uuid",4); |
| 224 | zKeyIsDir = cson_new_string("isDir",5); |
| @@ -207,10 +230,12 @@ | |
| 230 | if( zCI ){ |
| 231 | zKeySize = cson_new_string("size",4); |
| 232 | cson_array_append( keyStore, cson_string_value(zKeySize) ); |
| 233 | zKeyTime = cson_new_string("timestamp",9); |
| 234 | cson_array_append( keyStore, cson_string_value(zKeyTime) ); |
| 235 | zKeyRaw = cson_new_string("downloadPath",12); |
| 236 | cson_array_append( keyStore, cson_string_value(zKeyRaw) ); |
| 237 | } |
| 238 | zPayload = cson_new_object(); |
| 239 | cson_object_set_s( zPayload, zKeyName, |
| 240 | json_new_string((zD&&*zD) ? zD : "/") ); |
| 241 | if( zUuid ){ |
| @@ -239,18 +264,22 @@ | |
| 264 | one of the files in that directory :/. Entries with no |
| 265 | --checkin may refer to N versions, and therefore we cannot |
| 266 | associate a single size and uuid with them (and fetching all |
| 267 | would be overkill for most use cases). |
| 268 | */ |
| 269 | char const * fullName = db_column_text(&q,1); |
| 270 | char const * u = db_column_text(&q,2); |
| 271 | sqlite_int64 const sz = db_column_int64(&q,3); |
| 272 | sqlite_int64 const ts = db_column_int64(&q,4); |
| 273 | cson_object_set_s(zEntry, zKeyUuid, json_new_string( u ) ); |
| 274 | cson_object_set_s(zEntry, zKeySize, |
| 275 | cson_value_new_integer( (cson_int_t)sz )); |
| 276 | cson_object_set_s(zEntry, zKeyTime, |
| 277 | cson_value_new_integer( (cson_int_t)ts )); |
| 278 | cson_object_set_s(zEntry, zKeyRaw, |
| 279 | json_new_string_f("/raw/%s?name=%s", |
| 280 | fullName, u)); |
| 281 | } |
| 282 | } |
| 283 | db_finalize(&q); |
| 284 | if(pM){ |
| 285 | manifest_destroy(pM); |
| 286 |