Fossil SCM
Transform the forum status setting into a temp table to more easily filter on it.
Commit
5e5edbe5b3a8c5d93f5539f5e621faa45c088e7cde0d6f53185a411b63dee5d0
Parent
d6ff83b158ddc9b…
1 file changed
+68
-5
+68
-5
| --- src/forum.c | ||
| +++ src/forum.c | ||
| @@ -66,12 +66,12 @@ | ||
| 66 | 66 | |
| 67 | 67 | /* |
| 68 | 68 | ** A single entry from the forum-statuses setting. |
| 69 | 69 | */ |
| 70 | 70 | struct ForumStatus { |
| 71 | - char *zValue; /* status=X tag value */ | |
| 72 | 71 | char *zLabel; /* Label for the UI */ |
| 72 | + char *zValue; /* status=X tag value */ | |
| 73 | 73 | char *zDescr; /* Brief description */ |
| 74 | 74 | }; |
| 75 | 75 | |
| 76 | 76 | /* |
| 77 | 77 | ** A list of ForumStatus objects. |
| @@ -87,21 +87,67 @@ | ||
| 87 | 87 | ** This is a singleton, cached across calls. |
| 88 | 88 | */ |
| 89 | 89 | static const ForumStatusList * forum_statuses(void){ |
| 90 | 90 | static ForumStatusList fses = {0,0}; |
| 91 | 91 | static int once = 0; |
| 92 | - if( !once ){ | |
| 92 | + while( !once ){ | |
| 93 | + Stmt q; | |
| 94 | + char *zSetting; | |
| 93 | 95 | ++once; |
| 94 | - /* TODO: read `forum-statuses` setting and transform it into the | |
| 96 | + /* Read `forum-statuses` setting and transform it into the | |
| 95 | 97 | ** fses object. |
| 96 | 98 | ** |
| 97 | 99 | ** Maybe: if it's empty, synthesize a length-1 list from |
| 98 | 100 | ** {value:"default",label:"Default",...}. It's expected that |
| 99 | 101 | ** usage may be slightly simplified if we always have a non-empty |
| 100 | 102 | ** list. A length-1 list is, for purposes of the UI, identical to |
| 101 | - ** an empty one - we cannot change statuses if there's only one | |
| 102 | - ** choice. */ | |
| 103 | + ** an empty one - status selection/filtering makes no sense if | |
| 104 | + ** there's only one choice. */ | |
| 105 | + zSetting = db_get("forum-statuses", 0); | |
| 106 | + db_multi_exec( | |
| 107 | + "CREATE TEMP TABLE forumstatus(" | |
| 108 | + " ord, label, value, descr" | |
| 109 | + ");" | |
| 110 | + ); | |
| 111 | + if( !zSetting ) break; | |
| 112 | + db_prepare(&q, | |
| 113 | + " WITH setting(v) AS (SELECT %Q)," | |
| 114 | + " room(r) AS (" | |
| 115 | + " SELECT e.value FROM setting s, jsonb_each(s.v) e" | |
| 116 | + " WHERE json_valid(s.v, 0x02)" | |
| 117 | + " )" | |
| 118 | + " SELECT r->>'label', r->>'value', r->>'description'" | |
| 119 | + " FROM room", | |
| 120 | + zSetting | |
| 121 | + ); | |
| 122 | + while( SQLITE_ROW==db_step(&q) ){ | |
| 123 | + ++fses.n; | |
| 124 | + } | |
| 125 | + if( fses.n ){ | |
| 126 | + unsigned int i = 0; | |
| 127 | + Stmt qIns; | |
| 128 | + fses.aStatus = fossil_malloc(sizeof(fses.aStatus[0]) * fses.n); | |
| 129 | + db_reset(&q); | |
| 130 | + db_prepare(&qIns, | |
| 131 | + "INSERT INTO forumstatus(ord,label,value,descr)" | |
| 132 | + " VALUES(:ord,:label,:value,:descr)"); | |
| 133 | + while( SQLITE_ROW==db_step(&q) ){ | |
| 134 | + ForumStatus * fs = &fses.aStatus[i++]; | |
| 135 | + fs->zLabel = fossil_strdup(db_column_text(&q, 0)); | |
| 136 | + fs->zValue = fossil_strdup(db_column_text(&q, 1)); | |
| 137 | + fs->zDescr = fossil_strdup(db_column_text(&q, 2)); | |
| 138 | + db_reset(&qIns); | |
| 139 | + db_bind_int(&qIns, ":ord", (int)i); | |
| 140 | + db_bind_text(&qIns, ":label", fs->zLabel); | |
| 141 | + db_bind_text(&qIns, ":value", fs->zValue); | |
| 142 | + db_bind_text(&qIns, ":descr", fs->zDescr); | |
| 143 | + db_step(&qIns); | |
| 144 | + } | |
| 145 | + db_finalize(&qIns); | |
| 146 | + } | |
| 147 | + db_finalize(&q); | |
| 148 | + fossil_free(zSetting); | |
| 103 | 149 | } |
| 104 | 150 | return &fses; |
| 105 | 151 | } |
| 106 | 152 | |
| 107 | 153 | /* |
| @@ -124,10 +170,27 @@ | ||
| 124 | 170 | fs0 = fs; |
| 125 | 171 | } |
| 126 | 172 | } |
| 127 | 173 | return bFirst ? fs0 : 0; |
| 128 | 174 | } |
| 175 | + | |
| 176 | +/* | |
| 177 | +** COMMAND: test-forum-statuses | |
| 178 | +*/ | |
| 179 | +void test_forum_statuses_cmd(void){ | |
| 180 | + const ForumStatusList * fses; | |
| 181 | + unsigned i; | |
| 182 | + db_find_and_open_repository(0,0); | |
| 183 | + fses = forum_statuses(); | |
| 184 | + for(i = 0; i < fses->n; ++i ){ | |
| 185 | + const ForumStatus * fs = &fses->aStatus[i]; | |
| 186 | + fossil_print("Status: %!j %!j %!j\n", | |
| 187 | + fs->zValue, fs->zLabel, fs->zDescr); | |
| 188 | + assert( fs==forum_status_by_value(fs->zValue, 0) ); | |
| 189 | + } | |
| 190 | + fossil_print("Total statuses: %u\n", i); | |
| 191 | +} | |
| 129 | 192 | |
| 130 | 193 | /* |
| 131 | 194 | ** Return true if the forum post with the given rid has been |
| 132 | 195 | ** subsequently edited. |
| 133 | 196 | */ |
| 134 | 197 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -66,12 +66,12 @@ | |
| 66 | |
| 67 | /* |
| 68 | ** A single entry from the forum-statuses setting. |
| 69 | */ |
| 70 | struct ForumStatus { |
| 71 | char *zValue; /* status=X tag value */ |
| 72 | char *zLabel; /* Label for the UI */ |
| 73 | char *zDescr; /* Brief description */ |
| 74 | }; |
| 75 | |
| 76 | /* |
| 77 | ** A list of ForumStatus objects. |
| @@ -87,21 +87,67 @@ | |
| 87 | ** This is a singleton, cached across calls. |
| 88 | */ |
| 89 | static const ForumStatusList * forum_statuses(void){ |
| 90 | static ForumStatusList fses = {0,0}; |
| 91 | static int once = 0; |
| 92 | if( !once ){ |
| 93 | ++once; |
| 94 | /* TODO: read `forum-statuses` setting and transform it into the |
| 95 | ** fses object. |
| 96 | ** |
| 97 | ** Maybe: if it's empty, synthesize a length-1 list from |
| 98 | ** {value:"default",label:"Default",...}. It's expected that |
| 99 | ** usage may be slightly simplified if we always have a non-empty |
| 100 | ** list. A length-1 list is, for purposes of the UI, identical to |
| 101 | ** an empty one - we cannot change statuses if there's only one |
| 102 | ** choice. */ |
| 103 | } |
| 104 | return &fses; |
| 105 | } |
| 106 | |
| 107 | /* |
| @@ -124,10 +170,27 @@ | |
| 124 | fs0 = fs; |
| 125 | } |
| 126 | } |
| 127 | return bFirst ? fs0 : 0; |
| 128 | } |
| 129 | |
| 130 | /* |
| 131 | ** Return true if the forum post with the given rid has been |
| 132 | ** subsequently edited. |
| 133 | */ |
| 134 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -66,12 +66,12 @@ | |
| 66 | |
| 67 | /* |
| 68 | ** A single entry from the forum-statuses setting. |
| 69 | */ |
| 70 | struct ForumStatus { |
| 71 | char *zLabel; /* Label for the UI */ |
| 72 | char *zValue; /* status=X tag value */ |
| 73 | char *zDescr; /* Brief description */ |
| 74 | }; |
| 75 | |
| 76 | /* |
| 77 | ** A list of ForumStatus objects. |
| @@ -87,21 +87,67 @@ | |
| 87 | ** This is a singleton, cached across calls. |
| 88 | */ |
| 89 | static const ForumStatusList * forum_statuses(void){ |
| 90 | static ForumStatusList fses = {0,0}; |
| 91 | static int once = 0; |
| 92 | while( !once ){ |
| 93 | Stmt q; |
| 94 | char *zSetting; |
| 95 | ++once; |
| 96 | /* Read `forum-statuses` setting and transform it into the |
| 97 | ** fses object. |
| 98 | ** |
| 99 | ** Maybe: if it's empty, synthesize a length-1 list from |
| 100 | ** {value:"default",label:"Default",...}. It's expected that |
| 101 | ** usage may be slightly simplified if we always have a non-empty |
| 102 | ** list. A length-1 list is, for purposes of the UI, identical to |
| 103 | ** an empty one - status selection/filtering makes no sense if |
| 104 | ** there's only one choice. */ |
| 105 | zSetting = db_get("forum-statuses", 0); |
| 106 | db_multi_exec( |
| 107 | "CREATE TEMP TABLE forumstatus(" |
| 108 | " ord, label, value, descr" |
| 109 | ");" |
| 110 | ); |
| 111 | if( !zSetting ) break; |
| 112 | db_prepare(&q, |
| 113 | " WITH setting(v) AS (SELECT %Q)," |
| 114 | " room(r) AS (" |
| 115 | " SELECT e.value FROM setting s, jsonb_each(s.v) e" |
| 116 | " WHERE json_valid(s.v, 0x02)" |
| 117 | " )" |
| 118 | " SELECT r->>'label', r->>'value', r->>'description'" |
| 119 | " FROM room", |
| 120 | zSetting |
| 121 | ); |
| 122 | while( SQLITE_ROW==db_step(&q) ){ |
| 123 | ++fses.n; |
| 124 | } |
| 125 | if( fses.n ){ |
| 126 | unsigned int i = 0; |
| 127 | Stmt qIns; |
| 128 | fses.aStatus = fossil_malloc(sizeof(fses.aStatus[0]) * fses.n); |
| 129 | db_reset(&q); |
| 130 | db_prepare(&qIns, |
| 131 | "INSERT INTO forumstatus(ord,label,value,descr)" |
| 132 | " VALUES(:ord,:label,:value,:descr)"); |
| 133 | while( SQLITE_ROW==db_step(&q) ){ |
| 134 | ForumStatus * fs = &fses.aStatus[i++]; |
| 135 | fs->zLabel = fossil_strdup(db_column_text(&q, 0)); |
| 136 | fs->zValue = fossil_strdup(db_column_text(&q, 1)); |
| 137 | fs->zDescr = fossil_strdup(db_column_text(&q, 2)); |
| 138 | db_reset(&qIns); |
| 139 | db_bind_int(&qIns, ":ord", (int)i); |
| 140 | db_bind_text(&qIns, ":label", fs->zLabel); |
| 141 | db_bind_text(&qIns, ":value", fs->zValue); |
| 142 | db_bind_text(&qIns, ":descr", fs->zDescr); |
| 143 | db_step(&qIns); |
| 144 | } |
| 145 | db_finalize(&qIns); |
| 146 | } |
| 147 | db_finalize(&q); |
| 148 | fossil_free(zSetting); |
| 149 | } |
| 150 | return &fses; |
| 151 | } |
| 152 | |
| 153 | /* |
| @@ -124,10 +170,27 @@ | |
| 170 | fs0 = fs; |
| 171 | } |
| 172 | } |
| 173 | return bFirst ? fs0 : 0; |
| 174 | } |
| 175 | |
| 176 | /* |
| 177 | ** COMMAND: test-forum-statuses |
| 178 | */ |
| 179 | void test_forum_statuses_cmd(void){ |
| 180 | const ForumStatusList * fses; |
| 181 | unsigned i; |
| 182 | db_find_and_open_repository(0,0); |
| 183 | fses = forum_statuses(); |
| 184 | for(i = 0; i < fses->n; ++i ){ |
| 185 | const ForumStatus * fs = &fses->aStatus[i]; |
| 186 | fossil_print("Status: %!j %!j %!j\n", |
| 187 | fs->zValue, fs->zLabel, fs->zDescr); |
| 188 | assert( fs==forum_status_by_value(fs->zValue, 0) ); |
| 189 | } |
| 190 | fossil_print("Total statuses: %u\n", i); |
| 191 | } |
| 192 | |
| 193 | /* |
| 194 | ** Return true if the forum post with the given rid has been |
| 195 | ** subsequently edited. |
| 196 | */ |
| 197 |