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 | } |