diff options
Diffstat (limited to 'lib/statement.cpp')
| -rw-r--r-- | lib/statement.cpp | 621 |
1 files changed, 268 insertions, 353 deletions
| diff --git a/lib/statement.cpp b/lib/statement.cpp index ac83084..669dc2a 100644 --- a/lib/statement.cpp +++ b/lib/statement.cpp | |||
| @@ -133,19 +133,19 @@ namespace verbly { | |||
| 133 | return queryStream.str(); | 133 | return queryStream.str(); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | std::list<binding> statement::getBindings() const | 136 | std::list<hatkirby::binding> statement::getBindings() const |
| 137 | { | 137 | { |
| 138 | std::list<binding> result; | 138 | std::list<hatkirby::binding> result; |
| 139 | 139 | ||
| 140 | for (const with& w : withs_) | 140 | for (const with& w : withs_) |
| 141 | { | 141 | { |
| 142 | for (binding value : w.getCondition().flattenBindings()) | 142 | for (hatkirby::binding value : w.getCondition().flattenBindings()) |
| 143 | { | 143 | { |
| 144 | result.push_back(std::move(value)); | 144 | result.push_back(std::move(value)); |
| 145 | } | 145 | } |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | for (binding value : topCondition_.flattenBindings()) | 148 | for (hatkirby::binding value : topCondition_.flattenBindings()) |
| 149 | { | 149 | { |
| 150 | result.push_back(std::move(value)); | 150 | result.push_back(std::move(value)); |
| 151 | } | 151 | } |
| @@ -203,77 +203,152 @@ namespace verbly { | |||
| 203 | { | 203 | { |
| 204 | case filter::comparison::is_null: | 204 | case filter::comparison::is_null: |
| 205 | { | 205 | { |
| 206 | return condition(topTable_, clause.getField().getColumn(), true); | 206 | return { |
| 207 | topTable_, | ||
| 208 | clause.getField().getColumn(), | ||
| 209 | true | ||
| 210 | }; | ||
| 207 | } | 211 | } |
| 208 | 212 | ||
| 209 | case filter::comparison::is_not_null: | 213 | case filter::comparison::is_not_null: |
| 210 | { | 214 | { |
| 211 | return condition(topTable_, clause.getField().getColumn(), false); | 215 | return { |
| 216 | topTable_, | ||
| 217 | clause.getField().getColumn(), | ||
| 218 | false | ||
| 219 | }; | ||
| 212 | } | 220 | } |
| 213 | 221 | ||
| 214 | case filter::comparison::int_equals: | 222 | case filter::comparison::int_equals: |
| 215 | { | 223 | { |
| 216 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getIntegerArgument()); | 224 | return { |
| 225 | topTable_, | ||
| 226 | clause.getField().getColumn(), | ||
| 227 | condition::comparison::equals, | ||
| 228 | clause.getIntegerArgument() | ||
| 229 | }; | ||
| 217 | } | 230 | } |
| 218 | 231 | ||
| 219 | case filter::comparison::int_does_not_equal: | 232 | case filter::comparison::int_does_not_equal: |
| 220 | { | 233 | { |
| 221 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, clause.getIntegerArgument()); | 234 | return { |
| 235 | topTable_, | ||
| 236 | clause.getField().getColumn(), | ||
| 237 | condition::comparison::does_not_equal, | ||
| 238 | clause.getIntegerArgument() | ||
| 239 | }; | ||
| 222 | } | 240 | } |
| 223 | 241 | ||
| 224 | case filter::comparison::int_is_at_least: | 242 | case filter::comparison::int_is_at_least: |
| 225 | { | 243 | { |
| 226 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_at_least, clause.getIntegerArgument()); | 244 | return { |
| 245 | topTable_, | ||
| 246 | clause.getField().getColumn(), | ||
| 247 | condition::comparison::is_at_least, | ||
| 248 | clause.getIntegerArgument() | ||
| 249 | }; | ||
| 227 | } | 250 | } |
| 228 | 251 | ||
| 229 | case filter::comparison::int_is_greater_than: | 252 | case filter::comparison::int_is_greater_than: |
| 230 | { | 253 | { |
| 231 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_greater_than, clause.getIntegerArgument()); | 254 | return { |
| 255 | topTable_, | ||
| 256 | clause.getField().getColumn(), | ||
| 257 | condition::comparison::is_greater_than, | ||
| 258 | clause.getIntegerArgument() | ||
| 259 | }; | ||
| 232 | } | 260 | } |
| 233 | 261 | ||
| 234 | case filter::comparison::int_is_at_most: | 262 | case filter::comparison::int_is_at_most: |
| 235 | { | 263 | { |
| 236 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_at_most, clause.getIntegerArgument()); | 264 | return { |
| 265 | topTable_, | ||
| 266 | clause.getField().getColumn(), | ||
| 267 | condition::comparison::is_at_most, | ||
| 268 | clause.getIntegerArgument() | ||
| 269 | }; | ||
| 237 | } | 270 | } |
| 238 | 271 | ||
| 239 | case filter::comparison::int_is_less_than: | 272 | case filter::comparison::int_is_less_than: |
| 240 | { | 273 | { |
| 241 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_less_than, clause.getIntegerArgument()); | 274 | return { |
| 275 | topTable_, | ||
| 276 | clause.getField().getColumn(), | ||
| 277 | condition::comparison::is_less_than, | ||
| 278 | clause.getIntegerArgument() | ||
| 279 | }; | ||
| 242 | } | 280 | } |
| 243 | 281 | ||
| 244 | case filter::comparison::boolean_equals: | 282 | case filter::comparison::boolean_equals: |
| 245 | { | 283 | { |
| 246 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getBooleanArgument() ? 1 : 0); | 284 | return { |
| 285 | topTable_, | ||
| 286 | clause.getField().getColumn(), | ||
| 287 | condition::comparison::equals, | ||
| 288 | clause.getBooleanArgument() ? 1 : 0 | ||
| 289 | }; | ||
| 247 | } | 290 | } |
| 248 | 291 | ||
| 249 | case filter::comparison::string_equals: | 292 | case filter::comparison::string_equals: |
| 250 | { | 293 | { |
| 251 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getStringArgument()); | 294 | return { |
| 295 | topTable_, | ||
| 296 | clause.getField().getColumn(), | ||
| 297 | condition::comparison::equals, | ||
| 298 | clause.getStringArgument() | ||
| 299 | }; | ||
| 252 | } | 300 | } |
| 253 | 301 | ||
| 254 | case filter::comparison::string_does_not_equal: | 302 | case filter::comparison::string_does_not_equal: |
| 255 | { | 303 | { |
| 256 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, clause.getStringArgument()); | 304 | return { |
| 305 | topTable_, | ||
| 306 | clause.getField().getColumn(), | ||
| 307 | condition::comparison::does_not_equal, | ||
| 308 | clause.getStringArgument() | ||
| 309 | }; | ||
| 257 | } | 310 | } |
| 258 | 311 | ||
| 259 | case filter::comparison::string_is_like: | 312 | case filter::comparison::string_is_like: |
| 260 | { | 313 | { |
| 261 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_like, clause.getStringArgument()); | 314 | return { |
| 315 | topTable_, | ||
| 316 | clause.getField().getColumn(), | ||
| 317 | condition::comparison::is_like, | ||
| 318 | clause.getStringArgument() | ||
| 319 | }; | ||
| 262 | } | 320 | } |
| 263 | 321 | ||
| 264 | case filter::comparison::string_is_not_like: | 322 | case filter::comparison::string_is_not_like: |
| 265 | { | 323 | { |
| 266 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_not_like, clause.getStringArgument()); | 324 | return { |
| 325 | topTable_, | ||
| 326 | clause.getField().getColumn(), | ||
| 327 | condition::comparison::is_not_like, | ||
| 328 | clause.getStringArgument() | ||
| 329 | }; | ||
| 267 | } | 330 | } |
| 268 | 331 | ||
| 269 | case filter::comparison::field_equals: | 332 | case filter::comparison::field_equals: |
| 270 | { | 333 | { |
| 271 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, {"", clause.getCompareField().getColumn()}, clause.getCompareField().getObject()); | 334 | return { |
| 335 | topTable_, | ||
| 336 | clause.getField().getColumn(), | ||
| 337 | condition::comparison::equals, | ||
| 338 | field_binding {"", clause.getCompareField().getColumn()}, | ||
| 339 | clause.getCompareField().getObject() | ||
| 340 | }; | ||
| 272 | } | 341 | } |
| 273 | 342 | ||
| 274 | case filter::comparison::field_does_not_equal: | 343 | case filter::comparison::field_does_not_equal: |
| 275 | { | 344 | { |
| 276 | return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, {"", clause.getCompareField().getColumn()}, clause.getCompareField().getObject()); | 345 | return { |
| 346 | topTable_, | ||
| 347 | clause.getField().getColumn(), | ||
| 348 | condition::comparison::does_not_equal, | ||
| 349 | field_binding {"", clause.getCompareField().getColumn()}, | ||
| 350 | clause.getCompareField().getObject() | ||
| 351 | }; | ||
| 277 | } | 352 | } |
| 278 | 353 | ||
| 279 | case filter::comparison::matches: | 354 | case filter::comparison::matches: |
| @@ -680,206 +755,19 @@ namespace verbly { | |||
| 680 | << j.getJoinColumn(); | 755 | << j.getJoinColumn(); |
| 681 | } | 756 | } |
| 682 | 757 | ||
| 683 | statement::condition::condition(const condition& other) | ||
| 684 | { | ||
| 685 | type_ = other.type_; | ||
| 686 | |||
| 687 | switch (type_) | ||
| 688 | { | ||
| 689 | case type::empty: | ||
| 690 | { | ||
| 691 | break; | ||
| 692 | } | ||
| 693 | |||
| 694 | case type::singleton: | ||
| 695 | { | ||
| 696 | new(&singleton_.table_) std::string(other.singleton_.table_); | ||
| 697 | new(&singleton_.column_) std::string(other.singleton_.column_); | ||
| 698 | singleton_.comparison_ = other.singleton_.comparison_; | ||
| 699 | new(&singleton_.value_) binding(other.singleton_.value_); | ||
| 700 | singleton_.parentObject_ = other.singleton_.parentObject_; | ||
| 701 | |||
| 702 | break; | ||
| 703 | } | ||
| 704 | |||
| 705 | case type::group: | ||
| 706 | { | ||
| 707 | new(&group_.children_) std::list<condition>(other.group_.children_); | ||
| 708 | group_.orlogic_ = other.group_.orlogic_; | ||
| 709 | |||
| 710 | break; | ||
| 711 | } | ||
| 712 | } | ||
| 713 | } | ||
| 714 | |||
| 715 | statement::condition::condition(condition&& other) : condition() | ||
| 716 | { | ||
| 717 | swap(*this, other); | ||
| 718 | } | ||
| 719 | |||
| 720 | statement::condition& statement::condition::operator=(condition other) | ||
| 721 | { | ||
| 722 | swap(*this, other); | ||
| 723 | |||
| 724 | return *this; | ||
| 725 | } | ||
| 726 | |||
| 727 | void swap(statement::condition& first, statement::condition& second) | ||
| 728 | { | ||
| 729 | using type = statement::condition::type; | ||
| 730 | using condition = statement::condition; | ||
| 731 | |||
| 732 | type tempType = first.type_; | ||
| 733 | std::string tempTable; | ||
| 734 | std::string tempColumn; | ||
| 735 | condition::comparison tempComparison; | ||
| 736 | binding tempBinding; | ||
| 737 | object tempParentObject; | ||
| 738 | std::list<condition> tempChildren; | ||
| 739 | bool tempOrlogic; | ||
| 740 | |||
| 741 | switch (tempType) | ||
| 742 | { | ||
| 743 | case type::empty: | ||
| 744 | { | ||
| 745 | break; | ||
| 746 | } | ||
| 747 | |||
| 748 | case type::singleton: | ||
| 749 | { | ||
| 750 | tempTable = std::move(first.singleton_.table_); | ||
| 751 | tempColumn = std::move(first.singleton_.column_); | ||
| 752 | tempComparison = first.singleton_.comparison_; | ||
| 753 | tempBinding = std::move(first.singleton_.value_); | ||
| 754 | tempParentObject = first.singleton_.parentObject_; | ||
| 755 | |||
| 756 | break; | ||
| 757 | } | ||
| 758 | |||
| 759 | case type::group: | ||
| 760 | { | ||
| 761 | tempChildren = std::move(first.group_.children_); | ||
| 762 | tempOrlogic = first.group_.orlogic_; | ||
| 763 | |||
| 764 | break; | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | first.~condition(); | ||
| 769 | |||
| 770 | first.type_ = second.type_; | ||
| 771 | |||
| 772 | switch (first.type_) | ||
| 773 | { | ||
| 774 | case type::empty: | ||
| 775 | { | ||
| 776 | break; | ||
| 777 | } | ||
| 778 | |||
| 779 | case type::singleton: | ||
| 780 | { | ||
| 781 | new(&first.singleton_.table_) std::string(std::move(second.singleton_.table_)); | ||
| 782 | new(&first.singleton_.column_) std::string(std::move(second.singleton_.column_)); | ||
| 783 | first.singleton_.comparison_ = second.singleton_.comparison_; | ||
| 784 | new(&first.singleton_.value_) binding(std::move(second.singleton_.value_)); | ||
| 785 | first.singleton_.parentObject_ = second.singleton_.parentObject_; | ||
| 786 | |||
| 787 | break; | ||
| 788 | } | ||
| 789 | |||
| 790 | case type::group: | ||
| 791 | { | ||
| 792 | new(&first.group_.children_) std::list<condition>(std::move(second.group_.children_)); | ||
| 793 | first.group_.orlogic_ = second.group_.orlogic_; | ||
| 794 | |||
| 795 | break; | ||
| 796 | } | ||
| 797 | } | ||
| 798 | |||
| 799 | second.~condition(); | ||
| 800 | |||
| 801 | second.type_ = tempType; | ||
| 802 | |||
| 803 | switch (second.type_) | ||
| 804 | { | ||
| 805 | case type::empty: | ||
| 806 | { | ||
| 807 | break; | ||
| 808 | } | ||
| 809 | |||
| 810 | case type::singleton: | ||
| 811 | { | ||
| 812 | new(&second.singleton_.table_) std::string(std::move(tempTable)); | ||
| 813 | new(&second.singleton_.column_) std::string(std::move(tempColumn)); | ||
| 814 | second.singleton_.comparison_ = tempComparison; | ||
| 815 | new(&second.singleton_.value_) binding(std::move(tempBinding)); | ||
| 816 | second.singleton_.parentObject_ = tempParentObject; | ||
| 817 | |||
| 818 | break; | ||
| 819 | } | ||
| 820 | |||
| 821 | case type::group: | ||
| 822 | { | ||
| 823 | new(&second.group_.children_) std::list<condition>(std::move(tempChildren)); | ||
| 824 | second.group_.orlogic_ = tempOrlogic; | ||
| 825 | |||
| 826 | break; | ||
| 827 | } | ||
| 828 | } | ||
| 829 | } | ||
| 830 | |||
| 831 | statement::condition::~condition() | ||
| 832 | { | ||
| 833 | switch (type_) | ||
| 834 | { | ||
| 835 | case type::empty: | ||
| 836 | { | ||
| 837 | break; | ||
| 838 | } | ||
| 839 | |||
| 840 | case type::singleton: | ||
| 841 | { | ||
| 842 | using string_type = std::string; | ||
| 843 | |||
| 844 | singleton_.table_.~string_type(); | ||
| 845 | singleton_.column_.~string_type(); | ||
| 846 | singleton_.value_.~binding(); | ||
| 847 | |||
| 848 | break; | ||
| 849 | } | ||
| 850 | |||
| 851 | case type::group: | ||
| 852 | { | ||
| 853 | using list_type = std::list<condition>; | ||
| 854 | |||
| 855 | group_.children_.~list_type(); | ||
| 856 | |||
| 857 | break; | ||
| 858 | } | ||
| 859 | } | ||
| 860 | } | ||
| 861 | |||
| 862 | statement::condition::condition() : type_(type::empty) | ||
| 863 | { | ||
| 864 | } | ||
| 865 | |||
| 866 | statement::condition::condition( | 758 | statement::condition::condition( |
| 867 | std::string table, | 759 | std::string table, |
| 868 | std::string column, | 760 | std::string column, |
| 869 | bool isNull) : | 761 | bool isNull) : |
| 870 | type_(type::singleton) | 762 | type_(type::singleton), |
| 763 | variant_(singleton_type { | ||
| 764 | std::move(table), | ||
| 765 | std::move(column), | ||
| 766 | isNull ? comparison::is_null : comparison::is_not_null, | ||
| 767 | {}, | ||
| 768 | object::undefined | ||
| 769 | }) | ||
| 871 | { | 770 | { |
| 872 | new(&singleton_.table_) std::string(std::move(table)); | ||
| 873 | new(&singleton_.column_) std::string(std::move(column)); | ||
| 874 | |||
| 875 | if (isNull) | ||
| 876 | { | ||
| 877 | singleton_.comparison_ = comparison::is_null; | ||
| 878 | } else { | ||
| 879 | singleton_.comparison_ = comparison::is_not_null; | ||
| 880 | } | ||
| 881 | |||
| 882 | singleton_.parentObject_ = object::undefined; | ||
| 883 | } | 771 | } |
| 884 | 772 | ||
| 885 | statement::condition::condition( | 773 | statement::condition::condition( |
| @@ -888,201 +776,210 @@ namespace verbly { | |||
| 888 | comparison comp, | 776 | comparison comp, |
| 889 | binding value, | 777 | binding value, |
| 890 | object parentObject) : | 778 | object parentObject) : |
| 891 | type_(type::singleton) | 779 | type_(type::singleton), |
| 780 | variant_(singleton_type { | ||
| 781 | std::move(table), | ||
| 782 | std::move(column), | ||
| 783 | comp, | ||
| 784 | std::move(value), | ||
| 785 | parentObject | ||
| 786 | }) | ||
| 892 | { | 787 | { |
| 893 | new(&singleton_.table_) std::string(std::move(table)); | ||
| 894 | new(&singleton_.column_) std::string(std::move(column)); | ||
| 895 | singleton_.comparison_ = comp; | ||
| 896 | new(&singleton_.value_) binding(std::move(value)); | ||
| 897 | singleton_.parentObject_ = parentObject; | ||
| 898 | } | 788 | } |
| 899 | 789 | ||
| 900 | std::string statement::condition::toSql(bool toplevel, bool debug) const | 790 | std::string statement::condition::toSql(bool toplevel, bool debug) const |
| 901 | { | 791 | { |
| 792 | std::ostringstream sql; | ||
| 793 | |||
| 902 | switch (type_) | 794 | switch (type_) |
| 903 | { | 795 | { |
| 904 | case type::empty: | 796 | case type::empty: |
| 905 | { | 797 | { |
| 906 | return ""; | 798 | break; |
| 907 | } | 799 | } |
| 908 | 800 | ||
| 909 | case type::singleton: | 801 | case type::singleton: |
| 910 | { | 802 | { |
| 911 | switch (singleton_.comparison_) | 803 | const singleton_type& singleton = mpark::get<singleton_type>(variant_); |
| 804 | |||
| 805 | sql << singleton.table << "." << singleton.column; | ||
| 806 | |||
| 807 | switch (singleton.comparison) | ||
| 912 | { | 808 | { |
| 913 | case comparison::equals: | 809 | case comparison::equals: |
| 810 | case comparison::does_not_equal: | ||
| 914 | { | 811 | { |
| 915 | if (debug) | 812 | if (singleton.comparison == comparison::equals) |
| 916 | { | 813 | { |
| 917 | switch (singleton_.value_.getType()) | 814 | sql << " = "; |
| 918 | { | ||
| 919 | case binding::type::string: | ||
| 920 | { | ||
| 921 | return singleton_.table_ + "." + singleton_.column_ + " = \"" + singleton_.value_.getString() + "\""; | ||
| 922 | } | ||
| 923 | |||
| 924 | case binding::type::integer: | ||
| 925 | { | ||
| 926 | return singleton_.table_ + "." + singleton_.column_ + " = " + std::to_string(singleton_.value_.getInteger()); | ||
| 927 | } | ||
| 928 | |||
| 929 | case binding::type::field: | ||
| 930 | { | ||
| 931 | return singleton_.table_ + "." + singleton_.column_ + " = " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn(); | ||
| 932 | } | ||
| 933 | |||
| 934 | case binding::type::invalid: | ||
| 935 | { | ||
| 936 | throw std::logic_error("Invalid binding in statement generation"); | ||
| 937 | } | ||
| 938 | } | ||
| 939 | } else { | 815 | } else { |
| 940 | if (singleton_.value_.getType() == binding::type::field) | 816 | sql << " != "; |
| 941 | { | ||
| 942 | return singleton_.table_ + "." + singleton_.column_ + " = " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn(); | ||
| 943 | } else { | ||
| 944 | return singleton_.table_ + "." + singleton_.column_ + " = ?"; | ||
| 945 | } | ||
| 946 | } | 817 | } |
| 947 | } | ||
| 948 | 818 | ||
| 949 | case comparison::does_not_equal: | 819 | if (mpark::holds_alternative<field_binding>(singleton.value)) |
| 950 | { | 820 | { |
| 951 | if (debug) | 821 | sql << std::get<0>(mpark::get<field_binding>(singleton.value)) |
| 822 | << "." | ||
| 823 | << std::get<1>(mpark::get<field_binding>(singleton.value)); | ||
| 824 | } else if (debug) | ||
| 952 | { | 825 | { |
| 953 | switch (singleton_.value_.getType()) | 826 | if (mpark::holds_alternative<std::string>(singleton.value)) |
| 954 | { | 827 | { |
| 955 | case binding::type::string: | 828 | sql << "\"" << mpark::get<std::string>(singleton.value) << "\""; |
| 956 | { | ||
| 957 | return singleton_.table_ + "." + singleton_.column_ + " != \"" + singleton_.value_.getString() + "\""; | ||
| 958 | } | ||
| 959 | |||
| 960 | case binding::type::integer: | ||
| 961 | { | ||
| 962 | return singleton_.table_ + "." + singleton_.column_ + " != " + std::to_string(singleton_.value_.getInteger()); | ||
| 963 | } | ||
| 964 | |||
| 965 | case binding::type::field: | ||
| 966 | { | ||
| 967 | return singleton_.table_ + "." + singleton_.column_ + " != " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn(); | ||
| 968 | } | ||
| 969 | |||
| 970 | case binding::type::invalid: | ||
| 971 | { | ||
| 972 | throw std::logic_error("Invalid binding in statement generation"); | ||
| 973 | } | ||
| 974 | } | 829 | } |
| 975 | } else { | 830 | else if (mpark::holds_alternative<int>(singleton.value)) |
| 976 | if (singleton_.value_.getType() == binding::type::field) | ||
| 977 | { | 831 | { |
| 978 | return singleton_.table_ + "." + singleton_.column_ + " != " + singleton_.value_.getTable() + "." + singleton_.value_.getColumn(); | 832 | sql << mpark::get<int>(singleton.value); |
| 979 | } else { | ||
| 980 | return singleton_.table_ + "." + singleton_.column_ + " != ?"; | ||
| 981 | } | 833 | } |
| 834 | } else { | ||
| 835 | sql << "?"; | ||
| 982 | } | 836 | } |
| 837 | |||
| 838 | break; | ||
| 983 | } | 839 | } |
| 984 | 840 | ||
| 985 | case comparison::is_greater_than: | 841 | case comparison::is_greater_than: |
| 986 | { | 842 | { |
| 843 | sql << " > "; | ||
| 844 | |||
| 987 | if (debug) | 845 | if (debug) |
| 988 | { | 846 | { |
| 989 | return singleton_.table_ + "." + singleton_.column_ + " > " + std::to_string(singleton_.value_.getInteger()); | 847 | sql << mpark::get<int>(singleton.value); |
| 990 | } else { | 848 | } else { |
| 991 | return singleton_.table_ + "." + singleton_.column_ + " > ?"; | 849 | sql << "?"; |
| 992 | } | 850 | } |
| 851 | |||
| 852 | break; | ||
| 993 | } | 853 | } |
| 994 | 854 | ||
| 995 | case comparison::is_at_most: | 855 | case comparison::is_at_most: |
| 996 | { | 856 | { |
| 857 | sql << " <= "; | ||
| 858 | |||
| 997 | if (debug) | 859 | if (debug) |
| 998 | { | 860 | { |
| 999 | return singleton_.table_ + "." + singleton_.column_ + " <= " + std::to_string(singleton_.value_.getInteger()); | 861 | sql << mpark::get<int>(singleton.value); |
| 1000 | } else { | 862 | } else { |
| 1001 | return singleton_.table_ + "." + singleton_.column_ + " <= ?"; | 863 | sql << "?"; |
| 1002 | } | 864 | } |
| 865 | |||
| 866 | break; | ||
| 1003 | } | 867 | } |
| 1004 | 868 | ||
| 1005 | case comparison::is_less_than: | 869 | case comparison::is_less_than: |
| 1006 | { | 870 | { |
| 871 | sql << " < "; | ||
| 872 | |||
| 1007 | if (debug) | 873 | if (debug) |
| 1008 | { | 874 | { |
| 1009 | return singleton_.table_ + "." + singleton_.column_ + " < " + std::to_string(singleton_.value_.getInteger()); | 875 | sql << mpark::get<int>(singleton.value); |
| 1010 | } else { | 876 | } else { |
| 1011 | return singleton_.table_ + "." + singleton_.column_ + " < ?"; | 877 | sql << "?"; |
| 1012 | } | 878 | } |
| 879 | |||
| 880 | break; | ||
| 1013 | } | 881 | } |
| 1014 | 882 | ||
| 1015 | case comparison::is_at_least: | 883 | case comparison::is_at_least: |
| 1016 | { | 884 | { |
| 885 | sql << " >= "; | ||
| 886 | |||
| 1017 | if (debug) | 887 | if (debug) |
| 1018 | { | 888 | { |
| 1019 | return singleton_.table_ + "." + singleton_.column_ + " >= " + std::to_string(singleton_.value_.getInteger()); | 889 | sql << mpark::get<int>(singleton.value); |
| 1020 | } else { | 890 | } else { |
| 1021 | return singleton_.table_ + "." + singleton_.column_ + " >= ?"; | 891 | sql << "?"; |
| 1022 | } | 892 | } |
| 893 | |||
| 894 | break; | ||
| 1023 | } | 895 | } |
| 1024 | 896 | ||
| 1025 | case comparison::is_like: | 897 | case comparison::is_like: |
| 1026 | { | 898 | { |
| 899 | sql << " LIKE "; | ||
| 900 | |||
| 1027 | if (debug) | 901 | if (debug) |
| 1028 | { | 902 | { |
| 1029 | return singleton_.table_ + "." + singleton_.column_ + " LIKE \"" + singleton_.value_.getString() + "\""; | 903 | sql << "\"" << mpark::get<std::string>(singleton.value) << "\""; |
| 1030 | } else { | 904 | } else { |
| 1031 | return singleton_.table_ + "." + singleton_.column_ + " LIKE ?"; | 905 | sql << "?"; |
| 1032 | } | 906 | } |
| 907 | |||
| 908 | break; | ||
| 1033 | } | 909 | } |
| 1034 | 910 | ||
| 1035 | case comparison::is_not_like: | 911 | case comparison::is_not_like: |
| 1036 | { | 912 | { |
| 913 | sql << " NOT LIKE "; | ||
| 914 | |||
| 1037 | if (debug) | 915 | if (debug) |
| 1038 | { | 916 | { |
| 1039 | return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE \"" + singleton_.value_.getString() + "\""; | 917 | sql << "\"" << mpark::get<std::string>(singleton.value) << "\""; |
| 1040 | } else { | 918 | } else { |
| 1041 | return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE ?"; | 919 | sql << "?"; |
| 1042 | } | 920 | } |
| 921 | |||
| 922 | break; | ||
| 1043 | } | 923 | } |
| 1044 | 924 | ||
| 1045 | case comparison::is_not_null: | 925 | case comparison::is_not_null: |
| 1046 | { | 926 | { |
| 1047 | return singleton_.table_ + "." + singleton_.column_ + " IS NOT NULL"; | 927 | sql << " IS NOT NULL"; |
| 928 | |||
| 929 | break; | ||
| 1048 | } | 930 | } |
| 1049 | 931 | ||
| 1050 | case comparison::is_null: | 932 | case comparison::is_null: |
| 1051 | { | 933 | { |
| 1052 | return singleton_.table_ + "." + singleton_.column_ + " IS NULL"; | 934 | sql << " IS NULL"; |
| 935 | |||
| 936 | break; | ||
| 1053 | } | 937 | } |
| 1054 | } | 938 | } |
| 939 | |||
| 940 | break; | ||
| 1055 | } | 941 | } |
| 1056 | 942 | ||
| 1057 | case type::group: | 943 | case type::group: |
| 1058 | { | 944 | { |
| 945 | const group_type& group = mpark::get<group_type>(variant_); | ||
| 946 | |||
| 1059 | std::list<std::string> clauses; | 947 | std::list<std::string> clauses; |
| 1060 | for (const condition& cond : group_.children_) | 948 | for (const condition& cond : group.children) |
| 1061 | { | 949 | { |
| 1062 | clauses.push_back(cond.toSql(false, debug)); | 950 | clauses.push_back(cond.toSql(false, debug)); |
| 1063 | } | 951 | } |
| 1064 | 952 | ||
| 1065 | if (clauses.empty()) | 953 | if (clauses.size() == 1) |
| 1066 | { | 954 | { |
| 1067 | return ""; | 955 | sql << clauses.front(); |
| 1068 | } else if (clauses.size() == 1) | 956 | } else if (!clauses.empty()) |
| 1069 | { | 957 | { |
| 1070 | return clauses.front(); | 958 | if (!toplevel) |
| 1071 | } else { | 959 | { |
| 1072 | std::string result = hatkirby::implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND "); | 960 | sql << "("; |
| 961 | } | ||
| 962 | |||
| 963 | sql << | ||
| 964 | hatkirby::implode( | ||
| 965 | std::begin(clauses), | ||
| 966 | std::end(clauses), | ||
| 967 | group.orlogic ? " OR " : " AND "); | ||
| 1073 | 968 | ||
| 1074 | if (toplevel) | 969 | if (!toplevel) |
| 1075 | { | 970 | { |
| 1076 | return result; | 971 | sql << ")"; |
| 1077 | } else { | ||
| 1078 | return "(" + result + ")"; | ||
| 1079 | } | 972 | } |
| 1080 | } | 973 | } |
| 974 | |||
| 975 | break; | ||
| 1081 | } | 976 | } |
| 1082 | } | 977 | } |
| 978 | |||
| 979 | return sql.str(); | ||
| 1083 | } | 980 | } |
| 1084 | 981 | ||
| 1085 | std::list<binding> statement::condition::flattenBindings() const | 982 | std::list<hatkirby::binding> statement::condition::flattenBindings() const |
| 1086 | { | 983 | { |
| 1087 | switch (type_) | 984 | switch (type_) |
| 1088 | { | 985 | { |
| @@ -1093,39 +990,27 @@ namespace verbly { | |||
| 1093 | 990 | ||
| 1094 | case type::singleton: | 991 | case type::singleton: |
| 1095 | { | 992 | { |
| 1096 | if (singleton_.value_.getType() == binding::type::field) | 993 | const singleton_type& singleton = mpark::get<singleton_type>(variant_); |
| 994 | |||
| 995 | if (mpark::holds_alternative<std::string>(singleton.value)) | ||
| 1097 | { | 996 | { |
| 1098 | return {}; | 997 | return {{ mpark::get<std::string>(singleton.value) }}; |
| 998 | } else if (mpark::holds_alternative<int>(singleton.value)) | ||
| 999 | { | ||
| 1000 | return {{ mpark::get<int>(singleton.value) }}; | ||
| 1099 | } else { | 1001 | } else { |
| 1100 | switch (singleton_.comparison_) | 1002 | return {}; |
| 1101 | { | ||
| 1102 | case comparison::equals: | ||
| 1103 | case comparison::does_not_equal: | ||
| 1104 | case comparison::is_greater_than: | ||
| 1105 | case comparison::is_at_most: | ||
| 1106 | case comparison::is_less_than: | ||
| 1107 | case comparison::is_at_least: | ||
| 1108 | case comparison::is_like: | ||
| 1109 | case comparison::is_not_like: | ||
| 1110 | { | ||
| 1111 | return {singleton_.value_}; | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | case comparison::is_not_null: | ||
| 1115 | case comparison::is_null: | ||
| 1116 | { | ||
| 1117 | return {}; | ||
| 1118 | } | ||
| 1119 | } | ||
| 1120 | } | 1003 | } |
| 1121 | } | 1004 | } |
| 1122 | 1005 | ||
| 1123 | case type::group: | 1006 | case type::group: |
| 1124 | { | 1007 | { |
| 1125 | std::list<binding> bindings; | 1008 | const group_type& group = mpark::get<group_type>(variant_); |
| 1126 | for (const condition& cond : group_.children_) | 1009 | |
| 1010 | std::list<hatkirby::binding> bindings; | ||
| 1011 | for (const condition& cond : group.children) | ||
| 1127 | { | 1012 | { |
| 1128 | for (binding value : cond.flattenBindings()) | 1013 | for (hatkirby::binding value : cond.flattenBindings()) |
| 1129 | { | 1014 | { |
| 1130 | bindings.push_back(std::move(value)); | 1015 | bindings.push_back(std::move(value)); |
| 1131 | } | 1016 | } |
| @@ -1136,22 +1021,24 @@ namespace verbly { | |||
| 1136 | } | 1021 | } |
| 1137 | } | 1022 | } |
| 1138 | 1023 | ||
| 1139 | statement::condition::condition(bool orlogic) : type_(type::group) | 1024 | statement::condition::condition( |
| 1025 | bool orlogic) : | ||
| 1026 | type_(type::group), | ||
| 1027 | variant_(group_type { {}, orlogic }) | ||
| 1140 | { | 1028 | { |
| 1141 | new(&group_.children_) std::list<condition>(); | ||
| 1142 | group_.orlogic_ = orlogic; | ||
| 1143 | } | 1029 | } |
| 1144 | 1030 | ||
| 1145 | statement::condition& statement::condition::operator+=(condition n) | 1031 | statement::condition& statement::condition::operator+=(condition n) |
| 1146 | { | 1032 | { |
| 1147 | if (type_ == type::group) | 1033 | if (type_ != type::group) |
| 1148 | { | 1034 | { |
| 1149 | group_.children_.push_back(std::move(n)); | ||
| 1150 | |||
| 1151 | return *this; | ||
| 1152 | } else { | ||
| 1153 | throw std::domain_error("Cannot add condition to non-group condition"); | 1035 | throw std::domain_error("Cannot add condition to non-group condition"); |
| 1154 | } | 1036 | } |
| 1037 | |||
| 1038 | group_type& group = mpark::get<group_type>(variant_); | ||
| 1039 | group.children.emplace_back(std::move(n)); | ||
| 1040 | |||
| 1041 | return *this; | ||
| 1155 | } | 1042 | } |
| 1156 | 1043 | ||
| 1157 | statement::condition& statement::condition::operator&=(condition n) | 1044 | statement::condition& statement::condition::operator&=(condition n) |
| @@ -1187,14 +1074,17 @@ namespace verbly { | |||
| 1187 | return *this; | 1074 | return *this; |
| 1188 | } | 1075 | } |
| 1189 | 1076 | ||
| 1190 | const std::list<statement::condition>& statement::condition::getChildren() const | 1077 | const std::list<statement::condition>& statement::condition::getChildren() |
| 1078 | const | ||
| 1191 | { | 1079 | { |
| 1192 | if (type_ == type::group) | 1080 | if (type_ != type::group) |
| 1193 | { | 1081 | { |
| 1194 | return group_.children_; | ||
| 1195 | } else { | ||
| 1196 | throw std::domain_error("Cannot get children of non-group condition"); | 1082 | throw std::domain_error("Cannot get children of non-group condition"); |
| 1197 | } | 1083 | } |
| 1084 | |||
| 1085 | const group_type& group = mpark::get<group_type>(variant_); | ||
| 1086 | |||
| 1087 | return group.children; | ||
| 1198 | } | 1088 | } |
| 1199 | 1089 | ||
| 1200 | statement::condition statement::condition::flatten() const | 1090 | statement::condition statement::condition::flatten() const |
| @@ -1209,17 +1099,27 @@ namespace verbly { | |||
| 1209 | 1099 | ||
| 1210 | case type::group: | 1100 | case type::group: |
| 1211 | { | 1101 | { |
| 1212 | condition result(group_.orlogic_); | 1102 | const group_type& group = mpark::get<group_type>(variant_); |
| 1213 | 1103 | ||
| 1214 | for (const condition& child : group_.children_) | 1104 | condition result(group.orlogic); |
| 1105 | |||
| 1106 | for (const condition& child : group.children) | ||
| 1215 | { | 1107 | { |
| 1216 | condition newChild = child.flatten(); | 1108 | condition newChild = child.flatten(); |
| 1217 | 1109 | ||
| 1218 | if ((newChild.type_ == type::group) && (newChild.group_.orlogic_ == group_.orlogic_)) | 1110 | if (newChild.type_ == type::group) |
| 1219 | { | 1111 | { |
| 1220 | for (condition subChild : std::move(newChild.group_.children_)) | 1112 | group_type& childGroup = |
| 1113 | mpark::get<group_type>(newChild.variant_); | ||
| 1114 | |||
| 1115 | if (childGroup.orlogic == group.orlogic) | ||
| 1221 | { | 1116 | { |
| 1222 | result += std::move(subChild); | 1117 | for (condition subChild : std::move(childGroup.children)) |
| 1118 | { | ||
| 1119 | result += std::move(subChild); | ||
| 1120 | } | ||
| 1121 | } else { | ||
| 1122 | result += std::move(newChild); | ||
| 1223 | } | 1123 | } |
| 1224 | } else { | 1124 | } else { |
| 1225 | result += std::move(newChild); | 1125 | result += std::move(newChild); |
| @@ -1231,7 +1131,9 @@ namespace verbly { | |||
| 1231 | } | 1131 | } |
| 1232 | } | 1132 | } |
| 1233 | 1133 | ||
| 1234 | statement::condition statement::condition::resolveCompareFields(object context, std::string tableName) const | 1134 | statement::condition statement::condition::resolveCompareFields( |
| 1135 | object context, | ||
| 1136 | std::string tableName) const | ||
| 1235 | { | 1137 | { |
| 1236 | switch (type_) | 1138 | switch (type_) |
| 1237 | { | 1139 | { |
| @@ -1242,9 +1144,20 @@ namespace verbly { | |||
| 1242 | 1144 | ||
| 1243 | case type::singleton: | 1145 | case type::singleton: |
| 1244 | { | 1146 | { |
| 1245 | if ((singleton_.parentObject_ != object::undefined) && (singleton_.parentObject_ == context)) | 1147 | const singleton_type& singleton = mpark::get<singleton_type>(variant_); |
| 1148 | |||
| 1149 | if (singleton.parentObject != object::undefined && | ||
| 1150 | singleton.parentObject == context) | ||
| 1246 | { | 1151 | { |
| 1247 | return condition(singleton_.table_, singleton_.column_, singleton_.comparison_, {tableName, singleton_.value_.getColumn()}); | 1152 | return { |
| 1153 | singleton.table, | ||
| 1154 | singleton.column, | ||
| 1155 | singleton.comparison, | ||
| 1156 | field_binding { | ||
| 1157 | tableName, | ||
| 1158 | std::get<1>(mpark::get<field_binding>(singleton.value)) | ||
| 1159 | } | ||
| 1160 | }; | ||
| 1248 | } else { | 1161 | } else { |
| 1249 | return *this; | 1162 | return *this; |
| 1250 | } | 1163 | } |
| @@ -1252,8 +1165,10 @@ namespace verbly { | |||
| 1252 | 1165 | ||
| 1253 | case type::group: | 1166 | case type::group: |
| 1254 | { | 1167 | { |
| 1255 | condition result(group_.orlogic_); | 1168 | const group_type& group = mpark::get<group_type>(variant_); |
| 1256 | for (const condition& cond : group_.children_) | 1169 | |
| 1170 | condition result(group.orlogic); | ||
| 1171 | for (const condition& cond : group.children) | ||
| 1257 | { | 1172 | { |
| 1258 | result += cond.resolveCompareFields(context, tableName); | 1173 | result += cond.resolveCompareFields(context, tableName); |
| 1259 | } | 1174 | } |
