winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

SQLiteStatementBuilder.cpp (28051B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "Public/winget/SQLiteStatementBuilder.h"
      5 
      6 namespace AppInstaller::SQLite::Builder
      7 {
      8     std::ostream& operator<<(std::ostream& out, const QualifiedColumn& column)
      9     {
     10         if (!column.Table.empty())
     11         {
     12             out << '[' << column.Table << "].";
     13         }
     14         out << '[' << column.Column << ']';
     15         return out;
     16     }
     17 
     18     std::ostream& operator<<(std::ostream& out, const QualifiedTable& table)
     19     {
     20         if (!table.Schema.empty())
     21         {
     22             out << '[' << table.Schema << "].";
     23         }
     24         out << '[' << table.Table << ']';
     25         return out;
     26     }
     27 
     28     std::ostream& operator<<(std::ostream& out, const details::SubBuilder& column)
     29     {
     30         out << column.GetString();
     31         return out;
     32     }
     33 
     34     namespace
     35     {
     36         void OutputColumns(std::ostream& out, std::string_view op, std::string_view column)
     37         {
     38             out << op << '[' << column << ']';
     39         }
     40 
     41         void OutputColumns(std::ostream& out, std::string_view op, std::initializer_list<std::string_view> columns)
     42         {
     43             out << op;
     44             bool isFirst = true;
     45             for (const auto& c : columns)
     46             {
     47                 out << (isFirst ? "[" : ", [") << c << ']';
     48                 isFirst = false;
     49             }
     50         }
     51 
     52         void OutputColumns(std::ostream& out, std::string_view op, const QualifiedColumn& column)
     53         {
     54             out << op << column;
     55         }
     56 
     57         void OutputColumns(std::ostream& out, std::string_view op, std::initializer_list<QualifiedColumn> columns)
     58         {
     59             out << op;
     60             bool isFirst = true;
     61             for (const auto& c : columns)
     62             {
     63                 out << (isFirst ? "" : ", ") << c;
     64                 isFirst = false;
     65             }
     66         }
     67 
     68         void OutputColumns(std::ostream& out, std::string_view op, std::initializer_list<details::SubBuilder> columns)
     69         {
     70             out << op;
     71             bool isFirst = true;
     72             for (const auto& c : columns)
     73             {
     74                 out << (isFirst ? "" : ", ") << c;
     75                 isFirst = false;
     76             }
     77         }
     78 
     79         void OutputAggregate(std::ostream& out, Aggregate op)
     80         {
     81             out << ' ';
     82             switch (op)
     83             {
     84             case Aggregate::Min:
     85                 out << "MIN";
     86                 break;
     87             case Aggregate::Max:
     88                 out << "MAX";
     89                 break;
     90             default:
     91                 THROW_HR(E_UNEXPECTED);
     92             }
     93         }
     94 
     95         void OutputColumns(std::ostream& out, Aggregate op, std::string_view column)
     96         {
     97             OutputAggregate(out, op);
     98             out << "([" << column << "])";
     99         }
    100 
    101         void OutputColumns(std::ostream& out, Aggregate op, const QualifiedColumn& column)
    102         {
    103             OutputAggregate(out, op);
    104             out << '(' << column << ')';
    105         }
    106 
    107         // Use to output operation and table name, such as " FROM [table]"
    108         void OutputOperationAndTable(std::ostream& out, std::string_view op, std::string_view table)
    109         {
    110             out << op << " [" << table << ']';
    111         }
    112 
    113         void OutputOperationAndTable(std::ostream& out, std::string_view op, QualifiedTable table)
    114         {
    115             out << op << table;
    116         }
    117 
    118         void OutputOperationAndTable(std::ostream& out, std::string_view op, std::initializer_list<std::string_view> table)
    119         {
    120             out << op << " [";
    121             for (std::string_view t : table)
    122             {
    123                 out << t;
    124             }
    125             out << ']';
    126         }
    127 
    128         void OutputType(std::ostream& out, Type type)
    129         {
    130             out << ' ';
    131             switch (type)
    132             {
    133             case Type::Int:
    134                 out << "INT";
    135                 break;
    136             case Type::Int64:
    137                 out << "INT64";
    138                 break;
    139             case Type::Text:
    140                 out << "TEXT";
    141                 break;
    142             case Type::Blob:
    143                 out << "BLOB";
    144                 break;
    145             case Type::Integer:
    146                 out << "INTEGER";
    147                 break;
    148             case Type::None:
    149                 break;
    150             default:
    151                 THROW_HR(E_UNEXPECTED);
    152             }
    153         }
    154     }
    155 
    156     IntegerPrimaryKey::IntegerPrimaryKey()
    157     {
    158         m_stream << SQLite::RowIDName << " INTEGER PRIMARY KEY";
    159     }
    160 
    161     IntegerPrimaryKey& IntegerPrimaryKey::AutoIncrement(bool isTrue)
    162     {
    163         if (isTrue)
    164         {
    165             m_stream << " AUTOINCREMENT";
    166         }
    167         return *this;
    168     }
    169 
    170     ColumnBuilder::ColumnBuilder(std::string_view column, Type type)
    171     {
    172         OutputColumns(m_stream, "", column);
    173         OutputType(m_stream, type);
    174     }
    175 
    176     ColumnBuilder& ColumnBuilder::NotNull(bool isTrue)
    177     {
    178         if (isTrue)
    179         {
    180             m_stream << " NOT NULL";
    181         }
    182         return *this;
    183     }
    184 
    185     ColumnBuilder& ColumnBuilder::CollateNoCase(bool isTrue)
    186     {
    187         if (isTrue)
    188         {
    189             m_stream << " COLLATE NOCASE";
    190         }
    191         return *this;
    192     }
    193 
    194     ColumnBuilder& ColumnBuilder::Default(int64_t value)
    195     {
    196         m_stream << " DEFAULT " << value;
    197         return *this;
    198     }
    199 
    200     ColumnBuilder& ColumnBuilder::Unique(bool isTrue)
    201     {
    202         if (isTrue)
    203         {
    204             m_stream << " UNIQUE";
    205         }
    206         return *this;
    207     }
    208 
    209     ColumnBuilder& ColumnBuilder::PrimaryKey(bool isTrue)
    210     {
    211         if (isTrue)
    212         {
    213             m_stream << " PRIMARY KEY";
    214         }
    215         return *this;
    216     }
    217 
    218     PrimaryKeyBuilder::PrimaryKeyBuilder(std::initializer_list<std::string_view> columns)
    219     {
    220         OutputColumns(m_stream, "PRIMARY KEY(", columns);
    221         m_stream << ')';
    222         m_needsClosing = false;
    223     }
    224 
    225     PrimaryKeyBuilder::PrimaryKeyBuilder()
    226     {
    227         m_stream << "PRIMARY KEY(";
    228     }
    229 
    230     PrimaryKeyBuilder& PrimaryKeyBuilder::Column(std::string_view column)
    231     {
    232         if (m_isFirst)
    233         {
    234             m_isFirst = false;
    235         }
    236         else
    237         {
    238             m_stream << ", ";
    239         }
    240         OutputColumns(m_stream, "", column);
    241         return *this;
    242     }
    243 
    244     PrimaryKeyBuilder::operator details::SubBuilder()
    245     {
    246         if (m_needsClosing)
    247         {
    248             m_stream << ')';
    249             m_needsClosing = false;
    250         }
    251         return { m_stream.str() };
    252     }
    253 
    254     StatementBuilder& StatementBuilder::Select()
    255     {
    256         m_stream << "SELECT ";
    257         m_needsComma = false;
    258         return *this;
    259     }
    260 
    261     StatementBuilder& StatementBuilder::Select(std::string_view column)
    262     {
    263         OutputColumns(m_stream, "SELECT ", column);
    264         return *this;
    265     }
    266 
    267     StatementBuilder& StatementBuilder::Select(std::initializer_list<std::string_view> columns)
    268     {
    269         OutputColumns(m_stream, "SELECT ", columns);
    270         return *this;
    271     }
    272 
    273     StatementBuilder& StatementBuilder::Select(const QualifiedColumn& column)
    274     {
    275         OutputColumns(m_stream, "SELECT ", column);
    276         return *this;
    277     }
    278 
    279     StatementBuilder& StatementBuilder::Select(std::initializer_list<QualifiedColumn> columns)
    280     {
    281         OutputColumns(m_stream, "SELECT ", columns);
    282         return *this;
    283     }
    284 
    285     StatementBuilder& StatementBuilder::Select(details::rowcount_t)
    286     {
    287         m_stream << "SELECT COUNT(*)";
    288         return *this;
    289     }
    290 
    291     StatementBuilder& StatementBuilder::From()
    292     {
    293         m_stream << " FROM ";
    294         return *this;
    295     }
    296 
    297     StatementBuilder& StatementBuilder::From(std::string_view table)
    298     {
    299         OutputOperationAndTable(m_stream, " FROM", table);
    300         return *this;
    301     }
    302 
    303     StatementBuilder& StatementBuilder::From(QualifiedTable table)
    304     {
    305         OutputOperationAndTable(m_stream, " FROM", table);
    306         return *this;
    307     }
    308 
    309     StatementBuilder& StatementBuilder::From(std::initializer_list<std::string_view> table)
    310     {
    311         OutputOperationAndTable(m_stream, " FROM", table);
    312         return *this;
    313     }
    314 
    315     StatementBuilder& StatementBuilder::Where(std::string_view column)
    316     {
    317         OutputColumns(m_stream, " WHERE ", column);
    318         return *this;
    319     }
    320 
    321     StatementBuilder& StatementBuilder::Where(const QualifiedColumn& column)
    322     {
    323         OutputColumns(m_stream, " WHERE ", column);
    324         return *this;
    325     }
    326 
    327     StatementBuilder& StatementBuilder::WhereValueContainsEmbeddedNullCharacter(std::string_view column)
    328     {
    329         OutputColumns(m_stream, " WHERE instr(", column);
    330         m_stream << ",char(0))>0";
    331         return *this;
    332     }
    333 
    334     StatementBuilder& StatementBuilder::WhereValueContainsEmbeddedNullCharacter(const QualifiedColumn& column)
    335     {
    336         OutputColumns(m_stream, " WHERE instr(", column);
    337         m_stream << ",char(0))>0";
    338         return *this;
    339     }
    340 
    341     StatementBuilder& StatementBuilder::Equals(details::unbound_t, std::optional<size_t> index)
    342     {
    343         AppendOpAndBinder(Op::Equals, index);
    344         return *this;
    345     }
    346 
    347     StatementBuilder& StatementBuilder::Equals(std::nullptr_t)
    348     {
    349         // This is almost certainly not what you want.
    350         // In SQL, value = NULL is always false.
    351         // Use StatementBuilder::IsNull instead.
    352         THROW_HR(E_NOTIMPL);
    353     }
    354 
    355     StatementBuilder& StatementBuilder::Equals()
    356     {
    357         m_stream << " =";
    358         return *this;
    359     }
    360 
    361     StatementBuilder& StatementBuilder::Equals(const QualifiedColumn& column)
    362     {
    363         OutputColumns(m_stream, " = ", column);
    364         return *this;
    365     }
    366 
    367     StatementBuilder& StatementBuilder::IsGreaterThan(details::unbound_t, std::optional<size_t> index)
    368     {
    369         AppendOpAndBinder(Op::GreaterThan, index);
    370         return *this;
    371     }
    372 
    373     StatementBuilder& StatementBuilder::IsGreaterThanOrEqualTo(details::unbound_t, std::optional<size_t> index)
    374     {
    375         AppendOpAndBinder(Op::GreaterThanOrEqualTo, index);
    376         return *this;
    377     }
    378 
    379     StatementBuilder& StatementBuilder::LikeWithEscape(std::string_view value)
    380     {
    381         AddBindFunctor(AppendOpAndBinder(Op::Like), EscapeStringForLike(value));
    382         return Escape(EscapeCharForLike);
    383     }
    384 
    385     StatementBuilder& StatementBuilder::Like(details::unbound_t)
    386     {
    387         AppendOpAndBinder(Op::Like);
    388         return *this;
    389     }
    390 
    391     StatementBuilder& StatementBuilder::Escape(std::string_view escapeChar)
    392     {
    393         THROW_HR_IF(E_INVALIDARG, escapeChar.length() != 1);
    394         AddBindFunctor(AppendOpAndBinder(Op::Escape), escapeChar);
    395         return *this;
    396     }
    397 
    398     StatementBuilder& StatementBuilder::Not()
    399     {
    400         m_stream << " NOT";
    401         return *this;
    402     }
    403 
    404     StatementBuilder& StatementBuilder::In()
    405     {
    406         m_stream << " IN";
    407         return *this;
    408     }
    409 
    410     StatementBuilder& StatementBuilder::In(size_t count)
    411     {
    412         m_stream << " IN (";
    413         for (size_t i = 0; i < count; ++i)
    414         {
    415             m_stream << (i == 0 ? "?" : ", ?");
    416         }
    417         m_stream << ')';
    418 
    419         m_bindIndex += static_cast<int>(count);
    420         return *this;
    421     }
    422 
    423     StatementBuilder& StatementBuilder::IsNull(bool isNull)
    424     {
    425         m_stream << " IS " << (isNull ? "" : "NOT ") << "NULL";
    426         return *this;
    427     }
    428 
    429     StatementBuilder& StatementBuilder::And(std::string_view column)
    430     {
    431         OutputColumns(m_stream, " AND ", column);
    432         return *this;
    433     }
    434 
    435     StatementBuilder& StatementBuilder::And(const QualifiedColumn& column)
    436     {
    437         OutputColumns(m_stream, " AND ", column);
    438         return *this;
    439     }
    440 
    441     StatementBuilder& StatementBuilder::Or(const QualifiedColumn& column)
    442     {
    443         OutputColumns(m_stream, " OR ", column);
    444         return *this;
    445     }
    446 
    447     StatementBuilder& StatementBuilder::Join(std::string_view table)
    448     {
    449         OutputOperationAndTable(m_stream, " JOIN", table);
    450         return *this;
    451     }
    452 
    453     StatementBuilder& StatementBuilder::Join(QualifiedTable table)
    454     {
    455         OutputOperationAndTable(m_stream, " JOIN", table);
    456         return *this;
    457     }
    458 
    459     StatementBuilder& StatementBuilder::Join(std::initializer_list<std::string_view> table)
    460     {
    461         OutputOperationAndTable(m_stream, " JOIN", table);
    462         return *this;
    463     }
    464 
    465     StatementBuilder& StatementBuilder::LeftOuterJoin(std::string_view table)
    466     {
    467         OutputOperationAndTable(m_stream, " LEFT OUTER JOIN", table);
    468         return *this;
    469     }
    470 
    471     StatementBuilder& StatementBuilder::LeftOuterJoin(QualifiedTable table)
    472     {
    473         OutputOperationAndTable(m_stream, " LEFT OUTER JOIN", table);
    474         return *this;
    475     }
    476 
    477     StatementBuilder& StatementBuilder::LeftOuterJoin(std::initializer_list<std::string_view> table)
    478     {
    479         OutputOperationAndTable(m_stream, " LEFT OUTER JOIN", table);
    480         return *this;
    481     }
    482 
    483     StatementBuilder& StatementBuilder::On(const QualifiedColumn& column1, const QualifiedColumn& column2)
    484     {
    485         m_stream << " ON " << column1 << " = " << column2;
    486         return *this;
    487     }
    488 
    489     StatementBuilder& StatementBuilder::Limit(size_t rowCount)
    490     {
    491         m_stream << " LIMIT " << rowCount;
    492         return *this;
    493     }
    494 
    495     StatementBuilder& StatementBuilder::GroupBy(std::string_view column)
    496     {
    497         OutputColumns(m_stream, " GROUP BY ", column);
    498         return *this;
    499     }
    500 
    501     StatementBuilder& StatementBuilder::GroupBy(const QualifiedColumn& column)
    502     {
    503         OutputColumns(m_stream, " GROUP BY ", column);
    504         return *this;
    505     }
    506 
    507     StatementBuilder& StatementBuilder::OrderBy(std::string_view column)
    508     {
    509         OutputColumns(m_stream, " ORDER BY ", column);
    510         return *this;
    511     }
    512 
    513     StatementBuilder& StatementBuilder::OrderBy(const QualifiedColumn& column)
    514     {
    515         OutputColumns(m_stream, " ORDER BY ", column);
    516         return *this;
    517     }
    518 
    519     StatementBuilder& StatementBuilder::OrderBy(std::initializer_list<std::string_view> columns)
    520     {
    521         OutputColumns(m_stream, " ORDER BY ", columns);
    522         return *this;
    523     }
    524 
    525     StatementBuilder& StatementBuilder::Ascending()
    526     {
    527         m_stream << " ASC";
    528         return *this;
    529     }
    530 
    531     StatementBuilder& StatementBuilder::Descending()
    532     {
    533         m_stream << " DESC";
    534         return *this;
    535     }
    536 
    537     StatementBuilder& StatementBuilder::InsertInto(std::string_view table)
    538     {
    539         OutputOperationAndTable(m_stream, "INSERT INTO", table);
    540         return *this;
    541     }
    542 
    543     StatementBuilder& StatementBuilder::InsertInto(QualifiedTable table)
    544     {
    545         OutputOperationAndTable(m_stream, "INSERT INTO", table);
    546         return *this;
    547     }
    548 
    549     StatementBuilder& StatementBuilder::InsertInto(std::initializer_list<std::string_view> table)
    550     {
    551         OutputOperationAndTable(m_stream, "INSERT INTO", table);
    552         return *this;
    553     }
    554 
    555     StatementBuilder& StatementBuilder::InsertOrIgnore(std::string_view table)
    556     {
    557         OutputOperationAndTable(m_stream, "INSERT OR IGNORE INTO", table);
    558         return *this;
    559     }
    560 
    561     StatementBuilder& StatementBuilder::InsertOrIgnore(QualifiedTable table)
    562     {
    563         OutputOperationAndTable(m_stream, "INSERT OR IGNORE INTO", table);
    564         return *this;
    565     }
    566 
    567     StatementBuilder& StatementBuilder::InsertOrIgnore(std::initializer_list<std::string_view> table)
    568     {
    569         OutputOperationAndTable(m_stream, "INSERT OR IGNORE INTO", table);
    570         return *this;
    571     }
    572 
    573     StatementBuilder& StatementBuilder::Columns(std::string_view column)
    574     {
    575         OutputColumns(m_stream, "(", column);
    576         m_stream << ')';
    577         return *this;
    578     }
    579 
    580     StatementBuilder& StatementBuilder::Columns(std::initializer_list<std::string_view> columns)
    581     {
    582         OutputColumns(m_stream, "(", columns);
    583         m_stream << ')';
    584         return *this;
    585     }
    586 
    587     StatementBuilder& StatementBuilder::Columns(const QualifiedColumn& column)
    588     {
    589         OutputColumns(m_stream, "(", column);
    590         m_stream << ')';
    591         return *this;
    592     }
    593 
    594     StatementBuilder& StatementBuilder::Columns(std::initializer_list<QualifiedColumn> columns)
    595     {
    596         OutputColumns(m_stream, "(", columns);
    597         m_stream << ')';
    598         return *this;
    599     }
    600 
    601     StatementBuilder& StatementBuilder::Columns(std::initializer_list<details::SubBuilder> columns)
    602     {
    603         OutputColumns(m_stream, "(", columns);
    604         m_stream << ')';
    605         return *this;
    606     }
    607 
    608     StatementBuilder& StatementBuilder::BeginColumns()
    609     {
    610         m_stream << '(';
    611         m_needsComma = false;
    612         return *this;
    613     }
    614 
    615     StatementBuilder& StatementBuilder::Column(std::string_view column)
    616     {
    617         if (m_needsComma)
    618         {
    619             m_stream << ", ";
    620         }
    621         OutputColumns(m_stream, "", column);
    622         m_needsComma = true;
    623         return *this;
    624     }
    625 
    626     StatementBuilder& StatementBuilder::Column(const QualifiedColumn& column)
    627     {
    628         if (m_needsComma)
    629         {
    630             m_stream << ", ";
    631         }
    632         OutputColumns(m_stream, "", column);
    633         m_needsComma = true;
    634         return *this;
    635     }
    636 
    637     StatementBuilder& StatementBuilder::Column(Aggregate aggOp, std::string_view column)
    638     {
    639         if (m_needsComma)
    640         {
    641             m_stream << ", ";
    642         }
    643         OutputColumns(m_stream, aggOp, column);
    644         m_needsComma = true;
    645         return *this;
    646     }
    647 
    648     StatementBuilder& StatementBuilder::Column(Aggregate aggOp, const QualifiedColumn& column)
    649     {
    650         if (m_needsComma)
    651         {
    652             m_stream << ", ";
    653         }
    654         OutputColumns(m_stream, aggOp, column);
    655         m_needsComma = true;
    656         return *this;
    657     }
    658 
    659     StatementBuilder& StatementBuilder::Column(const details::SubBuilder& column)
    660     {
    661         if (m_needsComma)
    662         {
    663             m_stream << ", ";
    664         }
    665         m_stream << column;
    666         m_needsComma = true;
    667         return *this;
    668     }
    669 
    670     StatementBuilder& StatementBuilder::EndColumns()
    671     {
    672         m_stream << ')';
    673         m_needsComma = false;
    674         return *this;
    675     }
    676 
    677     StatementBuilder& StatementBuilder::NotNull(bool isTrue)
    678     {
    679         if (isTrue)
    680         {
    681             m_stream << " NOT NULL";
    682         }
    683         return *this;
    684     }
    685 
    686     StatementBuilder& StatementBuilder::BeginValues()
    687     {
    688         m_stream << " VALUES (";
    689         m_needsComma = false;
    690         return *this;
    691     }
    692 
    693     StatementBuilder& StatementBuilder::EndValues()
    694     {
    695         m_stream << ')';
    696         m_needsComma = false;
    697         return *this;
    698     }
    699 
    700     StatementBuilder& StatementBuilder::CreateTable(std::string_view table)
    701     {
    702         OutputOperationAndTable(m_stream, "CREATE TABLE", table);
    703         return *this;
    704     }
    705 
    706     StatementBuilder& StatementBuilder::CreateTable(QualifiedTable table)
    707     {
    708         OutputOperationAndTable(m_stream, "CREATE TABLE", table);
    709         return *this;
    710     }
    711 
    712     StatementBuilder& StatementBuilder::CreateTable(std::initializer_list<std::string_view> table)
    713     {
    714         OutputOperationAndTable(m_stream, "CREATE TABLE", table);
    715         return *this;
    716     }
    717 
    718     StatementBuilder& StatementBuilder::AlterTable(std::string_view table)
    719     {
    720         OutputOperationAndTable(m_stream, "ALTER TABLE", table);
    721         return *this;
    722     }
    723 
    724     StatementBuilder& StatementBuilder::AlterTable(QualifiedTable table)
    725     {
    726         OutputOperationAndTable(m_stream, "ALTER TABLE", table);
    727         return *this;
    728     }
    729 
    730     StatementBuilder& StatementBuilder::AlterTable(std::initializer_list<std::string_view> table)
    731     {
    732         OutputOperationAndTable(m_stream, "ALTER TABLE", table);
    733         return *this;
    734     }
    735 
    736     StatementBuilder& StatementBuilder::Add(std::string_view column, Type type)
    737     {
    738         m_stream << " ADD " << column;
    739         OutputType(m_stream, type);
    740         return *this;
    741     }
    742 
    743     StatementBuilder& StatementBuilder::DropTable(std::string_view table)
    744     {
    745         OutputOperationAndTable(m_stream, "DROP TABLE", table);
    746         return *this;
    747     }
    748 
    749     StatementBuilder& StatementBuilder::DropTable(QualifiedTable table)
    750     {
    751         OutputOperationAndTable(m_stream, "DROP TABLE", table);
    752         return *this;
    753     }
    754 
    755     StatementBuilder& StatementBuilder::DropTable(std::initializer_list<std::string_view> table)
    756     {
    757         OutputOperationAndTable(m_stream, "DROP TABLE", table);
    758         return *this;
    759     }
    760 
    761     StatementBuilder& StatementBuilder::DropTableIfExists(std::string_view table)
    762     {
    763         OutputOperationAndTable(m_stream, "DROP TABLE IF EXISTS", table);
    764         return *this;
    765     }
    766 
    767     StatementBuilder& StatementBuilder::DropTableIfExists(QualifiedTable table)
    768     {
    769         OutputOperationAndTable(m_stream, "DROP TABLE IF EXISTS", table);
    770         return *this;
    771     }
    772 
    773     StatementBuilder& StatementBuilder::DropTableIfExists(std::initializer_list<std::string_view> table)
    774     {
    775         OutputOperationAndTable(m_stream, "DROP TABLE IF EXISTS", table);
    776         return *this;
    777     }
    778 
    779     StatementBuilder& StatementBuilder::CreateIndex(std::string_view table)
    780     {
    781         OutputOperationAndTable(m_stream, "CREATE INDEX", table);
    782         return *this;
    783     }
    784 
    785     StatementBuilder& StatementBuilder::CreateIndex(QualifiedTable table)
    786     {
    787         OutputOperationAndTable(m_stream, "CREATE INDEX", table);
    788         return *this;
    789     }
    790 
    791     StatementBuilder& StatementBuilder::CreateIndex(std::initializer_list<std::string_view> table)
    792     {
    793         OutputOperationAndTable(m_stream, "CREATE INDEX", table);
    794         return *this;
    795     }
    796 
    797     StatementBuilder& StatementBuilder::CreateUniqueIndex(std::string_view table)
    798     {
    799         OutputOperationAndTable(m_stream, "CREATE UNIQUE INDEX", table);
    800         return *this;
    801     }
    802 
    803     StatementBuilder& StatementBuilder::CreateUniqueIndex(QualifiedTable table)
    804     {
    805         OutputOperationAndTable(m_stream, "CREATE UNIQUE INDEX", table);
    806         return *this;
    807     }
    808 
    809     StatementBuilder& StatementBuilder::CreateUniqueIndex(std::initializer_list<std::string_view> table)
    810     {
    811         OutputOperationAndTable(m_stream, "CREATE UNIQUE INDEX", table);
    812         return *this;
    813     }
    814 
    815     StatementBuilder& StatementBuilder::DropIndex(std::string_view index)
    816     {
    817         OutputOperationAndTable(m_stream, "DROP INDEX", index);
    818         return *this;
    819     }
    820 
    821     StatementBuilder& StatementBuilder::DropIndex(QualifiedTable index)
    822     {
    823         OutputOperationAndTable(m_stream, "DROP INDEX", index);
    824         return *this;
    825     }
    826 
    827     StatementBuilder& StatementBuilder::DropIndex(std::initializer_list<std::string_view> index)
    828     {
    829         OutputOperationAndTable(m_stream, "DROP INDEX", index);
    830         return *this;
    831     }
    832 
    833     StatementBuilder& StatementBuilder::On(std::string_view table)
    834     {
    835         OutputOperationAndTable(m_stream, " ON", table);
    836         return *this;
    837     }
    838 
    839     StatementBuilder& StatementBuilder::On(std::initializer_list<std::string_view> table)
    840     {
    841         OutputOperationAndTable(m_stream, " ON", table);
    842         return *this;
    843     }
    844 
    845     StatementBuilder& StatementBuilder::DeleteFrom(std::string_view table)
    846     {
    847         OutputOperationAndTable(m_stream, "DELETE FROM", table);
    848         return *this;
    849     }
    850 
    851     StatementBuilder& StatementBuilder::DeleteFrom(QualifiedTable table)
    852     {
    853         OutputOperationAndTable(m_stream, "DELETE FROM", table);
    854         return *this;
    855     }
    856 
    857     StatementBuilder& StatementBuilder::DeleteFrom(std::initializer_list<std::string_view> table)
    858     {
    859         OutputOperationAndTable(m_stream, "DELETE FROM", table);
    860         return *this;
    861     }
    862 
    863     StatementBuilder& StatementBuilder::Update(std::string_view table)
    864     {
    865         OutputOperationAndTable(m_stream, "UPDATE", table);
    866         return *this;
    867     }
    868 
    869     StatementBuilder& StatementBuilder::Update(QualifiedTable table)
    870     {
    871         OutputOperationAndTable(m_stream, "UPDATE", table);
    872         return *this;
    873     }
    874 
    875     StatementBuilder& StatementBuilder::Update(std::initializer_list<std::string_view> table)
    876     {
    877         OutputOperationAndTable(m_stream, "UPDATE", table);
    878         return *this;
    879     }
    880 
    881     StatementBuilder& StatementBuilder::UpdateOrReplace(std::string_view table)
    882     {
    883         OutputOperationAndTable(m_stream, "UPDATE OR REPLACE", table);
    884         return *this;
    885     }
    886 
    887     StatementBuilder& StatementBuilder::UpdateOrReplace(QualifiedTable table)
    888     {
    889         OutputOperationAndTable(m_stream, "UPDATE OR REPLACE", table);
    890         return *this;
    891     }
    892 
    893     StatementBuilder& StatementBuilder::UpdateOrReplace(std::initializer_list<std::string_view> table)
    894     {
    895         OutputOperationAndTable(m_stream, "UPDATE OR REPLACE", table);
    896         return *this;
    897     }
    898 
    899     StatementBuilder& StatementBuilder::Set()
    900     {
    901         m_stream << " SET ";
    902         m_needsComma = false;
    903         return *this;
    904     }
    905 
    906     StatementBuilder& StatementBuilder::Vacuum()
    907     {
    908         m_stream << "VACUUM";
    909         return *this;
    910     }
    911 
    912     StatementBuilder& StatementBuilder::BeginParenthetical()
    913     {
    914         m_stream << '(';
    915         return *this;
    916     }
    917 
    918     StatementBuilder& StatementBuilder::EndParenthetical()
    919     {
    920         m_stream << ')';
    921         return *this;
    922     }
    923 
    924     StatementBuilder& StatementBuilder::WithoutRowID()
    925     {
    926         m_stream << " WITHOUT ROWID";
    927         return *this;
    928     }
    929 
    930 
    931     StatementBuilder& StatementBuilder::As(std::string_view alias)
    932     {
    933         OutputOperationAndTable(m_stream, " AS", alias);
    934         return *this;
    935     }
    936 
    937     Statement StatementBuilder::Prepare(const Connection& connection)
    938     {
    939         Statement result = Statement::Create(connection, m_stream.str());
    940         for (const auto& f : m_binders)
    941         {
    942             f(result);
    943         }
    944         return result;
    945     }
    946 
    947     void StatementBuilder::Execute(const Connection& connection)
    948     {
    949         Prepare(connection).Execute();
    950     }
    951 
    952     int StatementBuilder::AppendOpAndBinder(Op op, std::optional<size_t> index)
    953     {
    954         switch (op)
    955         {
    956         case Op::Equals:
    957             m_stream << " = ?";
    958             break;
    959         case Op::Like:
    960             m_stream << " LIKE ?";
    961             break;
    962         case Op::Escape:
    963             m_stream << " ESCAPE ?";
    964             break;
    965         case Op::Literal:
    966             m_stream << " ?";
    967             break;
    968         case Op::GreaterThan:
    969             m_stream << " > ?";
    970             break;
    971         case Op::GreaterThanOrEqualTo:
    972             m_stream << " >= ?";
    973             break;
    974         default:
    975             THROW_HR(E_UNEXPECTED);
    976         }
    977 
    978         if (index)
    979         {
    980             m_stream << index.value();
    981         }
    982 
    983         return m_bindIndex++;
    984     }
    985 
    986     int StatementBuilder::AppendValuesAndBinders(size_t count)
    987     {
    988         m_stream << " VALUES (";
    989         for (size_t i = 0; i < count; ++i)
    990         {
    991             m_stream << (i == 0 ? "?" : ", ?");
    992         }
    993         m_stream << ')';
    994 
    995         int result = m_bindIndex;
    996         m_bindIndex += static_cast<int>(count);
    997         return result;
    998     }
    999 
   1000     int StatementBuilder::AppendValueAndBinder()
   1001     {
   1002         if (m_needsComma)
   1003         {
   1004             m_stream << ", ";
   1005         }
   1006         m_stream << '?';
   1007         m_needsComma = true;
   1008         return m_bindIndex++;
   1009     }
   1010 }